feat(maps): Google maps improvements for network and offline tilesources#4664
Merged
jamesarich merged 8 commits intomainfrom Feb 27, 2026
Merged
feat(maps): Google maps improvements for network and offline tilesources#4664jamesarich merged 8 commits intomainfrom
jamesarich merged 8 commits intomainfrom
Conversation
This commit introduces the capability to use local MBTiles files as a custom map tile source, in addition to the existing support for URL-based tile providers.
Key changes include:
* **MBTiles Provider:** A new `MBTilesProvider` class has been added to read map tiles directly from a local `.mbtiles` SQLite database file. It handles the conversion from Google Maps tile coordinates to the TMS standard used in MBTiles.
* **Data Model Update:** The `CustomTileProviderConfig` data model has been extended with a `localUri` field to store the path to the MBTiles file.
* **File Management:** The `MapViewModel` now includes logic to:
* Copy a user-selected MBTiles file into the app's internal storage to ensure persistent access.
* Generate a unique filename for the copied file to avoid conflicts.
* Delete the internal file when the corresponding custom map source is removed.
* **UI Integration:**
* The "Custom Tile Provider Manager" screen now features an "Add Local MBTiles File" button, which uses the system's file picker.
* The manager list now differentiates between remote URL sources and local MBTiles files.
* **Map Display Logic:**
* The `MapView` and `MapViewModel` have been updated to create either a `UrlTileProvider` or the new `MBTilesProvider` based on the configuration of the selected custom map source.
* When a custom tile provider is active, the base Google Map type is now set to `NONE` to prevent the base map from rendering underneath the custom tiles.
Signed-off-by: James Rich <[email protected]>
This commit introduces the ability to add KML map layers from a network URL. Users can now add, view, and refresh map layers hosted online. - A "Network Map Layer" feature has been added, allowing users to input a name and a URL (HTTP/HTTPS) to load a KML file onto the map. - These network layers are persisted across app restarts. - A refresh button is now available in the map controls when a network layer is visible, allowing for a manual refresh of all visible network layers. - Individual network layers can also be refreshed from the "Manage Layers" sheet. A loading indicator shows the refresh progress. - The "Manage Layers" bottom sheet has been updated with a new "Add Network Layer" button and a dialog to input the layer's details. Signed-off-by: James Rich <[email protected]>
… URLs
This commit adds support for the `{s}` placeholder in custom map tile server URLs, enabling load balancing across multiple subdomains (e.g., 'a', 'b', 'c').
The `MapViewModel` now cycles through a list of subdomains and replaces the `{s}` placeholder in the URL template. This distributes tile requests and can improve map loading performance. The hint text for the URL template has been updated to reflect this new capability.
Signed-off-by: James Rich <[email protected]>
…rkers This commit refactors the map feature by removing the flavor-specific `MapsInitializer` and centralizing map-related logic within the `feature/map` module. The explicit call to `initializeMaps` from `MeshUtilApplication` has been removed. Marker rendering has been improved to prioritize the user's node and favorite nodes. These nodes now have a higher `zIndex` to ensure they are always displayed on top of other nodes and clusters, preventing them from being obscured. A minor bug in custom map layer loading from a network URL has been fixed by switching from `Okio.source` to `java.io.BufferedInputStream` to prevent potential stream closing issues. **BREAKING CHANGE:** The flavor-specific `MapsInitializer.kt` files (`google` and `fdroid` variants) have been deleted. Map initialization is now expected to be handled within the map feature module itself or through a different mechanism. This simplifies the application's entry point but may require adjustments if other parts of the app relied on this explicit, flavor-based initialization. Signed-off-by: James Rich <[email protected]>
Signed-off-by: James Rich <[email protected]>
…anist This commit refactors the application's permission handling by replacing the `nordic-common-permissions` library with `com.google.accompanist.permissions`. The `AppIntroductionScreen` has been updated to use Accompanist's `rememberPermissionState` and `rememberMultiplePermissionsState` for managing runtime permissions for notifications, Bluetooth, and location. This change simplifies the permission request flow, removing the previous state management logic and custom composables like `RequireBluetooth` and `RequireLocation`. Additionally, the `maxSdkVersion` attribute has been removed from location permissions in `AndroidManifest.xml` to ensure compatibility with the new permission handling logic across all Android versions. Signed-off-by: James Rich <[email protected]>
This commit introduces a ViewModel to manage the application introduction flow and modularizes the navigation logic. Key changes include: - **IntroViewModel**: Created a new ViewModel to encapsulate the navigation logic, specifically determining the next step in the flow based on granted permissions. - **Navigation Refactoring**: Extracted the navigation graph into a standalone `introNavGraph` function. This improves readability of the `AppIntroductionScreen` and separates UI state hoisting from navigation structure. - **Flow Adjustment**: Reordered the introduction sequence to follow a new hierarchy: Welcome -> Bluetooth -> Location -> Notifications -> Critical Alerts. - **Testing**: Added unit tests for `IntroViewModel` to verify the navigation sequence logic. - **Dependencies**: Updated `build.gradle.kts` to include testing libraries such as JUnit, MockK, and Robolectric, and enabled Android resource inclusion for unit tests. Signed-off-by: James Rich <[email protected]>
This commit refactors the map layer lifecycle management and streamlines the introduction navigation flow. Key changes include: - **Map Layer Management**: Decoupled Google Maps `Layer` objects (KML/GeoJSON) from the `MapViewModel` to prevent leaking view-related dependencies. Layer state is now managed within the composition using a new `MapLayerOverlay` component, which utilizes `MapEffect` and `DisposableEffect` for proper resource cleanup. - **MBTiles Support**: Enhanced `MBTilesProvider` by implementing `AutoCloseable` to ensure the underlying SQLite database is properly closed. The `MapViewModel` now caches the current tile provider to avoid redundant allocations. - **Improved Layer Detection**: Network map layers now automatically detect GeoJSON format based on file extensions (.geojson, .json), defaulting to KML otherwise. - **Intro Flow Refactoring**: Centralized navigation logic in `IntroViewModel` by exposing `getNextKey` and updating `IntroNavGraph` to use this logic consistently across screens. - **Testing**: Added comprehensive unit tests for `MapViewModel` and `MBTilesProvider` using Robolectric and MockK. - **UI/Resources**: Updated string resources for better clarity regarding "Network" and "Map" layers, and added error messages for MBTiles file operations. ```kotlin // Example of the new Composable-based layer management @composable private fun MapLayerOverlay(layerItem: MapLayerItem, mapViewModel: MapViewModel) { MapEffect(layerItem.id, layerItem.isRefreshing) { map -> // Layer initialization and attachment to the map } DisposableEffect(layerItem.id) { onDispose { /* Cleanup layer from map */ } } } ``` Signed-off-by: James Rich <[email protected]>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4664 +/- ##
=======================================
Coverage 15.36% 15.36%
=======================================
Files 83 83
Lines 4342 4342
Branches 734 734
=======================================
Hits 667 667
Misses 3551 3551
Partials 124 124 ☔ View full report in Codecov by Sentry. |
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.
Implements offline maps (MBTiles) and remote data layers (KML/GeoJSON) with a focus on MAD best practices, leak prevention, and robust architecture.
Key Changes
1. Architectural & Performance Stability
GoogleMapand Layer SDK dependencies fromMapViewModel. Lifecycle management is now handled in the UI viaMapEffectandDisposableEffect.MBTilesProvidernow implementsAutoCloseable. ViewModel ensures SQLite connections are closed on source change oronCleared.MapLayerIteminto an immutable data class to ensure predictable state updates.2. New Mapping Features
3. Infrastructure & UI
IntroNavGraphto useIntroViewModellogic, eliminating code duplication.strings.xml.4. Testing
Related Issues
Resolves #4404
Resolves #4517
Resolves #3448
Closes #2352
Closes #1788
Addresses #2714