From c23dfe16e95713e7058137308bdbc28419609a39 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sat, 07 Mar 2026 11:54:15 +0100
Subject: [PATCH] feat: typing indicator, message deletion, chain playback, autoplay guard
---
services/audio.ts | 44 +++++++++++++++++++++++++++++++++++++-------
1 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/services/audio.ts b/services/audio.ts
index ea43236..188164e 100644
--- a/services/audio.ts
+++ b/services/audio.ts
@@ -4,10 +4,32 @@
setAudioModeAsync,
} from "expo-audio";
import * as LegacyFileSystem from "expo-file-system/legacy";
+import { AppState } from "react-native";
export interface RecordingResult {
uri: string;
durationMs: number;
+}
+
+// --- Autoplay suppression ---
+// Don't autoplay voice messages when the app is in the background
+// or when the user is on a phone call (detected via audio interruption).
+let _autoplayEnabled = true;
+let _audioInterrupted = false;
+
+// Track app state — suppress autoplay when backgrounded
+AppState.addEventListener("change", (state) => {
+ _autoplayEnabled = state === "active";
+});
+
+/** Check if autoplay is safe right now (app in foreground, no interruption). */
+export function canAutoplay(): boolean {
+ return _autoplayEnabled && !_audioInterrupted;
+}
+
+/** Called externally to signal audio interruption (e.g., phone call started/ended). */
+export function setAudioInterrupted(interrupted: boolean): void {
+ _audioInterrupted = interrupted;
}
// --- Singleton audio player ---
@@ -94,13 +116,13 @@
while (audioQueue.length > 0) {
const item = audioQueue.shift()!;
- await playOneAudio(item.uri, item.onFinish);
+ await playOneAudio(item.uri, item.onFinish, false);
}
processingQueue = false;
}
-function playOneAudio(uri: string, onFinish?: () => void): Promise<void> {
+function playOneAudio(uri: string, onFinish?: () => void, cancelPrevious = true): Promise<void> {
return new Promise<void>(async (resolve) => {
let settled = false;
const finish = () => {
@@ -118,8 +140,8 @@
resolve();
};
- // Stop any currently playing audio first
- if (cancelCurrent) {
+ // Stop any currently playing audio first (only for non-queued calls)
+ if (cancelPrevious && cancelCurrent) {
cancelCurrent();
}
@@ -138,9 +160,17 @@
notifyListeners(uri);
player.addListener("playbackStatusUpdate", (status) => {
- if (!status.playing && status.currentTime > 0 &&
- (status.duration <= 0 || status.currentTime >= status.duration)) {
- finish();
+ if (!status.playing && status.currentTime > 0) {
+ if (status.duration <= 0 || status.currentTime >= status.duration) {
+ // Playback finished naturally
+ finish();
+ } else {
+ // Paused mid-playback — likely audio interruption (phone call)
+ setAudioInterrupted(true);
+ }
+ } else if (status.playing && _audioInterrupted) {
+ // Resumed after interruption
+ setAudioInterrupted(false);
}
});
--
Gitblit v1.3.1