mirror of
https://github.com/go-vikunja/app
synced 2024-11-04 12:00:00 +00:00
fix: warnings (#1)
* Ran make format Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * Add VS Code launch config Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * pages/list/list.dart: Stop spinning wheel after adding a task Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * stores/list_store.dart: Fix updateTask() not being a future Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * Replace FlatButton with TextButton widgets Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * components/TaskTile.dart: Remove dead code Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * theme/theme.dart: Fix accentColor deprecation Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * pages/list/list_edit.dart: Fix SnackBar.hideCurrentSnackBar() deprecation Signed-off-by: Timo Reichl <timo.reichl@mailbox.org> * Remove unused folder lib/managers Signed-off-by: Timo Reichl <timo.reichl@mailbox.org>
This commit is contained in:
parent
d778f102a7
commit
ee99869cf6
4
.gitignore
vendored
4
.gitignore
vendored
@ -31,6 +31,7 @@
|
||||
.pub/
|
||||
/build/
|
||||
ios/Flutter/flutter_export_environment.sh
|
||||
analysis_options.yaml
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
@ -45,3 +46,6 @@ app.*.map.json
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
||||
# VS Code
|
||||
.vscode/settings.json
|
||||
|
10
.vscode/launch.json
vendored
Normal file
10
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Flutter",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "debug"
|
||||
}
|
||||
]
|
||||
}
|
@ -42,28 +42,36 @@ class Client {
|
||||
queryParameters: queryParameters,
|
||||
// Because dart takes a Map<String, String> here, it is only possible to sort by one parameter while the api supports n parameters.
|
||||
fragment: uri.fragment);
|
||||
return http.get(newUri, headers: _headers)
|
||||
.then(_handleResponse);
|
||||
return http.get(newUri, headers: _headers).then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<Response> delete(String url) {
|
||||
return http.delete('${this.base}$url'.toUri(),
|
||||
headers: _headers,
|
||||
).then(_handleResponse);
|
||||
return http
|
||||
.delete(
|
||||
'${this.base}$url'.toUri(),
|
||||
headers: _headers,
|
||||
)
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<Response> post(String url, {dynamic body}) {
|
||||
return http.post('${this.base}$url'.toUri(),
|
||||
headers: _headers,
|
||||
body: _encoder.convert(body),
|
||||
).then(_handleResponse);
|
||||
return http
|
||||
.post(
|
||||
'${this.base}$url'.toUri(),
|
||||
headers: _headers,
|
||||
body: _encoder.convert(body),
|
||||
)
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<Response> put(String url, {dynamic body}) {
|
||||
return http.put('${this.base}$url'.toUri(),
|
||||
headers: _headers,
|
||||
body: _encoder.convert(body),
|
||||
).then(_handleResponse);
|
||||
return http
|
||||
.put(
|
||||
'${this.base}$url'.toUri(),
|
||||
headers: _headers,
|
||||
body: _encoder.convert(body),
|
||||
)
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Response _handleResponse(http.Response response) {
|
||||
@ -81,10 +89,7 @@ class Client {
|
||||
response.statusCode, response.request.url.toString());
|
||||
}
|
||||
return Response(
|
||||
_decoder.convert(response.body),
|
||||
response.statusCode,
|
||||
response.headers
|
||||
);
|
||||
_decoder.convert(response.body), response.statusCode, response.headers);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,16 @@ class LabelTaskAPIService extends APIService implements LabelTaskService {
|
||||
|
||||
@override
|
||||
Future<Label> create(LabelTask lt) async {
|
||||
return client.put('/tasks/${lt.task.id}/labels', body: lt.toJSON())
|
||||
return client
|
||||
.put('/tasks/${lt.task.id}/labels', body: lt.toJSON())
|
||||
.then((result) => Label.fromJson(result.body));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Label> delete(LabelTask lt) async {
|
||||
return client.delete('/tasks/${lt.task.id}/labels/${lt.label.id}')
|
||||
.then((result) => Label.fromJson(result.body));
|
||||
return client
|
||||
.delete('/tasks/${lt.task.id}/labels/${lt.label.id}')
|
||||
.then((result) => Label.fromJson(result.body));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -27,4 +29,4 @@ class LabelTaskAPIService extends APIService implements LabelTaskService {
|
||||
return client.get('/tasks/${lt.task.id}/labels$params').then(
|
||||
(label) => convertList(label, (result) => Label.fromJson(result)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class LabelTaskBulkAPIService extends APIService
|
||||
return client
|
||||
.post('/tasks/${task.id}/labels/bulk',
|
||||
body: LabelTaskBulk(labels: labels).toJSON())
|
||||
.then((response) =>
|
||||
convertList(response.body['labels'], (result) => Label.fromJson(result)));
|
||||
.then((response) => convertList(
|
||||
response.body['labels'], (result) => Label.fromJson(result)));
|
||||
}
|
||||
}
|
||||
|
@ -8,19 +8,22 @@ class LabelAPIService extends APIService implements LabelService {
|
||||
|
||||
@override
|
||||
Future<Label> create(Label label) {
|
||||
return client.put('/labels', body: label.toJSON())
|
||||
return client
|
||||
.put('/labels', body: label.toJSON())
|
||||
.then((response) => Label.fromJson(response.body));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Label> delete(Label label) {
|
||||
return client.delete('/labels/${label.id}')
|
||||
return client
|
||||
.delete('/labels/${label.id}')
|
||||
.then((response) => Label.fromJson(response.body));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Label> get(int labelID) {
|
||||
return client.get('/labels/$labelID')
|
||||
return client
|
||||
.get('/labels/$labelID')
|
||||
.then((response) => Label.fromJson(response.body));
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@ class ListAPIService extends APIService implements ListService {
|
||||
return client.get('/lists/$listId').then((response) {
|
||||
final map = response.body;
|
||||
if (map.containsKey('id')) {
|
||||
return client.get("/lists/$listId/tasks")
|
||||
.then((tasks) => TaskList.fromJson(
|
||||
map, tasksJson: tasks.body));
|
||||
return client
|
||||
.get("/lists/$listId/tasks")
|
||||
.then((tasks) => TaskList.fromJson(map, tasksJson: tasks.body));
|
||||
}
|
||||
return TaskList.fromJson(map);
|
||||
});
|
||||
|
@ -21,11 +21,11 @@ class AddDialog extends StatelessWidget {
|
||||
)
|
||||
]),
|
||||
actions: <Widget>[
|
||||
new FlatButton(
|
||||
new TextButton(
|
||||
child: const Text('CANCEL'),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
new FlatButton(
|
||||
new TextButton(
|
||||
child: const Text('ADD'),
|
||||
onPressed: () {
|
||||
if (this.onAdd != null && textController.text.isNotEmpty)
|
||||
|
@ -10,7 +10,7 @@ class ErrorDialog extends StatelessWidget {
|
||||
return AlertDialog(
|
||||
content: Text(error.toString()),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
TextButton(
|
||||
child: Text('Close'),
|
||||
onPressed: () => Navigator.of(context).maybePop(),
|
||||
)
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:vikunja_app/global.dart';
|
||||
import 'package:vikunja_app/models/task.dart';
|
||||
|
||||
class TaskTile extends StatefulWidget {
|
||||
@ -21,17 +20,16 @@ class TaskTile extends StatefulWidget {
|
||||
|
||||
@override
|
||||
TaskTileState createState() {
|
||||
return new TaskTileState(this.task, this.loading);
|
||||
return new TaskTileState(this.loading);
|
||||
}
|
||||
}
|
||||
|
||||
class TaskTileState extends State<TaskTile> {
|
||||
bool _loading;
|
||||
Task _currentTask;
|
||||
|
||||
TaskTileState(this._currentTask, this._loading)
|
||||
: assert(_currentTask != null),
|
||||
assert(_loading != null);
|
||||
TaskTileState(this._loading) {
|
||||
assert(_loading != null);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -47,9 +45,10 @@ class TaskTileState extends State<TaskTile> {
|
||||
)),
|
||||
),
|
||||
title: Text(widget.task.title),
|
||||
subtitle: widget.task.description == null || widget.task.description.isEmpty
|
||||
? null
|
||||
: Text(widget.task.description),
|
||||
subtitle:
|
||||
widget.task.description == null || widget.task.description.isEmpty
|
||||
? null
|
||||
: Text(widget.task.description),
|
||||
trailing: IconButton(
|
||||
icon: Icon(Icons.settings),
|
||||
onPressed: () => widget.onEdit,
|
||||
@ -60,9 +59,10 @@ class TaskTileState extends State<TaskTile> {
|
||||
title: Text(widget.task.title),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
value: widget.task.done ?? false,
|
||||
subtitle: widget.task.description == null || widget.task.description.isEmpty
|
||||
? null
|
||||
: Text(widget.task.description),
|
||||
subtitle:
|
||||
widget.task.description == null || widget.task.description.isEmpty
|
||||
? null
|
||||
: Text(widget.task.description),
|
||||
secondary: IconButton(
|
||||
icon: Icon(Icons.settings),
|
||||
onPressed: widget.onEdit,
|
||||
@ -70,28 +70,6 @@ class TaskTileState extends State<TaskTile> {
|
||||
onChanged: widget.onMarkedAsDone,
|
||||
);
|
||||
}
|
||||
|
||||
void _change(bool value) async {
|
||||
setState(() {
|
||||
this._loading = true;
|
||||
});
|
||||
Task newTask = await _updateTask(widget.task, value);
|
||||
setState(() {
|
||||
//this.widget.task = newTask;
|
||||
this._loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<Task> _updateTask(Task task, bool checked) {
|
||||
// TODO use copyFrom
|
||||
return VikunjaGlobal.of(context).taskService.update(Task(
|
||||
id: task.id,
|
||||
done: checked,
|
||||
title: task.title,
|
||||
description: task.description,
|
||||
createdBy: null,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
typedef Future<void> TaskChanged(Task task, bool newValue);
|
||||
|
@ -43,7 +43,9 @@ class VikunjaDateTimePicker extends StatelessWidget {
|
||||
return showDatePicker(
|
||||
context: context,
|
||||
firstDate: DateTime(1900),
|
||||
initialDate: currentValue.millisecondsSinceEpoch > 0 ? currentValue : DateTime.now(),
|
||||
initialDate: currentValue.millisecondsSinceEpoch > 0
|
||||
? currentValue
|
||||
: DateTime.now(),
|
||||
lastDate: DateTime(2100));
|
||||
},
|
||||
);
|
||||
|
@ -1,4 +1,3 @@
|
||||
extension StringExtensions on String {
|
||||
|
||||
Uri toUri() => Uri.tryParse(this);
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import 'package:vikunja_app/api/list_implementation.dart';
|
||||
import 'package:vikunja_app/api/namespace_implementation.dart';
|
||||
import 'package:vikunja_app/api/task_implementation.dart';
|
||||
import 'package:vikunja_app/api/user_implementation.dart';
|
||||
import 'package:vikunja_app/managers/user.dart';
|
||||
import 'package:vikunja_app/models/user.dart';
|
||||
import 'package:vikunja_app/service/services.dart';
|
||||
|
||||
@ -22,7 +21,8 @@ class VikunjaGlobal extends StatefulWidget {
|
||||
VikunjaGlobalState createState() => VikunjaGlobalState();
|
||||
|
||||
static VikunjaGlobalState of(BuildContext context) {
|
||||
var widget = context.dependOnInheritedWidgetOfExactType<_VikunjaGlobalInherited>();
|
||||
var widget =
|
||||
context.dependOnInheritedWidgetOfExactType<_VikunjaGlobalInherited>();
|
||||
return widget.data;
|
||||
}
|
||||
}
|
||||
@ -38,8 +38,6 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
||||
|
||||
Client get client => _client;
|
||||
|
||||
UserManager get userManager => new UserManager(_storage);
|
||||
|
||||
UserService newUserService(base) => new UserAPIService(Client(null, base));
|
||||
|
||||
NamespaceService get namespaceService => new NamespaceAPIService(client);
|
||||
|
@ -1,24 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
class UserManager {
|
||||
final FlutterSecureStorage _storage;
|
||||
|
||||
UserManager(this._storage);
|
||||
|
||||
Future<List<int>> loadLocalUserIds() async {
|
||||
return await _storage.readAll().then((userMap) {
|
||||
userMap.keys
|
||||
.where((id) => _isNumeric(id))
|
||||
.map((idString) => int.tryParse(idString));
|
||||
});
|
||||
}
|
||||
|
||||
bool _isNumeric(String str) {
|
||||
if (str == null) {
|
||||
return false;
|
||||
}
|
||||
return double.tryParse(str) != null;
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:vikunja_app/models/user.dart';
|
||||
|
||||
class Label {
|
||||
|
@ -3,7 +3,6 @@ import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:vikunja_app/models/label.dart';
|
||||
import 'package:vikunja_app/models/user.dart';
|
||||
import 'package:vikunja_app/utils/datetime_to_unix.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Task {
|
||||
@ -60,16 +59,17 @@ class Task {
|
||||
?.toList(),
|
||||
updated = DateTime.parse(json['updated']),
|
||||
created = DateTime.parse(json['created']),
|
||||
createdBy = json['created_by'] == null ? null : User.fromJson(json['created_by']);
|
||||
createdBy = json['created_by'] == null
|
||||
? null
|
||||
: User.fromJson(json['created_by']);
|
||||
|
||||
toJSON() => {
|
||||
'id': id,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'done': done ?? false,
|
||||
'reminder_dates': reminderDates
|
||||
?.map((date) => date?.toIso8601String())
|
||||
?.toList(),
|
||||
'reminder_dates':
|
||||
reminderDates?.map((date) => date?.toIso8601String())?.toList(),
|
||||
'due_date': dueDate?.toIso8601String(),
|
||||
'start_date': startDate?.toIso8601String(),
|
||||
'end_date': endDate?.toIso8601String(),
|
||||
|
@ -14,8 +14,7 @@ class User {
|
||||
toJSON() => {"id": this.id, "email": this.email, "username": this.username};
|
||||
|
||||
String avatarUrl(BuildContext context) {
|
||||
return VikunjaGlobal.of(context).client.base +
|
||||
"/avatar/${this.username}";
|
||||
return VikunjaGlobal.of(context).client.base + "/avatar/${this.username}";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,24 +33,21 @@ class HomePageState extends State<HomePage> with AfterLayoutMixin<HomePage> {
|
||||
|
||||
Widget _namespacesWidget() {
|
||||
List<Widget> namespacesList = <Widget>[];
|
||||
_namespaces
|
||||
.asMap()
|
||||
.forEach((i, namespace) => namespacesList.add(ListTile(
|
||||
leading: const Icon(Icons.folder),
|
||||
title: Text(namespace.title),
|
||||
selected: i == _selectedDrawerIndex,
|
||||
onTap: () => _onSelectItem(i),
|
||||
))
|
||||
);
|
||||
_namespaces.asMap().forEach((i, namespace) => namespacesList.add(ListTile(
|
||||
leading: const Icon(Icons.folder),
|
||||
title: Text(namespace.title),
|
||||
selected: i == _selectedDrawerIndex,
|
||||
onTap: () => _onSelectItem(i),
|
||||
)));
|
||||
|
||||
return this._loading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: RefreshIndicator(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: ListTile.divideTiles(
|
||||
context: context,
|
||||
tiles: namespacesList).toList(),
|
||||
padding: EdgeInsets.zero,
|
||||
children:
|
||||
ListTile.divideTiles(context: context, tiles: namespacesList)
|
||||
.toList(),
|
||||
),
|
||||
onRefresh: _loadNamespaces,
|
||||
);
|
||||
@ -85,18 +82,18 @@ class HomePageState extends State<HomePage> with AfterLayoutMixin<HomePage> {
|
||||
MaterialPageRoute(
|
||||
builder: (context) => NamespaceEditPage(
|
||||
namespace: _currentNamespace,
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
)))),
|
||||
],
|
||||
),
|
||||
drawer: Drawer(
|
||||
child: Column(children: <Widget>[
|
||||
UserAccountsDrawerHeader(
|
||||
// Removed until we find a way to disable the user email only for some occasions and not everywhere
|
||||
accountEmail: currentUser?.email == null ? null : Text(currentUser.email),
|
||||
accountName: currentUser?.username == null ? null : Text(currentUser.username),
|
||||
accountEmail:
|
||||
currentUser?.email == null ? null : Text(currentUser.email),
|
||||
accountName: currentUser?.username == null
|
||||
? null
|
||||
: Text(currentUser.username),
|
||||
onDetailsPressed: () {
|
||||
setState(() {
|
||||
_showUserDetails = !_showUserDetails;
|
||||
@ -105,22 +102,24 @@ class HomePageState extends State<HomePage> with AfterLayoutMixin<HomePage> {
|
||||
currentAccountPicture: currentUser == null
|
||||
? null
|
||||
: CircleAvatar(
|
||||
backgroundImage: NetworkImage(currentUser.avatarUrl(context)),
|
||||
backgroundImage:
|
||||
NetworkImage(currentUser.avatarUrl(context)),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage("assets/graphics/hypnotize.png"),
|
||||
repeat: ImageRepeat.repeat,
|
||||
colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.multiply),
|
||||
image: AssetImage("assets/graphics/hypnotize.png"),
|
||||
repeat: ImageRepeat.repeat,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).primaryColor, BlendMode.multiply),
|
||||
),
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (BuildContext context) =>
|
||||
Expanded(
|
||||
child: _showUserDetails ? _userDetailsWidget(context) : _namespacesWidget(),
|
||||
)
|
||||
),
|
||||
builder: (BuildContext context) => Expanded(
|
||||
child: _showUserDetails
|
||||
? _userDetailsWidget(context)
|
||||
: _namespacesWidget(),
|
||||
)),
|
||||
Align(
|
||||
alignment: FractionalOffset.bottomCenter,
|
||||
child: Builder(
|
||||
@ -155,8 +154,8 @@ class HomePageState extends State<HomePage> with AfterLayoutMixin<HomePage> {
|
||||
builder: (_) => AddDialog(
|
||||
onAdd: (name) => _addNamespace(name, context),
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Namespace',
|
||||
hintText: 'eg. Personal Namespace',
|
||||
labelText: 'Namespace',
|
||||
hintText: 'eg. Personal Namespace',
|
||||
),
|
||||
));
|
||||
}
|
||||
@ -171,9 +170,9 @@ class HomePageState extends State<HomePage> with AfterLayoutMixin<HomePage> {
|
||||
content: Text('The namespace was created successfully!'),
|
||||
));
|
||||
}).catchError((error) => showDialog(
|
||||
context: context,
|
||||
builder: (context) => ErrorDialog(error: error),
|
||||
));
|
||||
context: context,
|
||||
builder: (context) => ErrorDialog(error: error),
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _loadNamespaces() {
|
||||
|
@ -11,7 +11,6 @@ import 'package:vikunja_app/pages/list/list_edit.dart';
|
||||
import 'package:vikunja_app/pages/list/task_edit.dart';
|
||||
import 'package:vikunja_app/stores/list_store.dart';
|
||||
|
||||
|
||||
class ListPage extends StatefulWidget {
|
||||
final TaskList taskList;
|
||||
|
||||
@ -41,63 +40,62 @@ class _ListPageState extends State<ListPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final taskState = Provider.of<ListProvider>(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_list.title),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEditPage(
|
||||
list: _list,
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// TODO: it brakes the flow with _loadingTasks and conflicts with the provider
|
||||
body: !taskState.isLoading
|
||||
? RefreshIndicator(
|
||||
child: taskState.tasks.length > 0
|
||||
appBar: AppBar(
|
||||
title: Text(_list.title),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEditPage(
|
||||
list: _list,
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
// TODO: it brakes the flow with _loadingTasks and conflicts with the provider
|
||||
body: !taskState.isLoading
|
||||
? RefreshIndicator(
|
||||
child: taskState.tasks.length > 0
|
||||
? ListenableProvider.value(
|
||||
value: taskState,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
itemBuilder: (context, i) {
|
||||
if (i.isOdd) return Divider();
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
itemBuilder: (context, i) {
|
||||
if (i.isOdd) return Divider();
|
||||
|
||||
if (_loadingTasks.isNotEmpty) {
|
||||
final loadingTask = _loadingTasks.removeLast();
|
||||
return _buildLoadingTile(loadingTask);
|
||||
}
|
||||
if (_loadingTasks.isNotEmpty) {
|
||||
final loadingTask = _loadingTasks.removeLast();
|
||||
return _buildLoadingTile(loadingTask);
|
||||
}
|
||||
|
||||
final index = i ~/ 2;
|
||||
final index = i ~/ 2;
|
||||
|
||||
// This handles the case if there are no more elements in the list left which can be provided by the api
|
||||
if (taskState.maxPages == _currentPage &&
|
||||
index == taskState.tasks.length - 1) return null;
|
||||
// This handles the case if there are no more elements in the list left which can be provided by the api
|
||||
if (taskState.maxPages == _currentPage &&
|
||||
index == taskState.tasks.length - 1)
|
||||
return null;
|
||||
|
||||
if (index >= taskState.tasks.length &&
|
||||
_currentPage < taskState.maxPages) {
|
||||
_currentPage++;
|
||||
_loadTasksForPage(_currentPage);
|
||||
}
|
||||
return index < taskState.tasks.length
|
||||
? _buildTile(taskState.tasks[index])
|
||||
: null;
|
||||
}
|
||||
),
|
||||
)
|
||||
if (index >= taskState.tasks.length &&
|
||||
_currentPage < taskState.maxPages) {
|
||||
_currentPage++;
|
||||
_loadTasksForPage(_currentPage);
|
||||
}
|
||||
return index < taskState.tasks.length
|
||||
? _buildTile(taskState.tasks[index])
|
||||
: null;
|
||||
}),
|
||||
)
|
||||
: Center(child: Text('This list is empty.')),
|
||||
onRefresh: _loadList,
|
||||
onRefresh: _loadList,
|
||||
)
|
||||
: Center(child: CircularProgressIndicator()),
|
||||
floatingActionButton: Builder(
|
||||
builder: (context) => FloatingActionButton(
|
||||
onPressed: () => _addItemDialog(context), child: Icon(Icons.add)),
|
||||
),
|
||||
: Center(child: CircularProgressIndicator()),
|
||||
floatingActionButton: Builder(
|
||||
builder: (context) => FloatingActionButton(
|
||||
onPressed: () => _addItemDialog(context), child: Icon(Icons.add)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -156,8 +154,8 @@ class _ListPageState extends State<ListPage> {
|
||||
builder: (_) => AddDialog(
|
||||
onAdd: (title) => _addItem(title, context),
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Task Name',
|
||||
hintText: 'eg. Milk',
|
||||
labelText: 'Task Name',
|
||||
hintText: 'eg. Milk',
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -174,13 +172,17 @@ class _ListPageState extends State<ListPage> {
|
||||
setState(() => _loadingTasks.add(newTask));
|
||||
Provider.of<ListProvider>(context, listen: false)
|
||||
.addTask(
|
||||
context: context,
|
||||
newTask: newTask,
|
||||
listId: _list.id,
|
||||
).then((_) {
|
||||
context: context,
|
||||
newTask: newTask,
|
||||
listId: _list.id,
|
||||
)
|
||||
.then((_) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text('The task was added successfully!'),
|
||||
));
|
||||
setState(() {
|
||||
_loadingTasks.remove(newTask);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +106,14 @@ class _ListEditPageState extends State<ListEditPage> {
|
||||
));
|
||||
}).catchError((err) {
|
||||
setState(() => _loading = false);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
ScaffoldMessengerState scaffoldState = ScaffoldMessenger.of(context);
|
||||
scaffoldState.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Something went wrong: ' + err.toString()),
|
||||
action: SnackBarAction(
|
||||
label: 'CLOSE',
|
||||
onPressed: Scaffold.of(context).hideCurrentSnackBar),
|
||||
onPressed: (() => scaffoldState.hideCurrentSnackBar(
|
||||
reason: SnackBarClosedReason.action))),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -59,7 +59,8 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||
builder: (BuildContext context) => SafeArea(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(padding: const EdgeInsets.all(16.0), children: <Widget>[
|
||||
child: ListView(padding: const EdgeInsets.all(16.0), children: <
|
||||
Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: TextFormField(
|
||||
|
@ -58,8 +58,11 @@ class _NamespacePageState extends State<NamespacePage>
|
||||
color: Colors.white, size: 36.0)),
|
||||
),
|
||||
onDismissed: (direction) {
|
||||
_removeList(ls).then((_) => ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(content: Text("${ls.title} removed"))));
|
||||
_removeList(ls).then((_) =>
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
"${ls.title} removed"))));
|
||||
},
|
||||
))).toList(),
|
||||
)
|
||||
|
@ -122,8 +122,7 @@ class MockedTaskService implements TaskService {
|
||||
@override
|
||||
Future delete(int taskId) {
|
||||
_lists.forEach(
|
||||
(_, list) => list.tasks.removeWhere((task) => task.id == taskId)
|
||||
);
|
||||
(_, list) => list.tasks.removeWhere((task) => task.id == taskId));
|
||||
_tasks.remove(taskId);
|
||||
return Future.value();
|
||||
}
|
||||
|
@ -39,13 +39,14 @@ class ListProvider with ChangeNotifier {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> addTaskByTitle({BuildContext context, String title, int listId}) {
|
||||
Future<void> addTaskByTitle(
|
||||
{BuildContext context, String title, int listId}) {
|
||||
var globalState = VikunjaGlobal.of(context);
|
||||
var newTask = Task(
|
||||
id: null,
|
||||
title: title,
|
||||
createdBy: globalState.currentUser,
|
||||
done: false,
|
||||
id: null,
|
||||
title: title,
|
||||
createdBy: globalState.currentUser,
|
||||
done: false,
|
||||
);
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
@ -69,12 +70,14 @@ class ListProvider with ChangeNotifier {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> updateTask({BuildContext context, int id, bool done}) {
|
||||
void updateTask({BuildContext context, int id, bool done}) {
|
||||
var globalState = VikunjaGlobal.of(context);
|
||||
globalState.taskService.update(Task(
|
||||
globalState.taskService
|
||||
.update(Task(
|
||||
id: id,
|
||||
done: done,
|
||||
)).then((task) {
|
||||
))
|
||||
.then((task) {
|
||||
// FIXME: This is ugly. We should use a redux to not have to do these kind of things.
|
||||
// This is enough for now (it works™) but we should definitly fix it later.
|
||||
_tasks.asMap().forEach((i, t) {
|
||||
|
@ -30,4 +30,4 @@ const vStandardVerticalPadding = EdgeInsets.symmetric(vertical: 5.0);
|
||||
const vStandardHorizontalPadding = EdgeInsets.symmetric(horizontal: 5.0);
|
||||
const vStandardPadding = EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0);
|
||||
|
||||
var vDateFormatLong = DateFormat("EEEE, MMMM d, yyyy 'at' H:mm");
|
||||
var vDateFormatLong = DateFormat("EEEE, MMMM d, yyyy 'at' H:mm");
|
||||
|
@ -2,13 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:vikunja_app/theme/constants.dart';
|
||||
|
||||
ThemeData buildVikunjaTheme() => _buildVikunjaTheme(ThemeData.light());
|
||||
|
||||
ThemeData buildVikunjaDarkTheme() {
|
||||
ThemeData base = _buildVikunjaTheme(ThemeData.dark());
|
||||
return base.copyWith(
|
||||
accentColor: vWhite,
|
||||
);
|
||||
}
|
||||
ThemeData buildVikunjaDarkTheme() => _buildVikunjaTheme(ThemeData.dark());
|
||||
|
||||
ThemeData _buildVikunjaTheme(ThemeData base) {
|
||||
return base.copyWith(
|
||||
|
@ -8,4 +8,4 @@ dateTimeFromUnixTimestamp(int timestamp) {
|
||||
return timestamp == null
|
||||
? 0
|
||||
: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user