feat(ui): add themed shell navigation

This commit is contained in:
2026-04-23 21:57:24 +02:00
parent bf67e9c2ae
commit 8cf6e95474
14 changed files with 531 additions and 122 deletions

View File

@ -1,3 +1,5 @@
// ignore_for_file: file_names
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -21,43 +23,61 @@ class SharedPrefNotifier<T> extends StateNotifier<T> {
// Helper to get the value with proper typing
static T _getValue<T>(SharedPreferences prefs, String key, T defaultValue) {
switch (T) {
case String:
return prefs.getString(key) as T ?? defaultValue;
case bool:
return prefs.getBool(key) as T ?? defaultValue;
case int:
return prefs.getInt(key) as T ?? defaultValue;
case double:
return prefs.getDouble(key) as T ?? defaultValue;
case const (List<String>):
return prefs.getStringList(key) as T ?? defaultValue;
default:
throw UnsupportedError('Type $T not supported by SharedPreferences');
if (T == String) {
return prefs.getString(key) as T? ?? defaultValue;
}
if (T == bool) {
return prefs.getBool(key) as T? ?? defaultValue;
}
if (T == int) {
return prefs.getInt(key) as T? ?? defaultValue;
}
if (T == double) {
return prefs.getDouble(key) as T? ?? defaultValue;
}
if (T == List<String>) {
return prefs.getStringList(key) as T? ?? defaultValue;
}
throw UnsupportedError('Type $T not supported by SharedPreferences');
}
Future<void> update(T value) async {
switch (T) {
case String:
await prefs.setString(key, value as String);
break;
case bool:
await prefs.setBool(key, value as bool);
break;
case int:
await prefs.setInt(key, value as int);
break;
case double:
await prefs.setDouble(key, value as double);
break;
case const (List<String>):
await prefs.setStringList(key, value as List<String>);
break;
default:
throw UnsupportedError('Type $T not supported by SharedPreferences');
if (T == String) {
await prefs.setString(key, value as String);
state = value;
return;
}
state = value;
if (T == bool) {
await prefs.setBool(key, value as bool);
state = value;
return;
}
if (T == int) {
await prefs.setInt(key, value as int);
state = value;
return;
}
if (T == double) {
await prefs.setDouble(key, value as double);
state = value;
return;
}
if (T == List<String>) {
await prefs.setStringList(key, value as List<String>);
state = value;
return;
}
throw UnsupportedError('Type $T not supported by SharedPreferences');
}
}
@ -70,3 +90,37 @@ final isDarkModeProvider =
defaultValue: false,
);
});
enum AppThemePreference {
system,
light,
dark,
}
class ThemePreferenceNotifier extends StateNotifier<AppThemePreference> {
ThemePreferenceNotifier(this._prefs)
: super(_themePreferenceFromStorage(_prefs.getString(_themeModeKey)));
static const String _themeModeKey = 'app_theme_preference';
final SharedPreferences _prefs;
Future<void> update(AppThemePreference value) async {
await _prefs.setString(_themeModeKey, value.name);
state = value;
}
}
AppThemePreference _themePreferenceFromStorage(String? value) {
return switch (value) {
'light' => AppThemePreference.light,
'dark' => AppThemePreference.dark,
_ => AppThemePreference.system,
};
}
final appThemePreferenceProvider =
StateNotifierProvider<ThemePreferenceNotifier, AppThemePreference>((ref) {
final prefs = ref.watch(sharedPreferencesProvider);
return ThemePreferenceNotifier(prefs);
});