style(car): apply official Car App Library sample patterns

- Use CarColor.GREEN tint on node icons for online status (visual diff)
- Use Row.IMAGE_TYPE_ICON explicitly per official showcase sample
- Use ConstraintManager for dynamic list limits (host-aware)
- Online nodes get green-tinted mesh icon, offline get default white

Patterns sourced from android/car-samples showcase app.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich
2026-05-21 20:46:34 -05:00
parent 1d4b3be493
commit c56f2f0be4
3 changed files with 17 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ package org.meshtastic.feature.car.screens
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.constraints.ConstraintManager
import androidx.car.app.model.Action
import androidx.car.app.model.ActionStrip
import androidx.car.app.model.Header
@@ -39,7 +40,11 @@ class ConversationScreen(
) : Screen(carContext) {
override fun onGetTemplate(): Template {
val messages = messagesProvider().takeLast(MAX_MESSAGES)
val listLimit =
carContext
.getCarService(ConstraintManager::class.java)
.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_LIST)
val messages = messagesProvider().takeLast(listLimit.coerceAtMost(MAX_MESSAGES))
val listBuilder = ItemList.Builder()
messages.forEach { msg ->

View File

@@ -19,6 +19,7 @@ package org.meshtastic.feature.car.screens
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.Header
import androidx.car.app.model.ItemList
@@ -136,7 +137,7 @@ class HomeScreen(carContext: CarContext, private val stateCoordinator: CarStateC
Row.Builder()
.setTitle(conversation.displayName)
.addText(conversation.lastMessage)
.setImage(personIcon)
.setImage(personIcon, Row.IMAGE_TYPE_ICON)
.setBrowsable(true)
.setOnClickListener { openConversation(conversation.contactKey, conversation.displayName) }
.build(),
@@ -171,13 +172,15 @@ class HomeScreen(carContext: CarContext, private val stateCoordinator: CarStateC
if (state.nodes.isEmpty()) {
listBuilder.setNoItemsMessage(carContext.getString(R.string.car_no_nodes))
} else {
val nodeIcon = CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_car_nodes)).build()
val baseIcon = IconCompat.createWithResource(carContext, R.drawable.ic_car_nodes)
val onlineIcon = CarIcon.Builder(baseIcon).setTint(CarColor.GREEN).build()
val offlineIcon = CarIcon.Builder(baseIcon).build()
state.nodes.forEach { node ->
listBuilder.addItem(
Row.Builder()
.setTitle(node.longName)
.addText(formatNodeSubtitle(node))
.setImage(nodeIcon)
.setImage(if (node.isOnline) onlineIcon else offlineIcon, Row.IMAGE_TYPE_ICON)
.setBrowsable(true)
.setOnClickListener {
screenManager.push(

View File

@@ -19,6 +19,7 @@ package org.meshtastic.feature.car.screens
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.Header
import androidx.car.app.model.ItemList
@@ -59,7 +60,9 @@ class NodeDashboardScreen(
val header = state.topologyHeader
val headerTitle = carContext.getString(R.string.car_nodes_online, header.onlineNodes)
val nodeIcon = CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_car_nodes)).build()
val baseIcon = IconCompat.createWithResource(carContext, R.drawable.ic_car_nodes)
val onlineIcon = CarIcon.Builder(baseIcon).setTint(CarColor.GREEN).build()
val offlineIcon = CarIcon.Builder(baseIcon).build()
val listBuilder = ItemList.Builder()
// Nodes already sorted by CarStateCoordinator (online-first, then by lastHeard)
@@ -68,7 +71,7 @@ class NodeDashboardScreen(
Row.Builder()
.setTitle(node.longName)
.addText(formatNodeSubtitle(node))
.setImage(nodeIcon)
.setImage(if (node.isOnline) onlineIcon else offlineIcon, Row.IMAGE_TYPE_ICON)
.setBrowsable(true)
.setOnClickListener { onNodeClick(node.nodeNum) }
.build(),