import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../../../core/utils/logger.dart'; import '../models/translation_models.dart'; /// 翻译历史记录管理类 /// 负责管理翻译历史的存储、加载、分页等功能 class TranslationHistoryManager extends GetxController { static const String TAG = 'TranslationHistoryManager'; // 存储相关配置 static const String _historyKey = 'translation_history'; static const int _maxStorageItems = 1000; // 存储限制 static const int _maxDisplayItems = 20; // 显示限制 final GetStorage _storage = GetStorage(); // 翻译历史数据 final translationHistory = [].obs; // 分页加载相关状态 final isLoadingMore = false.obs; final hasMoreHistory = true.obs; final currentPage = 1.obs; final pageSize = 20; final isLoadingMoreError = false.obs; bool _scrollListenerSetup = false; // 滚动控制器 final ScrollController scrollController = ScrollController(); /// 初始化历史管理器 void initialize() { loadTranslationHistory(); _setupScrollListener(); } /// 加载翻译历史记录 /// 初始化时只加载最近的显示条数,提高性能 void loadTranslationHistory() { final historyJson = _storage.read(_historyKey); if (historyJson != null) { try { final List historyList = jsonDecode(historyJson); final List allHistory = historyList.map((item) => TranslationItem.fromJson(item)).toList(); // 初始化分页状态 currentPage.value = 1; isLoadingMore.value = false; isLoadingMoreError.value = false; // 主页面只显示最近的记录,保证界面性能 if (allHistory.length > _maxDisplayItems) { translationHistory.value = allHistory.sublist(allHistory.length - _maxDisplayItems); hasMoreHistory.value = true; } else { translationHistory.value = allHistory; hasMoreHistory.value = false; } Logger.info('翻译历史加载成功: ${translationHistory.length}条记录'); } catch (e) { _storage.remove(_historyKey); Logger.error('加载翻译历史失败: ${e.toString()}'); } } else { // 没有历史数据时初始化分页状态 hasMoreHistory.value = false; currentPage.value = 1; isLoadingMore.value = false; isLoadingMoreError.value = false; } } /// 保存翻译历史记录 /// 只保存完成态记录,过滤中间态记录 void saveTranslationHistory() { try { // 只保存完成态记录 final List finalRecords = translationHistory.where((item) => !item.isIntermediate).toList(); // 应用存储限制 List historyToSave = finalRecords; if (finalRecords.length > _maxStorageItems) { historyToSave = finalRecords.sublist(finalRecords.length - _maxStorageItems); } // 保存到本地存储 final List> historyJson = historyToSave.map((item) => item.toJson()).toList(); _storage.write(_historyKey, jsonEncode(historyJson)); Logger.info('翻译历史保存成功: 存储${historyToSave.length}条记录'); } catch (e) { Logger.error('保存翻译历史失败: ${e.toString()}'); } } /// 添加新的翻译记录 /// [item] 要添加的翻译记录 /// [scrollToBottom] 是否滚动到底部 void addTranslationItem(TranslationItem item, {bool scrollToBottom = true}) { translationHistory.add(item); if (scrollToBottom) { _scrollToBottom(); } } /// 更新翻译记录 /// [timestamp] 记录的时间戳,用于定位记录 /// [updater] 更新函数 bool updateTranslationItem( DateTime timestamp, Function(TranslationItem) updater) { final index = translationHistory .indexWhere((item) => item.timestamp.isAtSameMomentAs(timestamp)); if (index != -1) { updater(translationHistory[index]); translationHistory.refresh(); return true; } return false; } /// 加载更多历史记录(分页加载) Future loadMoreHistory() async { if (isLoadingMore.value || !hasMoreHistory.value) { return; } try { isLoadingMore.value = true; isLoadingMoreError.value = false; final nextPage = currentPage.value + 1; Logger.i(TAG, '正在加载第 $nextPage 页翻译历史...'); // 从存储中获取所有历史记录 final historyJson = _storage.read(_historyKey); if (historyJson != null) { final List historyList = jsonDecode(historyJson); final List allHistory = historyList.map((item) => TranslationItem.fromJson(item)).toList(); // 计算分页参数 final totalItems = allHistory.length; final endIndex = totalItems - ((nextPage - 1) * pageSize); final startIndex = totalItems - (nextPage * pageSize); if (endIndex > 0) { final actualStartIndex = startIndex < 0 ? 0 : startIndex; final actualEndIndex = endIndex > totalItems ? totalItems : endIndex; final pageItems = allHistory.sublist(actualStartIndex, actualEndIndex); if (pageItems.isNotEmpty) { await Future.delayed(const Duration(milliseconds: 300)); // reverse模式下:将新记录插入到现有记录列表的开头 final updatedHistory = [...pageItems, ...translationHistory]; translationHistory.assignAll(updatedHistory); // 更新分页状态 currentPage.value = nextPage; hasMoreHistory.value = startIndex > 0; Logger.i(TAG, '成功加载 ${pageItems.length} 条历史记录'); } else { hasMoreHistory.value = false; } } else { hasMoreHistory.value = false; } } else { hasMoreHistory.value = false; } } catch (e) { Logger.e(TAG, '加载更多历史记录失败: $e'); isLoadingMoreError.value = true; } finally { isLoadingMore.value = false; } } /// 获取所有完成态历史记录 List getAllHistory() { try { final List result = []; final Set existingIds = {}; // 添加存储的历史记录 final historyJson = _storage.read(_historyKey); if (historyJson != null) { final List historyList = jsonDecode(historyJson); final List storedHistory = historyList.map((item) => TranslationItem.fromJson(item)).toList(); for (final item in storedHistory) { final id = '${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; if (!existingIds.contains(id)) { existingIds.add(id); result.add(item); } } } // 添加当前内存中的完成态记录 for (final item in translationHistory) { if (!item.isIntermediate) { final id = '${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; if (!existingIds.contains(id)) { existingIds.add(id); result.add(item); } } } // 按时间排序 result.sort((a, b) => a.timestamp.compareTo(b.timestamp)); return result; } catch (e) { Logger.error('获取完整历史记录失败: ${e.toString()}'); return translationHistory.where((item) => !item.isIntermediate).toList(); } } /// 清除所有翻译历史 void clearTranslationHistory() { translationHistory.clear(); _storage.remove(_historyKey); Logger.info('翻译历史已清除'); } /// 删除指定会话的所有翻译记录 void deleteSessionHistory(String sessionId) { try { // 从内存中删除 final originalCount = translationHistory.length; translationHistory.removeWhere((item) => item.sessionId == sessionId); final removedFromMemory = originalCount - translationHistory.length; // 从存储中删除 final historyJson = _storage.read(_historyKey); int removedFromStorage = 0; if (historyJson != null) { final List historyList = jsonDecode(historyJson); final List storedHistory = historyList.map((item) => TranslationItem.fromJson(item)).toList(); final originalStoredCount = storedHistory.length; storedHistory.removeWhere((item) => item.sessionId == sessionId); removedFromStorage = originalStoredCount - storedHistory.length; // 重新保存 final List> updatedHistoryJson = storedHistory.map((item) => item.toJson()).toList(); _storage.write(_historyKey, jsonEncode(updatedHistoryJson)); } translationHistory.refresh(); Logger.info( '删除会话历史成功: sessionId=$sessionId, 内存删除${removedFromMemory}条, 存储删除${removedFromStorage}条'); } catch (e) { Logger.error('删除会话历史失败: ${e.toString()}'); rethrow; } } /// 删除指定的单条翻译记录 void deleteTranslationItem(String sessionId, DateTime timestamp) { try { // 从内存中删除 final originalCount = translationHistory.length; translationHistory.removeWhere((item) => item.sessionId == sessionId && item.timestamp.millisecondsSinceEpoch == timestamp.millisecondsSinceEpoch); final removedFromMemory = originalCount - translationHistory.length; // 从存储中删除 final historyJson = _storage.read(_historyKey); int removedFromStorage = 0; if (historyJson != null) { final List historyList = jsonDecode(historyJson); final List storedHistory = historyList.map((item) => TranslationItem.fromJson(item)).toList(); final originalStoredCount = storedHistory.length; storedHistory.removeWhere((item) => item.sessionId == sessionId && item.timestamp.millisecondsSinceEpoch == timestamp.millisecondsSinceEpoch); removedFromStorage = originalStoredCount - storedHistory.length; // 重新保存 final List> updatedHistoryJson = storedHistory.map((item) => item.toJson()).toList(); _storage.write(_historyKey, jsonEncode(updatedHistoryJson)); } translationHistory.refresh(); Logger.info( '删除单条翻译记录成功: sessionId=$sessionId, 内存删除${removedFromMemory}条, 存储删除${removedFromStorage}条'); } catch (e) { Logger.error('删除单条翻译记录失败: ${e.toString()}'); rethrow; } } /// 滚动到底部 void scrollToBottom({bool animate = true}) { _scrollToBottom(animate: animate); } /// 设置滚动监听器 void _setupScrollListener() { if (_scrollListenerSetup) return; scrollController.addListener(() { // reverse模式下:检查是否滚动到底部 if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 100) { if (hasMoreHistory.value && !isLoadingMore.value) { Logger.d(TAG, '触发加载更多翻译历史记录'); loadMoreHistory(); } } }); _scrollListenerSetup = true; } /// 内部滚动到底部方法 void _scrollToBottom({bool animate = true}) { if (scrollController.hasClients && translationHistory.isNotEmpty) { try { const targetPosition = 0.0; // reverse模式下最新消息在顶部 if (animate) { scrollController.animateTo( targetPosition, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); } else { scrollController.jumpTo(targetPosition); } } catch (e) { Logger.error('滚动到顶部失败: ${e.toString()}'); } } } /// 释放资源 void dispose() { scrollController.dispose(); Logger.info('翻译历史管理器已释放'); } }