diff --git a/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt b/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt index 162f755c9..4a3d43b2c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import com.geeksville.mesh.R import com.geeksville.mesh.database.entity.NodeEntity +import com.geeksville.mesh.ui.components.NodeSignalQuality import com.geeksville.mesh.ui.preview.NodeEntityPreviewParameterProvider import com.geeksville.mesh.ui.theme.AppTheme @@ -21,7 +22,7 @@ fun signalInfo( modifier: Modifier = Modifier, node: NodeEntity, isThisNode: Boolean -): Boolean { +) { val text = if (isThisNode) { stringResource(R.string.channel_air_util).format( node.deviceMetrics.channelUtilization, @@ -40,24 +41,22 @@ fun signalInfo( if (node.channel > 0) { add("ch:${node.channel}") } - if (node.hopsAway <= 0) { - if (node.snr < MAX_VALID_SNR && node.rssi < MAX_VALID_RSSI) { - add("RSSI: %d SNR: %.1f".format(node.rssi, node.snr)) - } - } if (node.hopsAway != 0) add(hopsString) }.joinToString(" | ") } - return if (text.isNotEmpty()) { + if (text.isNotEmpty()) { Text( modifier = modifier, text = text, color = MaterialTheme.colors.onSurface, fontSize = MaterialTheme.typography.button.fontSize ) - true - } else { - false + } + /* We only know the Signal Quality from direct nodes aka 0 hop. */ + if (node.hopsAway <= 0) { + if (node.snr < MAX_VALID_SNR && node.rssi < MAX_VALID_RSSI) { + NodeSignalQuality(node.snr, node.rssi) + } } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/LoraSignalIndicator.kt b/app/src/main/java/com/geeksville/mesh/ui/components/LoraSignalIndicator.kt index 6f6f42629..9e0faf679 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/LoraSignalIndicator.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/LoraSignalIndicator.kt @@ -2,7 +2,9 @@ package com.geeksville.mesh.ui.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme @@ -38,8 +40,69 @@ private enum class Quality( GOOD(R.string.good, Icons.Default.SignalCellular4Bar, Color.Green) } +/** + * Displays the `snr` and `rssi` color coded based on the signal quality, along with + * a human readable description and related icon. + */ @Composable -fun Snr(snr: Float) { +fun NodeSignalQuality(snr: Float, rssi: Int) { + val quality = determineSignalQuality(snr, rssi) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Snr(snr) + Rssi(rssi) + Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}") + Icon( + imageVector = quality.imageVector, + contentDescription = stringResource(R.string.signal_quality), + tint = quality.color + ) + } +} + +/** + * Displays the `snr` and `rssi` with color depending on the values respectively. + */ +@Composable +fun SnrAndRssi(snr: Float, rssi: Int) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Snr(snr) + Rssi(rssi) + } +} + +/** + * Displays a human readable description and icon representing the signal quality. + */ +@Composable +fun LoraSignalIndicator(snr: Float, rssi: Int) { + + val quality = determineSignalQuality(snr, rssi) + + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxSize() + .padding(8.dp) + ) { + Icon( + imageVector = quality.imageVector, + contentDescription = stringResource(R.string.signal_quality), + tint = quality.color + ) + Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}") + } +} + +@Composable +private fun Snr(snr: Float) { val color: Color = if (snr > SNR_GOOD_THRESHOLD) { Quality.GOOD.color } else if (snr > SNR_FAIR_THRESHOLD) { @@ -53,13 +116,13 @@ fun Snr(snr: Float) { stringResource(id = R.string.snr), snr ), - color = color, - fontSize = MaterialTheme.typography.button.fontSize - ) + color = color, + fontSize = MaterialTheme.typography.button.fontSize + ) } @Composable -fun Rssi(rssi: Int) { +private fun Rssi(rssi: Int) { val color: Color = if (rssi > RSSI_GOOD_THRESHOLD) { Quality.GOOD.color } else if (rssi > RSSI_FAIR_THRESHOLD) { @@ -77,27 +140,6 @@ fun Rssi(rssi: Int) { ) } -@Composable -fun LoraSignalIndicator(snr: Float, rssi: Int) { - - val quality = determineSignalQuality(snr, rssi) - - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .fillMaxSize() - .padding(8.dp) - ) { - Icon( - imageVector = quality.imageVector, - contentDescription = stringResource(R.string.signal_quality), - tint = quality.color - ) - Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}") - } -} - private fun determineSignalQuality(snr: Float, rssi: Int): Quality = when { snr > SNR_GOOD_THRESHOLD && rssi > RSSI_GOOD_THRESHOLD -> Quality.GOOD snr > SNR_GOOD_THRESHOLD && rssi > RSSI_FAIR_THRESHOLD -> Quality.FAIR diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/SignalMetrics.kt b/app/src/main/java/com/geeksville/mesh/ui/components/SignalMetrics.kt index 0e2f88408..af8124f2a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/SignalMetrics.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/SignalMetrics.kt @@ -266,13 +266,7 @@ private fun SignalMetricsCard(meshPacket: MeshPacket) { Spacer(modifier = Modifier.height(8.dp)) /* SNR and RSSI */ - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Snr(meshPacket.rxSnr) - Rssi(meshPacket.rxRssi) - } + SnrAndRssi(meshPacket.rxSnr, meshPacket.rxRssi) } }