You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
12 KiB

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 = <TranslationItem>[].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<dynamic> historyList = jsonDecode(historyJson);
final List<TranslationItem> 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<TranslationItem> finalRecords =
translationHistory.where((item) => !item.isIntermediate).toList();
// 应用存储限制
List<TranslationItem> historyToSave = finalRecords;
if (finalRecords.length > _maxStorageItems) {
historyToSave =
finalRecords.sublist(finalRecords.length - _maxStorageItems);
}
// 保存到本地存储
final List<Map<String, dynamic>> 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<void> 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<dynamic> historyList = jsonDecode(historyJson);
final List<TranslationItem> 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<TranslationItem> getAllHistory() {
try {
final List<TranslationItem> result = <TranslationItem>[];
final Set<String> existingIds = <String>{};
// 添加存储的历史记录
final historyJson = _storage.read(_historyKey);
if (historyJson != null) {
final List<dynamic> historyList = jsonDecode(historyJson);
final List<TranslationItem> 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<dynamic> historyList = jsonDecode(historyJson);
final List<TranslationItem> storedHistory =
historyList.map((item) => TranslationItem.fromJson(item)).toList();
final originalStoredCount = storedHistory.length;
storedHistory.removeWhere((item) => item.sessionId == sessionId);
removedFromStorage = originalStoredCount - storedHistory.length;
// 重新保存
final List<Map<String, dynamic>> 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<dynamic> historyList = jsonDecode(historyJson);
final List<TranslationItem> 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<Map<String, dynamic>> 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('翻译历史管理器已释放');
}
}