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.
444 lines
14 KiB
444 lines
14 KiB
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:dio/dio.dart';
|
|
import 'package:get_storage/get_storage.dart';
|
|
import '../../../core/themes/theme_service.dart';
|
|
import '../../../data/services/speech_factory.dart';
|
|
import '../models/language_model.dart';
|
|
import 'package:logger/logger.dart';
|
|
import '../../../data/models/user_Info.dart';
|
|
import '../../../data/services/ble_manager.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'dart:io';
|
|
import 'package:package_info_plus/package_info_plus.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import 'dart:async';
|
|
import 'package:app_settings/app_settings.dart';
|
|
|
|
class SettingsController extends GetxController {
|
|
// 语言设置
|
|
final List<LanguageModel> languageList = [
|
|
LanguageModel(
|
|
name: 'followingSystem', // 跟随系统.tr
|
|
alias: '',
|
|
value: 'system'),
|
|
LanguageModel(name: 'english', alias: 'English', value: 'en_US'), // 英语.tr
|
|
LanguageModel(name: 'chinese', alias: '中文', value: 'zh_CN'), // 中文.tr
|
|
LanguageModel(
|
|
name: 'traditionalChinese', alias: '繁體中文', value: 'zh_HK'), // 添加繁体中文
|
|
LanguageModel(
|
|
name: 'spanish', alias: 'Español', value: 'es_ES'), // 添加西班牙语选项
|
|
LanguageModel(
|
|
name: 'portuguese', alias: 'Português', value: 'pt_PT'), // 添加葡萄牙语
|
|
LanguageModel(name: 'japanese', alias: '日本語', value: 'ja_JP'), // 添加日语选项
|
|
LanguageModel(name: 'korean', alias: '한국어', value: 'ko_KR'), // 添加韩语选项
|
|
LanguageModel(name: 'french', alias: 'Français', value: 'fr_FR'), // 添加法语选项
|
|
LanguageModel(name: 'german', alias: 'Deutsch', value: 'de_DE'), // 添加德语选项
|
|
LanguageModel(name: 'russian', alias: 'Русский', value: 'ru_RU'), // 添加俄语选项
|
|
LanguageModel(
|
|
name: 'vietnamese', alias: 'Tiếng Việt', value: 'vi_VN'), // 添加越南语选项
|
|
LanguageModel(
|
|
name: 'italian', alias: 'Italiano', value: 'it_IT'), // 添加意大利语选项
|
|
LanguageModel(
|
|
name: 'hindi', alias: 'हिन्दी', value: 'hi_IN'), // 添加印度语(印地语)选项
|
|
LanguageModel(
|
|
name: 'indonesian',
|
|
alias: 'Bahasa Indonesia',
|
|
value: 'id_ID'), // 添加印尼语选项
|
|
LanguageModel(name: 'thai', alias: 'ไทย', value: 'th_TH'), // 添加泰语选项
|
|
LanguageModel(
|
|
name: 'malay', alias: 'Bahasa Melayu', value: 'ms_MY'), // 添加马来语选项
|
|
LanguageModel(name: 'turkish', alias: 'Türkçe', value: 'tr_TR'), // 添加土耳其语选项
|
|
LanguageModel(name: 'polish', alias: 'Polski', value: 'pl_PL'), // 添加波兰语选项
|
|
];
|
|
|
|
Rx<LanguageModel> language = LanguageModel().obs;
|
|
|
|
final GetStorage _storage = GetStorage();
|
|
|
|
// 主题服务
|
|
final ThemeService _themeService = ThemeService();
|
|
|
|
// 是否是暗黑模式
|
|
final RxBool isDarkMode = false.obs;
|
|
|
|
// 翻译语言对
|
|
final RxString sourceLanguage = '中文'.obs;
|
|
final RxString targetLanguage = '英文'.obs;
|
|
final List<String> availableLanguages = [
|
|
'中文',
|
|
'英文',
|
|
'日文',
|
|
'韩文',
|
|
'法文',
|
|
'德文',
|
|
'西班牙文',
|
|
'俄文'
|
|
];
|
|
|
|
// 语音服务类型
|
|
final Rx<SpeechServiceType> speechServiceType = SpeechServiceType.azure.obs;
|
|
final List<Map<String, dynamic>> availableSpeechServices = [
|
|
{
|
|
'type': SpeechServiceType.azure,
|
|
'name': 'azureVoiceService', // Azure 语音服务.tr
|
|
'description': 'azureVoiceServiceInfo' // 微软云端语音服务,支持高质量语音合成和识别.tr
|
|
},
|
|
{
|
|
'type': SpeechServiceType.flutter,
|
|
'name': 'flutterVoiceService', // Flutter 本地语音服务.tr
|
|
'description': 'flutterVoiceServiceInfo' // 设备本地语音服务,无需联网即可使用.tr
|
|
},
|
|
];
|
|
|
|
RxString timbreName = 'defaultTimbre'.obs;
|
|
|
|
//用户信息
|
|
static const String userKey = 'user_info';
|
|
//final _storage=GetStorage();
|
|
//final ImagePicker _picker = ImagePicker();
|
|
final Rx<User> userInfo = User.instance.obs; //使用单例实例
|
|
|
|
// 添加版本信息变量
|
|
final appVersion = ''.obs;
|
|
final buildNumber = ''.obs;
|
|
|
|
// 权限相关
|
|
// 权限组,用于在UI中显示
|
|
final List<Map<String, dynamic>> permissionGroups = [
|
|
{
|
|
'name': '通讯权限',
|
|
'icon': Icons.phone_android,
|
|
'permissions': [
|
|
{'type': Permission.phone, 'name': '电话', 'description': '用于拨打电话功能'},
|
|
{'type': Permission.sms, 'name': '短信', 'description': '用于发送短信功能'},
|
|
{'type': Permission.contacts, 'name': '通讯录', 'description': '用于访问联系人'}
|
|
]
|
|
},
|
|
{
|
|
'name': '日程权限',
|
|
'icon': Icons.calendar_today,
|
|
'permissions': [
|
|
{'type': Permission.calendarFullAccess, 'name': '日历写入', 'description': '用于创建日历事件和提醒'},
|
|
{'type': Permission.calendarFullAccess, 'name': '日历完全访问', 'description': '用于读取和修改日历事件'}
|
|
]
|
|
},
|
|
{
|
|
'name': '存储权限',
|
|
'icon': Icons.storage,
|
|
'permissions': [
|
|
{'type': Permission.storage, 'name': '存储', 'description': '用于保存录音和文件'},
|
|
{'type': Permission.photos, 'name': '照片', 'description': '用于选择和保存照片'}
|
|
]
|
|
},
|
|
{
|
|
'name': '位置权限',
|
|
'icon': Icons.location_on,
|
|
'permissions': [
|
|
{'type': Permission.location, 'name': '位置', 'description': '用于获取当前位置信息'},
|
|
{'type': Permission.locationAlways, 'name': '后台位置', 'description': '用于后台获取位置信息'}
|
|
]
|
|
},
|
|
{
|
|
'name': '媒体权限',
|
|
'icon': Icons.mic,
|
|
'permissions': [
|
|
{'type': Permission.microphone, 'name': '麦克风', 'description': '用于语音识别和录音'},
|
|
{'type': Permission.bluetooth, 'name': '蓝牙', 'description': '用于连接蓝牙设备'}
|
|
]
|
|
}
|
|
];
|
|
|
|
// 检查单个权限状态
|
|
Future<PermissionStatus> checkPermission(Permission permission) async {
|
|
return await permission.status;
|
|
}
|
|
|
|
// 请求单个权限
|
|
Future<PermissionStatus> requestPermission(Permission permission) async {
|
|
return await permission.request();
|
|
}
|
|
|
|
// 打开应用设置
|
|
void openSettings() {
|
|
openAppSettings();
|
|
}
|
|
|
|
// 检查所有权限状态并返回结果
|
|
Future<Map<Permission, PermissionStatus>> checkAllPermissions() async {
|
|
Map<Permission, PermissionStatus> statuses = {};
|
|
|
|
for (var group in permissionGroups) {
|
|
for (var perm in group['permissions']) {
|
|
Permission permission = perm['type'];
|
|
statuses[permission] = await permission.status;
|
|
}
|
|
}
|
|
|
|
return statuses;
|
|
}
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
|
|
// 获取系统语言
|
|
_getLanguage();
|
|
|
|
_getTimbre();
|
|
|
|
// 从存储中加载上次保存的主题设置
|
|
final savedDarkMode = _themeService.isSavedDarkMode();
|
|
|
|
// 设置当前主题状态
|
|
isDarkMode.value = savedDarkMode;
|
|
|
|
// 获取当前语音服务类型
|
|
_loadCurrentSpeechServiceType();
|
|
|
|
//获取用户信息
|
|
loadUserInfo();
|
|
|
|
// 获取应用版本信息
|
|
getAppVersion();
|
|
}
|
|
|
|
// 获取应用版本信息的方法
|
|
Future<void> getAppVersion() async {
|
|
try {
|
|
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
|
appVersion.value = packageInfo.version;
|
|
buildNumber.value = packageInfo.buildNumber;
|
|
print('版本信息: ${packageInfo.version}+${packageInfo.buildNumber}');
|
|
} catch (e) {
|
|
appVersion.value = '未知';
|
|
buildNumber.value = '0';
|
|
print('获取版本信息失败: $e');
|
|
}
|
|
}
|
|
|
|
void loadUserInfo() {
|
|
final userJson = _storage.read(userKey);
|
|
Logger().d('加载用户信息: $userJson');
|
|
|
|
if (userJson != null) {
|
|
userInfo.value = User.instance;
|
|
Logger().d('用户信息已加载: ${userInfo.value.toJson()}');
|
|
|
|
if (userInfo.value.avatar.isNotEmpty) {
|
|
Logger().d('开始下载头像');
|
|
_downloadAndSaveAvatar(userInfo.value.avatar);
|
|
} else {
|
|
Logger().d('用户没有头像');
|
|
}
|
|
} else {
|
|
Logger().d('没有找到用户信息');
|
|
}
|
|
}
|
|
|
|
Future<void> saveUserInfo() async {
|
|
await _storage.write(userKey, userInfo.value.toJson());
|
|
}
|
|
|
|
// 下载并保存远程头像
|
|
Future<void> _downloadAndSaveAvatar(String url) async {
|
|
try {
|
|
Logger().d('开始下载头像: $url');
|
|
|
|
final dio = Dio(BaseOptions(
|
|
headers: {
|
|
'accept': '*/*',
|
|
'Authorization': _storage.read<String>("logintoken"),
|
|
},
|
|
));
|
|
|
|
final response = await dio.get(
|
|
url,
|
|
options: Options(responseType: ResponseType.bytes),
|
|
);
|
|
|
|
Logger().d('下载状态: ${response.statusCode}');
|
|
|
|
if (response.statusCode == 200) {
|
|
// 保存到应用文档目录
|
|
final appDir = await getApplicationDocumentsDirectory();
|
|
final fileName = 'avatar_${DateTime.now().millisecondsSinceEpoch}.jpg';
|
|
final localPath = '${appDir.path}/$fileName';
|
|
|
|
// 写入文件
|
|
final file = File(localPath);
|
|
await file.writeAsBytes(response.data);
|
|
|
|
// 更新本地头像路径
|
|
//localAvatar.value = localPath;
|
|
await _storage.write('local_avatar', localPath);
|
|
Logger().d('头像已下载到本地: $localPath');
|
|
//Get.snackbar('头像', '头像已下载到本地');
|
|
}
|
|
} catch (e) {
|
|
Logger().e('下载头像失败: $e');
|
|
}
|
|
}
|
|
|
|
// Future<void> updateUserAvatar() async {
|
|
// final XFile? image = await _picker.pickImage(
|
|
// source: ImageSource.gallery,
|
|
// maxWidth: 800,
|
|
// maxHeight: 800,
|
|
// imageQuality: 85,
|
|
// );
|
|
|
|
// if (image != null) {
|
|
// userInfo.update((user) {
|
|
// if (user != null) {
|
|
// user.avatar = image.path;
|
|
// }
|
|
// });
|
|
// await saveUserInfo();
|
|
// }
|
|
// }
|
|
|
|
Future<void> updateUserName(String name) async {
|
|
if (name.trim().isNotEmpty) {
|
|
userInfo.update((user) {
|
|
if (user != null) {
|
|
user.name = name.trim();
|
|
}
|
|
});
|
|
await saveUserInfo();
|
|
}
|
|
}
|
|
|
|
// Future<void> updateDeviceName(String deviceName) async {
|
|
// userInfo.update((user) {
|
|
// if (user != null) {
|
|
// user.deviceName = deviceName;
|
|
// }
|
|
// });
|
|
// await saveUserInfo();
|
|
// }
|
|
// }
|
|
|
|
void _getLanguage() {
|
|
String? languageValue = _storage.read('language');
|
|
LanguageModel data = languageList.firstWhere(
|
|
(element) => element.value == languageValue,
|
|
orElse: () => languageList[0],
|
|
);
|
|
language.value = data;
|
|
}
|
|
|
|
// 获取音色
|
|
void _getTimbre() {
|
|
List? timbreList = _storage.read('timbreList');
|
|
String? timbre = _storage.read('timbre');
|
|
if (timbreList != null && timbre != null) {
|
|
Map data = timbreList.firstWhere(
|
|
(element) => element['type'] == timbre,
|
|
orElse: () => {},
|
|
);
|
|
if (data.isNotEmpty) {
|
|
timbreName.value = data['name'];
|
|
}
|
|
}
|
|
}
|
|
|
|
void setLanguage(LanguageModel data) {
|
|
if (data.value != 'system') {
|
|
List languageList = data.value.split('_');
|
|
Get.updateLocale(Locale(languageList[0], languageList[1]));
|
|
} else {
|
|
Get.updateLocale(Get.deviceLocale!);
|
|
}
|
|
language.value = data;
|
|
_storage.write('language', data.value);
|
|
Get.back();
|
|
}
|
|
|
|
// 加载当前语音服务类型
|
|
void _loadCurrentSpeechServiceType() {
|
|
try {
|
|
final factory = Get.find<SpeechFactory>();
|
|
speechServiceType.value = factory.currentServiceType;
|
|
} catch (e) {
|
|
// 如果找不到SpeechFactory实例,使用默认值
|
|
}
|
|
}
|
|
|
|
// 切换主题
|
|
Future<void> toggleTheme() async {
|
|
// 切换暗黑模式状态
|
|
isDarkMode.value = !isDarkMode.value;
|
|
|
|
// 更新全局主题
|
|
Get.changeThemeMode(isDarkMode.value ? ThemeMode.dark : ThemeMode.light);
|
|
|
|
// 保存用户选择的主题设置 - 确保立即写入存储
|
|
await _themeService.saveThemeMode(isDarkMode.value);
|
|
}
|
|
|
|
// 设置语音服务类型
|
|
void setSpeechServiceType(SpeechServiceType type) {
|
|
try {
|
|
final factory = Get.find<SpeechFactory>();
|
|
factory.setServiceType(type);
|
|
speechServiceType.value = type;
|
|
} catch (e) {
|
|
// 处理错误
|
|
}
|
|
}
|
|
|
|
void setSourceLanguage(String language) {
|
|
sourceLanguage.value = language;
|
|
}
|
|
|
|
void setTargetLanguage(String language) {
|
|
targetLanguage.value = language;
|
|
}
|
|
|
|
void swapLanguages() {
|
|
final temp = sourceLanguage.value;
|
|
sourceLanguage.value = targetLanguage.value;
|
|
targetLanguage.value = temp;
|
|
}
|
|
|
|
/// 清除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: const Text('确定'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
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配对设备时发生错误');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|