From c9ced26fb059d32d5bd10c37b18ebe97a2f3018a Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sun, 22 Mar 2026 19:54:44 +0100
Subject: [PATCH] fix: save voice audio to file for cross-session persistence
---
lib/screens/chat_screen.dart | 33 +++++++++++++++++++++++++++++----
1 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart
index 16069ba..7741463 100644
--- a/lib/screens/chat_screen.dart
+++ b/lib/screens/chat_screen.dart
@@ -1,6 +1,8 @@
import 'dart:convert';
import 'dart:io';
+import 'package:path_provider/path_provider.dart';
+
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
@@ -302,7 +304,7 @@
}
}
- void _handleIncomingVoice(Map<String, dynamic> msg) {
+ Future<void> _handleIncomingVoice(Map<String, dynamic> msg) async {
final sessionId = msg['sessionId'] as String?;
final audioData = msg['audioBase64'] as String? ?? msg['audio'] as String? ?? msg['data'] as String?;
final content = msg['content'] as String? ?? msg['text'] as String? ?? '';
@@ -319,9 +321,33 @@
duration: duration,
);
+ // Save audio to file so it survives persistence (base64 gets stripped)
+ String? savedAudioPath;
+ if (audioData != null) {
+ try {
+ final dir = await getTemporaryDirectory();
+ savedAudioPath = '${dir.path}/voice_${message.id}.m4a';
+ final bytes = base64Decode(audioData.contains(',') ? audioData.split(',').last : audioData);
+ await File(savedAudioPath).writeAsBytes(bytes);
+ } catch (_) {
+ savedAudioPath = null;
+ }
+ }
+
+ final storedMessage = Message(
+ id: message.id,
+ role: message.role,
+ type: message.type,
+ content: content,
+ audioUri: savedAudioPath ?? audioData,
+ timestamp: message.timestamp,
+ status: message.status,
+ duration: duration,
+ );
+
final activeId = ref.read(activeSessionIdProvider);
if (sessionId != null && sessionId != activeId) {
- _storeForSession(sessionId, message);
+ _storeForSession(sessionId, storedMessage);
_incrementUnread(sessionId);
final sessions = ref.read(sessionsProvider);
final session = sessions.firstWhere(
@@ -339,12 +365,11 @@
return;
}
- ref.read(messagesProvider.notifier).addMessage(message);
+ ref.read(messagesProvider.notifier).addMessage(storedMessage);
ref.read(isTypingProvider.notifier).state = false;
_scrollToBottom();
if (audioData != null && !AudioService.isBackgrounded && !_isCatchingUp && !_isRecording) {
- // Queue incoming voice chunks — don't play while recording
AudioService.queueBase64(audioData);
}
}
--
Gitblit v1.3.1