fix(nests): drop themed colors when palette is incomplete

EGG-10 lets each `["c", hex, role]` tag stand alone, but a half-
applied palette (themed background + platform text, or themed text
+ platform background) collides with whichever system theme — light
or dark — the user is on. A room that ships ONLY `background=#FFE4B5`
ends up with platform-default white text on dark theme; unreadable.

Gate all three color overrides on having a complete bg + text pair
inside `RoomTheme.from(event)`. When either is missing the whole
palette drops to null and renderers fall through to the platform
theme. Background image (`bg`) and font tags still flow through —
they don't break contrast on their own.

Both consumers — NestThemedScope (room screen) and NestJoinCard
(lobby) — pick up the change without code edits because they read
through the same `RoomTheme` projection.

The nostrnests-style `["color", "gradient-7"]` tag was never parsed
(our `c`-tag parser ignores it), so events shipping only that don't
override anything either way; this fix targets the genuine half-
applied case (rooms that emit one EGG-10 c-tag without the matching
companion).

https://claude.ai/code/session_01RDpuki4t8StSg1CZcXnV5b
This commit is contained in:
Claude
2026-04-27 19:46:18 +00:00
parent 1a6b9a4cee
commit 15169de7e5

View File

@@ -89,10 +89,29 @@ data class RoomTheme(
?.hex
?.let { hexToOpaqueArgb(it) }
val backgroundArgb = pickHex(ColorTag.Target.BACKGROUND)
val textArgb = pickHex(ColorTag.Target.TEXT)
val primaryArgb = pickHex(ColorTag.Target.PRIMARY)
// EGG-10 lets each `["c", hex, role]` tag stand alone, but
// a half-applied palette (themed bg + platform text, or
// themed text + platform bg) collides with whichever
// system theme — light or dark — the user is on. A room
// that ships ONLY `background=#FFE4B5` (a light cream)
// ends up with platform-default white text on dark theme;
// unreadable.
//
// Gate ALL three color overrides on having a complete
// bg + text pair. When either is missing we drop the
// whole palette and fall back to the platform theme;
// background image (`bg`) and font tags still flow
// through (they don't break contrast on their own).
val hasReadablePalette = backgroundArgb != null && textArgb != null
return RoomTheme(
backgroundArgb = pickHex(ColorTag.Target.BACKGROUND),
textArgb = pickHex(ColorTag.Target.TEXT),
primaryArgb = pickHex(ColorTag.Target.PRIMARY),
backgroundArgb = if (hasReadablePalette) backgroundArgb else null,
textArgb = if (hasReadablePalette) textArgb else null,
primaryArgb = if (hasReadablePalette) primaryArgb else null,
backgroundImageUrl = bg?.url,
backgroundMode =
when (bg?.mode) {