Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d4ab600
initial commit : maplibre loaded
mdecourcy Nov 14, 2025
3b6883b
clustering, node info on click, basic layering
mdecourcy Nov 14, 2025
11ef38f
cluster fan-out, role-based colors, legend toggle, and UX polish
mdecourcy Nov 14, 2025
e6b91d0
better clustering, add filtering etc
mdecourcy Nov 14, 2025
dad09d8
styles working
mdecourcy Nov 18, 2025
b8f9884
waypoint mgmt, waypoint rendering, dropdown for style selector
mdecourcy Nov 18, 2025
62e7aaf
change some colors, hide user loc on gps toggle
mdecourcy Nov 18, 2025
097c177
janitorial work: code dedup, rm unused vars, rm debug work
mdecourcy Nov 18, 2025
6e0cc4e
refactor
mdecourcy Nov 18, 2025
608ce9a
refactor
mdecourcy Nov 18, 2025
9ccfdbd
initial kml geojson kmz support
mdecourcy Nov 18, 2025
3b37f9e
initial kml, geojson, kmz, caching support, match button style of goo…
mdecourcy Nov 19, 2025
836cad5
chore(deps): update com.google.firebase:firebase-bom to v34.6.0 (#3704)
renovate[bot] Nov 14, 2025
58bc55c
feat: jump to oldest unread message upon opening a thread, display di…
mdecourcy Nov 14, 2025
7e6579f
fix: address backfill issue on tcp connections; add logging (#3676)
mdecourcy Nov 14, 2025
4a07e4d
feat(build): Add distinct names for debug builds (#3707)
jamesarich Nov 15, 2025
43548e6
chore(deps): update google maps compose to v6.12.2 (#3706)
renovate[bot] Nov 15, 2025
edd9b29
Update strings.xml (#3711)
b8b8 Nov 15, 2025
c096572
add back arrow to the channelConfig screen (#3713)
DaneEvans Nov 16, 2025
f70c118
refactor(ble): Migrate to Nordic BLE Library for scanning and bonding…
jamesarich Nov 16, 2025
bdf3b2c
refactor(coroutines): Use SupervisorJobs (#3714)
jamesarich Nov 16, 2025
7bfefbb
chore: Update VERSION_NAME_BASE to 2.7.7 (#3715)
jamesarich Nov 16, 2025
de127ec
fix #3509: MQTT reporting interval not being selected, and sent to no…
DaneEvans Nov 16, 2025
d5ee9c8
chore(deps): update com.squareup.okhttp3:logging-interceptor to v5.3.…
renovate[bot] Nov 16, 2025
7904954
feat #3642: Add infrastructure to the list of filters. (#3716)
DaneEvans Nov 17, 2025
a0e7452
fix(bluetooth): Check for permissions before accessing bonded devices…
jamesarich Nov 17, 2025
8aab2d5
feat(connections): `Connecting` state refactor (#3722)
jamesarich Nov 17, 2025
031d5a2
feat(ui): Display BLE signal strength for connected device (#3721)
jamesarich Nov 17, 2025
aca34f1
feat(bluetooth): Request location permission for BLE scan pre S (#3724)
jamesarich Nov 17, 2025
a502629
chore(deps): update gradle to v9.2.1 (#3723)
renovate[bot] Nov 17, 2025
0da991b
feat(ui): Improve scan status text display (#3725)
jamesarich Nov 18, 2025
5161168
feat: polish jump to unread message (#3710)
mdecourcy Nov 18, 2025
74c3007
feat(nsd): Add support for Android 14+ NSD resolving (#3731)
jamesarich Nov 18, 2025
04b185d
New Crowdin updates (#3734)
jamesarich Nov 18, 2025
3e24122
chore(deps): update com.squareup.okhttp3:logging-interceptor to v5.3.…
renovate[bot] Nov 18, 2025
01c52e4
ux polish
mdecourcy Nov 19, 2025
b9492cd
utilize maplibre ambient caching api; initial work on node tracks
mdecourcy Nov 20, 2025
dec6584
clean up legacy ui bits
mdecourcy Nov 20, 2025
66102db
logging, center on click etc
mdecourcy Nov 21, 2025
c459080
center on click, refactor poc main
mdecourcy Nov 21, 2025
e209eb5
initial pass @ heatmap
mdecourcy Nov 21, 2025
86b5810
Merge origin/main into poc/maplibre
mdecourcy Nov 22, 2025
094ac17
merge main
mdecourcy Nov 22, 2025
641328c
merge main
mdecourcy Nov 22, 2025
d884ee0
Remove maplibre-native-integration.md design doc
mdecourcy Nov 22, 2025
00faafa
Remove wireless-install.sh personal script
mdecourcy Nov 22, 2025
5dd0805
Use MapLibre for node track visualization instead of osmdroid
mdecourcy Nov 22, 2025
ec9efcc
Make MapLibre the default map implementation
mdecourcy Nov 22, 2025
1a69897
Fix type mismatch: use MapViewModel instead of BaseMapViewModel
mdecourcy Nov 22, 2025
a51c1cf
node tracks - clusters and nodes now hidden
mdecourcy Nov 22, 2025
4dba868
fix InvalidLatLngBoundsException
mdecourcy Nov 22, 2025
8ecec7f
fix kmz upload
mdecourcy Nov 22, 2025
883bde0
debug logging
mdecourcy Nov 22, 2025
da06108
spotless
mdecourcy Nov 22, 2025
ac47683
first pass - janitorial work
mdecourcy Nov 22, 2025
e843a33
second pass - janitorial work
mdecourcy Nov 22, 2025
7231f7d
refactors and appease copilot
mdecourcy Nov 22, 2025
b2522ad
better waypoint
mdecourcy Nov 23, 2025
5d96d06
better waypoint
mdecourcy Nov 24, 2025
71d9caf
Merge remote-tracking branch 'origin/main' into poc/maplibre
mdecourcy Nov 24, 2025
7e38aaa
Merge branch 'main' of https://github.com/mdecourcy/Meshtastic-Androi…
mdecourcy Nov 25, 2025
ead31e6
Merge branch 'main' of https://github.com/mdecourcy/Meshtastic-Androi…
mdecourcy Nov 27, 2025
0c33599
Merge branch 'main' of https://github.com/mdecourcy/Meshtastic-Androi…
mdecourcy Nov 28, 2025
980578a
Merge branch 'main' of https://github.com/mdecourcy/Meshtastic-Androi…
mdecourcy Nov 30, 2025
973c307
Merge branch 'main' of https://github.com/mdecourcy/Meshtastic-Androi…
mdecourcy Dec 2, 2025
b19240a
fix: min/max zoom bounds
mdecourcy Dec 2, 2025
1638b4e
feat: cluster tap zoom
mdecourcy Dec 2, 2025
d10d325
feat: nodeColor/roleColor toggle, defaulting to nodeColor
mdecourcy Dec 3, 2025
55de4bb
feat: lifecycle mgmt
mdecourcy Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ dependencies {
googleImplementation(libs.location.services)
googleImplementation(libs.play.services.maps)

// MapLibre for F-Droid flavor (POC - additive, does not remove osmdroid yet)
fdroidImplementation("org.maplibre.gl:android-sdk:12.1.0")

fdroidImplementation(libs.osmdroid.android)
fdroidImplementation(libs.osmdroid.geopackage) { exclude(group = "com.j256.ormlite") }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ fun NavGraphBuilder.mapGraph(navController: NavHostController) {
restoreState = true
}
},
navigateToNodeDetails = { navController.navigate(NodesRoutes.NodeDetailGraph(it)) },
navigateToNodeDetails = {
navController.navigate(NodesRoutes.NodeDetailGraph(it)) {
// Don't save the state of the map when navigating to node details
// This ensures pressing back from node detail returns to map, not node list
launchSingleTop = false
}
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,20 @@ fun NavGraphBuilder.nodeDetailGraph(navController: NavHostController, scrollToTo
),
),
) { backStackEntry ->
val args = backStackEntry.toRoute<NodesRoutes.NodeDetail>()
// Get destNum from the parent graph (NodeDetailGraph) if available,
// otherwise from the route itself (for deep links)
val parentGraphEntry =
remember(backStackEntry) { navController.getBackStackEntry<NodesRoutes.NodeDetailGraph>() }
val graphArgs = parentGraphEntry.toRoute<NodesRoutes.NodeDetailGraph>()
val routeArgs = backStackEntry.toRoute<NodesRoutes.NodeDetail>()
val nodeId = graphArgs.destNum ?: routeArgs.destNum

// When navigating directly to NodeDetail (e.g. from Map or deep link),
// we use the Adaptive screen initialized with the specific node ID.
AdaptiveNodeListScreen(
navController = navController,
scrollToTopEvents = scrollToTopEvents,
initialNodeId = args.destNum,
initialNodeId = nodeId,
onNavigateToMessages = { navController.navigate(ContactsRoutes.Messages(it)) },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,23 @@ fun AdaptiveNodeListScreen(
val scope = rememberCoroutineScope()
val backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange

// Handle back navigation from detail pane
BackHandler(enabled = navigator.currentDestination?.pane == ListDetailPaneScaffoldRole.Detail) {
scope.launch { navigator.navigateBack(backNavigationBehavior) }
if (initialNodeId != null) {
// If opened with initialNodeId (from Map/Connections), always go back to previous screen
navController.navigateUp()
} else {
// Normal navigation within scaffold (when opened from Nodes tab)
scope.launch { navigator.navigateBack(backNavigationBehavior) }
}
}

// Handle back from list pane when opened with initialNodeId
// This handles the case where user is on list pane after scaffold navigation on tablet
BackHandler(
enabled = initialNodeId != null && navigator.currentDestination?.pane == ListDetailPaneScaffoldRole.List,
) {
navController.navigateUp()
}

LaunchedEffect(initialNodeId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.meshtastic.core.prefs.di

import android.content.Context
import android.content.SharedPreferences
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.meshtastic.core.prefs.map.MapLibrePrefs
import org.meshtastic.core.prefs.map.MapLibrePrefsImpl
import javax.inject.Qualifier
import javax.inject.Singleton

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class MapLibreSharedPreferences

@Module
@InstallIn(SingletonComponent::class)
object MapLibreProvidesModule {
@Provides
@Singleton
@MapLibreSharedPreferences
fun provideMapLibreSharedPreferences(@ApplicationContext context: Context): SharedPreferences =
context.getSharedPreferences("maplibre_prefs", Context.MODE_PRIVATE)
}

@Module
@InstallIn(SingletonComponent::class)
abstract class MapLibreBindsModule {
@Binds @Singleton
abstract fun bindMapLibrePrefs(mapLibrePrefsImpl: MapLibrePrefsImpl): MapLibrePrefs
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.meshtastic.core.prefs.map

import android.content.SharedPreferences
import org.meshtastic.core.prefs.DoublePrefDelegate
import org.meshtastic.core.prefs.NullableStringPrefDelegate
import org.meshtastic.core.prefs.PrefDelegate
import org.meshtastic.core.prefs.di.MapLibreSharedPreferences
import javax.inject.Inject
import javax.inject.Singleton

/** Interface for prefs specific to MapLibre. For general map prefs, see MapPrefs. */
interface MapLibrePrefs {
var cameraTargetLat: Double
var cameraTargetLng: Double
var cameraZoom: Double
var cameraBearing: Double
var cameraTilt: Double
var shouldRestoreCameraPosition: Boolean
var markerColorMode: String
var clusteringEnabled: Boolean
var heatmapEnabled: Boolean
var baseStyleIndex: Int
var customTileUrl: String?
var usingCustomTiles: Boolean
}

@Singleton
class MapLibrePrefsImpl @Inject constructor(@MapLibreSharedPreferences prefs: SharedPreferences) : MapLibrePrefs {
override var cameraTargetLat: Double by DoublePrefDelegate(prefs, "camera_target_lat", 0.0)
override var cameraTargetLng: Double by DoublePrefDelegate(prefs, "camera_target_lng", 0.0)
override var cameraZoom: Double by DoublePrefDelegate(prefs, "camera_zoom", 15.0)
override var cameraBearing: Double by DoublePrefDelegate(prefs, "camera_bearing", 0.0)
override var cameraTilt: Double by DoublePrefDelegate(prefs, "camera_tilt", 0.0)
override var shouldRestoreCameraPosition: Boolean by PrefDelegate(prefs, "should_restore_camera_position", false)
override var markerColorMode: String by PrefDelegate(prefs, "marker_color_mode", "NODE")
override var clusteringEnabled: Boolean by PrefDelegate(prefs, "clustering_enabled", true)
override var heatmapEnabled: Boolean by PrefDelegate(prefs, "heatmap_enabled", false)
override var baseStyleIndex: Int by PrefDelegate(prefs, "base_style_index", 0)
override var customTileUrl: String? by NullableStringPrefDelegate(prefs, "custom_tile_url", null)
override var usingCustomTiles: Boolean by PrefDelegate(prefs, "using_custom_tiles", false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,12 @@
<string name="add_layer_button">Add Layer</string>
<string name="hide_layer">Hide Layer</string>
<string name="show_layer">Show Layer</string>
<string name="role_legend_title">Show role legend</string>
<string name="role_legend_description">Display a role-to-color legend overlay on the map.</string>
<string name="marker_color_mode_title">Marker colors</string>
<string name="marker_color_mode_description">Switch between role colors and node-specific colors.</string>
<string name="marker_color_mode_role">Role colors</string>
<string name="marker_color_mode_node">Node colors</string>
<string name="remove_layer">Remove Layer</string>
<string name="add_layer">Add Layer</string>
<string name="nodes_at_this_location">Nodes at this location</string>
Expand Down
3 changes: 3 additions & 0 deletions feature/map/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ dependencies {
implementation(libs.osmdroid.android)
implementation(libs.timber)

// MapLibre for fdroid POC
fdroidImplementation("org.maplibre.gl:android-sdk:12.1.0")

googleImplementation(libs.location.services)
googleImplementation(libs.maps.compose)
googleImplementation(libs.maps.compose.utils)
Expand Down
Loading