Add variable playback speed feature for voice messages
Add playback speed control for voice messages with support for 0.5×, 1×, 1.5×, and 2× playback speeds. The speed button is displayed above the timestamp and cycles through the available speeds when tapped.
This commit is contained in:
parent
1c26c03cde
commit
5e07691fcd
13 changed files with 203 additions and 15 deletions
|
|
@ -8,6 +8,8 @@
|
|||
package io.element.android.features.messages.impl.timeline.components.event
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
|
|
@ -16,6 +18,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
|
|
@ -109,19 +112,30 @@ fun TimelineItemVoiceView(
|
|||
}
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
text = state.time,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
style = ElementTheme.typography.fontBodySmMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
PlaybackSpeedButton(
|
||||
speed = state.playbackSpeed,
|
||||
onClick = { state.eventSink(VoiceMessageEvents.ChangePlaybackSpeed) },
|
||||
)
|
||||
Text(
|
||||
text = state.time,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
style = ElementTheme.typography.fontBodySmMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
WaveformPlaybackView(
|
||||
showCursor = state.showCursor,
|
||||
playbackProgress = state.progress,
|
||||
waveform = content.waveform,
|
||||
modifier = Modifier.height(34.dp),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(34.dp),
|
||||
seekEnabled = !isTalkbackActive(),
|
||||
onSeek = { state.eventSink(VoiceMessageEvents.Seek(it)) },
|
||||
)
|
||||
|
|
@ -172,6 +186,36 @@ private fun RetryButton(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PlaybackSpeedButton(
|
||||
speed: Float,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val speedText = when (speed) {
|
||||
0.5f -> "0.5×"
|
||||
1.0f -> "1×"
|
||||
1.5f -> "1.5×"
|
||||
2.0f -> "2×"
|
||||
else -> "${speed}×"
|
||||
}
|
||||
androidx.compose.foundation.layout.Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = ElementTheme.colors.bgCanvasDefault,
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
)
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||
.clickable(onClick = onClick),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = speedText,
|
||||
color = ElementTheme.colors.iconSecondary,
|
||||
style = ElementTheme.typography.fontBodyXsMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ControlIcon(
|
||||
imageVector: ImageVector,
|
||||
|
|
@ -295,3 +339,14 @@ internal fun ProgressButtonPreview() = ElementPreview {
|
|||
ProgressButton(displayImmediately = false)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun PlaybackSpeedButtonPreview() = ElementPreview {
|
||||
Row {
|
||||
PlaybackSpeedButton(speed = 0.5f, onClick = {})
|
||||
PlaybackSpeedButton(speed = 1.0f, onClick = {})
|
||||
PlaybackSpeedButton(speed = 1.5f, onClick = {})
|
||||
PlaybackSpeedButton(speed = 2.0f, onClick = {})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue