diff --git a/README.md b/README.md index 47008ce..29e8103 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,10 @@ A Reminder based on todo.txt synced via nextcloud - [ ] make application-settings - [ ] store/load settings - [ ] setting for number of days into the future - - [ ] theme (light/dark mode, system theme) + - [ ] theme + - [x] light/dark mode + - [ ] color theme by system colors + - [ ] own primary/secondary color theme - [ ] fancy pop-animation & sound for the checkbox ## Current looks: @@ -34,4 +37,8 @@ A Reminder based on todo.txt synced via nextcloud ![](img/2023-01-10_Task_details.png) ### Complex repeat patterns -![](img/2023-01-10_repeat_patterns.png) \ No newline at end of file +![](img/2023-01-10_repeat_patterns.png) + +### Light/Dark theme +![](img/2023-01-13_theme_light.png) +![](img/2023-01-13_theme_dark.png) \ No newline at end of file diff --git a/img/2023-01-13_theme_dark.png b/img/2023-01-13_theme_dark.png new file mode 100644 index 0000000..acba3b4 Binary files /dev/null and b/img/2023-01-13_theme_dark.png differ diff --git a/img/2023-01-13_theme_light.png b/img/2023-01-13_theme_light.png new file mode 100644 index 0000000..746a603 Binary files /dev/null and b/img/2023-01-13_theme_light.png differ diff --git a/lib/main.dart b/lib/main.dart index 8482097..090ad5b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,25 +1,65 @@ import 'package:flutter/material.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl_standalone.dart'; import 'package:nextcloud_reminder/homescreen.dart'; void main() { - runApp(const TodoTxtReminderApp()); + findSystemLocale().then((value) => + initializeDateFormatting(value).then((_) => + runApp(const TodoTxtReminderApp()) + )); } class TodoTxtReminderApp extends StatelessWidget { const TodoTxtReminderApp({super.key}); + static const primaryColor = Colors.pink; + static const secondaryColor = Colors.amber; + + getInteractColor(Color a, Color b) { + return (Set states) { + const Set interactiveStates = { + MaterialState.pressed, + MaterialState.hovered, + MaterialState.focused, + }; + if (states.any(interactiveStates.contains)) { + return b; + } + return a; + }; + } + + Color getColor(Set states) { + return getInteractColor(primaryColor, secondaryColor)(states); + } // This widget is the root of your application. @override Widget build(BuildContext context) { + const inputDecorationTheme = InputDecorationTheme(border: OutlineInputBorder(), focusColor: secondaryColor); + return MaterialApp( title: 'Nextcloud Reminder', theme: ThemeData( - // This is the theme of your application. - primarySwatch: Colors.pink, - inputDecorationTheme: const InputDecorationTheme(border: OutlineInputBorder(), ), - + brightness: Brightness.light, + colorScheme: ThemeData.light().colorScheme.copyWith(primary: primaryColor, secondary: secondaryColor, background: primaryColor.shade50), + inputDecorationTheme: inputDecorationTheme, + checkboxTheme: ThemeData.light().checkboxTheme.copyWith( + fillColor: MaterialStateProperty.resolveWith(getColor), + checkColor: MaterialStateProperty.resolveWith(getInteractColor(Colors.white,Colors.black)) + ), ), + darkTheme: ThemeData( + brightness: Brightness.dark, + colorScheme: ThemeData.dark().colorScheme.copyWith(primary: primaryColor, secondary: secondaryColor, background: primaryColor.shade500.withAlpha(32)), + inputDecorationTheme: inputDecorationTheme, + checkboxTheme: ThemeData.dark().checkboxTheme.copyWith( + fillColor: MaterialStateProperty.resolveWith(getColor), + checkColor: MaterialStateProperty.resolveWith(getInteractColor(Colors.white,Colors.black)) + ), + ), + themeMode: ThemeMode.system, home: const HomeWidget(title: 'todo.txt reminder'), ); } diff --git a/lib/repeating_task.dart b/lib/repeating_task.dart index cd6776a..9da4693 100644 --- a/lib/repeating_task.dart +++ b/lib/repeating_task.dart @@ -33,7 +33,9 @@ class _RepeatingTaskState extends State { @override Widget build(BuildContext context) { return Container( - decoration: const BoxDecoration(border: Border(bottom: BorderSide(),)), + decoration: BoxDecoration(border: Border( + bottom: BorderSide(color: Theme.of(context).colorScheme.background, width: 1), + ),), margin: const EdgeInsets.all(0.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/table.dart b/lib/table.dart index 0e58428..fea6571 100644 --- a/lib/table.dart +++ b/lib/table.dart @@ -1,4 +1,7 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:nextcloud_reminder/repeating_task.dart'; import 'package:nextcloud_reminder/types/tasks.dart'; @@ -26,6 +29,7 @@ class ScrollTable extends StatefulWidget { class _ScrollTableState extends State { final List _content = []; + final _contentStart = DateTime.now(); addTask(RepeatingTask task) { setState(() { @@ -52,7 +56,7 @@ class _ScrollTableState extends State { 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), + Padding(padding: const 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}"))), @@ -75,19 +79,51 @@ class _ScrollTableState extends State { }); } + Widget _todoHeader(BuildContext context) { + return Container( + width: 200, + height: 60, + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12), + decoration: BoxDecoration(color: Theme.of(context).colorScheme.background), + child: Text("TODO", style: Theme.of(context).textTheme.titleSmall?.copyWith(color: Theme.of(context).colorScheme.primary),), + ); + } + + Widget _datesHeader(BuildContext context) { + return Row( + children: List.generate(10, (i) => Container( + width: 60, + height: 60, + alignment: Alignment.bottomCenter, + padding: const EdgeInsets.only(left: 8, right: 8, bottom: 16), + decoration: BoxDecoration(color: Theme.of(context).colorScheme.background), + child: Transform.rotate(angle: -pi/3, + child: Text(DateFormat.Md().format(_contentStart.add(Duration(days: i))), + style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Theme.of(context).colorScheme.primary),), + ) + )) + ); + } + + List _buildTitles(BuildContext context) { return List.from(_content.map((RepeatingTask t) => Container( alignment: Alignment.centerLeft, - width: 150.0, + width: 200.0, height: 60.0, - margin: const EdgeInsets.only(left: 4, top: 1), - decoration: const BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(),)), - child: TextButton( + margin: const EdgeInsets.only(top: 1), + decoration: BoxDecoration(color: Theme.of(context).canvasColor, border: Border(bottom: BorderSide(color: Theme.of(context).colorScheme.background, width: 1),)), + child: SizedBox(width: 200, child: TextButton( onPressed: () => _showDetailsAndRemoveTask(context,t), + style: const ButtonStyle(alignment: AlignmentDirectional.centerStart), child: Text(t.task.title, - style: Theme.of(context).textTheme.labelMedium), - ) + softWrap: true, + textAlign: TextAlign.left, + style: Theme.of(context).textTheme.titleSmall, + ) + )), ) ) ); @@ -97,19 +133,19 @@ class _ScrollTableState extends State { Widget build(BuildContext context) { return SingleChildScrollView( child: Row( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, //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), + children: List.from([_todoHeader(context)]) + _buildTitles(context), ), Flexible( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: List.from([Text("header ... date, date, date .. fancy turned 60 degrees", style: Theme.of(context).dataTableTheme.headingTextStyle)]) + List.from(_content), + children: [_datesHeader(context)] + List.from(_content), ), ), ) diff --git a/lib/task_item.dart b/lib/task_item.dart index 8b1d7ed..220f679 100644 --- a/lib/task_item.dart +++ b/lib/task_item.dart @@ -26,7 +26,9 @@ class _TaskItemState extends State{ alignment: Alignment.center, width: 60.0, height: 60.0, - color: Colors.white, + decoration: BoxDecoration(border: Border( + left: BorderSide(color: Theme.of(context).colorScheme.background, width: 1) + ),), margin: const EdgeInsets.all(0.0), child: _done == null ? null : Checkbox(value: _done, onChanged: (newState) => setState(() { _done = newState!; diff --git a/pubspec.lock b/pubspec.lock index dd2a70e..0441561 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -108,7 +108,7 @@ packages: source: hosted version: "2.0.1" intl: - dependency: transitive + dependency: "direct main" description: name: intl url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 930291f..d9c64fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: collection: ^1.16.0 date_field: ^3.0.2 gap: ^2.0.1 + intl: ^0.17.0 dev_dependencies: flutter_test: