mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
4.9 KiB
4.9 KiB
DI and Navigation 3 Anti-Patterns Playbook
This playbook is a fast guardrail for high-risk mistakes in dependency injection and navigation.
Version note: align guidance with repository-pinned versions in gradle/libs.versions.toml (currently Koin 4.2.x and Navigation 3 JetBrains fork 1.1.x).
DI anti-patterns
- Don't put Android framework dependencies (
Context,Activity,Application) into sharedcommonMainbusiness logic. - Do use
@Module,@ComponentScan, and@KoinViewModelannotations directly incommonMainshared modules. This provides compile-time safety and encapsulates dependency graphs per feature, which is the recommended 2026 KMP practice for Koin 4.x. - Don't instantiate ViewModels or service dependencies manually in Compose or activities.
- Do resolve app-layer wrappers via Koin (
koinViewModel()/ injected bindings). - Don't spread DI graph setup across unrelated modules without registration in app startup.
- Do ensure modules are reachable from app bootstrap in
app/src/main/kotlin/org/meshtastic/app/MeshUtilApplication.kt. - Don't assume feature/core
@Moduleclasses are active automatically. - Do ensure they are included by the app root module (
@Module(includes = [...])) inapp/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt. - Don't use Koin K2 Compiler Plugin's A1 Module Compile Safety checks for inverted dependencies.
- Do leave A1
compileSafetydisabled inbuild-logic/convention/src/main/kotlin/KoinConventionPlugin.kt(uses typedKoinGradleExtension). We rely on Koin's A3 full-graph validation (startKoin/VerifyModule) to handle our decoupled Clean Architecture design where interfaces are declared in one module and implemented in another. - Don't expect Koin to inject default parameters automatically. The K2 plugin's
skipDefaultValues = true(default behavior) will cause Koin to skip parameters that have default Kotlin values.
Current code anchors (DI)
- App-level module scanning:
app/src/main/kotlin/org/meshtastic/app/MainKoinModule.kt - App startup + Koin init:
app/src/main/kotlin/org/meshtastic/app/MeshUtilApplication.kt - Shared ViewModel base:
feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/MessageViewModel.kt - Shared base UI ViewModel:
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/viewmodel/UIViewModel.kt
Navigation 3 anti-patterns
- Don't reintroduce controller-coupled navigation APIs for shared flow state.
- Do use Navigation 3 types (
NavKey,NavBackStack,EntryProviderScope) consistently. - Don't build route identifiers as ad-hoc strings in feature code when typed route keys already exist.
- Do keep route definitions in
core:navigationand use typed route objects. - Don't mutate back navigation with custom stacks disconnected from app backstack.
- Do mutate
NavBackStack<NavKey>withadd(...)andremoveLastOrNull(). - Don't use Android's
androidx.activity.compose.BackHandleror customPredictiveBackHandlerin multiplatform UI. - Do use the official KMP
NavigationBackHandlerfromandroidx.navigationevent:navigationevent-composefor back gestures. - Don't parse deep links manually in platform code or push single routes without a backstack.
- Do use
DeepLinkRouter.route()incore:navigationto synthesize the correct typed backstack from RESTful paths. - Don't use a single
NavBackStacklist for multiple tabs, nor reuse the sameNavEntryDecoratorinstances across different backstacks. - Do use
MultiBackstack(fromcore:navigation) to manage independentNavBackStackinstances per tab. When rendering the active tab inMeshtasticNavDisplay, you must supply a fresh set of decorators (usingremember(backStack) { ... }) bound to the active backstack instance. Failure to swap decorators when swapping backstacks causes Navigation 3 to perceive the inactive entries as "popped", permanently destroying theirViewModelStoreand saved UI state.
Current code anchors (Navigation 3)
- Typed routes:
core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/Routes.kt - Shared saved-state config:
core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/NavigationConfig.kt - App root backstack +
MeshtasticNavDisplay:app/src/main/kotlin/org/meshtastic/app/ui/Main.kt - Shared graph entry provider pattern:
feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/navigation/SettingsNavigation.kt - Desktop Navigation 3 shell:
desktop/src/main/kotlin/org/meshtastic/desktop/ui/DesktopMainScreen.kt - Desktop nav graph assembly:
desktop/src/main/kotlin/org/meshtastic/desktop/navigation/DesktopNavigation.kt
Quick pre-PR checks for DI/navigation edits
- Verify affected graph/module is registered and reachable from app startup.
- Verify no new Android framework type leaks into
commonMain. - Verify routes/backstack use typed keys and Navigation 3 primitives.
- Run targeted verification from
docs/agent-playbooks/testing-and-ci-playbook.md.