1
0
mirror of https://github.com/go-vikunja/app synced 2024-09-16 12:51:46 +00:00

fix: understand new TaskReminder class

This commit is contained in:
Benimautner 2024-06-06 22:29:31 +02:00
parent 8423c8c5cc
commit bed2a8f004
4 changed files with 232 additions and 188 deletions

@ -136,10 +136,10 @@ class NotificationClass {
"Reminder",
"This is your reminder for '" + task.title + "'",
notificationsPlugin,
reminder,
reminder.reminder,
await FlutterTimezone.getLocalTimezone(),
platformChannelSpecificsReminders,
id: (reminder.millisecondsSinceEpoch / 1000).floor(),
id: (reminder.reminder.millisecondsSinceEpoch / 1000).floor(),
);
}
if (task.hasDueDate) {

@ -6,6 +6,25 @@ import 'package:vikunja_app/models/user.dart';
import 'package:vikunja_app/models/taskAttachment.dart';
import 'package:vikunja_app/utils/checkboxes_in_text.dart';
class TaskReminder {
final int relative_period;
final String relative_to;
DateTime reminder;
TaskReminder(this.reminder) : relative_period = 0, relative_to = "";
TaskReminder.fromJson(Map<String, dynamic> json)
: reminder = DateTime.parse(json['reminder']),
relative_period = json['relative_period'],
relative_to = json['relative_to'];
toJSON() => {
'relative_period': relative_period,
'relative_to': relative_to,
'reminder': reminder.toUtc().toIso8601String(),
};
}
@JsonSerializable()
class Task {
final int id;
@ -14,7 +33,7 @@ class Task {
final int? projectId;
final DateTime created, updated;
DateTime? dueDate, startDate, endDate;
final List<DateTime> reminderDates;
final List<TaskReminder> reminderDates;
final String identifier;
final String title, description;
final bool done;
@ -76,9 +95,9 @@ class Task {
description = json['description'],
identifier = json['identifier'],
done = json['done'],
reminderDates = json['reminder_dates'] != null
? (json['reminder_dates'] as List<dynamic>)
.map((ts) => DateTime.parse(ts))
reminderDates = json['reminders'] != null
? (json['reminders'] as List<dynamic>)
.map((ts) => TaskReminder.fromJson(ts))
.toList()
: [],
dueDate = DateTime.parse(json['due_date']),
@ -124,8 +143,8 @@ class Task {
'description': description,
'identifier': identifier.isNotEmpty ? identifier : null,
'done': done,
'reminder_dates': reminderDates
.map((date) => date.toUtc().toIso8601String())
'reminders': reminderDates
.map((date) => date.toJSON())
.toList(),
'due_date': dueDate?.toUtc().toIso8601String(),
'start_date': startDate?.toUtc().toIso8601String(),
@ -158,7 +177,7 @@ class Task {
DateTime? dueDate,
DateTime? startDate,
DateTime? endDate,
List<DateTime>? reminderDates,
List<TaskReminder>? reminderDates,
String? title,
String? description,
String? identifier,

@ -33,7 +33,7 @@ class _TaskEditPageState extends State<TaskEditPage> {
int? _priority;
DateTime? _dueDate, _startDate, _endDate;
late final List<DateTime> _reminderDates;
late final List<TaskReminder> _reminderDates;
String? _title, _description, _repeatAfterType;
Duration? _repeatAfter;
late final List<Label> _labels;
@ -53,13 +53,16 @@ class _TaskEditPageState extends State<TaskEditPage> {
_reminderDates = widget.task.reminderDates;
for (var i = 0; i < _reminderDates.length; i++) {
_reminderInputs.add(VikunjaDateTimePicker(
initialValue: _reminderDates[i],
label: 'Reminder',
onSaved: (reminder) {
_reminderDates[i] = reminder ?? DateTime(0);
return null;
},
_reminderInputs.add(Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: VikunjaDateTimePicker(
initialValue: _reminderDates[i].reminder,
label: 'Reminder',
onSaved: (reminder) {
_reminderDates[i].reminder = reminder ?? DateTime(0);
return null;
},
),
));
}
@ -163,153 +166,218 @@ class _TaskEditPageState extends State<TaskEditPage> {
),
),
),
VikunjaDateTimePicker(
icon: Icon(Icons.access_time),
label: 'Due Date',
initialValue: widget.task.dueDate,
onSaved: (duedate) => _dueDate = duedate,
onChanged: (_) => _changed = true,
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: 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,
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: 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,
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: 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(_repeatAfter)
?.toString(),
onSaved: (repeatAfter) => _repeatAfter =
getDurationFromType(
repeatAfter, _repeatAfterType),
onChanged: (_) => _changed = true,
decoration: new InputDecoration(
labelText: 'Repeat after',
border: InputBorder.none,
icon: Icon(Icons.repeat),
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Row(
children: [
Flexible(
flex: 65,
child: TextFormField(
keyboardType: TextInputType.number,
initialValue:
getRepeatAfterValueFromDuration(_repeatAfter)
?.toString(),
onSaved: (repeatAfter) => _repeatAfter =
getDurationFromType(
repeatAfter, _repeatAfterType),
onChanged: (_) => _changed = true,
decoration: new InputDecoration(
labelText: 'Repeat after',
border: InputBorder.none,
icon: Icon(Icons.repeat),
contentPadding:
EdgeInsets.fromLTRB(0, 0, 0, 0)),
),
),
),
Expanded(
child: DropdownButton<String>(
isExpanded: true,
isDense: true,
value: _repeatAfterType ??
getRepeatAfterTypeFromDuration(_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(),
Spacer(),
Flexible(
flex: 30,
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
border: InputBorder.none,
contentPadding:
EdgeInsets.fromLTRB(0, 0, 0, 0)),
isExpanded: true,
value: _repeatAfterType ??
getRepeatAfterTypeFromDuration(_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,
Padding(
padding: EdgeInsets.only(top: 15.0),
child: 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,
Padding(
padding: const EdgeInsets.only(bottom: 15),
child: 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,
)),
Text(
'Add a reminder',
style: TextStyle(
color: Colors.grey,
fontSize: 16,
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(DateTime(0));
var currentIndex = _reminderDates.length - 1;
onTap: () {
_changed = true;
// 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(TaskReminder(DateTime(0)));
var currentIndex = _reminderDates.length - 1;
// FIXME: Why does putting this into a row fail?
setState(() => _reminderInputs.add(
VikunjaDateTimePicker(
label: 'Reminder',
onSaved: (reminder) =>
_reminderDates[currentIndex] =
reminder ?? DateTime(0),
onChanged: (_) => _changed = true,
initialValue: DateTime.now(),
),
));
}),
InputDecorator(
isEmpty: _priority == null,
// FIXME: Why does putting this into a row fail?
setState(() => _reminderInputs.add(
VikunjaDateTimePicker(
label: 'Reminder',
onSaved: (reminder) =>
_reminderDates[currentIndex].reminder =
reminder ?? DateTime(0),
onChanged: (_) => _changed = true,
initialValue: DateTime.now(),
),
));
}),
),
new DropdownButtonFormField<String>(
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(),
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(),
),
Padding(
padding: const EdgeInsets.only(top: 10.0, bottom: 10),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 15, left: 2),
child: Icon(
Icons.label,
color: Colors.grey,
),
),
Container(
width: MediaQuery.of(context).size.width -
80 -
((IconTheme.of(context).size ?? 0) * 2),
child: TypeAheadField(
builder: (builder, controller, focusnode) {
return TextFormField(
controller: _labelTypeAheadController,
focusNode: focusnode,
decoration: InputDecoration(
labelText: 'Add a new label',
border: InputBorder.none,
),
);
},
suggestionsCallback: (pattern) =>
_searchLabel(pattern),
itemBuilder: (context, suggestion) {
return new ListTile(
title: Text(suggestion.toString()));
},
//transitionBuilder:
// (context, suggestionsBox, controller) {
// return suggestionsBox;
//},
onSelected: (suggestion) {
_addLabel(suggestion.toString());
},
),
),
IconButton(
onPressed: () => _createAndAddLabel(
_labelTypeAheadController.text),
icon: Icon(Icons.add),
)
],
),
),
Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 15, left: 2),
child: Icon(
Icons.label,
color: Colors.grey,
),
),
Wrap(
spacing: 10,
children: _labels.map((Label label) {
@ -322,49 +390,6 @@ class _TaskEditPageState extends State<TaskEditPage> {
}).toList()),
],
),
Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(
right: 15,
left: 2.0 + (IconTheme.of(context).size ?? 0))),
Container(
width: MediaQuery.of(context).size.width -
80 -
((IconTheme.of(context).size ?? 0) * 2),
child: TypeAheadField(
builder: (builder, controller, focusnode) {
return TextFormField(
controller: _labelTypeAheadController,
focusNode: focusnode,
decoration: InputDecoration(
labelText: 'Add a new label',
border: InputBorder.none,
),
);
},
suggestionsCallback: (pattern) =>
_searchLabel(pattern),
itemBuilder: (context, suggestion) {
return new ListTile(
title: Text(suggestion.toString()));
},
//transitionBuilder:
// (context, suggestionsBox, controller) {
// return suggestionsBox;
//},
onSelected: (suggestion) {
_addLabel(suggestion.toString());
},
),
),
IconButton(
onPressed: () => _createAndAddLabel(
_labelTypeAheadController.text),
icon: Icon(Icons.add),
)
],
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
@ -485,7 +510,7 @@ class _TaskEditPageState extends State<TaskEditPage> {
setState(() => _loading = true);
// Removes all reminders with no value set.
_reminderDates.removeWhere((d) => d == DateTime(0));
_reminderDates.removeWhere((d) => d.reminder == DateTime(0));
final updatedTask = widget.task.copyWith(
title: _title,

@ -35,7 +35,7 @@ enum TaskServiceOptionSortBy {
enum TaskServiceOptionOrderBy { asc, desc }
enum TaskServiceOptionFilterBy { done, due_date, reminder_dates }
enum TaskServiceOptionFilterBy { done, due_date, reminders }
enum TaskServiceOptionFilterValue { enum_true, enum_false, enum_null }