List edit #21
|
@ -46,10 +46,11 @@ class TaskTileState extends State<TaskTile> {
|
|||
_currentTask.description == null || _currentTask.description.isEmpty
|
||||
? null
|
||||
: Text(_currentTask.description),
|
||||
trailing: IconButton(icon: Icon(Icons.settings), onPressed: () {
|
||||
print("test");
|
||||
}
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: Icon(Icons.settings),
|
||||
|
||||
onPressed: () {
|
||||
print("test");
|
||||
}),
|
||||
);
|
||||
}
|
||||
return CheckboxListTile(
|
||||
|
|
|
@ -3,40 +3,40 @@ import 'package:vikunja_app/models/task.dart';
|
|||
import 'package:vikunja_app/models/user.dart';
|
||||
|
||||
class TaskList {
|
||||
final int id;
|
||||
final String title, description;
|
||||
final User owner;
|
||||
final DateTime created, updated;
|
||||
final List<Task> tasks;
|
||||
final int id;
|
||||
final String title, description;
|
||||
final User owner;
|
||||
final DateTime created, updated;
|
||||
final List<Task> tasks;
|
||||
|
||||
TaskList(
|
||||
{@required this.id,
|
||||
@required this.title,
|
||||
this.description,
|
||||
this.owner,
|
||||
this.created,
|
||||
this.updated,
|
||||
this.tasks});
|
||||
TaskList(
|
||||
{@required this.id,
|
||||
@required this.title,
|
||||
this.description,
|
||||
this.owner,
|
||||
this.created,
|
||||
this.updated,
|
||||
this.tasks});
|
||||
|
||||
TaskList.fromJson(Map<String, dynamic> json)
|
||||
: id = json['id'],
|
||||
owner = User.fromJson(json['owner']),
|
||||
description = json['description'],
|
||||
title = json['title'],
|
||||
updated = DateTime.fromMillisecondsSinceEpoch(json['updated']),
|
||||
created = DateTime.fromMillisecondsSinceEpoch(json['created']),
|
||||
tasks = (json['tasks'] as List<dynamic>)
|
||||
?.map((taskJson) => Task.fromJson(taskJson))
|
||||
?.toList();
|
||||
TaskList.fromJson(Map<String, dynamic> json)
|
||||
: id = json['id'],
|
||||
owner = User.fromJson(json['owner']),
|
||||
description = json['description'],
|
||||
title = json['title'],
|
||||
updated = DateTime.fromMillisecondsSinceEpoch(json['updated']),
|
||||
created = DateTime.fromMillisecondsSinceEpoch(json['created']),
|
||||
tasks = (json['tasks'] as List<dynamic>)
|
||||
?.map((taskJson) => Task.fromJson(taskJson))
|
||||
?.toList();
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
"id": this.id,
|
||||
"title": this.title,
|
||||
"description": this.description,
|
||||
"owner": this.owner?.toJSON(),
|
||||
"created": this.created?.millisecondsSinceEpoch,
|
||||
"updated": this.updated?.millisecondsSinceEpoch,
|
||||
};
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
"id": this.id,
|
||||
"title": this.title,
|
||||
"description": this.description,
|
||||
"owner": this.owner?.toJSON(),
|
||||
"created": this.created?.millisecondsSinceEpoch,
|
||||
JonasFranz
commented
Wrong indention, make format Wrong indention, make format
|
||||
"updated": this.updated?.millisecondsSinceEpoch,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,5 +46,3 @@ class Task {
|
|||
'createdBy': owner?.toJSON()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,130 +3,120 @@ import 'package:vikunja_app/global.dart';
|
|||
import 'package:vikunja_app/models/list.dart';
|
||||
|
||||
class ListEditPage extends StatefulWidget {
|
||||
final TaskList list;
|
||||
final TaskList list;
|
||||
|
||||
ListEditPage({this.list}) : super(key: Key(list.toString()));
|
||||
ListEditPage({this.list}) : super(key: Key(list.toString()));
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ListEditPageState();
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ListEditPageState();
|
||||
}
|
||||
|
||||
class _ListEditPageState extends State<ListEditPage> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
bool _loading = false;
|
||||
String _title, _description;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
bool _loading = false;
|
||||
String _title, _description;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext ctx) {
|
||||
@override
|
||||
Widget build(BuildContext ctx) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Edit List'),
|
||||
),
|
||||
body: Builder(
|
||||
builder: (BuildContext context) => SafeArea(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: TextFormField(
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType.multiline,
|
||||
initialValue: widget.list.title,
|
||||
onSaved: (title) => _title = title,
|
||||
validator: (title) {
|
||||
if (title.length < 3 || title.length > 250) {
|
||||
return 'The title needs to have between 3 and 250 characters.';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration:
|
||||
new InputDecoration(labelText: 'Title'),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: TextFormField(
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType.multiline,
|
||||
initialValue: widget.list.description,
|
||||
onSaved: (description) =>
|
||||
_description = description,
|
||||
validator: (description) {
|
||||
if (description.length > 1000) {
|
||||
return 'The description can have a maximum of 1000 characters.';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: new InputDecoration(
|
||||
labelText: 'Description'),
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (context) => RaisedButton(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 10.0),
|
||||
onPressed: !_loading
|
||||
? () {
|
||||
if (_formKey.currentState
|
||||
.validate()) {
|
||||
Form.of(context)
|
||||
.save(); // Why does this not work?
|
||||
_saveList(context);
|
||||
} else {
|
||||
print(
|
||||
"sdf"); // TODO: handle error
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: _loading
|
||||
? CircularProgressIndicator()
|
||||
: Text('Save'),
|
||||
)),
|
||||
])),
|
||||
)));
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Edit List'),
|
||||
),
|
||||
body: Builder(
|
||||
builder: (BuildContext context) =>
|
||||
SafeArea(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0),
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: TextFormField(
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType.multiline,
|
||||
initialValue: widget.list.title,
|
||||
onSaved: (title) => _title = title,
|
||||
validator: (title) {
|
||||
if (title.length < 3 || title.length > 250) {
|
||||
return 'The title needs to have between 3 and 250 characters.';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration:
|
||||
new InputDecoration(labelText: 'Title'),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: TextFormField(
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType.multiline,
|
||||
initialValue: widget.list.description,
|
||||
onSaved: (description) => _description = description,
|
||||
validator: (description) {
|
||||
if (description.length > 1000) {
|
||||
return 'The description can have a maximum of 1000 characters.';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration:
|
||||
new InputDecoration(labelText: 'Description'),
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (context) => RaisedButton(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
onPressed: !_loading
|
||||
? () {
|
||||
if (_formKey.currentState
|
||||
.validate()) {
|
||||
Form.of(context).save(); // Why does this not work?
|
||||
_saveList(context);
|
||||
} else {
|
||||
print("sdf"); // TODO: handle error
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: _loading
|
||||
? CircularProgressIndicator()
|
||||
: Text('Save'),
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
_saveList(BuildContext context) async {
|
||||
setState(() => _loading = true);
|
||||
// FIXME: Do we need the try/catch block or is .then .catch .finally enough?
|
||||
try {
|
||||
JonasFranz
commented
That's not possible. You may add a function like copyWith(...) as helper. But this may be to big for the problem. That's not possible. You may add a function like copyWith(...) as helper. But this may be to big for the problem.
konrad
commented
I see, thanks! I see, thanks!
konrad
commented
I see, thanks! I see, thanks!
|
||||
// FIXME: is there a way we can update the list without creating a new list object?
|
||||
// aka updating the existing list we got from context (setters?)
|
||||
TaskList updatedList = TaskList(
|
||||
id: widget.list.id, title: _title, description: _description);
|
||||
|
||||
_saveList(BuildContext context) async {
|
||||
setState(() => _loading = true);
|
||||
// FIXME: Do we need the try/catch block or is .then .catch .finally enough?
|
||||
try {
|
||||
// FIXME: is there a way we can update the list without creating a new list object?
|
||||
// aka updating the existing list we got from context (setters?)
|
||||
TaskList updatedList = TaskList(
|
||||
id: widget.list.id,
|
||||
title: _title,
|
||||
description: _description
|
||||
);
|
||||
|
||||
// FIXME: When the api returns an error (status code != 2xx), this throws an exception
|
||||
VikunjaGlobal.of(context).listService.update(updatedList)
|
||||
.then((_) {
|
||||
setState(() {});
|
||||
final scaffold = Scaffold.of(context);
|
||||
scaffold.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('The list was updated successfully!'),
|
||||
)
|
||||
);
|
||||
}); // TODO: show the user a message the list was updated successfully
|
||||
} catch(err) {
|
||||
final scaffold = Scaffold.of(context);
|
||||
scaffold.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Something went wrong: ' + err.toString()),
|
||||
action: SnackBarAction(
|
||||
label: 'CLOSE', onPressed: scaffold.hideCurrentSnackBar),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
setState(() => _loading = false);
|
||||
}
|
||||
}
|
||||
// FIXME: When the api returns an error (status code != 2xx), this throws an exception
|
||||
VikunjaGlobal.of(context).listService.update(updatedList).then((_) {
|
||||
setState(() {});
|
||||
final scaffold = Scaffold.of(context);
|
||||
scaffold.showSnackBar(SnackBar(
|
||||
content: Text('The list was updated successfully!'),
|
||||
));
|
||||
}); // TODO: show the user a message the list was updated successfully
|
||||
} catch (err) {
|
||||
final scaffold = Scaffold.of(context);
|
||||
scaffold.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Something went wrong: ' + err.toString()),
|
||||
action: SnackBarAction(
|
||||
label: 'CLOSE', onPressed: scaffold.hideCurrentSnackBar),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
setState(() => _loading = false);
|
||||
JonasFranz
commented
catch won't work here. You should use .catch instead catch won't work here. You should use .catch instead
konrad
commented
If I do this, is the whole If I do this, is the whole `try` `catch` block still nessecary?
JonasFranz
commented
No, it's not since the that stuff is asynchron and will finish after the function already returned. No, it's not since the that stuff is asynchron and will finish after the function already returned.
konrad
commented
Done. Done.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,12 +42,13 @@ class _ListPageState extends State<ListPage> {
|
|||
title: new Text(_list.title),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => ListEditPage(list: _list,))
|
||||
)
|
||||
)
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEditPage(
|
||||
list: _list,
|
||||
))))
|
||||
],
|
||||
),
|
||||
body: !this._loading
|
||||
|
|
Reference in New Issue
Block a user
Unrelated change