diff --git a/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt b/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt index def972c55ca..4108deeeeb2 100644 --- a/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt +++ b/androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt @@ -1262,8 +1262,24 @@ private fun TracerouteMapContent( ) } displayNodes.forEach { node -> - val markerState = rememberUpdatedMarkerState(position = node.position.toLatLng()) - MarkerComposable(state = markerState, zIndex = 4f) { NodeChip(node = node) } + // Key by the stable node num so each marker's composition state (and MarkerComposable's cached + // icon bitmap) stays bound to its node. Without this, reordering displayNodes between reloads + // reuses marker slots positionally and swaps node labels/positions (#6197). The remaining keys + // are every NodeChip input (short name, colors, ignored strike-through) so the rendered chip + // bitmap refreshes when node metadata changes. + key(node.num) { + val markerState = rememberUpdatedMarkerState(position = node.position.toLatLng()) + MarkerComposable( + node.num, + node.user.short_name, + node.colors, + node.isIgnored, + state = markerState, + zIndex = 4f, + ) { + NodeChip(node = node) + } + } } } diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt index 7306151d616..b38a2442494 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt @@ -24,6 +24,7 @@ import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -267,10 +268,12 @@ private fun TracerouteCardContent(time: String, summaryText: String, icon: Image private fun TracerouteCardMetrics(point: TraceroutePoint) { if (point.forwardHops == null && point.returnHops == null && point.roundTripSeconds == null) return Spacer(modifier = Modifier.height(4.dp)) - Row( + // FlowRow so the three metric labels wrap onto additional lines when they don't fit the card width + // (e.g. long translated strings), rather than the last item being crushed and wrapped per character (#5743). + FlowRow( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalAlignment = Alignment.CenterVertically, + verticalArrangement = Arrangement.spacedBy(4.dp), ) { point.forwardHops?.let { hops -> Row(verticalAlignment = Alignment.CenterVertically) {