From 6a336bbd8dfc03aa2d061ca4cf0f2750ea925638 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sun, 22 Mar 2026 16:33:05 +0100
Subject: [PATCH] fix: smart catch_up merge - dedup by content, preserve user messages
---
lib/screens/chat_screen.dart | 24 ++++++++++++++++++++----
1 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart
index 1982f27..5f3e38c 100644
--- a/lib/screens/chat_screen.dart
+++ b/lib/screens/chat_screen.dart
@@ -207,15 +207,31 @@
final sessionId = msg['sessionId'] as String?;
if (sessionId != null) _incrementUnread(sessionId);
case 'catch_up':
- // Only update lastSeq — don't replay messages.
- // Local storage already has our messages. Replaying causes duplicates
- // and overwrites user messages. New messages arriving while offline
- // are stored via _storeForSession from the DIRECT broadcast path.
final serverSeq = msg['serverSeq'] as int?;
if (serverSeq != null && serverSeq > _lastSeq) {
_lastSeq = serverSeq;
_saveLastSeq();
}
+ // Merge catch_up messages: only add messages not already in local storage.
+ // We check by content match against existing messages to avoid duplicates
+ // while still picking up messages that arrived while the app was backgrounded.
+ final catchUpMsgs = msg['messages'] as List<dynamic>?;
+ if (catchUpMsgs != null && catchUpMsgs.isNotEmpty) {
+ _isCatchingUp = true;
+ final existing = ref.read(messagesProvider);
+ final existingContents = existing
+ .where((m) => m.role == MessageRole.assistant)
+ .map((m) => m.content)
+ .toSet();
+ for (final m in catchUpMsgs) {
+ final content = (m as Map<String, dynamic>)['content'] as String? ?? '';
+ // Skip if we already have this message locally
+ if (content.isNotEmpty && existingContents.contains(content)) continue;
+ _handleMessage(m);
+ if (content.isNotEmpty) existingContents.add(content);
+ }
+ _isCatchingUp = false;
+ }
case 'pong':
break; // heartbeat response, ignore
case 'delete_message':
--
Gitblit v1.3.1