app_provider.dart 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:shared_preferences/shared_preferences.dart';
  4. // ── SharedPreferences Provider ────────────────────────
  5. final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
  6. throw UnimplementedError('在 main.dart 中 override 此 Provider');
  7. });
  8. // ── 主题模式 ─────────────────────────────────────────
  9. const _kThemeKey = 'theme_mode';
  10. class ThemeNotifier extends Notifier<ThemeMode> {
  11. @override
  12. ThemeMode build() {
  13. final prefs = ref.read(sharedPreferencesProvider);
  14. final saved = prefs.getString(_kThemeKey);
  15. return switch (saved) {
  16. 'light' => ThemeMode.light,
  17. 'dark' => ThemeMode.dark,
  18. _ => ThemeMode.dark, // 默认夜间模式
  19. };
  20. }
  21. /// 切换主题
  22. void setTheme(ThemeMode mode) {
  23. state = mode;
  24. final prefs = ref.read(sharedPreferencesProvider);
  25. prefs.setString(_kThemeKey, mode.name);
  26. }
  27. /// 在深色与浅色之间切换
  28. void toggle() {
  29. setTheme(state == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark);
  30. }
  31. }
  32. final themeProvider = NotifierProvider<ThemeNotifier, ThemeMode>(
  33. ThemeNotifier.new,
  34. );
  35. // ── 语言设置 ─────────────────────────────────────────
  36. const _kLocaleKey = 'locale';
  37. const _kLocaleCountryKey = 'locale_country';
  38. /// 支持的语言列表:与 [MaterialApp.router] 的 `supportedLocales` 一致。
  39. const supportedLanguages = <({String label, Locale locale})>[
  40. (label: '简体中文', locale: Locale('zh')),
  41. (label: '繁體中文', locale: Locale('zh', 'TW')),
  42. (label: 'English', locale: Locale('en')),
  43. (label: 'हिन्दी', locale: Locale('hi')),
  44. (label: 'Bahasa Indonesia', locale: Locale('id')),
  45. (label: '日本語', locale: Locale('ja')),
  46. (label: '한국어', locale: Locale('ko')),
  47. ];
  48. class LocaleNotifier extends Notifier<Locale> {
  49. @override
  50. Locale build() {
  51. final prefs = ref.read(sharedPreferencesProvider);
  52. final lang = prefs.getString(_kLocaleKey);
  53. final country = prefs.getString(_kLocaleCountryKey) ?? '';
  54. if (lang != null) {
  55. return country.isNotEmpty ? Locale(lang, country) : Locale(lang);
  56. }
  57. return const Locale('zh');
  58. }
  59. /// 切换语言,立即生效(无需重启 App)
  60. void setLocale(Locale locale) {
  61. state = locale;
  62. final prefs = ref.read(sharedPreferencesProvider);
  63. prefs.setString(_kLocaleKey, locale.languageCode);
  64. prefs.setString(_kLocaleCountryKey, locale.countryCode ?? '');
  65. }
  66. }
  67. final localeProvider = NotifierProvider<LocaleNotifier, Locale>(
  68. LocaleNotifier.new,
  69. );
  70. /// [Locale] → 后端 `lang` 参数(与 Dio `lang` Header、`uc/ancillary/more/help` 等一致)
  71. String backendLangFromLocale(Locale locale) {
  72. switch (locale.languageCode) {
  73. case 'zh':
  74. return locale.countryCode == 'TW' ? 'zh_HK' : 'zh_CN';
  75. case 'en':
  76. return 'en_US';
  77. case 'hi':
  78. return 'hi_IN';
  79. case 'id':
  80. return 'id_ID';
  81. case 'ja':
  82. return 'ja_JP';
  83. case 'ko':
  84. return 'ko_KR';
  85. default:
  86. return 'zh_CN';
  87. }
  88. }