Skip to content

Claude/meshtastic offline map brtxh5 - #6584

Closed
marmotte5 wants to merge 4 commits into
meshtastic:mainfrom
marmotte5:claude/meshtastic-offline-map-brtxh5
Closed

Claude/meshtastic offline map brtxh5#6584
marmotte5 wants to merge 4 commits into
meshtastic:mainfrom
marmotte5:claude/meshtastic-offline-map-brtxh5

Conversation

@marmotte5

@marmotte5 marmotte5 commented Aug 5, 2026

Copy link
Copy Markdown

Thank you for sending in a pull request, here's some tips to get started!

(Please delete all these tips and replace with your text)

  • Before starting on some new big chunk of code, it it is optional but highly recommended to open an issue first to say "Hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback is appreciated." This will allow other devs to potentially save you time by not accidentally duplicating work etc...
  • Mention "#(issue)" in the description, when applicable
  • Please do not check in files that don't have real changes
  • Please do not reformat lines that you didn't have to change the code on
  • If your other co-developers have comments on your PR please tweak as needed
  • Do not use any external image service, just paste or drag and drop the image here and it will be uploaded automatically
  • Please also enable "Allow edits by maintainers".

Summary by CodeRabbit

  • New Features
    • Added a map shortcut to locate your favorite contact using bearing and distance.
    • Selecting a contact from the map can now open its compass view automatically.
    • Offline map providers are restored reliably after restarting the app.
    • Local map providers are prioritized when available.
    • Connections are now focused on Bluetooth, with transport selection removed.
  • Improvements
    • Map controls now use consistent sizing for easier interaction.
    • Custom map selections are preserved more reliably.

marmotte5 and others added 4 commits August 5, 2026 00:00
An imported MBTiles tile provider and its selected layer were lost on every cold
start, so the file had to be re-imported and the layer re-enabled by hand.

Two independent causes, each sufficient on its own:

- CustomTileProviderRepositoryImpl read MapTileProviderPrefs.customTileProviders
  synchronously in its constructor. That StateFlow is seeded with null while the
  real value arrives asynchronously from DataStore, so the constructor always read
  the placeholder and cached an empty list permanently. The next edit then
  persisted a list built on that empty baseline, destroying the stored providers
  rather than merely failing to show them, and orphaning their copied files.

- MapViewModel.loadPersistedMapType() matched a saved selection with
  `urlTemplate == saved && isValidTileUrlTemplate(saved)`. A local provider has an
  empty urlTemplate and is persisted by its file:// URI, so both conditions were
  always false and the fallback branch actively cleared the stored preference. The
  renderer resolved the same selection correctly, so the two paths disagreed.

Stored values are now plain Flows rather than StateFlows: a StateFlow has to
invent an initial value, and callers could not tell that placeholder apart from a
genuine "nothing saved". Start-up awaits a real value from both stores before
deciding, and no write is built on a list that has not been loaded. Selection
matching now lives in CustomTileProviderConfig and is shared by the renderer and
the restore path so they cannot drift apart again.

Also fixed: editing a provider left the persisted selection pointing at a stale
key, dropping the layer on the following start.

Adds one deliberate fork behaviour, documented in FORK.md: when no valid saved
selection applies, an imported local provider is selected on start-up so the app
opens on usable offline tiles with no network and no user action. Trade-off: while
an MBTiles provider exists, an explicit switch to a Google base map does not
survive a restart.

Removes feature/map/src/androidUnitTestGoogle/, a source set no Gradle task
builds, whose tests targeted a package and a constructor signature that no longer
exist. Replacement tests live in androidApp/src/testGoogle/.




Claude-Session: https://claude.ai/code/session_015A8oGSLDYu8BW5WknB1qzx

Co-authored-by: Claude <noreply@anthropic.com>
Hides the transport selector and pins the Connections pane to BLE, so the app
presents one way to connect instead of three.

Pinning the pane matters beyond hiding the control. activeTransport was resolved
from a stored preference and from the selected device's address, so a phone that
had TCP or USB stored — from an earlier build or a stray tap — would open on a
pane that is now unreachable, with an empty device list and no visible way back to
Bluetooth. Pinning removes that trap.

Consequences, both intended: network auto-scan can no longer start, and BLE
auto-scan is never gated off. selectTransport is left in place; its scan-stopping
side effects still apply and keeping it limits the divergence from upstream.

Updates the ScannerViewModel tests that encoded upstream's multi-transport
contract, and adds one covering the stored-preference trap.

Fork-specific, not upstreamable: upstream deliberately supports three transports.
Documented in FORK.md.




Claude-Session: https://claude.ai/code/session_015A8oGSLDYu8BW5WknB1qzx

Co-authored-by: Claude <noreply@anthropic.com>
The compass already existed and already does the hard part: it reads the phone's
magnetometer, so the arrow points where to walk rather than showing a bearing
relative to north, and it reports distance, alignment, and the degraded cases.
What it lacked was reach — node list, find the node, open it, tap the compass.

Adds a map toolbar button that lands straight on it:

- NodesRoute.NodeDetail gains openCompass, and NodeDetailScreen opens the overlay
  once the node has loaded when it is set. Keyed on the node so dismissing the
  overlay does not reopen it on the next recomposition.
- MapViewProvider.MapView and LocalMapMainScreenProvider gain navigateToNodeCompass,
  defaulting to plain node details so callers that do not offer the shortcut are
  unaffected. The osmdroid provider accepts it and ignores it.
- The button renders only when a favourite node has a known position, so it is
  never a control that does nothing, and only on the main map.

Targeting is by favourite node rather than a hard-coded node number: mark the
device once and it stays changeable in the field without a rebuild.

The route flag is generic and could go upstream; the map button is opinionated.
Documented in FORK.md.




Claude-Session: https://claude.ai/code/session_015A8oGSLDYu8BW5WknB1qzx

Co-authored-by: Claude <noreply@anthropic.com>
MapButton inherited Material's FilledIconButton container size, which left the
map controls below the 44dp minimum in .skills/design-standards. The size is now
set explicitly, and the glyph goes from Material's 24dp default to 26dp so the
symbol stays readable at arm's length outdoors.

Sized to 44dp rather than the roomier 48dp deliberately: HorizontalFloatingToolbar
does not scroll, and a fully-populated map toolbar — compass, find-favourite,
filter, map type, layers, site planner, location — at 48dp overflows a 360dp-wide
screen and clips its last buttons. 44dp meets the standard and still fits. If the
toolbar ever gains horizontal scrolling, 48dp becomes the better value.

Only one caller passes a modifier (the compass, a rotation), so no existing sizing
is overridden.

Deliberately not changed: the icon glyphs. Which symbols read as unclear needs eyes
on a real screen, and swapping artwork blind trades a known set for an unverified one.




Claude-Session: https://claude.ai/code/session_015A8oGSLDYu8BW5WknB1qzx

Co-authored-by: Claude <noreply@anthropic.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f94ee0a0-4340-4dba-952d-2982f15eac79

📥 Commits

Reviewing files that changed from the base of the PR and between 7710220 and 0ef81d3.

📒 Files selected for processing (31)
  • .skills/compose-ui/strings-index.txt
  • FORK.md
  • androidApp/src/fdroid/kotlin/org/meshtastic/app/map/FdroidMapViewProvider.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/GoogleMapViewProvider.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/MapViewModel.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/model/CustomTileProviderConfig.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/prefs/map/GoogleMapsPrefs.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/repository/CustomTileProviderRepository.kt
  • androidApp/src/main/kotlin/org/meshtastic/app/MainActivity.kt
  • androidApp/src/testGoogle/kotlin/org/meshtastic/app/map/model/CustomTileProviderConfigTest.kt
  • androidApp/src/testGoogle/kotlin/org/meshtastic/app/map/repository/CustomTileProviderRepositoryTest.kt
  • core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/Routes.kt
  • core/prefs/src/commonMain/kotlin/org/meshtastic/core/prefs/map/MapTileProviderPrefsImpl.kt
  • core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/AppPreferences.kt
  • core/resources/src/commonMain/composeResources/values/strings.xml
  • core/ui/detekt-baseline.xml
  • core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/LocalMapMainScreenProvider.kt
  • core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/MapViewProvider.kt
  • feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ScannerViewModel.kt
  • feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt
  • feature/connections/src/commonTest/kotlin/org/meshtastic/feature/connections/ScannerViewModelTest.kt
  • feature/map/src/androidMain/kotlin/org/meshtastic/feature/map/MapScreen.kt
  • feature/map/src/androidUnitTestGoogle/kotlin/org/meshtastic/feature/map/MBTilesProviderTest.kt
  • feature/map/src/androidUnitTestGoogle/kotlin/org/meshtastic/feature/map/MapViewModelTest.kt
  • feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapButton.kt
  • feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapControlsOverlay.kt
  • feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/navigation/MapNavigation.kt
  • feature/node/detekt-baseline.xml
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/NodeDetailScreens.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/navigation/NodesNavigation.kt

📝 Walkthrough

Walkthrough

The pull request adds favorite-node compass navigation, fixes asynchronous offline tile-provider persistence and selection restoration, pins the connections pane to Bluetooth, and documents fork-specific behavior and map-control sizing.

Changes

Favorite-node compass navigation

Layer / File(s) Summary
Compass navigation contracts and wiring
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/MapViewProvider.kt, feature/map/..., androidApp/...
Map screen providers now accept and forward navigateToNodeCompass.
Favorite shortcut and compass route
feature/map/..., feature/node/..., core/navigation/..., core/resources/..., FORK.md
The map overlay opens the first positioned favorite in compass mode. Node routes carry openCompass, and map buttons use 44dp touch targets with 26dp icons.

Offline map persistence

Layer / File(s) Summary
Storage flow and repository loading
core/repository/..., core/prefs/..., androidApp/src/google/.../prefs/..., androidApp/src/google/.../repository/...
Provider preferences use cold flows. Repository reads and writes wait for persisted data and use serialized mutations.
Provider identity and selection restoration
androidApp/src/google/.../model/..., androidApp/src/google/.../MapView.kt, androidApp/src/google/.../MapViewModel.kt
Custom providers use stable selection keys. Startup restores valid selections, clears stale values, prioritizes local providers, and falls back to Google map settings.
Persistence validation and fork documentation
androidApp/src/testGoogle/..., FORK.md
Tests cover cold starts, delayed storage, write ordering, and selection matching. Fork documentation records the persistence behavior.

BLE-only connections

Layer / File(s) Summary
BLE transport behavior and validation
feature/connections/src/commonMain/..., feature/connections/src/commonTest/...
The transport selector was removed. Active transport remains BLE, BLE scanning follows the updated rules, and network auto-scan remains disabled.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested labels: enhancement, bugfix

Suggested reviewers: jamesarich

Sequence Diagram(s)

sequenceDiagram
  participant MapControlsOverlay
  participant MapView
  participant MapNavigation
  participant NodeDetailScaffold
  MapControlsOverlay->>MapView: invoke favorite shortcut
  MapView->>MapNavigation: navigate to favorite node
  MapNavigation->>NodeDetailScaffold: open node with openCompass=true
  NodeDetailScaffold->>NodeDetailScaffold: start and show compass once
Loading
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (description_diff_mismatch). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@marmotte5 marmotte5 closed this Aug 5, 2026
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