|
|
|
@ -10,6 +10,7 @@ import 'package:get_storage/get_storage.dart'; |
|
|
|
import 'package:intl/intl.dart'; |
|
|
|
import 'package:path_provider/path_provider.dart'; |
|
|
|
import 'package:permission_handler/permission_handler.dart'; |
|
|
|
import '../../../data/services/music_manager.dart'; |
|
|
|
import '../../../data/services/volcano_translation_service.dart'; |
|
|
|
import '../../../data/services/tts_service.dart'; |
|
|
|
import '../../../data/services/language_manager.dart'; |
|
|
|
@ -37,6 +38,8 @@ class TranslationController extends GetxController { |
|
|
|
final GetStorage _storage = GetStorage(); |
|
|
|
// 蓝牙服务 |
|
|
|
final bleManager = Get.find<BleManager>(); |
|
|
|
//音乐播放管理 |
|
|
|
final _musiceManager = Get.find<MusicManager>(); |
|
|
|
// 音频输入源 |
|
|
|
bool _audioSourceType = false; |
|
|
|
//是否开启播放 |
|
|
|
@ -68,6 +71,7 @@ class TranslationController extends GetxController { |
|
|
|
|
|
|
|
RxInt activeSpeaker = 0.obs; // 0=无激活, 1=按钮1, 2=按钮2 |
|
|
|
RxInt lastActiveSpeaker = 0.obs; // 上一次状态 |
|
|
|
bool isContinuePlaying = false; // 是否继续播放 |
|
|
|
// 状态变量 |
|
|
|
final isRecognizing = false.obs; |
|
|
|
final isTranslating = false.obs; |
|
|
|
@ -260,6 +264,32 @@ class TranslationController extends GetxController { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 暂停其他服务 |
|
|
|
Future<void> suspendOtherServices() async { |
|
|
|
try { |
|
|
|
var status = await _musiceManager.getStatus(); |
|
|
|
var isPlaying = status['isPlaying'] ?? false; |
|
|
|
|
|
|
|
if (isPlaying == true) { |
|
|
|
isContinuePlaying = true; |
|
|
|
await _musiceManager.pause(); // 暂停音乐 |
|
|
|
} else { |
|
|
|
isContinuePlaying = false; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
Logger.error('初始化服务失败: ${e.toString()}'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 恢复其他服务 |
|
|
|
Future<void> restoreOtherServices() async { |
|
|
|
try { |
|
|
|
if (isContinuePlaying) await _musiceManager.resume(); // 暂停音乐 |
|
|
|
} catch (e) { |
|
|
|
Logger.error('初始化服务失败: ${e.toString()}'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 初始化服务 |
|
|
|
Future<void> _initServices() async { |
|
|
|
try { |
|
|
|
@ -298,6 +328,7 @@ class TranslationController extends GetxController { |
|
|
|
_voiceInteractionSubscription?.cancel(); |
|
|
|
_translationDebounceTimer?.cancel(); |
|
|
|
scrollController.dispose(); |
|
|
|
restoreOtherServices(); |
|
|
|
super.onClose(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -647,8 +678,7 @@ class TranslationController extends GetxController { |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
Logger.info( |
|
|
|
'未找到匹配的历史项 $sourceText ${timestamp.toIso8601String()}'); |
|
|
|
Logger.info('未找到匹配的历史项 $sourceText ${timestamp.toIso8601String()}'); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
@ -906,14 +936,14 @@ class TranslationController extends GetxController { |
|
|
|
void saveTranslationHistory() { |
|
|
|
try { |
|
|
|
// 只保存当前内存中的完成态记录,过滤掉中间态记录 |
|
|
|
final List<TranslationItem> finalRecords = translationHistory |
|
|
|
.where((item) => !item.isIntermediate) |
|
|
|
.toList(); |
|
|
|
final List<TranslationItem> finalRecords = |
|
|
|
translationHistory.where((item) => !item.isIntermediate).toList(); |
|
|
|
|
|
|
|
// 应用存储限制,保留最新的1000条完成态记录 |
|
|
|
List<TranslationItem> historyToSave = finalRecords; |
|
|
|
if (finalRecords.length > _maxStorageItems) { |
|
|
|
historyToSave = finalRecords.sublist(finalRecords.length - _maxStorageItems); |
|
|
|
historyToSave = |
|
|
|
finalRecords.sublist(finalRecords.length - _maxStorageItems); |
|
|
|
} |
|
|
|
|
|
|
|
// 保存到本地存储 |
|
|
|
@ -934,7 +964,8 @@ class TranslationController extends GetxController { |
|
|
|
scrollController.addListener(() { |
|
|
|
// 🔑 reverse模式下:检查是否滚动到底部(实际是历史记录的顶部) |
|
|
|
// 参考Agent模块的实现 |
|
|
|
if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 100) { |
|
|
|
if (scrollController.position.pixels >= |
|
|
|
scrollController.position.maxScrollExtent - 100) { |
|
|
|
// 当距离底部100像素时触发加载更多历史记录 |
|
|
|
if (hasMoreHistory.value && !isLoadingMore.value) { |
|
|
|
Logger.d(TAG, '触发加载更多翻译历史记录(reverse模式)'); |
|
|
|
@ -950,7 +981,8 @@ class TranslationController extends GetxController { |
|
|
|
Future<void> loadMoreHistory() async { |
|
|
|
// 防止重复加载 |
|
|
|
if (isLoadingMore.value || !hasMoreHistory.value) { |
|
|
|
Logger.d(TAG, '跳过加载更多:isLoadingMore=${isLoadingMore.value}, hasMoreHistory=${hasMoreHistory.value}'); |
|
|
|
Logger.d(TAG, |
|
|
|
'跳过加载更多:isLoadingMore=${isLoadingMore.value}, hasMoreHistory=${hasMoreHistory.value}'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
@ -979,15 +1011,18 @@ class TranslationController extends GetxController { |
|
|
|
final endIndex = totalItems - ((nextPage - 1) * pageSize); |
|
|
|
final startIndex = totalItems - (nextPage * pageSize); |
|
|
|
|
|
|
|
Logger.d(TAG, '分页计算: 总记录=$totalItems, 总页数=$totalPages, 当前页=$nextPage, startIndex=$startIndex, endIndex=$endIndex'); |
|
|
|
Logger.d(TAG, |
|
|
|
'分页计算: 总记录=$totalItems, 总页数=$totalPages, 当前页=$nextPage, startIndex=$startIndex, endIndex=$endIndex'); |
|
|
|
|
|
|
|
if (endIndex > 0) { |
|
|
|
// 获取当前页的数据,确保索引不越界 |
|
|
|
final actualStartIndex = startIndex < 0 ? 0 : startIndex; |
|
|
|
final actualEndIndex = endIndex > totalItems ? totalItems : endIndex; |
|
|
|
|
|
|
|
final pageItems = allHistory.sublist(actualStartIndex, actualEndIndex); |
|
|
|
Logger.d(TAG, '实际索引: start=$actualStartIndex, end=$actualEndIndex, 获取${pageItems.length}条记录'); |
|
|
|
final pageItems = |
|
|
|
allHistory.sublist(actualStartIndex, actualEndIndex); |
|
|
|
Logger.d(TAG, |
|
|
|
'实际索引: start=$actualStartIndex, end=$actualEndIndex, 获取${pageItems.length}条记录'); |
|
|
|
|
|
|
|
if (pageItems.isNotEmpty) { |
|
|
|
// 🔑 简化延迟,参考Agent模块(300ms vs 1000ms) |
|
|
|
@ -1028,8 +1063,6 @@ class TranslationController extends GetxController { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有完成态历史记录(供历史页面使用) |
|
|
|
// 【修复】简化实现,合并存储和内存中的完成态记录 |
|
|
|
List<TranslationItem> getAllHistory() { |
|
|
|
@ -1045,7 +1078,8 @@ class TranslationController extends GetxController { |
|
|
|
historyList.map((item) => TranslationItem.fromJson(item)).toList(); |
|
|
|
|
|
|
|
for (final item in storedHistory) { |
|
|
|
final id = '${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; |
|
|
|
final id = |
|
|
|
'${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; |
|
|
|
if (!existingIds.contains(id)) { |
|
|
|
existingIds.add(id); |
|
|
|
result.add(item); |
|
|
|
@ -1056,7 +1090,8 @@ class TranslationController extends GetxController { |
|
|
|
// 添加当前内存中的完成态记录(排除中间态记录) |
|
|
|
for (final item in translationHistory) { |
|
|
|
if (!item.isIntermediate) { |
|
|
|
final id = '${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; |
|
|
|
final id = |
|
|
|
'${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; |
|
|
|
if (!existingIds.contains(id)) { |
|
|
|
existingIds.add(id); |
|
|
|
result.add(item); |
|
|
|
@ -1110,7 +1145,8 @@ class TranslationController extends GetxController { |
|
|
|
// 3. 刷新UI显示 |
|
|
|
translationHistory.refresh(); |
|
|
|
|
|
|
|
Logger.info('删除会话历史成功: sessionId=$sessionId, 内存删除${removedFromMemory}条, 存储删除${removedFromStorage}条'); |
|
|
|
Logger.info( |
|
|
|
'删除会话历史成功: sessionId=$sessionId, 内存删除${removedFromMemory}条, 存储删除${removedFromStorage}条'); |
|
|
|
} catch (e) { |
|
|
|
Logger.error('删除会话历史失败: ${e.toString()}'); |
|
|
|
rethrow; // 重新抛出异常,让调用方处理 |
|
|
|
@ -1124,7 +1160,8 @@ class TranslationController extends GetxController { |
|
|
|
final originalCount = translationHistory.length; |
|
|
|
translationHistory.removeWhere((item) => |
|
|
|
item.sessionId == sessionId && |
|
|
|
item.timestamp.millisecondsSinceEpoch == timestamp.millisecondsSinceEpoch); |
|
|
|
item.timestamp.millisecondsSinceEpoch == |
|
|
|
timestamp.millisecondsSinceEpoch); |
|
|
|
final removedFromMemory = originalCount - translationHistory.length; |
|
|
|
|
|
|
|
// 2. 从本地存储中删除指定的翻译记录 |
|
|
|
@ -1139,7 +1176,8 @@ class TranslationController extends GetxController { |
|
|
|
final originalStoredCount = storedHistory.length; |
|
|
|
storedHistory.removeWhere((item) => |
|
|
|
item.sessionId == sessionId && |
|
|
|
item.timestamp.millisecondsSinceEpoch == timestamp.millisecondsSinceEpoch); |
|
|
|
item.timestamp.millisecondsSinceEpoch == |
|
|
|
timestamp.millisecondsSinceEpoch); |
|
|
|
removedFromStorage = originalStoredCount - storedHistory.length; |
|
|
|
|
|
|
|
// 重新保存更新后的存储数据 |
|
|
|
@ -1151,7 +1189,8 @@ class TranslationController extends GetxController { |
|
|
|
// 3. 刷新UI显示 |
|
|
|
translationHistory.refresh(); |
|
|
|
|
|
|
|
Logger.info('删除单条翻译记录成功: sessionId=$sessionId, timestamp=${timestamp.toIso8601String()}, 内存删除${removedFromMemory}条, 存储删除${removedFromStorage}条'); |
|
|
|
Logger.info( |
|
|
|
'删除单条翻译记录成功: sessionId=$sessionId, timestamp=${timestamp.toIso8601String()}, 内存删除${removedFromMemory}条, 存储删除${removedFromStorage}条'); |
|
|
|
} catch (e) { |
|
|
|
Logger.error('删除单条翻译记录失败: ${e.toString()}'); |
|
|
|
rethrow; // 重新抛出异常,让调用方处理 |
|
|
|
@ -1162,10 +1201,6 @@ class TranslationController extends GetxController { |
|
|
|
void scrollToBottom({bool animate = true}) { |
|
|
|
_scrollToBottom(animate: animate); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 翻译项模型 |
|
|
|
|