fix(map): resolve rebase issues and detekt violations

- Remove phantom dd-sdk-android-compose dependency (not in version catalog)
- Deduplicate strings.xml (29 duplicate entries from rebase conflicts)
- Add missing waypoint_lock_to_my_node string resource
- Fix license header year format (2025-2026 → 2026)
- Rename past-tense lambda params to present tense (detekt)
- Use rememberUpdatedState for lambdas in LaunchedEffect
- Fix composable parameter ordering (non-defaults before modifier)
- Cap cluster zoom increment at max zoom level (24)
- Suppress ModifierMissing on OfflineMapContent expect/actual

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich
2026-05-18 12:06:10 -05:00
parent 177f97abdd
commit 18dac2eb09
15 changed files with 59 additions and 75 deletions

View File

@@ -698,7 +698,12 @@ map_reporting_interval_seconds
map_reporting_summary
map_select_download_region
map_start_download
map_style_dark
map_style_light
map_style_osm
map_style_road_map
map_style_selection
map_style_terrain
map_subDescription
map_tile_download_estimate
map_tile_source
@@ -887,6 +892,13 @@ notifications_on_message_receipt
now
ntp_server
number_of_records
### OFFLINE ###
offline_download
offline_download_visible_region
offline_downloaded_regions
offline_maps
offline_saves_tiles
offline_unnamed_region
ok_to_mqtt
okay
oled_type
@@ -1419,3 +1431,4 @@ wind_speed
you
zh_CN
zh_TW
zoom_to_fit_all

View File

@@ -263,7 +263,6 @@ dependencies {
debugImplementation(libs.androidx.compose.ui.test.manifest)
debugImplementation(libs.androidx.glance.preview)
googleImplementation(libs.dd.sdk.android.compose)
googleImplementation(libs.dd.sdk.android.logs)
googleImplementation(libs.dd.sdk.android.rum)
googleImplementation(libs.dd.sdk.android.session.replay)

View File

@@ -728,7 +728,12 @@
<string name="map_reporting_summary">Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, long and short name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name.</string>
<string name="map_select_download_region">Select download region</string>
<string name="map_start_download">Start Download</string>
<string name="map_style_dark">Dark</string>
<string name="map_style_light">Light</string>
<string name="map_style_osm">OpenStreetMap</string>
<string name="map_style_road_map">Road Map</string>
<string name="map_style_selection">Map style selection</string>
<string name="map_style_terrain">Terrain</string>
<string name="map_subDescription">bearing: %1$d° distance: %2$s</string>
<string name="map_tile_download_estimate">Tile download estimate:</string>
<string name="map_tile_source">Tile Source</string>
@@ -917,6 +922,13 @@
<string name="now">Now</string>
<string name="ntp_server">NTP server</string>
<string name="number_of_records">Number of records</string>
<!-- OFFLINE -->
<string name="offline_download">Download</string>
<string name="offline_download_visible_region">Download visible region</string>
<string name="offline_downloaded_regions">Downloaded Regions</string>
<string name="offline_maps">Offline Maps</string>
<string name="offline_saves_tiles">Saves tiles for offline use</string>
<string name="offline_unnamed_region">Unnamed Region</string>
<string name="ok_to_mqtt">Ok to MQTT</string>
<string name="okay">OK</string>
<string name="oled_type">OLED type</string>
@@ -1248,53 +1260,6 @@
<string name="sx126x_rx_boosted_gain">RX Boosted Gain</string>
<string name="system_settings">System Settings</string>
<!-- TAK -->
<string name="generate_qr_code">Generate QR Code</string>
<string name="nfc_disabled">NFC is disabled. Please enable it in system settings.</string>
<string name="all_time">All</string>
<string name="bluetooth_permission">Bluetooth</string>
<string name="configure_bluetooth_permissions">Configure Bluetooth Permissions</string>
<string name="bluetooth_feature_discovery">Discovery</string>
<string name="bluetooth_feature_discovery_description">Find and identify Meshtastic devices near you.</string>
<string name="bluetooth_feature_config">Configuration</string>
<string name="bluetooth_feature_config_description">Wirelessly manage your device settings and channels.</string>
<string name="map_style_selection">Map style selection</string>
<string name="map_style_osm">OpenStreetMap</string>
<string name="map_style_light">Light</string>
<string name="map_style_terrain">Terrain</string>
<string name="map_style_road_map">Road Map</string>
<string name="map_style_dark">Dark</string>
<string name="offline_maps">Offline Maps</string>
<string name="offline_download">Download</string>
<string name="offline_download_visible_region">Download visible region</string>
<string name="offline_saves_tiles">Saves tiles for offline use</string>
<string name="offline_downloaded_regions">Downloaded Regions</string>
<string name="offline_unnamed_region">Unnamed Region</string>
<string name="local_stats_battery">Battery: %1$d%</string>
<string name="local_stats_nodes">Nodes: %1$d online / %2$d total</string>
<string name="local_stats_uptime">Uptime: %1$s</string>
<string name="local_stats_utilization">ChUtil: %1$s% | AirTX: %2$s%</string>
<string name="local_stats_traffic">Traffic: TX %1$d / RX %2$d (D: %3$d)</string>
<string name="local_stats_relays">Relays: %1$d (Canceled: %2$d)</string>
<string name="local_stats_diagnostics_prefix">Diagnostics: %1$s</string>
<string name="local_stats_noise">Noise %1$d dBm</string>
<string name="local_stats_bad">Bad %1$d</string>
<string name="local_stats_dropped">Dropped %1$d</string>
<string name="local_stats_heap">Heap</string>
<string name="local_stats_heap_value">%1$d / %2$d</string>
<string name="local_stats_updated_at">%1$s</string>
<string name="powered">Powered</string>
<string name="refresh">Refresh</string>
<string name="updated">Updated</string>
<!-- Network Map Layers -->
<string name="add_network_layer">Add Network Layer</string>
<string name="network_layer_url_hint" translatable="false">https://example.com/map.kml or .geojson</string>
<string name="local_mbtiles_file">Local MBTiles File</string>
<string name="add_local_mbtiles_file">Add Local MBTiles File</string>
<string name="tak">TAK (ATAK)</string>
<string name="tak_config">TAK Configuration</string>
<string name="tak_role">Member Role</string>
@@ -1457,6 +1422,7 @@
<string name="warning">Warning</string>
<string name="waypoint_delete">Delete waypoint?</string>
<string name="waypoint_edit">Edit waypoint</string>
<string name="waypoint_lock_to_my_node">Lock to my node</string>
<string name="waypoint_new">New waypoint</string>
<string name="waypoint_received">Received waypoint: %1$s</string>
<string name="weight">Weight</string>

View File

@@ -54,7 +54,7 @@ import org.meshtastic.core.resources.offline_unnamed_region
import org.meshtastic.core.ui.icon.CloudDownload
import org.meshtastic.core.ui.icon.MeshtasticIcons
@Suppress("LongMethod")
@Suppress("LongMethod", "ModifierMissing")
@Composable
actual fun OfflineMapContent(styleUri: String, cameraState: CameraState) {
val offlineManager = rememberOfflineManager()

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
* Copyright (c) 2026 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
@@ -72,8 +72,8 @@ private val MAP_OVERLAY_PADDING = 16.dp
fun MapScreen(
onClickNodeChip: (Int) -> Unit,
navigateToNodeDetails: (Int) -> Unit,
modifier: Modifier = Modifier,
viewModel: MapViewModel,
modifier: Modifier = Modifier,
waypointId: Int? = null,
) {
val ourNodeInfo by viewModel.ourNodeInfo.collectAsStateWithLifecycle()
@@ -163,7 +163,7 @@ fun MapScreen(
modifier = Modifier.fillMaxSize(),
gestureOptions = gestureOptions,
styleState = styleState,
onCameraMoved = { position -> viewModel.saveCameraPosition(position) },
onCameraMove = { position -> viewModel.saveCameraPosition(position) },
onWaypointClick = { wpId ->
editingWaypointId = wpId
longPressPosition = null
@@ -235,10 +235,12 @@ fun MapScreen(
// TrackBearing → TrackNorth
bearingUpdate = BearingUpdate.ALWAYS_NORTH
}
BearingUpdate.ALWAYS_NORTH -> {
// TrackNorth → Off
isLocationTrackingEnabled = false
}
BearingUpdate.IGNORE -> {
isLocationTrackingEnabled = false
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
* Copyright (c) 2026 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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
* Copyright (c) 2026 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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
* Copyright (c) 2026 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

View File

@@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@@ -121,10 +122,10 @@ fun MaplibreMapContent(
modifier: Modifier = Modifier,
gestureOptions: GestureOptions = GestureOptions.Standard,
styleState: StyleState = rememberStyleState(),
onCameraMoved: (CameraPosition) -> Unit = {},
onCameraMove: (CameraPosition) -> Unit = {},
onWaypointClick: (Int) -> Unit = {},
onMapLoadFinished: () -> Unit = {},
onMapLoadFailed: (String?) -> Unit = {},
onMapLoad: () -> Unit = {},
onMapLoadFail: (String?) -> Unit = {},
locationState: UserLocationState? = null,
) {
MaplibreMap(
@@ -137,8 +138,8 @@ fun MaplibreMapContent(
onMapLongClick(position)
ClickResult.Consume
},
onMapLoadFinished = onMapLoadFinished,
onMapLoadFailed = onMapLoadFailed,
onMapLoadFinished = onMapLoad,
onMapLoadFailed = onMapLoadFail,
) {
// --- Terrain hillshade overlay ---
if (showHillshade) {
@@ -172,9 +173,10 @@ fun MaplibreMapContent(
}
// Persist camera position when it stops moving
val currentOnCameraMove = rememberUpdatedState(onCameraMove)
LaunchedEffect(cameraState.isCameraMoving) {
if (!cameraState.isCameraMoving) {
onCameraMoved(cameraState.position)
currentOnCameraMove.value(cameraState.position)
}
}
}
@@ -216,7 +218,7 @@ private fun NodeMarkerLayers(
cameraState.animateTo(
cameraState.position.copy(
target = target,
zoom = cameraState.position.zoom + CLUSTER_ZOOM_INCREMENT,
zoom = minOf(cameraState.position.zoom + CLUSTER_ZOOM_INCREMENT, PRECISION_ZOOM_MAX.toDouble()),
),
)
}

View File

@@ -49,7 +49,7 @@ private const val SELECTED_OPACITY = 0.9f
internal fun NodeTrackLayers(
positions: List<org.meshtastic.proto.Position>,
selectedPositionTime: Int? = null,
onPositionSelected: ((Int) -> Unit)? = null,
onSelectPosition: ((Int) -> Unit)? = null,
) {
if (positions.size < 2) return
@@ -87,8 +87,8 @@ internal fun NodeTrackLayers(
strokeColor = const(Color.White),
onClick = { features ->
val time = features.firstOrNull()?.properties?.get("time")?.jsonPrimitive?.content?.toIntOrNull()
if (time != null && onPositionSelected != null) {
onPositionSelected(time)
if (time != null && onSelectPosition != null) {
onSelectPosition(time)
ClickResult.Consume
} else {
ClickResult.Pass

View File

@@ -39,8 +39,8 @@ private const val BOUNDS_PADDING_DP = 48
/**
* Embeddable position-track map showing a polyline with markers for the given positions.
*
* Supports synchronized selection: [selectedPositionTime] highlights the corresponding marker and [onPositionSelected]
* is called when a marker is tapped, passing the `Position.time` for the host screen to synchronize its card list.
* Supports synchronized selection: [selectedPositionTime] highlights the corresponding marker and [onSelectPosition] is
* called when a marker is tapped, passing the `Position.time` for the host screen to synchronize its card list.
*
* Replaces both the Google Maps and OSMDroid flavor-specific NodeTrackMap implementations.
*/
@@ -49,7 +49,7 @@ fun NodeTrackMap(
positions: List<Position>,
modifier: Modifier = Modifier,
selectedPositionTime: Int? = null,
onPositionSelected: ((Int) -> Unit)? = null,
onSelectPosition: ((Int) -> Unit)? = null,
) {
val geoPositions =
remember(positions) { positions.mapNotNull { pos -> toGeoPositionOrNull(pos.latitude_i, pos.longitude_i) } }
@@ -82,7 +82,7 @@ fun NodeTrackMap(
NodeTrackLayers(
positions = positions,
selectedPositionTime = selectedPositionTime,
onPositionSelected = onPositionSelected,
onSelectPosition = onSelectPosition,
)
}
}

View File

@@ -19,6 +19,7 @@ package org.meshtastic.feature.map.component
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
@@ -66,7 +67,7 @@ internal fun TracerouteLayers(
overlay: TracerouteOverlay?,
nodePositions: Map<Int, org.meshtastic.proto.Position>,
nodes: Map<Int, Node>,
onMappableCountChanged: (shown: Int, total: Int) -> Unit,
onMappableCountChange: (shown: Int, total: Int) -> Unit,
) {
if (overlay == null) return
@@ -81,7 +82,8 @@ internal fun TracerouteLayers(
// Report mappable count via side effect (avoid state updates during composition)
val mappableCount = routeData.hopFeatures.features.size
val totalCount = overlay.relatedNodeNums.size
LaunchedEffect(mappableCount, totalCount) { onMappableCountChanged(mappableCount, totalCount) }
val currentOnMappableCountChange = rememberUpdatedState(onMappableCountChange)
LaunchedEffect(mappableCount, totalCount) { currentOnMappableCountChange.value(mappableCount, totalCount) }
// Forward route line
if (routeData.forwardLine.features.isNotEmpty()) {

View File

@@ -53,7 +53,7 @@ private const val BOUNDS_PADDING_DP = 64
fun TracerouteMap(
tracerouteOverlay: TracerouteOverlay?,
tracerouteNodePositions: Map<Int, Position>,
onMappableCountChanged: (shown: Int, total: Int) -> Unit,
onMappableCountChange: (shown: Int, total: Int) -> Unit,
modifier: Modifier = Modifier,
nodes: Map<Int, Node> = emptyMap(),
) {
@@ -91,7 +91,7 @@ fun TracerouteMap(
overlay = tracerouteOverlay,
nodePositions = tracerouteNodePositions,
nodes = nodes,
onMappableCountChanged = onMappableCountChanged,
onMappableCountChange = onMappableCountChange,
)
}
}

View File

@@ -67,7 +67,7 @@ fun PositionLogScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
positions = positions,
modifier = modifier,
selectedPositionTime = selectedTime,
onPositionSelected = { time -> onPointSelected(time.toDouble()) },
onSelectPosition = { time -> onPointSelected(time.toDouble()) },
)
},
listPart = { modifier, selectedX, lazyListState, onCardClick ->

View File

@@ -118,7 +118,7 @@ private fun TracerouteMapScaffold(
TracerouteMap(
tracerouteOverlay = overlay,
tracerouteNodePositions = snapshotPositions,
onMappableCountChanged = { shown: Int, total: Int ->
onMappableCountChange = { shown: Int, total: Int ->
tracerouteNodesShown = shown
tracerouteNodesTotal = total
},