xref: /aosp_15_r20/external/lottie/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieDynamicProperties.kt (revision bb5273fecd5c61b9ace70f9ff4fcd88f0e12e3f7)

<lambda>null1 package com.airbnb.lottie.compose
2 
3 import android.graphics.Bitmap
4 import android.graphics.ColorFilter
5 import android.graphics.Path
6 import android.graphics.PointF
7 import android.graphics.Typeface
8 import androidx.compose.runtime.Composable
9 import androidx.compose.runtime.getValue
10 import androidx.compose.runtime.remember
11 import androidx.compose.runtime.rememberUpdatedState
12 import com.airbnb.lottie.LottieDrawable
13 import com.airbnb.lottie.model.KeyPath
14 import com.airbnb.lottie.value.LottieFrameInfo
15 import com.airbnb.lottie.value.LottieValueCallback
16 import com.airbnb.lottie.value.ScaleXY
17 
18 /**
19  * Use this function when you want to apply one or more dynamic properties to an animation.
20  * This takes a vararg of individual dynamic properties which should be created with [rememberLottieDynamicProperty].
21  *
22  * @see rememberLottieDynamicProperty
23  * @see LottieDrawable.setMaintainOriginalImageBounds
24  */
25 @Composable
26 fun rememberLottieDynamicProperties(
27     vararg properties: LottieDynamicProperty<*>,
28 ): LottieDynamicProperties {
29     return remember(properties.contentHashCode()) {
30         LottieDynamicProperties(properties.toList())
31     }
32 }
33 
34 /**
35  * Use this to create a single dynamic property for an animation.
36  *
37  * @param property should be one of [com.airbnb.lottie.LottieProperty].
38  * @param value the desired value to use as this property's value.
39  * @param keyPath the string parts of a [com.airbnb.lottie.model.KeyPath] that specify which animation element
40  *                the property resides on.
41  */
42 @Composable
rememberLottieDynamicPropertynull43 fun <T> rememberLottieDynamicProperty(
44     property: T,
45     value: T,
46     vararg keyPath: String,
47 ): LottieDynamicProperty<T> {
48     val keyPathObj = remember(keyPath) { KeyPath(*keyPath) }
49     return remember(keyPathObj, property, value) {
50         LottieDynamicProperty(property, keyPathObj, value)
51     }
52 }
53 
54 /**
55  * Use this to create a single dynamic property for an animation.
56  *
57  * @param property Should be one of [com.airbnb.lottie.LottieProperty].
58  * @param keyPath The string parts of a [com.airbnb.lottie.model.KeyPath] that specify which animation element
59  *                the property resides on.
60  * @param callback A callback that will be invoked during the drawing pass with current frame info. The frame
61  *                 info can be used to alter the property's value based on the original animation data or it
62  *                 can be completely ignored and an arbitrary value can be returned. In this case, you may want
63  *                 the overloaded version of this function that takes a static value instead of a callback.
64  */
65 @Composable
rememberLottieDynamicPropertynull66 fun <T> rememberLottieDynamicProperty(
67     property: T,
68     vararg keyPath: String,
69     callback: (frameInfo: LottieFrameInfo<T>) -> T,
70 ): LottieDynamicProperty<T> {
71     val keyPathObj = remember(keyPath.contentHashCode()) { KeyPath(*keyPath) }
72     val callbackState by rememberUpdatedState(callback)
73     return remember(keyPathObj, property) {
74         LottieDynamicProperty(
75             property,
76             keyPathObj,
77         ) { callbackState(it) }
78     }
79 }
80 
81 /**
82  * @see rememberLottieDynamicProperty
83  */
84 class LottieDynamicProperty<T> internal constructor(
85     internal val property: T,
86     internal val keyPath: KeyPath,
87     internal val callback: (frameInfo: LottieFrameInfo<T>) -> T,
88 ) {
<lambda>null89     constructor(property: T, keyPath: KeyPath, value: T) : this(property, keyPath, { value })
90 }
91 
92 /**
93  * @see rememberLottieDynamicProperties
94  */
95 class LottieDynamicProperties internal constructor(
96     private val intProperties: List<LottieDynamicProperty<Int>>,
97     private val pointFProperties: List<LottieDynamicProperty<PointF>>,
98     private val floatProperties: List<LottieDynamicProperty<Float>>,
99     private val scaleProperties: List<LottieDynamicProperty<ScaleXY>>,
100     private val colorFilterProperties: List<LottieDynamicProperty<ColorFilter>>,
101     // Java doesn't have reified types. All LottieProperty arrays are Integer[].
102     private val intArrayProperties: List<LottieDynamicProperty<Array<*>>>,
103     private val typefaceProperties: List<LottieDynamicProperty<Typeface>>,
104     private val bitmapProperties: List<LottieDynamicProperty<Bitmap>>,
105     private val charSequenceProperties: List<LottieDynamicProperty<CharSequence>>,
106     private val pathProperties: List<LottieDynamicProperty<Path>>,
107 ) {
108     @Suppress("UNCHECKED_CAST")
109     constructor(properties: List<LottieDynamicProperty<*>>) : this(
<lambda>null110         properties.filter { it.property is Int } as List<LottieDynamicProperty<Int>>,
<lambda>null111         properties.filter { it.property is PointF } as List<LottieDynamicProperty<PointF>>,
<lambda>null112         properties.filter { it.property is Float } as List<LottieDynamicProperty<Float>>,
<lambda>null113         properties.filter { it.property is ScaleXY } as List<LottieDynamicProperty<ScaleXY>>,
<lambda>null114         properties.filter { it.property is ColorFilter } as List<LottieDynamicProperty<ColorFilter>>,
<lambda>null115         properties.filter { it.property is Array<*> } as List<LottieDynamicProperty<Array<*>>>,
<lambda>null116         properties.filter { it.property is Typeface } as List<LottieDynamicProperty<Typeface>>,
<lambda>null117         properties.filter { it.property is Bitmap } as List<LottieDynamicProperty<Bitmap>>,
<lambda>null118         properties.filter { it.property is CharSequence } as List<LottieDynamicProperty<CharSequence>>,
<lambda>null119         properties.filter { it.property is Path } as List<LottieDynamicProperty<Path>>,
120     )
121 
addTonull122     internal fun addTo(drawable: LottieDrawable) {
123         intProperties.forEach { p ->
124             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
125         }
126         pointFProperties.forEach { p ->
127             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
128         }
129         floatProperties.forEach { p ->
130             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
131         }
132         scaleProperties.forEach { p ->
133             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
134         }
135         colorFilterProperties.forEach { p ->
136             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
137         }
138         intArrayProperties.forEach { p ->
139             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
140         }
141         typefaceProperties.forEach { p ->
142             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
143         }
144         bitmapProperties.forEach { p ->
145             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
146         }
147         charSequenceProperties.forEach { p ->
148             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
149         }
150         pathProperties.forEach { p ->
151             drawable.addValueCallback(p.keyPath, p.property, p.callback.toValueCallback())
152         }
153     }
154 
removeFromnull155     internal fun removeFrom(drawable: LottieDrawable) {
156         intProperties.forEach { p ->
157             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<Int>?)
158         }
159         pointFProperties.forEach { p ->
160             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<PointF>?)
161         }
162         floatProperties.forEach { p ->
163             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<Float>?)
164         }
165         scaleProperties.forEach { p ->
166             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<ScaleXY>?)
167         }
168         colorFilterProperties.forEach { p ->
169             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<ColorFilter>?)
170         }
171         intArrayProperties.forEach { p ->
172             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<Array<*>>?)
173         }
174         typefaceProperties.forEach { p ->
175             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<Typeface>?)
176         }
177         bitmapProperties.forEach { p ->
178             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<Bitmap>?)
179         }
180         charSequenceProperties.forEach { p ->
181             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<CharSequence>?)
182         }
183         pathProperties.forEach { p ->
184             drawable.addValueCallback(p.keyPath, p.property, null as LottieValueCallback<Path>?)
185         }
186     }
187 }
188 
toValueCallbacknull189 private fun <T> ((frameInfo: LottieFrameInfo<T>) -> T).toValueCallback() = object : LottieValueCallback<T>() {
190     override fun getValue(frameInfo: LottieFrameInfo<T>): T {
191         return invoke(frameInfo)
192     }
193 }
194