Move signal info to compose (#879)

* Move battery info to compose - always show voltage level and icons to match battery percentage
Use tool text in preview, rather than actually set text value
Simplify node info layout to avoid defining margins on everything

* Move node position to Compose

* Update hyperlink color to match previous value

* Use compose preview in layout editor

* Use compose preview in layout editor

* Add simple preview for use in layout

* Move last heard node info to Compose
Clean up layout of node info

* Move signal info to Compose and simplify bind

* Prevent long coordinates from colliding with signal info
This commit is contained in:
Davis
2024-02-28 08:43:29 -07:00
committed by GitHub
parent 8f312e5d16
commit 9e9ecba4e3
5 changed files with 147 additions and 43 deletions

View File

@@ -59,6 +59,18 @@ fun LinkedCoordinates(
}
}
@Composable
@Preview
fun LinkedCoordinatesSimplePreview() {
AppTheme {
LinkedCoordinates(
position = Position(37.7749, -122.4194, 0),
format = 1,
nodeName = "Test Node Name"
)
}
}
@Composable
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES)

View File

@@ -0,0 +1,79 @@
package com.geeksville.mesh.ui
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.ui.preview.NodeInfoPreviewParameterProvider
import com.geeksville.mesh.ui.theme.AppTheme
@Composable
fun SignalInfo(
nodeInfo: NodeInfo,
isThisNode: Boolean
) {
val text = if (isThisNode) {
"ChUtil %.1f%% AirUtilTX %.1f%%".format(
nodeInfo.deviceMetrics?.channelUtilization,
nodeInfo.deviceMetrics?.airUtilTx
)
} else {
buildString {
if (nodeInfo.channel > 0) append("ch:${nodeInfo.channel}")
if (nodeInfo.snr < 100F && nodeInfo.rssi < 0) {
if (isNotEmpty()) append(" ")
append("RSSI: %d SNR: %.1f".format(nodeInfo.rssi, nodeInfo.snr))
}
}
}
if (text.isNotEmpty()) {
Text(
text = text,
color = MaterialTheme.colors.onSurface,
fontSize = MaterialTheme.typography.button.fontSize
)
}
}
@Composable
@Preview(showBackground = true)
fun SignalInfoSimplePreview() {
AppTheme {
SignalInfo(NodeInfo(
num = 1,
position = null,
lastHeard = 0,
channel = 0,
snr = 12.5F,
rssi = -42,
deviceMetrics = null,
user = null
), false)
}
}
@Composable
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES)
fun SignalInfoPreview(
@PreviewParameter(NodeInfoPreviewParameterProvider::class)
nodeInfo: NodeInfo
) {
AppTheme {
SignalInfo(nodeInfo, false)
}
}
@Composable
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES)
fun SignalInfoSelfPreview(
@PreviewParameter(NodeInfoPreviewParameterProvider::class)
nodeInfo: NodeInfo
) {
AppTheme {
SignalInfo(nodeInfo, true)
}
}

View File

@@ -54,12 +54,12 @@ class UsersFragment : ScreenFragment("Users"), Logging {
val chipNode = itemView.chipNode
val nodeNameView = itemView.nodeNameView
val distanceView = itemView.distanceView
val signalView = itemView.signalView
val envMetrics = itemView.envMetrics
val background = itemView.nodeCard
val nodePosition = itemView.nodePosition
val batteryInfo = itemView.batteryInfo
val lastHeard = itemView.lastHeardInfo
val signalInfo = itemView.signalInfo
fun blink() {
val bg = background.backgroundTintList
@@ -83,26 +83,28 @@ class UsersFragment : ScreenFragment("Users"), Logging {
}
fun bind(
batteryLevel: Int?,
voltage: Float?,
position: Position?,
nodeInfo: NodeInfo,
isThisNode: Boolean,
gpsFormat: Int,
nodeName: String?,
lastHeard: Int
) {
batteryInfo.setContent {
AppTheme {
BatteryInfo(batteryLevel, voltage)
BatteryInfo(nodeInfo.batteryLevel, nodeInfo.voltage)
}
}
nodePosition.setContent {
AppTheme {
LinkedCoordinates(position, gpsFormat, nodeName)
LinkedCoordinates(nodeInfo.position, gpsFormat, nodeInfo.user?.longName)
}
}
this.lastHeard.setContent {
AppTheme {
LastHeardInfo(lastHeard)
LastHeardInfo(nodeInfo.lastHeard)
}
}
this.signalInfo.setContent {
AppTheme {
SignalInfo(nodeInfo, isThisNode)
}
}
}
@@ -250,23 +252,21 @@ class UsersFragment : ScreenFragment("Users"), Logging {
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val n = nodes[position]
val user = n.user
val (textColor, nodeColor) = n.colors
val isIgnored: Boolean = ignoreIncomingList.contains(n.num)
val name = user?.longName
val isThisNode = n.num == nodes[0].num
holder.bind(n.batteryLevel, n.voltage, n.validPosition, gpsFormat, name, n.lastHeard)
holder.bind(n, isThisNode, gpsFormat)
holder.nodeNameView.text = name
holder.nodeNameView.text = n.user?.longName
with(holder.chipNode) {
text = (user?.shortName ?: "UNK").strikeIf(isIgnored)
text = (n.user?.shortName ?: "UNK").strikeIf(isIgnored)
chipBackgroundColor = ColorStateList.valueOf(nodeColor)
setTextColor(textColor)
}
val ourNodeInfo = nodes[0]
val distance = ourNodeInfo.distanceStr(n, displayUnits)
val distance = nodes[0].distanceStr(n, displayUnits)
if (distance != null) {
holder.distanceView.text = distance
holder.distanceView.visibility = View.VISIBLE
@@ -282,28 +282,6 @@ class UsersFragment : ScreenFragment("Users"), Logging {
holder.envMetrics.visibility = View.GONE
}
if (n.num == ourNodeInfo.num) {
val text = "ChUtil %.1f%% AirUtilTX %.1f%%".format(
n.deviceMetrics?.channelUtilization,
n.deviceMetrics?.airUtilTx
)
holder.signalView.text = text
holder.signalView.visibility = View.VISIBLE
} else {
val text = buildString {
if (n.channel > 0) append("ch:${n.channel}")
if (n.snr < 100f && n.rssi < 0) {
if (isNotEmpty()) append(" ")
append("rssi:%d snr:%.1f".format(n.rssi, n.snr))
}
}
if (text.isNotEmpty()) {
holder.signalView.text = text
holder.signalView.visibility = View.VISIBLE
} else {
holder.signalView.visibility = View.INVISIBLE
}
}
holder.chipNode.setOnClickListener {
popup(it, position)
}

View File

@@ -0,0 +1,27 @@
package com.geeksville.mesh.ui.preview
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.geeksville.mesh.DeviceMetrics
import com.geeksville.mesh.NodeInfo
class NodeInfoPreviewParameterProvider: PreviewParameterProvider<NodeInfo> {
override val values: Sequence<NodeInfo>
get() = sequenceOf(
NodeInfo(
num = 1,
position = null,
lastHeard = 0,
channel = 0,
snr = 12.5F,
rssi = -42,
deviceMetrics = DeviceMetrics(
channelUtilization = 2.4F,
airUtilTx = 3.5F,
batteryLevel = 85,
voltage = 3.7F
),
user = null
)
)
}

View File

@@ -63,7 +63,7 @@
app:layout_constraintTop_toBottomOf="@+id/nodeNameView"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
tools:composableName="com.geeksville.mesh.ui.LinkedCoordinatesKt.LinkedCoordinatesPreview"
tools:composableName="com.geeksville.mesh.ui.LinkedCoordinatesKt.LinkedCoordinatesSimplePreview"
/>
<androidx.compose.ui.platform.ComposeView
@@ -85,17 +85,25 @@
tools:composableName="com.geeksville.mesh.ui.LastHeardInfoKt.LastHeardInfoPreview"
/>
<TextView
android:id="@+id/signalView"
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/lastHeardInfo"
app:barrierDirection="bottom"
app:constraint_referenced_ids="nodePosition, lastHeardInfo"
/>
<androidx.compose.ui.platform.ComposeView
android:id="@+id/signalInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/barrier"
app:layout_constraintBottom_toTopOf="@id/envMetrics"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0"
android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
tools:text="RSSI: -40 SNR: -8"
tools:composableName="com.geeksville.mesh.ui.SignalInfoKt.SignalInfoSimplePreview"
/>
<TextView