Matthias Nott
2026-03-23 2a61f41741f81042e0272d06ba15ce5590e1227d
fix: screenshot chat leak, transcript disk update, cross-session image routing
1 files modified
changed files
lib/screens/chat_screen.dart patch | view | blame | history
lib/screens/chat_screen.dart
....@@ -214,7 +214,16 @@
214214 final messageId = msg['messageId'] as String?;
215215 final content = msg['content'] as String?;
216216 if (messageId != null && content != null) {
217
- ref.read(messagesProvider.notifier).updateContent(messageId, content);
217
+ // Try updating in current session first
218
+ final currentMessages = ref.read(messagesProvider);
219
+ final inCurrent = currentMessages.any((m) => m.id == messageId);
220
+ if (inCurrent) {
221
+ ref.read(messagesProvider.notifier).updateContent(messageId, content);
222
+ } else {
223
+ // Message is in a different session (user switched after recording).
224
+ // Load that session's messages from disk, update, and save back.
225
+ _updateTranscriptOnDisk(messageId, content);
226
+ }
218227 }
219228 case 'unread':
220229 final sessionId = msg['sessionId'] as String?;
....@@ -391,13 +400,16 @@
391400 void _handleIncomingImage(Map<String, dynamic> msg) {
392401 final imageData = msg['imageBase64'] as String? ?? msg['data'] as String? ?? msg['image'] as String?;
393402 final content = msg['content'] as String? ?? msg['caption'] as String? ?? '';
403
+ final sessionId = msg['sessionId'] as String?;
394404
395405 if (imageData == null) return;
396406
397
- // Always update the Navigate screen screenshot
407
+ // Always update the Navigate screen screenshot provider
398408 ref.read(latestScreenshotProvider.notifier).state = imageData;
399409
400
- final isScreenshot = content == 'Screenshot' || content == 'Capturing screenshot...';
410
+ final isScreenshot = content == 'Screenshot' ||
411
+ content == 'Capturing screenshot...' ||
412
+ (msg['type'] == 'screenshot');
401413
402414 if (isScreenshot) {
403415 // Remove any "Capturing screenshot..." placeholder text messages
....@@ -405,7 +417,7 @@
405417 (m) => m.role == MessageRole.assistant && m.content == 'Capturing screenshot...',
406418 );
407419
408
- // Only add to chat if the Screen button requested it
420
+ // Only add to chat if the Screen button explicitly requested it
409421 if (!_screenshotForChat) {
410422 ref.read(isTypingProvider.notifier).state = false;
411423 return;
....@@ -419,6 +431,14 @@
419431 content: content,
420432 status: MessageStatus.sent,
421433 );
434
+
435
+ // Cross-session routing: store for target session if not active
436
+ final activeId = ref.read(activeSessionIdProvider);
437
+ if (sessionId != null && sessionId != activeId) {
438
+ _storeForSession(sessionId, message);
439
+ _incrementUnread(sessionId);
440
+ return;
441
+ }
422442
423443 ref.read(messagesProvider.notifier).addMessage(message);
424444 ref.read(isTypingProvider.notifier).state = false;
....@@ -436,6 +456,42 @@
436456 _chatLog('storeForSession: verified ${verify.length} messages after save');
437457 }
438458
459
+ /// Update a transcript for a message stored on disk (not in the active session).
460
+ /// Scans all session files to find the message by ID, updates content, and saves.
461
+ Future<void> _updateTranscriptOnDisk(String messageId, String content) async {
462
+ try {
463
+ final dir = await getApplicationDocumentsDirectory();
464
+ final msgDir = Directory('${dir.path}/messages');
465
+ if (!await msgDir.exists()) return;
466
+
467
+ await for (final entity in msgDir.list()) {
468
+ if (entity is! File || !entity.path.endsWith('.json')) continue;
469
+
470
+ final jsonStr = await entity.readAsString();
471
+ final List<dynamic> jsonList = jsonDecode(jsonStr) as List<dynamic>;
472
+ bool found = false;
473
+
474
+ final updated = jsonList.map((j) {
475
+ final map = j as Map<String, dynamic>;
476
+ if (map['id'] == messageId) {
477
+ found = true;
478
+ return {...map, 'content': content};
479
+ }
480
+ return map;
481
+ }).toList();
482
+
483
+ if (found) {
484
+ await entity.writeAsString(jsonEncode(updated));
485
+ _chatLog('transcript: updated messageId=$messageId on disk in ${entity.path.split('/').last}');
486
+ return;
487
+ }
488
+ }
489
+ _chatLog('transcript: messageId=$messageId not found on disk');
490
+ } catch (e) {
491
+ _chatLog('transcript: disk update error=$e');
492
+ }
493
+ }
494
+
439495 void _incrementUnread(String sessionId) {
440496 final counts = Map<String, int>.from(ref.read(unreadCountsProvider));
441497 counts[sessionId] = (counts[sessionId] ?? 0) + 1;