From 9b14a28d862f6742a691abf8ff2cc47e258a31e1 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Tue, 1 Jul 2025 22:22:16 +0200 Subject: [PATCH] Add settings screen --- .../{login_screens.dart => login_screen.dart} | 5 +- .../lib/routes/settings/settings_screen.dart | 74 +++++++++++++++++++ moneymgr_mobile/lib/services/auth_state.dart | 8 +- .../lib/services/router/router.dart | 11 +-- .../lib/services/router/routes_list.dart | 6 +- moneymgr_mobile/lib/utils/extensions.dart | 3 +- 6 files changed, 92 insertions(+), 15 deletions(-) rename moneymgr_mobile/lib/routes/login/{login_screens.dart => login_screen.dart} (94%) create mode 100644 moneymgr_mobile/lib/routes/settings/settings_screen.dart diff --git a/moneymgr_mobile/lib/routes/login/login_screens.dart b/moneymgr_mobile/lib/routes/login/login_screen.dart similarity index 94% rename from moneymgr_mobile/lib/routes/login/login_screens.dart rename to moneymgr_mobile/lib/routes/login/login_screen.dart index 486e10e..a34d116 100644 --- a/moneymgr_mobile/lib/routes/login/login_screens.dart +++ b/moneymgr_mobile/lib/routes/login/login_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:moneymgr_mobile/routes/login/login_model.dart'; +import 'package:moneymgr_mobile/services/router/routes_list.dart'; import 'package:moneymgr_mobile/widgets/app_button.dart'; import '../../../services/auth_state.dart'; @@ -20,7 +21,7 @@ class LoginScreen extends HookConsumerWidget { final usernameController = useTextEditingController(); final passwordController = useTextEditingController(); - void onSettingsPressed() => context.push('/settings'); + void onSettingsPressed() => context.push(settingsPage); Future onLoginPressed() async { try { @@ -36,7 +37,7 @@ class LoginScreen extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: const Text('Login'), + title: const Text('MoneyMgr'), actions: [ IconButton( onPressed: onSettingsPressed, diff --git a/moneymgr_mobile/lib/routes/settings/settings_screen.dart b/moneymgr_mobile/lib/routes/settings/settings_screen.dart new file mode 100644 index 0000000..f1765e4 --- /dev/null +++ b/moneymgr_mobile/lib/routes/settings/settings_screen.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:moneymgr_mobile/providers/settings.dart'; +import 'package:moneymgr_mobile/utils/extensions.dart'; + +class SettingsScreen extends ConsumerWidget { + const SettingsScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final themeMode = ref.watch(currentThemeModeProvider); + + void onTapThemeMode() => + showDialog(context: context, builder: (_) => const _ThemeModeDialog()); + + void onTapLicenses() => context.showAppLicensePage(); + + return Scaffold( + appBar: AppBar(title: const Text('Settings')), + body: ListView( + children: [ + ListTile( + leading: const Icon(Icons.brightness_6), + title: const Text('Theme mode'), + trailing: Text(themeMode.label), + onTap: onTapThemeMode, + ), + const Divider(), + ListTile( + leading: const Icon(Icons.info_outline), + title: const Text('Licenses'), + onTap: onTapLicenses, + ), + ], + ), + ); + } +} + +/// Select theme dialog +class _ThemeModeDialog extends ConsumerWidget { + const _ThemeModeDialog(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + void onTapOption(ThemeMode themeMode) { + ref.read(currentThemeModeProvider.notifier).set(themeMode); + Navigator.of(context).pop(); + } + + return SimpleDialog( + clipBehavior: Clip.antiAlias, + children: [ + for (final themeMode in ThemeMode.values) + _ThemeModeDialogOption( + value: themeMode, + onTap: () => onTapOption(themeMode), + ), + ], + ); + } +} + +class _ThemeModeDialogOption extends StatelessWidget { + const _ThemeModeDialogOption({required this.value, required this.onTap}); + + final ThemeMode value; + final GestureTapCallback? onTap; + + @override + Widget build(BuildContext context) { + return ListTile(onTap: onTap, title: Text(value.label)); + } +} diff --git a/moneymgr_mobile/lib/services/auth_state.dart b/moneymgr_mobile/lib/services/auth_state.dart index 46fd23d..7f54e11 100644 --- a/moneymgr_mobile/lib/services/auth_state.dart +++ b/moneymgr_mobile/lib/services/auth_state.dart @@ -56,12 +56,12 @@ class CurrentAuthState extends _$CurrentAuthState { /// The possible authentication states of the app. enum AuthState { - unknown(redirectPath: homePath, allowedPaths: [homePath]), + unknown(redirectPath: homePage, allowedPaths: [homePage]), unauthenticated( - redirectPath: authPath, - allowedPaths: [authPath, settingsPath], + redirectPath: authPage, + allowedPaths: [authPage, settingsPage], ), - authenticated(redirectPath: homePath, allowedPaths: null); + authenticated(redirectPath: homePage, allowedPaths: null); const AuthState({required this.redirectPath, required this.allowedPaths}); diff --git a/moneymgr_mobile/lib/services/router/router.dart b/moneymgr_mobile/lib/services/router/router.dart index 4ff6d87..c668301 100644 --- a/moneymgr_mobile/lib/services/router/router.dart +++ b/moneymgr_mobile/lib/services/router/router.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:moneymgr_mobile/routes/login/login_screens.dart'; +import 'package:moneymgr_mobile/routes/login/login_screen.dart'; +import 'package:moneymgr_mobile/routes/settings/settings_screen.dart'; import 'package:moneymgr_mobile/services/auth_state.dart'; import 'package:moneymgr_mobile/services/router/routes_list.dart'; import 'package:moneymgr_mobile/widgets/scaffold_with_navigation.dart'; @@ -58,11 +59,11 @@ GoRouter router(Ref ref) { debugLogDiagnostics: true, initialLocation: navigationItems.first.path, routes: [ - GoRoute(path: homePath, builder: (_, __) => const Scaffold()), - GoRoute(path: authPath, builder: (_, __) => const LoginScreen()), + GoRoute(path: homePage, builder: (_, __) => const Scaffold()), + GoRoute(path: authPage, builder: (_, __) => const LoginScreen()), GoRoute( - path: settingsPath, - builder: (_, __) => const Text("settings screen"), + path: settingsPage, + builder: (_, __) => const SettingsScreen(), ), // Configuration for the bottom navigation bar routes. The routes themselves diff --git a/moneymgr_mobile/lib/services/router/routes_list.dart b/moneymgr_mobile/lib/services/router/routes_list.dart index 74ccc9a..33aa071 100644 --- a/moneymgr_mobile/lib/services/router/routes_list.dart +++ b/moneymgr_mobile/lib/services/router/routes_list.dart @@ -1,7 +1,7 @@ -const homePath = "/"; +const homePage = "/"; /// Authentication path -const authPath = "/login"; +const authPage = "/login"; /// Settings path -const settingsPath = "/settings"; \ No newline at end of file +const settingsPage = "/settings"; \ No newline at end of file diff --git a/moneymgr_mobile/lib/utils/extensions.dart b/moneymgr_mobile/lib/utils/extensions.dart index 9dd0c0a..ce7aed5 100644 --- a/moneymgr_mobile/lib/utils/extensions.dart +++ b/moneymgr_mobile/lib/utils/extensions.dart @@ -25,7 +25,8 @@ extension BuildContextX on BuildContext { void showAppLicensePage() => showLicensePage( context: this, useRootNavigator: true, - applicationName: 'DummyMart', + applicationName: 'MoneyMgr', + applicationLegalese: '(c) Pierre HUBERT 2025 - ${DateTime.now().year}' ); }