/// App 语言设置(P3 计划 Task 10 完整版)。 /// /// 三档选择(跟随系统 / 中文 / English),持久化于 shared_preferences /// 键 `app.locale`('system'|'zh'|'en')。main() 在 runApp 前读持久值 /// 注入 Notifier 初始状态——首帧即正确语言(无 system→选择闪变); /// 持久值非法(旧版本/手改损坏)回退 system。 /// /// 存储读写失败均不阻断:读失败按 system;写失败保留本次会话状态 /// (仅丢失记忆,下次启动回退旧值)。 library; import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// 语言档位(枚举值顺序即设置页选项顺序)。 enum AppLocaleChoice { /// 跟随系统(MaterialApp.locale=null,交由 localeResolutionCallback 解析)。 system('system'), /// 固定中文。 zh('zh'), /// 固定英文。 en('en'); const AppLocaleChoice(this.persistedValue); /// 持久化字符串(shared_preferences `app.locale` 的值域)。 final String persistedValue; /// 对应 [MaterialApp.locale];system 为 null。 Locale? get locale => switch (this) { AppLocaleChoice.system => null, AppLocaleChoice.zh => const Locale('zh'), AppLocaleChoice.en => const Locale('en'), }; /// 持久值解析;null/未知值回退 [system](前向兼容未来新增档位)。 static AppLocaleChoice fromPersisted(String? value) => AppLocaleChoice.values.firstWhere( (choice) => choice.persistedValue == value, orElse: () => AppLocaleChoice.system, ); } /// 存储抽象(测试注入内存实现;生产=shared_preferences 单键)。 abstract class LocalePrefsStore { Future read(); Future write(String value); } /// [LocalePrefsStore] 的 shared_preferences 生产实现。 class SharedPrefsLocaleStore implements LocalePrefsStore { const SharedPrefsLocaleStore(); static const String kKey = 'app.locale'; @override Future read() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString(kKey); } @override Future write(String value) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(kKey, value); } } /// 语言设置 Notifier:状态为当前档位,[localeSettingsProvider] 全局唯一。 /// /// 生产经 main() 以持久值构造(overrideWith 注入,见 main.dart); /// 测试可注入初始档位与内存存储。 class LocaleSettings extends Notifier { LocaleSettings({ this.initial = AppLocaleChoice.system, LocalePrefsStore? store, }) : _store = store ?? const SharedPrefsLocaleStore(); /// 启动注入的初始档位(main() 以持久值构造)。 final AppLocaleChoice initial; final LocalePrefsStore _store; @override AppLocaleChoice build() => initial; /// 切换档位:状态立即生效(MaterialApp 即刻重建);持久化尽力而为。 Future setChoice(AppLocaleChoice choice) async { state = choice; try { await _store.write(choice.persistedValue); } on Object { // 写失败不回滚:语言记忆属锦上添花,不值得打断交互。 } } /// 启动读取持久档位(main() runApp 前调用;失败按 system)。 static Future readPersisted([ LocalePrefsStore store = const SharedPrefsLocaleStore(), ]) async { try { return AppLocaleChoice.fromPersisted(await store.read()); } on Object { return AppLocaleChoice.system; } } } final localeSettingsProvider = NotifierProvider(LocaleSettings.new);