234 lines
9.3 KiB
Dart
234 lines
9.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:vikunja_app/components/datetimePicker.dart';
|
|
|
|
import 'package:vikunja_app/global.dart';
|
|
import 'package:vikunja_app/models/label.dart';
|
|
import 'package:vikunja_app/models/task.dart';
|
|
import 'package:vikunja_app/theme/button.dart';
|
|
import 'package:vikunja_app/theme/buttonText.dart';
|
|
import 'package:vikunja_app/theme/constants.dart';
|
|
import 'package:vikunja_app/utils/repeat_after_parse.dart';
|
|
|
|
class TaskEditPage extends StatefulWidget {
|
|
final Task task;
|
|
|
|
TaskEditPage({this.task}) : super(key: Key(task.toString()));
|
|
|
|
@override
|
|
State<StatefulWidget> createState() => _TaskEditPageState();
|
|
}
|
|
|
|
class _TaskEditPageState extends State<TaskEditPage> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
bool _loading = false;
|
|
final dateFormat = DateFormat("EEEE, MMMM d, yyyy 'at' h:mma");
|
|
|
|
int _parentTaskID, _priority, _repeatAfterValue;
|
|
DateTime _dueDate, _startDate, _endDate;
|
|
List<DateTime> _reminderDates;
|
|
String _text, _description, _repeatAfterType;
|
|
Duration _repeatAfter;
|
|
List<Task> _subtasks;
|
|
List<Label> _labels;
|
|
|
|
@override
|
|
Widget build(BuildContext ctx) {
|
|
_repeatAfterType = getRepeatAfterTypeFromDuration(widget.task.repeatAfter);
|
|
_repeatAfterValue = getRepeatAfterValueFromDuration(widget.task.repeatAfter);
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text('Edit Task'),
|
|
),
|
|
body: Builder(
|
|
builder: (BuildContext context) => SafeArea(
|
|
child: Form(
|
|
key: _formKey,
|
|
child: ListView(
|
|
padding: const EdgeInsets.all(16.0),
|
|
children: <Widget>[
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 10.0),
|
|
child: TextFormField(
|
|
maxLines: null,
|
|
keyboardType: TextInputType.multiline,
|
|
initialValue: widget.task.text,
|
|
onSaved: (text) => _text = text,
|
|
validator: (text) {
|
|
if (text.length < 3 || text.length > 250) {
|
|
return 'The text needs to have between 3 and 250 characters.';
|
|
}
|
|
return null;
|
|
},
|
|
decoration: new InputDecoration(
|
|
labelText: 'Text',
|
|
border: OutlineInputBorder(),
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 10.0),
|
|
child: TextFormField(
|
|
maxLines: null,
|
|
keyboardType: TextInputType.multiline,
|
|
initialValue: widget.task.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',
|
|
border: OutlineInputBorder(),
|
|
),
|
|
),
|
|
),
|
|
VikunjaDateTimePicker(
|
|
icon: Icon(Icons.access_time),
|
|
label: 'Due Date',
|
|
initialValue: widget.task.dueDate,
|
|
onSaved: (duedate) => _dueDate = duedate,
|
|
),
|
|
VikunjaDateTimePicker(
|
|
label: 'Start Date',
|
|
initialValue: widget.task.startDate,
|
|
onSaved: (startDate) => _startDate = startDate,
|
|
),
|
|
VikunjaDateTimePicker(
|
|
label: 'End Date',
|
|
initialValue: widget.task.endDate,
|
|
onSaved: (endDate) => _endDate = endDate,
|
|
),
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 10.0),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
flex: 2,
|
|
child: TextFormField(
|
|
keyboardType: TextInputType.number,
|
|
initialValue: _repeatAfterValue == null
|
|
? null
|
|
: _repeatAfterValue.toString(),
|
|
onSaved: (repeatAfter) => _repeatAfter =
|
|
_makeDurationFromType(
|
|
repeatAfter, _repeatAfterType),
|
|
decoration: new InputDecoration(
|
|
labelText: 'Repeat after',
|
|
border: InputBorder.none,
|
|
icon: Icon(Icons.repeat),
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: DropdownButton<String>(
|
|
isExpanded: true,
|
|
value: _repeatAfterType,
|
|
onChanged: (String newValue) {
|
|
setState(() {
|
|
_repeatAfterType = newValue;
|
|
});
|
|
},
|
|
items: <String>[
|
|
'Hours',
|
|
'Days',
|
|
'Weeks',
|
|
'Months',
|
|
'Years'
|
|
].map<DropdownMenuItem<String>>((String value) {
|
|
return DropdownMenuItem<String>(
|
|
value: value,
|
|
child: Text(value),
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Builder(
|
|
builder: (context) => Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 10.0),
|
|
child: FancyButton(
|
|
onPressed: !_loading
|
|
? () {
|
|
if (_formKey.currentState.validate()) {
|
|
Form.of(context).save();
|
|
_saveTask(context);
|
|
}
|
|
}
|
|
: null,
|
|
child: _loading
|
|
? CircularProgressIndicator()
|
|
: VikunjaButtonText('Save'),
|
|
))),
|
|
]),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
_saveTask(BuildContext context) async {
|
|
setState(() => _loading = true);
|
|
// FIXME: is there a way we can update the task without creating a new task object?
|
|
// aka updating the existing task we got from context (setters?)
|
|
Task updatedTask = Task(
|
|
id: widget.task.id,
|
|
text: _text,
|
|
description: _description,
|
|
done: widget.task.done,
|
|
reminderDates: _reminderDates,
|
|
dueDate: _dueDate,
|
|
startDate: _startDate,
|
|
endDate: _endDate,
|
|
priority: _priority,
|
|
repeatAfter: _repeatAfter,
|
|
labels: _labels,
|
|
);
|
|
|
|
VikunjaGlobal.of(context).taskService.update(updatedTask).then((_) {
|
|
setState(() => _loading = false);
|
|
Scaffold.of(context).showSnackBar(SnackBar(
|
|
content: Text('The task was updated successfully!'),
|
|
));
|
|
}).catchError((err) {
|
|
setState(() => _loading = false);
|
|
Scaffold.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Something went wrong: ' + err.toString()),
|
|
action: SnackBarAction(
|
|
label: 'CLOSE',
|
|
onPressed: Scaffold.of(context).hideCurrentSnackBar),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
_makeDurationFromType(String value, String type) {
|
|
// Return an empty duration if either of the values is not set
|
|
if (value == null || value == '' || type == null || type == '') {
|
|
return Duration();
|
|
}
|
|
|
|
int val = int.parse(value);
|
|
|
|
switch (type) {
|
|
case 'Hours':
|
|
return Duration(seconds: val * 60);
|
|
case 'Days':
|
|
return Duration(seconds: val * 60 * 24);
|
|
case 'Weeks':
|
|
return Duration(seconds: val * 60 * 24 * 7);
|
|
case 'Months':
|
|
return Duration(seconds: val * 60 * 24 * 7 * 30);
|
|
case 'Years':
|
|
return Duration(seconds: val * 60 * 24 * 7 * 365);
|
|
}
|
|
}
|
|
}
|