Browse Source

voice: fix waveform — pointerInput on Box, cursor + white bars stay on pause

- Canvas pointerInput moved to wrapping Box (state updates trigger recomposition)
- showCursor = playing || paused (cursor and white bars visible on pause)
- elapsed/dur stays visible on pause too
topo_upd
evgeny 2 months ago
parent
commit
2e8aa89397
  1. 61
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt

61
tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt

@ -129,36 +129,39 @@ private fun VoiceBubble(message: Message, textColor: Color,
/* Waveform with seek on tap */
if (wfCount >= 2) {
Canvas(modifier = Modifier.weight(1f).height(28.dp)
.pointerInput(message.filePath) {
detectTapGestures { offset ->
if (message.filePath.isEmpty()) return@detectTapGestures
val seekFrac = (offset.x / size.width).coerceIn(0f, 1f)
val seekMs = (seekFrac * durMs).toInt()
playing = true; paused = false; elapsedMs = seekMs; progress = seekFrac
onSeek(message.filePath, seekMs, onDone)
Box(
modifier = Modifier.weight(1f).height(28.dp)
.pointerInput(message.filePath) {
detectTapGestures { offset ->
if (message.filePath.isEmpty()) return@detectTapGestures
val seekFrac = (offset.x / size.width).coerceIn(0f, 1f)
val seekMs = (seekFrac * durMs).toInt()
playing = true; paused = false; elapsedMs = seekMs; progress = seekFrac
onSeek(message.filePath, seekMs, onDone)
}
}
}
) {
val barW = size.width / wfCount
val ph = size.height
val showCursor = playing && !paused
val playedIdx = if (showCursor && progress > 0f) (progress * wfCount).toInt() else 0
for (i in 0 until wfCount) {
val level = wf[i].coerceIn(0f, 1f)
val barH = (2f + level * (ph - 2f)).coerceAtMost(ph)
val x = i.toFloat() * barW
val y = ph - barH
val played = showCursor && i < playedIdx
drawRect(
color = when { played -> Color.White; else -> Color(0xFFCCCCD4).copy(alpha = 0.8f) },
topLeft = Offset(x, y),
size = Size(barW * 0.75f, barH)
)
}
if (showCursor && progress > 0f && progress < 1f) {
val cursorX = progress * size.width
drawLine(Color(0xFFFFD600), Offset(cursorX, 0f), Offset(cursorX, ph), strokeWidth = 2.5f)
Canvas(modifier = Modifier.fillMaxSize()) {
val barW = size.width / wfCount
val ph = size.height
val showCursor = playing || paused
val playedIdx = if (showCursor && progress > 0f) (progress * wfCount).toInt() else 0
for (i in 0 until wfCount) {
val level = wf[i].coerceIn(0f, 1f)
val barH = (2f + level * (ph - 2f)).coerceAtMost(ph)
val x = i.toFloat() * barW
val y = ph - barH
val played = showCursor && i < playedIdx
drawRect(
color = when { played -> Color.White; else -> Color(0xFFCCCCD4).copy(alpha = 0.8f) },
topLeft = Offset(x, y),
size = Size(barW * 0.75f, barH)
)
}
if (showCursor && progress > 0f && progress < 1f) {
val cursorX = progress * size.width
drawLine(Color(0xFFFFD600), Offset(cursorX, 0f), Offset(cursorX, ph), strokeWidth = 2.5f)
}
}
}
}
@ -173,7 +176,7 @@ private fun VoiceBubble(message: Message, textColor: Color,
verticalAlignment = Alignment.Bottom
) {
Text(
if (playing && !paused) "${formatDurationMs(elapsedMs)} / ${formatDurationMs(durMs)}"
if (playing || paused) "${formatDurationMs(elapsedMs)} / ${formatDurationMs(durMs)}"
else formatDurationMs(durMs),
fontSize = 12.sp,
color = textColor.copy(alpha = 0.55f)

Loading…
Cancel
Save