format
continuous-integration/drone/pr Build is passing
Details
continuous-integration/drone/pr Build is passing
Details
This commit is contained in:
parent
fbd8efa2b2
commit
780ee537f6
|
@ -80,13 +80,13 @@ class _ListPageState extends State<ListPage> {
|
||||||
task: task,
|
task: task,
|
||||||
loading: false,
|
loading: false,
|
||||||
onEdit: () => Navigator.push(
|
onEdit: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => TaskEditPage(
|
builder: (context) => TaskEditPage(
|
||||||
task: task,
|
task: task,
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
onMarkedAsDone: (done) {
|
onMarkedAsDone: (done) {
|
||||||
VikunjaGlobal.of(context)
|
VikunjaGlobal.of(context)
|
||||||
.taskService
|
.taskService
|
||||||
|
@ -112,13 +112,13 @@ class _ListPageState extends State<ListPage> {
|
||||||
task: task,
|
task: task,
|
||||||
loading: true,
|
loading: true,
|
||||||
onEdit: () => Navigator.push(
|
onEdit: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => TaskEditPage(
|
builder: (context) => TaskEditPage(
|
||||||
task: task,
|
task: task,
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,248 +57,240 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||||
),
|
),
|
||||||
body: Builder(
|
body: Builder(
|
||||||
builder: (BuildContext context) => SafeArea(
|
builder: (BuildContext context) => SafeArea(
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: ListView(padding: const EdgeInsets.all(16.0), children: <
|
child: ListView(padding: const EdgeInsets.all(16.0), children: <
|
||||||
Widget>[
|
Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
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,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
maxLines: null,
|
keyboardType: TextInputType.number,
|
||||||
keyboardType: TextInputType.multiline,
|
initialValue: getRepeatAfterValueFromDuration(
|
||||||
initialValue: widget.task.text,
|
widget.task.repeatAfter)
|
||||||
onSaved: (text) => _text = text,
|
?.toString(),
|
||||||
validator: (text) {
|
onSaved: (repeatAfter) => _repeatAfter =
|
||||||
if (text.length < 3 || text.length > 250) {
|
getDurationFromType(repeatAfter, _repeatAfterType),
|
||||||
return 'The text needs to have between 3 and 250 characters.';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
decoration: new InputDecoration(
|
decoration: new InputDecoration(
|
||||||
labelText: 'Text',
|
labelText: 'Repeat after',
|
||||||
border: OutlineInputBorder(),
|
border: InputBorder.none,
|
||||||
|
icon: Icon(Icons.repeat),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Expanded(
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
child: DropdownButton<String>(
|
||||||
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,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: TextFormField(
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
initialValue: getRepeatAfterValueFromDuration(
|
|
||||||
widget.task.repeatAfter)
|
|
||||||
?.toString(),
|
|
||||||
onSaved: (repeatAfter) => _repeatAfter =
|
|
||||||
getDurationFromType(
|
|
||||||
repeatAfter, _repeatAfterType),
|
|
||||||
decoration: new InputDecoration(
|
|
||||||
labelText: 'Repeat after',
|
|
||||||
border: InputBorder.none,
|
|
||||||
icon: Icon(Icons.repeat),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: DropdownButton<String>(
|
|
||||||
isExpanded: true,
|
|
||||||
isDense: true,
|
|
||||||
value: _repeatAfterType ??
|
|
||||||
getRepeatAfterTypeFromDuration(
|
|
||||||
widget.task.repeatAfter),
|
|
||||||
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(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: _reminderInputs,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 10),
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(right: 15, left: 2),
|
|
||||||
child: Icon(
|
|
||||||
Icons.alarm_add,
|
|
||||||
color: Colors.grey,
|
|
||||||
)),
|
|
||||||
Text(
|
|
||||||
'Add a reminder',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.grey,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
// We add a new entry every time we add a new input, to make sure all inputs have a place where they can put their value.
|
|
||||||
_reminderDates.add(null);
|
|
||||||
var currentIndex = _reminderDates.length - 1;
|
|
||||||
|
|
||||||
// FIXME: Why does putting this into a row fails?
|
|
||||||
setState(() => _reminderInputs.add(Row(
|
|
||||||
children: <Widget>[
|
|
||||||
VikunjaDateTimePicker(
|
|
||||||
label: 'Reminder',
|
|
||||||
onSaved: (reminder) =>
|
|
||||||
_reminderDates[currentIndex] = reminder,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () => print('tapped'),
|
|
||||||
child: Icon(Icons.close),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)));
|
|
||||||
}),
|
|
||||||
InputDecorator(
|
|
||||||
isEmpty: _priority == null,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
icon: const Icon(Icons.flag),
|
|
||||||
labelText: 'Priority',
|
|
||||||
border: InputBorder.none,
|
|
||||||
),
|
|
||||||
child: new DropdownButton<String>(
|
|
||||||
value: _priorityToString(_priority),
|
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
isDense: true,
|
isDense: true,
|
||||||
|
value: _repeatAfterType ??
|
||||||
|
getRepeatAfterTypeFromDuration(
|
||||||
|
widget.task.repeatAfter),
|
||||||
onChanged: (String newValue) {
|
onChanged: (String newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_priority = _priorityFromString(newValue);
|
_repeatAfterType = newValue;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: [
|
items: <String>[
|
||||||
'Unset',
|
'Hours',
|
||||||
'Low',
|
'Days',
|
||||||
'Medium',
|
'Weeks',
|
||||||
'High',
|
'Months',
|
||||||
'Urgent',
|
'Years'
|
||||||
'DO NOW'
|
].map<DropdownMenuItem<String>>((String value) {
|
||||||
].map((String value) {
|
return DropdownMenuItem<String>(
|
||||||
return new DropdownMenuItem(
|
|
||||||
value: value,
|
value: value,
|
||||||
child: new Text(value),
|
child: Text(value),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Wrap(
|
],
|
||||||
spacing: 10,
|
|
||||||
children: _labels.map((Label label) {
|
|
||||||
return LabelComponent(
|
|
||||||
label: label,
|
|
||||||
onDelete: () {
|
|
||||||
_removeLabel(label);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}).toList()),
|
|
||||||
Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
width: MediaQuery.of(context).size.width - 80,
|
|
||||||
child: TypeAheadFormField(
|
|
||||||
textFieldConfiguration: TextFieldConfiguration(
|
|
||||||
controller: _labelTypeAheadController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'Add a new label')),
|
|
||||||
suggestionsCallback: (pattern) {
|
|
||||||
return _searchLabel(pattern);
|
|
||||||
},
|
|
||||||
itemBuilder: (context, suggestion) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(suggestion),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
transitionBuilder:
|
|
||||||
(context, suggestionsBox, controller) {
|
|
||||||
return suggestionsBox;
|
|
||||||
},
|
|
||||||
onSuggestionSelected: (suggestion) {
|
|
||||||
_addLabel(suggestion);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () =>
|
|
||||||
_createAndAddLabel(_labelTypeAheadController.text),
|
|
||||||
icon: Icon(Icons.add),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
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'),
|
|
||||||
))),
|
|
||||||
]),
|
|
||||||
),
|
),
|
||||||
),
|
Column(
|
||||||
|
children: _reminderInputs,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(right: 15, left: 2),
|
||||||
|
child: Icon(
|
||||||
|
Icons.alarm_add,
|
||||||
|
color: Colors.grey,
|
||||||
|
)),
|
||||||
|
Text(
|
||||||
|
'Add a reminder',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.grey,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
// We add a new entry every time we add a new input, to make sure all inputs have a place where they can put their value.
|
||||||
|
_reminderDates.add(null);
|
||||||
|
var currentIndex = _reminderDates.length - 1;
|
||||||
|
|
||||||
|
// FIXME: Why does putting this into a row fails?
|
||||||
|
setState(() => _reminderInputs.add(Row(
|
||||||
|
children: <Widget>[
|
||||||
|
VikunjaDateTimePicker(
|
||||||
|
label: 'Reminder',
|
||||||
|
onSaved: (reminder) =>
|
||||||
|
_reminderDates[currentIndex] = reminder,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => print('tapped'),
|
||||||
|
child: Icon(Icons.close),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)));
|
||||||
|
}),
|
||||||
|
InputDecorator(
|
||||||
|
isEmpty: _priority == null,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
icon: const Icon(Icons.flag),
|
||||||
|
labelText: 'Priority',
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
child: new DropdownButton<String>(
|
||||||
|
value: _priorityToString(_priority),
|
||||||
|
isExpanded: true,
|
||||||
|
isDense: true,
|
||||||
|
onChanged: (String newValue) {
|
||||||
|
setState(() {
|
||||||
|
_priority = _priorityFromString(newValue);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items: ['Unset', 'Low', 'Medium', 'High', 'Urgent', 'DO NOW']
|
||||||
|
.map((String value) {
|
||||||
|
return new DropdownMenuItem(
|
||||||
|
value: value,
|
||||||
|
child: new Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
spacing: 10,
|
||||||
|
children: _labels.map((Label label) {
|
||||||
|
return LabelComponent(
|
||||||
|
label: label,
|
||||||
|
onDelete: () {
|
||||||
|
_removeLabel(label);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}).toList()),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.of(context).size.width - 80,
|
||||||
|
child: TypeAheadFormField(
|
||||||
|
textFieldConfiguration: TextFieldConfiguration(
|
||||||
|
controller: _labelTypeAheadController,
|
||||||
|
decoration:
|
||||||
|
InputDecoration(labelText: 'Add a new label')),
|
||||||
|
suggestionsCallback: (pattern) {
|
||||||
|
return _searchLabel(pattern);
|
||||||
|
},
|
||||||
|
itemBuilder: (context, suggestion) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(suggestion),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
transitionBuilder: (context, suggestionsBox, controller) {
|
||||||
|
return suggestionsBox;
|
||||||
|
},
|
||||||
|
onSuggestionSelected: (suggestion) {
|
||||||
|
_addLabel(suggestion);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () =>
|
||||||
|
_createAndAddLabel(_labelTypeAheadController.text),
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
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'),
|
||||||
|
))),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue