fix: enforce SignalInfo single-line layout

closes #1441
This commit is contained in:
andrekir 2024-11-30 14:19:39 -03:00
parent e412faecb9
commit f4c24dbfff
3 changed files with 27 additions and 22 deletions

View file

@ -19,10 +19,14 @@ package com.geeksville.mesh.ui.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
@ -61,17 +65,23 @@ private enum class Quality(
* Displays the `snr` and `rssi` color coded based on the signal quality, along with
* a human readable description and related icon.
*/
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun NodeSignalQuality(snr: Float, rssi: Int) {
fun NodeSignalQuality(snr: Float, rssi: Int, modifier: Modifier = Modifier) {
val quality = determineSignalQuality(snr, rssi)
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
FlowRow(
modifier = modifier,
maxLines = 1,
) {
Snr(snr)
Spacer(Modifier.width(8.dp))
Rssi(rssi)
Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}")
Spacer(Modifier.width(8.dp))
Text(
text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}",
fontSize = MaterialTheme.typography.button.fontSize
)
Spacer(Modifier.width(8.dp))
Icon(
imageVector = quality.imageVector,
contentDescription = stringResource(R.string.signal_quality),
@ -129,10 +139,7 @@ private fun Snr(snr: Float) {
}
Text(
text = "%s %.2fdB".format(
stringResource(id = R.string.snr),
snr
),
text = "%s %.2fdB".format(stringResource(id = R.string.snr), snr),
color = color,
fontSize = MaterialTheme.typography.button.fontSize
)
@ -148,10 +155,7 @@ private fun Rssi(rssi: Int) {
Quality.BAD.color
}
Text(
text = "%s %ddB".format(
stringResource(id = R.string.rssi),
rssi
),
text = "%s %ddBm".format(stringResource(id = R.string.rssi), rssi),
color = color,
fontSize = MaterialTheme.typography.button.fontSize
)

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2024 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.ui.components
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
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.preview.NodeEntityPreviewParameterProvider
import com.geeksville.mesh.ui.theme.AppTheme
const val MAX_VALID_SNR = 100F
const val MAX_VALID_RSSI = 0
@Composable
fun SignalInfo(
modifier: Modifier = Modifier,
node: NodeEntity,
isThisNode: Boolean
) {
val text = if (isThisNode) {
stringResource(R.string.channel_air_util).format(
node.deviceMetrics.channelUtilization,
node.deviceMetrics.airUtilTx
)
} else {
buildList {
val hopsString = "%s: %s".format(
stringResource(R.string.hops_away),
if (node.hopsAway == -1) {
"?"
} else {
node.hopsAway.toString()
}
)
if (node.channel > 0) {
add("ch:${node.channel}")
}
if (node.hopsAway != 0) add(hopsString)
}.joinToString(" ")
}
if (text.isNotEmpty()) {
Text(
modifier = modifier,
text = text,
color = MaterialTheme.colors.onSurface,
fontSize = MaterialTheme.typography.button.fontSize
)
}
/* 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)
}
}
}
@Composable
@Preview(showBackground = true)
fun SignalInfoSimplePreview() {
AppTheme {
SignalInfo(
node = NodeEntity(
num = 1,
lastHeard = 0,
channel = 0,
snr = 12.5F,
rssi = -42,
hopsAway = 0
),
isThisNode = false
)
}
}
@PreviewLightDark
@Composable
fun SignalInfoPreview(
@PreviewParameter(NodeEntityPreviewParameterProvider::class)
node: NodeEntity
) {
AppTheme {
SignalInfo(
node = node,
isThisNode = false
)
}
}
@Composable
@PreviewLightDark
fun SignalInfoSelfPreview(
@PreviewParameter(NodeEntityPreviewParameterProvider::class)
node: NodeEntity
) {
AppTheme {
SignalInfo(
node = node,
isThisNode = true
)
}
}