Files
Meshtastic-Android/feature/map
James Rich 4970e45e14 refactor: Consolidate contact-key parsing into ContactKey
Six call sites hand-rolled the same fragile contact-key parse
(`contactKey[0].digitToIntOrNull()` + `substring(1)`). Move that logic
into the ContactKey value class introduced with this branch:

- Add `channelOrNull: Int?` which preserves the semantically meaningful
  "no leading channel digit == legacy unprefixed DM" signal that the
  existing `channel: Int` collapses to 0. SendMessageUseCase relies on
  this distinction to classify direct messages, so the naive `channel`
  accessor would have been a regression.
- Make `addressString` respect it: returns the whole key when there is
  no channel prefix (matching the old defensive behaviour) instead of
  blindly dropping the first character.

Migrated SendMessageUseCase, BaseMapViewModel, ReplyReceiver, Message,
Contacts, and ContactItem onto the typed accessors. Added ContactKey
unit tests for the prefixed / unprefixed / empty cases.

Also removed a dead empty `companion object` left on DataPacket after
its constants moved to NodeAddress.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 09:31:07 -05:00
..

:feature:map

Overview

The :feature:map module provides the mapping interface for the application. Map rendering is decomposed into three focused CompositionLocal provider contracts, each with per-flavor implementations in :androidApp.

Architecture

Provider Contracts (in core:ui/commonMain)

Contract Purpose Implementations
MapViewProvider Main map (nodes, waypoints, controls) GoogleMapViewProvider, FdroidMapViewProvider
NodeTrackMapProvider Per-node GPS track overlay (embedded in PositionLogScreen) Google: NodeTrackMapMapView(GoogleMapMode.NodeTrack), F-Droid: NodeTrackMapNodeTrackOsmMap
TracerouteMapProvider Traceroute route visualization Google: TracerouteMapMapView(GoogleMapMode.Traceroute), F-Droid: TracerouteMapTracerouteOsmMap

All providers are injected via CompositionLocal in MainActivity.kt and consumed by feature modules without direct dependency on Google Maps or osmdroid.

Shared ViewModels (in commonMain)

  • BaseMapViewModel — Core contract for all map state management, node markers, camera positions, and traceroute node selection logic (TracerouteNodeSelection, tracerouteNodeSelection()).
  • NodeMapViewModel — Shared logic for per-node map views (track display, position history).

Key Data Types

  • TracerouteOverlay (core:model/commonMain) — Pure data class representing traceroute route segments. Extracted from feature:map for cross-module reuse.
  • TracerouteNodeSelection (feature:map/commonMain) — Data class modeling node selection results during traceroute visualization.
  • GeoConstants (core:model/commonMain) — Centralized geographic constants (DEG_D, HEADING_DEG, EARTH_RADIUS_METERS).

Map Providers

  • Google Maps (google flavor): Uses Google Play Services Maps SDK. Implementations in androidApp/src/google/kotlin/org/meshtastic/app/map/.
  • OpenStreetMap (fdroid flavor): Uses osmdroid for a fully open-source experience. Implementations in androidApp/src/fdroid/kotlin/org/meshtastic/app/map/.

Features

  • Live Node Tracking: Real-time position updates for nodes on the mesh.
  • Waypoints: Create and share points of interest.
  • Per-Node Track Overlay: Embedded map in PositionLogScreen showing a node's GPS track history.
  • Traceroute Visualization: Dedicated map view showing route segments between mesh nodes.
  • Offline Maps: Support for pre-downloaded map tiles (via osmdroid).

Dependency Graph

graph TB
  :feature:map[map]:::kmp-feature
  :feature:map -.-> :core:data
  :feature:map -.-> :core:database
  :feature:map -.-> :core:datastore
  :feature:map -.-> :core:model
  :feature:map -.-> :core:navigation
  :feature:map -.-> :core:prefs
  :feature:map -.-> :core:proto
  :feature:map -.-> :core:service
  :feature:map -.-> :core:resources
  :feature:map -.-> :core:ui
  :feature:map -.-> :core:di
  :feature:map -.-> :core:testing

classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef compose-desktop-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library-compose fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;