From ceef4f4c722c9123e862b75d97efd7e9d411631c Mon Sep 17 00:00:00 2001 From: m3mo Date: Tue, 3 Feb 2026 14:20:49 +0100 Subject: [PATCH] Add offline-first mode support to settings - Add AppMode enum (local, online) - Extend settings datasource with mode, setup, and onboarding flags - Update settings viewmodel with mode helpers and persistence --- .../data/settings_local_datasource.dart | 43 +++++++++++++++++++ .../settings/domain/enums/app_mode.dart | 4 ++ .../viewmodels/settings_viewmodel.dart | 35 ++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 lib/features/settings/domain/enums/app_mode.dart diff --git a/lib/features/settings/data/settings_local_datasource.dart b/lib/features/settings/data/settings_local_datasource.dart index c0addfe..a3e4856 100644 --- a/lib/features/settings/data/settings_local_datasource.dart +++ b/lib/features/settings/data/settings_local_datasource.dart @@ -1,11 +1,19 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../domain/enums/app_mode.dart'; + abstract class SettingsLocalDataSource { Locale? getLocale(); Future setLocale(Locale locale); ThemeMode getThemeMode(); Future setThemeMode(ThemeMode mode); + AppMode? getAppMode(); + Future setAppMode(AppMode mode); + bool isSetupCompleted(); + Future setSetupCompleted(bool completed); + bool isOnboardingShown(); + Future setOnboardingShown(bool shown); } class SettingsLocalDataSourceImpl implements SettingsLocalDataSource { @@ -13,6 +21,9 @@ class SettingsLocalDataSourceImpl implements SettingsLocalDataSource { static const String _localeKey = 'locale'; static const String _themeModeKey = 'theme_mode'; + static const String _appModeKey = 'app_mode'; + static const String _setupCompletedKey = 'setup_completed'; + static const String _onboardingShownKey = 'onboarding_shown'; SettingsLocalDataSourceImpl({required this.sharedPreferences}); @@ -39,4 +50,36 @@ class SettingsLocalDataSourceImpl implements SettingsLocalDataSource { Future setThemeMode(ThemeMode mode) async { await sharedPreferences.setInt(_themeModeKey, mode.index); } + + @override + AppMode? getAppMode() { + final index = sharedPreferences.getInt(_appModeKey); + if (index == null) return null; + return AppMode.values[index]; + } + + @override + Future setAppMode(AppMode mode) async { + await sharedPreferences.setInt(_appModeKey, mode.index); + } + + @override + bool isSetupCompleted() { + return sharedPreferences.getBool(_setupCompletedKey) ?? false; + } + + @override + Future setSetupCompleted(bool completed) async { + await sharedPreferences.setBool(_setupCompletedKey, completed); + } + + @override + bool isOnboardingShown() { + return sharedPreferences.getBool(_onboardingShownKey) ?? false; + } + + @override + Future setOnboardingShown(bool shown) async { + await sharedPreferences.setBool(_onboardingShownKey, shown); + } } diff --git a/lib/features/settings/domain/enums/app_mode.dart b/lib/features/settings/domain/enums/app_mode.dart new file mode 100644 index 0000000..ff63fdb --- /dev/null +++ b/lib/features/settings/domain/enums/app_mode.dart @@ -0,0 +1,4 @@ +enum AppMode { + local, + online, +} diff --git a/lib/features/settings/presentation/viewmodels/settings_viewmodel.dart b/lib/features/settings/presentation/viewmodels/settings_viewmodel.dart index b95bce0..1d31fce 100644 --- a/lib/features/settings/presentation/viewmodels/settings_viewmodel.dart +++ b/lib/features/settings/presentation/viewmodels/settings_viewmodel.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../../../../core/logging/app_logger.dart'; import '../../data/settings_local_datasource.dart'; +import '../../domain/enums/app_mode.dart'; class SettingsViewModel extends ChangeNotifier { final SettingsLocalDataSource dataSource; @@ -16,9 +17,17 @@ class SettingsViewModel extends ChangeNotifier { Locale? _locale; ThemeMode _themeMode = ThemeMode.system; + AppMode? _appMode; + bool _setupCompleted = false; + bool _onboardingShown = false; Locale? get locale => _locale; ThemeMode get themeMode => _themeMode; + AppMode? get appMode => _appMode; + bool get setupCompleted => _setupCompleted; + bool get onboardingShown => _onboardingShown; + bool get isLocalMode => _appMode == AppMode.local; + bool get isOnlineMode => _appMode == AppMode.online; static const supportedLocales = [ Locale('en'), @@ -28,7 +37,10 @@ class SettingsViewModel extends ChangeNotifier { void _loadSettings() { _locale = dataSource.getLocale() ?? const Locale('en'); _themeMode = dataSource.getThemeMode(); - logger.info('Settings loaded: locale=$_locale, themeMode=$_themeMode'); + _appMode = dataSource.getAppMode(); + _setupCompleted = dataSource.isSetupCompleted(); + _onboardingShown = dataSource.isOnboardingShown(); + logger.info('Settings loaded: locale=$_locale, themeMode=$_themeMode, appMode=$_appMode, setupCompleted=$_setupCompleted, onboardingShown=$_onboardingShown'); } Future setLocale(Locale locale) async { @@ -45,6 +57,27 @@ class SettingsViewModel extends ChangeNotifier { notifyListeners(); } + Future setAppMode(AppMode mode) async { + _appMode = mode; + await dataSource.setAppMode(mode); + logger.info('App mode changed to: $mode'); + notifyListeners(); + } + + Future setSetupCompleted(bool completed) async { + _setupCompleted = completed; + await dataSource.setSetupCompleted(completed); + logger.info('Setup completed: $completed'); + notifyListeners(); + } + + Future setOnboardingShown(bool shown) async { + _onboardingShown = shown; + await dataSource.setOnboardingShown(shown); + logger.info('Onboarding shown: $shown'); + notifyListeners(); + } + String getLanguageName(Locale locale) { switch (locale.languageCode) { case 'en':