Refactor preferences

This commit is contained in:
problematicconsumer
2023-09-06 12:56:30 +03:30
parent cf1acb0b25
commit ef1846e553
26 changed files with 303 additions and 229 deletions

View File

@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:hiddify/core/locale/locale.dart';
import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/core/prefs/prefs.dart';
import 'package:hiddify/core/router/router.dart';
import 'package:hiddify/core/theme/theme.dart';
import 'package:hiddify/features/common/common_controllers.dart';
import 'package:hiddify/gen/fonts.gen.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -15,24 +14,21 @@ class AppView extends HookConsumerWidget with PresLogger {
@override
Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider);
final locale = ref.watch(localeControllerProvider).locale;
final theme = ref.watch(themeControllerProvider);
final locale = ref.watch(localeProvider).locale;
final theme = ref.watch(themeProvider);
ref.watch(commonControllersProvider);
// HACK temporary solution
final fontFamily = locale.languageCode == "fa" ? FontFamily.shabnam : "";
return MaterialApp.router(
routerConfig: router,
locale: locale,
supportedLocales: LocalePref.locales,
supportedLocales: AppLocale.locales,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
debugShowCheckedModeBanner: false,
themeMode: theme.themeMode,
theme: theme.light(fontFamily: fontFamily),
darkTheme: theme.dark(fontFamily: fontFamily),
title: 'Hiddify',
themeMode: theme.mode,
theme: theme.light(),
darkTheme: theme.dark(),
title: 'Hiddify Next',
).animate().fadeIn();
}
}

View File

@@ -1,6 +1,15 @@
import 'package:hiddify/core/locale/locale.dart';
import 'package:hiddify/core/prefs/prefs.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
final translationsProvider = Provider<TranslationsEn>(
(ref) => ref.watch(localeControllerProvider).translations(),
);
part 'core_providers.g.dart';
@Riverpod(keepAlive: true)
TranslationsEn translations(TranslationsRef ref) =>
ref.watch(localeProvider).translations();
@riverpod
AppTheme theme(ThemeRef ref) => AppTheme(
ref.watch(themeModeProvider),
ref.watch(trueBlackThemeProvider),
ref.watch(localeProvider).preferredFontFamily,
);

View File

@@ -1,2 +0,0 @@
export 'locale_controller.dart';
export 'locale_pref.dart';

View File

@@ -1,24 +0,0 @@
import 'package:hiddify/core/locale/locale_pref.dart';
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'locale_controller.g.dart';
@Riverpod(keepAlive: true)
class LocaleController extends _$LocaleController with AppLogger {
@override
LocalePref build() {
return LocalePref.values[_prefs.getInt(_localeKey) ?? 0];
}
static const _localeKey = 'locale';
SharedPreferences get _prefs => ref.read(sharedPreferencesProvider);
Future<void> change(LocalePref locale) async {
loggy.debug('changing locale to [$locale]');
await _prefs.setInt(_localeKey, locale.index);
state = locale;
}
}

View File

@@ -1,33 +0,0 @@
import 'package:dartx/dartx.dart';
import 'package:flutter/widgets.dart';
import 'package:hiddify/gen/translations.g.dart';
export 'package:hiddify/gen/translations.g.dart';
enum LocalePref {
en,
fa;
Locale get locale {
return Locale(name);
}
static List<Locale> get locales =>
LocalePref.values.map((e) => e.locale).toList();
static LocalePref fromString(String e) {
return LocalePref.values.firstOrNullWhere((element) => element.name == e) ??
LocalePref.en;
}
static LocalePref deviceLocale() {
return LocalePref.fromString(
AppLocaleUtils.findDeviceLocale().languageCode,
);
}
TranslationsEn translations() {
final appLocale = AppLocaleUtils.parse(name);
return appLocale.build();
}
}

View File

@@ -1,12 +1,19 @@
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart';
import 'package:hiddify/core/theme/theme_prefs.dart';
// mostly exact copy of flex color scheme 7.1's fabulous 12 theme
extension AppTheme on ThemePrefs {
ThemeData light({
String fontFamily = "Shabnam",
}) {
class AppTheme {
AppTheme(
this.mode,
this.trueBlack,
this.fontFamily,
);
final ThemeMode mode;
final bool trueBlack;
final String fontFamily;
ThemeData light() {
return FlexThemeData.light(
scheme: FlexScheme.indigoM3,
surfaceMode: FlexSurfaceMode.highScaffoldLowSurface,
@@ -62,12 +69,13 @@ extension AppTheme on ThemePrefs {
tones: FlexTones.jolly(Brightness.light),
visualDensity: FlexColorScheme.comfortablePlatformDensity,
fontFamily: fontFamily,
extensions: <ThemeExtension<dynamic>>{
ConnectionButtonTheme.light,
},
);
}
ThemeData dark({
String fontFamily = "Shabnam",
}) {
ThemeData dark() {
return FlexThemeData.dark(
scheme: FlexScheme.indigoM3,
useMaterial3: true,
@@ -124,6 +132,48 @@ extension AppTheme on ThemePrefs {
// tones: FlexTones.jolly(Brightness.dark),
visualDensity: FlexColorScheme.comfortablePlatformDensity,
fontFamily: fontFamily,
extensions: <ThemeExtension<dynamic>>{
ConnectionButtonTheme.light,
},
);
}
}
class ConnectionButtonTheme extends ThemeExtension<ConnectionButtonTheme> {
const ConnectionButtonTheme({
this.idleColor,
this.connectedColor,
});
final Color? idleColor;
final Color? connectedColor;
static const ConnectionButtonTheme light = ConnectionButtonTheme(
idleColor: Color(0xFF4a4d8b),
connectedColor: Color(0xFF44a334),
);
@override
ThemeExtension<ConnectionButtonTheme> copyWith({
Color? idleColor,
Color? connectedColor,
}) =>
ConnectionButtonTheme(
idleColor: idleColor ?? this.idleColor,
connectedColor: connectedColor ?? this.connectedColor,
);
@override
ThemeExtension<ConnectionButtonTheme> lerp(
covariant ThemeExtension<ConnectionButtonTheme>? other,
double t,
) {
if (other is! ConnectionButtonTheme) {
return this;
}
return ConnectionButtonTheme(
idleColor: Color.lerp(idleColor, other.idleColor, t),
connectedColor: Color.lerp(connectedColor, other.connectedColor, t),
);
}
}

View File

@@ -0,0 +1,44 @@
import 'package:dartx/dartx.dart';
import 'package:flutter/widgets.dart';
import 'package:hiddify/gen/fonts.gen.dart';
import 'package:hiddify/gen/translations.g.dart';
import 'package:hiddify/utils/pref_notifier.dart';
export 'package:hiddify/gen/translations.g.dart';
final localeProvider = AlwaysAlivePrefNotifier.provider(
"locale",
AppLocale.deviceLocale(),
mapFrom: AppLocale.values.byName,
mapTo: (value) => value.name,
);
enum AppLocale {
en,
fa;
Locale get locale {
return Locale(name);
}
static List<Locale> get locales =>
AppLocale.values.map((e) => e.locale).toList();
static AppLocale fromString(String e) {
return AppLocale.values.firstOrNullWhere((element) => element.name == e) ??
AppLocale.en;
}
static AppLocale deviceLocale() {
return AppLocale.fromString(
AppLocaleUtils.findDeviceLocale().languageCode,
);
}
TranslationsEn translations() {
final appLocale = AppLocaleUtils.parse(name);
return appLocale.build();
}
String get preferredFontFamily => this == fa ? FontFamily.shabnam : "";
}

View File

@@ -1 +1,4 @@
export 'app_theme.dart';
export 'general_prefs.dart';
export 'locale_prefs.dart';
export 'theme_prefs.dart';

View File

@@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
import 'package:hiddify/utils/pref_notifier.dart';
final themeModeProvider = AlwaysAlivePrefNotifier.provider(
"theme_mode",
ThemeMode.system,
mapFrom: ThemeMode.values.byName,
mapTo: (value) => value.name,
);
final trueBlackThemeProvider = AlwaysAlivePrefNotifier.provider(
"true_black_theme",
false,
);

View File

@@ -1,6 +0,0 @@
import 'package:flutter/widgets.dart';
abstract class ConnectionButtonColor {
static const connected = Color.fromRGBO(89, 140, 82, 1);
static const disconnected = Color.fromRGBO(74, 77, 139, 1);
}

View File

@@ -1,4 +0,0 @@
export 'app_theme.dart';
export 'constants.dart';
export 'theme_controller.dart';
export 'theme_prefs.dart';

View File

@@ -1,41 +0,0 @@
import 'package:flutter/material.dart';
import 'package:hiddify/core/theme/theme_prefs.dart';
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'theme_controller.g.dart';
@Riverpod(keepAlive: true)
class ThemeController extends _$ThemeController with AppLogger {
@override
ThemePrefs build() {
return ThemePrefs(
themeMode: ThemeMode.values[_prefs.getInt(_themeModeKey) ?? 0],
trueBlack: _prefs.getBool(_trueBlackKey) ?? false,
);
}
SharedPreferences get _prefs => ref.read(sharedPreferencesProvider);
static const _themeModeKey = "theme_mode";
static const _trueBlackKey = "true_black";
Future<void> change({
ThemeMode? themeMode,
bool? trueBlack,
}) async {
loggy.debug('changing theme, mode=$themeMode, trueBlack=$trueBlack');
if (themeMode != null) {
await _prefs.setInt(_themeModeKey, themeMode.index);
}
if (trueBlack != null) {
await _prefs.setBool(_trueBlackKey, trueBlack);
}
state = state.copyWith(
themeMode: themeMode ?? state.themeMode,
trueBlack: trueBlack ?? state.trueBlack,
);
}
}

View File

@@ -1,14 +0,0 @@
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'theme_prefs.freezed.dart';
@freezed
class ThemePrefs with _$ThemePrefs {
const ThemePrefs._();
const factory ThemePrefs({
@Default(ThemeMode.system) ThemeMode themeMode,
@Default(false) bool trueBlack,
}) = _ThemePrefs;
}