Browse Source

feat(translation): 添加左滑手势导航至历史记录页面

refactor(translation): 移除火山AI摘要生成相关代码
fix(pairing): 修正华为设备权限检查逻辑
weicu
lxm 1 year ago
parent
commit
d4fedde95e
  1. 10
      lib/modules/pairing/controllers/pairing_controller.dart
  2. 162
      lib/modules/translation/controllers/translation_detail_controller.dart
  3. 352
      lib/modules/translation/views/translation_detail_view.dart
  4. 45
      lib/modules/translation/views/translation_view.dart

10
lib/modules/pairing/controllers/pairing_controller.dart

@ -576,9 +576,15 @@ class PairingController extends GetxController with WidgetsBindingObserver {
/// 检查权限 /// 检查权限
Future<bool> _checkPermissions() async { Future<bool> _checkPermissions() async {
//如果是华为设备,且已经检查过,直接返回false //如果是华为设备,且已经检查过,直接返回权限状态
if (isHuaweiDevice && isHuaweiHasChecked) { 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权限检查 // Android权限检查

162
lib/modules/translation/controllers/translation_detail_controller.dart

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.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 '../controllers/translation_controller.dart';
import 'translation_audiohistory_controller.dart'; import 'translation_audiohistory_controller.dart';
import '../models/translation_models.dart'; // 添加这行导入 import '../models/translation_models.dart'; // 添加这行导入
@ -12,7 +12,7 @@ import '../../../data/services/translation_usage_service.dart';
//详情页管理 //详情页管理
class TranslationDetailController extends GetxController { class TranslationDetailController extends GetxController {
// 依赖注入 // 依赖注入
final VolcanoAIService _aiService = Get.find<VolcanoAIService>(); //final VolcanoAIService _aiService = Get.find<VolcanoAIService>();
final GetStorage _storage = GetStorage(); final GetStorage _storage = GetStorage();
late final TranslationUsageService _usageService; late final TranslationUsageService _usageService;
@ -124,89 +124,89 @@ class TranslationDetailController extends GetxController {
sessionItems.map((e) => e.translatedText).join('\n\n'); sessionItems.map((e) => e.translatedText).join('\n\n');
// 使用延长的超时时间重试提取摘要 // 使用延长的超时时间重试提取摘要
Future<String> retryExtractSummaryWithExtendedTimeout(String text) async { // Future<String> retryExtractSummaryWithExtendedTimeout(String text) async {
return _extractSummaryInternal(text, _extendedTimeoutDuration); // return _extractSummaryInternal(text, _extendedTimeoutDuration);
} // }
// 提取摘要 // 提取摘要
Future<String> extractSummary(String text) async { // Future<String> extractSummary(String text) async {
return _extractSummaryInternal(text, _defaultTimeoutDuration); // return _extractSummaryInternal(text, _defaultTimeoutDuration);
} // }
// 内部摘要提取方法,避免代码重复 // 内部摘要提取方法,避免代码重复
Future<String> _extractSummaryInternal( // Future<String> _extractSummaryInternal(
String text, int timeoutDuration) async { // String text, int timeoutDuration) async {
if (text.isEmpty) { // if (text.isEmpty) {
return '无法生成摘要:文本为空'; // return '无法生成摘要:文本为空';
} // }
isGeneratingSummary.value = true; // isGeneratingSummary.value = true;
try { // try {
// 构建提示词 // // 构建提示词
final messages = [ // final messages = [
{'role': 'user', 'content': '请为以下文本生成一个简洁的摘要,突出重点内容:\n\n$text'}, // {'role': 'user', 'content': '请为以下文本生成一个简洁的摘要,突出重点内容:\n\n$text'},
]; // ];
// 系统提示词 // // 系统提示词
const systemPrompt = ''' // const systemPrompt = '''
你是一个专业的文本摘要助手,擅长从会议记录、对话和文本中提取关键信息并生成简洁的摘要。 // 你是一个专业的文本摘要助手,擅长从会议记录、对话和文本中提取关键信息并生成简洁的摘要。
请按照以下格式生成摘要: // 请按照以下格式生成摘要:
1. 首先用1-2句话对整体内容进行简要概括 // 1. 首先用1-2句话对整体内容进行简要概括
2. 然后使用项目符号列表(•)列出关键点或重要信息 // 2. 然后使用项目符号列表(•)列出关键点或重要信息
3. 如果是对话内容,请特别标注出讨论的结论或达成的共识 // 3. 如果是对话内容,请特别标注出讨论的结论或达成的共识
请遵循以下原则: // 请遵循以下原则:
1. 保留原文的核心信息和关键点 // 1. 保留原文的核心信息和关键点
2. 使用简洁、清晰的语言 // 2. 使用简洁、清晰的语言
3. 保持客观,不添加个人观点 // 3. 保持客观,不添加个人观点
4. 摘要总长度应该是原文的1/3或更短 // 4. 摘要总长度应该是原文的1/3或更短
5. 确保列表中的每个要点都简明扼要,突出重点 // 5. 确保列表中的每个要点都简明扼要,突出重点
'''; // ''';
String result; // String result;
try { // try {
// 使用超时限制 // // 使用超时限制
result = await _aiService // result = await _aiService
.sendMessage( // .sendMessage(
messages: messages, // messages: messages,
systemPrompt: systemPrompt, // systemPrompt: systemPrompt,
) // )
.timeout(Duration(seconds: timeoutDuration), onTimeout: () { // .timeout(Duration(seconds: timeoutDuration), onTimeout: () {
throw TimeoutException('请求超时', Duration(seconds: timeoutDuration)); // throw TimeoutException('请求超时', Duration(seconds: timeoutDuration));
}); // });
} on TimeoutException catch (_) { // } on TimeoutException catch (_) {
final timeoutMessage = timeoutDuration == _defaultTimeoutDuration // final timeoutMessage = timeoutDuration == _defaultTimeoutDuration
? '生成摘要超时,请稍后重试' // ? '生成摘要超时,请稍后重试'
: '生成摘要超时,请检查网络连接后重试'; // : '生成摘要超时,请检查网络连接后重试';
summaryResult.value = timeoutMessage; // summaryResult.value = timeoutMessage;
return summaryResult.value; // return summaryResult.value;
} // }
// 更新结果并保存 // // 更新结果并保存
if (result.isNotEmpty) { // if (result.isNotEmpty) {
summaryResult.value = result; // summaryResult.value = result;
saveSummary(result); // saveSummary(result);
// 记录AI摘要API调用统计 // // 记录AI摘要API调用统计
try { // try {
_usageService.recordAiSummaryApiCall(); // _usageService.recordAiSummaryApiCall();
} catch (e) { // } catch (e) {
Logger.error('记录AI摘要统计失败: $e'); // Logger.error('记录AI摘要统计失败: $e');
} // }
} // }
return result; // return result;
} catch (e) { // } catch (e) {
final errorMessage = '生成摘要失败: ${e.toString()}'; // final errorMessage = '生成摘要失败: ${e.toString()}';
Logger.error('TranslationDetailController', errorMessage); // Logger.error('TranslationDetailController', errorMessage);
summaryResult.value = errorMessage; // summaryResult.value = errorMessage;
return errorMessage; // return errorMessage;
} finally { // } finally {
isGeneratingSummary.value = false; // isGeneratingSummary.value = false;
} // }
} // }
// 删除单条翻译记录 // 删除单条翻译记录
Future<void> deleteTranslationItem(TranslationItem item) async { Future<void> deleteTranslationItem(TranslationItem item) async {

352
lib/modules/translation/views/translation_detail_view.dart

@ -142,9 +142,9 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
if (controller.selectedTabIndex.value == 0) if (controller.selectedTabIndex.value == 0)
..._buildOriginalRecords(isDarkMode) ..._buildOriginalRecords(isDarkMode)
else else
_buildSummaryWidget(isDarkMode), //_buildSummaryWidget(isDarkMode),
SizedBox(height: 24.h), SizedBox(height: 24.h),
], ],
); );
}), }),
@ -323,23 +323,23 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
} }
// 构建总结视图 // 构建总结视图
Widget _buildSummaryWidget(bool isDarkMode) { // Widget _buildSummaryWidget(bool isDarkMode) {
final String combinedSourceText = _getCombinedSourceText(); // final String combinedSourceText = _getCombinedSourceText();
return Column( // return Column(
children: [ // children: [
// 摘要内容容器 // // 摘要内容容器
_buildSummaryContainer(isDarkMode), // _buildSummaryContainer(isDarkMode),
// 提取摘要按钮 // // 提取摘要按钮
Obx(() => _buildExtractSummaryButton(combinedSourceText, isDarkMode)), // Obx(() => _buildExtractSummaryButton(combinedSourceText, isDarkMode)),
// 重新生成按钮 // // 重新生成按钮
Obx(() => // Obx(() =>
_buildRegenerateSummaryButton(combinedSourceText, isDarkMode)), // _buildRegenerateSummaryButton(combinedSourceText, isDarkMode)),
], // ],
); // );
} // }
// 构建摘要容器 // 构建摘要容器
Widget _buildSummaryContainer(bool isDarkMode) { Widget _buildSummaryContainer(bool isDarkMode) {
@ -484,163 +484,163 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
} }
// 构建提取摘要按钮 // 构建提取摘要按钮
Widget _buildExtractSummaryButton( // Widget _buildExtractSummaryButton(
String combinedSourceText, bool isDarkMode) { // String combinedSourceText, bool isDarkMode) {
final bool isDisabled = controller.isGeneratingSummary.value || // final bool isDisabled = controller.isGeneratingSummary.value ||
controller.summaryResult.value.isNotEmpty; // controller.summaryResult.value.isNotEmpty;
return Container( // return Container(
width: double.infinity, // width: double.infinity,
margin: EdgeInsets.only(bottom: 16.h), // margin: EdgeInsets.only(bottom: 16.h),
child: ElevatedButton( // child: ElevatedButton(
onPressed: // onPressed:
isDisabled ? null : () => _extractSummary(combinedSourceText), // isDisabled ? null : () => _extractSummary(combinedSourceText),
style: ElevatedButton.styleFrom( // style: ElevatedButton.styleFrom(
backgroundColor: isDarkMode ? AppColors.primary : Colors.blue, // backgroundColor: isDarkMode ? AppColors.primary : Colors.blue,
foregroundColor: Colors.white, // foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 12.h), // padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r), // borderRadius: BorderRadius.circular(16.r),
), // ),
elevation: 0, // elevation: 0,
disabledBackgroundColor: controller.isGeneratingSummary.value // disabledBackgroundColor: controller.isGeneratingSummary.value
? isDarkMode // ? isDarkMode
? AppColors.primary.withAlpha(128) // ? AppColors.primary.withAlpha(128)
: Colors.blue.withAlpha(128) // : Colors.blue.withAlpha(128)
: Colors.grey.withAlpha(128), // : Colors.grey.withAlpha(128),
), // ),
child: controller.isGeneratingSummary.value // child: controller.isGeneratingSummary.value
? _buildGeneratingIndicator(isDarkMode) // ? _buildGeneratingIndicator(isDarkMode)
: Text( // : Text(
controller.summaryResult.value.isEmpty // controller.summaryResult.value.isEmpty
? 'extractSummary'.tr // ? 'extractSummary'.tr
: 'summaryGenerated'.tr, // 提取摘要 : 已生成摘要 // : 'summaryGenerated'.tr, // 提取摘要 : 已生成摘要
style: TextStyle( // style: TextStyle(
fontSize: 16.sp, // fontSize: 16.sp,
fontWeight: FontWeight.w600, // fontWeight: FontWeight.w600,
), // ),
), // ),
), // ),
); // );
} // }
// 构建生成中指示器 // 构建生成中指示器
Widget _buildGeneratingIndicator(bool isDarkMode) { // Widget _buildGeneratingIndicator(bool isDarkMode) {
return Row( // return Row(
mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
children: [ // children: [
SizedBox( // SizedBox(
width: 20.w, // width: 20.w,
height: 20.h, // height: 20.h,
child: CircularProgressIndicator( // child: CircularProgressIndicator(
color: Colors.white, // color: Colors.white,
strokeWidth: 2.0, // strokeWidth: 2.0,
), // ),
), // ),
SizedBox(width: 12.w), // SizedBox(width: 12.w),
Text( // Text(
'generating'.tr, // 生成中... // 'generating'.tr, // 生成中...
style: TextStyle( // style: TextStyle(
fontSize: 16.sp, // fontSize: 16.sp,
fontWeight: FontWeight.w600, // fontWeight: FontWeight.w600,
), // ),
), // ),
], // ],
); // );
} // }
// 构建重新生成按钮 // 构建重新生成按钮
Widget _buildRegenerateSummaryButton( // Widget _buildRegenerateSummaryButton(
String combinedSourceText, bool isDarkMode) { // String combinedSourceText, bool isDarkMode) {
if (controller.summaryResult.value.isEmpty || // if (controller.summaryResult.value.isEmpty ||
controller.isGeneratingSummary.value) { // controller.isGeneratingSummary.value) {
return SizedBox.shrink(); // return SizedBox.shrink();
} // }
return Container( // return Container(
width: double.infinity, // width: double.infinity,
margin: EdgeInsets.only(bottom: 16.h), // margin: EdgeInsets.only(bottom: 16.h),
child: OutlinedButton( // child: OutlinedButton(
onPressed: () => _extractSummary(combinedSourceText), // onPressed: () => _extractSummary(combinedSourceText),
style: OutlinedButton.styleFrom( // style: OutlinedButton.styleFrom(
foregroundColor: isDarkMode ? AppColors.primary : Colors.blue, // foregroundColor: isDarkMode ? AppColors.primary : Colors.blue,
side: BorderSide(color: isDarkMode ? AppColors.primary : Colors.blue), // side: BorderSide(color: isDarkMode ? AppColors.primary : Colors.blue),
padding: EdgeInsets.symmetric(vertical: 12.h), // padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r), // borderRadius: BorderRadius.circular(16.r),
), // ),
), // ),
child: Text( // child: Text(
'regenerate'.tr, // 重新生成 // 'regenerate'.tr, // 重新生成
style: TextStyle( // style: TextStyle(
fontSize: 16.sp, // fontSize: 16.sp,
fontWeight: FontWeight.w600, // fontWeight: FontWeight.w600,
), // ),
), // ),
), // ),
); // );
} // }
// 提取摘要方法 // 提取摘要方法
void _extractSummary(String text) async { // void _extractSummary(String text) async {
final result = await controller.extractSummary(text); // final result = await controller.extractSummary(text);
// 检查是否超时,如果超时则显示重试选项 // // 检查是否超时,如果超时则显示重试选项
if (result.contains('超时')) { // if (result.contains('超时')) {
_showTimeoutDialog(text); // _showTimeoutDialog(text);
} // }
} // }
// 显示超时对话框 // 显示超时对话框
void _showTimeoutDialog(String text) { // void _showTimeoutDialog(String text) {
Get.dialog( // Get.dialog(
AlertDialog( // AlertDialog(
title: Text( // title: Text(
'requestTimeout'.tr, // 请求超时 // 'requestTimeout'.tr, // 请求超时
style: TextStyle( // style: TextStyle(
fontSize: 18.sp, // fontSize: 18.sp,
fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
), // ),
), // ),
content: Text( // content: Text(
'summaryTimeoutMessage'.tr, // 生成摘要请求超时,可能是网络问题或服务器繁忙。 // 'summaryTimeoutMessage'.tr, // 生成摘要请求超时,可能是网络问题或服务器繁忙。
style: TextStyle( // style: TextStyle(
fontSize: 16.sp, // fontSize: 16.sp,
), // ),
), // ),
actions: [ // actions: [
TextButton( // TextButton(
onPressed: () => Get.back(), // onPressed: () => Get.back(),
child: Text( // child: Text(
'cancel'.tr, // 取消 // 'cancel'.tr, // 取消
style: TextStyle( // style: TextStyle(
fontSize: 16.sp, // fontSize: 16.sp,
color: Colors.grey[700], // color: Colors.grey[700],
), // ),
), // ),
), // ),
TextButton( // TextButton(
onPressed: () { // onPressed: () {
Get.back(); // Get.back();
// 使用延长的超时时间重试 // // 使用延长的超时时间重试
controller.retryExtractSummaryWithExtendedTimeout(text); // controller.retryExtractSummaryWithExtendedTimeout(text);
}, // },
child: Text( // child: Text(
'retry'.tr, // 重试 // 'retry'.tr, // 重试
style: TextStyle( // style: TextStyle(
fontSize: 16.sp, // fontSize: 16.sp,
color: Colors.blue, // color: Colors.blue,
fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
), // ),
), // ),
), // ),
], // ],
shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r), // borderRadius: BorderRadius.circular(12.r),
), // ),
), // ),
); // );
} // }
// 显示删除单条记录确认对话框 // 显示删除单条记录确认对话框
void _showDeleteItemConfirmDialog(TranslationItem item) { void _showDeleteItemConfirmDialog(TranslationItem item) {
@ -750,18 +750,18 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
'${'originalText'.tr}:\n$sourceText\n\n${'translatedText'.tr}:\n$translatedText'; // 原文:译文: '${'originalText'.tr}:\n$sourceText\n\n${'translatedText'.tr}:\n$translatedText'; // 原文:译文:
} else { } else {
// 分享摘要 // 分享摘要
if (controller.summaryResult.value.isNotEmpty) { // if (controller.summaryResult.value.isNotEmpty) {
shareText = // shareText =
'${'sessionSummary'.tr}:\n${controller.summaryResult.value}'; // 会话摘要: // '${'sessionSummary'.tr}:\n${controller.summaryResult.value}'; // 会话摘要:
} else { // } else {
Get.snackbar( // Get.snackbar(
'cannotShare'.tr, // 无法分享 // 'cannotShare'.tr, // 无法分享
'generateSummaryFirst'.tr, // 请先生成摘要 // 'generateSummaryFirst'.tr, // 请先生成摘要
snackPosition: SnackPosition.BOTTOM, // snackPosition: SnackPosition.BOTTOM,
duration: Duration(seconds: 2), // duration: Duration(seconds: 2),
); // );
return; // return;
} // }
} }
// 调用系统分享 // 调用系统分享

45
lib/modules/translation/views/translation_view.dart

@ -343,16 +343,31 @@ class TranslationView extends GetView<TranslationController> {
} }
Widget _buildBody(bool isDarkMode) { Widget _buildBody(bool isDarkMode) {
return Column( return GestureDetector(
children: [ onPanUpdate: (details) {
Expanded( // 检测左滑手势
child: _buildTranslationContent(isDarkMode), if (details.delta.dx < -10) {
), // 左滑距离超过10像素时触发
_buildControlBar(isDarkMode), _handleSwipeLeft();
], }
},
child: Column(
children: [
Expanded(
child: _buildTranslationContent(isDarkMode),
),
_buildControlBar(isDarkMode),
],
),
); );
} }
// 处理左滑手势
void _handleSwipeLeft() async {
await controller.stopAll();
Get.toNamed(Routes.translationHistory);
}
Widget _buildTranslationContent(bool isDarkMode) { Widget _buildTranslationContent(bool isDarkMode) {
return Obx(() { return Obx(() {
// 其他模式使用原有的列表布局 // 其他模式使用原有的列表布局
@ -969,14 +984,14 @@ class TranslationView extends GetView<TranslationController> {
controller.deleteTranslationItem(item.sessionId, item.timestamp); controller.deleteTranslationItem(item.sessionId, item.timestamp);
// 显示删除成功提示 // 显示删除成功提示
Get.snackbar( // Get.snackbar(
'success'.tr, // deleteSuccess // 'success'.tr, // deleteSuccess
'已删除该翻译记录', // deleteTranslationSuccess // '已删除该翻译记录', // deleteTranslationSuccess
snackPosition: SnackPosition.BOTTOM, // snackPosition: SnackPosition.BOTTOM,
backgroundColor: Get.isDarkMode ? Colors.grey[800] : Colors.grey[200], // backgroundColor: Get.isDarkMode ? Colors.grey[800] : Colors.grey[200],
colorText: Get.isDarkMode ? Colors.white : Colors.black, // colorText: Get.isDarkMode ? Colors.white : Colors.black,
duration: const Duration(milliseconds: 800), // duration: const Duration(milliseconds: 800),
); // );
} catch (e) { } catch (e) {
// 显示删除失败提示 // 显示删除失败提示
Get.snackbar( Get.snackbar(

Loading…
Cancel
Save