TLS Fallback (Bridge → RVS)

Audio-Rendering fuer App (Piper TTS via RVS)
Chat-Persistenz (AsyncStorage, 500 Nachrichten)
This commit is contained in:
2026-03-10 18:40:03 +01:00
parent b5f1bf6d2c
commit e951fc712f
80 changed files with 261 additions and 63 deletions
+34 -3
View File
@@ -17,6 +17,7 @@ import {
StyleSheet,
Modal,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import rvs, { RVSMessage, ConnectionState } from '../services/rvs';
import audioService from '../services/audio';
import VoiceButton from '../components/VoiceButton';
@@ -41,6 +42,11 @@ interface ChatMessage {
attachments?: Attachment[];
}
// --- Konstanten ---
const CHAT_STORAGE_KEY = 'aria_chat_messages';
const MAX_STORED_MESSAGES = 500;
// --- Komponente ---
const ChatScreen: React.FC = () => {
@@ -60,10 +66,26 @@ const ChatScreen: React.FC = () => {
return `msg_${Date.now()}_${messageIdCounter.current}`;
};
// GPS-Einstellung aus Settings laden (vereinfacht)
// Chat-Verlauf aus AsyncStorage laden
useEffect(() => {
// In Produktion: AsyncStorage oder Context verwenden
// Hier Platzhalter - GPS Toggle kommt aus SettingsScreen
const loadMessages = async () => {
try {
const stored = await AsyncStorage.getItem(CHAT_STORAGE_KEY);
if (stored) {
const parsed: ChatMessage[] = JSON.parse(stored);
setMessages(parsed);
// ID-Counter auf hoechsten Wert setzen um Kollisionen zu vermeiden
const maxId = parsed.reduce((max, msg) => {
const num = parseInt(msg.id.split('_').pop() || '0', 10);
return num > max ? num : max;
}, 0);
messageIdCounter.current = maxId;
}
} catch (err) {
console.error('[Chat] Fehler beim Laden des Verlaufs:', err);
}
};
loadMessages();
}, []);
// RVS-Nachrichten abonnieren
@@ -99,6 +121,15 @@ const ChatScreen: React.FC = () => {
};
}, []);
// Chat-Verlauf in AsyncStorage speichern (letzte N Nachrichten)
useEffect(() => {
if (messages.length === 0) return;
const toStore = messages.slice(-MAX_STORED_MESSAGES);
AsyncStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(toStore)).catch(err =>
console.error('[Chat] Fehler beim Speichern:', err),
);
}, [messages]);
// Auto-Scroll bei neuen Nachrichten
useEffect(() => {
if (messages.length > 0) {
+9 -4
View File
@@ -7,6 +7,7 @@
import { Platform, PermissionsAndroid } from 'react-native';
import Sound from 'react-native-sound';
import RNFS from 'react-native-fs';
// --- Typen ---
@@ -127,18 +128,20 @@ class AudioService {
/** Base64-kodiertes Audio abspielen (z.B. TTS-Antwort von ARIA) */
async playAudio(base64Data: string): Promise<void> {
if (!base64Data) return;
// Laufende Wiedergabe stoppen
this.stopPlayback();
try {
// Base64-Daten in temporaere Datei schreiben und abspielen
// In Produktion: react-native-fs + Sound kombinieren
const tmpPath = `${Platform.OS === 'android' ? '/data/user/0/' : ''}aria_tts_temp.wav`;
// Base64 temporaere WAV-Datei → Sound abspielen
const tmpPath = `${RNFS.CachesDirectoryPath}/aria_tts_${Date.now()}.wav`;
await RNFS.writeFile(tmpPath, base64Data, 'base64');
// Platzhalter: Sound aus Datei laden
this.currentSound = new Sound(tmpPath, '', (error) => {
if (error) {
console.error('[Audio] Fehler beim Laden:', error);
RNFS.unlink(tmpPath).catch(() => {});
return;
}
this.currentSound?.play((success) => {
@@ -149,6 +152,8 @@ class AudioService {
}
this.currentSound?.release();
this.currentSound = null;
// Temp-Datei aufraeumen
RNFS.unlink(tmpPath).catch(() => {});
});
});
} catch (err) {