Change core prefs to use code generation

This commit is contained in:
problematicconsumer
2023-09-06 23:09:49 +03:30
parent 167ec5f797
commit 35866beaa0
6 changed files with 119 additions and 26 deletions

View File

@@ -13,7 +13,7 @@ class AppView extends HookConsumerWidget with PresLogger {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider); final router = ref.watch(routerProvider);
final locale = ref.watch(localeProvider).locale; final locale = ref.watch(localeNotifierProvider).locale;
final theme = ref.watch(themeProvider); final theme = ref.watch(themeProvider);
ref.watch(commonControllersProvider); ref.watch(commonControllersProvider);

View File

@@ -5,11 +5,11 @@ part 'core_providers.g.dart';
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
TranslationsEn translations(TranslationsRef ref) => TranslationsEn translations(TranslationsRef ref) =>
ref.watch(localeProvider).translations(); ref.watch(localeNotifierProvider).translations();
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
AppTheme theme(ThemeRef ref) => AppTheme( AppTheme theme(ThemeRef ref) => AppTheme(
ref.watch(themeModeProvider), ref.watch(themeModeNotifierProvider),
ref.watch(trueBlackThemeProvider), ref.watch(trueBlackThemeNotifierProvider),
ref.watch(localeProvider).preferredFontFamily, ref.watch(localeNotifierProvider).preferredFontFamily,
); );

View File

@@ -1,17 +1,28 @@
import 'package:dartx/dartx.dart'; import 'package:dartx/dartx.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/gen/fonts.gen.dart'; import 'package:hiddify/gen/fonts.gen.dart';
import 'package:hiddify/gen/translations.g.dart'; import 'package:hiddify/gen/translations.g.dart';
import 'package:hiddify/utils/pref_notifier.dart'; import 'package:hiddify/utils/pref_notifier.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
export 'package:hiddify/gen/translations.g.dart'; export 'package:hiddify/gen/translations.g.dart';
final localeProvider = AlwaysAlivePrefNotifier.provider( part 'locale_prefs.g.dart';
"locale",
AppLocale.en, @Riverpod(keepAlive: true)
mapFrom: AppLocale.values.byName, class LocaleNotifier extends _$LocaleNotifier {
mapTo: (value) => value.name, late final _pref =
); Pref(ref.watch(sharedPreferencesProvider), "locale", AppLocale.en);
@override
AppLocale build() => _pref.getValue();
Future<void> update(AppLocale value) {
state = value;
return _pref.update(value);
}
}
enum AppLocale { enum AppLocale {
en, en,

View File

@@ -1,14 +1,39 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/utils/pref_notifier.dart'; import 'package:hiddify/utils/pref_notifier.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
final themeModeProvider = AlwaysAlivePrefNotifier.provider( part 'theme_prefs.g.dart';
"theme_mode",
ThemeMode.system,
mapFrom: ThemeMode.values.byName,
mapTo: (value) => value.name,
);
final trueBlackThemeProvider = AlwaysAlivePrefNotifier.provider( @Riverpod(keepAlive: true)
"true_black_theme", class ThemeModeNotifier extends _$ThemeModeNotifier {
false, late final _pref = Pref(
); ref.watch(sharedPreferencesProvider),
"theme_mode",
ThemeMode.system,
mapFrom: ThemeMode.values.byName,
mapTo: (value) => value.name,
);
@override
ThemeMode build() => _pref.getValue();
Future<void> update(ThemeMode value) {
state = value;
return _pref.update(value);
}
}
@Riverpod(keepAlive: true)
class TrueBlackThemeNotifier extends _$TrueBlackThemeNotifier {
late final _pref =
Pref(ref.watch(sharedPreferencesProvider), "true_black_theme", false);
@override
bool build() => _pref.getValue();
Future<void> update(bool value) {
state = value;
return _pref.update(value);
}
}

View File

@@ -14,7 +14,7 @@ class GeneralSettingTiles extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final t = ref.watch(translationsProvider); final t = ref.watch(translationsProvider);
final locale = ref.watch(localeProvider); final locale = ref.watch(localeNotifierProvider);
final theme = ref.watch(themeProvider); final theme = ref.watch(themeProvider);
@@ -51,7 +51,9 @@ class GeneralSettingTiles extends HookConsumerWidget {
}, },
); );
if (selectedLocale != null) { if (selectedLocale != null) {
await ref.read(localeProvider.notifier).update(selectedLocale); await ref
.read(localeNotifierProvider.notifier)
.update(selectedLocale);
} }
}, },
), ),
@@ -66,11 +68,11 @@ class GeneralSettingTiles extends HookConsumerWidget {
), ),
trailing: ThemeModeSwitch( trailing: ThemeModeSwitch(
themeMode: theme.mode, themeMode: theme.mode,
onChanged: ref.read(themeModeProvider.notifier).update, onChanged: ref.read(themeModeNotifierProvider.notifier).update,
), ),
leading: const Icon(Icons.light_mode), leading: const Icon(Icons.light_mode),
onTap: () async { onTap: () async {
await ref.read(themeModeProvider.notifier).update( await ref.read(themeModeNotifierProvider.notifier).update(
Theme.of(context).brightness == Brightness.light Theme.of(context).brightness == Brightness.light
? ThemeMode.dark ? ThemeMode.dark
: ThemeMode.light, : ThemeMode.light,
@@ -80,7 +82,7 @@ class GeneralSettingTiles extends HookConsumerWidget {
SwitchListTile( SwitchListTile(
title: Text(t.settings.general.trueBlack), title: Text(t.settings.general.trueBlack),
value: theme.trueBlack, value: theme.trueBlack,
onChanged: ref.read(trueBlackThemeProvider.notifier).update, onChanged: ref.read(trueBlackThemeNotifierProvider.notifier).update,
), ),
if (PlatformUtils.isDesktop) ...[ if (PlatformUtils.isDesktop) ...[
SwitchListTile( SwitchListTile(

View File

@@ -3,6 +3,61 @@ import 'package:hiddify/utils/custom_loggers.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
class Pref<T> with InfraLogger {
const Pref(
this.prefs,
this.key,
this.defaultValue, {
this.mapFrom,
this.mapTo,
});
final SharedPreferences prefs;
final String key;
final T defaultValue;
final T Function(String value)? mapFrom;
final String Function(T value)? mapTo;
/// Updates the value asynchronously.
Future<void> update(T value) async {
loggy.debug("updating preference [$key] to [$value]");
try {
if (mapTo != null && mapFrom != null) {
await prefs.setString(key, mapTo!(value));
} else {
switch (value) {
case String _:
await prefs.setString(key, value);
case bool _:
await prefs.setBool(key, value);
case int _:
await prefs.setInt(key, value);
case double _:
await prefs.setDouble(key, value);
case List<String> _:
await prefs.setStringList(key, value);
}
}
} catch (e) {
loggy.warning("error updating preference[$key]: $e");
}
}
T getValue() {
try {
loggy.debug("getting persisted preference [$key]");
if (mapTo != null && mapFrom != null) {
final persisted = prefs.getString(key);
return persisted != null ? mapFrom!(persisted) : defaultValue;
}
return prefs.get(key) as T? ?? defaultValue;
} catch (e) {
loggy.warning("error getting preference[$key]: $e");
return defaultValue;
}
}
}
class PrefNotifier<T> extends AutoDisposeNotifier<T> class PrefNotifier<T> extends AutoDisposeNotifier<T>
with _Prefs<T>, InfraLogger { with _Prefs<T>, InfraLogger {
PrefNotifier( PrefNotifier(