Skip to content

Commit 46c9364

Browse files
authored
fix(nodes): refresh distance when display units change (#6351)
1 parent c9506d2 commit 46c9364

3 files changed

Lines changed: 95 additions & 4 deletions

File tree

core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/NodeItem.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ fun NodeItem(
106106
Config.DisplayConfig.DisplayUnits.fromValue(distanceUnits) ?: Config.DisplayConfig.DisplayUnits.METRIC
107107
}
108108
val distance =
109-
remember(thisNode, thatNode) { thisNode?.distance(thatNode)?.takeIf { it > 0 }?.toDistanceString(system) }
109+
remember(thisNode, thatNode, system) {
110+
thisNode?.distance(thatNode)?.takeIf { it > 0 }?.toDistanceString(system)
111+
}
110112
val bearingDegrees = remember(thisNode, thatNode) { thisNode?.bearing(thatNode) }
111113

112114
val contentColor = MaterialTheme.colorScheme.onSurface
@@ -133,7 +135,7 @@ fun NodeItem(
133135
val a11yStrings = rememberNodeDescriptionStrings()
134136
val modemPreset = LocalModemPreset.current
135137
val nodeDescription =
136-
remember(thatNode, a11yStrings, modemPreset) {
138+
remember(thatNode, distance, a11yStrings, modemPreset) {
137139
buildNodeDescription(
138140
name = originalLongName,
139141
isOnline = thatNode.isOnline,

core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/NodeItemCompact.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ fun NodeItemCompact(
122122
Config.DisplayConfig.DisplayUnits.fromValue(distanceUnits) ?: Config.DisplayConfig.DisplayUnits.METRIC
123123
}
124124
val distance =
125-
remember(thisNode, thatNode) { thisNode?.distance(thatNode)?.takeIf { it > 0 }?.toDistanceString(system) }
125+
remember(thisNode, thatNode, system) {
126+
thisNode?.distance(thatNode)?.takeIf { it > 0 }?.toDistanceString(system)
127+
}
126128
val bearingDegrees = remember(thisNode, thatNode) { thisNode?.bearing(thatNode) }
127129
val unmessageable =
128130
remember(thatNode) {
@@ -143,7 +145,7 @@ fun NodeItemCompact(
143145
val a11yStrings = rememberNodeDescriptionStrings()
144146
val modemPreset = LocalModemPreset.current
145147
val nodeDescription =
146-
remember(thatNode, lastHeardIsRelative, a11yStrings, modemPreset) {
148+
remember(thatNode, distance, lastHeardIsRelative, a11yStrings, modemPreset) {
147149
buildNodeDescription(
148150
name = longName,
149151
isOnline = thatNode.isOnline,
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2026 Meshtastic LLC
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
package org.meshtastic.core.ui.component
18+
19+
import androidx.compose.material3.MaterialTheme
20+
import androidx.compose.runtime.getValue
21+
import androidx.compose.runtime.mutableIntStateOf
22+
import androidx.compose.runtime.setValue
23+
import androidx.compose.ui.test.ComposeUiTest
24+
import androidx.compose.ui.test.ExperimentalTestApi
25+
import androidx.compose.ui.test.assertIsDisplayed
26+
import androidx.compose.ui.test.onNodeWithContentDescription
27+
import androidx.compose.ui.test.onNodeWithText
28+
import androidx.compose.ui.test.v2.runComposeUiTest
29+
import org.meshtastic.core.model.ConnectionState
30+
import org.meshtastic.core.model.Node
31+
import org.meshtastic.core.model.util.toDistanceString
32+
import org.meshtastic.proto.Config.DisplayConfig.DisplayUnits
33+
import org.meshtastic.proto.Position
34+
import org.meshtastic.proto.User
35+
import kotlin.test.Test
36+
37+
@OptIn(ExperimentalTestApi::class)
38+
class NodeItemDistanceUnitsTest {
39+
40+
@Test
41+
fun nodeItem_updatesDistanceWhenUnitsChange() = runComposeUiTest {
42+
assertDistanceUpdates { thisNode, thatNode, distanceUnits ->
43+
NodeItem(
44+
thisNode = thisNode,
45+
thatNode = thatNode,
46+
distanceUnits = distanceUnits,
47+
tempInFahrenheit = false,
48+
connectionState = ConnectionState.Connected,
49+
)
50+
}
51+
}
52+
53+
@Test
54+
fun nodeItemCompact_updatesDistanceWhenUnitsChange() = runComposeUiTest {
55+
assertDistanceUpdates { thisNode, thatNode, distanceUnits ->
56+
NodeItemCompact(thisNode = thisNode, thatNode = thatNode, distanceUnits = distanceUnits)
57+
}
58+
}
59+
60+
private fun ComposeUiTest.assertDistanceUpdates(
61+
content: @androidx.compose.runtime.Composable (Node, Node, Int) -> Unit,
62+
) {
63+
val thisNode = node(num = 1, latitudeI = 100_000_000, longitudeI = 100_000_000)
64+
val thatNode = node(num = 2, latitudeI = 100_000_000, longitudeI = 110_000_000)
65+
val distanceMeters = requireNotNull(thisNode.distance(thatNode))
66+
val metricDistance = distanceMeters.toDistanceString(DisplayUnits.METRIC)
67+
val imperialDistance = distanceMeters.toDistanceString(DisplayUnits.IMPERIAL)
68+
var distanceUnits by mutableIntStateOf(DisplayUnits.METRIC.value)
69+
70+
setContent { MaterialTheme { content(thisNode, thatNode, distanceUnits) } }
71+
72+
onNodeWithText(metricDistance).assertIsDisplayed()
73+
74+
runOnIdle { distanceUnits = DisplayUnits.IMPERIAL.value }
75+
76+
onNodeWithText(metricDistance).assertDoesNotExist()
77+
onNodeWithText(imperialDistance).assertIsDisplayed()
78+
onNodeWithContentDescription(metricDistance, substring = true).assertDoesNotExist()
79+
onNodeWithContentDescription(imperialDistance, substring = true).assertIsDisplayed()
80+
}
81+
82+
private fun node(num: Int, latitudeI: Int, longitudeI: Int): Node = Node(
83+
num = num,
84+
user = User(id = "!$num", long_name = "Node $num"),
85+
position = Position(latitude_i = latitudeI, longitude_i = longitudeI),
86+
)
87+
}

0 commit comments

Comments
 (0)