From 9f8e0c875cb45e2539fce70831489bbe7f53025a Mon Sep 17 00:00:00 2001 From: Stefan Dresselhaus Date: Tue, 10 Jan 2023 02:01:05 +0100 Subject: [PATCH] task removeable, added header, more todos :woman_shrugging: .. --- README.md | 11 ++- img/2023-01-10_Task_details.png | Bin 0 -> 27885 bytes lib/addReminder.dart | 2 +- lib/homescreen.dart | 24 +++--- lib/repeating_task.dart | 8 +- lib/table.dart | 74 +++++++++++++++--- lib/task_item.dart | 2 +- lib/types/tasks.dart | 8 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 19 +++++ pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 15 files changed, 128 insertions(+), 32 deletions(-) create mode 100644 img/2023-01-10_Task_details.png diff --git a/README.md b/README.md index c0a1aa8..ed45bca 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,18 @@ A Reminder based on todo.txt synced via nextcloud - [ ] define isomorphism for 'repeat:'-meta-tag - [ ] add interface for repeat-datatype in addReminder.dart - [x] save/load data to/from disk +- [x] adding/removing tasks - [ ] respect ordering that was used when starting the app when saving. - [ ] add Nextcloud-login for getting a Token - [ ] use webdav for synchronizing with Nextcloud using that token - [ ] sorting by "next up", "priority" - [ ] respect 'color:'-meta-tag (usual formats like "#aabbcc", html-colors like "red") - [ ] use color in rendering todos +- [ ] make application-settings + - [ ] store/load settings + - [ ] setting for number of days into the future + - [ ] theme (light/dark mode, system theme) +- [ ] fancy pop-animation & sound for the checkbox ## Current looks: @@ -21,4 +27,7 @@ A Reminder based on todo.txt synced via nextcloud ![](img/2023-01-08_application.png) ### Adding Tasks -![](img/2023-01-08_addTask.png) \ No newline at end of file +![](img/2023-01-08_addTask.png) + +### Details/Removing tasks +![](img/2023-01-10_Task_details.png) \ No newline at end of file diff --git a/img/2023-01-10_Task_details.png b/img/2023-01-10_Task_details.png new file mode 100644 index 0000000000000000000000000000000000000000..92bda9e9f075109ff7bcf90131213ac16dddee92 GIT binary patch literal 27885 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 EKUr?!9smFU literal 0 HcmV?d00001 diff --git a/lib/addReminder.dart b/lib/addReminder.dart index 01a0570..e873043 100644 --- a/lib/addReminder.dart +++ b/lib/addReminder.dart @@ -103,7 +103,7 @@ class _AddTaskWidgetState extends State with RestorationMixin { children: [ Text("Begin: ", style: Theme.of(context).textTheme.labelLarge), Expanded( - child: Text("${_beginDate.value.year}-${_beginDate.value.month.toString().padLeft(2,'0')}-${_beginDate.value.day.toString().padLeft(2,'0')}") + child: Text(Task.formatDate(_beginDate.value)) ), IconButton( onPressed: () => _restorableDatePickerRouteFuture.present(), diff --git a/lib/homescreen.dart b/lib/homescreen.dart index fa98a16..e4d81af 100644 --- a/lib/homescreen.dart +++ b/lib/homescreen.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_window_close/flutter_window_close.dart'; import 'package:nextcloud_reminder/addReminder.dart'; import 'package:nextcloud_reminder/parser/todotxt.dart'; import 'package:nextcloud_reminder/repeating_task.dart'; @@ -28,7 +29,7 @@ class HomeWidget extends StatefulWidget { class _HomeWidgetState extends State with WidgetsBindingObserver { - final ScrollTable _checkboxes = ScrollTable(title: "TODOs"); + late final ScrollTable _checkboxes; int _counter = 1; late final Directory appDocDirectory; late final File todotxt = File('${appDocDirectory.path}/todo.txt'); @@ -45,7 +46,6 @@ class _HomeWidgetState extends State with WidgetsBindingObserver { appDocDirectory = (await getApplicationDocumentsDirectory()); if (await todotxt.exists()) { var data = await todotxt.readAsLines(); - debugPrint(data.toString()); tasks.addAll(TodoParser.parse(data)); _loadTodos(); } else { @@ -57,7 +57,12 @@ class _HomeWidgetState extends State with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + _checkboxes = ScrollTable(title: "TODOs", deleteCallback: _removeTask); initLazy(); + FlutterWindowClose.setWindowShouldCloseHandler(() async { + saveData(); + return true; + }); } @override @@ -81,16 +86,6 @@ class _HomeWidgetState extends State with WidgetsBindingObserver { await todotxt.writeAsString(data); } - void _addDummyTask() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // stuff without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _checkboxes.addTask(RepeatingTask(task: Task(title: "Dummy Task #$_counter", begin: DateTime.now()), repeat: _counter++)); - }); - } void _addTask(RepeatingTask? t) { if (t != null) { setState(() { @@ -99,6 +94,11 @@ class _HomeWidgetState extends State with WidgetsBindingObserver { }); } } + void _removeTask(RepeatingTask t) { + setState(() { + tasks.remove(t.task); + }); + } @override Widget build(BuildContext context) { diff --git a/lib/repeating_task.dart b/lib/repeating_task.dart index 34161c6..ddb2070 100644 --- a/lib/repeating_task.dart +++ b/lib/repeating_task.dart @@ -23,9 +23,13 @@ class _RepeatingTaskState extends State { @override Widget build(BuildContext context) { - return Row( + return Container( + decoration: const BoxDecoration(border: Border(bottom: BorderSide(),)), + margin: const EdgeInsets.all(0.0), + child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: _occurrences, - ); + ) + ); } } \ No newline at end of file diff --git a/lib/table.dart b/lib/table.dart index 52bbf4f..0e58428 100644 --- a/lib/table.dart +++ b/lib/table.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:nextcloud_reminder/repeating_task.dart'; +import 'package:nextcloud_reminder/types/tasks.dart'; class ScrollTable extends StatefulWidget { - ScrollTable({super.key, required this.title}); + ScrollTable({super.key, required this.title, required this.deleteCallback}); // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and @@ -11,6 +12,7 @@ class ScrollTable extends StatefulWidget { final String title; final _ScrollTableState _internalState = _ScrollTableState(); + final ValueChanged deleteCallback; @override State createState() => _internalState; @@ -31,19 +33,64 @@ class _ScrollTableState extends State { }); } - List _buildTitles() { + removeTask(RepeatingTask task) { + setState(() { + _content.remove(task); + }); + widget.deleteCallback(task); + } + + Future _showDetailsAndRemoveTask(BuildContext context, RepeatingTask t) { + return showDialog(context: context, + barrierDismissible: true, + builder: (BuildContext context) + { + return AlertDialog( + title: const Text("Task details"), + content: SingleChildScrollView( + child: ListBody( + children: [ Text(t.task.title), + Text("Projects: ${t.task.projects.isEmpty ? "none" : t.task.projects.join(", ")}"), + Text("Contexts: ${t.task.contexts.isEmpty ? "none" : t.task.contexts.join(", ")}"), + Padding(padding: EdgeInsets.only(top: 16), + child: Text(t.task.meta.isEmpty ? "" : "Meta:", style: Theme.of(context).textTheme.bodyLarge,) + ), + ] + List.of(t.task.meta.entries.map((e) => Text("${e.key}: ${e.value}"))), + ), + ), + actions: [ + TextButton(onPressed: () { + removeTask(t); + Navigator.of(context).pop(); + }, + style: TextButton.styleFrom(foregroundColor: Theme + .of(context) + .errorColor), + child: const Text("remove"),), + TextButton(onPressed: () => Navigator.of(context).pop(), + child: const Text("close")), + ] + + ); + }); + } + + List _buildTitles(BuildContext context) { return List.from(_content.map((RepeatingTask t) => Container( - alignment: Alignment.center, - width: 120.0, + alignment: Alignment.centerLeft, + width: 150.0, height: 60.0, - color: Colors.white, - margin: const EdgeInsets.all(4.0), - child: Text(t.task.title, style: Theme - .of(context) - .textTheme - .labelMedium), - ))); + margin: const EdgeInsets.only(left: 4, top: 1), + decoration: const BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(),)), + child: TextButton( + onPressed: () => _showDetailsAndRemoveTask(context,t), + child: Text(t.task.title, + style: Theme.of(context).textTheme.labelMedium), + ) + ) + ) + ); } @override @@ -54,14 +101,15 @@ class _ScrollTableState extends State { children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, - children: _buildTitles(), + //TODO: Text in container wie bei _buildTitles oben und width/height/margin/etc. festnageln. + children: List.from([Text("Todo", style: Theme.of(context).dataTableTheme.headingTextStyle,)]) + _buildTitles(context), ), Flexible( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: _content, + children: List.from([Text("header ... date, date, date .. fancy turned 60 degrees", style: Theme.of(context).dataTableTheme.headingTextStyle)]) + List.from(_content), ), ), ) diff --git a/lib/task_item.dart b/lib/task_item.dart index e77d3f6..8b1d7ed 100644 --- a/lib/task_item.dart +++ b/lib/task_item.dart @@ -27,7 +27,7 @@ class _TaskItemState extends State{ width: 60.0, height: 60.0, color: Colors.white, - margin: const EdgeInsets.all(4.0), + margin: const EdgeInsets.all(0.0), child: _done == null ? null : Checkbox(value: _done, onChanged: (newState) => setState(() { _done = newState!; })), diff --git a/lib/types/tasks.dart b/lib/types/tasks.dart index b52bc8a..f4fa9d6 100644 --- a/lib/types/tasks.dart +++ b/lib/types/tasks.dart @@ -19,12 +19,16 @@ class Task { this.end, }); + static String formatDate(DateTime dt) { + return "${dt!.year}-${dt!.month.toString().padLeft(2,'0')}-${dt!.day.toString().padLeft(2,'0')}"; + } + @override String toString() { return (done ? "x " : "") + (priority == null ? "" : "(${priority!}) ") - + (begin == null ? "" : "${begin!.year}-${begin!.month}-${begin!.day} ") - + (end == null ? "" : "${end!.year}-${end!.month}-${end!.day} ") + + (begin == null ? "" : "${Task.formatDate(begin!)} ") + + (end == null ? "" : "${Task.formatDate(end!)} ") + ("$title ") + meta.entries.map((entry) => "${entry.key}:${entry.value}").join(" ") ; diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..9d48e63 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) flutter_window_close_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWindowClosePlugin"); + flutter_window_close_plugin_register_with_registrar(flutter_window_close_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..8b616e4 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_window_close ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0d56f51..08b50cd 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,10 @@ import FlutterMacOS import Foundation +import flutter_window_close import path_provider_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterWindowClosePlugin.register(with: registry.registrar(forPlugin: "FlutterWindowClosePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 3724a95..82d7417 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -81,6 +81,25 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_window_close: + dependency: "direct main" + description: + name: flutter_window_close + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.2" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" lints: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f3c5d20..f97f81f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: path_provider: ^2.0.11 petitparser: ^5.1.0 tuple: ^2.0.1 + flutter_window_close: ^0.2.2 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..f6af760 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + FlutterWindowClosePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterWindowClosePlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..5ffb577 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_window_close ) list(APPEND FLUTTER_FFI_PLUGIN_LIST