entire solid recording indicator bar stops recording when tapped, not just the small stop icon.

This commit is contained in:
davotoula
2026-03-24 09:08:58 +01:00
parent 6f3308e45c
commit 4e43b14b09
5 changed files with 24 additions and 7 deletions
@@ -50,7 +50,7 @@ fun RecordAudioBox(
modifier: Modifier, modifier: Modifier,
onRecordTaken: (RecordingResult) -> Unit, onRecordTaken: (RecordingResult) -> Unit,
maxDurationSeconds: Int? = null, maxDurationSeconds: Int? = null,
content: @Composable (Boolean, Int) -> Unit, content: @Composable (Boolean, Int, () -> Unit) -> Unit,
) { ) {
val mediaRecorder = remember { mutableStateOf<VoiceMessageRecorder?>(null) } val mediaRecorder = remember { mutableStateOf<VoiceMessageRecorder?>(null) }
val context = LocalContext.current val context = LocalContext.current
@@ -136,6 +136,12 @@ fun RecordAudioBox(
} }
} }
}, },
content = { active -> content(active, elapsedSeconds) }, content = { active ->
content(active, elapsedSeconds) {
if (isRecording) {
stopRecording()
}
}
},
) )
} }
@@ -50,15 +50,17 @@ fun RecordVoiceButton(
) { ) {
var isRecording by remember { mutableStateOf(false) } var isRecording by remember { mutableStateOf(false) }
var elapsedSeconds by remember { mutableIntStateOf(0) } var elapsedSeconds by remember { mutableIntStateOf(0) }
var onStopRecording by remember { mutableStateOf({}) }
Column( Column(
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
) { ) {
// Floating recording indicator at the top // Floating recording indicator at the top (outside ToggleableBox to avoid scale/circle)
FloatingRecordingIndicator( FloatingRecordingIndicator(
modifier = Modifier.height(50.dp), modifier = Modifier.height(50.dp),
isRecording = isRecording, isRecording = isRecording,
elapsedSeconds = elapsedSeconds, elapsedSeconds = elapsedSeconds,
onClick = onStopRecording,
) )
RecordAudioBox( RecordAudioBox(
@@ -69,8 +71,7 @@ fun RecordVoiceButton(
onVoiceTaken(recording) onVoiceTaken(recording)
}, },
maxDurationSeconds = maxDurationSeconds, maxDurationSeconds = maxDurationSeconds,
) { recordingState, elapsed -> ) { recordingState, elapsed, onStop ->
// Update parent state after composition completes
SideEffect { SideEffect {
if (isRecording != recordingState) { if (isRecording != recordingState) {
isRecording = recordingState isRecording = recordingState
@@ -78,6 +79,7 @@ fun RecordVoiceButton(
if (elapsedSeconds != elapsed) { if (elapsedSeconds != elapsed) {
elapsedSeconds = elapsed elapsedSeconds = elapsed
} }
onStopRecording = onStop
} }
Box( Box(
@@ -27,6 +27,7 @@ import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -176,6 +177,7 @@ fun FloatingRecordingIndicator(
isRecording: Boolean, isRecording: Boolean,
elapsedSeconds: Int, elapsedSeconds: Int,
isCompact: Boolean = false, isCompact: Boolean = false,
onClick: (() -> Unit)? = null,
) { ) {
if (!isRecording) return if (!isRecording) return
@@ -199,6 +201,12 @@ fun FloatingRecordingIndicator(
.background( .background(
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
).then(
if (onClick != null) {
Modifier.clickable(onClick = onClick)
} else {
Modifier
},
), ),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
@@ -215,7 +215,7 @@ private fun ReRecordButton(
modifier = Modifier, modifier = Modifier,
onRecordTaken = onRecordTaken, onRecordTaken = onRecordTaken,
maxDurationSeconds = MAX_VOICE_RECORD_SECONDS, maxDurationSeconds = MAX_VOICE_RECORD_SECONDS,
) { isRecording, elapsedSeconds -> ) { isRecording, elapsedSeconds, _ ->
val contentColor = val contentColor =
if (isRecording) { if (isRecording) {
MaterialTheme.colorScheme.onPrimary MaterialTheme.colorScheme.onPrimary
@@ -672,7 +672,7 @@ fun ReplyViaVoiceReaction(
} }
}, },
maxDurationSeconds = MAX_VOICE_RECORD_SECONDS, maxDurationSeconds = MAX_VOICE_RECORD_SECONDS,
) { isRecording, elapsedSeconds -> ) { isRecording, elapsedSeconds, onStop ->
if (voiceRecordingState != null) { if (voiceRecordingState != null) {
SideEffect { SideEffect {
if (voiceRecordingState.value != isRecording) { if (voiceRecordingState.value != isRecording) {
@@ -689,6 +689,7 @@ fun ReplyViaVoiceReaction(
isRecording = true, isRecording = true,
elapsedSeconds = elapsedSeconds, elapsedSeconds = elapsedSeconds,
isCompact = true, isCompact = true,
onClick = onStop,
) )
} else { } else {
VoiceReplyIcon(iconSizeModifier, grayTint) VoiceReplyIcon(iconSizeModifier, grayTint)