[Compose] Add merge paths flag (#1744)

Fixes #1734

LottieAnimationView had merge paths disabled by default, but LottieAnimation enables them by default. As long as merge paths contain known bugs, I think it makes sense not to change that behavior - what do you think?
I added a flag for it to the state. If you want, we can add it as a constructor param too, but I feel like that's not needed as it's not that commonly used.
diff --git a/CHANGELOG_COMPOSE.md b/CHANGELOG_COMPOSE.md
index 0e00617..9056077 100644
--- a/CHANGELOG_COMPOSE.md
+++ b/CHANGELOG_COMPOSE.md
@@ -1,6 +1,9 @@
 #### Note: For the time being, we won't provide numbered releases for every new Jetpack Compose
 version. Check out our [snapshot builds](https://github.com/airbnb/lottie/blob/master/android-compose.md#getting-started) instead.
 
+# 1.0.0-alpha07-SNAPSHOT
+* Add flag for merge paths to LottieAnimationState
+
 # 1.0.0-alpha06
 * Compatible with Jetpack Compose Alpha 12
 
diff --git a/build.gradle b/build.gradle
index a180923..b35e692 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@
   }
   dependencies {
     classpath 'org.ajoberstar:grgit:1.9.3'
-    classpath 'com.android.tools.build:gradle:7.0.0-alpha06'
+    classpath 'com.android.tools.build:gradle:7.0.0-alpha07'
     classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
     classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion"
     classpath 'org.ajoberstar:grgit:1.9.3'
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 1c7a10a..61b3473 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
@@ -9,7 +9,6 @@
 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.graphics.drawscope.withTransform
 import androidx.compose.ui.graphics.nativeCanvas
-import androidx.compose.ui.platform.AmbientContext
 import androidx.compose.ui.platform.LocalContext
 import com.airbnb.lottie.LottieComposition
 import com.airbnb.lottie.LottieCompositionFactory
@@ -80,11 +79,7 @@
     state: LottieAnimationState,
     modifier: Modifier = Modifier,
 ) {
-    val drawable = remember {
-        LottieDrawable().apply {
-            enableMergePathsForKitKatAndAbove(true)
-        }
-    }
+    val drawable = remember { LottieDrawable() }
 
     SideEffect {
         drawable.composition = composition
@@ -118,7 +113,6 @@
     }
 
     if (composition == null || composition.duration == 0f) return
-    SideEffect {}
 
     Canvas(
         modifier = Modifier
@@ -129,6 +123,7 @@
             drawable.progress = state.progress
             drawable.setOutlineMasksAndMattes(state.outlineMasksAndMattes)
             drawable.isApplyingOpacityToLayersEnabled = state.applyOpacityToLayers
+            drawable.enableMergePathsForKitKatAndAbove(state.enableMergePaths)
             withTransform({
                 scale(size.width / composition.bounds.width().toFloat(), size.height / composition.bounds.height().toFloat(), Offset.Zero)
             }) {
@@ -143,4 +138,4 @@
     return this.then(aspectRatio(composition.bounds.width() / composition.bounds.height().toFloat()))
 }
 
-private fun lerp(a: Float, b: Float, @FloatRange(from = 0.0, to = 1.0) percentage: Float) =  a + percentage * (b - a)
+private fun lerp(a: Float, b: Float, @FloatRange(from = 0.0, to = 1.0) percentage: Float) = a + percentage * (b - a)
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt
index a245789..b410285 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt
@@ -6,25 +6,47 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 
+/**
+ * Create a [LottieAnimationState] and remember it
+ *
+ * @param autoPlay Initial value for [LottieAnimationState.isPlaying]
+ * @param repeatCount Initial value for [LottieAnimationState.repeatCount]
+ * @param initialProgress Initial value for [LottieAnimationState.progress]
+ * @param enableMergePaths Initial value for [LottieAnimationState.enableMergePaths]
+ */
 @Composable
 fun rememberLottieAnimationState(
     autoPlay: Boolean = true,
     repeatCount: Int = 0,
     initialProgress: Float = 0f,
+    enableMergePaths: Boolean = true
 ): LottieAnimationState {
     // Use rememberSavedInstanceState so you can pause/resume animations
     return remember(repeatCount, autoPlay) {
-        LottieAnimationState(isPlaying = autoPlay, repeatCount, initialProgress)
+        LottieAnimationState(
+            isPlaying = autoPlay,
+            repeatCount = repeatCount,
+            initialProgress = initialProgress,
+            enableMergePaths = enableMergePaths
+        )
     }
 }
 
 /**
- * @see rememberLottieAnimationState()
+ * State of the [LottieAnimation] composable
+ *
+ * @param isPlaying Initial value for [isPlaying]
+ * @param repeatCount Initial value for [repeatCount]
+ * @param initialProgress Initial value for [progress]
+ * @param enableMergePaths Initial value for [enableMergePaths]
+ *
+ * @see rememberLottieAnimationState
  */
 class LottieAnimationState(
     isPlaying: Boolean,
     repeatCount: Int = 0,
     initialProgress: Float = 0f,
+    enableMergePaths: Boolean = true
 ) {
     var progress by mutableStateOf(initialProgress)
 
@@ -32,7 +54,15 @@
     private var _frame = mutableStateOf(0)
     val frame: Int by _frame
 
+    /**
+     * Whether the animation is currently playing.
+     */
     var isPlaying by mutableStateOf(isPlaying)
+
+    /**
+     * How many times the animation will be played. Use [Int.MAX_VALUE] for
+     * infinite repetitions.
+     */
     var repeatCount by mutableStateOf(repeatCount)
 
     var speed by mutableStateOf(1f)
@@ -58,6 +88,18 @@
      */
     var applyOpacityToLayers by mutableStateOf(false)
 
+    /**
+     * Enable this to get merge path support.
+     * <p>
+     * Merge paths currently don't work if the the operand shape is entirely contained within the
+     * first shape. If you need to cut out one shape from another shape, use an even-odd fill type
+     * instead of using merge paths.
+     * <p>
+     * If your animation contains merge paths and you are encountering rendering issues, disabling
+     * merge paths might help.
+     */
+    var enableMergePaths by mutableStateOf(enableMergePaths)
+
     internal fun updateFrame(frame: Int) {
         _frame.value = frame
     }
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt
index 37e48e2..4933326 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt
@@ -141,7 +141,8 @@
                 value = state.query,
                 onValueChange = onQueryChanged,
                 label = { Text(stringResource(R.string.query)) },
-                modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
+                singleLine = true
             )
             LazyColumn(
                 modifier = Modifier.weight(1f)
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 a8c81f4..f882c01 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
@@ -19,7 +19,9 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
 import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.style.TextAlign
@@ -50,6 +52,7 @@
     val scaffoldState = rememberScaffoldState()
     val outlineMasksAndMattes = remember { mutableStateOf(false) }
     val applyOpacityToLayers = remember { mutableStateOf(false) }
+    val enableMergePaths = remember { mutableStateOf(animationState.enableMergePaths) }
     var focusMode by remember { mutableStateOf(false) }
     var backgroundColor by remember { mutableStateOf(animationBackgroundColor) }
     var showWarningsDialog by remember { mutableStateOf(false) }
@@ -72,6 +75,7 @@
 
     animationState.outlineMasksAndMattes = outlineMasksAndMattes.value
     animationState.applyOpacityToLayers = applyOpacityToLayers.value
+    animationState.enableMergePaths = enableMergePaths.value
 
     Scaffold(
         scaffoldState = scaffoldState,
@@ -164,6 +168,7 @@
                     backgroundColor = backgroundColorToolbar,
                     outlineMasksAndMattes = outlineMasksAndMattes,
                     applyOpacityToLayers = applyOpacityToLayers,
+                    enableMergePaths = enableMergePaths
                 )
             }
         }
@@ -344,6 +349,7 @@
     backgroundColor: MutableState<Boolean>,
     outlineMasksAndMattes: MutableState<Boolean>,
     applyOpacityToLayers: MutableState<Boolean>,
+    enableMergePaths: MutableState<Boolean>,
 ) {
     Row(
         modifier = Modifier
@@ -352,40 +358,47 @@
             .padding(bottom = 8.dp)
     ) {
         ToolbarChip(
-            iconRes = R.drawable.ic_masks_and_mattes,
+            iconPainter = painterResource(R.drawable.ic_masks_and_mattes),
             label = stringResource(R.string.toolbar_item_masks),
             isActivated = outlineMasksAndMattes.value,
             onClick = { outlineMasksAndMattes.value = it },
             modifier = Modifier.padding(end = 8.dp)
         )
         ToolbarChip(
-            iconRes = R.drawable.ic_layers,
+            iconPainter = painterResource(R.drawable.ic_layers),
             label = stringResource(R.string.toolbar_item_opacity_layers),
             isActivated = applyOpacityToLayers.value,
             onClick = { applyOpacityToLayers.value = it },
             modifier = Modifier.padding(end = 8.dp)
         )
         ToolbarChip(
-            iconRes = R.drawable.ic_color,
+            iconPainter = painterResource(R.drawable.ic_color),
             label = stringResource(R.string.toolbar_item_color),
             isActivated = backgroundColor.value,
             onClick = { backgroundColor.value = it },
             modifier = Modifier.padding(end = 8.dp)
         )
         ToolbarChip(
-            iconRes = R.drawable.ic_speed,
+            iconPainter = painterResource(R.drawable.ic_speed),
             label = stringResource(R.string.toolbar_item_speed),
             isActivated = speed.value,
             onClick = { speed.value = it },
             modifier = Modifier.padding(end = 8.dp)
         )
         ToolbarChip(
-            iconRes = R.drawable.ic_border,
+            iconPainter = painterResource(R.drawable.ic_border),
             label = stringResource(R.string.toolbar_item_border),
             isActivated = border.value,
             onClick = { border.value = it },
             modifier = Modifier.padding(end = 8.dp)
         )
+        ToolbarChip(
+            iconPainter = rememberVectorPainter(Icons.Default.MergeType),
+            label = stringResource(R.string.toolbar_item_merge_paths),
+            isActivated = enableMergePaths.value,
+            onClick = { enableMergePaths.value = it },
+            modifier = Modifier.padding(end = 8.dp)
+        )
     }
 }
 
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt
index 69904b8..1440c32 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt
@@ -13,6 +13,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clipToBounds
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.Painter
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.TextStyle
@@ -28,7 +29,7 @@
     isActivated: Boolean,
     onClick: (isActivated: Boolean) -> Unit,
     modifier: Modifier = Modifier,
-    @DrawableRes iconRes: Int = 0,
+    iconPainter: Painter? = null,
 ) {
     val unActivatedColor = remember { Color(0xFF444444) }
     Surface(
@@ -44,9 +45,9 @@
             modifier = Modifier
                 .padding(horizontal = 8.dp, vertical = 4.dp)
         ) {
-            if (iconRes != 0) {
+            if (iconPainter != null) {
                 Icon(
-                    painterResource(iconRes),
+                    iconPainter,
                     tint = if (isActivated) Color.White else unActivatedColor,
                     modifier = Modifier
                         .preferredSize(12.dp),
@@ -67,7 +68,7 @@
 @Composable
 fun PreviewToolbarChip() {
     ToolbarChip(
-        iconRes = R.drawable.ic_border,
+        iconPainter = painterResource(R.drawable.ic_border),
         label = stringResource(R.string.toolbar_item_border),
         isActivated = false,
         onClick = {}
diff --git a/sample-compose/src/main/res/values/strings.xml b/sample-compose/src/main/res/values/strings.xml
index 46de9bf..4f9ee0d 100644
--- a/sample-compose/src/main/res/values/strings.xml
+++ b/sample-compose/src/main/res/values/strings.xml
@@ -22,6 +22,7 @@
     <string name="toolbar_item_speed">Speed</string>
     <string name="toolbar_item_color">Background</string>
     <string name="toolbar_item_opacity_layers">Apply Opacity To Layers</string>
+    <string name="toolbar_item_merge_paths">Enable Merge Paths</string>
 
     <string name="failed_to_load">Failed to load composition</string>
     <string name="ok">OK</string>