From 18dac2eb098fa4839c768a0bbe0faa95b633790e Mon Sep 17 00:00:00 2001 From: James Rich Date: Mon, 18 May 2026 12:06:10 -0500 Subject: [PATCH] fix(map): resolve rebase issues and detekt violations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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> --- .skills/compose-ui/strings-index.txt | 13 ++++ androidApp/build.gradle.kts | 1 - .../composeResources/values/strings.xml | 60 ++++--------------- .../feature/map/OfflineManagerFactory.kt | 2 +- .../org/meshtastic/feature/map/MapScreen.kt | 8 ++- .../map/component/EditWaypointDialog.kt | 2 +- .../map/component/MapFilterDropdown.kt | 2 +- .../feature/map/component/MapStyleSelector.kt | 2 +- .../map/component/MaplibreMapContent.kt | 16 ++--- .../feature/map/component/NodeTrackLayers.kt | 6 +- .../feature/map/component/NodeTrackMap.kt | 8 +-- .../feature/map/component/TracerouteLayers.kt | 6 +- .../feature/map/component/TracerouteMap.kt | 4 +- .../node/metrics/PositionLogScreens.kt | 2 +- .../node/metrics/TracerouteMapScreen.kt | 2 +- 15 files changed, 59 insertions(+), 75 deletions(-) diff --git a/.skills/compose-ui/strings-index.txt b/.skills/compose-ui/strings-index.txt index f6884c99d..5a92c0e05 100644 --- a/.skills/compose-ui/strings-index.txt +++ b/.skills/compose-ui/strings-index.txt @@ -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 diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index 81896d010..e68e5c6cb 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -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) diff --git a/core/resources/src/commonMain/composeResources/values/strings.xml b/core/resources/src/commonMain/composeResources/values/strings.xml index aa8c1fdac..9ea2aaf17 100644 --- a/core/resources/src/commonMain/composeResources/values/strings.xml +++ b/core/resources/src/commonMain/composeResources/values/strings.xml @@ -728,7 +728,12 @@ 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. Select download region Start Download + Dark + Light + OpenStreetMap + Road Map Map style selection + Terrain bearing: %1$d° distance: %2$s Tile download estimate: Tile Source @@ -917,6 +922,13 @@ Now NTP server Number of records + + Download + Download visible region + Downloaded Regions + Offline Maps + Saves tiles for offline use + Unnamed Region Ok to MQTT OK OLED type @@ -1248,53 +1260,6 @@ RX Boosted Gain System Settings - Generate QR Code - NFC is disabled. Please enable it in system settings. - All - - Bluetooth - Configure Bluetooth Permissions - Discovery - Find and identify Meshtastic devices near you. - Configuration - Wirelessly manage your device settings and channels. - Map style selection - OpenStreetMap - Light - Terrain - Road Map - Dark - Offline Maps - Download - Download visible region - Saves tiles for offline use - Downloaded Regions - Unnamed Region - - Battery: %1$d% - Nodes: %1$d online / %2$d total - Uptime: %1$s - ChUtil: %1$s% | AirTX: %2$s% - Traffic: TX %1$d / RX %2$d (D: %3$d) - Relays: %1$d (Canceled: %2$d) - Diagnostics: %1$s - Noise %1$d dBm - Bad %1$d - Dropped %1$d - Heap - %1$d / %2$d - %1$s - Powered - Refresh - Updated - - - Add Network Layer - https://example.com/map.kml or .geojson - - Local MBTiles File - Add Local MBTiles File - TAK (ATAK) TAK Configuration Member Role @@ -1457,6 +1422,7 @@ Warning Delete waypoint? Edit waypoint + Lock to my node New waypoint Received waypoint: %1$s Weight diff --git a/feature/map/src/androidMain/kotlin/org/meshtastic/feature/map/OfflineManagerFactory.kt b/feature/map/src/androidMain/kotlin/org/meshtastic/feature/map/OfflineManagerFactory.kt index 561b05681..26856b139 100644 --- a/feature/map/src/androidMain/kotlin/org/meshtastic/feature/map/OfflineManagerFactory.kt +++ b/feature/map/src/androidMain/kotlin/org/meshtastic/feature/map/OfflineManagerFactory.kt @@ -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() diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/MapScreen.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/MapScreen.kt index 594272bf9..8027020a1 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/MapScreen.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/MapScreen.kt @@ -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 } diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/EditWaypointDialog.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/EditWaypointDialog.kt index 5a2b408e9..8578885c4 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/EditWaypointDialog.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/EditWaypointDialog.kt @@ -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 diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapFilterDropdown.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapFilterDropdown.kt index 5b8cb5993..015fd4756 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapFilterDropdown.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapFilterDropdown.kt @@ -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 diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapStyleSelector.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapStyleSelector.kt index a50c9e2a7..9d3993aab 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapStyleSelector.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapStyleSelector.kt @@ -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 diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MaplibreMapContent.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MaplibreMapContent.kt index 63ad11aa7..6a5b022ee 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MaplibreMapContent.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MaplibreMapContent.kt @@ -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()), ), ) } diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackLayers.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackLayers.kt index fe38673c3..b07d92a5b 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackLayers.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackLayers.kt @@ -49,7 +49,7 @@ private const val SELECTED_OPACITY = 0.9f internal fun NodeTrackLayers( positions: List, 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 diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackMap.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackMap.kt index 78091b1fc..619245a9f 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackMap.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/NodeTrackMap.kt @@ -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, 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, ) } } diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteLayers.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteLayers.kt index 9aa2826dc..22e88f8b1 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteLayers.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteLayers.kt @@ -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, nodes: Map, - 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()) { diff --git a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteMap.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteMap.kt index 68a93726d..f1523e757 100644 --- a/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteMap.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteMap.kt @@ -53,7 +53,7 @@ private const val BOUNDS_PADDING_DP = 64 fun TracerouteMap( tracerouteOverlay: TracerouteOverlay?, tracerouteNodePositions: Map, - onMappableCountChanged: (shown: Int, total: Int) -> Unit, + onMappableCountChange: (shown: Int, total: Int) -> Unit, modifier: Modifier = Modifier, nodes: Map = emptyMap(), ) { @@ -91,7 +91,7 @@ fun TracerouteMap( overlay = tracerouteOverlay, nodePositions = tracerouteNodePositions, nodes = nodes, - onMappableCountChanged = onMappableCountChanged, + onMappableCountChange = onMappableCountChange, ) } } diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt index 14061cc76..25ed83620 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt @@ -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 -> diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteMapScreen.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteMapScreen.kt index 83079acb3..2b49b4bdc 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteMapScreen.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteMapScreen.kt @@ -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 },