Skip to content

refactor: maps #2097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 32 commits into
base: main
Choose a base branch
from
Draft

refactor: maps #2097

wants to merge 32 commits into from

Conversation

jamesarich
Copy link
Collaborator

Draft

This commit restructures the map-related code to support different map providers (OSMDroid for F-Droid, Google Maps for Google Play).

Key changes:

  • Moved OSMDroid-specific map files to the fdroid source set.
  • Created placeholder files for Google Maps in the google source set.
  • Added Google Maps Compose dependencies and the secrets plugin to build.gradle.kts.
  • Added local.defaults.properties for API key management.
  • Introduced MAP_STYLE_ID constant.
  • Added "Unknown" string resource.
  • Created LocationUtils.kt in the google source set with GPS formatting and calculation utilities.

This commit restructures the map-related code to support different map providers (OSMDroid for F-Droid, Google Maps for Google Play).

Key changes:
- Moved OSMDroid-specific map files to the `fdroid` source set.
- Created placeholder files for Google Maps in the `google` source set.
- Added Google Maps Compose dependencies and the secrets plugin to `build.gradle.kts`.
- Added `local.defaults.properties` for API key management.
- Introduced `MAP_STYLE_ID` constant.
- Added "Unknown" string resource.
- Created `LocationUtils.kt` in the `google` source set with GPS formatting and calculation utilities.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit introduces a basic map view using Google Maps Compose library.
It also adds `secrets.properties` to the `.gitignore` file to prevent committing sensitive information.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit refactors the map implementation to use Google Maps, introducing several new features:

-   **Node Clustering**: Nodes on the map are now clustered for better visualization of dense areas.
-   **Waypoint Management**:
    -   Added the ability to create, edit, and delete waypoints.
    -   Waypoints can be created via a long press on the map.
    -   An "Edit Waypoint" dialog allows modification of name, description, icon, lock status, and expiration.
    -   Waypoints can be deleted, with shared waypoints sending a delete message if connected.
-   **Map Filtering**:
    -   Implemented a filter menu with options to:
        -   Show only favorite nodes.
        -   Toggle visibility of waypoints.
        -   Toggle visibility of precision circles for nodes.
-   **Map Type Selection**:
    -   Added a dropdown to switch between Normal, Satellite, Terrain, and Hybrid map types.
-   **UI Enhancements**:
    -   Added map buttons for accessing filter and map type options.
    -   Implemented a scale bar on the map.
    -   Improved dark mode support for the map.
-   **Node Detail Map**:
    -   The individual node map screen now displays the node's position history as markers and a polyline.
    -   The map automatically zooms to fit all logged positions.
-   **String Resources**: Added new strings for map types.
-   **Dependency Update**: Added `play-services-location` to Google Maps dependencies.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit refactors the map view, including changes to waypoint editing, cluster item handling, and map marker display. It also updates build configurations, including SDK versions and Detekt settings.

Specific changes:
- Modified waypoint editing logic in `EditWaypointDialog.kt`
- Updated `MapView.kt` to:
    - Change how node cluster items are handled and displayed
    - Modify waypoint marker display and interaction
    - Adjust map UI settings and properties
- Updated `MIN_SDK_VERSION` to `MIN_SDK` in `Configs.kt` and build files
- Set `compileSdk` to `Configs.COMPILE_SDK` in `network/build.gradle.kts`
- Updated Detekt source paths in `app/build.gradle.kts` and `network/build.gradle.kts`
- Removed conditional Firebase Crashlytics setup based on `Configs.USE_CRASHLYTICS`
- Passed `uiViewModel` instead of `model` to `MapView` in `MapRoutes.kt`
- Added `enabled` parameter to `NodeChip`

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Rename `model` parameter to `uiViewModel` for clarity.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
# Conflicts:
#	app/src/main/res/values/strings.xml
#	build.gradle.kts
#	buildSrc/src/main/kotlin/Configs.kt
#	network/build.gradle.kts
This commit introduces the ability to load and manage KML/KMZ layers on the map view.

Key changes include:
- Added a `MapViewModel` to handle KML/KMZ layer logic, including loading, saving, and managing visibility.
- Implemented functionality to add KML/KMZ files via a file picker.
- Added a "Manage Map Layers" dialog to:
    - Display currently loaded layers.
    - Toggle the visibility of individual layers.
    - Remove layers.
- Persisted layers are loaded on app start from internal storage.
- Updated the map view to display loaded KML layers.
- Added new string resources for layer management UI elements.
- Adjusted map controls layout.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
The MapViewModel was being injected into the MapView composable, but it was not being used. This change removes the unnecessary injection.

Additionally, a function `isGooglePlayAvailable()` is added to the F-Droid flavor, which always returns `false`.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Copy link
Collaborator

@DaneEvans DaneEvans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try and suppress lines, or at most functions, rather than whole files

All the incidental changes look good, need to test and go through the new code in more detail.

@@ -27,5 +27,5 @@ keystore.properties
# Kotlin compiler
.kotlin

# VS code
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why you override my ignores??


@Suppress("MaxLineLength")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't need this

@@ -33,26 +33,38 @@ import com.suddenh4x.ratingdialog.AppRating
* Created by kevinh on 1/4/15.
*/

@Suppress("MagicNumber")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it just the min launch times ?

Define it at the top as, do it properly

@DaneEvans
Copy link
Collaborator

DaneEvans commented Jul 5, 2025

Comments on the google variant:

  • defaults to some random US location - Black rock desert, nv.
  • no 'to me' button
  • Something odd happening ( some nodes in Aus. appear off the coast of Ghana @ appx 0,0)
    • some of mine are in the right place - those with fixed locations I think ...
    • one of those at 0,0 seems to have no location info. another has a GPS, and it's 'node map' puts it in the right place. and last position log made sense.
  • no clustering?
  • precision circles are very small - much smaller than on open maps, but may be accurate, I'll need to check what they are broadcasting.
  • Directions etc are working.
  • didn't test adding layers

# Conflicts:
#	app/src/fdroid/java/com/geeksville/mesh/ui/map/MapView.kt
#	app/src/main/res/values/strings.xml
This commit introduces a `LocationPermissionsHandler` composable to manage location permissions and settings checks.

- Enables map UI features (My Location button, compass, gestures) based on location permission status.
- Prompts the user to grant location permission if not already granted.
- Prompts the user to enable location services if they are disabled after permission is granted.
- Aligns map control buttons to `CenterEnd`.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
- Use `getPrecisionMeters()` for circle radius to show position accuracy.
- Adds a function to `NodeClusterItem` to convert precision bits to meters.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit refactors the `MapView.kt` composable by extracting several parts of its UI and logic into new, more focused composable functions. This improves readability and maintainability of the map screen.

The following components were created:
- `MapControlsOverlay.kt`: Handles the display and interaction of map control buttons (filter, map type, layers).
- `NodeClusterMarkers.kt`: Responsible for rendering node markers and clusters on the map, including precision circles.
- `WaypointMarkers.kt`: Manages the display of waypoint markers.

Changes in `MapView.kt`:
- Replaced the inline implementation of map controls with `MapControlsOverlay`.
- Replaced the inline implementation of node and waypoint markers with `NodeClusterMarkers` and `WaypointMarkers` respectively.
- Replaced `LayerManagementDialog` with a `ModalBottomSheet` for managing map layers, providing a more modern UX.
- Moved `MapFilterDropdown`, `MapTypeDropdown`, `convertIntToEmoji`, and `unicodeEmojiToBitmap` to be internal to the map package as they are primarily used within this context.
- Updated `Uri.getFileName` to be more robust and fall back to a generated name if needed.
- `NodeClusterItem` data class remains in `MapView.kt` as it's tightly coupled with the clustering logic within.

String resource updates:
- Added new strings for "Hide Layer", "Show Layer", "Remove Layer", and "Add Layer" to support the new layer management UI.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit introduces a `MapViewModel` to manage map-specific UI state, separating it from the general `UIViewModel`.

Key changes:
- Created `MapViewModel` in both `fdroid` and `google` flavors.
- Moved map filter state (onlyFavorites, showWaypoints, showPrecisionCircle) and related logic from `UIViewModel` to `MapViewModel`.
- Updated `MapView` in both flavors to use `MapViewModel`.
- Modified `MapControlsOverlay` and `MapFilterDropdown` to accept `MapViewModel`.
- Added a new string resource `nodes_at_this_location`.
- Implemented a dialog to show a list of nodes when a cluster of nodes at the exact same location is clicked on the Google Maps view.
- Adjusted `NodeClusterMarkers` to handle cluster clicks and display the new dialog.
- Ensured `WaypointMarkers` shows a toast when trying to edit a locked waypoint.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
@jamesarich
Copy link
Collaborator Author

jamesarich commented Jul 8, 2025

Comments on the google variant:

  • defaults to some random US location - Black rock desert, nv.

was testing kml layer data for burningman, working on setting up an initial bounding box based on the nodelist and waypoints

  • no 'to me' button

added perms check for location and made sure myLocation button shows up

  • Something odd happening ( some nodes in Aus. appear off the coast of Ghana @ appx 0,0)

    • some of mine are in the right place - those with fixed locations I think ...
    • one of those at 0,0 seems to have no location info. another has a GPS, and it's 'node map' puts it in the right place. and last position log made sense.

pretty easy to filter out nodes with positionValid==false i'll get that in

  • no clustering?

clustering should be working, and added a dialog when multiple nodes report the same location

  • precision circles are very small - much smaller than on open maps, but may be accurate, I'll need to check what they are broadcasting.

good catch - needed some conversion from precison bits to meters

  • Directions etc are working.
  • didn't test adding layers

moved layer ui into a bottom sheet

# Conflicts:
#	app/src/main/res/values/strings.xml
…onents

This commit introduces the ability for users to add and manage custom map tile providers. It also includes several refactorings and improvements to the map screen components.

Key changes:
- Implement `CustomTileProviderRepository` using SharedPreferences to store custom tile provider configurations.
- Add `CustomTileProviderManagerSheet` composable for users to add, edit, and delete custom tile sources.
- Integrate custom tile providers into `MapViewModel` and `MapView`, allowing selection and display of custom map layers.
- Update `MapTypeDropdown` to include custom tile providers and a "Manage Custom Tile Sources" option.
- Refactor `MapView` by extracting `MapFilterDropdown`, `MapTypeDropdown`, and `CustomMapLayersSheet` into their own composable files for better organization.
- Improve KML/KMZ layer management with better file handling and UI updates.
- Ensure precision circles are drawn correctly with stable keys and z-index.
- Add new string resources for custom tile provider management.
- Introduce Hilt modules (`MapModule`, `MapRepositoryModule`) for dependency injection related to map features.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
The `UrlTileProvider` in `MapViewModel.kt` was updated to use a new constant `TILE_SIZE` (set to 256) for both width and height parameters instead of hardcoded values.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
When the map is first displayed, automatically adjust the camera
to encompass all currently known nodes and waypoints.
This ensures users see all relevant items upon opening the map.

The zoom operation is performed only once when the map is initially loaded
and items are available.

Other changes:
- Minor code cleanup in MapView.kt related to comments.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This change introduces the ability to display a polyline track for a selected node on the map.

Key changes:
- Modified `MapView` to accept an optional `focusedNodeNum` and `nodeTrack`.
- When `nodeTrack` is provided, the map now zooms to the bounds of the track and displays it as a polyline with markers for each point.
- The last point of the track is represented by a `NodeChip`.
- The map filter button is hidden when a node track is displayed.
- `NodeMapScreen` now utilizes the enhanced `MapView` to show the logged position tracks of a node.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit refactors the `MapControlsOverlay` composable.
It replaces the `Column` layout with a `VerticalFloatingToolbar` for the map control buttons.
The `MapButton` composable was also updated to use `FilledIconButton` instead of `FloatingActionButton`.

Key changes:
- Replaced `Column` with `VerticalFloatingToolbar` in `MapControlsOverlay.kt` for improved UI/UX.
- Updated `MapButton.kt` to use `FilledIconButton` for a more consistent Material Design look.
- Integrated `FloatingToolbarScrollBehavior` in `MapView.kt` to allow the toolbar to scroll with content.
- Adjusted layout modifiers and parameters in `MapControlsOverlay.kt` and `MapView.kt` to accommodate the new toolbar.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit introduces an animation to the map controls overlay. The controls now smoothly hide when the map camera is moving and reappear when the camera movement stops.

- Added a `LaunchedEffect` to observe `cameraPositionState.isMoving`.
- When the camera starts moving, the map controls animate to an offset, effectively hiding them.
- When the camera stops moving, the controls animate back to their original position.
- Utilized `rememberFloatingToolbarState` and `animate` for the animation.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
The `UIViewModel` parameter was inadvertently missing in the F-Droid
build variant of the `NodeMapScreen` composable. This commit adds it
to maintain consistency with the Google Play build.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
# Conflicts:
#	gradle/libs.versions.toml
@DaneEvans
Copy link
Collaborator

I'll have another look at this one over teg weekend

# Conflicts:
#	app/src/main/res/values/strings.xml
The ModalBottomSheet was moved from CustomMapLayersSheet to the MapView.
This allows the MapView to control the presentation of the bottom sheet.

BREAKING CHANGE: The `onDismissRequest` parameter was removed from the `CustomMapLayersSheet` composable. Consumers of this composable should now wrap it in a `ModalBottomSheet` and provide the `onDismissRequest` callback there.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants