Device metric lines and info dialog (#1252)

* Removed constants from CommonCharts only used in specific charts.

* Altered CommonCharts.ChartOverlay to take a list of colors for the lines. Adjusted the device metrics line colors for channel utilization.

* Started an info dialog in the device metric chart to help users better understand Meshtastic.
pull/1255/head
Robert-0410 2024-09-18 02:57:01 -07:00 zatwierdzone przez GitHub
rodzic f863f00d4a
commit 843e423648
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
4 zmienionych plików z 125 dodań i 27 usunięć

Wyświetl plik

@ -27,28 +27,21 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.ui.components.CommonCharts.LINE_OFF
import com.geeksville.mesh.ui.components.CommonCharts.LINE_ON
import com.geeksville.mesh.ui.components.CommonCharts.TIME_FORMAT
import com.geeksville.mesh.ui.components.CommonCharts.LINE_LIMIT
import com.geeksville.mesh.ui.components.CommonCharts.TEXT_PAINT_ALPHA
import com.geeksville.mesh.ui.theme.Orange
import java.text.DateFormat
object CommonCharts {
val DEVICE_METRICS_COLORS = listOf(Color.Green, Color.Magenta, Color.Cyan)
val ENVIRONMENT_METRICS_COLORS = listOf(Color.Red, Color.Blue)
val TIME_FORMAT: DateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM)
const val MAX_PERCENT_VALUE = 100f
const val LINE_LIMIT = 4
const val TEXT_PAINT_ALPHA = 192
const val LINE_ON = 10f
const val LINE_OFF = 20f
const val LEFT_CHART_SPACING = 8f
const val MS_PER_SEC = 1000.0f
}
private const val LINE_LIMIT = 4
private const val TEXT_PAINT_ALPHA = 192
private const val LINE_ON = 10f
private const val LINE_OFF = 20f
@Composable
fun ChartHeader(amount: Int) {
@ -68,11 +61,13 @@ fun ChartHeader(amount: Int) {
/**
* Draws chart lines and labels with respect to the Y-axis range; defined by (`maxValue` - `minValue`).
* Assumes `lineColors` is a list of 5 `Color`s with index 0 being the lowest line on the chart.
*/
@Composable
fun ChartOverlay(
modifier: Modifier,
graphColor: Color,
lineColors: List<Color>,
minValue: Float,
maxValue: Float
) {
@ -89,15 +84,10 @@ fun ChartOverlay(
for (i in 0..LINE_LIMIT) {
val ratio = (lineY - minValue) / range
val y = height - (ratio * height)
val color: Color = when (i) {
1 -> Color.Red
2 -> Orange
else -> graphColor
}
drawLine(
start = Offset(0f, y),
end = Offset(width, y),
color = color,
color = lineColors[i],
strokeWidth = 1.dp.toPx(),
cap = StrokeCap.Round,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(LINE_ON, LINE_OFF), 0f)

Wyświetl plik

@ -1,6 +1,7 @@
package com.geeksville.mesh.ui.components
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -15,39 +16,62 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.AlertDialog
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.ui.BatteryInfo
import com.geeksville.mesh.ui.components.CommonCharts.DEVICE_METRICS_COLORS
import com.geeksville.mesh.ui.components.CommonCharts.LEFT_CHART_SPACING
import com.geeksville.mesh.ui.components.CommonCharts.MAX_PERCENT_VALUE
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.ui.components.CommonCharts.TIME_FORMAT
import com.geeksville.mesh.ui.theme.Orange
private val DEVICE_METRICS_COLORS = listOf(Color.Green, Color.Magenta, Color.Cyan)
private const val MAX_PERCENT_VALUE = 100f
@Composable
fun DeviceMetricsScreen(telemetries: List<Telemetry>) {
var displayInfoDialog by remember { mutableStateOf(false) }
Column {
if (displayInfoDialog)
DeviceInfoDialog { displayInfoDialog = false }
DeviceMetricsChart(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(fraction = 0.33f),
telemetries.reversed()
telemetries.reversed(),
promptInfoDialog = { displayInfoDialog = true }
)
/* Device Metric Cards */
LazyColumn(
@ -60,7 +84,11 @@ fun DeviceMetricsScreen(telemetries: List<Telemetry>) {
@Suppress("LongMethod")
@Composable
private fun DeviceMetricsChart(modifier: Modifier = Modifier, telemetries: List<Telemetry>) {
private fun DeviceMetricsChart(
modifier: Modifier = Modifier,
telemetries: List<Telemetry>,
promptInfoDialog: () -> Unit
) {
ChartHeader(amount = telemetries.size)
if (telemetries.isEmpty())
@ -73,7 +101,18 @@ private fun DeviceMetricsChart(modifier: Modifier = Modifier, telemetries: List<
Box(contentAlignment = Alignment.TopStart) {
ChartOverlay(modifier, graphColor, minValue = 0f, maxValue = 100f)
/*
* The order of the colors are with respect to the ChUtil.
* 25 - 49 Orange
* 50 - 100 Red
*/
ChartOverlay(
modifier,
graphColor,
lineColors = listOf(graphColor, Orange, Color.Red, graphColor, graphColor),
minValue = 0f,
maxValue = 100f
)
/* Plot Battery Line, ChUtil, and AirUtilTx */
Canvas(modifier = modifier) {
@ -142,7 +181,7 @@ private fun DeviceMetricsChart(modifier: Modifier = Modifier, telemetries: List<
}
Spacer(modifier = Modifier.height(16.dp))
DeviceLegend()
DeviceLegend(promptInfoDialog)
Spacer(modifier = Modifier.height(16.dp))
}
@ -205,7 +244,7 @@ private fun DeviceMetricsCard(telemetry: Telemetry) {
}
@Composable
private fun DeviceLegend() {
private fun DeviceLegend(promptInfoDialog: () -> Unit) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
@ -223,6 +262,65 @@ private fun DeviceLegend() {
LegendLabel(text = stringResource(R.string.air_utilization), color = DEVICE_METRICS_COLORS[2])
Spacer(modifier = Modifier.width(4.dp))
Icon(
imageVector = Icons.Default.Info,
modifier = Modifier.clickable { promptInfoDialog() },
contentDescription = stringResource(R.string.info)
)
Spacer(modifier = Modifier.weight(1f))
}
}
@Composable
private fun DeviceInfoDialog(onDismiss: () -> Unit) {
AlertDialog(
title = {
Text(
text = stringResource(R.string.info),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center
)
},
text = {
Column {
Text(
text = stringResource(R.string.channel_utilization),
style = TextStyle(fontWeight = FontWeight.Bold),
textDecoration = TextDecoration.Underline
)
Text(
text = stringResource(R.string.ch_util_definition),
style = TextStyle.Default,
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(R.string.air_utilization),
style = TextStyle(fontWeight = FontWeight.Bold),
textDecoration = TextDecoration.Underline
)
Text(
text = stringResource(R.string.air_util_definition),
style = TextStyle.Default
)
}
},
onDismissRequest = onDismiss,
confirmButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.okay))
}
},
backgroundColor = MaterialTheme.colors.background
)
}
@Preview
@Composable
private fun DeviceInfoDialogPreview() {
DeviceInfoDialog {}
}

Wyświetl plik

@ -36,12 +36,13 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.geeksville.mesh.R
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.ui.components.CommonCharts.ENVIRONMENT_METRICS_COLORS
import com.geeksville.mesh.ui.components.CommonCharts.LEFT_CHART_SPACING
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
import com.geeksville.mesh.ui.components.CommonCharts.TIME_FORMAT
private val ENVIRONMENT_METRICS_COLORS = listOf(Color.Red, Color.Blue)
@Composable
fun EnvironmentMetricsScreen(telemetries: List<Telemetry>) {
Column {
@ -95,7 +96,13 @@ private fun EnvironmentMetricsChart(modifier: Modifier = Modifier, telemetries:
Box(contentAlignment = Alignment.TopStart) {
ChartOverlay(modifier = modifier, graphColor = graphColor, minValue = min, maxValue = max)
ChartOverlay(
modifier = modifier,
graphColor = graphColor,
lineColors = List(size = 5) { graphColor },
minValue = min,
maxValue = max
)
/* Plot Temperature and Relative Humidity */
Canvas(modifier = modifier) {

Wyświetl plik

@ -227,4 +227,7 @@
<string name="humidity">Humidity</string>
<string name="logs">Logs</string>
<string name="hops_away">Hops Away</string>
<string name="info">Information</string>
<string name="ch_util_definition">Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise).</string>
<string name="air_util_definition">Percent of airtime for transmission used within the last hour.</string>
</resources>