Fix LottieAnimation recomposes on every frame degrading performance (#2078)

Fixes #2077

This issue can be fixed by a very simple approach mentioned in [https://developer.android.com/jetpack/compose/performance#defer-reads](Compose performance docs - Defer reads as long as possible) by deferring the progress read to the draw function.

Also, I've updated samples in this repo to use the new approach.
diff --git a/issue-repro-compose/src/main/java/com/airbnb/lottie/issues/compose/ComposeIssueReproActivity.kt b/issue-repro-compose/src/main/java/com/airbnb/lottie/issues/compose/ComposeIssueReproActivity.kt
index 81acbed..aeecf2f 100755
--- a/issue-repro-compose/src/main/java/com/airbnb/lottie/issues/compose/ComposeIssueReproActivity.kt
+++ b/issue-repro-compose/src/main/java/com/airbnb/lottie/issues/compose/ComposeIssueReproActivity.kt
@@ -22,6 +22,6 @@
     fun Content() {
         val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.heart))
         val progress by animateLottieCompositionAsState(composition)
-        LottieAnimation(composition, progress)
+        LottieAnimation(composition, { progress })
     }
 }
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 f22be00..fefea85 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
@@ -32,12 +32,12 @@
  *
  * @param composition The composition that will be rendered. To generate a [LottieComposition], you can use
  *                    [rememberLottieComposition].
- * @param progress The progress (between 0 and 1) that should be rendered. If you want to render a specific
- *                 frame, you can use [LottieComposition.getFrameForProgress]. In most cases, you will want
- *                 to use one of the overloaded LottieAnimation composables that drives the animation for you.
- *                 The overloads that have isPlaying as a parameter instead of progress will drive the
- *                 animation automatically. You may want to use this version if you want to drive the animation
- *                 from your own Animatable or via events such as download progress or a gesture.
+ * @param progressProvider A provider for the progress (between 0 and 1) that should be rendered. If you want to render a
+ *                         specific frame, you can use [LottieComposition.getFrameForProgress]. In most cases, you will want
+ *                         to use one of the overloaded LottieAnimation composables that drives the animation for you.
+ *                         The overloads that have isPlaying as a parameter instead of progress will drive the
+ *                         animation automatically. You may want to use this version if you want to drive the animation
+ *                         from your own Animatable or via events such as download progress or a gesture.
  * @param outlineMasksAndMattes Enable this to debug slow animations by outlining masks and mattes.
  *                              The performance overhead of the masks and mattes will be proportional to the
  *                              surface area of all of the masks/mattes combined.
@@ -69,7 +69,7 @@
 @Composable
 fun LottieAnimation(
     composition: LottieComposition?,
-    @FloatRange(from = 0.0, to = 1.0) progress: Float,
+    @FloatRange(from = 0.0, to = 1.0) progressProvider: () -> Float,
     modifier: Modifier = Modifier,
     outlineMasksAndMattes: Boolean = false,
     applyOpacityToLayers: Boolean = false,
@@ -114,7 +114,7 @@
             drawable.isApplyingOpacityToLayersEnabled = applyOpacityToLayers
             drawable.maintainOriginalImageBounds = maintainOriginalImageBounds
             drawable.clipToCompositionBounds = clipToCompositionBounds
-            drawable.progress = progress
+            drawable.progress = progressProvider()
             drawable.setBounds(0, 0, composition.bounds.width(), composition.bounds.height())
             drawable.draw(canvas.nativeCanvas, matrix)
         }
@@ -122,8 +122,44 @@
 }
 
 /**
+ * This is like [LottieAnimation] except that it takes a raw progress parameter instead of taking a progress provider.
+ *
+ * @see LottieAnimation
+ */
+@Composable
+fun LottieAnimation(
+    composition: LottieComposition?,
+    @FloatRange(from = 0.0, to = 1.0) progress: Float,
+    modifier: Modifier = Modifier,
+    outlineMasksAndMattes: Boolean = false,
+    applyOpacityToLayers: Boolean = false,
+    enableMergePaths: Boolean = false,
+    renderMode: RenderMode = RenderMode.AUTOMATIC,
+    maintainOriginalImageBounds: Boolean = false,
+    dynamicProperties: LottieDynamicProperties? = null,
+    alignment: Alignment = Alignment.Center,
+    contentScale: ContentScale = ContentScale.Fit,
+    clipToCompositionBounds: Boolean = true,
+) {
+    LottieAnimation(
+        composition,
+        { progress },
+        modifier,
+        outlineMasksAndMattes,
+        applyOpacityToLayers,
+        enableMergePaths,
+        renderMode,
+        maintainOriginalImageBounds,
+        dynamicProperties,
+        alignment,
+        contentScale,
+        clipToCompositionBounds,
+    )
+}
+
+/**
  * This is like [LottieAnimation] except that it handles driving the animation via [animateLottieCompositionAsState]
- * instead of taking a raw progress parameter.
+ * instead of taking a progress provider.
  *
  * @see LottieAnimation
  * @see animateLottieCompositionAsState
@@ -157,7 +193,7 @@
     )
     LottieAnimation(
         composition,
-        progress,
+        { progress },
         modifier,
         outlineMasksAndMattes,
         applyOpacityToLayers,
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/AnimatableExamplesPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/AnimatableExamplesPage.kt
index 562b837..f52b15d 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/AnimatableExamplesPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/AnimatableExamplesPage.kt
@@ -64,7 +64,7 @@
             iterations = LottieConstants.IterateForever,
         )
     }
-    LottieAnimation(anim.composition, anim.progress)
+    LottieAnimation(anim.composition, { anim.progress })
 }
 
 @Composable
@@ -84,7 +84,7 @@
         }
     }
     Box {
-        LottieAnimation(anim.composition, anim.progress)
+        LottieAnimation(anim.composition, { anim.progress })
         Slider(
             value = sliderGestureProgress ?: anim.progress,
             onValueChange = { sliderGestureProgress = it },
@@ -110,7 +110,7 @@
         )
     }
     Box {
-        LottieAnimation(composition, anim.progress)
+        LottieAnimation(composition, { anim.progress })
         Slider(
             value = speed,
             onValueChange = { speed = it },
@@ -144,7 +144,7 @@
     }
     LottieAnimation(
         composition,
-        animatable.progress,
+        { animatable.progress },
         modifier = Modifier
             .clickable { nonce++ }
     )
@@ -162,7 +162,7 @@
     }
     LottieAnimation(
         composition,
-        animatable.progress,
+        { animatable.progress },
         modifier = Modifier
             .clickable { shouldPlay = !shouldPlay }
     )
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 d592c18..f82e2ba 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
@@ -140,7 +140,7 @@
     )
     LottieAnimation(
         composition,
-        progress,
+        { progress },
     )
 }
 
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 e6eec4e..0dbcd85 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
@@ -90,7 +90,7 @@
             } while (s == TransitionSection.LoopMiddle)
         }
     }
-    LottieAnimation(composition, animatable.progress)
+    LottieAnimation(composition, { animatable.progress })
 }
 
 @Composable
@@ -113,5 +113,5 @@
         )
     }
 
-    LottieAnimation(animatable.composition, animatable.progress)
+    LottieAnimation(animatable.composition, { animatable.progress })
 }
\ No newline at end of file
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ViewPagerExample.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ViewPagerExample.kt
index 26a5146..79945be 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ViewPagerExample.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/examples/ViewPagerExample.kt
@@ -60,7 +60,7 @@
     val progress by derivedStateOf { (pagerState.currentPage + pagerState.currentPageOffset) / (pagerState.pageCount - 1f) }
     LottieAnimation(
         composition,
-        progress,
+        { progress },
         modifier = Modifier
             .fillMaxSize()
     )
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 e050069..3a640f2 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
@@ -255,7 +255,7 @@
         ) {
             PlayerPageLottieAnimation(
                 composition,
-                state.animatable.progress,
+                { state.animatable.progress },
                 modifier = Modifier
                     // TODO: figure out how maxWidth can play nice with the aspectRatio modifier inside of LottieAnimation.
                     .fillMaxWidth()
@@ -291,12 +291,12 @@
 @Composable
 private fun PlayerPageLottieAnimation(
     composition: LottieComposition?,
-    progress: Float,
+    progressProvider: () -> Float,
     modifier: Modifier = Modifier,
 ) {
     LottieAnimation(
         composition,
-        progress,
+        progressProvider,
         modifier = modifier,
     )
 }