From 89438f3553f36e46e44a8d5e7e10fd1858f187ec Mon Sep 17 00:00:00 2001 From: Davis Date: Mon, 26 Feb 2024 15:19:32 -0700 Subject: [PATCH] Improved battery/voltage info in node list (#874) * 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 * Use compose preview in layout editor * Add simple preview for use in layout --- .../com/geeksville/mesh/ui/BatteryInfo.kt | 83 +++++++++++++++++++ .../com/geeksville/mesh/ui/UsersFragment.kt | 34 +++----- .../com/geeksville/mesh/ui/theme/Color.kt | 4 +- .../com/geeksville/mesh/ui/theme/Theme.kt | 10 ++- .../main/res/drawable/ic_battery_alert.xml | 14 ++++ app/src/main/res/drawable/ic_battery_high.xml | 14 ++++ app/src/main/res/drawable/ic_battery_low.xml | 14 ++++ .../main/res/drawable/ic_battery_medium.xml | 14 ++++ .../main/res/drawable/ic_battery_outline.xml | 14 ++++ .../main/res/drawable/ic_battery_unknown.xml | 14 ++++ .../main/res/layout/adapter_node_layout.xml | 80 +++++++++--------- 11 files changed, 229 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/com/geeksville/mesh/ui/BatteryInfo.kt create mode 100644 app/src/main/res/drawable/ic_battery_alert.xml create mode 100644 app/src/main/res/drawable/ic_battery_high.xml create mode 100644 app/src/main/res/drawable/ic_battery_low.xml create mode 100644 app/src/main/res/drawable/ic_battery_medium.xml create mode 100644 app/src/main/res/drawable/ic_battery_outline.xml create mode 100644 app/src/main/res/drawable/ic_battery_unknown.xml diff --git a/app/src/main/java/com/geeksville/mesh/ui/BatteryInfo.kt b/app/src/main/java/com/geeksville/mesh/ui/BatteryInfo.kt new file mode 100644 index 000000000..8462f6c50 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/ui/BatteryInfo.kt @@ -0,0 +1,83 @@ +package com.geeksville.mesh.ui + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import com.geeksville.mesh.R +import com.geeksville.mesh.ui.theme.AppTheme + +@Composable +fun BatteryInfo(batteryLevel: Int?, voltage: Float?) { + val infoString = "%d%% %.1fV".format(batteryLevel, voltage) + val (image, level) = when (batteryLevel) { + in 0 .. 4 -> R.drawable.ic_battery_alert to " $infoString" + in 5 .. 14 -> R.drawable.ic_battery_outline to infoString + in 15..34 -> R.drawable.ic_battery_low to infoString + in 35..79 -> R.drawable.ic_battery_medium to infoString + in 80..100 -> R.drawable.ic_battery_high to infoString + 101 -> R.drawable.ic_power_plug_24 to "%.1fV".format(voltage) + else -> R.drawable.ic_battery_unknown to (voltage?.let { "%.1fV".format(it) } ?: "") + } + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = Modifier.height(18.dp), + imageVector = ImageVector.vectorResource(id = image), + contentDescription = null, + tint = MaterialTheme.colors.onSurface, + ) + Text( + text = level, + color = MaterialTheme.colors.onSurface, + fontSize = MaterialTheme.typography.button.fontSize + ) + } +} + +@Composable +@Preview(showBackground = true) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +fun BatteryInfoPreview( + @PreviewParameter(BatteryInfoPreviewParameterProvider::class) + batteryInfo: Pair +) { + AppTheme { + BatteryInfo(batteryInfo.first, batteryInfo.second) + } +} + +@Composable +@Preview +fun BatteryInfoPreviewSimple() { + AppTheme { + BatteryInfo(85, 3.7F) + } +} + +class BatteryInfoPreviewParameterProvider : PreviewParameterProvider> { + override val values: Sequence> + get() = sequenceOf( + 85 to 3.7F, + 2 to 3.7F, + 12 to 3.7F, + 28 to 3.7F, + 50 to 3.7F, + 101 to 4.9F, + null to 4.5F, + null to null + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index 94a5ed948..36bf10935 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -28,6 +28,7 @@ import com.geeksville.mesh.android.Logging import com.geeksville.mesh.databinding.AdapterNodeLayoutBinding import com.geeksville.mesh.databinding.NodelistFragmentBinding import com.geeksville.mesh.model.UIViewModel +import com.geeksville.mesh.ui.theme.AppTheme import com.geeksville.mesh.util.formatAgo import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -58,12 +59,11 @@ class UsersFragment : ScreenFragment("Users"), Logging { val nodeNameView = itemView.nodeNameView val distanceView = itemView.distanceView val coordsView = itemView.coordsView - val batteryPctView = itemView.batteryPercentageView val lastTime = itemView.lastConnectionView - val powerIcon = itemView.batteryIcon val signalView = itemView.signalView val envMetrics = itemView.envMetrics val background = itemView.nodeCard + val batteryInfo = itemView.batteryInfo fun blink() { val bg = background.backgroundTintList @@ -85,6 +85,14 @@ class UsersFragment : ScreenFragment("Users"), Logging { } } } + + fun bind(batteryLevel: Int?, voltage: Float?) { + batteryInfo.setContent { + AppTheme { + BatteryInfo(batteryLevel, voltage) + } + } + } } private val nodesAdapter = object : RecyclerView.Adapter() { @@ -232,6 +240,9 @@ class UsersFragment : ScreenFragment("Users"), Logging { val user = n.user val (textColor, nodeColor) = n.colors val isIgnored: Boolean = ignoreIncomingList.contains(n.num) + + holder.bind(n.batteryLevel, n.voltage) + with(holder.chipNode) { text = (user?.shortName ?: "UNK").strikeIf(isIgnored) chipBackgroundColor = ColorStateList.valueOf(nodeColor) @@ -260,7 +271,6 @@ class UsersFragment : ScreenFragment("Users"), Logging { } else { holder.distanceView.visibility = View.INVISIBLE } - renderBattery(n.batteryLevel, n.voltage, holder) holder.lastTime.text = formatAgo(n.lastHeard) @@ -312,24 +322,6 @@ class UsersFragment : ScreenFragment("Users"), Logging { } } - private fun renderBattery( - battery: Int?, - voltage: Float?, - holder: ViewHolder - ) { - - val (image, text) = when (battery) { - in 0..100 -> R.drawable.ic_battery_full_24 to "%d%% %.2fV".format(battery, voltage) - 101 -> R.drawable.ic_power_plug_24 to "" - else -> R.drawable.ic_battery_full_24 to "?" - } - - holder.batteryPctView.text = text - holder.powerIcon.setImageDrawable(context?.let { - ContextCompat.getDrawable(it, image) - }) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/app/src/main/java/com/geeksville/mesh/ui/theme/Color.kt b/app/src/main/java/com/geeksville/mesh/ui/theme/Color.kt index adc0e933b..265a28315 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/theme/Color.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/theme/Color.kt @@ -15,4 +15,6 @@ val LightPink = Color(0xFFFFE6E6) val LightGreen = Color(0xFFCFE8A9) val LightRed = Color(0xFFFFB3B3) -val MeshtasticGreen = Color(0xFF67EA94) \ No newline at end of file +val MeshtasticGreen = Color(0xFF67EA94) +val AlmostWhite = Color(0xB3FFFFFF) +val AlmostBlack = Color(0x8A000000) \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/ui/theme/Theme.kt b/app/src/main/java/com/geeksville/mesh/ui/theme/Theme.kt index 0646ca402..261ddb617 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/theme/Theme.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/theme/Theme.kt @@ -7,15 +7,17 @@ import androidx.compose.material.lightColors import androidx.compose.runtime.Composable private val DarkColorPalette = darkColors( - primary = Purple200, + primary = MeshtasticGreen, primaryVariant = Purple700, - secondary = Teal200 + secondary = Teal200, + onSurface = AlmostWhite ) private val LightColorPalette = lightColors( - primary = SkyBlue, + primary = MeshtasticGreen, primaryVariant = LightSkyBlue, - secondary = Teal200 + secondary = Teal200, + onSurface = AlmostBlack /* Other default colors to override background = Color.White, diff --git a/app/src/main/res/drawable/ic_battery_alert.xml b/app/src/main/res/drawable/ic_battery_alert.xml new file mode 100644 index 000000000..aab98bc9d --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_alert.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_battery_high.xml b/app/src/main/res/drawable/ic_battery_high.xml new file mode 100644 index 000000000..032956f30 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_high.xml @@ -0,0 +1,14 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_low.xml b/app/src/main/res/drawable/ic_battery_low.xml new file mode 100644 index 000000000..2126c0bc3 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_low.xml @@ -0,0 +1,14 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_medium.xml b/app/src/main/res/drawable/ic_battery_medium.xml new file mode 100644 index 000000000..e60a81575 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_medium.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_battery_outline.xml b/app/src/main/res/drawable/ic_battery_outline.xml new file mode 100644 index 000000000..ec515ed01 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_outline.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_battery_unknown.xml b/app/src/main/res/drawable/ic_battery_unknown.xml new file mode 100644 index 000000000..6be9c7145 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_unknown.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_node_layout.xml b/app/src/main/res/layout/adapter_node_layout.xml index 7ddbdf324..2bc8a1ee3 100644 --- a/app/src/main/res/layout/adapter_node_layout.xml +++ b/app/src/main/res/layout/adapter_node_layout.xml @@ -1,9 +1,12 @@ - + android:clipToPadding="false" + > + android:layout_height="wrap_content" + android:padding="8dp" + > + app:layout_constraintTop_toTopOf="parent" + tools:text="@string/some_username" + /> + app:layout_constraintTop_toTopOf="@+id/chip_node" + tools:text="@string/unknown_username" + /> + android:layout_marginTop="8dp" + tools:text="@string/sample_distance" + /> + app:layout_constraintVertical_bias="0.0" + tools:text="@string/sample_coords" + /> - - - + tools:composableName="com.geeksville.mesh.ui.BatteryInfoKt.BatteryInfoPreviewSimple" + /> + tools:text="11h01 PM" + /> + tools:text="RSSI: -40 SNR: -8" + /> + app:layout_constraintStart_toStartOf="parent" + tools:visibility="visible" + />