You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
14 KiB
413 lines
14 KiB
import 'dart:async';
|
|
|
|
import 'package:agent_service/agent_service.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get_storage/get_storage.dart';
|
|
import 'package:logger/logger.dart';
|
|
import 'package:package_info_plus/package_info_plus.dart';
|
|
|
|
import '../../../core/themes/theme_service.dart';
|
|
import '../../../core/translations/app_translations.dart';
|
|
import '../../../data/services/network/dio_manager.dart';
|
|
import '../../../routes/app_routes.dart';
|
|
import '../models/language_model.dart';
|
|
import '../models/app_supported_languages.dart';
|
|
import '../../../data/services/language_manager.dart';
|
|
import '../../../data/services/version_update_service.dart';
|
|
import '../../common/widgets/version_update_dialog.dart';
|
|
|
|
class SettingsController extends GetxController {
|
|
// 语言设置
|
|
final List<LanguageModel> languageList = appSupportedLanguages; // 应用支持的语言列表
|
|
|
|
Rx<LanguageModel> currentLanguage = LanguageModel().obs; // 当前选择的语言
|
|
|
|
final GetStorage _storage = GetStorage();
|
|
|
|
// 主题服务
|
|
final ThemeService _themeService = ThemeService();
|
|
|
|
// 是否是暗黑模式
|
|
final RxBool isDarkMode = false.obs;
|
|
|
|
// 添加版本信息变量
|
|
final appVersion = ''.obs;
|
|
final buildNumber = ''.obs;
|
|
|
|
bool isCheckingUpdate = false; //状态锁,防止重复检查
|
|
DateTime? lastCheckTime; // 添加上次检查时间记录
|
|
|
|
// 隐藏功能变量
|
|
int _clickCount = 0; // 点击计数
|
|
DateTime? _lastClickTime; // 上次点击时间
|
|
final RxBool showDebugInfo = false.obs; // 是否显示调试信息
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
|
|
// 获取系统语言
|
|
_getLanguage();
|
|
|
|
// 从存储中加载上次保存的主题设置
|
|
final savedDarkMode = _themeService.isSavedDarkMode();
|
|
|
|
// 设置当前主题状态
|
|
isDarkMode.value = savedDarkMode;
|
|
|
|
// 获取应用版本信息
|
|
getAppVersion();
|
|
}
|
|
|
|
// 获取应用版本信息的方法
|
|
Future<void> getAppVersion() async {
|
|
try {
|
|
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
|
appVersion.value = packageInfo.version;
|
|
buildNumber.value = packageInfo.buildNumber;
|
|
} catch (e) {
|
|
appVersion.value = '未知';
|
|
buildNumber.value = '0';
|
|
}
|
|
}
|
|
|
|
/// 获取系统语言
|
|
/// 从存储中读取用户上次选择的语言
|
|
/// 如果没有保存记录,则默认使用第一个语言
|
|
void _getLanguage() {
|
|
String? storedLanguageCode = _storage.read('language');
|
|
//在语言列表中查找匹配的语言
|
|
LanguageModel languageToApply = languageList.firstWhere(
|
|
//查找条件:元素的value属性与从存储中读取的值匹配
|
|
(element) => element.value == storedLanguageCode,
|
|
//如果没有找到匹配的语言,返回第一个语言作为默认值
|
|
orElse: () => languageList[0],
|
|
);
|
|
currentLanguage.value = languageToApply;
|
|
}
|
|
|
|
/// 设置应用语言
|
|
/// 1. 更新Flutter的Locale设置
|
|
/// 2. 保存用户选择到本地存储
|
|
/// 3. 更新agent服务的语音识别语言设置
|
|
/// 4. 显示语言切换成功提示
|
|
/// 5. 延迟一下确保语言更新完成,然后重新进入应用
|
|
Future<void> setLanguage(LanguageModel selectedLanguage) async {
|
|
try {
|
|
// 如果用户选择的语言与当前语言一致,则直接返回,避免重复设置
|
|
// print('lxm--设置语言: ${selectedLanguage.value}');
|
|
// print('lxm--当前语言: ${currentLanguage.value.value}');
|
|
if (selectedLanguage.value == currentLanguage.value.value) {
|
|
return;
|
|
}
|
|
|
|
Locale? targetLocale;
|
|
// print('lxm--设置语言: ${selectedLanguage.value}');
|
|
|
|
if (selectedLanguage.value != 'system') {
|
|
// 用户手动选择的语言
|
|
List languageList = selectedLanguage.value.split('_');
|
|
targetLocale = Locale(languageList[0], languageList[1]);
|
|
} else {
|
|
// 跟随系统语言,使用智能匹配
|
|
targetLocale = Get.deviceLocale;
|
|
if (targetLocale != null) {
|
|
// 智能匹配系统语言到支持的语言
|
|
targetLocale = AppTranslations.getMatchedLocale(targetLocale);
|
|
}
|
|
}
|
|
|
|
if (targetLocale != null) {
|
|
Get.updateLocale(targetLocale);
|
|
Logger()
|
|
.i("设置语言: ${selectedLanguage.value} -> ${targetLocale.toString()}");
|
|
} else {
|
|
// 如果无法确定目标语言,使用智能fallback
|
|
targetLocale = AppTranslations.getSmartFallbackLocale();
|
|
Get.updateLocale(targetLocale);
|
|
Logger().i("使用fallback语言: ${targetLocale.toString()}");
|
|
}
|
|
|
|
// 保存用户选择
|
|
currentLanguage.value = selectedLanguage;
|
|
await _storage.write('language', selectedLanguage.value);
|
|
|
|
// 更新agent服务的语音识别语言设置
|
|
await _updateAgentLanguageSettings(selectedLanguage);
|
|
|
|
// 显示语言切换成功提示
|
|
Logger().i("lxm--语言切换成功: ${selectedLanguage.value}");
|
|
|
|
// 延迟一下确保语言更新完成,然后重新进入应用
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
|
|
// 重新进入应用 - 回到启动页面重新初始化
|
|
Get.offAllNamed(Routes.splash);
|
|
Get.back();
|
|
} catch (e) {
|
|
Logger().e("设置语言时出错: $e");
|
|
}
|
|
}
|
|
|
|
/// 更新agent服务的语音识别语言设置
|
|
Future<void> _updateAgentLanguageSettings(LanguageModel languageModel) async {
|
|
try {
|
|
final languageManager = Get.find<LanguageManager>();
|
|
List<String> supportedLanguages = [];
|
|
|
|
// 根据选择的语言设置对应的ASR语言代码
|
|
if (languageModel.value == 'system') {
|
|
// 跟随系统语言
|
|
final deviceLocale = Get.deviceLocale;
|
|
if (deviceLocale != null) {
|
|
final matchedLocale = AppTranslations.getMatchedLocale(deviceLocale);
|
|
final lang = matchedLocale.languageCode;
|
|
final country = matchedLocale.countryCode;
|
|
if (country != null && country.isNotEmpty) {
|
|
final normalizedLang = lang.toLowerCase();
|
|
final normalizedCountry = country.toUpperCase();
|
|
if (normalizedLang == 'tl' && normalizedCountry == 'PH') {
|
|
supportedLanguages.add('fil-PH');
|
|
} else {
|
|
supportedLanguages.add('$normalizedLang-$normalizedCountry');
|
|
}
|
|
} else {
|
|
// 根据语言代码映射到对应的ASR代码
|
|
final asrCode = languageManager.getAsrCodeByShortCode(lang);
|
|
if (asrCode != null) {
|
|
supportedLanguages.add(asrCode);
|
|
} else {
|
|
supportedLanguages.add('en-US'); // 默认英语
|
|
}
|
|
}
|
|
} else {
|
|
supportedLanguages.add('en-US'); // 默认英语
|
|
}
|
|
} else {
|
|
// 根据选择的语言值映射到ASR代码
|
|
final parts = languageModel.value.split('_');
|
|
if (parts.length == 2) {
|
|
final lang = parts[0].toLowerCase();
|
|
final country = parts[1].toUpperCase();
|
|
|
|
if (lang == 'zh' &&
|
|
(country == 'HK' || country == 'TW' || country == 'CN')) {
|
|
supportedLanguages.add('zh-$country');
|
|
} else if (lang == 'tl' && country == 'PH') {
|
|
supportedLanguages.add('fil-PH');
|
|
} else {
|
|
supportedLanguages.add('$lang-$country');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 确保至少有一个语言
|
|
if (supportedLanguages.isEmpty) {
|
|
supportedLanguages.add('en-US');
|
|
}
|
|
|
|
Logger().i('更新agent服务语音识别语言: ${supportedLanguages.join(', ')}');
|
|
|
|
// 调用agent服务更新语言设置
|
|
final success =
|
|
await AgentService.setSupportedLanguages(supportedLanguages);
|
|
if (success) {
|
|
Logger().i('agent服务语言设置更新成功');
|
|
} else {
|
|
Logger().w('agent服务语言设置更新失败');
|
|
}
|
|
} catch (e) {
|
|
Logger().e('更新agent服务语言设置时出错: $e');
|
|
}
|
|
}
|
|
|
|
// 切换主题
|
|
Future<void> toggleTheme() async {
|
|
// 切换暗黑模式状态
|
|
isDarkMode.value = !isDarkMode.value;
|
|
|
|
// 更新全局主题
|
|
Get.changeThemeMode(isDarkMode.value ? ThemeMode.dark : ThemeMode.light);
|
|
|
|
// 保存用户选择的主题设置 - 确保立即写入存储
|
|
await _themeService.saveThemeMode(isDarkMode.value);
|
|
}
|
|
|
|
/// 清除BLE配对设备
|
|
// Future<void> clearBleDevices() async {
|
|
// // 显示确认对话框
|
|
// final confirmed = await Get.dialog<bool>(
|
|
// AlertDialog(
|
|
// title: const Text('清除配对设备'),
|
|
// content: const Text('确定要清除所有BLE配对设备吗?此操作不可撤销。'),
|
|
// actions: [
|
|
// TextButton(
|
|
// onPressed: () => Get.back(result: false),
|
|
// child: Text('cancel'.tr),
|
|
// ),
|
|
// TextButton(
|
|
// onPressed: () => Get.back(result: true),
|
|
// style: TextButton.styleFrom(
|
|
// foregroundColor: Colors.red,
|
|
// ),
|
|
// child: Text('confirm'.tr), //确认
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// );
|
|
|
|
// if (confirmed == true) {
|
|
// try {
|
|
// final bleManager = Get.find<BleManager>();
|
|
// final result = await bleManager.clearPairedDevices();
|
|
// if (result) {
|
|
// Get.snackbar('成功', 'BLE配对设备已清除');
|
|
// } else {
|
|
// Get.snackbar('失败', '清除BLE配对设备失败');
|
|
// }
|
|
// } catch (e) {
|
|
// Get.snackbar('错误', '清除BLE配对设备时发生错误');
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
/// 手动检查版本更新
|
|
Future<void> checkForUpdate() async {
|
|
// 检查是否在2秒内重复调用
|
|
final now = DateTime.now();
|
|
if (lastCheckTime != null && now.difference(lastCheckTime!).inSeconds < 2) {
|
|
// 在2秒内重复调用,直接返回
|
|
// Get.snackbar(
|
|
// 'checkUpdate'.tr,
|
|
// 'checkUpdateTooFrequent'.tr, // 检查更新过于频繁,请稍后再试
|
|
// snackPosition: SnackPosition.TOP,
|
|
// backgroundColor: Colors.orange.withValues(alpha: 0.8),
|
|
// colorText: Colors.white,
|
|
// );
|
|
return;
|
|
}
|
|
|
|
if (isCheckingUpdate) return;
|
|
isCheckingUpdate = true;
|
|
lastCheckTime = now; // 记录本次检查时间
|
|
|
|
// 用于跟踪我们的对话框
|
|
bool dialogShown = false;
|
|
|
|
try {
|
|
// 显示加载提示
|
|
dialogShown = true;
|
|
Get.dialog(
|
|
const Center(
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
barrierDismissible: false,
|
|
);
|
|
|
|
final versionService = VersionUpdateService.to;
|
|
final updateInfo = await versionService.checkForUpdate();
|
|
|
|
// 关闭加载提示 - 使用精确的关闭方式
|
|
if (dialogShown) {
|
|
dialogShown = false;
|
|
// 直接关闭最顶层的对话框,不依赖状态判断
|
|
Navigator.of(Get.overlayContext!).pop();
|
|
}
|
|
|
|
if (updateInfo.hasUpdate) {
|
|
// 显示更新对话框
|
|
await VersionUpdateDialog.show(updateInfo);
|
|
} else {
|
|
// 显示已是最新版本的提示
|
|
Get.snackbar(
|
|
'checkUpdate'.tr,
|
|
'currentLatestVersion'
|
|
.tr //当前已是最新版本
|
|
.replaceAll('{version}', updateInfo.currentVersion),
|
|
snackPosition: SnackPosition.TOP,
|
|
backgroundColor: Colors.green.withValues(alpha: 0.8),
|
|
colorText: Colors.white,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
// 关闭加载提示 - 异常情况下的可靠关闭
|
|
if (dialogShown) {
|
|
dialogShown = false;
|
|
try {
|
|
// 尝试直接关闭
|
|
Navigator.of(Get.overlayContext!).pop();
|
|
} catch (popError) {
|
|
// 如果直接关闭失败,使用备用方案
|
|
if (Get.isDialogOpen == true) {
|
|
Get.back();
|
|
}
|
|
}
|
|
}
|
|
|
|
Get.snackbar(
|
|
'error'.tr,
|
|
'networkErrorRetry'.tr, // 网络错误,请稍后重试
|
|
snackPosition: SnackPosition.TOP,
|
|
backgroundColor: Colors.red.withValues(alpha: 0.8),
|
|
colorText: Colors.white,
|
|
);
|
|
} finally {
|
|
isCheckingUpdate = false;
|
|
}
|
|
}
|
|
|
|
/// 处理隐藏功能点击
|
|
void handleSecretTap() {
|
|
final now = DateTime.now();
|
|
|
|
// 如果距离上次点击超过2秒,重置计数
|
|
if (_lastClickTime != null &&
|
|
now.difference(_lastClickTime!).inSeconds > 2) {
|
|
_clickCount = 0;
|
|
}
|
|
|
|
_lastClickTime = now;
|
|
_clickCount++;
|
|
|
|
// 点击5次后显示版本信息
|
|
if (_clickCount >= 5) {
|
|
showDebugInfo.value = !showDebugInfo.value;
|
|
_clickCount = 0;
|
|
|
|
// Get.snackbar(
|
|
// showDebugInfo.value ? '调试信息已显示' : '调试信息已隐藏',
|
|
// '版本服务数据',
|
|
// snackPosition: SnackPosition.TOP,
|
|
// backgroundColor: Colors.blue.withOpacity(0.8),
|
|
// colorText: Colors.white,
|
|
// duration: const Duration(seconds: 1),
|
|
// );
|
|
}
|
|
}
|
|
|
|
/// 获取当前应用信息
|
|
String getSomeAppInfo() {
|
|
try {
|
|
final versionService = Get.find<VersionUpdateService>();
|
|
return '''
|
|
应用版本: ${versionService.cachedAppVersion}
|
|
构建号: ${versionService.cachedBuildNumber}
|
|
平台: ${versionService.cachedPlatform}
|
|
设备品牌: ${versionService.cachedDeviceBrand}
|
|
渠道: ${versionService.cachedChannel}
|
|
最新版本: ${versionService.cachedLatestVersion}
|
|
有更新: ${versionService.cachedHasUpdate}
|
|
强制更新: ${versionService.cachedIsForceUpdate}
|
|
更新链接: ${versionService.cachedUpdateUrl}
|
|
游客模式: ${versionService.cachedShowTourists}
|
|
最近版本检查时间: ${versionService.lastCheckTime ?? '未检查'}
|
|
国家地区编码: ${versionService.cachedCountryCode}
|
|
语言编码: ${versionService.cachedLanguageCode}
|
|
服务器地址: ${DioManager().dio.options.baseUrl}
|
|
''';
|
|
} catch (e) {
|
|
return '获取版本服务数据失败: $e';
|
|
}
|
|
}
|
|
}
|
|
|