From d4fedde95ec40acfa023ffc33d088cebcab514d2 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Fri, 19 Sep 2025 20:46:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(translation):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=B7=A6=E6=BB=91=E6=89=8B=E5=8A=BF=E5=AF=BC=E8=88=AA=E8=87=B3?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E9=A1=B5=E9=9D=A2=20refact?= =?UTF-8?q?or(translation):=20=E7=A7=BB=E9=99=A4=E7=81=AB=E5=B1=B1AI?= =?UTF-8?q?=E6=91=98=E8=A6=81=E7=94=9F=E6=88=90=E7=9B=B8=E5=85=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20fix(pairing):=20=E4=BF=AE=E6=AD=A3=E5=8D=8E?= =?UTF-8?q?=E4=B8=BA=E8=AE=BE=E5=A4=87=E6=9D=83=E9=99=90=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/pairing_controller.dart | 10 +- .../translation_detail_controller.dart | 162 ++++---- .../views/translation_detail_view.dart | 352 +++++++++--------- .../translation/views/translation_view.dart | 45 ++- 4 files changed, 295 insertions(+), 274 deletions(-) diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index e1bd5f96d..60543dc64 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -576,9 +576,15 @@ class PairingController extends GetxController with WidgetsBindingObserver { /// 检查权限 Future _checkPermissions() async { - //如果是华为设备,且已经检查过,直接返回false + //如果是华为设备,且已经检查过,直接返回权限状态 if (isHuaweiDevice && isHuaweiHasChecked) { - return false; + final bluetoothScanStatus = await Permission.bluetoothScan.status; + final bluetoothConnectStatus = await Permission.bluetoothConnect.status; + final locationStatus = await Permission.locationWhenInUse.status; + + return bluetoothScanStatus.isGranted && + bluetoothConnectStatus.isGranted && + locationStatus.isGranted; } // Android权限检查 diff --git a/lib/modules/translation/controllers/translation_detail_controller.dart b/lib/modules/translation/controllers/translation_detail_controller.dart index fd3239f0d..da34f3ff2 100644 --- a/lib/modules/translation/controllers/translation_detail_controller.dart +++ b/lib/modules/translation/controllers/translation_detail_controller.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import '../../../data/services/volcano_ai_service.dart'; +// import '../../../data/services/volcano_ai_service.dart';// 注释掉火山AI服务导入 import '../controllers/translation_controller.dart'; import 'translation_audiohistory_controller.dart'; import '../models/translation_models.dart'; // 添加这行导入 @@ -12,7 +12,7 @@ import '../../../data/services/translation_usage_service.dart'; //详情页管理 class TranslationDetailController extends GetxController { // 依赖注入 - final VolcanoAIService _aiService = Get.find(); + //final VolcanoAIService _aiService = Get.find(); final GetStorage _storage = GetStorage(); late final TranslationUsageService _usageService; @@ -124,89 +124,89 @@ class TranslationDetailController extends GetxController { sessionItems.map((e) => e.translatedText).join('\n\n'); // 使用延长的超时时间重试提取摘要 - Future retryExtractSummaryWithExtendedTimeout(String text) async { - return _extractSummaryInternal(text, _extendedTimeoutDuration); - } + // Future retryExtractSummaryWithExtendedTimeout(String text) async { + // return _extractSummaryInternal(text, _extendedTimeoutDuration); + // } // 提取摘要 - Future extractSummary(String text) async { - return _extractSummaryInternal(text, _defaultTimeoutDuration); - } + // Future extractSummary(String text) async { + // return _extractSummaryInternal(text, _defaultTimeoutDuration); + // } // 内部摘要提取方法,避免代码重复 - Future _extractSummaryInternal( - String text, int timeoutDuration) async { - if (text.isEmpty) { - return '无法生成摘要:文本为空'; - } - - isGeneratingSummary.value = true; - - try { - // 构建提示词 - final messages = [ - {'role': 'user', 'content': '请为以下文本生成一个简洁的摘要,突出重点内容:\n\n$text'}, - ]; - - // 系统提示词 - const systemPrompt = ''' -你是一个专业的文本摘要助手,擅长从会议记录、对话和文本中提取关键信息并生成简洁的摘要。 -请按照以下格式生成摘要: - -1. 首先用1-2句话对整体内容进行简要概括 -2. 然后使用项目符号列表(•)列出关键点或重要信息 -3. 如果是对话内容,请特别标注出讨论的结论或达成的共识 - -请遵循以下原则: -1. 保留原文的核心信息和关键点 -2. 使用简洁、清晰的语言 -3. 保持客观,不添加个人观点 -4. 摘要总长度应该是原文的1/3或更短 -5. 确保列表中的每个要点都简明扼要,突出重点 -'''; - - String result; - try { - // 使用超时限制 - result = await _aiService - .sendMessage( - messages: messages, - systemPrompt: systemPrompt, - ) - .timeout(Duration(seconds: timeoutDuration), onTimeout: () { - throw TimeoutException('请求超时', Duration(seconds: timeoutDuration)); - }); - } on TimeoutException catch (_) { - final timeoutMessage = timeoutDuration == _defaultTimeoutDuration - ? '生成摘要超时,请稍后重试' - : '生成摘要超时,请检查网络连接后重试'; - summaryResult.value = timeoutMessage; - return summaryResult.value; - } - - // 更新结果并保存 - if (result.isNotEmpty) { - summaryResult.value = result; - saveSummary(result); - - // 记录AI摘要API调用统计 - try { - _usageService.recordAiSummaryApiCall(); - } catch (e) { - Logger.error('记录AI摘要统计失败: $e'); - } - } - - return result; - } catch (e) { - final errorMessage = '生成摘要失败: ${e.toString()}'; - Logger.error('TranslationDetailController', errorMessage); - summaryResult.value = errorMessage; - return errorMessage; - } finally { - isGeneratingSummary.value = false; - } - } +// Future _extractSummaryInternal( +// String text, int timeoutDuration) async { +// if (text.isEmpty) { +// return '无法生成摘要:文本为空'; +// } + +// isGeneratingSummary.value = true; + +// try { +// // 构建提示词 +// final messages = [ +// {'role': 'user', 'content': '请为以下文本生成一个简洁的摘要,突出重点内容:\n\n$text'}, +// ]; + +// // 系统提示词 +// const systemPrompt = ''' +// 你是一个专业的文本摘要助手,擅长从会议记录、对话和文本中提取关键信息并生成简洁的摘要。 +// 请按照以下格式生成摘要: + +// 1. 首先用1-2句话对整体内容进行简要概括 +// 2. 然后使用项目符号列表(•)列出关键点或重要信息 +// 3. 如果是对话内容,请特别标注出讨论的结论或达成的共识 + +// 请遵循以下原则: +// 1. 保留原文的核心信息和关键点 +// 2. 使用简洁、清晰的语言 +// 3. 保持客观,不添加个人观点 +// 4. 摘要总长度应该是原文的1/3或更短 +// 5. 确保列表中的每个要点都简明扼要,突出重点 +// '''; + +// String result; +// try { +// // 使用超时限制 +// result = await _aiService +// .sendMessage( +// messages: messages, +// systemPrompt: systemPrompt, +// ) +// .timeout(Duration(seconds: timeoutDuration), onTimeout: () { +// throw TimeoutException('请求超时', Duration(seconds: timeoutDuration)); +// }); +// } on TimeoutException catch (_) { +// final timeoutMessage = timeoutDuration == _defaultTimeoutDuration +// ? '生成摘要超时,请稍后重试' +// : '生成摘要超时,请检查网络连接后重试'; +// summaryResult.value = timeoutMessage; +// return summaryResult.value; +// } + +// // 更新结果并保存 +// if (result.isNotEmpty) { +// summaryResult.value = result; +// saveSummary(result); + +// // 记录AI摘要API调用统计 +// try { +// _usageService.recordAiSummaryApiCall(); +// } catch (e) { +// Logger.error('记录AI摘要统计失败: $e'); +// } +// } + +// return result; +// } catch (e) { +// final errorMessage = '生成摘要失败: ${e.toString()}'; +// Logger.error('TranslationDetailController', errorMessage); +// summaryResult.value = errorMessage; +// return errorMessage; +// } finally { +// isGeneratingSummary.value = false; +// } +// } // 删除单条翻译记录 Future deleteTranslationItem(TranslationItem item) async { diff --git a/lib/modules/translation/views/translation_detail_view.dart b/lib/modules/translation/views/translation_detail_view.dart index e2ec8dfbf..7a10c65da 100644 --- a/lib/modules/translation/views/translation_detail_view.dart +++ b/lib/modules/translation/views/translation_detail_view.dart @@ -142,9 +142,9 @@ class TranslationDetailView extends GetView { if (controller.selectedTabIndex.value == 0) ..._buildOriginalRecords(isDarkMode) else - _buildSummaryWidget(isDarkMode), + //_buildSummaryWidget(isDarkMode), - SizedBox(height: 24.h), + SizedBox(height: 24.h), ], ); }), @@ -323,23 +323,23 @@ class TranslationDetailView extends GetView { } // 构建总结视图 - Widget _buildSummaryWidget(bool isDarkMode) { - final String combinedSourceText = _getCombinedSourceText(); + // Widget _buildSummaryWidget(bool isDarkMode) { + // final String combinedSourceText = _getCombinedSourceText(); - return Column( - children: [ - // 摘要内容容器 - _buildSummaryContainer(isDarkMode), + // return Column( + // children: [ + // // 摘要内容容器 + // _buildSummaryContainer(isDarkMode), - // 提取摘要按钮 - Obx(() => _buildExtractSummaryButton(combinedSourceText, isDarkMode)), + // // 提取摘要按钮 + // Obx(() => _buildExtractSummaryButton(combinedSourceText, isDarkMode)), - // 重新生成按钮 - Obx(() => - _buildRegenerateSummaryButton(combinedSourceText, isDarkMode)), - ], - ); - } + // // 重新生成按钮 + // Obx(() => + // _buildRegenerateSummaryButton(combinedSourceText, isDarkMode)), + // ], + // ); + // } // 构建摘要容器 Widget _buildSummaryContainer(bool isDarkMode) { @@ -484,163 +484,163 @@ class TranslationDetailView extends GetView { } // 构建提取摘要按钮 - Widget _buildExtractSummaryButton( - String combinedSourceText, bool isDarkMode) { - final bool isDisabled = controller.isGeneratingSummary.value || - controller.summaryResult.value.isNotEmpty; - - return Container( - width: double.infinity, - margin: EdgeInsets.only(bottom: 16.h), - child: ElevatedButton( - onPressed: - isDisabled ? null : () => _extractSummary(combinedSourceText), - style: ElevatedButton.styleFrom( - backgroundColor: isDarkMode ? AppColors.primary : Colors.blue, - foregroundColor: Colors.white, - padding: EdgeInsets.symmetric(vertical: 12.h), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.r), - ), - elevation: 0, - disabledBackgroundColor: controller.isGeneratingSummary.value - ? isDarkMode - ? AppColors.primary.withAlpha(128) - : Colors.blue.withAlpha(128) - : Colors.grey.withAlpha(128), - ), - child: controller.isGeneratingSummary.value - ? _buildGeneratingIndicator(isDarkMode) - : Text( - controller.summaryResult.value.isEmpty - ? 'extractSummary'.tr - : 'summaryGenerated'.tr, // 提取摘要 : 已生成摘要 - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - ), - ), - ), - ); - } + // Widget _buildExtractSummaryButton( + // String combinedSourceText, bool isDarkMode) { + // final bool isDisabled = controller.isGeneratingSummary.value || + // controller.summaryResult.value.isNotEmpty; + + // return Container( + // width: double.infinity, + // margin: EdgeInsets.only(bottom: 16.h), + // child: ElevatedButton( + // onPressed: + // isDisabled ? null : () => _extractSummary(combinedSourceText), + // style: ElevatedButton.styleFrom( + // backgroundColor: isDarkMode ? AppColors.primary : Colors.blue, + // foregroundColor: Colors.white, + // padding: EdgeInsets.symmetric(vertical: 12.h), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16.r), + // ), + // elevation: 0, + // disabledBackgroundColor: controller.isGeneratingSummary.value + // ? isDarkMode + // ? AppColors.primary.withAlpha(128) + // : Colors.blue.withAlpha(128) + // : Colors.grey.withAlpha(128), + // ), + // child: controller.isGeneratingSummary.value + // ? _buildGeneratingIndicator(isDarkMode) + // : Text( + // controller.summaryResult.value.isEmpty + // ? 'extractSummary'.tr + // : 'summaryGenerated'.tr, // 提取摘要 : 已生成摘要 + // style: TextStyle( + // fontSize: 16.sp, + // fontWeight: FontWeight.w600, + // ), + // ), + // ), + // ); + // } // 构建生成中指示器 - Widget _buildGeneratingIndicator(bool isDarkMode) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: 20.w, - height: 20.h, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2.0, - ), - ), - SizedBox(width: 12.w), - Text( - 'generating'.tr, // 生成中... - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - ), - ), - ], - ); - } + // Widget _buildGeneratingIndicator(bool isDarkMode) { + // return Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // SizedBox( + // width: 20.w, + // height: 20.h, + // child: CircularProgressIndicator( + // color: Colors.white, + // strokeWidth: 2.0, + // ), + // ), + // SizedBox(width: 12.w), + // Text( + // 'generating'.tr, // 生成中... + // style: TextStyle( + // fontSize: 16.sp, + // fontWeight: FontWeight.w600, + // ), + // ), + // ], + // ); + // } // 构建重新生成按钮 - Widget _buildRegenerateSummaryButton( - String combinedSourceText, bool isDarkMode) { - if (controller.summaryResult.value.isEmpty || - controller.isGeneratingSummary.value) { - return SizedBox.shrink(); - } - - return Container( - width: double.infinity, - margin: EdgeInsets.only(bottom: 16.h), - child: OutlinedButton( - onPressed: () => _extractSummary(combinedSourceText), - style: OutlinedButton.styleFrom( - foregroundColor: isDarkMode ? AppColors.primary : Colors.blue, - side: BorderSide(color: isDarkMode ? AppColors.primary : Colors.blue), - padding: EdgeInsets.symmetric(vertical: 12.h), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.r), - ), - ), - child: Text( - 'regenerate'.tr, // 重新生成 - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - ), - ), - ), - ); - } + // Widget _buildRegenerateSummaryButton( + // String combinedSourceText, bool isDarkMode) { + // if (controller.summaryResult.value.isEmpty || + // controller.isGeneratingSummary.value) { + // return SizedBox.shrink(); + // } + + // return Container( + // width: double.infinity, + // margin: EdgeInsets.only(bottom: 16.h), + // child: OutlinedButton( + // onPressed: () => _extractSummary(combinedSourceText), + // style: OutlinedButton.styleFrom( + // foregroundColor: isDarkMode ? AppColors.primary : Colors.blue, + // side: BorderSide(color: isDarkMode ? AppColors.primary : Colors.blue), + // padding: EdgeInsets.symmetric(vertical: 12.h), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16.r), + // ), + // ), + // child: Text( + // 'regenerate'.tr, // 重新生成 + // style: TextStyle( + // fontSize: 16.sp, + // fontWeight: FontWeight.w600, + // ), + // ), + // ), + // ); + // } // 提取摘要方法 - void _extractSummary(String text) async { - final result = await controller.extractSummary(text); + // void _extractSummary(String text) async { + // final result = await controller.extractSummary(text); - // 检查是否超时,如果超时则显示重试选项 - if (result.contains('超时')) { - _showTimeoutDialog(text); - } - } + // // 检查是否超时,如果超时则显示重试选项 + // if (result.contains('超时')) { + // _showTimeoutDialog(text); + // } + // } // 显示超时对话框 - void _showTimeoutDialog(String text) { - Get.dialog( - AlertDialog( - title: Text( - 'requestTimeout'.tr, // 请求超时 - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - ), - ), - content: Text( - 'summaryTimeoutMessage'.tr, // 生成摘要请求超时,可能是网络问题或服务器繁忙。 - style: TextStyle( - fontSize: 16.sp, - ), - ), - actions: [ - TextButton( - onPressed: () => Get.back(), - child: Text( - 'cancel'.tr, // 取消 - style: TextStyle( - fontSize: 16.sp, - color: Colors.grey[700], - ), - ), - ), - TextButton( - onPressed: () { - Get.back(); - // 使用延长的超时时间重试 - controller.retryExtractSummaryWithExtendedTimeout(text); - }, - child: Text( - 'retry'.tr, // 重试 - style: TextStyle( - fontSize: 16.sp, - color: Colors.blue, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.r), - ), - ), - ); - } + // void _showTimeoutDialog(String text) { + // Get.dialog( + // AlertDialog( + // title: Text( + // 'requestTimeout'.tr, // 请求超时 + // style: TextStyle( + // fontSize: 18.sp, + // fontWeight: FontWeight.bold, + // ), + // ), + // content: Text( + // 'summaryTimeoutMessage'.tr, // 生成摘要请求超时,可能是网络问题或服务器繁忙。 + // style: TextStyle( + // fontSize: 16.sp, + // ), + // ), + // actions: [ + // TextButton( + // onPressed: () => Get.back(), + // child: Text( + // 'cancel'.tr, // 取消 + // style: TextStyle( + // fontSize: 16.sp, + // color: Colors.grey[700], + // ), + // ), + // ), + // TextButton( + // onPressed: () { + // Get.back(); + // // 使用延长的超时时间重试 + // controller.retryExtractSummaryWithExtendedTimeout(text); + // }, + // child: Text( + // 'retry'.tr, // 重试 + // style: TextStyle( + // fontSize: 16.sp, + // color: Colors.blue, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // ], + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(12.r), + // ), + // ), + // ); + // } // 显示删除单条记录确认对话框 void _showDeleteItemConfirmDialog(TranslationItem item) { @@ -750,18 +750,18 @@ class TranslationDetailView extends GetView { '${'originalText'.tr}:\n$sourceText\n\n${'translatedText'.tr}:\n$translatedText'; // 原文:译文: } else { // 分享摘要 - if (controller.summaryResult.value.isNotEmpty) { - shareText = - '${'sessionSummary'.tr}:\n${controller.summaryResult.value}'; // 会话摘要: - } else { - Get.snackbar( - 'cannotShare'.tr, // 无法分享 - 'generateSummaryFirst'.tr, // 请先生成摘要 - snackPosition: SnackPosition.BOTTOM, - duration: Duration(seconds: 2), - ); - return; - } + // if (controller.summaryResult.value.isNotEmpty) { + // shareText = + // '${'sessionSummary'.tr}:\n${controller.summaryResult.value}'; // 会话摘要: + // } else { + // Get.snackbar( + // 'cannotShare'.tr, // 无法分享 + // 'generateSummaryFirst'.tr, // 请先生成摘要 + // snackPosition: SnackPosition.BOTTOM, + // duration: Duration(seconds: 2), + // ); + // return; + // } } // 调用系统分享 diff --git a/lib/modules/translation/views/translation_view.dart b/lib/modules/translation/views/translation_view.dart index 69abbd234..fc506df20 100644 --- a/lib/modules/translation/views/translation_view.dart +++ b/lib/modules/translation/views/translation_view.dart @@ -343,16 +343,31 @@ class TranslationView extends GetView { } Widget _buildBody(bool isDarkMode) { - return Column( - children: [ - Expanded( - child: _buildTranslationContent(isDarkMode), - ), - _buildControlBar(isDarkMode), - ], + return GestureDetector( + onPanUpdate: (details) { + // 检测左滑手势 + if (details.delta.dx < -10) { + // 左滑距离超过10像素时触发 + _handleSwipeLeft(); + } + }, + child: Column( + children: [ + Expanded( + child: _buildTranslationContent(isDarkMode), + ), + _buildControlBar(isDarkMode), + ], + ), ); } + // 处理左滑手势 + void _handleSwipeLeft() async { + await controller.stopAll(); + Get.toNamed(Routes.translationHistory); + } + Widget _buildTranslationContent(bool isDarkMode) { return Obx(() { // 其他模式使用原有的列表布局 @@ -969,14 +984,14 @@ class TranslationView extends GetView { controller.deleteTranslationItem(item.sessionId, item.timestamp); // 显示删除成功提示 - Get.snackbar( - 'success'.tr, // deleteSuccess - '已删除该翻译记录', // deleteTranslationSuccess - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Get.isDarkMode ? Colors.grey[800] : Colors.grey[200], - colorText: Get.isDarkMode ? Colors.white : Colors.black, - duration: const Duration(milliseconds: 800), - ); + // Get.snackbar( + // 'success'.tr, // deleteSuccess + // '已删除该翻译记录', // deleteTranslationSuccess + // snackPosition: SnackPosition.BOTTOM, + // backgroundColor: Get.isDarkMode ? Colors.grey[800] : Colors.grey[200], + // colorText: Get.isDarkMode ? Colors.white : Colors.black, + // duration: const Duration(milliseconds: 800), + // ); } catch (e) { // 显示删除失败提示 Get.snackbar(