From 887bbdbf84c841e234c35d19d0d16ee62bbb6611 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 29 Jul 2026 01:51:25 +0300 Subject: [PATCH] voice: play/pause toggle, stop previous on new track MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ViewModel: _currentPlayingPath tracks active track. Tap same → stop. Tap different → stop old, play new. onComplete clears currentPlayingPath. - AudioRecorderManager: stopPlayback() already called at start (existing) - VoiceBubble: simplified click, always sends to ViewModel for state management --- .../com/utun/chat/ui/components/MessageBubble.kt | 4 +--- .../java/com/utun/chat/viewmodel/ChatViewModel.kt | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt index 5a35bf69..a1cbec90 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt @@ -107,11 +107,9 @@ private fun VoiceBubble(message: Message, textColor: Color, onPlay: (String, () Box( modifier = Modifier.size(32.dp).background(Color.White, CircleShape) .clickable { - if (!playing && message.filePath.isNotEmpty()) { + if (message.filePath.isNotEmpty()) { playing = true; elapsedMs = 0; progress = 0f onPlay(message.filePath, onDone) - } else { - playing = false; onDone() } }, contentAlignment = Alignment.Center diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt index f0d6dca0..9ece7926 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt @@ -264,9 +264,22 @@ class ChatViewModel : ViewModel() { NativeLib.voiceSetCompressorConfig(maxGainDb, lookbackMs, lookaheadMs, riseRate, targetLevelDb) } + private var _currentPlayingPath: String? = null + fun playVoiceMessage(filePath: String, onComplete: () -> Unit) { + if (_currentPlayingPath == filePath) { + audioRecorder.stopPlayback() + _currentPlayingPath = null + onComplete() + return + } + audioRecorder.stopPlayback() + _currentPlayingPath = filePath LogManager.addLog("INFO", "VM", "play voice: $filePath") - audioRecorder.playVoiceFile(filePath, onComplete = onComplete) + audioRecorder.playVoiceFile(filePath, onComplete = { + _currentPlayingPath = null + onComplete() + }) } fun clearState() {