Add smooth animation to voice messages play progress (#7698)

* Add linear animation to voice message playback progress

Instead of animating the small `progress` value changes, calculate an animation for the range `maxProgress - progress`, with a linear interpolator so it's completely smooth. Previously, the progress was updated in 'steps' that were quite noticeable.
This commit is contained in:
bxdxnn
2026-09-18 10:39:15 +03:00
committed by GitHub
parent c0bb68c872
commit 5cac4767f1
26 changed files with 1120 additions and 39 deletions
@@ -370,6 +370,7 @@ fun TextComposer(
waveform = voiceMessageState.waveform,
playbackProgress = voiceMessageState.playbackProgress,
time = voiceMessageState.time,
duration = voiceMessageState.duration,
onPlayClick = onPlayVoiceMessageClick,
onPauseClick = onPauseVoiceMessageClick,
onSeek = onSeekVoiceMessage,
@@ -929,6 +930,7 @@ internal fun TextComposerVoicePreview() = ElementPreview {
showCursor = false,
waveform = WaveFormSamples.realisticWaveForm,
time = 0.seconds,
duration = 61.seconds,
playbackProgress = 0.0f,
),
VoiceMessageState.Preview(
@@ -937,6 +939,7 @@ internal fun TextComposerVoicePreview() = ElementPreview {
showCursor = true,
waveform = WaveFormSamples.realisticWaveForm,
time = 3.seconds,
duration = 0.seconds,
playbackProgress = 0.2f,
),
VoiceMessageState.Preview(
@@ -945,6 +948,7 @@ internal fun TextComposerVoicePreview() = ElementPreview {
showCursor = false,
waveform = WaveFormSamples.realisticWaveForm,
time = 61.seconds,
duration = 61.seconds,
playbackProgress = 0.0f,
),
)
@@ -972,6 +976,7 @@ internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview {
showCursor = false,
waveform = WaveFormSamples.realisticWaveForm,
time = 0.seconds,
duration = 61.seconds,
playbackProgress = 0.0f
),
VoiceMessageState.Preview(
@@ -980,6 +985,7 @@ internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview {
showCursor = true,
waveform = WaveFormSamples.realisticWaveForm,
time = 3.seconds,
duration = 0.seconds,
playbackProgress = 0.2f
),
VoiceMessageState.Preview(
@@ -988,6 +994,7 @@ internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview {
showCursor = false,
waveform = WaveFormSamples.realisticWaveForm,
time = 61.seconds,
duration = 61.seconds,
playbackProgress = 0.0f
),
)
@@ -50,6 +50,7 @@ internal fun VoiceMessagePreview(
showCursor: Boolean,
waveform: ImmutableList<Float>,
time: Duration,
duration: Duration,
onPlayClick: () -> Unit,
onPauseClick: () -> Unit,
onSeek: (Float) -> Unit,
@@ -88,6 +89,8 @@ internal fun VoiceMessagePreview(
playbackProgress = playbackProgress,
showCursor = showCursor,
waveform = waveform,
isPlaying = isPlaying,
durationMs = duration.inWholeMilliseconds,
seekEnabled = true,
onSeek = onSeek,
)
@@ -151,6 +154,8 @@ internal fun VoiceMessagePreviewPreview() = ElementPreview {
isInteractive = true,
isPlaying = true,
time = 2.seconds,
// Keep previews static: a non-zero duration would start a long linear tween.
duration = 0.seconds,
playbackProgress = 0.2f,
showCursor = true,
waveform = WaveFormSamples.longRealisticWaveForm,
@@ -159,6 +164,7 @@ internal fun VoiceMessagePreviewPreview() = ElementPreview {
isInteractive = true,
isPlaying = false,
time = 0.seconds,
duration = 10.seconds,
playbackProgress = 0.0f,
showCursor = true,
waveform = WaveFormSamples.longRealisticWaveForm,
@@ -167,6 +173,7 @@ internal fun VoiceMessagePreviewPreview() = ElementPreview {
isInteractive = false,
isPlaying = false,
time = 789.seconds,
duration = 789.seconds,
playbackProgress = 0.0f,
showCursor = false,
waveform = WaveFormSamples.longRealisticWaveForm,
@@ -179,6 +186,7 @@ private fun AVoiceMessagePreview(
isInteractive: Boolean,
isPlaying: Boolean,
time: Duration,
duration: Duration,
playbackProgress: Float,
showCursor: Boolean,
waveform: ImmutableList<Float>,
@@ -187,6 +195,7 @@ private fun AVoiceMessagePreview(
isInteractive = isInteractive,
isPlaying = isPlaying,
time = time,
duration = duration,
playbackProgress = playbackProgress,
showCursor = showCursor,
waveform = waveform,
@@ -22,6 +22,7 @@ sealed interface VoiceMessageState {
val showCursor: Boolean,
val playbackProgress: Float,
val time: Duration,
val duration: Duration,
// Values are between 0 and 1
val waveform: ImmutableList<Float>,
) : VoiceMessageState