fix(genex-mobile): 语言偏好持久化 — 用户选择不再因重启丢失

修复 LocaleManager 仅用内存 ValueNotifier 存储语言选择的问题,
重启 App 后用户选的语言会丢失,回退到系统语言。

改动:
- pubspec.yaml: 添加 shared_preferences 依赖
- locale_manager.dart: 新增 init() 启动恢复 + setLocale() 写入持久化
  · null = 跟随系统语言(清除 SP 记录)
  · 非 null = 持久化到 SharedPreferences,重启后自动恢复
- main.dart: 启动时调用 await LocaleManager.init()
- settings_page.dart: 语言选择改用 LocaleManager.setLocale()

行为:首次安装跟随系统语言 → 用户选择后持久化 → 重启保持不变

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-03 19:39:07 -08:00
parent 0cd5c58ecb
commit e7c1e33355
4 changed files with 49 additions and 2 deletions

View File

@ -1,12 +1,15 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
///
///
/// userLocale = null
/// Locale
/// SharedPreferences
class LocaleManager {
static final ValueNotifier<Locale?> userLocale = ValueNotifier(null);
static const _prefKey = 'user_locale';
static const supportedLocales = [
Locale('zh', 'CN'),
Locale('zh', 'TW'),
@ -14,6 +17,29 @@ class LocaleManager {
Locale('ja'),
];
/// SharedPreferences
static Future<void> init() async {
final prefs = await SharedPreferences.getInstance();
final saved = prefs.getString(_prefKey);
if (saved != null) {
final locale = _parseLocale(saved);
if (locale != null) {
userLocale.value = locale;
}
}
}
/// null
static Future<void> setLocale(Locale? locale) async {
userLocale.value = locale;
final prefs = await SharedPreferences.getInstance();
if (locale == null) {
await prefs.remove(_prefKey);
} else {
await prefs.setString(_prefKey, _serializeLocale(locale));
}
}
/// locale
static Locale resolve(List<Locale>? systemLocales, Iterable<Locale> supported) {
if (systemLocales == null || systemLocales.isEmpty) {
@ -71,4 +97,21 @@ class LocaleManager {
return locale.toString();
}
}
static String _serializeLocale(Locale locale) {
if (locale.countryCode != null && locale.countryCode!.isNotEmpty) {
return '${locale.languageCode}_${locale.countryCode}';
}
return locale.languageCode;
}
static Locale? _parseLocale(String str) {
final parts = str.split('_');
if (parts.length == 2) {
return Locale(parts[0], parts[1]);
} else if (parts.length == 1 && parts[0].isNotEmpty) {
return Locale(parts[0]);
}
return null;
}
}

View File

@ -269,7 +269,7 @@ class _SettingsPageState extends State<SettingsPage> {
color: AppColors.primary, size: 22)
: null,
onTap: () {
LocaleManager.userLocale.value = locale;
LocaleManager.setLocale(locale);
setState(() {});
Navigator.pop(context);
},

View File

@ -52,6 +52,9 @@ Future<void> main() async {
//
NotificationBadgeManager().initialize();
//
await LocaleManager.init();
runApp(const GenexConsumerApp());
}

View File

@ -22,6 +22,7 @@ dependencies:
firebase_core: ^3.4.0
flutter_local_notifications: ^18.0.0
in_app_update: ^4.2.2
shared_preferences: ^2.2.3
dev_dependencies:
flutter_test: