Potentially working well
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt
index 7c30b6c..f1ad819 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt
@@ -159,13 +159,10 @@
fun LottieAnimation(
compositionSpec: LottieCompositionSpec,
modifier: Modifier = Modifier,
- isPlaying: Boolean = true,
- restartOnPlay: Boolean = true,
- repeatCount: Int = 1,
+ playMode: LottiePlayMode = LottiePlayMode.Play,
clipSpec: LottieClipSpec? = null,
speed: Float = 1f,
- onRepeat: ((repeatCount: Int) -> Unit)? = null,
- onFinished: (() -> Unit)? = null,
+ iterations: Int = 1,
imageAssetsFolder: String? = null,
imageAssetDelegate: ImageAssetDelegate? = null,
outlineMasksAndMattes: Boolean = false,
@@ -176,13 +173,10 @@
LottieAnimation(
composition,
modifier,
- isPlaying,
- restartOnPlay,
+ playMode,
+ iterations,
clipSpec,
speed,
- repeatCount,
- onRepeat,
- onFinished,
imageAssetsFolder,
imageAssetDelegate,
outlineMasksAndMattes,
@@ -202,32 +196,26 @@
fun LottieAnimation(
composition: LottieComposition?,
modifier: Modifier = Modifier,
- isPlaying: Boolean = true,
- restartOnPlay: Boolean = true,
+ playMode: LottiePlayMode = LottiePlayMode.Play,
+ iterations: Int = 1,
clipSpec: LottieClipSpec? = null,
speed: Float = 1f,
- repeatCount: Int = 1,
- onRepeat: ((repeatCount: Int) -> Unit)? = null,
- onFinished: (() -> Unit)? = null,
imageAssetsFolder: String? = null,
imageAssetDelegate: ImageAssetDelegate? = null,
outlineMasksAndMattes: Boolean = false,
applyOpacityToLayers: Boolean = false,
enableMergePaths: Boolean = false,
) {
- val progress by animateLottieComposition(
+ val animationState = animateLottieComposition(
composition,
- isPlaying,
- restartOnPlay,
- clipSpec,
- speed,
- repeatCount,
- onRepeat,
- onFinished,
+ playMode,
+ iterations = iterations,
+ clipSpec = clipSpec,
+ speed = speed,
)
LottieAnimation(
composition,
- progress,
+ animationState.value,
modifier,
imageAssetsFolder,
imageAssetDelegate,
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationResult.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationResult.kt
new file mode 100644
index 0000000..544aee7
--- /dev/null
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationResult.kt
@@ -0,0 +1,9 @@
+package com.airbnb.lottie.compose
+
+sealed class LottieAnimationResult {
+ abstract val lastFrameTime: Long?
+
+ class Cancelled(override val lastFrameTime: Long?) : LottieAnimationResult()
+
+ class Finished(override val lastFrameTime: Long) : LottieAnimationResult()
+}
\ No newline at end of file
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieComposition.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieComposition.kt
index f3ac523..09a8c5f 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieComposition.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieComposition.kt
@@ -3,7 +3,154 @@
import androidx.compose.animation.core.*
import androidx.compose.runtime.*
import com.airbnb.lottie.LottieComposition
-import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.Channel
+import java.util.concurrent.atomic.AtomicReference
+
+enum class LottiePlayMode {
+ Play,
+ Pause;
+
+ operator fun not(): LottiePlayMode = if (this == Play) Pause else Play
+}
+
+@Composable
+fun rememberLottieAnimationState(
+ iterations: Int = 1,
+ clipSpec: LottieClipSpec? = null,
+ speed: Float = 1f,
+): LottieAnimationState {
+ val state = remember { LottieAnimationState() }
+ LaunchedEffect(iterations) {
+ state.iterations = iterations
+ }
+ LaunchedEffect(clipSpec) {
+ state.clipSpec = clipSpec
+ }
+ LaunchedEffect(speed) {
+ state.speed = speed
+ }
+ return state
+}
+
+@Stable
+class LottieAnimationState internal constructor() : MutableState<Float> {
+ private var job = AtomicReference<Job?>()
+
+ private val updatesChannel = Channel<Unit>()
+
+ private var _value by mutableStateOf(0f)
+ override var value: Float
+ get() = _value
+ set(value) {
+ _value = value
+ updatesChannel.offer(Unit)
+ }
+
+ var isPlaying: Boolean by mutableStateOf(false)
+ private set
+
+ var iteration: Int by mutableStateOf(1)
+
+ private var _iterations: Int by mutableStateOf(1)
+ var iterations: Int
+ get() = _iterations
+ set(value) {
+ _iterations = value
+ iteration = minOf(iteration, value)
+ updatesChannel.offer(Unit)
+ }
+
+ var _clipSpec: LottieClipSpec? by mutableStateOf(null)
+ var clipSpec: LottieClipSpec?
+ get() = _clipSpec
+ set(value) {
+ _clipSpec = value
+ updatesChannel.offer(Unit)
+ }
+
+ var speed: Float by mutableStateOf(1f)
+
+ var isAtEnd by mutableStateOf(true)
+ private set
+
+ /**
+ * Animate the Lottie composition given the state properties above.
+ * If the animation reaches the end, instead of finishing,
+ */
+ suspend fun animate(
+ composition: LottieComposition?,
+ cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediate,
+ ): Unit = coroutineScope {
+ val oldJob = job.get()
+ oldJob?.cancelAndJoin()
+ if (composition == null) {
+ isPlaying = false
+ return@coroutineScope
+ }
+ val newJob = coroutineContext.job
+ job.compareAndSet(oldJob, newJob)
+ isPlaying = true
+ try {
+ animateImpl(composition, cancellationBehavior)
+ } finally {
+ isPlaying = false
+ }
+ }
+
+ private suspend fun animateImpl(
+ composition: LottieComposition,
+ cancellationBehavior: LottieCancellationBehavior,
+ ) {
+ val minProgress = clipSpec?.getMinProgress(composition) ?: 0f
+ val maxProgress = clipSpec?.getMaxProgress(composition) ?: 1f
+ _value = value.coerceIn(minProgress, maxProgress)
+ var lastFrameTimeNanos = withFrameNanos { it }
+ while (true) {
+ awaitReadyToAnimate(maxProgress)
+ lastFrameTimeNanos = animateLottieComposition(
+ composition,
+ progress = this@LottieAnimationState,
+ clipSpec = clipSpec,
+ speed = speed,
+ lastFrameTimeNanos = lastFrameTimeNanos,
+ startAtMinProgress = false,
+ cancellationBehavior = cancellationBehavior,
+ )
+ if (iteration < iterations) {
+ iteration++
+ _value = when {
+ speed >= 0 -> minProgress
+ else -> maxProgress
+ }
+ }
+ }
+ }
+
+ private suspend fun awaitReadyToAnimate(maxProgress: Float) {
+ if (iteration < iterations || value < maxProgress) {
+ isAtEnd = false
+ return
+ }
+ isPlaying = false
+ isAtEnd = true
+ for (u in updatesChannel) {
+ if (iteration < iterations || value < maxProgress) {
+ isAtEnd = false
+ isPlaying = true
+ return
+ }
+ }
+ }
+
+ override fun component1(): Float {
+ return value
+ }
+
+ override fun component2(): (Float) -> Unit {
+ return { value = it }
+ }
+}
/**
* Returns a mutable state representing the progress of an animation.
@@ -19,99 +166,30 @@
* and pass its progress to [LottieComposition].
*
* @param composition The composition to render. This should be retrieved with [lottieComposition].
- * @param isPlaying Whether or not the animation is currently playing. Note that the internal
- * animation may end due to reaching the target repeatCount. If that happens,
- * the animation may stop even if this is still true. You may want to use
- * onFinished to set isPlaying to false but in many cases, it won't matter.
- * @param restartOnPlay If isPlaying switches from false to true, restartOnPlay determines whether
- * the progress and repeatCount get reset.
+ * @param playMode Whether or not the Lottie animation should be playing if it is not at the end of
+ * the animation.
* @param clipSpec A [LottieClipSpec] that specifies the bound the animation playback
* should be clipped to.
* @param speed The speed the animation should play at. Numbers larger than one will speed it up.
* Numbers between 0 and 1 will slow it down. Numbers less than 0 will play it backwards.
- * @param repeatCount The number of times the animation should repeat before stopping. It must be
+ * @param iterations The number of times the animation should repeat before stopping. It must be
* a positive number. [Integer.MAX_VALUE] can be used to repeat forever.
- * @param onRepeat An optional callback to be notified every time the animation repeats. Return whether
- * or not the animation should continue to repeat.
- * @param onFinished An optional callback that is invoked when animation completes. Note that the isPlaying
- * parameter you pass in may still be true. If you want to restart the animation, increase the
- * repeatCount or change isPlaying to false and then true again.
*/
@Composable
fun animateLottieComposition(
composition: LottieComposition?,
- isPlaying: Boolean = true,
- restartOnPlay: Boolean = true,
+ playMode: LottiePlayMode = LottiePlayMode.Play,
+ iterations: Int = 1,
clipSpec: LottieClipSpec? = null,
speed: Float = 1f,
- repeatCount: Int = 1,
- onRepeat: ((repeatCount: Int) -> Unit)? = null,
- onFinished: (() -> Unit)? = null,
-): MutableState<Float> {
- require(repeatCount > 0) { "Repeat count must be a positive number ($repeatCount)." }
- require(speed != 0f) { "Speed must not be 0" }
- require(speed.isFinite()) { "Speed must be a finite number. It is $speed." }
-
- val progress = remember { mutableStateOf(0f) }
-
- var currentRepeatCount by remember { mutableStateOf(0) }
- val currentOnRepeat by rememberUpdatedState(onRepeat)
- val currentOnFinished by rememberUpdatedState(onFinished)
-
- LaunchedEffect(composition) {
- progress.value = when (composition) {
- null -> 0f
- else -> if (speed >= 0) clipSpec?.getMinProgress(composition) ?: 0f else clipSpec?.getMaxProgress(composition) ?: 1f
- }
- currentRepeatCount = 0
+): LottieAnimationState {
+ val state = rememberLottieAnimationState(
+ iterations = iterations,
+ clipSpec = clipSpec,
+ speed = speed,
+ )
+ LaunchedEffect(composition, playMode) {
+ if (playMode == LottiePlayMode.Play) state.animate(composition)
}
-
- LaunchedEffect(composition, isPlaying, repeatCount, clipSpec, speed) {
- if (!isPlaying || composition == null) return@LaunchedEffect
- val minProgress = clipSpec?.getMinProgress(composition) ?: 0f
- val maxProgress = clipSpec?.getMaxProgress(composition) ?: 1f
- if (speed > 0 && (progress.value == 1f || restartOnPlay)) {
- progress.value = minProgress
- } else if (speed < 0 && (progress.value == 0f || restartOnPlay)) {
- progress.value = maxProgress
- }
- if (restartOnPlay || currentRepeatCount >= repeatCount) {
- currentRepeatCount = 0
- }
- var lastFrameTime = withFrameNanos { it }
- var done = false
- while (!done) {
- withFrameNanos { frameTime ->
- val dTime = (frameTime - lastFrameTime) / TimeUnit.MILLISECONDS.toNanos(1).toFloat()
- lastFrameTime = frameTime
- val dProgress = (dTime * speed) / composition.duration
- val rawProgress = minProgress + ((progress.value - minProgress) + dProgress)
- if (speed > 0 && rawProgress > maxProgress) {
- currentRepeatCount++
- currentOnRepeat?.invoke(repeatCount)
- } else if (speed < 0 && rawProgress < minProgress) {
- currentRepeatCount++
- currentOnRepeat?.invoke(repeatCount)
- }
- done = if (currentRepeatCount < repeatCount && !rawProgress.isInfinite()) {
- progress.value = minProgress + ((rawProgress - minProgress) fmod (maxProgress - minProgress))
- false
- } else {
- progress.value = when {
- speed >= 0 -> clipSpec?.getMaxProgress(composition) ?: 1f
- else -> clipSpec?.getMinProgress(composition) ?: 0f
- }
- true
- }
- }
- }
- currentOnFinished?.invoke()
- }
- return progress
+ return state
}
-
-/**
- * Floor mod instead of % which is remainder. This allows negative speeds to properly wrap around to
- * the max progress.
- */
-private infix fun Float.fmod(other: Float) = ((this % other) + other) % other
\ No newline at end of file
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieCompositionSuspend.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieCompositionSuspend.kt
index aedf9e1..af863df 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieCompositionSuspend.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/animateLottieCompositionSuspend.kt
@@ -41,6 +41,8 @@
* until the animation completes. [LottieCancellationBehavior.Immediate] will immediately cancel the
* animation and return early.
*
+ * @return the ending frame time nanos
+ *
* @see lottieTransition
*/
suspend fun animateLottieComposition(
@@ -49,10 +51,14 @@
clipSpec: LottieClipSpec? = null,
cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediate,
speed: Float = 1f,
-) {
+ lastFrameTimeNanos: Long? = null,
+ startAtMinProgress: Boolean = true,
+): Long {
require(speed != 0f) { "Speed must not be 0" }
require(speed.isFinite()) { "Speed must be a finite number. It is $speed." }
- composition ?: return
+ var lastFrameTime = lastFrameTimeNanos ?: withFrameNanos { it }
+ composition ?: return lastFrameTime
+
val context = when (cancellationBehavior) {
LottieCancellationBehavior.Immediate -> EmptyCoroutineContext
LottieCancellationBehavior.AtEnd -> NonCancellable
@@ -61,10 +67,10 @@
val minProgress = clipSpec?.getMinProgress(composition) ?: 0f
val maxProgress = clipSpec?.getMaxProgress(composition) ?: 1f
progress.value = when {
+ !startAtMinProgress -> progress.value.coerceIn(minProgress, maxProgress)
speed >= 0 -> minProgress
else -> maxProgress
}
- var lastFrameTime = withFrameNanos { it }
var done = false
while (!done) {
withFrameNanos { frameTime ->
@@ -80,4 +86,5 @@
}
}
}
+ return lastFrameTime
}
\ No newline at end of file
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/BasicUsageExamplesPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/BasicUsageExamplesPage.kt
index 3045941..a63aa5c 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/BasicUsageExamplesPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/BasicUsageExamplesPage.kt
@@ -62,7 +62,7 @@
private fun Example2() {
LottieAnimation(
LottieCompositionSpec.RawRes(R.raw.heart),
- repeatCount = Integer.MAX_VALUE,
+ iterations = Integer.MAX_VALUE,
)
}
@@ -73,7 +73,7 @@
private fun Example3() {
LottieAnimation(
LottieCompositionSpec.RawRes(R.raw.heart),
- repeatCount = Integer.MAX_VALUE,
+ iterations = Integer.MAX_VALUE,
clipSpec = LottieClipSpec.MinAndMaxProgress(0.5f, 0.75f),
)
}
@@ -116,13 +116,11 @@
@Composable
private fun Example6() {
val composition by lottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
- val progress by animateLottieComposition(
- composition,
- repeatCount = Integer.MAX_VALUE,
- )
+ val animationState = animateLottieComposition(composition)
+ animationState.iterations = Integer.MAX_VALUE
LottieAnimation(
composition,
- progress,
+ animationState.value,
)
}
@@ -131,16 +129,18 @@
*/
@Composable
private fun Example7() {
- var isPlaying by remember { mutableStateOf(false) }
+ var playMode by remember { mutableStateOf(LottiePlayMode.Play) }
+ val composition by lottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
+ val progress by animateLottieComposition(
+ composition,
+ playMode = playMode,
+ iterations = Integer.MAX_VALUE,
+ )
LottieAnimation(
- LottieCompositionSpec.RawRes(R.raw.heart),
- repeatCount = Integer.MAX_VALUE,
- // When this is true, it it will start from 0 every time it is played again.
- // When this is false, it will resume from the progress it was pause at.
- restartOnPlay = false,
- isPlaying = isPlaying,
+ composition,
+ progress,
modifier = Modifier
- .clickable { isPlaying = !isPlaying }
+ .clickable { playMode = !playMode }
)
}
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/TransitionsExamplesPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/TransitionsExamplesPage.kt
index 65a01de..6f4c090 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/TransitionsExamplesPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/TransitionsExamplesPage.kt
@@ -42,44 +42,34 @@
@Composable
fun SingleCompositionTransition(state: Int) {
val compositionResult = lottieComposition(LottieCompositionSpec.RawRes(R.raw.bar))
+ val animationState = rememberLottieAnimationState()
// This version of lottieTransition is for when your transition is segments of a single animation.
// It just takes state and returns progress.
- val progress = lottieTransition(state) { progress ->
+ lottieTransition(state) {
compositionResult.awaitOrNull() ?: return@lottieTransition
when (state) {
0 -> {
- // This version of animateLottieComposition takes a MutableState<Float> as a parameter
- // and then suspends until one iteration through the animation is complete.
- animateLottieComposition(
- compositionResult.value,
- progress,
- clipSpec = LottieClipSpec.MinAndMaxProgress(0f, 0.301f),
- cancellationBehavior = LottieCancellationBehavior.AtEnd,
- )
+ animationState.clipSpec = LottieClipSpec.MinAndMaxProgress(0f, 0.301f)
+ animationState.iterations = 1
+ animationState.animate(compositionResult.value, cancellationBehavior = LottieCancellationBehavior.AtEnd)
}
1 -> {
// To loop a segment, just wrap this in a while loop.
while (isActive) {
- animateLottieComposition(
- compositionResult.value,
- progress,
- clipSpec = LottieClipSpec.MinAndMaxProgress(0.301f, 2f / 3f),
- cancellationBehavior = LottieCancellationBehavior.AtEnd,
- )
+ animationState.clipSpec = LottieClipSpec.MinAndMaxProgress(0.301f, 2f / 3f)
+ animationState.iterations = Integer.MAX_VALUE
+ animationState.animate(compositionResult.value, cancellationBehavior = LottieCancellationBehavior.AtEnd)
}
}
2 -> {
- animateLottieComposition(
- compositionResult.value,
- progress,
- clipSpec = LottieClipSpec.MinAndMaxProgress(2f / 3f, 1f),
- cancellationBehavior = LottieCancellationBehavior.AtEnd,
- )
+ animationState.clipSpec = LottieClipSpec.MinAndMaxProgress(0.301f, 2f / 3f)
+ animationState.iterations = 1
+ animationState.animate(compositionResult.value, cancellationBehavior = LottieCancellationBehavior.AtEnd)
}
}
}
- LottieAnimation(compositionResult.value, progress)
+ LottieAnimation(compositionResult.value, animationState.value)
}
@Composable
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt
index 52f637d..718ebf6 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt
@@ -1,5 +1,6 @@
package com.airbnb.lottie.sample.compose.player
+import android.util.Log
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
@@ -45,9 +46,7 @@
@Stable
class PlayerPageState {
- var isPlaying by mutableStateOf(true)
- var repeatCount by mutableStateOf(Integer.MAX_VALUE)
- var speed by mutableStateOf(1f)
+ var playMode by mutableStateOf(LottiePlayMode.Play)
var outlineMasksAndMattes by mutableStateOf(false)
var applyOpacityToLayers by mutableStateOf(false)
var enableMergePaths by mutableStateOf(false)
@@ -173,13 +172,14 @@
ImageAssetDelegate { if (it.hasBitmap()) null else it.toDummyBitmap(dummyBitmapStrokeWidth) }
}
}
- val progress = animateLottieComposition(
+ val animationState = animateLottieComposition(
composition,
- state.isPlaying,
- restartOnPlay = false,
- repeatCount = state.repeatCount,
- speed = state.speed,
- ) { state.isPlaying = false }
+ playMode = state.playMode,
+ iterations = Integer.MAX_VALUE,
+ )
+ LaunchedEffect(animationState.iteration, animationState.iterations) {
+ Log.d("Gabe", "Iteration ${animationState.iteration}/${animationState.iterations}")
+ }
Column(
verticalArrangement = Arrangement.SpaceBetween,
@@ -194,7 +194,7 @@
) {
LottieAnimation(
composition,
- progress.value,
+ animationState.value,
imageAssetDelegate = imageAssetDelegate,
modifier = Modifier
.fillMaxSize()
@@ -210,7 +210,7 @@
}
}
ExpandVisibility(state.speedToolbar && !state.focusMode) {
- SpeedToolbar(state)
+ SpeedToolbar(animationState)
}
ExpandVisibility(!state.focusMode && state.backgroundColorToolbar) {
BackgroundColorToolbar(
@@ -219,7 +219,7 @@
)
}
ExpandVisibility(!state.focusMode) {
- PlayerControlsRow(composition, progress, state)
+ PlayerControlsRow(composition, state, animationState)
}
ExpandVisibility(!state.focusMode) {
Toolbar(state)
@@ -230,15 +230,15 @@
@Composable
private fun PlayerControlsRow(
composition: LottieComposition?,
- progress: MutableState<Float>,
state: PlayerPageState,
+ animationState: LottieAnimationState,
) {
- val totalTime = ((composition?.duration ?: 0L / state.speed) / 1000.0)
+ val totalTime = ((composition?.duration ?: 0L / animationState.speed) / 1000.0)
val totalTimeFormatted = ("%.1f").format(totalTime)
- val progressFormatted = ("%.1f").format(progress.value * totalTime)
+ val progressFormatted = ("%.1f").format(animationState.value * totalTime)
- val frame = composition?.getFrameForProgress(progress.value)?.roundToInt() ?: 0
+ val frame = composition?.getFrameForProgress(animationState.value)?.roundToInt() ?: 0
val durationFrames = ceil(composition?.durationFrames ?: 0f).roundToInt()
Box(
modifier = Modifier
@@ -251,10 +251,10 @@
contentAlignment = Alignment.Center
) {
IconButton(
- onClick = { state.isPlaying = !state.isPlaying },
+ onClick = { state.playMode = !state.playMode },
) {
Icon(
- if (state.isPlaying) Icons.Filled.Pause
+ if (animationState.isPlaying) Icons.Filled.Pause
else Icons.Filled.PlayArrow,
contentDescription = null
)
@@ -268,18 +268,18 @@
)
}
Slider(
- value = progress.value,
- onValueChange = { progress.value = it },
+ value = animationState.value,
+ onValueChange = { animationState.value = it },
modifier = Modifier.weight(1f)
)
IconButton(
onClick = {
- state.repeatCount = if (state.repeatCount == Integer.MAX_VALUE) 1 else Integer.MAX_VALUE
+ animationState.iterations = if (animationState.iterations == Integer.MAX_VALUE) 1 else Integer.MAX_VALUE
},
) {
Icon(
Icons.Filled.Repeat,
- tint = if (state.repeatCount == Integer.MAX_VALUE) Teal else Color.Black,
+ tint = if (animationState.iterations == Integer.MAX_VALUE) Teal else Color.Black,
contentDescription = null
)
}
@@ -297,7 +297,7 @@
@Composable
private fun SpeedToolbar(
- state: PlayerPageState,
+ animationState: LottieAnimationState,
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
@@ -308,26 +308,26 @@
) {
ToolbarChip(
label = "0.5x",
- isActivated = state.speed == 0.5f,
- onClick = { state.speed = 0.5f },
+ isActivated = animationState.speed == 0.5f,
+ onClick = { animationState.speed = 0.5f },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
label = "1x",
- isActivated = state.speed == 1f,
- onClick = { state.speed = 1f },
+ isActivated = animationState.speed == 1f,
+ onClick = { animationState.speed = 1f },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
label = "1.5x",
- isActivated = state.speed == 1.5f,
- onClick = { state.speed = 1.5f },
+ isActivated = animationState.speed == 1.5f,
+ onClick = { animationState.speed = 1.5f },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
label = "2x",
- isActivated = state.speed == 2f,
- onClick = { state.speed = 2f },
+ isActivated = animationState.speed == 2f,
+ onClick = { animationState.speed = 2f },
modifier = Modifier.padding(end = 8.dp)
)
}
@@ -470,8 +470,7 @@
@Preview
@Composable
fun SpeedToolbarPreview() {
- val state = remember { PlayerPageState() }
- state.speed = 1f
+ val state = animateLottieComposition(null)
SpeedToolbar(state)
}