Bugfix: bind MoleculeViewModels as ViewModel and complete Metro wiring#2962
Merged
StylianosGakis merged 6 commits intoJun 2, 2026
Conversation
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.
6b98c6c
into
eng/metro-nav3-pr1-koin-to-metro
3 of 4 checks passed
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.
After the Koin→Metro migration, the app crashed on startup:
Root cause
Metro's
@ContributesIntoMapinfers the bound type from a class's single declared supertype. Our ViewModels extendMoleculeViewModel<Event, State>, so they were contributed asMoleculeViewModel<…>instead ofViewModel— and never landed in theMap<KClass<out ViewModel>, () -> ViewModel>thatMetroViewModelFactoryreads. They were silently dropped, then crashed when first requested. 40 ViewModels were affected (assisted-factory ViewModels were not, since they bind via a factory interface).Fixing that surfaced a second layer: because the dropped ViewModels were never validated, the graph compiled despite genuinely missing dependency bindings. Once the VMs were correctly in the graph, Metro reported 10 MissingBinding errors.
Decisions
binding<ViewModel>()— per Metro's docs, a ViewModel that extends an intermediate base must specify the bound type explicitly. Applied to all 40 MoleculeViewModel subclasses.Provider<UseCase>bindings couldn't feed the single shared AppGraph (:app can only reference public types). Graph extensions were considered but rejected: a parent graph can't see child-extension bindings, andMetroViewModelFactorylives in the parent — so they'd require re-architecting how every screen resolves its ViewModel. Instead we made the relevant use cases/repositories + their providers public, matching the existing pattern (cross-sell already worked because its model lives in a public module).ApplicationScopeover rawCoroutineScope— HomeViewModel was the lone outlier injecting CoroutineScope; switched to ApplicationScope like the rest of the codebase.SavedStateHandle—SavedStateHandleis only available via CreationExtras at creation time, not as a graph binding, so those ViewModels were converted to metrox'sViewModelAssistedFactory.Changes
binding<ViewModel>()to@ContributesIntoMap.Provider<GetAddonBannerInfoUseCase>(base type) fromDataAddonsMetroProviders.@ContributesTomodules public so their Provider bindings reach AppGraph (includes the public model cascade, e.g.HomeData,PaymentOverview,ContactInformation).SeenImportantMessagesStorage(@Inject+@ContributesBinding); HomeViewModel/HomePresenter now inject ApplicationScope.SavedStateHandleVMs (SwedishLogin, movingflow EnterNewAddress / AddHouseInformation / Summary): converted to@AssistedInject+ nestedViewModelAssistedFactory; call sites updated toassistedMetroViewModel().