Refactor map layer management and navigation infrastructure#4921
Merged
jamesarich merged 55 commits intomainfrom Mar 26, 2026
Merged
Refactor map layer management and navigation infrastructure#4921jamesarich merged 55 commits intomainfrom
jamesarich merged 55 commits intomainfrom
Conversation
This commit introduces safer handling for adding and removing map layers in the Google Maps implementation to prevent crashes during rapid updates or disposal. Specific changes include: - Introduced `safeAddLayerToMap()` and `safeRemoveLayerFromMap()` extension functions for `com.google.maps.android.data.Layer` to catch and log exceptions (specifically addressing potential `NullPointerException` in `KmlRenderer`). - Updated `KmlLayer` component to explicitly cleanup the old layer before reloading a new one. - Replaced direct layer lifecycle calls with safe wrappers in `MapEffect`, `DisposableEffect`, and `LaunchedEffect`. - Ensured `isLayerOnMap` checks are performed within the safe wrapper to prevent redundant operations. Signed-off-by: James Rich <[email protected]>
This commit refactors the navigation infrastructure to share adaptive UI components across platforms (Android and Desktop) and introduces a `CompositionLocal` pattern for providing platform-specific map screens. This reduces code duplication in the `app` and `desktop` modules.
Specific changes include:
- **Navigation Refactoring:**
- Created `MeshtasticNavigationSuite` in `core:ui` as a shared adaptive navigation shell that provides a `NavigationBar` for compact screens and a `NavigationRail` for larger screens.
- Relocated `ConnectionsNavIcon` and `AnimatedConnectionsNavIcon` from `feature:connections` to `core:ui` to support the shared navigation suite.
- Updated `MainScreen` (Android) and `DesktopMainScreen` to use the new `MeshtasticNavigationSuite`.
- Removed `androidx.compose.material3.navigationSuite` dependency in favor of the custom implementation.
- **Map Provider Pattern:**
- Introduced `LocalNodeMapScreenProvider` in `core:ui` to decouple the `node` feature from specific map implementations.
- Updated `NodesNavigation` to use the provider instead of accepting a `Composable` lambda parameter.
- Provided the real `NodeMapScreen` in the Android `MainActivity` and a `PlaceholderScreen` as the default/Desktop implementation.
- Deleted `KmpMapPlaceholder.kt` in the desktop module in favor of the shared `PlaceholderScreen`.
- **Infrastructure & Cleanup:**
- Exposed `currentDeviceAddressFlow` in `UIViewModel` for consumption by the navigation icons.
- Cleaned up unused imports and parameters in `NodesNavigation.kt`, `Main.kt`, and `DesktopNavigation.kt`.
- Updated `gradle/libs.versions.toml` to remove the unused navigation suite library.
Signed-off-by: James Rich <[email protected]>
This commit unifies the `ContactsEntryContent` implementation by moving it from platform-specific source sets (`androidMain`, `iosMain`, `jvmMain`) into `commonMain`. This eliminates redundant code and provides a consistent implementation of the contacts screen across all platforms. Specific changes include: - Removed platform-specific `ContactsEntryContent` implementations in `androidMain`, `jvmMain`, and the placeholder in `iosMain`. - Converted `ContactsEntryContent` from an `expect` to a standard function in `commonMain`. - Integrated `UIViewModel` for handling shared contact requests and deep links within the common implementation. - Standardized the use of `AdaptiveContactsScreen` with a `detailPaneCustom` block that dynamically initializes the `MessageViewModel` for the selected contact. - Ensured that `initialContactKey` correctly sets the state in the `MessageViewModel` to maintain navigation consistency. Signed-off-by: James Rich <[email protected]>
…ider pattern
This commit refactors the navigation architecture for map-related screens by replacing `expect`/`actual` declarations with a `CompositionLocal` provider pattern. This decouples the feature modules from platform-specific implementations and centralizes UI provisioning in the main application module.
Specific changes include:
- **Provider Introduction**: Created `LocalMapMainScreenProvider` and `LocalTracerouteMapScreenProvider` in `core:ui` to allow dependency inversion for map rendering across platforms.
- **Feature Decoupling**:
- Removed `expect` declarations for `MapMainScreen` and `TracerouteMapScreen` from `feature:map` and `feature:node`.
- Deleted platform-specific `actual` implementations in `androidMain`, `iosMain`, and `jvmMain` for these screens.
- Updated `mapGraph` and `NodesNavigation` to consume screens via the new providers.
- **App Integration**: Updated `MainActivity` to provide the concrete Android implementations and ViewModels for `MapScreen` and `TracerouteMapScreen` through `CompositionLocalProvider`.
- **Deep Linking**: Refactored `UIViewModel` and `MeshtasticAppShell` to pass parsed `NavKey` lists directly through `navigationDeepLink` instead of raw URIs, improving navigation handling efficiency.
- **Cleanup**: Removed unused imports and applied minor formatting in `ContactsNavigation.kt`.
Signed-off-by: James Rich <[email protected]>
This commit moves the `PositionLogScreen` from platform-specific implementations to `commonMain`, enabling a shared UI for position logging across Android, iOS, and Desktop. It also introduces a platform-agnostic file saving utility.
Specific changes include:
- **UI Migration**: Relocated `PositionLogScreen` to `commonMain` and implemented the UI using Compose Multiplatform.
- **New Components**: Added `ActionButtons` for clearing and saving logs, and integrated `PositionLogHeader` and `PositionList`.
- **File Export**: Introduced `rememberSaveFileLauncher` in `core:ui` with an Android implementation using `ACTION_CREATE_DOCUMENT` and a JVM stub.
- **Navigation Improvements**:
- Updated `MeshtasticNavigationSuite` to better handle top-level navigation and "re-press" logic for `Nodes` and `Conversations` tabs.
- Improved active destination detection by checking the root of the backstack.
- **Refactoring**:
- Removed redundant `colorScheme` parameter from `AnimatedConnectionsNavIcon` in favor of `MaterialTheme.colorScheme`.
- Cleaned up now-obsolete `PositionLogScreens.kt` files in `iosMain` and `jvmMain`.
Signed-off-by: James Rich <[email protected]>
…ing, and persistence
…and FakeRadioTransport
…sion' as complete
…chieve 92% coverage
…es and migrate tests
…st practices using in-memory DB builder
- Add FakeDatabaseManager and FakeNotificationPrefs - Migrate and expand ViewModel tests in commonTest - Target 80% coverage (Best effort reached ~39% for feature:settings) - Fix flaky flow tests using Turbine and UnconfinedTestDispatcher
- Increased feature:firmware coverage to 42.2% - Refactored FirmwareUpdateViewModel to support JVM testing of getString - Extracted FirmwareReleaseRepository interface - Made BootloaderWarningDataSource open for mocking - Expanded TestDataFactory with Node and MyNodeInfo helpers
…(firmware in-depth)
- Migrated FirmwareUpdateState and ProgressState to use UiText - Refactored FirmwareUpdateViewModel to use UiText instead of direct getString calls - Fixed JVM tests to pass without Skiko by asserting on UiText structure - Increased feature:firmware coverage to 43%
…ion errors in androidMain and test
… BleRadioInterfaceTest
…s and CommonUri alignment
… subclassing pattern
…g best practices' as complete
…ing best practices'
This commit restructures the test suite to better support Kotlin Multiplatform (KMP) by moving core test logic into abstract base classes and providing platform-specific implementations for Android and JVM.
Specific changes include:
- **Test Architecture Refactoring:**
- Migrated `MeshLogRepositoryTest`, `NodeRepositoryTest`, `PacketRepositoryTest`, `NodeInfoDaoTest`, `PacketDaoTest`, and `ChannelViewModelTest` into abstract `Common*` classes in `commonTest`.
- Implemented platform-specific test wrappers in `jvmTest` and `androidHostTest` (using Robolectric) to execute these common tests.
- Deleted `CleanNodeDatabaseViewModelTest` from the settings feature.
- **Database Configuration:**
- Refactored `MeshtasticDatabase` to move `BundledSQLiteDriver` configuration out of common logic.
- Explicitly set `BundledSQLiteDriver` in platform-specific `DatabaseBuilder` implementations for iOS and JVM.
- Added `androidx.sqlite.bundled` dependency to the database module's `androidHostTest`.
- **Build Logic & Dependencies:**
- Updated `KotlinAndroid` convention plugin to include `robolectric` and `androidx-test-core` in the standard test dependency set.
- **iOS UI Stubs:**
- Added no-op stubs for `rememberSaveFileLauncher`, `rememberRequestLocationPermission`, and `rememberOpenLocationSettings` in `iosMain` to satisfy platform requirements.
- **Maintenance:**
- Updated copyright headers to 2026 across new and modified test files.
Signed-off-by: James Rich <[email protected]>
Signed-off-by: James Rich <[email protected]>
…ching
This commit refactors several core components to improve code organization, maintainability, and data handling. Most notably, it introduces a robust caching strategy for firmware releases and cleans up UI logic in the main entry point and navigation components.
Specific changes include:
- **Core Data & Repository:**
- Implemented `FirmwareReleaseRepositoryImpl` to handle firmware release fetching with a "cache-then-network" strategy.
- Added support for both STABLE and ALPHA release streams with automatic background refresh and fallback to bundled JSON assets.
- Defined cache expiration logic (1 hour) to ensure firmware information remains reasonably up-to-date.
- **Main Activity & UI Logic:**
- Extracted `AppCompositionLocals` in `MainActivity.kt` to clean up the `onCreate` method and improve readability of dependency providers.
- Refactored `MeshtasticNavigationSuite` to decompose large Composable functions into smaller, specialized components (`MeshtasticNavigationBar`, `MeshtasticNavigationRail`).
- Extracted navigation handling logic into a standalone private function.
- **Firmware Feature:**
- Improved error handling in `FirmwareUpdateViewModel` by adding logging for update failures.
- Refactored `UsbUpdateHandler` for better code formatting and simplified state updates.
- **Testing Infrastructure:**
- Cleaned up several "fake" implementations (`FakeBle`, `FakeNodeRepository`, `FakeDatabaseManager`) by introducing constants and extracting complex filtering logic.
- Applied `@Suppress` annotations to test doubles where specific lint rules (e.g., `TooManyFunctions`, `EmptyFunctionBlock`) were intentionally bypassed.
- **Maintenance:**
- Applied consistent code formatting and suppressed specific wrapping/linting warnings in `core:ui` utility providers.
- Updated copyright headers to include 2026.
Signed-off-by: James Rich <[email protected]>
…TS.md This commit updates the `AGENTS.md` documentation to reflect recent architectural changes and provide clearer guidance on Kotlin Multiplatform (KMP) development patterns. Specific changes include: - **Project Structure**: Updated descriptions for `build-logic`, `core:network`, `core:navigation`, and `core:ui` to include new components like `DeepLinkRouter`, `MeshtasticAppShell`, and `BleRadioInterface`. - **New Convention Plugin**: Added reference to `meshtastic.kmp.jvm.android` for sharing code between Android and Desktop. - **`jvmAndroidMain` Source Set**: Added a new section explaining the usage of the `jvmAndroidMain` source set across core modules. - **Navigation Patterns**: Defined standards for exporting Navigation 3 graphs from feature modules using `EntryProviderScope` in `commonMain`. - **Shared Helpers**: Added new examples of shared logic extraction, including `MeshtasticAppShell` and `BaseRadioTransportFactory`. - **Best Practices**: Clarified file naming conventions to avoid JVM duplicate class errors in KMP modules. Signed-off-by: James Rich <[email protected]>
Signed-off-by: James Rich <[email protected]>
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.
This pull request introduces several improvements and refactorings across the codebase, focusing on safer map layer management, enhanced documentation, and simplification of composition locals and navigation. The changes aim to improve app stability (especially around map overlays), clarify project structure, and streamline dependency usage.
Map Layer Management Improvements
safeAddLayerToMap()andsafeRemoveLayerFromMap()extension functions tocom.google.maps.android.data.LayerinMapView.ktto handle exceptions (such asNullPointerException) when adding or removing map layers, preventing crashes during layer disposal or reload. All usages of direct layer manipulation are updated to use these safe methods. [1] [2] [3]Project Structure and Documentation Enhancements
AGENTS.mdto reflect new and renamed convention plugins, expanded descriptions for modules (including new features likeBleRadioInterface,DeepLinkRouter, andMeshtasticNavSavedStateConfig), and added documentation for the newjvmAndroidMainsource set and feature navigation graph conventions. [1] [2] [3]Composition Locals and Navigation Refactor
CompositionLocalProviderblock inMainActivity.ktinto a dedicatedAppCompositionLocalscomposable, and expanded it to include providers for map-related screens, centralizing and simplifying the app's composition locals setup. [1] [2]Dependency and Import Cleanup
libs.androidx.compose.material3.navigationSuitefromapp/build.gradle.ktsand cleaned up related unused imports inMain.kt, reflecting a shift to custom or alternative navigation solutions. [1] [2] [3]