From bf98bbd1fc24be11ea67cb56e087efbe270bcd97 Mon Sep 17 00:00:00 2001 From: cogwheel0 <172976095+cogwheel0@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:53:55 +0530 Subject: [PATCH] feat(conversations): Implement local cache persistence for conversations --- lib/core/providers/app_providers.dart | 92 +++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/lib/core/providers/app_providers.dart b/lib/core/providers/app_providers.dart index 0e9a30d..ca03ecb 100644 --- a/lib/core/providers/app_providers.dart +++ b/lib/core/providers/app_providers.dart @@ -793,6 +793,7 @@ class Conversations extends _$Conversations { if (!authed) { DebugLogger.log('skip-unauthed', scope: 'conversations'); _updateCacheTimestamp(null); + _persistConversationsAsync(const []); return const []; } @@ -800,7 +801,43 @@ class Conversations extends _$Conversations { return _demoConversations(); } - return _loadRemoteConversations(); + final storage = ref.read(optimizedStorageServiceProvider); + try { + final cached = await storage.getLocalConversations(); + if (cached.isNotEmpty) { + final sortedCached = _sortByUpdatedAt(cached); + Future.microtask(() async { + try { + await refresh(includeFolders: true); + } catch (error, stackTrace) { + DebugLogger.error( + 'warm-refresh-failed', + scope: 'conversations/cache', + error: error, + stackTrace: stackTrace, + ); + } + }); + DebugLogger.log( + 'cache-restored', + scope: 'conversations/cache', + data: {'count': sortedCached.length}, + ); + return sortedCached; + } + DebugLogger.log('cache-empty', scope: 'conversations/cache'); + } catch (error, stackTrace) { + DebugLogger.error( + 'cache-load-failed', + scope: 'conversations/cache', + error: error, + stackTrace: stackTrace, + ); + } + + final fresh = await _loadRemoteConversations(); + _persistConversationsAsync(fresh); + return fresh; } Future refresh({bool includeFolders = false}) async { @@ -808,6 +845,7 @@ class Conversations extends _$Conversations { if (!authed) { _updateCacheTimestamp(null); state = AsyncData>([]); + _persistConversationsAsync(const []); if (includeFolders) { unawaited(ref.read(foldersProvider.notifier).refresh()); } @@ -824,7 +862,22 @@ class Conversations extends _$Conversations { final result = await AsyncValue.guard(_loadRemoteConversations); if (!ref.mounted) return; - state = result; + result.when( + data: (conversations) { + state = AsyncData>(conversations); + _persistConversationsAsync(conversations); + }, + error: (error, stackTrace) { + DebugLogger.error( + 'refresh-failed', + scope: 'conversations', + error: error, + stackTrace: stackTrace, + data: {'preservedData': state.asData != null}, + ); + }, + loading: () {}, + ); if (includeFolders) { unawaited(ref.read(foldersProvider.notifier).refresh()); } @@ -836,7 +889,7 @@ class Conversations extends _$Conversations { final updated = current .where((conversation) => conversation.id != id) .toList(growable: true); - state = AsyncData>(_sortByUpdatedAt(updated)); + _replaceState(updated); } void upsertConversation(Conversation conversation) { @@ -850,7 +903,7 @@ class Conversations extends _$Conversations { } else { updated.add(conversation); } - state = AsyncData>(_sortByUpdatedAt(updated)); + _replaceState(updated); } void updateConversation( @@ -863,7 +916,36 @@ class Conversations extends _$Conversations { if (index < 0) return; final updated = [...current]; updated[index] = transform(updated[index]); - state = AsyncData>(_sortByUpdatedAt(updated)); + _replaceState(updated); + } + + void _replaceState(List conversations) { + final sorted = _sortByUpdatedAt(conversations); + state = AsyncData>(sorted); + _persistConversationsAsync(sorted); + } + + void _persistConversationsAsync(List conversations) { + final storage = ref.read(optimizedStorageServiceProvider); + unawaited( + Future(() async { + try { + await storage.saveLocalConversations(conversations); + DebugLogger.log( + 'cache-saved', + scope: 'conversations/cache', + data: {'count': conversations.length}, + ); + } catch (error, stackTrace) { + DebugLogger.error( + 'cache-save-failed', + scope: 'conversations/cache', + error: error, + stackTrace: stackTrace, + ); + } + }), + ); } List _demoConversations() => [