Skip to content

Commit 5440ab7

Browse files
hoisieDagger Team
authored andcommitted
Internal changes
RELNOTES=n/a PiperOrigin-RevId: 641978383
1 parent e679774 commit 5440ab7

File tree

49 files changed

+6591
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+6591
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Copyright (C) 2023 The Dagger Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Description:
16+
# Hilt Android classes for Jetpack Compose.
17+
18+
load("//third_party/kotlin/build_extensions:rules.bzl", "kt_android_library")
19+
20+
package(default_visibility = ["//:src"])
21+
22+
java_library(
23+
name = "package_info",
24+
srcs = ["package-info.java"],
25+
)
26+
27+
kt_android_library(
28+
name = "retained_view_model_manager",
29+
srcs = ["RetainedViewModelManager.kt"],
30+
visibility = ["//visibility:private"],
31+
deps = [
32+
":remember_component_host",
33+
"//:dagger_with_compiler",
34+
"//third_party/java/androidx/activity",
35+
"//third_party/java/androidx/lifecycle",
36+
],
37+
)
38+
39+
kt_android_library(
40+
name = "component_host_creator",
41+
srcs = ["ComponentHostCreator.kt"],
42+
)
43+
44+
kt_android_library(
45+
name = "compose_component_host",
46+
srcs = ["ComposeComponentHost.kt"],
47+
exported_plugins = [
48+
"//java/dagger/hilt/android/processor/internal/compose/composecomponenthost:processor",
49+
],
50+
exports = [
51+
":component_host_creator",
52+
":compose_component_host_extras",
53+
":retained_view_model_manager",
54+
"//:dagger_with_compiler",
55+
"//java/dagger/hilt:install_in",
56+
"//java/dagger/hilt/android/components",
57+
"//java/dagger/hilt/android/compose/components",
58+
"//java/dagger/hilt/android/compose/internal",
59+
"//java/dagger/hilt/android/compose/internal/builders",
60+
"//java/dagger/hilt/codegen:originating_element",
61+
"//java/dagger/hilt/internal:generated_entry_point",
62+
],
63+
deps = [
64+
"//java/dagger/hilt:generates_root_input",
65+
],
66+
)
67+
68+
kt_android_library(
69+
name = "compose_component_host_extras",
70+
srcs = ["ComposeComponentHostExtras.kt"],
71+
deps = ["//java/dagger/hilt/android/internal"],
72+
)
73+
74+
kt_android_library(
75+
name = "compose_retained_lifecycle",
76+
srcs = ["ComposeRetainedLifecycle.kt"],
77+
deps = ["//java/dagger/hilt/android/lifecycle:retained_lifecycle"],
78+
)
79+
80+
kt_android_library(
81+
name = "compose_retained_provided",
82+
srcs = ["ComposeRetainedProvided.kt"],
83+
exported_plugins = [
84+
"//java/dagger/hilt/android/processor/internal/compose/composeretainedprovided:processor",
85+
],
86+
exports = [
87+
"//:dagger_with_compiler",
88+
"//java/dagger/hilt:install_in",
89+
"//java/dagger/hilt/android/compose/components",
90+
"//java/dagger/hilt/android/compose/internal/qualifiers",
91+
"//java/dagger/hilt/codegen:originating_element",
92+
"//java/dagger/hilt/internal:generated_entry_point",
93+
],
94+
)
95+
96+
kt_android_library(
97+
name = "remember_component_host",
98+
srcs = ["RememberComponentHost.kt"],
99+
deps = [
100+
":component_host_creator",
101+
":compose_component_host_extras",
102+
":compose_retained_lifecycle",
103+
":compose_retained_provided",
104+
"//:dagger_with_compiler",
105+
"//java/dagger/hilt:entry_point",
106+
"//java/dagger/hilt:install_in",
107+
"//java/dagger/hilt/android/compose/components",
108+
"//java/dagger/hilt/android/compose/internal",
109+
"//java/dagger/hilt/android/compose/scopes",
110+
"//java/dagger/hilt/android/internal",
111+
"//java/dagger/hilt/android/internal/lifecycle",
112+
"//third_party/java/androidx/compose/runtime",
113+
"//third_party/java/androidx/compose/ui",
114+
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
115+
"@maven//:androidx_lifecycle_lifecycle_viewmodel_compose",
116+
],
117+
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (C) 2023 The Dagger Authors.
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 dagger.hilt.android.compose
18+
19+
/**
20+
* Provides a way to retrieve the given ComponentHost type from an appropriate component.
21+
*
22+
* This class should never be used on its own. It should always be used with [rememberComponentHost]
23+
* to ensure that the lifecycle of the given host is correct.
24+
*
25+
* The annotation processor will generate appropriate classes to ensure that it's possible to inject
26+
* `ComponentHostCreator<SpecificHost>`.
27+
*
28+
* @param HostT the type annotated with [ComposeComponentHost], which is used here to differentiate one
29+
* ComponentHostCreator from another.
30+
*/
31+
interface ComponentHostCreator<out HostT>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (C) 2023 The Dagger Authors.
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 dagger.hilt.android.compose
18+
19+
import dagger.hilt.GeneratesRootInput
20+
21+
/**
22+
* Annotation used to indicate that the annotated type hosts the Compose and ComposeRetained Dagger
23+
* components.
24+
*
25+
* See the following example on how to use `@ComposeComponentHost`:
26+
* ```
27+
* /** Hosts the MyScreen Composable. Hilt_MyHost is generated and must be the super type. */
28+
* @ComposeComponentHost
29+
* class MyHost @Inject internal constructor(dependency: MyInjectedDependency) : Hilt_MyHost {
30+
*
31+
* @Composable
32+
* fun MyScreen(modifier: Modifier = Modifier) {
33+
* // Define MyScreen, using data from the injected dependency
34+
* }
35+
* }
36+
* ```
37+
*
38+
* `MyHost` is annotated with `@ComposeComponentHost`, so Hilt generates a
39+
* `ComponentHostCreator<MyHost>` and provides a binding for it. `MyHost` is injected and used as
40+
* follows:
41+
* ```
42+
* @AndroidEntryPoint(ComponentActivity::class)
43+
* class HomeActivity: Hilt_HomeActivity() {
44+
* @Inject lateinit var myHostCreator: ComponentHostCreator<MyHost>
45+
*
46+
* override fun onCreate(bundle: Bundle?) {
47+
* super.onCreate(bundle)
48+
* setContent {
49+
* // myHostCreator must be used with rememberComponentHost to have the correct lifecycle
50+
* val myHost = rememberComponentHost(myHostCreator)
51+
* myHost.MyScreen()
52+
* }
53+
* }
54+
* }
55+
* ```
56+
*
57+
* As with other Hilt components, bindings can be scoped to either the ComposeComponent or
58+
* ComposeRetainedComponent by using the appropriate scope annotation:
59+
* [dagger.hilt.android.compose.scopes.ComposeScoped] for the ComposeComponent and
60+
* [dagger.hilt.android.compose.scopes.ComposeRetainedScoped] for the ComposeRetainedComponent.
61+
* Annotating a binding as such results in Hilt providing the same instance of that binding every
62+
* time it's requested in the corresponding component. For example:
63+
* ```
64+
* /**
65+
* * Because ComposeScopedDependency is @ComposeScoped,
66+
* * firstDependency.scopedDependency === secondDependency.scopedDependency.
67+
* */
68+
* @ComposeComponentHost
69+
* class MyHost @Inject internal constructor(
70+
* private val firstDependency: FirstDependency,
71+
* private val secondDependency: SecondDependency
72+
* ) {...}
73+
*
74+
* class FirstDependency @Inject constructor(private val scopedDependency: ComposeScopedDependency)
75+
* class SecondDependency @Inject constructor(private val scopedDependency: ComposeScopedDependency)
76+
*
77+
* @ComposeScoped
78+
* class ComposeScopedDependency @Inject constructor()
79+
* ```
80+
*
81+
* The equivalent applies to `@ComposeRetainedScoped` annotated bindings, however additional
82+
* machinery is needed. See the documentation on
83+
* [dagger.hilt.android.compose.ComposeRetainedProvided] for details.
84+
*/
85+
@Target(AnnotationTarget.CLASS)
86+
@Retention(AnnotationRetention.BINARY)
87+
@GeneratesRootInput
88+
annotation class ComposeComponentHost
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright (C) 2023 The Dagger Authors.
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 dagger.hilt.android.compose
18+
19+
import dagger.hilt.android.internal.ThreadUtil
20+
21+
/**
22+
* Read only version of extras provided to a ComposeComponentHost.
23+
*
24+
* Use [buildComposeComponentHostExtras] to create an instance of ComposeComponentHostExtras.
25+
*
26+
* ComposeComponentHostExtras support a specific use case and should not replace alternate means of
27+
* providing objects to a host:
28+
* - Objects that are part of the Dagger graph should be injected directly where they're used.
29+
* - Objects that aren't part of the Dagger graph can be provided through ComposeComponentHostExtras
30+
* if they're used in enough places to benefit from making them globally accessible in the
31+
* ComposeComponent and ComposeRetainedComponent.
32+
* - Objects that are not used in enough places to warrant use of ComposeComponentHostExtras can be
33+
* passed as parameters to `@Composable` functions.
34+
*/
35+
class ComposeComponentHostExtras internal constructor(private val keyToExtra: Map<Key<*>, Any>) {
36+
37+
/** Returns the argument associated with the given key, if available. */
38+
@Suppress("UNCHECKED_CAST") // extras can only be inserted with a type that matches the key
39+
fun <T> get(key: Key<T>): T? = keyToExtra[key] as T
40+
41+
/**
42+
* Represents the key for a given argument.
43+
*
44+
* Key subclasses require no implementation and should generally be implemented as a Kotlin
45+
* object. The generic type parameter should be set as the type of the argument. Example key for a
46+
* specific argument of type String:
47+
* ```kotlin
48+
* object MyStringKey: Key<String>
49+
* ```
50+
*/
51+
interface Key<out T>
52+
53+
override fun equals(other: Any?): Boolean {
54+
if (this === other) return true
55+
if (other !is ComposeComponentHostExtras) return false
56+
return keyToExtra == other.keyToExtra
57+
}
58+
59+
override fun hashCode(): Int = keyToExtra.hashCode()
60+
}
61+
62+
/**
63+
* Builds a new instance of [ComposeComponentHostExtras] by populating a
64+
* [MutableComposeComponentHostExtras] instance using the given [builderAction].
65+
*
66+
* Build and use the extras in a host with the following:
67+
* ```kotlin
68+
* @Composable
69+
* fun MyContent() {
70+
* val extras = buildComposeComponentHostExtras {
71+
* put(MyStringKey, "someStringExtra")
72+
* put(MyIntKey, 5)
73+
* put(MyBooleanKey, true)
74+
* }
75+
*
76+
* val host = rememberComponentHost(myHost, extras)
77+
* }
78+
* ```
79+
*/
80+
fun buildComposeComponentHostExtras(
81+
builderAction: MutableComposeComponentHostExtras.() -> Unit
82+
): ComposeComponentHostExtras {
83+
ThreadUtil.ensureMainThread()
84+
return MutableComposeComponentHostExtras().apply { this.builderAction() }.build()
85+
}
86+
87+
/**
88+
* The write-only version of extras provided to a ComposeComponentHost.
89+
*
90+
* For all [put] methods, calling the method multiple times with the same key will overwrite the
91+
* stored value. For example:
92+
* ```kotlin
93+
* @Composable fun Content() {
94+
* val extras = buildComposeComponentHostExtras {
95+
* put(SomeStringKey, "hello") // "hello" is associated with SomeStringKey
96+
* put(SomeStringKey, "world") // now "world" is associated with SomeStringKey
97+
* }
98+
* }
99+
* ```
100+
*/
101+
class MutableComposeComponentHostExtras internal constructor() {
102+
private val keyToExtra: MutableMap<ComposeComponentHostExtras.Key<*>, Any> = mutableMapOf()
103+
104+
fun put(key: ComposeComponentHostExtras.Key<Int>, value: Int) {
105+
keyToExtra[key] = value
106+
}
107+
108+
fun put(key: ComposeComponentHostExtras.Key<Long>, value: Long) {
109+
keyToExtra[key] = value
110+
}
111+
112+
fun put(key: ComposeComponentHostExtras.Key<Float>, value: Float) {
113+
keyToExtra[key] = value
114+
}
115+
116+
fun put(key: ComposeComponentHostExtras.Key<Double>, value: Double) {
117+
keyToExtra[key] = value
118+
}
119+
120+
fun put(key: ComposeComponentHostExtras.Key<Boolean>, value: Boolean) {
121+
keyToExtra[key] = value
122+
}
123+
124+
fun put(key: ComposeComponentHostExtras.Key<String>, value: String) {
125+
keyToExtra[key] = value
126+
}
127+
128+
// TODO: b/303256918 - Also support immutable data types and protos
129+
130+
internal fun build() = ComposeComponentHostExtras(keyToExtra)
131+
}

0 commit comments

Comments
 (0)