mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat(map): replace Google Maps + OSMDroid with unified MapLibre Compose Multiplatform
Replace the dual flavor-specific map implementations (Google Maps for google, OSMDroid for fdroid) with a single MapLibre Compose Multiplatform implementation in feature:map/commonMain, eliminating ~8,500 lines of duplicated code. Key changes: - Add maplibre-compose v0.12.1 dependency (KMP: Android, Desktop, iOS) - Create unified MapViewModel with camera persistence via MapCameraPrefs - Create MapScreen, MaplibreMapContent, NodeTrackLayers, TracerouteLayers, InlineMap, NodeTrackMap, TracerouteMap, NodeMapScreen in commonMain - Create MapStyle enum with predefined OpenFreeMap tile styles - Create GeoJsonConverters for Node/Waypoint/Position to GeoJSON - Move TracerouteMapScreen from feature:node/androidMain to commonMain - Wire navigation to use direct imports instead of CompositionLocal providers - Delete 61 flavor-specific map files (google + fdroid source sets) - Remove 8 CompositionLocal map providers from core:ui - Remove SharedMapViewModel (replaced by new MapViewModel) - Remove dead google-maps and osmdroid entries from version catalog - Add MapViewModelTest with 10 test cases in commonTest Baseline verified: spotlessCheck, detekt, assembleGoogleDebug, allTests all pass.
This commit is contained in:
parent
a2763bdfeb
commit
598cae564e
86 changed files with 1653 additions and 8333 deletions
|
|
@ -43,7 +43,7 @@ import org.meshtastic.core.resources.open_compass
|
|||
import org.meshtastic.core.ui.icon.Compass
|
||||
import org.meshtastic.core.ui.icon.Distance
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.util.LocalInlineMapProvider
|
||||
import org.meshtastic.feature.map.component.InlineMap
|
||||
import org.meshtastic.feature.node.model.NodeDetailAction
|
||||
import org.meshtastic.proto.Config
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ internal fun PositionInlineContent(
|
|||
private fun PositionMap(node: Node, distance: String?) {
|
||||
Box(modifier = Modifier.padding(vertical = 4.dp)) {
|
||||
Surface(shape = MaterialTheme.shapes.large, modifier = Modifier.fillMaxWidth().height(MAP_HEIGHT_DP.dp)) {
|
||||
LocalInlineMapProvider.current(node, Modifier.fillMaxSize())
|
||||
InlineMap(node, Modifier.fillMaxSize())
|
||||
}
|
||||
if (distance != null && distance.isNotEmpty()) {
|
||||
Surface(
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import org.meshtastic.core.resources.position_log
|
|||
import org.meshtastic.core.ui.icon.Delete
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Refresh
|
||||
import org.meshtastic.core.ui.util.LocalNodeTrackMapProvider
|
||||
import org.meshtastic.core.ui.util.rememberSaveFileLauncher
|
||||
import org.meshtastic.feature.map.component.NodeTrackMap
|
||||
|
||||
@Composable
|
||||
fun PositionLogScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
|
||||
|
|
@ -41,9 +41,6 @@ fun PositionLogScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
|
|||
|
||||
val exportPositionLauncher = rememberSaveFileLauncher { uri -> viewModel.savePositionCSV(uri, positions) }
|
||||
|
||||
val trackMap = LocalNodeTrackMapProvider.current
|
||||
val destNum = state.node?.num ?: 0
|
||||
|
||||
BaseMetricScreen(
|
||||
onNavigateUp = onNavigateUp,
|
||||
telemetryType = null,
|
||||
|
|
@ -66,7 +63,12 @@ fun PositionLogScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
|
|||
},
|
||||
chartPart = { modifier, selectedX, _, onPointSelected ->
|
||||
val selectedTime = selectedX?.toInt()
|
||||
trackMap(destNum, positions, modifier, selectedTime) { time -> onPointSelected(time.toDouble()) }
|
||||
NodeTrackMap(
|
||||
positions = positions,
|
||||
modifier = modifier,
|
||||
selectedPositionTime = selectedTime,
|
||||
onPositionSelected = { time -> onPointSelected(time.toDouble()) },
|
||||
)
|
||||
},
|
||||
listPart = { modifier, selectedX, lazyListState, onCardClick ->
|
||||
LazyColumn(modifier = modifier.fillMaxSize(), state = lazyListState) {
|
||||
|
|
|
|||
|
|
@ -52,8 +52,7 @@ import org.meshtastic.core.ui.component.MainAppBar
|
|||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Route
|
||||
import org.meshtastic.core.ui.theme.TracerouteColors
|
||||
import org.meshtastic.core.ui.util.LocalTracerouteMapOverlayInsetsProvider
|
||||
import org.meshtastic.core.ui.util.LocalTracerouteMapProvider
|
||||
import org.meshtastic.feature.map.component.TracerouteMap
|
||||
import org.meshtastic.proto.Position
|
||||
|
||||
@Composable
|
||||
|
|
@ -102,7 +101,6 @@ private fun TracerouteMapScaffold(
|
|||
) {
|
||||
var tracerouteNodesShown by remember { mutableStateOf(0) }
|
||||
var tracerouteNodesTotal by remember { mutableStateOf(0) }
|
||||
val insets = LocalTracerouteMapOverlayInsetsProvider.current
|
||||
Scaffold(
|
||||
topBar = {
|
||||
MainAppBar(
|
||||
|
|
@ -117,18 +115,18 @@ private fun TracerouteMapScaffold(
|
|||
},
|
||||
) { paddingValues ->
|
||||
Box(modifier = modifier.fillMaxSize().padding(paddingValues)) {
|
||||
LocalTracerouteMapProvider.current(
|
||||
overlay,
|
||||
snapshotPositions,
|
||||
{ shown: Int, total: Int ->
|
||||
TracerouteMap(
|
||||
tracerouteOverlay = overlay,
|
||||
tracerouteNodePositions = snapshotPositions,
|
||||
onMappableCountChanged = { shown: Int, total: Int ->
|
||||
tracerouteNodesShown = shown
|
||||
tracerouteNodesTotal = total
|
||||
},
|
||||
Modifier.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.align(insets.overlayAlignment).padding(insets.overlayPadding),
|
||||
horizontalAlignment = insets.contentHorizontalAlignment,
|
||||
modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
TracerouteNodeCount(shown = tracerouteNodesShown, total = tracerouteNodesTotal)
|
||||
|
|
@ -66,6 +66,7 @@ import org.meshtastic.feature.node.metrics.PositionLogScreen
|
|||
import org.meshtastic.feature.node.metrics.PowerMetricsScreen
|
||||
import org.meshtastic.feature.node.metrics.SignalMetricsScreen
|
||||
import org.meshtastic.feature.node.metrics.TracerouteLogScreen
|
||||
import org.meshtastic.feature.node.metrics.TracerouteMapScreen
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||
|
|
@ -143,8 +144,14 @@ fun EntryProviderScope<NavKey>.nodeDetailGraph(
|
|||
}
|
||||
|
||||
entry<NodeDetailRoute.TracerouteMap>(metadata = { ListDetailSceneStrategy.extraPane() }) { args ->
|
||||
val tracerouteMapScreen = org.meshtastic.core.ui.util.LocalTracerouteMapScreenProvider.current
|
||||
tracerouteMapScreen(args.destNum, args.requestId, args.logUuid) { backStack.removeLastOrNull() }
|
||||
val metricsViewModel = koinViewModel<MetricsViewModel> { parametersOf(args.destNum) }
|
||||
metricsViewModel.setNodeId(args.destNum)
|
||||
TracerouteMapScreen(
|
||||
metricsViewModel = metricsViewModel,
|
||||
requestId = args.requestId,
|
||||
logUuid = args.logUuid,
|
||||
onNavigateUp = { backStack.removeLastOrNull() },
|
||||
)
|
||||
}
|
||||
|
||||
NodeDetailScreen.entries.forEach { routeInfo ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue