Added a coroutines sample
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..6c9268d 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
@@ -49,27 +49,31 @@
     clipSpec: LottieClipSpec? = null,
     cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediate,
     speed: Float = 1f,
-) {
+    snapToMinProgress: Boolean = true,
+    lastFrameTimeNanos: Long? = null,
+): Long? {
     require(speed != 0f) { "Speed must not be 0" }
     require(speed.isFinite()) { "Speed must be a finite number. It is $speed." }
-    composition ?: return
+    composition ?: return null
     val context = when (cancellationBehavior) {
         LottieCancellationBehavior.Immediate -> EmptyCoroutineContext
         LottieCancellationBehavior.AtEnd -> NonCancellable
     }
-    withContext(context) {
+    return withContext(context) {
         val minProgress = clipSpec?.getMinProgress(composition) ?: 0f
         val maxProgress = clipSpec?.getMaxProgress(composition) ?: 1f
         progress.value = when {
+            !snapToMinProgress -> progress.value.coerceIn(minProgress, maxProgress)
             speed >= 0 -> minProgress
             else -> maxProgress
         }
-        var lastFrameTime = withFrameNanos { it }
+        @Suppress("LocalVariableName")
+        var _lastFrameTimeNanos = lastFrameTimeNanos ?: withFrameNanos { it }
         var done = false
         while (!done) {
             withFrameNanos { frameTime ->
-                val dTime = (frameTime - lastFrameTime) / TimeUnit.MILLISECONDS.toNanos(1).toFloat()
-                lastFrameTime = frameTime
+                val dTime = (frameTime - _lastFrameTimeNanos) / TimeUnit.MILLISECONDS.toNanos(1).toFloat()
+                _lastFrameTimeNanos = frameTime
                 val dProgress = (dTime * speed) / composition.duration
                 val rawProgress = minProgress + ((progress.value - minProgress) + dProgress)
                 progress.value = rawProgress.coerceIn(minProgress, maxProgress)
@@ -79,5 +83,6 @@
                 }
             }
         }
+        _lastFrameTimeNanos
     }
 }
\ No newline at end of file
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/ComposeActivity.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/ComposeActivity.kt
index 2665ded..470c328 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/ComposeActivity.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/ComposeActivity.kt
@@ -80,6 +80,7 @@
                         composable(Route.LottieFiles.route) { LottieFilesPage(navController) }
                         composable(Route.Examples.route) { ExamplesPage(navController) }
                         composable(Route.BasicUsageExamples.route) { BasicUsageExamplesPage() }
+                        composable(Route.CoroutinesExamples.route) { CoroutinesExamplesPage() }
                         composable(Route.TransitionsExamples.route) { TransitionsExamplesPage() }
                         composable(Route.ViewPagerExample.route) { ViewPagerExamplePage() }
                         composable(Route.NetworkExamples.route) { NetworkExamplesPage() }
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/Route.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/Route.kt
index 93b4770..232d780 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/Route.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/Route.kt
@@ -18,6 +18,8 @@
 
     object BasicUsageExamples : Route("basic usage examples")
 
+    object CoroutinesExamples : Route("coroutines examples")
+
     object TransitionsExamples : Route("transitions examples")
 
     object ViewPagerExample : Route("view pager example")
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/CoroutinesExamplesPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/CoroutinesExamplesPage.kt
new file mode 100644
index 0000000..679b8d5
--- /dev/null
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/CoroutinesExamplesPage.kt
@@ -0,0 +1,113 @@
+package com.airbnb.lottie.sample.compose.examples
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.airbnb.lottie.compose.*
+import com.airbnb.lottie.sample.compose.R
+import kotlinx.coroutines.isActive
+
+@Composable
+fun CoroutinesExamplesPage() {
+    UsageExamplePageScaffold {
+        Column(
+            modifier = Modifier
+                .fillMaxWidth()
+                .verticalScroll(rememberScrollState())
+        ) {
+            Box(modifier = Modifier.height(16.dp))
+            ExampleCard("Example 1", "Repeat once") {
+                Example1()
+            }
+            ExampleCard("Example 2", "Repeat once. Click to repeat again") {
+                Example2()
+            }
+            ExampleCard("Example 3", "Repeat forever") {
+                Example3()
+            }
+            ExampleCard("Example 4", "Click to toggle playback") {
+                Example4()
+            }
+        }
+    }
+}
+
+
+@Composable
+private fun Example1() {
+    val composition by lottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
+    val progress = remember { mutableStateOf(0f) }
+
+    LaunchedEffect(composition) {
+        animateLottieComposition(composition, progress)
+    }
+    LottieAnimation(composition, progress.value)
+}
+
+@Composable
+private fun Example2() {
+    var iteration by remember { mutableStateOf(1) }
+    val composition by lottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
+    val progress = remember { mutableStateOf(0f) }
+
+    LaunchedEffect(composition, iteration) {
+        animateLottieComposition(composition, progress)
+    }
+    LottieAnimation(
+        composition,
+        progress.value,
+        modifier = Modifier
+            .clickable { iteration++ }
+    )
+}
+
+@Composable
+private fun Example3() {
+    val composition by lottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
+    val progress = remember { mutableStateOf(0f) }
+
+    LaunchedEffect(composition) {
+        // Return early when the composition is parsing so it doesn't loop in animateLottieComposition
+        // over and over again.
+        composition ?: return@LaunchedEffect
+        var lastFrameNanos: Long? = null
+        while (isActive) {
+            lastFrameNanos = animateLottieComposition(
+                composition,
+                progress,
+                lastFrameTimeNanos = lastFrameNanos,
+            )
+        }
+    }
+    LottieAnimation(composition, progress.value)
+}
+
+@Composable
+private fun Example4() {
+    var isPlaying by remember { mutableStateOf(true) }
+    val composition by lottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
+    val progress = remember { mutableStateOf(0f) }
+
+    LaunchedEffect(composition, isPlaying) {
+        if (composition == null || !isPlaying) return@LaunchedEffect
+        var snapToMinProgress = false
+        while (isActive) {
+            animateLottieComposition(
+                composition,
+                progress,
+                snapToMinProgress = snapToMinProgress,
+            )
+            snapToMinProgress = true
+        }
+    }
+    LottieAnimation(
+        composition,
+        progress.value,
+        modifier = Modifier
+            .clickable { isPlaying = !isPlaying }
+    )
+}
\ No newline at end of file
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ExamplesPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ExamplesPage.kt
index e27ea89..fac0c3d 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ExamplesPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ExamplesPage.kt
@@ -24,13 +24,19 @@
         Marquee(stringResource(R.string.examples_title))
         ListItem(
             text = { Text("Basic Usage") },
-            secondaryText = { Text("Various example of simple Lottie usage.") },
+            secondaryText = { Text("Various example of simple Lottie usage") },
             modifier = Modifier
                 .clickable { navController.navigate(Route.BasicUsageExamples) }
         )
         ListItem(
+            text = { Text("Coroutines Usage") },
+            secondaryText = { Text("Animating lottie with a suspending coroutine") },
+            modifier = Modifier
+                .clickable { navController.navigate(Route.CoroutinesExamples) }
+        )
+        ListItem(
             text = { Text("Transitions") },
-            secondaryText = { Text("Sequencing segments of an animation based on state.") },
+            secondaryText = { Text("Sequencing segments of an animation based on state") },
             modifier = Modifier
                 .clickable { navController.navigate(Route.TransitionsExamples) }
         )