Chore: migrate DI from Koin to Metro (RND-1987)#2961
Open
StylianosGakis wants to merge 57 commits into
Open
Conversation
The deps were gated on configurationName == "implementation", which is also the path pure-JVM (hedvig.jvm.library) modules take, so ~33 JVM modules pulled the Compose-bearing metrox-viewmodel-compose artifact. Gate on the Android Gradle plugin instead so only Android modules — the ones that host ViewModels resolved through the factory — receive them.
Metro's compiler plugin rejects language version 2.2; the compiler was already bumped to 2.3.21 but the convention plugins still pinned the language/api version to 2.2.
…composition local Adds the Metro @DependencyGraph (AppGraph extending ViewModelGraph), an AppGraphInitializer Startup entry that builds the graph and stores it in AppGraphHolder, and wires LocalMetroViewModelFactory into the Compose tree via CompositionLocalProvider. Koin is untouched and coexists with Metro throughout PR1.
Add @ContributesBinding/@SingleIn/@Inject to impl classes in data-addons, data-changetier, data-cross-sell-after-claim-closed, and data-cross-sell-after-flow. Koin module files are untouched (coexistence).
…rs/logging DI to Metro
Lets @ContributesBinding/@Inject impls (and their helper interfaces) stay `internal` while still merging into the :app graph. Metro then generates top-level @provides returning only the bound type instead of @BINDS shorthands, so the merge site never needs to reference the internal impl class directly. Without this flag an internal contributed class is silently dropped and only fails at full-graph compile time. Requires Metro >= 0.13.0 and Kotlin >= 2.3.20 (on 1.1.1 / 2.3.21). Verified by merging an internal cross-module binding into :app:compileDebugKotlin.
…language-data DI to Metro
…oose-tier/insurance-certificate/chip-id DI to Metro
…-account/terminate-insurance DI to Metro
…tly/notification-badge/tier-comparison DI to Metro
…e-model/language-migration/demo-mode/forever-ui DI to Metro
…ificate/travel-certificate/payout-account ViewModels to Metro
…ewModels to Metro
Wires the Android-only @DatabaseFile File binding for the Metro graph, mirroring the Koin databaseChatAndroidModule. The @iodispatcher and @BaseHttpClient providers live in commonMain (core-common, network-clients) and are deferred to the KMP graph task; Qualifier.kt deletion is deferred to Koin removal since Koin modules still reference the string qualifiers.
Introduces ChildWorkerFactory + @workerkey multibinding infra in core-common-public/androidMain, converts FCMTokenUploadWorker to assisted injection contributing into the worker map, and adds MetroWorkerFactory plus an AppGraph accessor. The worker constructor keeps its signature so Koin's worker DSL still builds it during coexistence; wiring the factory into the Application's Configuration.Provider is deferred to Koin removal.
Add @ContributesBinding/@SingleIn/@Inject to interface-backed use-case impls across 11 KMP modules so they merge into the Metro graph alongside the existing Koin bindings during coexistence. Purely additive — Koin modules untouched.
Add Metro multibinding annotations to the 10 commonMain ViewModels in feature-help-center, feature-remove-addons and feature-claim-chat: no-arg VMs get @Inject/@ViewModelKey/@ContributesIntoMap; parameterized VMs get @AssistedInject with a nested ManualViewModelAssistedFactory. Add metrox-viewmodel to each commonMain so the annotations resolve on the iOS/native classpath too. Koin call sites untouched (coexistence).
Mirrors the existing Koin modules with @ContributesTo(AppScope) Metro providers so both the Android AppGraph and the iOS IosGraph can resolve ApplicationScope, IO dispatcher, the Ktor/Apollo network chain, and the platform DataStore<Preferences>. Koin modules kept intact for coexistence.
Introduce IosGraph (Metro @DependencyGraph) for the iOS side, wired through IosDiHolder in design-system-hedvig to avoid a circular dependency with feature modules. Convert iOS-reachable ViewModel call sites (help-center, claim-chat, remove-addons) to metroViewModel/ assistedMetroViewModel, and add native Metro bindings for FileService and AudioRecordingManager. Koin still runs alongside Metro on iOS for not-yet-flipped call sites.
Delete all Koin DI modules and the koin-bom auto-injection, removing the koin dependencies from the version catalog. Resolve the resulting Metro MissingBinding errors at the :app graph root by widening the four demo/prod providers consumed there (paying-member, missed-payment, chat repository, insurance contracts) to the data-addons idiom: public provider interfaces, internal impls bound via @ContributesBinding, and public demo classes. Expose room.runtime and the AppDatabase/ChatDao-bearing modules via api so Metro can resolve RoomDatabase.Builder<AppDatabase> when reading the generated database factory from :app.
Mechanical line wraps to satisfy max-line-length (120) now enforced by the bumped ktlint, plus annotation-spacing fixes from ktlintFormat.
Replace the two process-global graph holders (AppGraphHolder and the MetroGraphHolder object) with a single source of truth: the graph lives on HedvigApplication. :app-internal callers read the typed `appGraph`; feature modules reach it through the new MetroGraphProvider interface and cast to their own @ContributesTo entry point, exactly as before.
Construct the prod and demo implementations inline inside the Metro @provides factories instead of contributing them as bindings. Only the factory needs the impls, so they (and their ProdOrDemoProviders) can drop their DI annotations and become internal, keeping GraphQL/impl details out of cross-module visibility.
Construct GetHomeDataUseCase prod/demo impls inline in the Metro @provides factory and make them (plus the provider and SeenImportantMessagesStorageImpl) internal, so the impls are no longer exposed across the module boundary.
Construct the prod and demo ContactInfoRepository impls inline in the Metro @provides factory and make them and ProfileRepositoryProvider internal.
Construct the prod and demo ForeverRepository impls inline in the Metro @provides factory and make them and ForeverRepositoryProvider internal.
Construct the prod and demo GetCrossSellSheetDataUseCase impls inline in the Metro @provides factory and make them internal.
…-to-metro-start-crush-fix Bugfix: bind MoleculeViewModels as ViewModel and complete Metro wiring
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates the entire app's dependency injection from Koin to Metro (compiler-plugin DI). This is PR1 of a two-PR stack; PR2 will migrate Navigation2 → Navigation3 on top of this. Navigation is unchanged here.
Stacked on top of
eng/metro-nav3-pr0-kotlin-bump(Kotlin 2.3.21 bump, a Metro prerequisite).What changed
AppGraph(:app, Android) andIosGraph(:shareddi, iOS), both@DependencyGraph(AppScope::class).@Inject+@ContributesBinding(AppScope::class); singletons via@SingleIn(AppScope::class).@ContributesIntoMapmultibinding; parameterized ViewModels via@AssistedInject+@AssistedFactorykeyed factories.@Providesfunctions on public@ContributesTo(AppScope::class)provider interfaces.@Qualifierannotations.WorkerFactorynow Metro-multibound.Coordinated iOS change (ugglan/)
The iOS bootstrap entry point changes from
initKoin(...)→initDiGraph(...). The Swift side (ugglan/) must be updated in lockstep when this lands.Test plan
./gradlew ktlintCheck— green./gradlew :app:assembleDebug— green./gradlew testDebugUnitTest— green./gradlew :shareddi:compileKotlinIosSimulatorArm64— green