1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.runtime
18 
19 /**
20  * Compose passes data through the composition tree explicitly through means of parameters to
21  * composable functions. This is often times the simplest and best way to have data flow through the
22  * tree.
23  *
24  * Sometimes this model can be cumbersome or break down for data that is needed by lots of
25  * components, or when components need to pass data between one another but keep that implementation
26  * detail private. For these cases, [CompositionLocal]s can be used as an implicit way to have data
27  * flow through a composition.
28  *
29  * [CompositionLocal]s by their nature are hierarchical. They make sense when the value of the
30  * [CompositionLocal] needs to be scoped to a particular sub-hierarchy of the composition.
31  *
32  * One must create a [CompositionLocal] instance, which can be referenced by the consumers
33  * statically. [CompositionLocal] instances themselves hold no data, and can be thought of as a
34  * type-safe identifier for the data being passed down a tree. [CompositionLocal] factory functions
35  * take a single parameter: a factory to create a default value in cases where a [CompositionLocal]
36  * is used without a Provider. If this is a situation you would rather not handle, you can throw an
37  * error in this factory.
38  *
39  * @sample androidx.compose.runtime.samples.createCompositionLocal
40  *
41  * Somewhere up the tree, a [CompositionLocalProvider] component can be used, which provides a value
42  * for the [CompositionLocal]. This would often be at the "root" of a tree, but could be anywhere,
43  * and can also be used in multiple places to override the provided value for a sub-tree.
44  *
45  * @sample androidx.compose.runtime.samples.compositionLocalProvider
46  *
47  * Intermediate components do not need to know about the [CompositionLocal] value, and can have zero
48  * dependencies on it. For example, `SomeScreen` might look like this:
49  *
50  * @sample androidx.compose.runtime.samples.someScreenSample
51  *
52  * Finally, a component that wishes to consume the [CompositionLocal] value can use the [current]
53  * property of the [CompositionLocal] key which returns the current value of the [CompositionLocal],
54  * and subscribes the component to changes of it.
55  *
56  * @sample androidx.compose.runtime.samples.consumeCompositionLocal
57  */
58 @Stable
59 sealed class CompositionLocal<T>(defaultFactory: () -> T) {
60     internal open val defaultValueHolder: ValueHolder<T> = LazyValueHolder(defaultFactory)
61 
updatedStateOfnull62     internal abstract fun updatedStateOf(
63         value: ProvidedValue<T>,
64         previous: ValueHolder<T>?
65     ): ValueHolder<T>
66 
67     /**
68      * Return the value provided by the nearest [CompositionLocalProvider] component that invokes,
69      * directly or indirectly, the composable function that uses this property.
70      *
71      * @sample androidx.compose.runtime.samples.consumeCompositionLocal
72      */
73     @OptIn(InternalComposeApi::class)
74     inline val current: T
75         @ReadOnlyComposable @Composable get() = currentComposer.consume(this)
76 }
77 
78 /**
79  * A [ProvidableCompositionLocal] can be used in [CompositionLocalProvider] to provide values.
80  *
81  * @see compositionLocalOf
82  * @see staticCompositionLocalOf
83  * @see CompositionLocal
84  * @see CompositionLocalProvider
85  */
86 @Stable
87 abstract class ProvidableCompositionLocal<T> internal constructor(defaultFactory: () -> T) :
88     CompositionLocal<T>(defaultFactory) {
89     internal abstract fun defaultProvidedValue(value: T): ProvidedValue<T>
90 
91     /**
92      * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider].
93      *
94      * @see CompositionLocal
95      * @see ProvidableCompositionLocal
96      */
97     infix fun provides(value: T) = defaultProvidedValue(value)
98 
99     /**
100      * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider] if the
101      * key does not already have an associated value.
102      *
103      * @see CompositionLocal
104      * @see ProvidableCompositionLocal
105      */
106     infix fun providesDefault(value: T) = defaultProvidedValue(value).ifNotAlreadyProvided()
107 
108     /**
109      * Associates a [CompositionLocal] key to a lambda, [compute], in a call to [CompositionLocal].
110      * The [compute] lambda is invoked whenever the key is retrieved. The lambda is executed in the
111      * context of a [CompositionLocalContext] which allow retrieving the current values of other
112      * composition locals by calling [CompositionLocalAccessorScope.currentValue], which is an
113      * extension function provided by the context for a [CompositionLocal] key.
114      *
115      * The lambda passed to [providesComputed] will be invoked every time the
116      * [CompositionLocal.current] is evaluated for the composition local and computes its value
117      * based on the current value of the locals referenced in the lambda at the time
118      * [CompositionLocal.current] is evaluated. This allows providing values that can be derived
119      * from other locals. For example, if accent colors can be calculated from a single base color,
120      * the accent colors can be provided as computed composition locals. Providing a new base color
121      * would automatically update all the accent colors.
122      *
123      * @sample androidx.compose.runtime.samples.compositionLocalProvidedComputed
124      * @sample androidx.compose.runtime.samples.compositionLocalComputedAfterProvidingLocal
125      * @see CompositionLocal
126      * @see CompositionLocalContext
127      * @see ProvidableCompositionLocal
128      */
129     infix fun providesComputed(compute: CompositionLocalAccessorScope.() -> T) =
130         ProvidedValue(
131             compositionLocal = this,
132             value = null,
133             explicitNull = false,
134             mutationPolicy = null,
135             state = null,
136             compute = compute,
137             isDynamic = false
138         )
139 
140     override fun updatedStateOf(
141         value: ProvidedValue<T>,
142         previous: ValueHolder<T>?
143     ): ValueHolder<T> {
144         return when (previous) {
145             is DynamicValueHolder ->
146                 if (value.isDynamic) {
147                     previous.state.value = value.effectiveValue
148                     previous
149                 } else null
150             is StaticValueHolder ->
151                 if (value.isStatic && value.effectiveValue == previous.value) previous else null
152             is ComputedValueHolder -> if (value.compute === previous.compute) previous else null
153             else -> null
154         } ?: valueHolderOf(value)
155     }
156 
157     private fun valueHolderOf(value: ProvidedValue<T>): ValueHolder<T> =
158         when {
159             value.isDynamic ->
160                 DynamicValueHolder(
161                     value.state
162                         ?: mutableStateOf(
163                             value.value,
164                             value.mutationPolicy ?: structuralEqualityPolicy()
165                         )
166                 )
167             value.compute != null -> ComputedValueHolder(value.compute)
168             value.state != null -> DynamicValueHolder(value.state)
169             else -> StaticValueHolder(value.effectiveValue)
170         }
171 }
172 
173 /**
174  * A [DynamicProvidableCompositionLocal] is a [CompositionLocal] backed by [mutableStateOf].
175  * Providing new values using a [DynamicProvidableCompositionLocal] will provide the same [State]
176  * with a different value. Reading the [CompositionLocal] value of a
177  * [DynamicProvidableCompositionLocal] will record a read in the [RecomposeScope] of the
178  * composition. Changing the provided value will invalidate the [RecomposeScope]s.
179  *
180  * @see compositionLocalOf
181  */
182 internal class DynamicProvidableCompositionLocal<T>(
183     private val policy: SnapshotMutationPolicy<T>,
184     defaultFactory: () -> T
185 ) : ProvidableCompositionLocal<T>(defaultFactory) {
186 
defaultProvidedValuenull187     override fun defaultProvidedValue(value: T) =
188         ProvidedValue(
189             compositionLocal = this,
190             value = value,
191             explicitNull = value === null,
192             mutationPolicy = policy,
193             state = null,
194             compute = null,
195             isDynamic = true
196         )
197 }
198 
199 /**
200  * A [StaticProvidableCompositionLocal] is a value that is expected to rarely change.
201  *
202  * @see staticCompositionLocalOf
203  */
204 internal class StaticProvidableCompositionLocal<T>(defaultFactory: () -> T) :
205     ProvidableCompositionLocal<T>(defaultFactory) {
206 
207     override fun defaultProvidedValue(value: T) =
208         ProvidedValue(
209             compositionLocal = this,
210             value = value,
211             explicitNull = value === null,
212             mutationPolicy = null,
213             state = null,
214             compute = null,
215             isDynamic = false
216         )
217 }
218 
219 /**
220  * Create a [CompositionLocal] key that can be provided using [CompositionLocalProvider]. Changing
221  * the value provided during recomposition will invalidate the content of [CompositionLocalProvider]
222  * that read the value using [CompositionLocal.current].
223  *
224  * [compositionLocalOf] creates a [ProvidableCompositionLocal] which can be used in a a call to
225  * [CompositionLocalProvider]. Similar to [MutableList] vs. [List], if the key is made public as
226  * [CompositionLocal] instead of [ProvidableCompositionLocal], it can be read using
227  * [CompositionLocal.current] but not re-provided.
228  *
229  * @param policy a policy to determine when a [CompositionLocal] is considered changed. See
230  *   [SnapshotMutationPolicy] for details.
231  * @param defaultFactory a value factory to supply a value when a value is not provided. This
232  *   factory is called when no value is provided through a [CompositionLocalProvider] of the caller
233  *   of the component using [CompositionLocal.current]. If no reasonable default can be provided
234  *   then consider throwing an exception.
235  * @see CompositionLocal
236  * @see staticCompositionLocalOf
237  * @see mutableStateOf
238  */
compositionLocalOfnull239 fun <T> compositionLocalOf(
240     policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy(),
241     defaultFactory: () -> T
242 ): ProvidableCompositionLocal<T> = DynamicProvidableCompositionLocal(policy, defaultFactory)
243 
244 /**
245  * Create a [CompositionLocal] key that can be provided using [CompositionLocalProvider].
246  *
247  * Unlike [compositionLocalOf], reads of a [staticCompositionLocalOf] are not tracked by the
248  * composer and changing the value provided in the [CompositionLocalProvider] call will cause the
249  * entirety of the content to be recomposed instead of just the places where in the composition the
250  * local value is used. This lack of tracking, however, makes a [staticCompositionLocalOf] more
251  * efficient when the value provided is highly unlikely to or will never change. For example, the
252  * android context, font loaders, or similar shared values, are unlikely to change for the
253  * components in the content of a the [CompositionLocalProvider] and should consider using a
254  * [staticCompositionLocalOf]. A color, or other theme like value, might change or even be animated
255  * therefore a [compositionLocalOf] should be used.
256  *
257  * [staticCompositionLocalOf] creates a [ProvidableCompositionLocal] which can be used in a a call
258  * to [CompositionLocalProvider]. Similar to [MutableList] vs. [List], if the key is made public as
259  * [CompositionLocal] instead of [ProvidableCompositionLocal], it can be read using
260  * [CompositionLocal.current] but not re-provided.
261  *
262  * @param defaultFactory a value factory to supply a value when a value is not provided. This
263  *   factory is called when no value is provided through a [CompositionLocalProvider] of the caller
264  *   of the component using [CompositionLocal.current]. If no reasonable default can be provided
265  *   then consider throwing an exception.
266  * @see CompositionLocal
267  * @see compositionLocalOf
268  */
269 fun <T> staticCompositionLocalOf(defaultFactory: () -> T): ProvidableCompositionLocal<T> =
270     StaticProvidableCompositionLocal(defaultFactory)
271 
272 /**
273  * Create a [CompositionLocal] that behaves like it was provided using
274  * [ProvidableCompositionLocal.providesComputed] by default. If a value is provided using
275  * [ProvidableCompositionLocal.provides] it behaves as if the [CompositionLocal] was produced by
276  * calling [compositionLocalOf].
277  *
278  * In other words, a [CompositionLocal] produced by can be provided identically to
279  * [CompositionLocal] created with [compositionLocalOf] with the only difference is how it behaves
280  * when the value is not provided. For a [compositionLocalOf] the default value is returned. If no
281  * default value has be computed for [CompositionLocal] the default computation is called.
282  *
283  * The lambda passed to [compositionLocalWithComputedDefaultOf] will be invoked every time the
284  * [CompositionLocal.current] is evaluated for the composition local and computes its value based on
285  * the current value of the locals referenced in the lambda at the time [CompositionLocal.current]
286  * is evaluated. This allows providing values that can be derived from other locals. For example, if
287  * accent colors can be calculated from a single base color, the accent colors can be provided as
288  * computed composition locals. Providing a new base color would automatically update all the accent
289  * colors.
290  *
291  * @sample androidx.compose.runtime.samples.compositionLocalComputedByDefault
292  * @sample androidx.compose.runtime.samples.compositionLocalComputedAfterProvidingLocal
293  * @param defaultComputation the default computation to use when this [CompositionLocal] is not
294  *   provided.
295  * @see CompositionLocal
296  * @see ProvidableCompositionLocal
297  */
298 fun <T> compositionLocalWithComputedDefaultOf(
299     defaultComputation: CompositionLocalAccessorScope.() -> T
300 ): ProvidableCompositionLocal<T> = ComputedProvidableCompositionLocal(defaultComputation)
301 
302 internal class ComputedProvidableCompositionLocal<T>(
303     defaultComputation: CompositionLocalAccessorScope.() -> T
304 ) : ProvidableCompositionLocal<T>({ composeRuntimeError("Unexpected call to default provider") }) {
305     override val defaultValueHolder = ComputedValueHolder(defaultComputation)
306 
defaultProvidedValuenull307     override fun defaultProvidedValue(value: T): ProvidedValue<T> =
308         ProvidedValue(
309             compositionLocal = this,
310             value = value,
311             explicitNull = value === null,
312             mutationPolicy = null,
313             state = null,
314             compute = null,
315             isDynamic = true
316         )
317 }
318 
319 interface CompositionLocalAccessorScope {
320     /**
321      * An extension property that allows accessing the current value of a composition local in the
322      * context of this scope. This scope is the type of the `this` parameter when in a computed
323      * composition. Computed composition locals can be provided by either using
324      * [compositionLocalWithComputedDefaultOf] or by using the
325      * [ProvidableCompositionLocal.providesComputed] infix operator.
326      *
327      * @sample androidx.compose.runtime.samples.compositionLocalProvidedComputed
328      * @see ProvidableCompositionLocal
329      * @see ProvidableCompositionLocal.providesComputed
330      * @see ProvidableCompositionLocal.provides
331      * @see CompositionLocalProvider
332      */
333     val <T> CompositionLocal<T>.currentValue: T
334 }
335 
336 /**
337  * Stores [CompositionLocal]'s and their values.
338  *
339  * Can be obtained via [currentCompositionLocalContext] and passed to another composition via
340  * [CompositionLocalProvider].
341  *
342  * [CompositionLocalContext] is immutable and won't be changed after its obtaining.
343  */
344 @Stable
345 class CompositionLocalContext
346 internal constructor(internal val compositionLocals: PersistentCompositionLocalMap)
347 
348 /**
349  * [CompositionLocalProvider] binds values to [ProvidableCompositionLocal] keys. Reading the
350  * [CompositionLocal] using [CompositionLocal.current] will return the value provided in
351  * [CompositionLocalProvider]'s [values] parameter for all composable functions called directly or
352  * indirectly in the [content] lambda.
353  *
354  * @sample androidx.compose.runtime.samples.compositionLocalProvider
355  * @see CompositionLocal
356  * @see compositionLocalOf
357  * @see staticCompositionLocalOf
358  */
359 @Composable
360 @OptIn(InternalComposeApi::class)
361 @NonSkippableComposable
CompositionLocalProvidernull362 fun CompositionLocalProvider(vararg values: ProvidedValue<*>, content: @Composable () -> Unit) {
363     currentComposer.startProviders(values)
364     content()
365     currentComposer.endProviders()
366 }
367 
368 /**
369  * [CompositionLocalProvider] binds value to [ProvidableCompositionLocal] key. Reading the
370  * [CompositionLocal] using [CompositionLocal.current] will return the value provided in
371  * [CompositionLocalProvider]'s [value] parameter for all composable functions called directly or
372  * indirectly in the [content] lambda.
373  *
374  * @sample androidx.compose.runtime.samples.compositionLocalProvider
375  * @see CompositionLocal
376  * @see compositionLocalOf
377  * @see staticCompositionLocalOf
378  */
379 @Composable
380 @OptIn(InternalComposeApi::class)
381 @NonSkippableComposable
CompositionLocalProvidernull382 fun CompositionLocalProvider(value: ProvidedValue<*>, content: @Composable () -> Unit) {
383     currentComposer.startProvider(value)
384     content()
385     currentComposer.endProvider()
386 }
387 
388 /**
389  * [CompositionLocalProvider] binds values to [CompositionLocal]'s, provided by [context]. Reading
390  * the [CompositionLocal] using [CompositionLocal.current] will return the value provided in values
391  * stored inside [context] for all composable functions called directly or indirectly in the
392  * [content] lambda.
393  *
394  * @sample androidx.compose.runtime.samples.compositionLocalProvider
395  * @see CompositionLocal
396  * @see compositionLocalOf
397  * @see staticCompositionLocalOf
398  */
399 @Composable
CompositionLocalProvidernull400 fun CompositionLocalProvider(context: CompositionLocalContext, content: @Composable () -> Unit) {
401     CompositionLocalProvider(
402         *context.compositionLocals.map { it.value.toProvided(it.key) }.toTypedArray(),
403         content = content
404     )
405 }
406