Matthias Nott
2026-03-22 c9ced26fb059d32d5bd10c37b18ebe97a2f3018a
fix: save voice audio to file for cross-session persistence
1 files modified
changed files
lib/screens/chat_screen.dart patch | view | blame | history
lib/screens/chat_screen.dart
....@@ -1,6 +1,8 @@
11 import 'dart:convert';
22 import 'dart:io';
33
4
+import 'package:path_provider/path_provider.dart';
5
+
46 import 'package:flutter/material.dart';
57 import 'package:flutter_riverpod/flutter_riverpod.dart';
68 import 'package:go_router/go_router.dart';
....@@ -302,7 +304,7 @@
302304 }
303305 }
304306
305
- void _handleIncomingVoice(Map<String, dynamic> msg) {
307
+ Future<void> _handleIncomingVoice(Map<String, dynamic> msg) async {
306308 final sessionId = msg['sessionId'] as String?;
307309 final audioData = msg['audioBase64'] as String? ?? msg['audio'] as String? ?? msg['data'] as String?;
308310 final content = msg['content'] as String? ?? msg['text'] as String? ?? '';
....@@ -319,9 +321,33 @@
319321 duration: duration,
320322 );
321323
324
+ // Save audio to file so it survives persistence (base64 gets stripped)
325
+ String? savedAudioPath;
326
+ if (audioData != null) {
327
+ try {
328
+ final dir = await getTemporaryDirectory();
329
+ savedAudioPath = '${dir.path}/voice_${message.id}.m4a';
330
+ final bytes = base64Decode(audioData.contains(',') ? audioData.split(',').last : audioData);
331
+ await File(savedAudioPath).writeAsBytes(bytes);
332
+ } catch (_) {
333
+ savedAudioPath = null;
334
+ }
335
+ }
336
+
337
+ final storedMessage = Message(
338
+ id: message.id,
339
+ role: message.role,
340
+ type: message.type,
341
+ content: content,
342
+ audioUri: savedAudioPath ?? audioData,
343
+ timestamp: message.timestamp,
344
+ status: message.status,
345
+ duration: duration,
346
+ );
347
+
322348 final activeId = ref.read(activeSessionIdProvider);
323349 if (sessionId != null && sessionId != activeId) {
324
- _storeForSession(sessionId, message);
350
+ _storeForSession(sessionId, storedMessage);
325351 _incrementUnread(sessionId);
326352 final sessions = ref.read(sessionsProvider);
327353 final session = sessions.firstWhere(
....@@ -339,12 +365,11 @@
339365 return;
340366 }
341367
342
- ref.read(messagesProvider.notifier).addMessage(message);
368
+ ref.read(messagesProvider.notifier).addMessage(storedMessage);
343369 ref.read(isTypingProvider.notifier).state = false;
344370 _scrollToBottom();
345371
346372 if (audioData != null && !AudioService.isBackgrounded && !_isCatchingUp && !_isRecording) {
347
- // Queue incoming voice chunks — don't play while recording
348373 AudioService.queueBase64(audioData);
349374 }
350375 }