Files
photo-live/apps/mobile/lib/app/locale_controller.dart
T
2026-09-19 05:00:11 +08:00

113 lines
3.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 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<String?> read();
Future<void> write(String value);
}
/// [LocalePrefsStore] 的 shared_preferences 生产实现。
class SharedPrefsLocaleStore implements LocalePrefsStore {
const SharedPrefsLocaleStore();
static const String kKey = 'app.locale';
@override
Future<String?> read() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(kKey);
}
@override
Future<void> write(String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(kKey, value);
}
}
/// 语言设置 Notifier:状态为当前档位,[localeSettingsProvider] 全局唯一。
///
/// 生产经 main() 以持久值构造(overrideWith 注入,见 main.dart);
/// 测试可注入初始档位与内存存储。
class LocaleSettings extends Notifier<AppLocaleChoice> {
LocaleSettings({
this.initial = AppLocaleChoice.system,
LocalePrefsStore? store,
}) : _store = store ?? const SharedPrefsLocaleStore();
/// 启动注入的初始档位(main() 以持久值构造)。
final AppLocaleChoice initial;
final LocalePrefsStore _store;
@override
AppLocaleChoice build() => initial;
/// 切换档位:状态立即生效(MaterialApp 即刻重建);持久化尽力而为。
Future<void> setChoice(AppLocaleChoice choice) async {
state = choice;
try {
await _store.write(choice.persistedValue);
} on Object {
// 写失败不回滚:语言记忆属锦上添花,不值得打断交互。
}
}
/// 启动读取持久档位(main() runApp 前调用;失败按 system)。
static Future<AppLocaleChoice> readPersisted([
LocalePrefsStore store = const SharedPrefsLocaleStore(),
]) async {
try {
return AppLocaleChoice.fromPersisted(await store.read());
} on Object {
return AppLocaleChoice.system;
}
}
}
final localeSettingsProvider =
NotifierProvider<LocaleSettings, AppLocaleChoice>(LocaleSettings.new);