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,
MaterialPageRoute(builder: (context) => TaskEditPage(
task: _currentTask,
)),
),
).then((task) => setState(() {
if (task != null) _currentTask = task;
})),
),
);
}

View File

@ -81,14 +81,16 @@ class TaskTileState extends State<TaskTile> {
: Text(_currentTask.description),
secondary:
IconButton(icon: Icon(Icons.settings), onPressed: () {
Navigator.push(
Navigator.push<Task>(
context,
MaterialPageRoute(
builder: (context) => TaskEditPage(
task: _currentTask,
))).whenComplete(() {
widget.onEdit();
});
),
),
).then((task) => setState(() {
if (task != null) _currentTask = task;
})).whenComplete(() => widget.onEdit());
}),
onChanged: _change,
);
@ -107,14 +109,8 @@ class TaskTileState extends State<TaskTile> {
}
Future<Task> _updateTask(Task task, bool checked) {
// TODO use copyFrom
return VikunjaGlobal.of(context).taskService.update(Task(
id: task.id,
return VikunjaGlobal.of(context).taskService.update(task.copyWith(
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.computeLuminance() > 0.5 ? Colors.black : Colors.white
: 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),
onReorder: (oldIndex, newIndex) {},
onReorderEnd: (newIndex) => setState(() {
if (newIndex > _draggedBucketIndex) newIndex -= 1;
taskState.buckets.insert(newIndex, taskState.buckets.removeAt(_draggedBucketIndex));
bool indexUpdated = false;
if (newIndex > _draggedBucketIndex) {
newIndex -= 1;
indexUpdated = true;
}
taskState.buckets.insert(newIndex, taskState.buckets.removeAt(_draggedBucketIndex));
if (newIndex == 0) {
taskState.buckets[0].position = 0;
_updateBucket(context, taskState.buckets[0]);
newIndex = 1;
indexUpdated = true;
}
taskState.buckets[newIndex].position = newIndex == taskState.buckets.length - 1
? taskState.buckets[newIndex - 1].position + 1
@ -239,7 +241,9 @@ class _ListPageState extends State<ListPage> {
+ taskState.buckets[newIndex + 1].position) / 2.0;
_updateBucket(context, taskState.buckets[newIndex]);
_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_typeahead/flutter_typeahead.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:vikunja_app/components/datetimePicker.dart';
import 'package:vikunja_app/components/label.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/utils/repeat_after_parse.dart';
class TaskEditPage extends StatefulWidget {
@ -22,6 +21,7 @@ class TaskEditPage extends StatefulWidget {
class _TaskEditPageState extends State<TaskEditPage> {
final _formKey = GlobalKey<FormState>();
final _listKey = GlobalKey();
bool _loading = false;
bool _changed = false;
@ -35,6 +35,9 @@ class _TaskEditPageState extends State<TaskEditPage> {
List<Label> _suggestedLabels;
var _reminderInputs = <Widget>[];
final _labelTypeAheadController = TextEditingController();
Color _color;
Color _pickerColor;
bool _resetColor = false;
@override
Widget build(BuildContext ctx) {
@ -47,14 +50,16 @@ class _TaskEditPageState extends State<TaskEditPage> {
initialValue: time,
label: 'Reminder',
onSaved: (reminder) => _reminderDates[i] = reminder,
))));
)))
);
}
if (_labels == null) {
_labels = widget.task.labels ?? [];
}
return WillPopScope(onWillPop: () {
return WillPopScope(
onWillPop: () {
if(_changed) {
return _showConfirmationDialog();
}
@ -68,8 +73,10 @@ class _TaskEditPageState extends State<TaskEditPage> {
builder: (BuildContext context) => SafeArea(
child: Form(
key: _formKey,
child: ListView(padding: const EdgeInsets.all(16.0), children: <
Widget>[
child: ListView(
key: _listKey,
padding: const EdgeInsets.all(16.0),
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
@ -136,8 +143,7 @@ class _TaskEditPageState extends State<TaskEditPage> {
child: TextFormField(
keyboardType: TextInputType.number,
initialValue: getRepeatAfterValueFromDuration(
widget.task.repeatAfter)
?.toString(),
widget.task.repeatAfter)?.toString(),
onSaved: (repeatAfter) => _repeatAfter =
getDurationFromType(repeatAfter, _repeatAfterType),
onChanged: (_) => _changed = true,
@ -279,27 +285,65 @@ class _TaskEditPageState extends State<TaskEditPage> {
)
],
),
Builder(
builder: (context) => Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: FancyButton(
onPressed: !_loading
? () {
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 15, left: 2),
child: Icon(
Icons.palette,
color: Colors.grey,
),
),
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,
),
);
}(),
),
],
),
),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: !_loading ? () {
if (_formKey.currentState.validate()) {
Form.of(context).save();
_saveTask(context);
Form.of(_listKey.currentContext).save();
_saveTask(_listKey.currentContext);
}
}
: null,
child: _loading
? CircularProgressIndicator()
: VikunjaButtonText('Save'),
))),
]),
} : null,
child: Icon(Icons.save),
),
),
),
));
);
}
_saveTask(BuildContext context) async {
@ -308,18 +352,17 @@ class _TaskEditPageState extends State<TaskEditPage> {
// Removes all reminders with no value set.
_reminderDates.removeWhere((d) => d == null);
Task updatedTask = Task(
id: widget.task.id,
Task updatedTask = widget.task.copyWith(
title: _title,
description: _description,
done: widget.task.done,
reminderDates: _reminderDates,
createdBy: widget.task.createdBy,
dueDate: _dueDate,
startDate: _startDate,
endDate: _endDate,
priority: _priority,
repeatAfter: _repeatAfter,
color: _resetColor ? null : (_color ?? widget.task.color),
resetColor: _resetColor,
);
// 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;});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The task was updated successfully!'),
));
Navigator.of(context).pop(result);
}).catchError((err) {
setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar(
@ -361,9 +405,7 @@ class _TaskEditPageState extends State<TaskEditPage> {
_searchLabel(String query) {
return VikunjaGlobal.of(context)
.labelService
.getAll(query: query)
.then((labels) {
.labelService.getAll(query: query).then((labels) {
log("searched");
// Only show those labels which aren't already added to the task
labels.removeWhere((labelToRemove) => _labels.contains(labelToRemove));
@ -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 {
return showDialog<bool>(
context: context,

View File

@ -174,6 +174,13 @@ packages:
description: flutter
source: sdk
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:
dependency: transitive
description:

View File

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