Simplified ClipSpec classes
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieClipSpec.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieClipSpec.kt
index 0aecbb1..78399dc 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieClipSpec.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieClipSpec.kt
@@ -16,131 +16,77 @@
internal abstract fun getMaxProgress(composition: LottieComposition): Float
/**
- * Play the animation starting from this frame.
+ * Play the animation between these two frames. [maxInclusive] determines whether the animation
+ * should play the max frame or stop one frame before it.
*/
- data class MinFrame(val minFrame: Int) : LottieClipSpec() {
+ data class Frame(
+ val min: Int? = null,
+ val max: Int? = null,
+ val maxInclusive: Boolean = true,
+ ) : LottieClipSpec() {
+
+ private val actualMaxFrame = when {
+ max == null -> null
+ maxInclusive -> max
+ else -> max - 1
+ }
+
override fun getMinProgress(composition: LottieComposition): Float {
- return (minFrame / composition.endFrame).coerceIn(0f, 1f)
+ return when (min) {
+ null -> 0f
+ else -> (min / composition.endFrame).coerceIn(0f, 1f)
+ }
}
override fun getMaxProgress(composition: LottieComposition): Float {
- return 1f
+ return when (actualMaxFrame) {
+ null -> 1f
+ else -> (actualMaxFrame / composition.endFrame).coerceIn(0f, 1f)
+ }
}
}
/**
- * Play the animation until this frame.
+ * Play the animation between these two progress values.
*/
- data class MaxFrame(val maxFrame: Int, val inclusive: Boolean = true) : LottieClipSpec() {
-
- private val actualMaxFrame = if (inclusive) maxFrame else maxFrame - 1
-
+ data class Progress(
+ val min: Float = 0f,
+ val max: Float = 1f,
+ ) : LottieClipSpec() {
override fun getMinProgress(composition: LottieComposition): Float {
- return 0f
+ return min
}
override fun getMaxProgress(composition: LottieComposition): Float {
- return (actualMaxFrame / composition.endFrame).coerceIn(0f, 1f)
- }
- }
-
- /**
- * Play the animation between these two frames.
- */
- data class MinAndMaxFrame(val minFrame: Int, val maxFrame: Int, val maxFrameInclusive: Boolean = true) : LottieClipSpec() {
-
- private val actualMaxFrame = if (maxFrameInclusive) maxFrame else maxFrame - 1
-
- override fun getMinProgress(composition: LottieComposition): Float {
- return (minFrame / composition.endFrame).coerceIn(0f, 1f)
- }
-
- override fun getMaxProgress(composition: LottieComposition): Float {
- return (actualMaxFrame / composition.endFrame).coerceIn(0f, 1f)
- }
- }
-
- /**
- * Play the animation from this progress.
- */
- data class MinProgress(val minProgress: Float) : LottieClipSpec() {
- override fun getMinProgress(composition: LottieComposition): Float {
- return minProgress
- }
-
- override fun getMaxProgress(composition: LottieComposition): Float {
- return 1f
- }
- }
-
- /**
- * Play the animation until this progress.
- */
- data class MaxProgress(val maxProgress: Float) : LottieClipSpec() {
- override fun getMinProgress(composition: LottieComposition): Float {
- return 0f
- }
-
- override fun getMaxProgress(composition: LottieComposition): Float {
- return maxProgress
- }
- }
-
- /**
- * Play the animation between these two progresses.
- */
- data class MinAndMaxProgress(val minProgress: Float, val maxProgress: Float) : LottieClipSpec() {
- override fun getMinProgress(composition: LottieComposition): Float {
- return minProgress
- }
-
- override fun getMaxProgress(composition: LottieComposition): Float {
- return maxProgress
- }
- }
-
- /**
- * Play the animation starting from this marker.
- */
- data class MinMarker(val minMarker: String) : LottieClipSpec() {
- override fun getMinProgress(composition: LottieComposition): Float {
- return ((composition.getMarker(minMarker)?.startFrame ?: 0f) / composition.endFrame).coerceIn(0f, 1f)
- }
-
- override fun getMaxProgress(composition: LottieComposition): Float {
- return 1f
- }
- }
-
- /**
- * Play the animation until this marker. If the marker represents the end of your animation, set
- * [playMarkerFrame] to true. If the marker represents the beginning of the next section, set
- * it to false. In that case, the animation will stop at the frame before the marker.
- */
- data class MaxMarker(val maxMarker: String, val playMarkerFrame: Boolean = true) : LottieClipSpec() {
- override fun getMinProgress(composition: LottieComposition): Float {
- return 0f
- }
-
- override fun getMaxProgress(composition: LottieComposition): Float {
- val offset = if (playMarkerFrame) 0 else -1
- return ((composition.getMarker(maxMarker)?.startFrame?.plus(offset) ?: 0f) / composition.endFrame).coerceIn(0f, 1f)
+ return max
}
}
/**
* Play the animation from minMarker until maxMarker. If maxMarker represents the end of your animation,
- * set [playMaxMarkerStartFrame] to true. If the marker represents the beginning of the next section, set
- * it to false. In that case, the animation will stop at the frame before maxMarker.
+ * set [maxInclusive] to true. If the marker represents the beginning of the next section, set
+ * it to false to stop the animation at the frame before maxMarker.
*/
- data class MinAndMaxMarker(val minMarker: String, val maxMarker: String, val playMaxMarkerStartFrame: Boolean = true) : LottieClipSpec() {
+ data class Markers(
+ val min: String? = null,
+ val max: String? = null,
+ val maxInclusive: Boolean = true
+ ) : LottieClipSpec() {
override fun getMinProgress(composition: LottieComposition): Float {
- return ((composition.getMarker(minMarker)?.startFrame ?: 0f) / composition.endFrame).coerceIn(0f, 1f)
+ return when (min) {
+ null -> 0f
+ else -> ((composition.getMarker(min)?.startFrame ?: 0f) / composition.endFrame).coerceIn(0f, 1f)
+ }
}
override fun getMaxProgress(composition: LottieComposition): Float {
- val offset = if (playMaxMarkerStartFrame) 0 else -1
- return ((composition.getMarker(maxMarker)?.startFrame?.plus(offset) ?: 0f) / composition.endFrame).coerceIn(0f, 1f)
+ return when (max) {
+ null -> 1f
+ else -> {
+ val offset = if (maxInclusive) 0 else -1
+ return ((composition.getMarker(max)?.startFrame?.plus(offset) ?: 0f) / composition.endFrame).coerceIn(0f, 1f)
+ }
+ }
}
}
diff --git a/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieAnimatableImplTest.kt b/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieAnimatableImplTest.kt
index 50367ca..e207733 100644
--- a/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieAnimatableImplTest.kt
+++ b/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieAnimatableImplTest.kt
@@ -11,7 +11,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
-import java.lang.IllegalArgumentException
@RunWith(RobolectricTestRunner::class)
class LottieAnimatableImplTest {
@@ -111,7 +110,7 @@
@Test
fun testClipSpec() = runTest {
- val clipSpec = LottieClipSpec.MinAndMaxProgress(0.25f, 0.75f)
+ val clipSpec = LottieClipSpec.Progress(0.25f, 0.75f)
launch {
anim.animate(composition, clipSpec = clipSpec)
}
@@ -122,7 +121,7 @@
@Test
fun testClipSpecWithTwoIterations() = runTest {
- val clipSpec = LottieClipSpec.MinAndMaxProgress(0.25f, 0.75f)
+ val clipSpec = LottieClipSpec.Progress(0.25f, 0.75f)
launch {
anim.animate(composition, clipSpec = clipSpec, iterations = 2)
}
@@ -134,7 +133,7 @@
@Test
fun testNegativeSpeedWithClipSpec() = runTest {
- val clipSpec = LottieClipSpec.MinAndMaxProgress(0.25f, 0.75f)
+ val clipSpec = LottieClipSpec.Progress(0.25f, 0.75f)
launch {
anim.animate(composition, clipSpec = clipSpec, speed = -1f)
}
@@ -150,7 +149,7 @@
}
assertFrame(0, progress = 0f)
assertFrame(300, progress = 0.5f)
- val clipSpec = LottieClipSpec.MaxProgress(0.75f)
+ val clipSpec = LottieClipSpec.Progress(max = 0.75f)
launch {
anim.animate(composition, clipSpec = clipSpec, continueFromPreviousAnimate = false)
}
@@ -166,7 +165,7 @@
}
assertFrame(0, progress = 0f, iterations = 2)
assertFrame(300, progress = 0.5f, iterations = 2)
- val clipSpec = LottieClipSpec.MinProgress(0.25f)
+ val clipSpec = LottieClipSpec.Progress(min = 0.25f)
launch {
anim.animate(composition, clipSpec = clipSpec, initialProgress = anim.progress, continueFromPreviousAnimate = true)
}
@@ -183,7 +182,7 @@
}
assertFrame(0, progress = 0f)
assertFrame(300, progress = 0.5f)
- val clipSpec = LottieClipSpec.MaxProgress(0.75f)
+ val clipSpec = LottieClipSpec.Progress(max = 0.75f)
launch {
anim.animate(
composition,
diff --git a/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieClipSpecTest.kt b/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieClipSpecTest.kt
index 53f064d..8457f54 100644
--- a/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieClipSpecTest.kt
+++ b/lottie-compose/src/test/java/com/airbnb/lottie/compose/LottieClipSpecTest.kt
@@ -12,7 +12,7 @@
@Test
fun testMinFrame() {
- val spec = LottieClipSpec.MinFrame(20)
+ val spec = LottieClipSpec.Frame(min = 20)
val composition = createComposition(endFrame = 40f)
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(1f, spec.getMaxProgress(composition))
@@ -20,7 +20,7 @@
@Test
fun testMaxFrame() {
- val spec = LottieClipSpec.MaxFrame(20)
+ val spec = LottieClipSpec.Frame(max = 20)
val composition = createComposition(endFrame = 40f)
assertEquals(0f, spec.getMinProgress(composition))
assertEquals(0.5f, spec.getMaxProgress(composition))
@@ -28,7 +28,7 @@
@Test
fun testMaxFrameNotInclusive() {
- val spec = LottieClipSpec.MaxFrame(20, inclusive = false)
+ val spec = LottieClipSpec.Frame(max = 20, maxInclusive = false)
val composition = createComposition(endFrame = 40f)
assertEquals(0f, spec.getMinProgress(composition))
assertEquals(0.475f, spec.getMaxProgress(composition))
@@ -36,7 +36,7 @@
@Test
fun testMinAndMaxFrame() {
- val spec = LottieClipSpec.MinAndMaxFrame(20, 30)
+ val spec = LottieClipSpec.Frame(min = 20, max = 30)
val composition = createComposition(endFrame = 40f)
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(0.75f, spec.getMaxProgress(composition))
@@ -44,7 +44,7 @@
@Test
fun testMinAndMaxFrameNotExclusive() {
- val spec = LottieClipSpec.MinAndMaxFrame(20, 30, maxFrameInclusive = false)
+ val spec = LottieClipSpec.Frame(min = 20, max = 30, maxInclusive = false)
val composition = createComposition(endFrame = 40f)
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(0.725f, spec.getMaxProgress(composition))
@@ -52,7 +52,7 @@
@Test
fun testMinProgress() {
- val spec = LottieClipSpec.MinProgress(0.5f)
+ val spec = LottieClipSpec.Progress(min = 0.5f)
val composition = createComposition(endFrame = 40f)
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(1f, spec.getMaxProgress(composition))
@@ -60,7 +60,7 @@
@Test
fun testMaxProgress() {
- val spec = LottieClipSpec.MaxProgress(0.5f)
+ val spec = LottieClipSpec.Progress(max = 0.5f)
val composition = createComposition(endFrame = 40f)
assertEquals(0f, spec.getMinProgress(composition))
assertEquals(0.5f, spec.getMaxProgress(composition))
@@ -68,7 +68,7 @@
@Test
fun testMinAndMaxProgress() {
- val spec = LottieClipSpec.MinAndMaxProgress(0.5f, 0.75f)
+ val spec = LottieClipSpec.Progress(min = 0.5f, max = 0.75f)
val composition = createComposition(endFrame = 40f)
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(0.75f, spec.getMaxProgress(composition))
@@ -76,7 +76,7 @@
@Test
fun testMinMarker() {
- val spec = LottieClipSpec.MinMarker("start")
+ val spec = LottieClipSpec.Markers(min = "start")
val composition = createComposition(endFrame = 40f, listOf(Marker("start", 20f, 10f)))
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(1f, spec.getMaxProgress(composition))
@@ -84,7 +84,7 @@
@Test
fun testMaxMarker() {
- val spec = LottieClipSpec.MaxMarker("end")
+ val spec = LottieClipSpec.Markers(max = "end")
val composition = createComposition(endFrame = 40f, listOf(Marker("end", 20f, 10f)))
assertEquals(0f, spec.getMinProgress(composition))
assertEquals(0.5f, spec.getMaxProgress(composition))
@@ -93,7 +93,7 @@
@Test
fun testMaxMarkerExclusive() {
- val spec = LottieClipSpec.MaxMarker("end", playMarkerFrame = false)
+ val spec = LottieClipSpec.Markers(max = "end", maxInclusive = false)
val composition = createComposition(endFrame = 40f, listOf(Marker("end", 20f, 10f)))
assertEquals(0f, spec.getMinProgress(composition))
assertEquals(0.475f, spec.getMaxProgress(composition))
@@ -102,7 +102,7 @@
@Test
fun testMinAndMaxMarker() {
- val spec = LottieClipSpec.MinAndMaxMarker("start", "end")
+ val spec = LottieClipSpec.Markers(min = "start", max = "end")
val composition = createComposition(endFrame = 40f, listOf(Marker("start", 20f, 10f), Marker("end", 30f, 10f)))
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(0.75f, spec.getMaxProgress(composition))
@@ -110,7 +110,7 @@
@Test
fun testMinAndMaxMarkerExclusive() {
- val spec = LottieClipSpec.MinAndMaxMarker("start", "end", playMaxMarkerStartFrame = false)
+ val spec = LottieClipSpec.Markers(min = "start", max = "end", maxInclusive = false)
val composition = createComposition(endFrame = 40f, listOf(Marker("start", 20f, 10f), Marker("end", 30f, 10f)))
assertEquals(0.5f, spec.getMinProgress(composition))
assertEquals(0.725f, spec.getMaxProgress(composition))
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 de75ff6..d3f3a1c 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
@@ -89,7 +89,7 @@
LottieAnimation(
composition,
iterations = LottieConstants.IterateForever,
- clipSpec = LottieClipSpec.MinAndMaxProgress(0.5f, 0.75f),
+ clipSpec = LottieClipSpec.Progress(0.5f, 0.75f),
)
}
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 8414048..978cd7c 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
@@ -1,8 +1,6 @@
package com.airbnb.lottie.sample.compose.examples
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material.TextButton
@@ -81,9 +79,9 @@
composition ?: return@LaunchedEffect
snapshotFlow { state }.collectLatest { s ->
val clipSpec = when (s) {
- TransitionSection.Intro -> LottieClipSpec.MinAndMaxProgress(0f, 0.301f)
- TransitionSection.LoopMiddle -> LottieClipSpec.MinAndMaxProgress(0.301f, 2f / 3f)
- TransitionSection.Outro -> LottieClipSpec.MinAndMaxProgress(2f / 3f, 1f)
+ TransitionSection.Intro -> LottieClipSpec.Progress(0f, 0.301f)
+ TransitionSection.LoopMiddle -> LottieClipSpec.Progress(0.301f, 2f / 3f)
+ TransitionSection.Outro -> LottieClipSpec.Progress(2f / 3f, 1f)
}
do {
animatable.animate(