import 'dart:convert'; import 'package:ainoval/models/editor_content.dart'; import 'package:ainoval/models/novel_structure.dart' as novel_models; import 'package:ainoval/models/novel_summary.dart'; import 'package:ainoval/utils/logger.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uuid/uuid.dart'; // Import uuid package import 'package:hive/hive.dart'; import '../models/chat_models.dart'; /// 本地存储服务,用于缓存和获取小说数据 class LocalStorageService { SharedPreferences? _prefs; final Uuid _uuid = const Uuid(); // For generating unique local IDs // 添加小说缓存 final Map _novelCache = {}; final Map _novelCacheTimestamp = {}; final Duration _cacheTTL = const Duration(minutes: 5); // 缓存有效期 final Map _wordCountCache = {}; // 场景字数缓存 // 初始化 Future init() async { _prefs ??= await SharedPreferences.getInstance(); } // 确保已初始化 Future _ensureInitialized() async { if (_prefs == null) { await init(); } return _prefs!; } // 基础存储方法 Future getString(String key) async { final prefs = await _ensureInitialized(); return prefs.getString(key); } Future setString(String key, String value) async { final prefs = await _ensureInitialized(); return await prefs.setString(key, value); } Future remove(String key) async { final prefs = await _ensureInitialized(); return await prefs.remove(key); } // 存储键 static const String _novelsKey = 'novels'; static const String _currentNovelKey = 'current_novel'; static const String _editorContentPrefix = 'editor_content_'; static const String _editorSettingsKey = 'editor_settings'; // --- New Key for Pending Messages --- static const String _pendingMessagesKey = 'pending_chat_messages'; // 获取所有小说 Future> getNovels() async { final prefs = await _ensureInitialized(); final novelsJson = prefs.getStringList(_novelsKey) ?? []; /* AppLogger.d('LocalStorageService', 'getNovels: Raw JSON list from prefs: $novelsJson'); */ try { final novels = novelsJson.map((json) { // AppLogger.v('LocalStorageService', 'getNovels: Parsing JSON: $json'); final novel = novel_models.Novel.fromJson(jsonDecode(json)); AppLogger.v('LocalStorageService', 'getNovels: Parsed Novel: ID=${novel.id}, Title=${novel.title}, Acts=${novel.acts.length}'); return novel; }).toList(); AppLogger.i('LocalStorageService', 'getNovels: Successfully parsed ${novels.length} novels.'); return novels; } catch (e, stackTrace) { AppLogger.e('LocalStorageService', 'getNovels: Failed to parse novels JSON.', e, stackTrace); return []; } } // 保存所有小说 Future saveNovels(List novels) async { final prefs = await _ensureInitialized(); try { final novelsJson = novels.map((novel) { final jsonMap = novel.toJson(); final jsonString = jsonEncode(jsonMap); AppLogger.v('LocalStorageService', 'saveNovels: Serializing Novel ID=${novel.id}, Title=${novel.title}, Acts=${novel.acts.length}'); return jsonString; }).toList(); /* AppLogger.d('LocalStorageService', 'saveNovels: Saving JSON list to prefs: $novelsJson'); */ await prefs.setStringList(_novelsKey, novelsJson); AppLogger.i('LocalStorageService', 'saveNovels: Successfully saved ${novels.length} novels.'); } catch (e, stackTrace) { AppLogger.e('LocalStorageService', 'saveNovels: Failed to save novels.', e, stackTrace); } } // 保存小说摘要列表 Future saveNovelSummaries(List novels) async { final prefs = await _ensureInitialized(); final novelsJson = novels.map((novel) => jsonEncode(novel.toJson())).toList(); await prefs.setStringList('novel_summaries', novelsJson); } // 获取单个小说 Future getNovel(String id) async { AppLogger.d('LocalStorageService', 'getNovel: Attempting to get novel with ID: $id'); // 检查缓存是否存在且有效 if (_novelCache.containsKey(id)) { final cacheTime = _novelCacheTimestamp[id]; if (cacheTime != null && DateTime.now().difference(cacheTime) < _cacheTTL) { AppLogger.i('LocalStorageService', 'getNovel: Using cached novel: ID=$id, Title=${_novelCache[id]!.title}, Acts=${_novelCache[id]!.acts.length}'); return _novelCache[id]; } } // 缓存不存在或已过期,从存储获取 final novels = await getNovels(); try { final novel = novels.firstWhere( (novel) => novel.id == id, ); // 更新缓存 _novelCache[id] = novel; _novelCacheTimestamp[id] = DateTime.now(); AppLogger.i('LocalStorageService', 'getNovel: Found novel: ID=${novel.id}, Title=${novel.title}, Acts=${novel.acts.length}'); return novel; } catch (e) { AppLogger.w( 'LocalStorageService', 'getNovel: Novel with ID $id not found.', e); return null; } } // 保存单个小说 Future saveNovel(novel_models.Novel novel) async { //AppLogger.d('LocalStorageService', // 'saveNovel: Attempting to save novel ID=${novel.id}, Title=${novel.title}, Acts=${novel.acts.length}'); // 检查上次保存时间,如果短时间内多次保存同一个小说,可以合并为一次操作 final cacheTime = _novelCacheTimestamp[novel.id]; final now = DateTime.now(); if (cacheTime != null && now.difference(cacheTime).inMilliseconds < 500) { // 如果500毫秒内有多次保存,只更新缓存,延迟实际的存储操作 _novelCache[novel.id] = novel; _novelCacheTimestamp[novel.id] = now; //AppLogger.i('LocalStorageService', // 'saveNovel: Multiple saves detected within 500ms, delaying actual storage operation for novel ID=${novel.id}'); return; } // 更新缓存 _novelCache[novel.id] = novel; _novelCacheTimestamp[novel.id] = now; try { final novels = await getNovels(); final index = novels.indexWhere((n) => n.id == novel.id); if (index >= 0) { AppLogger.d('LocalStorageService', 'saveNovel: Updating existing novel at index $index.'); novels[index] = novel; } else { AppLogger.d('LocalStorageService', 'saveNovel: Adding new novel.'); novels.add(novel); } await saveNovels(novels); AppLogger.i('LocalStorageService', 'saveNovel: Completed saving process for novel ID=${novel.id}.'); } catch (e) { AppLogger.e('LocalStorageService', 'saveNovel: Failed to save novel', e); // 从缓存中移除,以便下次重新加载 _novelCache.remove(novel.id); _novelCacheTimestamp.remove(novel.id); throw Exception('保存小说失败: $e'); } } // 删除小说 Future deleteNovel(String id) async { final novels = await getNovels(); novels.removeWhere((novel) => novel.id == id); await saveNovels(novels); } // 获取当前正在编辑的小说ID Future getCurrentNovelId() async { final prefs = await _ensureInitialized(); return prefs.getString(_currentNovelKey); } // 设置当前正在编辑的小说ID Future setCurrentNovelId(String id) async { final prefs = await _ensureInitialized(); final previousId = prefs.getString(_currentNovelKey); // 如果前一个小说ID存在且与新ID不同,清理前一个小说的同步标记 if (previousId != null && previousId.isNotEmpty && previousId != id) { AppLogger.i('LocalStorageService', '小说ID切换: $previousId -> $id'); // 如果是设置为空ID(特殊情况,如app关闭),不触发清理 if (id.isNotEmpty) { await clearNovelSyncFlags(previousId); } } await prefs.setString(_currentNovelKey, id); AppLogger.i('LocalStorageService', '当前小说ID已设置为: $id'); } // 获取章节内容 Future getChapterContent( String novelId, String chapterId) async { final prefs = await _ensureInitialized(); final key = _getContentKey(novelId, chapterId); final jsonString = prefs.getString(key); if (jsonString == null) { return null; } try { final json = jsonDecode(jsonString); return EditorContent.fromJson(json); } catch (e) { AppLogger.e('LocalStorageService', '解析章节内容失败', e); return null; } } // 保存章节内容 Future saveChapterContent( String novelId, String chapterId, EditorContent content) async { final prefs = await _ensureInitialized(); final key = _getContentKey(novelId, chapterId); final jsonString = jsonEncode(content.toJson()); await prefs.setString(key, jsonString); } // 获取编辑器内容 Future getEditorContent( String novelId, String chapterId, String sceneId) async { return getChapterContent(novelId, chapterId); } // 保存编辑器内容 Future saveEditorContent(EditorContent content) async { final parts = content.id.split('-'); if (parts.length == 3) { final novelId = parts[0]; final chapterId = parts[1]; final sceneId = parts[2]; await saveChapterContent(novelId, chapterId, content); } else if (parts.length == 2) { // 兼容旧格式 final novelId = parts[0]; final chapterId = parts[1]; await saveChapterContent(novelId, chapterId, content); } } // 获取编辑器设置 Future> getEditorSettings() async { try { final prefs = await _ensureInitialized(); final settingsJson = prefs.getString('editor_settings'); if (settingsJson != null) { return jsonDecode(settingsJson) as Map; } // 返回默认设置 return { 'fontSize': 16.0, 'lineHeight': 1.5, 'fontFamily': 'Roboto', 'theme': 'light', 'autoSave': true, }; } catch (e) { AppLogger.e('LocalStorageService', '获取编辑器设置失败', e); // 返回默认设置 return { 'fontSize': 16.0, 'lineHeight': 1.5, 'fontFamily': 'Roboto', 'theme': 'light', 'autoSave': true, }; } } // 保存编辑器设置 Future saveEditorSettings(Map settings) async { try { final prefs = await _ensureInitialized(); await prefs.setString('editor_settings', jsonEncode(settings)); } catch (e) { AppLogger.e('LocalStorageService', '保存编辑器设置失败', e); throw Exception('保存编辑器设置失败: $e'); } } // 生成内容存储键 String _getContentKey(String novelId, String chapterId) { return '$_editorContentPrefix${novelId}_$chapterId'; } /// 获取场景内容 Future getSceneContent( String novelId, String actId, String chapterId, String sceneId) async { try { final novel = await getNovel(novelId); if (novel == null) return null; final act = novel.acts.firstWhere((a) => a.id == actId); final chapter = act.chapters.firstWhere((c) => c.id == chapterId); if (chapter.scenes.isEmpty) return null; // 查找特定场景 try { return chapter.scenes.firstWhere((s) => s.id == sceneId); } catch (e) { // 如果找不到特定场景,返回第一个场景 return chapter.scenes.first; } } catch (e) { return null; } } /// 保存场景内容 Future saveSceneContent(String novelId, String actId, String chapterId, String sceneId, novel_models.Scene scene) async { try { // 生成场景缓存键 final sceneKey = '${novelId}_${actId}_${chapterId}_$sceneId'; // 如果缓存中有小说,则直接更新缓存中的场景内容 if (_novelCache.containsKey(novelId)) { final novel = _novelCache[novelId]!; bool sceneUpdated = false; // 查找并更新缓存中的场景 final updatedActs = novel.acts.map((act) { if (act.id == actId) { final updatedChapters = act.chapters.map((chapter) { if (chapter.id == chapterId) { final sceneIndex = chapter.scenes.indexWhere((s) => s.id == sceneId); if (sceneIndex >= 0) { // 更新现有场景 final updatedScenes = List.from(chapter.scenes); updatedScenes[sceneIndex] = scene; sceneUpdated = true; return chapter.copyWith(scenes: updatedScenes); } else { // 添加新场景 sceneUpdated = true; return chapter.copyWith( scenes: [...chapter.scenes, scene], ); } } return chapter; }).toList(); if (sceneUpdated) { return act.copyWith(chapters: updatedChapters); } } return act; }).toList(); if (sceneUpdated) { // 更新缓存中的小说 final updatedNovel = novel.copyWith( acts: updatedActs, updatedAt: DateTime.now(), ); _novelCache[novelId] = updatedNovel; _novelCacheTimestamp[novelId] = DateTime.now(); // 更新字数缓存 _updateWordCountCache(sceneKey, scene.content, scene.wordCount); AppLogger.i('LocalStorageService', 'saveSceneContent: Updated scene in cached novel: $sceneKey'); } } // 正常保存场景到存储 final novel = await getNovel(novelId); if (novel == null) return; final acts = novel.acts.map((act) { if (act.id == actId) { final chapters = act.chapters.map((chapter) { if (chapter.id == chapterId) { // 查找特定场景 final sceneIndex = chapter.scenes.indexWhere((s) => s.id == sceneId); List updatedScenes; if (sceneIndex >= 0) { // 更新现有场景 updatedScenes = List.from(chapter.scenes); updatedScenes[sceneIndex] = scene; } else { // 添加新场景 updatedScenes = List.from(chapter.scenes)..add(scene); } return chapter.copyWith(scenes: updatedScenes); } return chapter; }).toList(); return act.copyWith(chapters: chapters); } return act; }).toList(); final updatedNovel = novel.copyWith( acts: acts, updatedAt: DateTime.now(), ); await saveNovel(updatedNovel); // 更新字数缓存 _updateWordCountCache(sceneKey, scene.content, scene.wordCount); } catch (e) { AppLogger.e('LocalStorageService', '保存场景内容失败', e); } } /// 保存摘要内容 Future saveSummary(String novelId, String actId, String chapterId, String sceneId, novel_models.Summary summary) async { try { final novel = await getNovel(novelId); if (novel == null) return; final acts = novel.acts.map((act) { if (act.id == actId) { final chapters = act.chapters.map((chapter) { if (chapter.id == chapterId) { // 查找特定场景 final sceneIndex = chapter.scenes.indexWhere((s) => s.id == sceneId); List updatedScenes; if (sceneIndex >= 0) { // 更新现有场景 updatedScenes = List.from(chapter.scenes); updatedScenes[sceneIndex] = updatedScenes[sceneIndex].copyWith(summary: summary); } else { // 如果场景不存在,不做任何操作 updatedScenes = chapter.scenes; } return chapter.copyWith(scenes: updatedScenes); } return chapter; }).toList(); return act.copyWith(chapters: chapters); } return act; }).toList(); final updatedNovel = novel.copyWith( acts: acts, updatedAt: DateTime.now(), ); await saveNovel(updatedNovel); } catch (e) { AppLogger.e('LocalStorageService', '保存摘要内容失败', e); } } // 标记需要同步的内容(按类型) Future markForSyncByType(String id, String type) async { try { final prefs = await _ensureInitialized(); final syncKey = 'syncList_$type'; final syncList = prefs.getStringList(syncKey) ?? []; if (!syncList.contains(id)) { syncList.add(id); await prefs.setStringList(syncKey, syncList); AppLogger.i('LocalStorageService', '已标记 $type: $id 需要同步'); } } catch (e) { AppLogger.e('LocalStorageService', '标记同步失败', e); } } // 获取需要同步的内容列表(按类型) Future> getSyncList(String type) async { try { final prefs = await _ensureInitialized(); final syncKey = 'syncList_$type'; return prefs.getStringList(syncKey) ?? []; } catch (e) { AppLogger.e('LocalStorageService', '获取同步列表失败', e); return []; } } // 清除同步标记(按类型和ID) Future clearSyncFlagByType(String type, String id) async { try { final prefs = await _ensureInitialized(); final syncKey = 'syncList_$type'; final syncList = prefs.getStringList(syncKey) ?? []; if (syncList.contains(id)) { syncList.remove(id); await prefs.setStringList(syncKey, syncList); AppLogger.i('LocalStorageService', '已清除 $type: $id 的同步标记'); } } catch (e) { AppLogger.e('LocalStorageService', '清除同步标记失败', e); } } // 保存聊天会话列表 Future saveChatSessions( String novelId, List sessions) async { final key = 'chat_sessions_$novelId'; final jsonList = sessions.map((session) => jsonEncode(session.toJson())).toList(); final prefs = await _ensureInitialized(); await prefs.setStringList(key, jsonList); } // 获取聊天会话列表 Future> getChatSessions(String novelId) async { final key = 'chat_sessions_$novelId'; final prefs = await _ensureInitialized(); final jsonList = prefs.getStringList(key) ?? []; return jsonList .map((json) => ChatSession.fromJson(jsonDecode(json))) .toList(); } // 添加聊天会话 Future addChatSession(String novelId, ChatSession session, {bool needsSync = false}) async { final sessions = await getChatSessions(novelId); sessions.add(session); await saveChatSessions(novelId, sessions); await updateChatSession(session, needsSync: needsSync); } // 获取特定会话 Future getChatSession(String sessionId) async { final key = 'chat_session_detail_$sessionId'; final prefs = await _ensureInitialized(); final json = prefs.getString(key); if (json == null) { return null; } return ChatSession.fromJson(jsonDecode(json)); } // 更新会话 - 同时处理标记同步 Future updateChatSession(ChatSession session, {bool needsSync = false}) async { final key = 'chat_session_detail_${session.id}'; final prefs = await _ensureInitialized(); await prefs.setString(key, jsonEncode(session.toJson())); if (needsSync) { await markForSyncByType(session.id, 'chat_session'); } } // 删除会话 Future deleteChatSession(String sessionId) async { final key = 'chat_session_detail_$sessionId'; final prefs = await _ensureInitialized(); await prefs.remove(key); await clearSyncFlagByType('chat_session', sessionId); } // 获取需要同步的所有会话 Future> getSessionsToSync() async { final syncList = await getSyncList('chat_session'); final sessions = []; for (final sessionId in syncList) { final session = await getChatSession(sessionId); if (session != null) { sessions.add(session); } else { AppLogger.w('LocalStorageService', 'getSessionsToSync: 未找到标记为同步的会话详情: $sessionId。考虑清除此标记。'); } } return sessions; } // 清除所有数据 Future clearAll() async { final prefs = await _ensureInitialized(); await prefs.clear(); } /// 获取会话的消息列表(用于显示历史记录) Future?> getMessagesForSession(String sessionId) async { final prefs = await _ensureInitialized(); final key = 'chat_messages_$sessionId'; // Key for storing full history final jsonList = prefs.getStringList(key); if (jsonList == null) return null; try { // Sort messages by timestamp after parsing final messages = jsonList .map((json) => ChatMessage.fromJson(jsonDecode(json))) .toList(); messages.sort((a, b) => a.timestamp.compareTo(b.timestamp)); return messages; } catch (e, stackTrace) { AppLogger.e( 'LocalStorageService', '解析会话 $sessionId 的消息失败', e, stackTrace); return null; } } /// 保存会话的消息列表(用于缓存历史记录) Future saveMessagesForSession( String sessionId, List messages) async { final prefs = await _ensureInitialized(); final key = 'chat_messages_$sessionId'; // Key for storing full history // Sort messages by timestamp before saving messages.sort((a, b) => a.timestamp.compareTo(b.timestamp)); final jsonList = messages.map((msg) => jsonEncode(msg.toJson())).toList(); await prefs.setStringList(key, jsonList); } /// 添加单条消息到会话历史(例如,收到新消息或发送成功后) Future addMessageToSessionHistory( String sessionId, ChatMessage message) async { final messages = await getMessagesForSession(sessionId) ?? []; // Avoid duplicates if message already exists if (!messages.any((m) => m.id == message.id)) { messages.add(message); await saveMessagesForSession(sessionId, messages); } } /// 添加待发送消息到队列 Future addPendingMessage({ required String userId, required String sessionId, required String content, required Map? metadata, }) async { final prefs = await _ensureInitialized(); final pendingList = prefs.getStringList(_pendingMessagesKey) ?? []; final localId = _uuid.v4(); // Generate unique local ID final pendingMessageData = { 'localId': localId, // Unique ID for removal later 'userId': userId, 'sessionId': sessionId, 'content': content, 'metadata': metadata, 'timestamp': DateTime.now().toIso8601String(), // Store time added to queue }; pendingList.add(jsonEncode(pendingMessageData)); await prefs.setStringList(_pendingMessagesKey, pendingList); AppLogger.i('LocalStorageService', '添加待发送消息到队列: sessionId=$sessionId, localId=$localId'); return localId; // Return localId in case UI needs it } /// 获取所有待发送消息 Future>> getPendingMessages() async { final prefs = await _ensureInitialized(); final jsonList = prefs.getStringList(_pendingMessagesKey) ?? []; try { return jsonList .map((json) => jsonDecode(json) as Map) .toList(); } catch (e, stackTrace) { AppLogger.e('LocalStorageService', '解析待发送消息队列失败', e, stackTrace); // Optionally clear the corrupted queue // await prefs.remove(_pendingMessagesKey); return []; } } /// 从队列中移除已发送的消息 (通过 localId) Future removePendingMessage(String localId) async { final prefs = await _ensureInitialized(); final pendingList = prefs.getStringList(_pendingMessagesKey) ?? []; final updatedList = []; bool removed = false; for (final jsonString in pendingList) { try { final data = jsonDecode(jsonString) as Map; if (data['localId'] != localId) { updatedList.add(jsonString); } else { removed = true; } } catch (e) { // Skip corrupted entry AppLogger.w('LocalStorageService', '移除待发送消息时跳过损坏条目: $e'); } } if (removed) { await prefs.setStringList(_pendingMessagesKey, updatedList); AppLogger.i('LocalStorageService', '从队列移除待发送消息: localId=$localId'); } else { AppLogger.w('LocalStorageService', '尝试移除待发送消息,但未找到: localId=$localId'); } } // 清理所有同步标记 Future clearAllSyncFlags() async { final prefs = await _ensureInitialized(); final syncTypes = ['novel', 'scene', 'editor', 'chat_session']; for (final type in syncTypes) { final syncKey = 'syncList_$type'; await prefs.remove(syncKey); } AppLogger.i('LocalStorageService', '已清理所有同步标记'); } // 清理指定小说的同步标记 Future clearNovelSyncFlags(String novelId) async { if (novelId.isEmpty) return; final prefs = await _ensureInitialized(); // 清理小说本身的同步标记 const novelSyncKey = 'syncList_novel'; final novelSyncList = prefs.getStringList(novelSyncKey) ?? []; if (novelSyncList.contains(novelId)) { novelSyncList.remove(novelId); await prefs.setStringList(novelSyncKey, novelSyncList); AppLogger.i('LocalStorageService', '已清理小说同步标记: $novelId'); } // 清理场景同步标记 const sceneSyncKey = 'syncList_scene'; final sceneSyncList = prefs.getStringList(sceneSyncKey) ?? []; final updatedSceneSyncList = sceneSyncList.where((sceneKey) { final parts = sceneKey.split('_'); return parts.isEmpty || parts[0] != novelId; }).toList(); if (updatedSceneSyncList.length != sceneSyncList.length) { await prefs.setStringList(sceneSyncKey, updatedSceneSyncList); AppLogger.i('LocalStorageService', '已清理场景同步标记: ${sceneSyncList.length - updatedSceneSyncList.length} 个场景,小说ID: $novelId'); } // 清理编辑器内容同步标记 const editorSyncKey = 'syncList_editor'; final editorSyncList = prefs.getStringList(editorSyncKey) ?? []; final updatedEditorSyncList = editorSyncList.where((contentKey) { final parts = contentKey.split('_'); return parts.isEmpty || parts[0] != novelId; }).toList(); if (updatedEditorSyncList.length != editorSyncList.length) { await prefs.setStringList(editorSyncKey, updatedEditorSyncList); AppLogger.i('LocalStorageService', '已清理编辑器内容同步标记: ${editorSyncList.length - updatedEditorSyncList.length} 个内容,小说ID: $novelId'); } // 清理聊天会话同步标记 // 注意:这需要先获取所有会话,然后检查它们的metadata中的novelId final sessions = await getSessionsToSync(); final sessionsToRemove = sessions.where((session) => session.metadata != null && session.metadata!['novelId'] == novelId).toList(); for (final session in sessionsToRemove) { await clearSyncFlagByType('chat_session', session.id); AppLogger.i('LocalStorageService', '已清理聊天会话同步标记: ${session.id},小说ID: $novelId'); } } /// 获取指定章节的所有场景键 Future> getSceneKeysForChapter( String novelId, String actId, String chapterId, ) async { try { final box = await Hive.openBox('scenes'); final prefix = '${novelId}_${actId}_${chapterId}_'; // 过滤出所有属于该章节的场景键 final List sceneKeys = []; for (final key in box.keys) { if (key is String && key.startsWith(prefix)) { // 从键中提取场景ID final sceneId = key.substring(prefix.length); sceneKeys.add(sceneId); } } return sceneKeys; } catch (e) { AppLogger.e('LocalStorageService', '获取章节场景键失败', e); return []; } } /// 删除场景内容 Future deleteSceneContent( String novelId, String actId, String chapterId, String sceneId, ) async { final sceneKey = '${novelId}_${actId}_${chapterId}_$sceneId'; try { // 使用SharedPreferences删除场景内容 final prefs = await _ensureInitialized(); await prefs.remove('scene_$sceneKey'); // 从场景索引中移除 final indexKey = 'scenes_index_${novelId}_${actId}_$chapterId'; final sceneIds = prefs.getStringList(indexKey) ?? []; if (sceneIds.contains(sceneId)) { sceneIds.remove(sceneId); await prefs.setStringList(indexKey, sceneIds); } AppLogger.i('LocalStorageService', '本地场景内容已删除: $sceneKey'); } catch (e) { AppLogger.e('LocalStorageService', '删除场景内容失败: $sceneKey', e); throw Exception('删除场景内容失败: $e'); } } // 优化的字数统计缓存 void _updateWordCountCache(String sceneKey, String content, int wordCount) { final contentHash = content.hashCode.toString(); final cacheKey = '${sceneKey}_$contentHash'; _wordCountCache[cacheKey] = wordCount.toString(); } // 从缓存获取字数统计 int? getWordCountFromCache(String sceneKey, String content) { final contentHash = content.hashCode.toString(); final cacheKey = '${sceneKey}_$contentHash'; final cachedCount = _wordCountCache[cacheKey]; if (cachedCount != null) { return int.tryParse(cachedCount); } return null; } // 清除指定小说的缓存 Future clearNovelCache(String novelId) async { AppLogger.i('LocalStorageService', '清除小说缓存: $novelId'); _novelCache.remove(novelId); _novelCacheTimestamp.remove(novelId); } // 清除所有小说缓存 Future clearAllNovelCache() async { AppLogger.i('LocalStorageService', '清除所有小说缓存'); _novelCache.clear(); _novelCacheTimestamp.clear(); } }