mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-03-27 10:11:48 -04:00
3.5 KiB
3.5 KiB
Common Practices Playbook
This document captures discoverable patterns that are already used in the repository.
1) Module and layering boundaries
- Keep domain logic in KMP modules (
commonMain) and keep Android framework wiring inapporandroidMain. - Use
core:*for shared logic,feature:*for user-facing flows, andappfor Android entrypoints and integration wiring. - Note: Former passthrough Android ViewModel wrappers have been eliminated. ViewModels are now shared KMP components. Platform-specific dependencies (file I/O, permissions) are isolated behind injected
core:repositoryinterfaces.
2) Dependency injection conventions (Koin)
- Use Koin annotations (
@Module,@ComponentScan,@KoinViewModel,@KoinWorker) and keep DI wiring discoverable fromapp. - Example app scan module:
app/src/main/kotlin/org/meshtastic/app/MainKoinModule.kt. - Example app startup and module registration:
app/src/main/kotlin/org/meshtastic/app/MeshUtilApplication.kt. - Ensure feature/core modules are included in the app root module:
app/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt. - Prefer DI-agnostic shared logic in
commonMain; inject from Android wrappers.
3) Navigation conventions (Navigation 3)
- Use Navigation 3 types (
NavKey,NavBackStack, entry providers) instead of legacy controller-first patterns. - Example graph using
EntryProviderScope<NavKey>andbackStack.add/removeLastOrNull:feature/settings/src/androidMain/kotlin/org/meshtastic/feature/settings/navigation/SettingsNavigation.kt. - Example feature flow using
rememberNavBackStackandNavDisplay<NavKey>:feature/intro/src/androidMain/kotlin/org/meshtastic/feature/intro/AppIntroductionScreen.kt.
4) UI and resources
- Keep shared dialogs/components in
core:uiwhere possible. - Put localizable UI strings in Compose Multiplatform resources:
core/resources/src/commonMain/composeResources/values/strings.xml. - Use
stringResource(Res.string.key)from shared resources in feature screens. - When retrieving strings in non-composable Coroutines, Managers, or ViewModels, use
getStringSuspend(). Never use the blockinggetString()inside a coroutine as it will crash iOS and freeze the UI thread. - Example usage:
feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListScreen.kt.
5) Platform abstraction in shared UI
- Use
CompositionLocalproviders inappto inject Android/flavor-specific UI behavior into shared modules. - Example provider wiring in
MainActivity:app/src/main/kotlin/org/meshtastic/app/MainActivity.kt. - Example abstraction contract:
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/MapViewProvider.kt.
6) I/O and concurrency in shared code
- In
commonMain, use Okio streams (BufferedSource/BufferedSink) and coroutines/Flow. - For ViewModel state exposure, prefer
stateInWhileSubscribed(...)in shared ViewModels and collect in UI withcollectAsStateWithLifecycle(). - Example shared extension:
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/viewmodel/ViewModelExtensions.kt. - Example Okio usage in shared domain code:
core/domain/src/commonMain/kotlin/org/meshtastic/core/domain/usecase/settings/ImportProfileUseCase.ktcore/domain/src/commonMain/kotlin/org/meshtastic/core/domain/usecase/settings/ExportDataUseCase.kt
7) Namespace and compatibility
- New code should use
org.meshtastic.*. - Keep compatibility constraints where required (notably legacy app ID and intent signatures for external integration).