Skip to content

Commit 74b0e2f

Browse files
committed
DNM: Convert the :sample app to Metro
**DO NOT MERGE:** Metro's aggregation (Anvil) features are not working for other KMP targets than JVM/Android yet. This maybe will be resolved in Kotlin 2.3: https://youtrack.jetbrains.com/issue/KT-75865 This PR, nonetheless, is a proof of concept of using Metro with App Platform in an application and how a migration could look like. Migrate the `:sample` app from kotlin-inject to Metro. This change also renames "component" interfaces to "graph" interfaces. Fixes #127
1 parent 9d0ce13 commit 74b0e2f

File tree

58 files changed

+338
-329
lines changed

Some content is hidden

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

58 files changed

+338
-329
lines changed

sample/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugins {
1212
// This extension comes from our published plugin.
1313
appPlatform {
1414
enableComposeUi true
15-
enableKotlinInject true
15+
enableMetro true
1616
enableModuleStructure true
1717
enableMoleculePresenters true
1818
addImplModuleDependencies true

sample/app/src/androidInstrumentedTest/kotlin/software/amazon/app/platform/sample/TestAndroidAppComponent.kt

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package software.amazon.app.platform.sample
2+
3+
import android.app.Application
4+
import dev.zacsweers.metro.AppScope
5+
import dev.zacsweers.metro.DependencyGraph
6+
import dev.zacsweers.metro.Provides
7+
import software.amazon.app.platform.scope.RootScopeProvider
8+
9+
/** Metro graph that is used in instrumented tests. */
10+
@DependencyGraph(AppScope::class)
11+
interface TestAndroidAppGraph {
12+
/** The factory to create a new instance of [AndroidAppGraph]. */
13+
@DependencyGraph.Factory
14+
fun interface Factory {
15+
/**
16+
* Creates a new [AndroidAppGraph] instance. [application] and [rootScopeProvider] are provided
17+
* in the [AndroidAppGraph] and can be injected.
18+
*/
19+
fun create(
20+
@Provides application: Application,
21+
@Provides rootScopeProvider: RootScopeProvider,
22+
): TestAndroidAppGraph
23+
}
24+
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package software.amazon.app.platform.sample
22

3+
import dev.zacsweers.metro.createGraphFactory
4+
35
/**
46
* Application class that is used in instrumented tests. Note that it provides a
57
* [TestAndroidApplication] instead of [AndroidApplication].
68
*/
79
class TestAndroidApplication : AndroidApplication() {
8-
override fun component(demoApplication: DemoApplication): AppComponent {
9-
return TestAndroidAppComponent::class.create(this, demoApplication)
10+
override fun metroGraph(demoApplication: DemoApplication): AppGraph {
11+
return createGraphFactory<TestAndroidAppGraph.Factory>().create(this, demoApplication)
1012
}
1113
}

sample/app/src/androidMain/kotlin/software/amazon/app/platform/sample/AndroidAppComponent.kt

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package software.amazon.app.platform.sample
2+
3+
import android.app.Application
4+
import dev.zacsweers.metro.AppScope
5+
import dev.zacsweers.metro.DependencyGraph
6+
import dev.zacsweers.metro.Provides
7+
import software.amazon.app.platform.scope.RootScopeProvider
8+
9+
/**
10+
* The final Android app graph.
11+
*
12+
* Note that [Application] is an Android specific type and classes living in the Android source
13+
* folder can therefore inject [Application].
14+
*/
15+
@DependencyGraph(AppScope::class)
16+
interface AndroidAppGraph {
17+
/** The factory to create a new instance of [AndroidAppGraph]. */
18+
@DependencyGraph.Factory
19+
fun interface Factory {
20+
/**
21+
* Creates a new [AndroidAppGraph] instance. [application] and [rootScopeProvider] are provided
22+
* in the [AndroidAppGraph] and can be injected.
23+
*/
24+
fun create(
25+
@Provides application: Application,
26+
@Provides rootScopeProvider: RootScopeProvider,
27+
): AndroidAppGraph
28+
}
29+
}

sample/app/src/androidMain/kotlin/software/amazon/app/platform/sample/AndroidApplication.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package software.amazon.app.platform.sample
22

33
import android.app.Application
4+
import dev.zacsweers.metro.createGraphFactory
45
import software.amazon.app.platform.scope.RootScopeProvider
56
import software.amazon.app.platform.scope.Scope
67

@@ -16,12 +17,12 @@ open class AndroidApplication : Application(), RootScopeProvider {
1617
get() = demoApplication.rootScope
1718

1819
override fun onCreate() {
19-
demoApplication.create(component(demoApplication))
20+
demoApplication.create(metroGraph(demoApplication))
2021
super.onCreate()
2122
}
2223

23-
/** Create the [AppComponent]. In UI tests we use a different instance. */
24-
protected open fun component(demoApplication: DemoApplication): AppComponent {
25-
return AndroidAppComponent::class.create(this, demoApplication)
24+
/** Create the [AppGraph]. In UI tests we use a different instance. */
25+
protected open fun metroGraph(demoApplication: DemoApplication): AppGraph {
26+
return createGraphFactory<AndroidAppGraph.Factory>().create(this, demoApplication)
2627
}
2728
}

sample/app/src/androidMain/kotlin/software/amazon/app/platform/sample/MainActivityViewModel.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,21 @@ package software.amazon.app.platform.sample
22

33
import android.app.Application
44
import androidx.lifecycle.AndroidViewModel
5+
import dev.zacsweers.metro.AppScope
6+
import dev.zacsweers.metro.ContributesTo
57
import kotlinx.coroutines.flow.StateFlow
68
import software.amazon.app.platform.sample.template.SampleAppTemplate
79
import software.amazon.app.platform.scope.RootScopeProvider
8-
import software.amazon.app.platform.scope.di.kotlinInjectComponent
9-
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
10-
import software.amazon.lastmile.kotlin.inject.anvil.ContributesTo
10+
import software.amazon.app.platform.scope.di.metro.metroDependencyGraph
1111

1212
/**
1313
* `ViewModel` that hosts the stream of templates and survives configuration changes. Note that we
1414
* use [application] to get access to the root scope.
1515
*/
1616
class MainActivityViewModel(application: Application) : AndroidViewModel(application) {
1717

18-
private val component =
19-
(application as RootScopeProvider).rootScope.kotlinInjectComponent<Component>()
20-
private val templateProvider = component.templateProviderFactory.createTemplateProvider()
18+
private val graph = (application as RootScopeProvider).rootScope.metroDependencyGraph<Graph>()
19+
private val templateProvider = graph.templateProviderFactory.createTemplateProvider()
2120

2221
/** The stream of templates that are rendered by [MainActivity]. */
2322
val templates: StateFlow<SampleAppTemplate> = templateProvider.templates
@@ -26,9 +25,9 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica
2625
templateProvider.cancel()
2726
}
2827

29-
/** Component interface to give us access to objects from the app component. */
28+
/** Graph interface to give us access to objects from the app graph. */
3029
@ContributesTo(AppScope::class)
31-
interface Component {
30+
interface Graph {
3231
/** Gives access to the [TemplateProvider.Factory] from the object graph. */
3332
val templateProviderFactory: TemplateProvider.Factory
3433
}

sample/app/src/commonMain/kotlin/software/amazon/app/platform/sample/AppComponent.kt

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package software.amazon.app.platform.sample
2+
3+
import dev.zacsweers.metro.AppScope
4+
import dev.zacsweers.metro.ContributesTo
5+
import dev.zacsweers.metro.ForScope
6+
import dev.zacsweers.metro.Multibinds
7+
import software.amazon.app.platform.scope.Scoped
8+
import software.amazon.app.platform.scope.coroutine.CoroutineScopeScoped
9+
10+
/**
11+
* Shared interface for the app graph. The final graphs live in the platform specific source folders
12+
* in order to have access to platform specific code.
13+
*/
14+
@ContributesTo(AppScope::class)
15+
interface AppGraph {
16+
/** All [Scoped] instances part of the app scope. */
17+
@ForScope(AppScope::class) @Multibinds(allowEmpty = true) val appScopedInstances: Set<Scoped>
18+
19+
/** The coroutine scope that runs as long as the app scope is alive. */
20+
@ForScope(AppScope::class) val appScopeCoroutineScopeScoped: CoroutineScopeScoped
21+
}

0 commit comments

Comments
 (0)