feat: show per-message SNR, RSSI and hop count (#2040)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
Łukasz Kosson 2025-06-06 22:41:25 +02:00 committed by GitHub
parent 639213145b
commit 9a371ee9cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 794 additions and 8 deletions

View file

@ -44,6 +44,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.TextUnit
import com.geeksville.mesh.R
private const val SNR_GOOD_THRESHOLD = -7f
@ -132,7 +133,7 @@ fun LoraSignalIndicator(snr: Float, rssi: Int) {
}
@Composable
private fun Snr(snr: Float) {
fun Snr(snr: Float, fontSize: TextUnit = MaterialTheme.typography.labelLarge.fontSize) {
val color: Color = if (snr > SNR_GOOD_THRESHOLD) {
Quality.GOOD.color
} else if (snr > SNR_FAIR_THRESHOLD) {
@ -144,12 +145,12 @@ private fun Snr(snr: Float) {
Text(
text = "%s %.2fdB".format(stringResource(id = R.string.snr), snr),
color = color,
fontSize = MaterialTheme.typography.labelLarge.fontSize
fontSize = fontSize
)
}
@Composable
private fun Rssi(rssi: Int) {
fun Rssi(rssi: Int, fontSize: TextUnit = MaterialTheme.typography.labelLarge.fontSize) {
val color: Color = if (rssi > RSSI_GOOD_THRESHOLD) {
Quality.GOOD.color
} else if (rssi > RSSI_FAIR_THRESHOLD) {
@ -160,7 +161,7 @@ private fun Rssi(rssi: Int) {
Text(
text = "%s %ddBm".format(stringResource(id = R.string.rssi), rssi),
color = color,
fontSize = MaterialTheme.typography.labelLarge.fontSize
fontSize = fontSize
)
}

View file

@ -191,7 +191,15 @@ internal fun MessageList(
onAction = onNodeMenuAction,
onStatusClick = { showStatusDialog = msg },
onSendReaction = { onSendReaction(it, msg.packetId) },
isConnected = isConnected
isConnected = isConnected,
snr = msg.snr,
rssi = msg.rssi,
hopsAway = if (msg.hopsAway > 0) { "%s: %d".format(
stringResource(id = R.string.hops_away),
msg.hopsAway
) } else {
null
}
)
}
}

View file

@ -25,6 +25,7 @@ import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
@ -53,6 +54,8 @@ import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.R
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.ui.common.components.AutoLinkText
import com.geeksville.mesh.ui.common.components.Rssi
import com.geeksville.mesh.ui.common.components.Snr
import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
import com.geeksville.mesh.ui.common.theme.AppTheme
import com.geeksville.mesh.ui.node.components.NodeChip
@ -74,6 +77,9 @@ internal fun MessageItem(
onStatusClick: () -> Unit = {},
onSendReaction: (String) -> Unit = {},
isConnected: Boolean,
snr: Float,
rssi: Int,
hopsAway: String?,
) = Row(
modifier = modifier
.fillMaxWidth()
@ -141,6 +147,17 @@ internal fun MessageItem(
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
if (!fromLocal) {
if (hopsAway == null) {
Snr(snr, fontSize = MaterialTheme.typography.bodySmall.fontSize)
Spacer(Modifier.weight(1f))
Rssi(rssi, fontSize = MaterialTheme.typography.bodySmall.fontSize)
} else { Text(
text = hopsAway,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
) }
Spacer(Modifier.weight(1f))
}
Text(
text = messageTime,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
@ -181,6 +198,9 @@ private fun MessageItemPreview() {
messageStatus = MessageStatus.DELIVERED,
selected = false,
isConnected = true,
snr = 20.5f,
rssi = 90,
hopsAway = null
)
}
}