added selector for repeat-interval. Needs UI-polish though..
This commit is contained in:
		| @@ -6,7 +6,7 @@ A Reminder based on todo.txt synced via nextcloud | ||||
|  | ||||
| - [x] make repeat-datatype (like: daily, weekly on mo/th/fr, bi-monthly, etc.) | ||||
|   - [x] define isomorphism for 'repeat:'-meta-tag | ||||
| - [ ] add interface for repeat-datatype in addReminder.dart | ||||
| - [x] add interface for repeat-datatype in addReminder.dart | ||||
| - [x] save/load data to/from disk | ||||
| - [x] adding/removing tasks | ||||
| - [x] respect ordering that was used when starting the app when saving. | ||||
|   | ||||
| @@ -1,7 +1,10 @@ | ||||
| import 'package:date_field/date_field.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:nextcloud_reminder/repeating_task.dart'; | ||||
| import 'package:nextcloud_reminder/types/repeat.dart'; | ||||
| import 'package:nextcloud_reminder/types/tasks.dart'; | ||||
| import 'package:tuple/tuple.dart'; | ||||
|  | ||||
| class AddTaskWidget extends StatefulWidget { | ||||
|   const AddTaskWidget({super.key, this.restorationId, required this.onSave}); | ||||
| @@ -15,11 +18,14 @@ class AddTaskWidget extends StatefulWidget { | ||||
|  | ||||
| //TODO: make _repeat changeable. | ||||
|  | ||||
| class _AddTaskWidgetState extends State<AddTaskWidget> with RestorationMixin { | ||||
| class _AddTaskWidgetState extends State<AddTaskWidget> { | ||||
|   final _formKey = GlobalKey<FormState>(); | ||||
|   final _titleController = TextEditingController(); | ||||
|   final int _repeat = 1; | ||||
|   final RestorableDateTime _beginDate = RestorableDateTime(DateTime.now()); | ||||
|   static _emptyRepetition() { | ||||
|     return Tuple2(TextEditingController(text: "1"), ValueNotifier(DateInterval.daily)); | ||||
|   } | ||||
|   final List<Tuple2<TextEditingController,ValueNotifier<DateInterval>>> _repeatEveryController = [_emptyRepetition()]; | ||||
|   DateTime _beginDate = DateTime.now(); | ||||
|  | ||||
|   @override | ||||
|   void dispose() { | ||||
| @@ -27,53 +33,45 @@ class _AddTaskWidgetState extends State<AddTaskWidget> with RestorationMixin { | ||||
|     super.dispose(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String? get restorationId => widget.restorationId; | ||||
|  | ||||
|   late final RestorableRouteFuture<DateTime?> _restorableDatePickerRouteFuture = | ||||
|       RestorableRouteFuture<DateTime?>( | ||||
|     onComplete: _selectDate, | ||||
|     onPresent: (NavigatorState navigator, Object? arguments) { | ||||
|       return navigator.restorablePush( | ||||
|         _datePickerRoute, | ||||
|         arguments: _beginDate.value.millisecondsSinceEpoch, | ||||
|       ); | ||||
|     }, | ||||
|   ); | ||||
|  | ||||
|   static Route<DateTime> _datePickerRoute( | ||||
|     BuildContext context, | ||||
|     Object? arguments, | ||||
|   ) { | ||||
|     return DialogRoute<DateTime>( | ||||
|       context: context, | ||||
|       builder: (BuildContext context) { | ||||
|         return DatePickerDialog( | ||||
|           restorationId: 'date_picker_dialog', | ||||
|           initialEntryMode: DatePickerEntryMode.calendarOnly, | ||||
|           initialDate: DateTime.fromMillisecondsSinceEpoch(arguments! as int), | ||||
|           firstDate: DateTime(2000), | ||||
|           lastDate: DateTime(2100), | ||||
|         ); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void restoreState(RestorationBucket? oldBucket, bool initialRestore) { | ||||
|     registerForRestoration(_beginDate, 'selected_date'); | ||||
|     registerForRestoration( | ||||
|         _restorableDatePickerRouteFuture, 'date_picker_route_future'); | ||||
|   } | ||||
|  | ||||
|   void _selectDate(DateTime? newSelectedDate) { | ||||
|     if (newSelectedDate != null) { | ||||
|       setState(() { | ||||
|         _beginDate.value = newSelectedDate; | ||||
|       }); | ||||
|   String _prettyInterval(DateInterval d) { | ||||
|     switch (d) { | ||||
|       default: | ||||
|         return d.toString(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Widget _repeatBuilder(BuildContext context, Tuple2<TextEditingController,ValueNotifier<DateInterval>> data) { | ||||
|     return Row( | ||||
|       children: [ | ||||
|         Text("Repeat every " ), | ||||
|         Expanded( | ||||
|           flex: 1, | ||||
|           child: TextFormField( | ||||
|             controller: data.item1, | ||||
|             decoration: const InputDecoration( | ||||
|               hintText: "1", | ||||
|             ), | ||||
|             keyboardType: const TextInputType.numberWithOptions(signed: false, decimal: false), | ||||
|             inputFormatters: [FilteringTextInputFormatter.digitsOnly], | ||||
|           ), | ||||
|         ), | ||||
|         Expanded( | ||||
|           flex: 3, | ||||
|           child: DropdownButton<DateInterval>( | ||||
|             items: DateInterval.values.map((v) => DropdownMenuItem(value: v, child: Text(_prettyInterval(v)))).toList(), | ||||
|             onChanged: (v) => setState(() { | ||||
|               data.item2.value = v ?? data.item2.value; | ||||
|             }), | ||||
|             value: data.item2.value, | ||||
|           ), | ||||
|         ), | ||||
|         IconButton(onPressed: () => setState(() { | ||||
|           _repeatEveryController.remove(data); | ||||
|         }), icon: Icon(Icons.remove, color: Theme.of(context).errorColor,)), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
| @@ -98,21 +96,21 @@ class _AddTaskWidgetState extends State<AddTaskWidget> with RestorationMixin { | ||||
|                 labelText: "Taskname" | ||||
|               ), | ||||
|             ), | ||||
|             Container( | ||||
|               decoration: const BoxDecoration(), | ||||
|               child: Row( | ||||
|                 children: [ | ||||
|                   Text("Begin: ", style: Theme.of(context).textTheme.labelLarge), | ||||
|                   Expanded( | ||||
|                       child: Text(Task.formatDate(_beginDate.value)) | ||||
|                   ), | ||||
|                   IconButton( | ||||
|                     onPressed: () => _restorableDatePickerRouteFuture.present(), | ||||
|                     icon: Icon(Icons.date_range, | ||||
|                       color: Theme.of(context).focusColor)) | ||||
|                 ] | ||||
|               ) | ||||
|  | ||||
|             DateTimeField( | ||||
|               onDateSelected: (v) => setState(() { _beginDate = v; }), | ||||
|               selectedDate: _beginDate, | ||||
|               decoration: const InputDecoration( | ||||
|                 suffixIcon: Icon(Icons.event_note), | ||||
|                 labelText: "Begin" | ||||
|               ), | ||||
|               mode: DateTimeFieldPickerMode.date, | ||||
|             ), | ||||
|             ] + _repeatEveryController.map((c) => _repeatBuilder(context,c)).toList() | ||||
|             + [ | ||||
|             ElevatedButton(onPressed: () => setState(() { | ||||
|               _repeatEveryController.add(_emptyRepetition()); | ||||
|             }), child: const Text("add repetition")), | ||||
|             Padding( | ||||
|               padding: const EdgeInsets.symmetric(vertical: 16.0), | ||||
|               child: ElevatedButton( | ||||
| @@ -124,8 +122,16 @@ class _AddTaskWidgetState extends State<AddTaskWidget> with RestorationMixin { | ||||
|                     ScaffoldMessenger.of(context).showSnackBar( | ||||
|                       const SnackBar(content: Text('Task added.')), | ||||
|                     ); | ||||
|                     var repeats = _repeatEveryController.map((e) => RepeatInterval(interval: e.item2.value, every: int.parse(e.item1.text))).toList(); | ||||
|                     var meta = repeats.map((e) => e.toString()).join("/"); | ||||
|                     widget.onSave(RepeatingTask( | ||||
|                         task: TaskExtra(title: _titleController.text, begin: _beginDate.value, repeat: [RepeatInterval(interval: DateInterval.daily)],))); | ||||
|                       task: TaskExtra( | ||||
|                           title: _titleController.text, | ||||
|                           begin: _beginDate, | ||||
|                           meta: {"repeat": meta}, | ||||
|                           repeat: repeats, | ||||
|                       ) | ||||
|                     )); | ||||
|                     Navigator.pop(context); | ||||
|                   } | ||||
|                 }, | ||||
|   | ||||
							
								
								
									
										14
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -43,6 +43,13 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "1.0.5" | ||||
|   date_field: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: date_field | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "3.0.2" | ||||
|   fake_async: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -93,6 +100,13 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "0.2.2" | ||||
|   intl: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: intl | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "0.17.0" | ||||
|   js: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
| @@ -41,6 +41,7 @@ dependencies: | ||||
|   tuple: ^2.0.1 | ||||
|   flutter_window_close: ^0.2.2 | ||||
|   collection: ^1.16.0 | ||||
|   date_field: ^3.0.2 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user