From 2a61f41741f81042e0272d06ba15ce5590e1227d Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Mon, 23 Mar 2026 07:22:58 +0100
Subject: [PATCH] fix: screenshot chat leak, transcript disk update, cross-session image routing

---
 lib/screens/chat_screen.dart |   64 ++++++++++++++++++++++++++++++--
 1 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart
index 68842d8..23ce43d 100644
--- a/lib/screens/chat_screen.dart
+++ b/lib/screens/chat_screen.dart
@@ -214,7 +214,16 @@
         final messageId = msg['messageId'] as String?;
         final content = msg['content'] as String?;
         if (messageId != null && content != null) {
-          ref.read(messagesProvider.notifier).updateContent(messageId, content);
+          // Try updating in current session first
+          final currentMessages = ref.read(messagesProvider);
+          final inCurrent = currentMessages.any((m) => m.id == messageId);
+          if (inCurrent) {
+            ref.read(messagesProvider.notifier).updateContent(messageId, content);
+          } else {
+            // Message is in a different session (user switched after recording).
+            // Load that session's messages from disk, update, and save back.
+            _updateTranscriptOnDisk(messageId, content);
+          }
         }
       case 'unread':
         final sessionId = msg['sessionId'] as String?;
@@ -391,13 +400,16 @@
   void _handleIncomingImage(Map<String, dynamic> msg) {
     final imageData = msg['imageBase64'] as String? ?? msg['data'] as String? ?? msg['image'] as String?;
     final content = msg['content'] as String? ?? msg['caption'] as String? ?? '';
+    final sessionId = msg['sessionId'] as String?;
 
     if (imageData == null) return;
 
-    // Always update the Navigate screen screenshot
+    // Always update the Navigate screen screenshot provider
     ref.read(latestScreenshotProvider.notifier).state = imageData;
 
-    final isScreenshot = content == 'Screenshot' || content == 'Capturing screenshot...';
+    final isScreenshot = content == 'Screenshot' ||
+        content == 'Capturing screenshot...' ||
+        (msg['type'] == 'screenshot');
 
     if (isScreenshot) {
       // Remove any "Capturing screenshot..." placeholder text messages
@@ -405,7 +417,7 @@
         (m) => m.role == MessageRole.assistant && m.content == 'Capturing screenshot...',
       );
 
-      // Only add to chat if the Screen button requested it
+      // Only add to chat if the Screen button explicitly requested it
       if (!_screenshotForChat) {
         ref.read(isTypingProvider.notifier).state = false;
         return;
@@ -419,6 +431,14 @@
       content: content,
       status: MessageStatus.sent,
     );
+
+    // Cross-session routing: store for target session if not active
+    final activeId = ref.read(activeSessionIdProvider);
+    if (sessionId != null && sessionId != activeId) {
+      _storeForSession(sessionId, message);
+      _incrementUnread(sessionId);
+      return;
+    }
 
     ref.read(messagesProvider.notifier).addMessage(message);
     ref.read(isTypingProvider.notifier).state = false;
@@ -436,6 +456,42 @@
     _chatLog('storeForSession: verified ${verify.length} messages after save');
   }
 
+  /// Update a transcript for a message stored on disk (not in the active session).
+  /// Scans all session files to find the message by ID, updates content, and saves.
+  Future<void> _updateTranscriptOnDisk(String messageId, String content) async {
+    try {
+      final dir = await getApplicationDocumentsDirectory();
+      final msgDir = Directory('${dir.path}/messages');
+      if (!await msgDir.exists()) return;
+
+      await for (final entity in msgDir.list()) {
+        if (entity is! File || !entity.path.endsWith('.json')) continue;
+
+        final jsonStr = await entity.readAsString();
+        final List<dynamic> jsonList = jsonDecode(jsonStr) as List<dynamic>;
+        bool found = false;
+
+        final updated = jsonList.map((j) {
+          final map = j as Map<String, dynamic>;
+          if (map['id'] == messageId) {
+            found = true;
+            return {...map, 'content': content};
+          }
+          return map;
+        }).toList();
+
+        if (found) {
+          await entity.writeAsString(jsonEncode(updated));
+          _chatLog('transcript: updated messageId=$messageId on disk in ${entity.path.split('/').last}');
+          return;
+        }
+      }
+      _chatLog('transcript: messageId=$messageId not found on disk');
+    } catch (e) {
+      _chatLog('transcript: disk update error=$e');
+    }
+  }
+
   void _incrementUnread(String sessionId) {
     final counts = Map<String, int>.from(ref.read(unreadCountsProvider));
     counts[sessionId] = (counts[sessionId] ?? 0) + 1;

--
Gitblit v1.3.1