| /* |
| * Copyright 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.compose.runtime |
| |
| /** |
| * Compose passes data through the composition tree explicitly through means of parameters to |
| * composable functions. This is often times the simplest and best way to have data flow through |
| * the tree. |
| * |
| * Sometimes this model can be cumbersome or break down for data that is needed by lots of |
| * components, or when components need to pass data between one another but keep that implementation |
| * detail private. For these cases, [CompositionLocal]s can be used as an implicit way to have data |
| * flow through a composition. |
| * |
| * [CompositionLocal]s by their nature are hierarchical. They make sense when the value of the |
| * [CompositionLocal] needs to be scoped to a particular sub-hierarchy of the composition. |
| * |
| * One must create a [CompositionLocal] instance, which can be referenced by the consumers |
| * statically. [CompositionLocal] instances themselves hold no data, and can be thought of as a |
| * type-safe identifier for the data being passed down a tree. [CompositionLocal] factory functions |
| * take a single parameter: a factory to create a default value in cases where a [CompositionLocal] |
| * is used without a Provider. If this is a situation you would rather not handle, you can throw |
| * an error in this factory. |
| * |
| * @sample androidx.compose.runtime.samples.createCompositionLocal |
| * |
| * Somewhere up the tree, a [CompositionLocalProvider] component can be used, which provides a value for the |
| * [CompositionLocal]. This would often be at the "root" of a tree, but could be anywhere, and can |
| * also be used in multiple places to override the provided value for a sub-tree. |
| * |
| * @sample androidx.compose.runtime.samples.compositionLocalProvider |
| * |
| * Intermediate components do not need to know about the [CompositionLocal] value, and can have zero |
| * dependencies on it. For example, `SomeScreen` might look like this: |
| * |
| * @sample androidx.compose.runtime.samples.someScreenSample |
| * |
| * Finally, a component that wishes to consume the [CompositionLocal] value can use the [current] |
| * property of the [CompositionLocal] key which returns the current value of the |
| * [CompositionLocal], and subscribes the component to changes of it. |
| * |
| * @sample androidx.compose.runtime.samples.consumeCompositionLocal |
| */ |
| @Stable |
| sealed class CompositionLocal<T> constructor(defaultFactory: (() -> T)? = null) { |
| @Suppress("UNCHECKED_CAST") |
| internal val defaultValueHolder = LazyValueHolder(defaultFactory) |
| |
| @Composable |
| internal abstract fun provided(value: T): State<T> |
| |
| /** |
| * Return the value provided by the nearest [CompositionLocalProvider] component that invokes, directly or |
| * indirectly, the composable function that uses this property. |
| * |
| * @sample androidx.compose.runtime.samples.consumeCompositionLocal |
| */ |
| @OptIn(InternalComposeApi::class) |
| inline val current: T |
| @ReadOnlyComposable |
| @Composable |
| get() = currentComposer.consume(this) |
| } |
| |
| /** |
| * A [ProvidableCompositionLocal] can be used in [CompositionLocalProvider] to provide values. |
| * |
| * @see compositionLocalOf |
| * @see staticCompositionLocalOf |
| * @see CompositionLocal |
| * @see CompositionLocalProvider |
| */ |
| @Stable |
| abstract class ProvidableCompositionLocal<T> internal constructor(defaultFactory: (() -> T)?) : |
| CompositionLocal<T> (defaultFactory) { |
| |
| /** |
| * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider]. |
| * |
| * @see CompositionLocal |
| * @see ProvidableCompositionLocal |
| */ |
| @Suppress("UNCHECKED_CAST") |
| infix fun provides(value: T) = ProvidedValue(this, value, true) |
| |
| /** |
| * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider] if the key does not |
| * already have an associated value. |
| * |
| * @see CompositionLocal |
| * @see ProvidableCompositionLocal |
| */ |
| @Suppress("UNCHECKED_CAST") |
| infix fun providesDefault(value: T) = ProvidedValue(this, value, false) |
| } |
| |
| /** |
| * A [DynamicProvidableCompositionLocal] is a [CompositionLocal] backed by [mutableStateOf]. |
| * Providing new values using a [DynamicProvidableCompositionLocal] will provide the same [State] |
| * with a different value. Reading the [CompositionLocal] value of a |
| * [DynamicProvidableCompositionLocal] will record a read in the [RecomposeScope] of the |
| * composition. Changing the provided value will invalidate the [RecomposeScope]s. |
| * |
| * @see compositionLocalOf |
| */ |
| internal class DynamicProvidableCompositionLocal<T> constructor( |
| private val policy: SnapshotMutationPolicy<T>, |
| defaultFactory: (() -> T)? |
| ) : ProvidableCompositionLocal<T>(defaultFactory) { |
| |
| @Composable |
| override fun provided(value: T): State<T> = remember { mutableStateOf(value, policy) }.apply { |
| this.value = value |
| } |
| } |
| |
| /** |
| * A [StaticProvidableCompositionLocal] is a value that is expected to rarely change. |
| * |
| * @see staticCompositionLocalOf |
| */ |
| internal class StaticProvidableCompositionLocal<T>(defaultFactory: (() -> T)?) : |
| ProvidableCompositionLocal<T>(defaultFactory) { |
| |
| @Composable |
| override fun provided(value: T): State<T> = StaticValueHolder(value) |
| } |
| |
| /** |
| * Create a [CompositionLocal] key that can be provided using [CompositionLocalProvider]. Changing the value |
| * provided during recomposition will invalidate the children of [CompositionLocalProvider] that read the value |
| * using [CompositionLocal.current]. |
| * |
| * @param policy a policy to determine when a [CompositionLocal] is considered changed. See |
| * [SnapshotMutationPolicy] for details. |
| * |
| * @see CompositionLocal |
| * @see staticCompositionLocalOf |
| * @see mutableStateOf |
| */ |
| fun <T> compositionLocalOf( |
| policy: SnapshotMutationPolicy<T> = |
| @OptIn(ExperimentalComposeApi::class) |
| structuralEqualityPolicy(), |
| defaultFactory: (() -> T)? = null |
| ): ProvidableCompositionLocal<T> = DynamicProvidableCompositionLocal(policy, defaultFactory) |
| |
| /** |
| * Create a [CompositionLocal] key that can be provided using [CompositionLocalProvider]. Changing the value |
| * provided will cause the entire tree below [CompositionLocalProvider] to be recomposed, disabling skipping of |
| * composable calls. |
| * |
| * A static [CompositionLocal] should be only be used when the value provided is highly unlikely to |
| * change. |
| * |
| * @see CompositionLocal |
| * @see compositionLocalOf |
| */ |
| fun <T> staticCompositionLocalOf(defaultFactory: (() -> T)? = null): ProvidableCompositionLocal<T> = |
| StaticProvidableCompositionLocal(defaultFactory) |
| |
| /** |
| * [CompositionLocalProvider] binds values to [ProvidableCompositionLocal] keys. Reading the [CompositionLocal] |
| * using [CompositionLocal.current] will return the value provided in [CompositionLocalProvider]'s [values] |
| * parameter for all composable functions called directly or indirectly in the [content] lambda. |
| * |
| * @sample androidx.compose.runtime.samples.compositionLocalProvider |
| * |
| * @see CompositionLocal |
| * @see compositionLocalOf |
| * @see staticCompositionLocalOf |
| */ |
| @Composable |
| @OptIn(InternalComposeApi::class) |
| fun CompositionLocalProvider(vararg values: ProvidedValue<*>, content: @Composable () -> Unit) { |
| currentComposer.startProviders(values) |
| content() |
| currentComposer.endProviders() |
| } |