feat(conversations): Implement local cache persistence for conversations

This commit is contained in:
cogwheel0
2025-11-05 14:53:55 +05:30
parent c40e692388
commit bf98bbd1fc

View File

@@ -793,6 +793,7 @@ class Conversations extends _$Conversations {
if (!authed) { if (!authed) {
DebugLogger.log('skip-unauthed', scope: 'conversations'); DebugLogger.log('skip-unauthed', scope: 'conversations');
_updateCacheTimestamp(null); _updateCacheTimestamp(null);
_persistConversationsAsync(const <Conversation>[]);
return const []; return const [];
} }
@@ -800,7 +801,43 @@ class Conversations extends _$Conversations {
return _demoConversations(); 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<void> refresh({bool includeFolders = false}) async { Future<void> refresh({bool includeFolders = false}) async {
@@ -808,6 +845,7 @@ class Conversations extends _$Conversations {
if (!authed) { if (!authed) {
_updateCacheTimestamp(null); _updateCacheTimestamp(null);
state = AsyncData<List<Conversation>>(<Conversation>[]); state = AsyncData<List<Conversation>>(<Conversation>[]);
_persistConversationsAsync(const <Conversation>[]);
if (includeFolders) { if (includeFolders) {
unawaited(ref.read(foldersProvider.notifier).refresh()); unawaited(ref.read(foldersProvider.notifier).refresh());
} }
@@ -824,7 +862,22 @@ class Conversations extends _$Conversations {
final result = await AsyncValue.guard(_loadRemoteConversations); final result = await AsyncValue.guard(_loadRemoteConversations);
if (!ref.mounted) return; if (!ref.mounted) return;
state = result; result.when(
data: (conversations) {
state = AsyncData<List<Conversation>>(conversations);
_persistConversationsAsync(conversations);
},
error: (error, stackTrace) {
DebugLogger.error(
'refresh-failed',
scope: 'conversations',
error: error,
stackTrace: stackTrace,
data: {'preservedData': state.asData != null},
);
},
loading: () {},
);
if (includeFolders) { if (includeFolders) {
unawaited(ref.read(foldersProvider.notifier).refresh()); unawaited(ref.read(foldersProvider.notifier).refresh());
} }
@@ -836,7 +889,7 @@ class Conversations extends _$Conversations {
final updated = current final updated = current
.where((conversation) => conversation.id != id) .where((conversation) => conversation.id != id)
.toList(growable: true); .toList(growable: true);
state = AsyncData<List<Conversation>>(_sortByUpdatedAt(updated)); _replaceState(updated);
} }
void upsertConversation(Conversation conversation) { void upsertConversation(Conversation conversation) {
@@ -850,7 +903,7 @@ class Conversations extends _$Conversations {
} else { } else {
updated.add(conversation); updated.add(conversation);
} }
state = AsyncData<List<Conversation>>(_sortByUpdatedAt(updated)); _replaceState(updated);
} }
void updateConversation( void updateConversation(
@@ -863,7 +916,36 @@ class Conversations extends _$Conversations {
if (index < 0) return; if (index < 0) return;
final updated = <Conversation>[...current]; final updated = <Conversation>[...current];
updated[index] = transform(updated[index]); updated[index] = transform(updated[index]);
state = AsyncData<List<Conversation>>(_sortByUpdatedAt(updated)); _replaceState(updated);
}
void _replaceState(List<Conversation> conversations) {
final sorted = _sortByUpdatedAt(conversations);
state = AsyncData<List<Conversation>>(sorted);
_persistConversationsAsync(sorted);
}
void _persistConversationsAsync(List<Conversation> conversations) {
final storage = ref.read(optimizedStorageServiceProvider);
unawaited(
Future<void>(() 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<Conversation> _demoConversations() => [ List<Conversation> _demoConversations() => [