import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../../data/services/volcano_translation_service.dart'; import '../../../data/services/language_manager.dart'; import '../../../core/utils/logger.dart'; /// 文本翻译控制器 class TextTranslationController extends GetxController { // 依赖服务 final VolcanoTranslationService _translationService = Get.find(); final LanguageManager _languageManager = Get.find(); final GetStorage _storage = GetStorage(); // 文本输入控制器 final TextEditingController textController = TextEditingController(); // 响应式状态 final sourceLanguageChineseName = '中文(简体)'.obs; final targetLanguageChineseName = '英语'.obs; final sourceLanguageCode = 'zh-CN'.obs; final targetLanguageCode = 'en-US'.obs; final translatedText = ''.obs; final isTranslating = false.obs; final inputText = ''.obs; // 支持的语言列表 List get supportedLanguages => _languageManager.getAllChineseNames(); @override void onInit() { super.onInit(); // 初始化翻译服务 _initializeTranslationService(); _loadSavedLanguages(); // 监听文本输入变化 textController.addListener(() { inputText.value = textController.text; }); } /// 初始化翻译服务 Future _initializeTranslationService() async { try { // 已初始化则跳过 if (_translationService.isInitialized) { Logger.info('翻译服务已初始化'); return; } // final initialized = final initialized = await _translationService.initialize(); if (!initialized) { Logger.error('翻译服务初始化失败'); Get.snackbar( 'error'.tr, '翻译服务初始化失败,请检查网络连接', snackPosition: SnackPosition.TOP, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, ); } else { Logger.info('翻译服务初始化成功'); } } catch (e) { Logger.error('翻译服务初始化异常: $e'); } } @override void onClose() { textController.dispose(); super.onClose(); } /// 加载保存的语言设置 void _loadSavedLanguages() { try { final savedSourceLanguage = _storage.read('text_translation_source_language'); final savedTargetLanguage = _storage.read('text_translation_target_language'); if (savedSourceLanguage != null && supportedLanguages.contains(savedSourceLanguage)) { sourceLanguageChineseName.value = savedSourceLanguage; // 同时更新语言代码 final asrCode = _languageManager.getAsrCodeByChineseName(savedSourceLanguage); if (asrCode != null) { sourceLanguageCode.value = asrCode; } } if (savedTargetLanguage != null && supportedLanguages.contains(savedTargetLanguage)) { targetLanguageChineseName.value = savedTargetLanguage; // 同时更新语言代码 final asrCode = _languageManager.getAsrCodeByChineseName(savedTargetLanguage); if (asrCode != null) { targetLanguageCode.value = asrCode; } } } catch (e) { Logger.error('加载语言设置失败: $e'); } } /// 保存语言设置 void _saveLanguageSettings() { try { _storage.write( 'text_translation_source_language', sourceLanguageChineseName.value); _storage.write( 'text_translation_target_language', targetLanguageChineseName.value); } catch (e) { Logger.error('保存语言设置失败: $e'); } } /// 设置源语言 void setSourceLanguage(String language) { if (language != sourceLanguageChineseName.value) { sourceLanguageChineseName.value = language; // 同时更新语言代码;当选择“自动检测”时,将源语言代码置空,后续翻译流程会进行语种检测 if (language == '自动检测') { sourceLanguageCode.value = ''; } else { final asrCode = _languageManager.getAsrCodeByChineseName(language); if (asrCode != null) { sourceLanguageCode.value = asrCode; } } _saveLanguageSettings(); // 如果已有翻译结果,清空结果 if (translatedText.value.isNotEmpty) { translatedText.value = ''; } } } /// 设置目标语言 void setTargetLanguage(String language) { if (language != targetLanguageChineseName.value) { targetLanguageChineseName.value = language; // 同时更新语言代码 final asrCode = _languageManager.getAsrCodeByChineseName(language); if (asrCode != null) { targetLanguageCode.value = asrCode; } _saveLanguageSettings(); // 如果已有翻译结果,清空结果 if (translatedText.value.isNotEmpty) { translatedText.value = ''; } } } /// 交换源语言和目标语言 void swapLanguages() { final tempSource = sourceLanguageChineseName.value; final tempTarget = targetLanguageChineseName.value; final tempSourceCode = sourceLanguageCode.value; final tempTargetCode = targetLanguageCode.value; final tempInputText = textController.text; final tempTranslatedText = translatedText.value; sourceLanguageChineseName.value = tempTarget; targetLanguageChineseName.value = tempSource; sourceLanguageCode.value = tempTargetCode; targetLanguageCode.value = tempSourceCode; // 交换输入文本和翻译结果 textController.text = tempTranslatedText; translatedText.value = tempInputText; _saveLanguageSettings(); } /// 执行翻译 Future translateText() async { final text = textController.text.trim(); // 验证输入 if (text.isEmpty) { // Get.snackbar( // 'error'.tr, // 'pleaseInputText'.tr, // snackPosition: SnackPosition.TOP, // backgroundColor: Colors.orange.withOpacity(0.9), // colorText: Colors.white, // ); return; } if (text.length > 5000) { // 5000 字符限制 Get.snackbar( 'error'.tr, 'textTooLong'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.orange.withOpacity(0.9), colorText: Colors.white, ); return; } // 检查源语言和目标语言是否相同 if (sourceLanguageChineseName.value == targetLanguageChineseName.value) { translatedText.value = text; return; } isTranslating.value = true; translatedText.value = ''; try { Logger.info('开始翻译: $text'); Logger.info( '源语言: ${sourceLanguageChineseName.value} -> ${sourceLanguageCode.value}'); Logger.info( '目标语言: ${targetLanguageChineseName.value} -> ${targetLanguageCode.value}'); // 确保翻译服务已初始化 Logger.info('确保翻译服务已初始化...'); bool initialized = _translationService.isInitialized; if (!initialized) { initialized = await _translationService.initialize(); } Logger.info('翻译服务初始化结果: $initialized'); if (!initialized) { throw Exception('翻译服务初始化失败'); } Logger.info('调用翻译服务...'); // 若选择了“自动检测”,先进行语种检测 if (sourceLanguageChineseName.value == '自动检测' || sourceLanguageCode.value.isEmpty) { Logger.info('源语言为自动检测,开始语种检测…'); final detectedAsrCode = await _translationService.detectTextLanguage(text: text); if (detectedAsrCode == null || detectedAsrCode.isEmpty) { Logger.error('语种检测失败'); Get.snackbar( '错误', // 翻译键代表的中文文本内容 '语种检测失败,请手动选择源语言或稍后重试', // 翻译键代表的中文文本内容 snackPosition: SnackPosition.TOP, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, ); return; } sourceLanguageCode.value = detectedAsrCode; Logger.info('语种检测结果: $detectedAsrCode'); } // 调用翻译服务,使用检测或手动选择的源语言代码 final result = await _translationService.translateText( text: text, sourceLanguageCode: sourceLanguageCode.value, targetLanguageCode: targetLanguageCode.value, ); Logger.info('翻译服务返回结果: $result'); if (result != null && result.isNotEmpty) { translatedText.value = result; Logger.info('翻译成功: $result'); } else { Logger.error('翻译服务返回空结果'); throw Exception('翻译服务返回空结果'); } } catch (e) { Logger.error('翻译失败: $e'); Get.snackbar( 'error'.tr, 'translationFailed'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, ); } finally { isTranslating.value = false; } } /// 复制翻译结果 void copyResult() { if (translatedText.value.isNotEmpty) { Clipboard.setData(ClipboardData(text: translatedText.value)); Get.snackbar( 'success'.tr, 'copied'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.green.withOpacity(0.9), colorText: Colors.white, duration: const Duration(seconds: 1), ); } } /// 清空输入 void clearInput() { textController.clear(); translatedText.value = ''; } /// 显示语言选择对话框(统一与其它翻译模式的样式) void showLanguageSelector({required bool isSourceLanguage}) { final isDarkMode = Theme.of(Get.context!).brightness == Brightness.dark; Get.dialog(Dialog( backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), // 统一圆角尺寸 ), alignment: isSourceLanguage ? Alignment.centerLeft : Alignment.centerRight, insetPadding: EdgeInsets.symmetric(horizontal: 10.w), child: SizedBox( width: 0.4.sw, child: Padding( padding: EdgeInsets.all(12.w), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题区域 Padding( padding: EdgeInsets.symmetric(horizontal: 8.w), child: Text( isSourceLanguage ? 'selectSourceLanguage'.tr // 翻译键代表的中文文本内容 : 'selectTargetLanguage'.tr, // 翻译键代表的中文文本内容 style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black87, ), ), ), SizedBox(height: 16.h), // 语言列表区域 Container( constraints: BoxConstraints(maxHeight: 0.5.sh), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: List.generate( isSourceLanguage ? (supportedLanguages.length + 1) : supportedLanguages.length, (index) { // 源语言下首项为“自动检测” final displayText = isSourceLanguage && index == 0 ? 'autoDetect'.tr // 翻译键代表的中文文本内容 : (isSourceLanguage ? supportedLanguages[index - 1] : supportedLanguages[index]); final valueText = isSourceLanguage && index == 0 ? '自动检测' : (isSourceLanguage ? supportedLanguages[index - 1] : supportedLanguages[index]); final isSelected = isSourceLanguage ? valueText == sourceLanguageChineseName.value : valueText == targetLanguageChineseName.value; return GestureDetector( onTap: () { if (isSourceLanguage) { setSourceLanguage(valueText); } else { setTargetLanguage(valueText); } Get.back(); }, child: Container( margin: EdgeInsets.only(bottom: 10.h), padding: EdgeInsets.all(10.w), decoration: BoxDecoration( color: isSelected ? (isDarkMode ? const Color(0xFF6200EE).withOpacity(0.2) : Colors.blue.withOpacity(0.1)) : (isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[200]!), borderRadius: BorderRadius.circular(12.r), border: Border.all( color: isSelected ? (isDarkMode ? const Color(0xFF6200EE) : Colors.blue) : (isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[200]!), width: 1, ), ), child: Row( children: [ // 语言名称(中文名直接显示不进行翻译) Expanded( child: Text( displayText, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, color: isDarkMode ? Colors.white : Colors.black87, overflow: TextOverflow.ellipsis, ), ), ), // 选中指示器 Container( width: 24.w, height: 24.w, decoration: BoxDecoration( color: isSelected ? (isDarkMode ? const Color(0xFF6200EE) : Colors.blue) : (isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[300]), shape: BoxShape.circle, ), child: isSelected ? Icon( Icons.check, size: 16.w, color: Colors.white, ) : null, ), ], ), ), ); }, ), ), ), ), SizedBox(height: 16.h), // 取消按钮 Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () => Get.back(), child: Text( 'cancel'.tr, // 翻译键代表的中文文本内容 style: TextStyle( color: isDarkMode ? const Color(0xFF6200EE) : Colors.blue, ), ), ), ), ], ), ), ), )); } }