fix(chat): tint composer send/stop/mic button with theme primary (#1410)
This commit is contained in:
3 files changed
+44
-3
No files matched your search
@@ -91,3 +91,6 @@ fun parseProjectColor(raw: String?): Color? {
|
||||
if (h !in 0f..360f || s !in 0f..1f || l !in 0f..1f) return null
|
||||
return Color.hsl(h % 360f, s, l)
|
||||
}
|
||||
|
||||
/** Pure white glyph for filled accent controls (composer action button) when it is legible on the preset primary. */
|
||||
val GlyphWhite = Color(0xFFFFFFFF)
|
||||
@@ -6,6 +6,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import com.m57.hermescontrol.theme.GlyphWhite
|
||||
|
||||
/**
|
||||
* Resolved colors for the chat composer card and its controls.
|
||||
@@ -15,7 +17,8 @@ import androidx.compose.ui.graphics.compositeOver
|
||||
* (Nord's High and Highest are the same color), which made the flat controls
|
||||
* vanish into the card. A fixed onSurface tint keeps them visible in every
|
||||
* preset and under dynamic color. Text and icon contrast is gated per preset
|
||||
* in ComposerPaletteTest.
|
||||
* in ComposerPaletteTest. The send / stop / mic action button is the one
|
||||
* themed control: it takes the preset's primary so it follows the theme tint.
|
||||
*/
|
||||
internal data class ComposerPalette(
|
||||
val card: Color,
|
||||
@@ -30,10 +33,30 @@ internal data class ComposerPalette(
|
||||
)
|
||||
|
||||
private const val CONTROL_TINT_ALPHA = 0.12f
|
||||
private const val ACTION_MIN_CONTRAST = 3f
|
||||
|
||||
private fun contrastRatio(
|
||||
a: Color,
|
||||
b: Color,
|
||||
): Float {
|
||||
val l1 = a.luminance()
|
||||
val l2 = b.luminance()
|
||||
return (maxOf(l1, l2) + 0.05f) / (minOf(l1, l2) + 0.05f)
|
||||
}
|
||||
|
||||
internal fun composerPalette(scheme: ColorScheme): ComposerPalette {
|
||||
val card = scheme.surfaceContainer
|
||||
val tint = scheme.onSurface.copy(alpha = CONTROL_TINT_ALPHA)
|
||||
// Pastel primaries (Nord light) vanish on the card; keep the neutral fill there.
|
||||
val tinted = contrastRatio(scheme.primary, card) >= ACTION_MIN_CONTRAST
|
||||
val action = if (tinted) scheme.primary else scheme.onSurface
|
||||
// White glyph wherever it clears 3:1 on the primary; pastel primaries keep their own dark onPrimary.
|
||||
val onAction =
|
||||
when {
|
||||
!tinted -> scheme.surface
|
||||
contrastRatio(GlyphWhite, scheme.primary) >= ACTION_MIN_CONTRAST -> GlyphWhite
|
||||
else -> scheme.onPrimary
|
||||
}
|
||||
return ComposerPalette(
|
||||
card = card,
|
||||
cardBorder = tint.compositeOver(scheme.background),
|
||||
@@ -42,8 +65,8 @@ internal fun composerPalette(scheme: ColorScheme): ComposerPalette {
|
||||
control = tint.compositeOver(card),
|
||||
onControl = scheme.onSurface,
|
||||
onControlVariant = scheme.onSurfaceVariant,
|
||||
action = scheme.onSurface,
|
||||
onAction = scheme.surface,
|
||||
action = action,
|
||||
onAction = onAction,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user