Drei groessere Aenderungen in der Android-App.
Datei-Manager (Settings → Dateien)
- Neuer Eintrag im Settings-Menue → Modal mit Liste
- Suche + Filter (Alle / Von ARIA / Vom User)
- Per Eintrag: ARIA/USER-Badge, Groesse, Datum, Loeschen-Button
- file_list_request via RVS → Bridge → Diagnostic-HTTP → response
- file_delete_request loescht serverseitig, file_deleted-Event
aktualisiert ALLE Chat-Bubbles (Attachment.deleted = true mit
Strikethrough-Name + 🗑️-Icon)
Skill-Created-Bubble
- Neuer ChatMessage.skillCreated Typ — eigenes Render mit gelbem
Border, Skill-Name, Beschreibung, Execution-Mode, Active-Status
- Falls Skill-Setup fehlschlug: ⚠ Setup-Fehler-Zeile direkt in der Bubble
- Stefan sieht in der Chat-History immer wenn ARIA selbst einen
Skill angelegt hat — Transparenz statt schweigend im Hintergrund
Pinch-Zoom rewriten (ZoomableImage.tsx)
- Multi-Touch-Race-Bugs in der alten Variante geloest:
* Touch-Count jetzt aus e.nativeEvent.touches.length statt
gestureState.numberActiveTouches (war nicht zuverlaessig)
* Re-Snapshot bei JEDEM Finger-Wechsel (1↔2) → keine Spruenge mehr
* Doppel-Tap via onPanResponderRelease + Bewegungs-Cap
* pointerEvents="none" auf Image-Wrapper → Touches gehen garantiert
an PanResponder-View
* collapsable={false} verhindert Android-View-Flattening
- 2-Finger-Pinch 1x..5x, simultaner Pan via Focal,
1-Finger-Pan nur wenn gezoomt (>1.02x), Doppel-Tap toggelt 1x↔2.5x
App SettingsScreen Repair-Section
- aria-core-spezifische Buttons raus: 🔧 Reparieren, 🚨 ARIA hart neu,
🧹 Konversation komprimieren (OpenClaw ist abgerissen)
- Stattdessen generischer container_restart fuer aria-bridge/brain/qdrant
- Repair-Buttons aus der "ARIA denkt..."-Bubble entfernt (nur Abbrechen)
ChatScreen
- skill_created und file_deleted Handler im RVS-Message-Switch
- file_list_response (Modal-State liegt in SettingsScreen)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neue ZoomableImage-Komponente — reine RN-Implementation mit
PanResponder + Animated, ohne extra Dependency.
- 2-Finger-Pinch: Zoom 1x..5x, Focal-Point folgt der Geste
- 1-Finger-Pan: nur aktiv wenn gezoomt, mit Bounds-Clamping
- Doppel-Tap: Toggle 1x ↔ 2.5x
Vollbild-Modal ersetzt das simple <Image> durch ZoomableImage fuer
JPEG/PNG/etc. SVGs bleiben non-zoomable (SvgUri-Limitation), Tap
schliesst sie. Plus dedicated ✕-Close-Button oben rechts da Tap-to-
Close mit PanResponder kollidiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MessageText erkennt http(s)-URLs auf Bilder (jpg/png/gif/webp/bmp/ico)
und rendert sie als <Image> unter dem Text. Markdown-Syntax
 wird durch dasselbe Regex erfasst weil die URL drin ist.
SVGs ausgespart — React Native Image kann SVG nicht ohne Extra-Lib.
Aspect-Ratio wird via Image.getSize ermittelt, gecapped auf 0.5..2.5
damit Panorama-/Streifen-Bilder die Bubble nicht sprengen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
handlePressIn/Out + onResponderGrant/Release/Terminate weg. Push-to-
Talk lief parallel zu Tap-to-Talk und triggerte je nach Touch-Timing
unkontrollierbar. Stefan kennt das Verhalten ohnehin nicht (sagt
"druecken startet, druecken stoppt") — Push-to-Talk macht UX nur
unklarer ohne Mehrwert.
isLongPress-Ref entfernt (war nur fuer Push-to-Talk-Discrimination).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug 1 — Textauswahl in Bubbles ging nicht mehr:
MessageText hatte verschachtelte <Text onPress={...}> fuer Custom-Link-
Styling. Das fing die Long-Press-Geste ab, daher kein Markieren+Kopieren
mehr. Jetzt nur noch ein einzelnes <Text selectable dataDetectorType="all">,
Android macht URLs/Telefonnummern/Emails per System-Detection klickbar.
Bug 2 — VAD erkannte Stille nicht zuverlaessig (Aufnahme lief endlos):
Festwerte (-45dB Stille / -28dB Sprache) passten nicht zu jeder Umgebung.
In lauteren Raeumen lag der Hintergrundpegel ueber der Stille-Schwelle,
lastSpeechTime wurde dauerhaft aktualisiert → VAD feuerte nie, Aufnahme
lief bis 120s Max-Duration.
Jetzt adaptiv: erste 5 Mic-Samples (~500ms) bilden die Baseline; Stille-
Schwelle = baseline+6dB, Sprache-Schwelle = baseline+12dB. Toast zeigt
die kalibrierten Werte beim Aufnahmestart. Fallback auf -38dB/-22dB falls
das Mikro keine Metering-Updates liefert.
Bug 3 — Barge-In ("ach vergiss es"):
Wenn waehrend ARIAs Antwort eine neue Sprachnachricht aufgenommen wird,
wird ARIAs aktuelle Aktivitaet (TTS + thinking/tool) sofort abgebrochen
bevor die neue Message gesendet wird — wie in einem echten Gespraech wo
man den anderen unterbrechen darf.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Android-Eigenheit: bei nested Text-Komponenten muss selectable=true
auch an die Kinder; der Wert auf dem Parent erbt sich nicht zuverlaessig.
Plus: dataDetectorType="all" als Fallback fuer System-Linkifizierung,
falls unsere Regex einen Match verpasst.
suppressHighlighting=false damit Long-Press auf den Link-Texten den
Selection-Mode nicht blockt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drei zusammenhaengende Bugs:
1. VAD-Timer feuerte im 200ms setInterval WEITER nachdem die Stille-
Schwelle erreicht war — listeners wurden pro Aufnahme bis zu 5x
getriggert. Parallel laufende stopRecording()-Calls lieferten
audio-recorder-player's nativen Layer OOM / Crash.
Fix: silenceFired-Latch + Timer-Clear SOFORT beim ersten Feuer
(fireSilenceOnce-Helper). Gleiche Logik fuer Max-Dauer + Conv-Window.
2. VoiceButton silence-listener re-registrierte bei jedem isRecording-
Flip (deps [isRecording, onRecordingComplete]). Closure-State war
stale, und bei schnellen flips gabs register/unregister-Races.
Fix: empty deps, state direkt vom audioService via getRecordingState()
lesen. onRecordingComplete via Ref (damit der Callback aktuell bleibt
ohne re-register).
3. handleTap las den Button-State aus React (isRecording), der bei
schnellen Taps stale sein konnte — "erst zweiter Tap geht" Symptom.
Fix: audioService.getRecordingState() als Source-of-Truth, plus
tapBusy-Ref als Anti-Doppel-Tap-Guard waehrend asyncer start/stop.
'processing'-State wird korrekt ignoriert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bugs:
- App Mute-/Auto-Playback: onMessage-Closure hielt stale ttsDeviceEnabled/
ttsMuted → Mute wurde ignoriert + AsyncStorage-Load kam nicht durch.
Fix via ttsCanPlayRef (live gespiegelt) statt Closure-Variablen.
- App Zombie-Recording: toggleWakeWord hat die laufende Aufnahme nicht
gestoppt → audioService.recordingState blieb 'recording' → normaler
Aufnahme-Button wirkungslos. Fix: await stopRecording() vor stop().
- Porcupine robuster: BuiltInKeywords-Enum Mapping mit String-Fallback,
errorCallback fuer Runtime-Crashes (state zurueck auf off statt
App-Crash), mehr Logging damit man beim naechsten Issue debuggen kann.
App-Features:
- MessageText Komponente: Text ist durchgehend selektierbar, erkennt
URLs (http/https), E-Mails, Telefonnummern und macht sie anklickbar
(oeffnet Browser / Mail-App / Android-Dialer via Linking).
- TTS-Wiedergabegeschwindigkeit pro Geraet einstellbar (Settings ->
"Sprechgeschwindigkeit", 0.5-2.0 in 0.1-Schritten, Default 1.0).
Wird als speed-Param an die F5-TTS-Bridge durchgereicht.
Bridge-Durchreichen:
- ChatScreen: speed aus AsyncStorage via ttsSpeedRef, an chat/audio/
tts_request mitgeschickt
- aria-bridge: _next_speed_override wie voice_override, an xtts_request
weitergereicht
- f5tts-bridge: speed-Param an F5TTS.infer() durchgereicht
Diagnostic-Feature:
- Voice-Preview-Button (Play-Icon) vor dem Delete-X in der Stimmen-Liste
- Modal mit Textfeld (Default-Beispieltext wird bei jedem Oeffnen neu
gesetzt) und Play-Button
- Server sammelt audio_pcm Frames der Preview-Anfrage, baut WAV,
schickt base64 zurueck, Browser spielt im <audio>-Tag ab
- 60s Timeout-Safety-Net
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
App Settings: Voice-Sektion (nur wenn TTS an)
- Liste aller XTTS-Server-Stimmen mit Auswahl-Radio + X zum Loeschen
- 'Standard' fuer Diagnostic-Default-Voice (keine lokale Ueberschreibung)
- 'Aktualisieren' Button laedt Liste neu (xtts_list_voices via RVS)
- 'Eigene Stimme aufnehmen' oeffnet VoiceCloneModal
VoiceCloneModal: 30s Aufnahme + Upload
- Vorlese-Text (>30s Lesedauer, thematisch passend)
- Rot-pulsierender Stop-Button, live Timer + Progressbar
- Auto-Stop bei 30s, Hinweise ab 15s ('genug fuer gute Clonung')
- Nach Stop: Namenseingabe (a-Z, 0-9, _, -), Upload via voice_upload
- Nach Upload: Modal schliesst, Settings bekommt xtts_voice_saved
und setzt automatisch die neue Stimme als gewaehlt
Voice-Flow App → Bridge → XTTS (geraetelokal):
- Jeder chat/audio/tts_request schickt aria_xtts_voice (AsyncStorage)
mit der Message mit
- Bridge speichert _next_voice_override bei chat/audio Empfang,
nutzt es fuer die naechste ARIA-Antwort und resettet dann
- Fallback: globale xtts_voice aus voice_config.json (Diagnostic)
Ergebnis:
- Gerat A hat 'stefan' geclont → ARIA antwortet Geraet A mit stefan
- Gerat B hat nichts gewaehlt → ARIA antwortet Geraet B mit Default
- Diagnostic-Einstellung wirkt als fallback-default fuer neue Geraete
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>