diff --git a/lib/main.dart b/lib/main.dart index 95de0cf..f401002 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_zustand/flutter_zustand.dart'; import 'package:iris/info.dart'; import 'package:iris/pages/home_page.dart'; +import 'package:iris/store/use_app_store.dart'; import 'package:iris/utils/is_desktop.dart'; import 'package:media_kit/media_kit.dart'; import 'package:window_manager/window_manager.dart'; @@ -37,6 +38,18 @@ class MyApp extends HookWidget { @override Widget build(BuildContext context) { + String theme = useAppStore().select(context, (state) => state.theme); + + ThemeMode themeMode = useMemoized( + () => + { + 'auto': ThemeMode.system, + 'light': ThemeMode.light, + 'dark': ThemeMode.dark, + }[theme] ?? + ThemeMode.system, + [theme]); + return MaterialApp( title: INFO.title, theme: ThemeData( @@ -44,7 +57,7 @@ class MyApp extends HookWidget { useMaterial3: true, ), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, + themeMode: themeMode, home: const HomePage(), ); } diff --git a/lib/pages/settings/general.dart b/lib/pages/settings/general.dart new file mode 100644 index 0000000..609982c --- /dev/null +++ b/lib/pages/settings/general.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_zustand/flutter_zustand.dart'; +import 'package:iris/store/use_app_store.dart'; +import 'package:iris/widgets/show_theme_color_dialog.dart'; + +class General extends HookWidget { + const General({super.key}); + + @override + Widget build(BuildContext context) { + final theme = useAppStore().select(context, (state) => state.theme); + + return Column(children: [ + ListTile( + leading: Icon(theme == 'light' + ? Icons.light_mode_rounded + : theme == 'dark' + ? Icons.dark_mode_rounded + : Icons.contrast_rounded), + title: const Text('Theme color'), + subtitle: Text(theme), + onTap: () => showThemeColorDialog(context), + ), + ]); + } +} diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index df27ccb..5ee6793 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:iris/pages/settings/about.dart'; +import 'package:iris/pages/settings/general.dart'; import 'package:iris/pages/settings/libraries.dart'; class Settings extends HookWidget { @@ -18,7 +19,9 @@ class Settings extends HookWidget { child: TabBarView( controller: tabController, children: const [ - Center(child: Text('General')), + SingleChildScrollView( + child: General(), + ), SingleChildScrollView( child: About(), ), diff --git a/lib/store/use_app_store.dart b/lib/store/use_app_store.dart index 3c0efab..977ac83 100644 --- a/lib/store/use_app_store.dart +++ b/lib/store/use_app_store.dart @@ -18,6 +18,11 @@ class AppStore extends PersistentStore { Future toggleFullScreen() async => set(state.copyWith(isFullScreen: !state.isFullScreen)); + Future updateTheme(String theme) async { + set(state.copyWith(theme: theme)); + save(state); + } + @override Future load() async { try { diff --git a/lib/widgets/show_theme_color_dialog.dart b/lib/widgets/show_theme_color_dialog.dart new file mode 100644 index 0000000..a6349e8 --- /dev/null +++ b/lib/widgets/show_theme_color_dialog.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_zustand/flutter_zustand.dart'; +import 'package:iris/store/use_app_store.dart'; + +Future showThemeColorDialog(BuildContext context) async => + await showDialog( + context: context, + builder: (context) => const ThemeColorDialog(), + ); + +class ThemeColorDialog extends HookWidget { + const ThemeColorDialog({super.key}); + + @override + Widget build(BuildContext context) { + final theme = useAppStore().select(context, (state) => state.theme); + return AlertDialog( + title: const Text('Theme color'), + content: SingleChildScrollView( + child: Column( + children: [ + ListTile( + title: const Text('Auto'), + leading: Radio( + value: 'auto', + groupValue: theme, + onChanged: (_) { + useAppStore().updateTheme('auto'); + Navigator.pop(context); + }, + ), + onTap: () { + useAppStore().updateTheme('auto'); + Navigator.pop(context); + }, + ), + ListTile( + title: const Text('Light'), + leading: Radio( + value: 'light', + groupValue: theme, + onChanged: (_) { + useAppStore().updateTheme('light'); + Navigator.pop(context); + }, + ), + onTap: () { + useAppStore().updateTheme('light'); + Navigator.pop(context); + }, + ), + ListTile( + title: const Text('Dark'), + leading: Radio( + value: 'dark', + groupValue: theme, + onChanged: (_) { + useAppStore().updateTheme('dark'); + Navigator.pop(context); + }, + ), + onTap: () { + useAppStore().updateTheme('dark'); + Navigator.pop(context); + }, + ), + ], + )), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'Cancel'), + child: const Text('Cancel'), + ), + ], + ); + } +} diff --git a/lib/widgets/storage_dialog/show_local_alert_dialog.dart b/lib/widgets/storage_dialog/show_local_alert_dialog.dart index b1ba559..067662b 100644 --- a/lib/widgets/storage_dialog/show_local_alert_dialog.dart +++ b/lib/widgets/storage_dialog/show_local_alert_dialog.dart @@ -4,14 +4,11 @@ import 'package:iris/models/storages/local_storage.dart'; import 'package:iris/store/use_storage_store.dart'; Future showLocalAlertDialog(BuildContext context, - {LocalStorage? localStorage}) async { - await showDialog( - context: context, - builder: (BuildContext context) { - return LocalDialog(localStorage: localStorage); - }, - ); -} + {LocalStorage? localStorage}) async => + await showDialog( + context: context, + builder: (BuildContext context) => + LocalDialog(localStorage: localStorage)); class LocalDialog extends HookWidget { const LocalDialog({super.key, this.localStorage}); diff --git a/lib/widgets/storage_dialog/show_webdav_alert_dialog.dart b/lib/widgets/storage_dialog/show_webdav_alert_dialog.dart index e71edb6..695364c 100644 --- a/lib/widgets/storage_dialog/show_webdav_alert_dialog.dart +++ b/lib/widgets/storage_dialog/show_webdav_alert_dialog.dart @@ -4,14 +4,13 @@ import 'package:iris/models/storages/webdav_storage.dart'; import 'package:iris/store/use_storage_store.dart'; Future showWebDAVAlertDialog(BuildContext context, - {WebdavStorage? webdavStorage}) async { - await showDialog( - context: context, - builder: (BuildContext context) { - return WebDAVDialog(webdavStorage: webdavStorage); - }, - ); -} + {WebdavStorage? webdavStorage}) async => + await showDialog( + context: context, + builder: (BuildContext context) { + return WebDAVDialog(webdavStorage: webdavStorage); + }, + ); class WebDAVDialog extends HookWidget { const WebDAVDialog({super.key, this.webdavStorage});