From 75dfaa3013f3cc9cd7b96ed730bd73bf007f84f1 Mon Sep 17 00:00:00 2001 From: Seb3thehacker Date: Fri, 9 Oct 2026 15:26:48 -0700 Subject: [PATCH] car icons: drop app tints that can't be seen, mark MAPS.ME and MapQuest as working MAPS.ME tints its map buttons dark grey for dark mode, which vanished on Gearslip's dark buttons. A tint below 3:1 contrast now falls back to the normal text colour, as Android Auto does. --- .../seb3thehacker/gearslip/car/TemplateParts.kt | 17 ++++++++++++++++- .../seb3thehacker/gearslip/host/KnownApps.kt | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/TemplateParts.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/TemplateParts.kt index 0d07349..91303ca 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/TemplateParts.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/TemplateParts.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.material3.LocalContentColor import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.foundation.Image import kotlinx.coroutines.Dispatchers @@ -468,7 +469,10 @@ internal fun CarGlyph(icon: CarIcon?, modifier: Modifier = Modifier, standard: I val white = remember(bitmap) { bitmap.isPlainWhite() } // Untinted white artwork is a template-app habit from dark surfaces; it is coloured like // text so it stays readable on a light one. - val tint = icon?.tint?.color(dark, content) ?: content.takeIf { white } + // An app's own tint is kept only if it can be seen: MAPS.ME asks for dark grey on dark + // buttons. Android Auto drops colours that fail contrast the same way. + val tint = icon?.tint?.color(dark, content)?.takeIf { it.readableOn(content) } + ?: content.takeIf { white || icon?.tint != null } Image( bitmap, contentDescription = null, modifier = modifier, colorFilter = tint?.let { ColorFilter.tint(it) }, @@ -661,6 +665,17 @@ internal fun RowItem(row: CarRow, selection: RowSelection? = null, large: Boolea /** A row's place in a single-choice list: whether it is the chosen one, and what picking it does. */ internal class RowSelection(val selected: Boolean, val onPick: () -> Unit) +/** + * Whether this colour stands out against the background that [content] was chosen for: at least + * 3:1, the WCAG minimum for icons. The background is taken as the opposite of the content colour. + */ +private fun Color.readableOn(content: Color): Boolean { + val background = if (content.luminanceIsDark()) Color.White else Color(0xFF121212) + val a = luminance() + 0.05f + val b = background.luminance() + 0.05f + return maxOf(a, b) / minOf(a, b) >= 3f +} + internal fun Color.luminanceIsDark(): Boolean = (red * 0.299f + green * 0.587f + blue * 0.114f) < 0.5f diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt index 7e03a49..74289ee 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/host/KnownApps.kt @@ -19,6 +19,7 @@ object KnownApps { "com.metrolist.music", // Metrolist: browse, play, works "nl.flitsmeister", // Flitsmeister: map, routing, alerts - works well "com.mapquest.android.ace", // MapQuest: map, routing, navigation + "com.mapswithme.maps.pro", // MAPS.ME: map, search, place pages, navigation ) fun works(packageName: String): Boolean = packageName in working @@ -72,7 +73,6 @@ object KnownApps { */ private val partial = setOf( "app.vela", // Vela Maps: connects and draws, but rough enough not to call it working yet - "com.mapquest.android.ace", // MapQuest: map, search and routing run, but not cleanly "com.spotify.music", // Spotify: plays through Gearslip's player, but the app has to be opened on the phone first "deezer.android.app", // Deezer: the same - it has to be opened on the phone first )