mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
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
This commit is contained in:
parent
7fb2761dc6
commit
89438f3553
11 changed files with 229 additions and 66 deletions
83
app/src/main/java/com/geeksville/mesh/ui/BatteryInfo.kt
Normal file
83
app/src/main/java/com/geeksville/mesh/ui/BatteryInfo.kt
Normal file
|
|
@ -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<Int?, Float?>
|
||||
) {
|
||||
AppTheme {
|
||||
BatteryInfo(batteryInfo.first, batteryInfo.second)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun BatteryInfoPreviewSimple() {
|
||||
AppTheme {
|
||||
BatteryInfo(85, 3.7F)
|
||||
}
|
||||
}
|
||||
|
||||
class BatteryInfoPreviewParameterProvider : PreviewParameterProvider<Pair<Int?, Float?>> {
|
||||
override val values: Sequence<Pair<Int?, Float?>>
|
||||
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
|
||||
)
|
||||
}
|
||||
|
|
@ -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<ViewHolder>() {
|
||||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -15,4 +15,6 @@ val LightPink = Color(0xFFFFE6E6)
|
|||
val LightGreen = Color(0xFFCFE8A9)
|
||||
val LightRed = Color(0xFFFFB3B3)
|
||||
|
||||
val MeshtasticGreen = Color(0xFF67EA94)
|
||||
val MeshtasticGreen = Color(0xFF67EA94)
|
||||
val AlmostWhite = Color(0xB3FFFFFF)
|
||||
val AlmostBlack = Color(0x8A000000)
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
14
app/src/main/res/drawable/ic_battery_alert.xml
Normal file
14
app/src/main/res/drawable/ic_battery_alert.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M14,20H6V6H14M14.67,4H13V2H7V4H5.33C4.6,4 4,4.6 4,5.33V20.67C4,21.4 4.6,22 5.33,22H14.67C15.4,22 16,21.4 16,20.67V5.33C16,4.6 15.4,4 14.67,4M21,7H19V13H21V8M21,15H19V17H21V15Z"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_battery_high.xml
Normal file
14
app/src/main/res/drawable/ic_battery_high.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,20H8V6H16M16.67,4H15V2H9V4H7.33C6.6,4 6,4.6 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67C17.41,22 18,21.41 18,20.67V5.33C18,4.6 17.4,4 16.67,4M15,16H9V19H15V16M15,7H9V10H15V7M15,11.5H9V14.5H15V11.5Z"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_battery_low.xml
Normal file
14
app/src/main/res/drawable/ic_battery_low.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,20H8V6H16M16.67,4H15V2H9V4H7.33C6.6,4 6,4.6 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67C17.41,22 18,21.41 18,20.67V5.33C18,4.6 17.4,4 16.67,4M15,16H9V19H15V16"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_battery_medium.xml
Normal file
14
app/src/main/res/drawable/ic_battery_medium.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,20H8V6H16M16.67,4H15V2H9V4H7.33C6.6,4 6,4.6 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67C17.41,22 18,21.41 18,20.67V5.33C18,4.6 17.4,4 16.67,4M15,16H9V19H15V16M15,11.5H9V14.5H15V11.5Z"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_battery_outline.xml
Normal file
14
app/src/main/res/drawable/ic_battery_outline.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,20H8V6H16M16.67,4H15V2H9V4H7.33A1.33,1.33 0,0 0,6 5.33V20.67C6,21.4 6.6,22 7.33,22H16.67A1.33,1.33 0,0 0,18 20.67V5.33C18,4.6 17.4,4 16.67,4Z"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_battery_unknown.xml
Normal file
14
app/src/main/res/drawable/ic_battery_unknown.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.07,12.25L14.17,13.17C13.63,13.71 13.25,14.18 13.09,15H11.05C11.16,14.1 11.56,13.28 12.17,12.67L13.41,11.41C13.78,11.05 14,10.55 14,10C14,8.89 13.1,8 12,8A2,2 0,0 0,10 10H8A4,4 0,0 1,12 6A4,4 0,0 1,16 10C16,10.88 15.64,11.68 15.07,12.25M13,19H11V17H13M16.67,4H15V2H9V4H7.33A1.33,1.33 0,0 0,6 5.33V20.66C6,21.4 6.6,22 7.33,22H16.67C17.4,22 18,21.4 18,20.66V5.33C18,4.59 17.4,4 16.67,4Z"
|
||||
android:fillAlpha="0.5"
|
||||
/>
|
||||
</vector>
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false">
|
||||
android:clipToPadding="false"
|
||||
>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/Widget.App.CardView"
|
||||
|
|
@ -15,110 +18,107 @@
|
|||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_node"
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/some_username"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@string/some_username"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nodeNameView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/unknown_username"
|
||||
app:layout_constraintStart_toEndOf="@+id/chip_node"
|
||||
app:layout_constraintTop_toTopOf="@+id/chip_node" />
|
||||
app:layout_constraintTop_toTopOf="@+id/chip_node"
|
||||
tools:text="@string/unknown_username"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/distance_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/sample_distance"
|
||||
app:layout_constraintTop_toBottomOf="@+id/chip_node"
|
||||
app:layout_constraintEnd_toEndOf="@+id/chip_node"
|
||||
app:layout_constraintStart_toStartOf="@+id/chip_node"
|
||||
app:layout_constraintTop_toBottomOf="@+id/chip_node" />
|
||||
android:layout_marginTop="8dp"
|
||||
tools:text="@string/sample_distance"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/coords_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/sample_coords"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toEndOf="@+id/chip_node"
|
||||
app:layout_constraintTop_toBottomOf="@+id/nodeNameView"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
tools:text="@string/sample_coords"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/batteryIcon"
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/batteryInfo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/batteryPercentageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_battery_full_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/batteryPercentageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="100%"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/nodeNameView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/nodeNameView" />
|
||||
tools:composableName="com.geeksville.mesh.ui.BatteryInfoKt.BatteryInfoPreviewSimple"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/lastCommIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@id/signalView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/lastConnectionView"
|
||||
app:layout_constraintTop_toBottomOf="@id/batteryIcon"
|
||||
app:layout_constraintTop_toBottomOf="@id/batteryInfo"
|
||||
app:srcCompat="@drawable/ic_antenna_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lastConnectionView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="11h01 PM"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintTop_toTopOf="@+id/lastCommIcon"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/lastCommIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/lastCommIcon" />
|
||||
tools:text="11h01 PM"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/signalView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="rssi:-40 snr:-8"
|
||||
app:layout_constraintTop_toBottomOf="@id/lastConnectionView"
|
||||
app:layout_constraintBottom_toTopOf="@id/envMetrics"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/lastConnectionView" />
|
||||
tools:text="RSSI: -40 SNR: -8"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/envMetrics"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue