1
0
mirror of https://github.com/go-vikunja/app synced 2024-06-14 08:24:18 +00:00

edit task color, update edited task, some cleanup

This commit is contained in:
Paul Nettleton 2022-07-27 13:10:01 -05:00
parent 5d6120a7ac
commit c3a7962679
7 changed files with 403 additions and 258 deletions

View File

@ -174,12 +174,14 @@ class _BucketTaskCardState extends State<BucketTaskCard> {
), ),
), ),
), ),
onTap: () => Navigator.push( onTap: () => Navigator.push<Task>(
context, context,
MaterialPageRoute(builder: (context) => TaskEditPage( MaterialPageRoute(builder: (context) => TaskEditPage(
task: _currentTask, task: _currentTask,
)), )),
), ).then((task) => setState(() {
if (task != null) _currentTask = task;
})),
), ),
); );
} }

View File

@ -81,14 +81,16 @@ class TaskTileState extends State<TaskTile> {
: Text(_currentTask.description), : Text(_currentTask.description),
secondary: secondary:
IconButton(icon: Icon(Icons.settings), onPressed: () { IconButton(icon: Icon(Icons.settings), onPressed: () {
Navigator.push( Navigator.push<Task>(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => TaskEditPage( builder: (context) => TaskEditPage(
task: _currentTask, task: _currentTask,
))).whenComplete(() { ),
widget.onEdit(); ),
}); ).then((task) => setState(() {
if (task != null) _currentTask = task;
})).whenComplete(() => widget.onEdit());
}), }),
onChanged: _change, onChanged: _change,
); );
@ -107,15 +109,9 @@ class TaskTileState extends State<TaskTile> {
} }
Future<Task> _updateTask(Task task, bool checked) { Future<Task> _updateTask(Task task, bool checked) {
// TODO use copyFrom return VikunjaGlobal.of(context).taskService.update(task.copyWith(
return VikunjaGlobal.of(context).taskService.update(Task( done: checked,
id: task.id, ));
done: checked,
title: task.title,
description: task.description,
createdBy: task.createdBy,
dueDate: task.dueDate
));
} }
} }

View File

@ -107,4 +107,42 @@ class Task {
Color get textColor => color != null Color get textColor => color != null
? color.computeLuminance() > 0.5 ? Colors.black : Colors.white ? color.computeLuminance() > 0.5 ? Colors.black : Colors.white
: null; : null;
Task copyWith({
int id, int parentTaskId, int priority, int listId, int bucketId,
DateTime created, DateTime updated, DateTime dueDate, DateTime startDate, DateTime endDate,
List<DateTime> reminderDates,
String title, String description,
bool done,
Color color,
bool resetColor,
User createdBy,
Duration repeatAfter,
List<Task> subtasks,
List<Label> labels,
List<TaskAttachment> attachments,
}) {
return Task(
id: id ?? this.id,
parentTaskId: parentTaskId ?? this.parentTaskId,
priority: priority ?? this.priority,
listId: listId ?? this.listId,
bucketId: bucketId ?? this.bucketId,
created: created ?? this.created,
updated: updated ?? this.updated,
dueDate: dueDate ?? this.dueDate,
startDate: startDate ?? this.startDate,
endDate: endDate ?? this.endDate,
reminderDates: reminderDates ?? this.reminderDates,
title: title ?? this.title,
description: description ?? this.description,
done: done ?? this.done,
color: (resetColor ?? false) ? null : color ?? this.color,
createdBy: createdBy ?? this.createdBy,
repeatAfter: repeatAfter ?? this.repeatAfter,
subtasks: subtasks ?? this.subtasks,
labels: labels ?? this.labels,
attachments: attachments ?? this.attachments,
);
}
} }

View File

@ -224,14 +224,16 @@ class _ListPageState extends State<ListPage> {
onReorderStart: (oldIndex) => setState(() => _draggedBucketIndex = oldIndex), onReorderStart: (oldIndex) => setState(() => _draggedBucketIndex = oldIndex),
onReorder: (oldIndex, newIndex) {}, onReorder: (oldIndex, newIndex) {},
onReorderEnd: (newIndex) => setState(() { onReorderEnd: (newIndex) => setState(() {
if (newIndex > _draggedBucketIndex) newIndex -= 1;
taskState.buckets.insert(newIndex, taskState.buckets.removeAt(_draggedBucketIndex));
bool indexUpdated = false; bool indexUpdated = false;
if (newIndex > _draggedBucketIndex) {
newIndex -= 1;
indexUpdated = true;
}
taskState.buckets.insert(newIndex, taskState.buckets.removeAt(_draggedBucketIndex));
if (newIndex == 0) { if (newIndex == 0) {
taskState.buckets[0].position = 0; taskState.buckets[0].position = 0;
_updateBucket(context, taskState.buckets[0]); _updateBucket(context, taskState.buckets[0]);
newIndex = 1; newIndex = 1;
indexUpdated = true;
} }
taskState.buckets[newIndex].position = newIndex == taskState.buckets.length - 1 taskState.buckets[newIndex].position = newIndex == taskState.buckets.length - 1
? taskState.buckets[newIndex - 1].position + 1 ? taskState.buckets[newIndex - 1].position + 1
@ -239,7 +241,9 @@ class _ListPageState extends State<ListPage> {
+ taskState.buckets[newIndex + 1].position) / 2.0; + taskState.buckets[newIndex + 1].position) / 2.0;
_updateBucket(context, taskState.buckets[newIndex]); _updateBucket(context, taskState.buckets[newIndex]);
_draggedBucketIndex = null; _draggedBucketIndex = null;
_pageController.jumpToPage(indexUpdated ? 0 : newIndex); if (indexUpdated)
_pageController.jumpToPage((newIndex
/ (deviceData.orientation == Orientation.portrait ? 1 : 2)).floor());
}), }),
); );
} }

View File

@ -2,13 +2,12 @@ import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:vikunja_app/components/datetimePicker.dart'; import 'package:vikunja_app/components/datetimePicker.dart';
import 'package:vikunja_app/components/label.dart'; import 'package:vikunja_app/components/label.dart';
import 'package:vikunja_app/global.dart'; import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/label.dart'; import 'package:vikunja_app/models/label.dart';
import 'package:vikunja_app/models/task.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/utils/repeat_after_parse.dart'; import 'package:vikunja_app/utils/repeat_after_parse.dart';
class TaskEditPage extends StatefulWidget { class TaskEditPage extends StatefulWidget {
@ -22,6 +21,7 @@ class TaskEditPage extends StatefulWidget {
class _TaskEditPageState extends State<TaskEditPage> { class _TaskEditPageState extends State<TaskEditPage> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _listKey = GlobalKey();
bool _loading = false; bool _loading = false;
bool _changed = false; bool _changed = false;
@ -35,6 +35,9 @@ class _TaskEditPageState extends State<TaskEditPage> {
List<Label> _suggestedLabels; List<Label> _suggestedLabels;
var _reminderInputs = <Widget>[]; var _reminderInputs = <Widget>[];
final _labelTypeAheadController = TextEditingController(); final _labelTypeAheadController = TextEditingController();
Color _color;
Color _pickerColor;
bool _resetColor = false;
@override @override
Widget build(BuildContext ctx) { Widget build(BuildContext ctx) {
@ -44,282 +47,322 @@ class _TaskEditPageState extends State<TaskEditPage> {
_reminderDates?.asMap()?.forEach((i, time) => _reminderDates?.asMap()?.forEach((i, time) =>
setState(() => _reminderInputs?.add(VikunjaDateTimePicker( setState(() => _reminderInputs?.add(VikunjaDateTimePicker(
initialValue: time, initialValue: time,
label: 'Reminder', label: 'Reminder',
onSaved: (reminder) => _reminderDates[i] = reminder, onSaved: (reminder) => _reminderDates[i] = reminder,
)))); )))
);
} }
if (_labels == null) { if (_labels == null) {
_labels = widget.task.labels ?? []; _labels = widget.task.labels ?? [];
} }
return WillPopScope(onWillPop: () { return WillPopScope(
if(_changed) { onWillPop: () {
return _showConfirmationDialog(); if(_changed) {
} return _showConfirmationDialog();
return new Future(() => true); }
}, return new Future(() => true);
child: Scaffold( },
appBar: AppBar( child: Scaffold(
title: Text('Edit Task'), appBar: AppBar(
), title: Text('Edit Task'),
body: Builder( ),
builder: (BuildContext context) => SafeArea( body: Builder(
child: Form( builder: (BuildContext context) => SafeArea(
key: _formKey, child: Form(
child: ListView(padding: const EdgeInsets.all(16.0), children: < key: _formKey,
Widget>[ child: ListView(
Padding( key: _listKey,
padding: EdgeInsets.symmetric(vertical: 10.0), padding: const EdgeInsets.all(16.0),
child: TextFormField( children: <Widget>[
maxLines: null, Padding(
keyboardType: TextInputType.multiline, padding: EdgeInsets.symmetric(vertical: 10.0),
initialValue: widget.task.title,
onSaved: (title) => _title = title,
onChanged: (_) => _changed = true,
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',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
maxLines: null,
keyboardType: TextInputType.multiline,
initialValue: widget.task.description,
onSaved: (description) => _description = description,
onChanged: (_) => _changed = true,
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,
onChanged: (_) => _changed = true,
),
VikunjaDateTimePicker(
label: 'Start Date',
initialValue: widget.task.startDate,
onSaved: (startDate) => _startDate = startDate,
onChanged: (_) => _changed = true,
),
VikunjaDateTimePicker(
label: 'End Date',
initialValue: widget.task.endDate,
onSaved: (endDate) => _endDate = endDate,
onChanged: (_) => _changed = true,
),
Row(
children: [
Expanded(
flex: 2,
child: TextFormField( child: TextFormField(
keyboardType: TextInputType.number, maxLines: null,
initialValue: getRepeatAfterValueFromDuration( keyboardType: TextInputType.multiline,
widget.task.repeatAfter) initialValue: widget.task.title,
?.toString(), onSaved: (title) => _title = title,
onSaved: (repeatAfter) => _repeatAfter =
getDurationFromType(repeatAfter, _repeatAfterType),
onChanged: (_) => _changed = true, onChanged: (_) => _changed = true,
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( decoration: new InputDecoration(
labelText: 'Repeat after', labelText: 'Title',
border: InputBorder.none, border: OutlineInputBorder(),
icon: Icon(Icons.repeat),
), ),
), ),
), ),
Expanded( Padding(
child: DropdownButton<String>( padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
maxLines: null,
keyboardType: TextInputType.multiline,
initialValue: widget.task.description,
onSaved: (description) => _description = description,
onChanged: (_) => _changed = true,
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,
onChanged: (_) => _changed = true,
),
VikunjaDateTimePicker(
label: 'Start Date',
initialValue: widget.task.startDate,
onSaved: (startDate) => _startDate = startDate,
onChanged: (_) => _changed = true,
),
VikunjaDateTimePicker(
label: 'End Date',
initialValue: widget.task.endDate,
onSaved: (endDate) => _endDate = endDate,
onChanged: (_) => _changed = true,
),
Row(
children: [
Expanded(
flex: 2,
child: TextFormField(
keyboardType: TextInputType.number,
initialValue: getRepeatAfterValueFromDuration(
widget.task.repeatAfter)?.toString(),
onSaved: (repeatAfter) => _repeatAfter =
getDurationFromType(repeatAfter, _repeatAfterType),
onChanged: (_) => _changed = true,
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(
VikunjaDateTimePicker(
label: 'Reminder',
onSaved: (reminder) =>
_reminderDates[currentIndex] = reminder,
onChanged: (_) => _changed = true,
initialValue: DateTime.now(),
),
));
}),
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(() {
_repeatAfterType = newValue; _priority = _priorityFromString(newValue);
}); });
}, },
items: <String>[ items: ['Unset', 'Low', 'Medium', 'High', 'Urgent', 'DO NOW']
'Hours', .map((String value) {
'Days', return new DropdownMenuItem(
'Weeks',
'Months',
'Years'
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value, value: value,
child: Text(value), child: new Text(value),
); );
}).toList(), }).toList(),
), ),
), ),
], Wrap(
), spacing: 10,
Column( children: _labels.map((Label label) {
children: _reminderInputs, return LabelComponent(
), label: label,
GestureDetector( onDelete: () {
child: Padding( _removeLabel(label);
padding: EdgeInsets.symmetric(vertical: 10), },
);
}).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) => _searchLabel(pattern),
itemBuilder: (context, suggestion) {
return Text(suggestion);
},
transitionBuilder: (context, suggestionsBox, controller) {
return suggestionsBox;
},
onSuggestionSelected: (suggestion) {
_addLabel(suggestion);
},
),
),
IconButton(
onPressed: () =>
_createAndAddLabel(_labelTypeAheadController.text),
icon: Icon(Icons.add),
)
],
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: EdgeInsets.only(right: 15, left: 2), padding: const EdgeInsets.only(right: 15, left: 2),
child: Icon( child: Icon(
Icons.alarm_add, Icons.palette,
color: Colors.grey,
)),
Text(
'Add a reminder',
style: TextStyle(
color: Colors.grey, color: Colors.grey,
fontSize: 16,
), ),
), ),
ElevatedButton(
child: Text(
'Color',
style: _resetColor || (_color ?? widget.task.color) == null ? null : TextStyle(
color: (_color ?? widget.task.color)
.computeLuminance() > 0.5 ? Colors.black : Colors.white,
),
),
style: _resetColor ? null : ButtonStyle(
backgroundColor: MaterialStateProperty
.resolveWith((_) => _color ?? widget.task.color),
),
onPressed: _onColorEdit,
),
Padding(
padding: const EdgeInsets.only(left: 15),
child: () {
String colorString = (_resetColor ? null : (_color ?? widget.task.color))?.toString();
colorString = colorString?.substring(10, colorString.length - 1)?.toUpperCase();
colorString = colorString != null ? '#$colorString' : 'None';
return Text(
'$colorString',
style: TextStyle(
color: Colors.grey,
fontStyle: FontStyle.italic,
),
);
}(),
),
], ],
), ),
), ),
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(
VikunjaDateTimePicker(
label: 'Reminder',
onSaved: (reminder) =>
_reminderDates[currentIndex] = reminder,
onChanged: (_) => _changed = true,
initialValue: DateTime.now(),
),
));
}),
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) => _searchLabel(pattern),
itemBuilder: (context, suggestion) {
return 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'),
))),
]),
), ),
), ),
floatingActionButton: FloatingActionButton(
onPressed: !_loading ? () {
if (_formKey.currentState.validate()) {
Form.of(_listKey.currentContext).save();
_saveTask(_listKey.currentContext);
}
} : null,
child: Icon(Icons.save),
),
), ),
)); );
} }
_saveTask(BuildContext context) async { _saveTask(BuildContext context) async {
setState(() => _loading = true); setState(() => _loading = true);
// Removes all reminders with no value set. // Removes all reminders with no value set.
_reminderDates.removeWhere((d) => d == null); _reminderDates.removeWhere((d) => d == null);
Task updatedTask = Task( Task updatedTask = widget.task.copyWith(
id: widget.task.id,
title: _title, title: _title,
description: _description, description: _description,
done: widget.task.done,
reminderDates: _reminderDates, reminderDates: _reminderDates,
createdBy: widget.task.createdBy,
dueDate: _dueDate, dueDate: _dueDate,
startDate: _startDate, startDate: _startDate,
endDate: _endDate, endDate: _endDate,
priority: _priority, priority: _priority,
repeatAfter: _repeatAfter, repeatAfter: _repeatAfter,
color: _resetColor ? null : (_color ?? widget.task.color),
resetColor: _resetColor,
); );
// update the labels // update the labels
@ -335,11 +378,12 @@ class _TaskEditPageState extends State<TaskEditPage> {
); );
}); });
VikunjaGlobal.of(context).taskService.update(updatedTask).then((_) { VikunjaGlobal.of(context).taskService.update(updatedTask).then((result) {
setState(() { _loading = false; _changed = false;}); setState(() { _loading = false; _changed = false;});
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The task was updated successfully!'), content: Text('The task was updated successfully!'),
)); ));
Navigator.of(context).pop(result);
}).catchError((err) { }).catchError((err) {
setState(() => _loading = false); setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -361,15 +405,13 @@ class _TaskEditPageState extends State<TaskEditPage> {
_searchLabel(String query) { _searchLabel(String query) {
return VikunjaGlobal.of(context) return VikunjaGlobal.of(context)
.labelService .labelService.getAll(query: query).then((labels) {
.getAll(query: query)
.then((labels) {
log("searched"); log("searched");
// Only show those labels which aren't already added to the task // Only show those labels which aren't already added to the task
labels.removeWhere((labelToRemove) => _labels.contains(labelToRemove)); labels.removeWhere((labelToRemove) => _labels.contains(labelToRemove));
_suggestedLabels = labels; _suggestedLabels = labels;
return labels.map((label) => label.title).toList(); return labels.map((label) => label.title).toList();
}); });
} }
_addLabel(String labelTitle) { _addLabel(String labelTitle) {
@ -444,6 +486,61 @@ class _TaskEditPageState extends State<TaskEditPage> {
} }
} }
_onColorEdit() {
_pickerColor = _resetColor || (_color ?? widget.task.color) == null
? Colors.black
: _color ?? widget.task.color;
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Task Color'),
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: _pickerColor,
enableAlpha: false,
labelTypes: const [ColorLabelType.hsl, ColorLabelType.rgb],
paletteType: PaletteType.hslWithLightness,
hexInputBar: true,
onColorChanged: (color) => setState(() => _pickerColor = color),
),
),
actions: <TextButton>[
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Reset'),
onPressed: () {
setState(() {
_color = null;
_resetColor = true;
_changed = _color != widget.task.color;
});
Navigator.of(context).pop();
},
),
TextButton(
child: Text('Ok'),
onPressed: () {
if (_pickerColor != Colors.black) setState(() {
_color = _pickerColor;
_resetColor = false;
_changed = _color != widget.task.color;
});
else setState(() {
_color = null;
_resetColor = true;
_changed = _color != widget.task.color;
});
Navigator.of(context).pop();
},
),
],
),
);
}
Future<bool> _showConfirmationDialog() async { Future<bool> _showConfirmationDialog() async {
return showDialog<bool>( return showDialog<bool>(
context: context, context: context,

View File

@ -174,6 +174,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_colorpicker:
dependency: "direct main"
description:
name: flutter_colorpicker
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
flutter_keyboard_visibility: flutter_keyboard_visibility:
dependency: transitive dependency: transitive
description: description:

View File

@ -24,6 +24,7 @@ dependencies:
petitparser: ^5.0.0 petitparser: ^5.0.0
provider: ^6.0.3 provider: ^6.0.3
webview_flutter: ^3.0.4 webview_flutter: ^3.0.4
flutter_colorpicker: ^1.0.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: