From 4e43b14b09fa26eb7835fb20001033d63a018886 Mon Sep 17 00:00:00 2001 From: davotoula Date: Tue, 24 Mar 2026 09:08:58 +0100 Subject: [PATCH] entire solid recording indicator bar stops recording when tapped, not just the small stop icon. --- .../amethyst/ui/actions/uploads/RecordAudio.kt | 10 ++++++++-- .../amethyst/ui/actions/uploads/RecordVoiceButton.kt | 8 +++++--- .../amethyst/ui/actions/uploads/RecordingIndicators.kt | 8 ++++++++ .../amethyst/ui/actions/uploads/VoiceMessagePreview.kt | 2 +- .../com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt | 3 ++- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordAudio.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordAudio.kt index 9eaa1a5da..82888202a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordAudio.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordAudio.kt @@ -50,7 +50,7 @@ fun RecordAudioBox( modifier: Modifier, onRecordTaken: (RecordingResult) -> Unit, maxDurationSeconds: Int? = null, - content: @Composable (Boolean, Int) -> Unit, + content: @Composable (Boolean, Int, () -> Unit) -> Unit, ) { val mediaRecorder = remember { mutableStateOf(null) } val context = LocalContext.current @@ -136,6 +136,12 @@ fun RecordAudioBox( } } }, - content = { active -> content(active, elapsedSeconds) }, + content = { active -> + content(active, elapsedSeconds) { + if (isRecording) { + stopRecording() + } + } + }, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordVoiceButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordVoiceButton.kt index 32613496f..856e36e47 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordVoiceButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordVoiceButton.kt @@ -50,15 +50,17 @@ fun RecordVoiceButton( ) { var isRecording by remember { mutableStateOf(false) } var elapsedSeconds by remember { mutableIntStateOf(0) } + var onStopRecording by remember { mutableStateOf({}) } Column( verticalArrangement = Arrangement.Center, ) { - // Floating recording indicator at the top + // Floating recording indicator at the top (outside ToggleableBox to avoid scale/circle) FloatingRecordingIndicator( modifier = Modifier.height(50.dp), isRecording = isRecording, elapsedSeconds = elapsedSeconds, + onClick = onStopRecording, ) RecordAudioBox( @@ -69,8 +71,7 @@ fun RecordVoiceButton( onVoiceTaken(recording) }, maxDurationSeconds = maxDurationSeconds, - ) { recordingState, elapsed -> - // Update parent state after composition completes + ) { recordingState, elapsed, onStop -> SideEffect { if (isRecording != recordingState) { isRecording = recordingState @@ -78,6 +79,7 @@ fun RecordVoiceButton( if (elapsedSeconds != elapsed) { elapsedSeconds = elapsed } + onStopRecording = onStop } Box( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordingIndicators.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordingIndicators.kt index 8981e320f..1fb909cc3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordingIndicators.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/RecordingIndicators.kt @@ -27,6 +27,7 @@ import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -176,6 +177,7 @@ fun FloatingRecordingIndicator( isRecording: Boolean, elapsedSeconds: Int, isCompact: Boolean = false, + onClick: (() -> Unit)? = null, ) { if (!isRecording) return @@ -199,6 +201,12 @@ fun FloatingRecordingIndicator( .background( color = MaterialTheme.colorScheme.primary, shape = RoundedCornerShape(12.dp), + ).then( + if (onClick != null) { + Modifier.clickable(onClick = onClick) + } else { + Modifier + }, ), contentAlignment = Alignment.Center, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/VoiceMessagePreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/VoiceMessagePreview.kt index 198cf0711..c87d34b75 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/VoiceMessagePreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/VoiceMessagePreview.kt @@ -215,7 +215,7 @@ private fun ReRecordButton( modifier = Modifier, onRecordTaken = onRecordTaken, maxDurationSeconds = MAX_VOICE_RECORD_SECONDS, - ) { isRecording, elapsedSeconds -> + ) { isRecording, elapsedSeconds, _ -> val contentColor = if (isRecording) { MaterialTheme.colorScheme.onPrimary diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index f6e92f3c4..76b943fa7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -672,7 +672,7 @@ fun ReplyViaVoiceReaction( } }, maxDurationSeconds = MAX_VOICE_RECORD_SECONDS, - ) { isRecording, elapsedSeconds -> + ) { isRecording, elapsedSeconds, onStop -> if (voiceRecordingState != null) { SideEffect { if (voiceRecordingState.value != isRecording) { @@ -689,6 +689,7 @@ fun ReplyViaVoiceReaction( isRecording = true, elapsedSeconds = elapsedSeconds, isCompact = true, + onClick = onStop, ) } else { VoiceReplyIcon(iconSizeModifier, grayTint)