mirror of
https://github.com/go-vikunja/app
synced 2025-01-22 07:36:04 +00:00
Add API implementations of List, Namespace, Task, User
Use Services in order to retrieve data
This commit is contained in:
parent
1994892b63
commit
f7db5324aa
@ -31,6 +31,12 @@ class Client {
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<dynamic> delete(String url) {
|
||||
return http
|
||||
.delete('${this.base}$url', headers: _headers)
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<dynamic> post(String url, {dynamic body}) {
|
||||
return http
|
||||
.post('${this.base}$url',
|
||||
@ -38,6 +44,13 @@ class Client {
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<dynamic> put(String url, {dynamic body}) {
|
||||
return http
|
||||
.put('${this.base}$url',
|
||||
headers: _headers, body: _encoder.convert(body))
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
dynamic _handleResponse(http.Response response) {
|
||||
if (response.statusCode < 200 ||
|
||||
response.statusCode > 400 ||
|
||||
|
46
lib/api/list_implementation.dart
Normal file
46
lib/api/list_implementation.dart
Normal file
@ -0,0 +1,46 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/api/service.dart';
|
||||
import 'package:fluttering_vikunja/models/task.dart';
|
||||
import 'package:fluttering_vikunja/service/services.dart';
|
||||
|
||||
class ListAPIService extends APIService implements ListService {
|
||||
ListAPIService(Client client) : super(client);
|
||||
|
||||
@override
|
||||
Future<TaskList> create(namespaceId, TaskList tl) {
|
||||
return client
|
||||
.put('/namespaces/$namespaceId/lists', body: tl.toJSON())
|
||||
.then((map) => TaskList.fromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future delete(int listId) {
|
||||
return client.delete('/lists/$listId').then((_) {});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TaskList> get(int listId) {
|
||||
return client.get('/lists/$listId').then((map) => TaskList.fromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<TaskList>> getAll() {
|
||||
return client.get('/lists').then(
|
||||
(list) => convertList(list, (result) => TaskList.fromJson(result)));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<TaskList>> getByNamespace(int namespaceId) {
|
||||
return client.get('/namespaces/$namespaceId/lists').then(
|
||||
(list) => convertList(list, (result) => TaskList.fromJson(result)));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TaskList> update(TaskList tl) {
|
||||
return client
|
||||
.put('/lists/${tl.id}', body: tl.toJSON())
|
||||
.then((map) => TaskList.fromJson(map));
|
||||
}
|
||||
}
|
42
lib/api/namespace_implementation.dart
Normal file
42
lib/api/namespace_implementation.dart
Normal file
@ -0,0 +1,42 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/api/service.dart';
|
||||
import 'package:fluttering_vikunja/models/namespace.dart';
|
||||
import 'package:fluttering_vikunja/service/services.dart';
|
||||
|
||||
class NamespaceAPIService extends APIService implements NamespaceService {
|
||||
NamespaceAPIService(Client client) : super(client);
|
||||
|
||||
@override
|
||||
Future<Namespace> create(Namespace ns) {
|
||||
return client
|
||||
.put('/namespaces', body: ns.toJSON())
|
||||
.then((map) => Namespace.fromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future delete(int namespaceId) {
|
||||
return client.delete('/namespaces/$namespaceId');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Namespace> get(int namespaceId) {
|
||||
return client
|
||||
.get('/namespaces/$namespaceId')
|
||||
.then((map) => Namespace.fromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Namespace>> getAll() {
|
||||
return client.get('/namespaces').then(
|
||||
(list) => convertList(list, (result) => Namespace.fromJson(result)));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Namespace> update(Namespace ns) {
|
||||
return client
|
||||
.post('/namespaces/${ns.id}', body: ns.toJSON())
|
||||
.then((map) => Namespace.fromJson(map));
|
||||
}
|
||||
}
|
19
lib/api/service.dart
Normal file
19
lib/api/service.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
class APIService {
|
||||
final Client _client;
|
||||
|
||||
@protected
|
||||
Client get client => _client;
|
||||
|
||||
APIService(this._client);
|
||||
|
||||
@protected
|
||||
List<T> convertList<T>(dynamic value, Mapper<T> mapper) {
|
||||
if (value == null) return [];
|
||||
return (value as List<dynamic>).map((map) => mapper(map)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
typedef T Mapper<T>(Map<String, dynamic> json);
|
29
lib/api/task_implementation.dart
Normal file
29
lib/api/task_implementation.dart
Normal file
@ -0,0 +1,29 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/api/service.dart';
|
||||
import 'package:fluttering_vikunja/models/task.dart';
|
||||
import 'package:fluttering_vikunja/service/services.dart';
|
||||
|
||||
class TaskAPIService extends APIService implements TaskService {
|
||||
TaskAPIService(Client client) : super(client);
|
||||
|
||||
@override
|
||||
Future<Task> add(int listId, Task task) {
|
||||
return client
|
||||
.put('/lists/$listId', body: task.toJSON())
|
||||
.then((map) => Task.fromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future delete(int taskId) {
|
||||
return client.delete('/tasks/$taskId');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Task> update(Task task) {
|
||||
return client
|
||||
.post('/tasks/${task.id}', body: task.toJSON())
|
||||
.then((map) => Task.fromJson(map));
|
||||
}
|
||||
}
|
@ -1,27 +1,26 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/api/service.dart';
|
||||
import 'package:fluttering_vikunja/models/user.dart';
|
||||
import 'package:fluttering_vikunja/service/services.dart';
|
||||
|
||||
class UserAPIService implements UserService {
|
||||
final Client _client;
|
||||
|
||||
UserAPIService(this._client);
|
||||
class UserAPIService extends APIService implements UserService {
|
||||
UserAPIService(Client client) : super(client);
|
||||
|
||||
@override
|
||||
Future<UserTokenPair> login(String username, password) async {
|
||||
var token = await _client.post('/login', body: {
|
||||
var token = await client.post('/login', body: {
|
||||
'username': username,
|
||||
'password': password
|
||||
}).then((map) => map['token']);
|
||||
return UserAPIService(Client(token, _client.base))
|
||||
return UserAPIService(Client(token, client.base))
|
||||
.getCurrentUser()
|
||||
.then((user) => UserTokenPair(user, token));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<User> getCurrentUser() {
|
||||
return _client.get('/user').then((map) => User.fromJson(map));
|
||||
return client.get('/user').then((map) => User.fromJson(map));
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,121 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttering_vikunja/global.dart';
|
||||
import 'package:fluttering_vikunja/models/namespace.dart';
|
||||
import 'package:fluttering_vikunja/models/task.dart';
|
||||
import 'package:fluttering_vikunja/pages/list_page.dart';
|
||||
|
||||
class NamespaceFragment extends StatefulWidget {
|
||||
final String namespace;
|
||||
NamespaceFragment({this.namespace}) : super(key: Key(namespace));
|
||||
final Namespace namespace;
|
||||
NamespaceFragment({this.namespace})
|
||||
: super(key: Key(namespace.id.toString()));
|
||||
|
||||
@override
|
||||
_NamespaceFragmentState createState() => new _NamespaceFragmentState();
|
||||
}
|
||||
|
||||
class _NamespaceFragmentState extends State<NamespaceFragment> {
|
||||
Set<String> _lists = Set.from(
|
||||
["Cupertino List", "Material List", "Shopping List", "NAS List"]);
|
||||
List<TaskList> _lists = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new ListView(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
children: ListTile.divideTiles(
|
||||
context: context,
|
||||
tiles: _lists.map((name) => Dismissible(
|
||||
key: Key(name),
|
||||
direction: DismissDirection.startToEnd,
|
||||
child: ListTile(
|
||||
title: new Text(name),
|
||||
onTap: () => _openList(context, name),
|
||||
trailing: Icon(Icons.arrow_right),
|
||||
),
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: const ListTile(
|
||||
leading:
|
||||
Icon(Icons.delete, color: Colors.white, size: 36.0)),
|
||||
),
|
||||
onDismissed: (direction) {
|
||||
setState(() => _lists.remove(name));
|
||||
Scaffold.of(context)
|
||||
.showSnackBar(SnackBar(content: Text("$name removed")));
|
||||
},
|
||||
))).toList(),
|
||||
return Scaffold(
|
||||
body: new ListView(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
children: ListTile.divideTiles(
|
||||
context: context,
|
||||
tiles: _lists.map((ls) => Dismissible(
|
||||
key: Key(ls.id.toString()),
|
||||
direction: DismissDirection.startToEnd,
|
||||
child: ListTile(
|
||||
title: new Text(ls.title),
|
||||
onTap: () => _openList(context, ls),
|
||||
trailing: Icon(Icons.arrow_right),
|
||||
),
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: const ListTile(
|
||||
leading: Icon(Icons.delete,
|
||||
color: Colors.white, size: 36.0)),
|
||||
),
|
||||
onDismissed: (direction) {
|
||||
_removeList(ls).then((_) => Scaffold.of(context)
|
||||
.showSnackBar(
|
||||
SnackBar(content: Text("${ls.title} removed"))));
|
||||
},
|
||||
))).toList(),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => _addListDialog(), child: const Icon(Icons.add)),
|
||||
);
|
||||
}
|
||||
|
||||
_openList(BuildContext context, String name) {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_updateLists();
|
||||
}
|
||||
|
||||
Future _removeList(TaskList list) {
|
||||
return VikunjaGlobal.of(context)
|
||||
.listService
|
||||
.delete(list.id)
|
||||
.then((_) => _updateLists());
|
||||
}
|
||||
|
||||
_updateLists() {
|
||||
VikunjaGlobal.of(context)
|
||||
.listService
|
||||
.getByNamespace(widget.namespace.id)
|
||||
.then((lists) => setState(() => this._lists = lists));
|
||||
}
|
||||
|
||||
_openList(BuildContext context, TaskList list) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => ListPage(listName: name)));
|
||||
MaterialPageRoute(builder: (context) => ListPage(taskList: list)));
|
||||
}
|
||||
|
||||
_addListDialog() {
|
||||
var textController = new TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
child: new AlertDialog(
|
||||
contentPadding: const EdgeInsets.all(16.0),
|
||||
content: new Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: new TextField(
|
||||
autofocus: true,
|
||||
decoration: new InputDecoration(
|
||||
labelText: 'List Name', hintText: 'eg. Shopping List'),
|
||||
controller: textController,
|
||||
),
|
||||
)
|
||||
]),
|
||||
actions: <Widget>[
|
||||
new FlatButton(
|
||||
child: const Text('CANCEL'),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
new FlatButton(
|
||||
child: const Text('ADD'),
|
||||
onPressed: () {
|
||||
if (textController.text.isNotEmpty) {
|
||||
_addList(textController.text);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_addList(String name) {
|
||||
VikunjaGlobal.of(context)
|
||||
.listService
|
||||
.create(widget.namespace.id, TaskList(id: null, title: name, tasks: []))
|
||||
.then((_) => setState(() {}));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/api/list_implementation.dart';
|
||||
import 'package:fluttering_vikunja/api/namespace_implementation.dart';
|
||||
import 'package:fluttering_vikunja/api/task_implementation.dart';
|
||||
import 'package:fluttering_vikunja/api/user_implementation.dart';
|
||||
import 'package:fluttering_vikunja/managers/user.dart';
|
||||
import 'package:fluttering_vikunja/models/user.dart';
|
||||
@ -36,6 +39,9 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
||||
UserManager get userManager => new UserManager(_storage);
|
||||
UserService get userService => new UserAPIService(_client);
|
||||
UserService newLoginService(base) => new UserAPIService(Client(null, base));
|
||||
NamespaceService get namespaceService => new NamespaceAPIService(client);
|
||||
TaskService get taskService => new TaskAPIService(client);
|
||||
ListService get listService => new ListAPIService(client);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -84,12 +90,27 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
||||
});
|
||||
return;
|
||||
}
|
||||
var client = Client(token, base);
|
||||
var loadedCurrentUser;
|
||||
try {
|
||||
loadedCurrentUser = await UserAPIService(client).getCurrentUser();
|
||||
} on ApiException catch (e) {
|
||||
if (e.errorCode ~/ 100 == 4) {
|
||||
setState(() {
|
||||
_client = null;
|
||||
_currentUser = null;
|
||||
_loading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
loadedCurrentUser = User(int.tryParse(currentUser), "", "");
|
||||
} catch (otherExceptions) {
|
||||
loadedCurrentUser = User(int.tryParse(currentUser), "", "");
|
||||
}
|
||||
setState(() {
|
||||
_client = Client(token, base);
|
||||
});
|
||||
var loadedCurrentUser = await userService.getCurrentUser();
|
||||
setState(() {
|
||||
_client = client;
|
||||
_currentUser = loadedCurrentUser;
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -6,16 +6,21 @@ import 'package:fluttering_vikunja/pages/home_page.dart';
|
||||
import 'package:fluttering_vikunja/pages/login_page.dart';
|
||||
import 'package:fluttering_vikunja/style.dart';
|
||||
|
||||
void main() => runApp(new VikunjaApp());
|
||||
void main() => runApp(VikunjaGlobal(
|
||||
child: new VikunjaApp(home: HomePage()),
|
||||
login: new VikunjaApp(home: LoginPage())));
|
||||
|
||||
class VikunjaApp extends StatelessWidget {
|
||||
final Widget home;
|
||||
|
||||
const VikunjaApp({Key key, this.home}) : super(key: key);
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new MaterialApp(
|
||||
title: 'Vikunja',
|
||||
theme: buildVikunjaTheme(),
|
||||
home: VikunjaGlobal(child: new HomePage(), login: new LoginPage()),
|
||||
home: this.home,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,12 @@ class Namespace {
|
||||
created = DateTime.fromMillisecondsSinceEpoch(json['created']),
|
||||
updated = DateTime.fromMillisecondsSinceEpoch(json['updated']),
|
||||
owner = User.fromJson(json['owner']);
|
||||
|
||||
toJSON() => {
|
||||
"created": created?.millisecondsSinceEpoch,
|
||||
"updated": updated?.millisecondsSinceEpoch,
|
||||
"name": name,
|
||||
"owner": owner?.toJSON(),
|
||||
"description": description
|
||||
};
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class Task {
|
||||
this.due,
|
||||
@required this.text,
|
||||
this.description,
|
||||
this.done,
|
||||
@required this.done,
|
||||
@required this.owner});
|
||||
|
||||
Task.fromJson(Map<String, dynamic> json)
|
||||
@ -29,6 +29,18 @@ class Task {
|
||||
text = json['text'],
|
||||
done = json['done'],
|
||||
owner = User.fromJson(json['createdBy']);
|
||||
|
||||
toJSON() => {
|
||||
'id': id,
|
||||
'updated': updated?.millisecondsSinceEpoch,
|
||||
'created': created?.millisecondsSinceEpoch,
|
||||
'reminderDate': reminder?.millisecondsSinceEpoch,
|
||||
'dueDate': due?.millisecondsSinceEpoch,
|
||||
'description': description,
|
||||
'text': text,
|
||||
'done': done ?? false,
|
||||
'createdBy': owner?.toJSON()
|
||||
};
|
||||
}
|
||||
|
||||
class TaskList {
|
||||
@ -54,5 +66,17 @@ class TaskList {
|
||||
title = json['title'],
|
||||
updated = DateTime.fromMillisecondsSinceEpoch(json['updated']),
|
||||
created = DateTime.fromMillisecondsSinceEpoch(json['created']),
|
||||
tasks = json['tasks'].map((taskJson) => Task.fromJson(taskJson));
|
||||
tasks = (json['tasks'] as List<dynamic>)
|
||||
?.map((taskJson) => Task.fromJson(taskJson))
|
||||
?.toList();
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
"created": this.created?.millisecondsSinceEpoch,
|
||||
"updated": this.updated?.millisecondsSinceEpoch,
|
||||
"id": this.id,
|
||||
"title": this.title,
|
||||
"owner": this.owner?.toJSON()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ class User {
|
||||
: id = json['id'],
|
||||
email = json['email'],
|
||||
username = json['username'];
|
||||
|
||||
toJSON() => {"id": this.id, "email": this.email, "username": this.username};
|
||||
}
|
||||
|
||||
class UserTokenPair {
|
||||
|
@ -3,6 +3,8 @@ import 'package:fluttering_vikunja/components/GravatarImage.dart';
|
||||
import 'package:fluttering_vikunja/fragments/namespace.dart';
|
||||
import 'package:fluttering_vikunja/fragments/placeholder.dart';
|
||||
import 'package:fluttering_vikunja/global.dart';
|
||||
import 'package:fluttering_vikunja/models/namespace.dart';
|
||||
import 'package:fluttering_vikunja/models/task.dart';
|
||||
import 'package:fluttering_vikunja/models/user.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@ -11,14 +13,18 @@ class HomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class HomePageState extends State<HomePage> {
|
||||
List<String> namespaces = ["Jonas's namespace", 'Another namespace'];
|
||||
List<Namespace> _namespaces = [];
|
||||
Namespace get _currentNamespace =>
|
||||
_selectedDrawerIndex >= 0 && _selectedDrawerIndex < _namespaces.length
|
||||
? _namespaces[_selectedDrawerIndex]
|
||||
: null;
|
||||
int _selectedDrawerIndex = -1;
|
||||
|
||||
_getDrawerItemWidget(int pos) {
|
||||
if (pos == -1) {
|
||||
return new PlaceholderFragment();
|
||||
}
|
||||
return new NamespaceFragment(namespace: namespaces[pos]);
|
||||
return new NamespaceFragment(namespace: _namespaces[pos]);
|
||||
}
|
||||
|
||||
_onSelectItem(int index) {
|
||||
@ -26,7 +32,7 @@ class HomePageState extends State<HomePage> {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
_addNamespace() {
|
||||
_addNamespaceDialog() {
|
||||
var textController = new TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -50,8 +56,9 @@ class HomePageState extends State<HomePage> {
|
||||
new FlatButton(
|
||||
child: const Text('ADD'),
|
||||
onPressed: () {
|
||||
if (textController.text.isNotEmpty)
|
||||
setState(() => namespaces.add(textController.text));
|
||||
if (textController.text.isNotEmpty) {
|
||||
_addNamespace(textController.text);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
},
|
||||
)
|
||||
@ -60,28 +67,42 @@ class HomePageState extends State<HomePage> {
|
||||
);
|
||||
}
|
||||
|
||||
_addNamespace(String name) {
|
||||
VikunjaGlobal.of(context)
|
||||
.namespaceService
|
||||
.create(Namespace(id: null, name: name))
|
||||
.then((_) => _updateNamespaces());
|
||||
}
|
||||
|
||||
_updateNamespaces() {
|
||||
VikunjaGlobal.of(context).namespaceService.getAll().then((result) {
|
||||
setState(() {
|
||||
_namespaces = result;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_updateNamespaces();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var currentUser = VikunjaGlobal.of(context).currentUser;
|
||||
List<Widget> drawerOptions = <Widget>[];
|
||||
namespaces.asMap().forEach((i, namespace) => drawerOptions.add(new ListTile(
|
||||
leading: const Icon(Icons.folder),
|
||||
title: new Text(namespace),
|
||||
selected: i == _selectedDrawerIndex,
|
||||
onTap: () => _onSelectItem(i),
|
||||
)));
|
||||
_namespaces
|
||||
.asMap()
|
||||
.forEach((i, namespace) => drawerOptions.add(new ListTile(
|
||||
leading: const Icon(Icons.folder),
|
||||
title: new Text(namespace.name),
|
||||
selected: i == _selectedDrawerIndex,
|
||||
onTap: () => _onSelectItem(i),
|
||||
)));
|
||||
|
||||
return new Scaffold(
|
||||
appBar: AppBar(
|
||||
title: new Text(_selectedDrawerIndex == -1
|
||||
? 'Vakunja'
|
||||
: namespaces[_selectedDrawerIndex]),
|
||||
),
|
||||
appBar: AppBar(title: new Text(_currentNamespace?.name ?? 'Vakunja')),
|
||||
drawer: new Drawer(
|
||||
child: new Column(children: <Widget>[
|
||||
new UserAccountsDrawerHeader(
|
||||
@ -110,7 +131,7 @@ class HomePageState extends State<HomePage> {
|
||||
child: new ListTile(
|
||||
leading: const Icon(Icons.add),
|
||||
title: const Text('Add namespace...'),
|
||||
onTap: () => _addNamespace(),
|
||||
onTap: () => _addNamespaceDialog(),
|
||||
),
|
||||
),
|
||||
])),
|
||||
|
@ -1,46 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttering_vikunja/global.dart';
|
||||
import 'package:fluttering_vikunja/models/task.dart';
|
||||
|
||||
class ListPage extends StatefulWidget {
|
||||
final String listName;
|
||||
final TaskList taskList;
|
||||
|
||||
ListPage({this.listName}) : super(key: Key(listName));
|
||||
ListPage({this.taskList}) : super(key: Key(taskList.id.toString()));
|
||||
|
||||
@override
|
||||
_ListPageState createState() => _ListPageState();
|
||||
}
|
||||
|
||||
class _ListPageState extends State<ListPage> {
|
||||
Map<String, bool> items = {"Butter": true, "Milch": false};
|
||||
TaskList items;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
items = TaskList(
|
||||
id: widget.taskList.id, title: widget.taskList.title, tasks: []);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: new Text(widget.listName),
|
||||
title: new Text(items.title),
|
||||
),
|
||||
body: ListView(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
children: ListTile.divideTiles(
|
||||
context: context,
|
||||
tiles: items
|
||||
.map((item, checked) => MapEntry(
|
||||
item,
|
||||
CheckboxListTile(
|
||||
title: Text(item),
|
||||
tiles: items?.tasks?.map((task) => CheckboxListTile(
|
||||
title: Text(task.text),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
value: checked,
|
||||
onChanged: (bool value) =>
|
||||
setState(() => items[item] = value),
|
||||
)))
|
||||
.values)
|
||||
value: task.done ?? false,
|
||||
subtitle: task.description == null
|
||||
? null
|
||||
: Text(task.description),
|
||||
onChanged: (bool value) => _updateTask(task, value),
|
||||
)) ??
|
||||
[])
|
||||
.toList(),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => _addItem(), child: Icon(Icons.add)),
|
||||
onPressed: () => _addItemDialog(), child: Icon(Icons.add)),
|
||||
);
|
||||
}
|
||||
|
||||
_addItem() {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_updateList();
|
||||
}
|
||||
|
||||
_updateTask(Task task, bool checked) {
|
||||
// TODO use copyFrom
|
||||
VikunjaGlobal.of(context)
|
||||
.taskService
|
||||
.update(Task(
|
||||
id: task.id,
|
||||
done: checked,
|
||||
text: task.text,
|
||||
description: task.description,
|
||||
owner: null,
|
||||
))
|
||||
.then((_) => _updateList());
|
||||
}
|
||||
|
||||
_updateList() {
|
||||
VikunjaGlobal.of(context).listService.get(widget.taskList.id).then((tasks) {
|
||||
setState(() {
|
||||
items = tasks;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_addItemDialog() {
|
||||
var textController = new TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -64,8 +100,7 @@ class _ListPageState extends State<ListPage> {
|
||||
new FlatButton(
|
||||
child: const Text('ADD'),
|
||||
onPressed: () {
|
||||
if (textController.text.isNotEmpty)
|
||||
setState(() => items[textController.text] = false);
|
||||
if (textController.text.isNotEmpty) _addItem(textController.text);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
)
|
||||
@ -73,4 +108,21 @@ class _ListPageState extends State<ListPage> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_addItem(String name) {
|
||||
var globalState = VikunjaGlobal.of(context);
|
||||
globalState.taskService
|
||||
.add(
|
||||
items.id,
|
||||
Task(
|
||||
id: null,
|
||||
text: name,
|
||||
owner: globalState.currentUser,
|
||||
done: false))
|
||||
.then((task) {
|
||||
setState(() {
|
||||
items.tasks.add(task);
|
||||
});
|
||||
}).then((_) => _updateList());
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ var _lists = {
|
||||
1: TaskList(
|
||||
id: 1,
|
||||
title: 'List 1',
|
||||
tasks: _tasks.values,
|
||||
tasks: _tasks.values.toList(),
|
||||
owner: _users[1],
|
||||
description: 'A nice list',
|
||||
created: DateTime.now(),
|
||||
@ -81,7 +81,8 @@ class MockedNamespaceService implements NamespaceService {
|
||||
|
||||
class MockedListService implements ListService {
|
||||
@override
|
||||
Future<TaskList> create(TaskList tl) {
|
||||
Future<TaskList> create(namespaceId, TaskList tl) {
|
||||
_nsLists[namespaceId].add(tl.id);
|
||||
return Future.value(_lists[tl.id] = tl);
|
||||
}
|
||||
|
||||
@ -111,7 +112,7 @@ class MockedListService implements ListService {
|
||||
Future<TaskList> update(TaskList tl) {
|
||||
if (!_lists.containsKey(tl))
|
||||
throw Exception('TaskList ${tl.id} does not exists');
|
||||
return create(tl);
|
||||
return Future.value(_lists[tl.id] = tl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,8 +127,22 @@ class MockedTaskService implements TaskService {
|
||||
|
||||
@override
|
||||
Future<Task> update(Task task) {
|
||||
_lists.forEach((_, list) {
|
||||
if (list.tasks.where((t) => t.id == task.id).length > 0) {
|
||||
list.tasks.removeWhere((t) => t.id == task.id);
|
||||
list.tasks.add(task);
|
||||
}
|
||||
});
|
||||
return Future.value(_tasks[task.id] = task);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Task> add(int listId, Task task) {
|
||||
var id = _tasks.keys.last + 1;
|
||||
_tasks[id] = task;
|
||||
_lists[listId].tasks.add(task);
|
||||
return Future.value(task);
|
||||
}
|
||||
}
|
||||
|
||||
class MockedUserService implements UserService {
|
||||
|
@ -16,7 +16,7 @@ abstract class ListService {
|
||||
Future<List<TaskList>> getAll();
|
||||
Future<TaskList> get(int listId);
|
||||
Future<List<TaskList>> getByNamespace(int namespaceId);
|
||||
Future<TaskList> create(TaskList tl);
|
||||
Future<TaskList> create(int namespaceId, TaskList tl);
|
||||
Future<TaskList> update(TaskList tl);
|
||||
Future delete(int listId);
|
||||
}
|
||||
@ -24,6 +24,7 @@ abstract class ListService {
|
||||
abstract class TaskService {
|
||||
Future<Task> update(Task task);
|
||||
Future delete(int taskId);
|
||||
Future<Task> add(int listId, Task task);
|
||||
}
|
||||
|
||||
abstract class UserService {
|
||||
|
Loading…
x
Reference in New Issue
Block a user