feat(event): DEF CON 34 logo and full brand palette in event theming - #6483
Conversation
Event branding read only one color per edition — the accent wash on the app
bar. For DEF CON 34 that color is #0D294A, a navy so dark it is invisible
washed over a dark surface, so the app showed a generic Meshtastic logo and no
visible theming at all while connected to DEF CON firmware. The metadata
already carried a six-color palette, named brand colors, a theme name, and a
tagline; none of it reached the UI.
- Bundle the DEF CON 34 mark as the branding icon, and point the edition's
iconUrl at the hosted copy shipping alongside in meshtastic/api.
- Carry the full palette and a high-contrast highlight through EventTheme, and
draw the palette as a gradient rule under the app bar and closing the info
sheet header — the wash can only ever show one color.
- Surface the theme name and tagline in the info sheet ("Agency" for DC34).
- Pick info-sheet tints with pickLegible(): brand palettes are authored for the
event's own materials, so an edition's loudest color may fail contrast on our
light or dark surface. Falls back through the palette, then onSurfaceVariant.
All of it is data-driven, so every edition gets whatever colors it publishes;
DEF CON is simply the first with a full palette to spend.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughDEF CON 34 metadata now includes an icon URL. Event branding resolves palettes and highlights, propagates them through ChangesEvent branding
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant EventFirmwareEdition
participant AppCompositionLocals
participant LocalEventTheme
participant MainAppBar
participant EventInfoSheet
EventFirmwareEdition->>AppCompositionLocals: provide event metadata
AppCompositionLocals->>LocalEventTheme: resolve accent, highlight, and palette
LocalEventTheme->>MainAppBar: provide palette
LocalEventTheme->>EventInfoSheet: provide palette and highlight
MainAppBar->>MainAppBar: render brand rule
EventInfoSheet->>EventInfoSheet: render palette strip and legible icons
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/LocalEventBranding.kt (1)
127-132: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueAuthored palette path skips
distinct().The fallback branch de-dupes but
fromPalettedoesn't, so a duplicated authored hex yields repeated gradient stops. Cheap to make consistent.♻️ Proposed tweak
- val fromPalette = theme?.palette.orEmpty().mapNotNull(::parseBrandColor) + val fromPalette = theme?.palette.orEmpty().mapNotNull(::parseBrandColor).distinct()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/LocalEventBranding.kt` around lines 127 - 132, Update EventFirmwareEdition.brandPalette so the authored theme palette mapped through parseBrandColor is de-duplicated with distinct() before returning, matching the fallback named-color path while preserving palette order.core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.kt (1)
155-165: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPalette-strip rendering is duplicated across two files. Both sites build the same gradient-or-solid
Brushand draw the same full-widthBox, each with its own privateMIN_GRADIENT_STOPS; only the height differs. Extract one shared composable (e.g.EventPaletteStrip(palette, height)) incore:uiand drop the duplicate constant.
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.kt#L155-L165: replaceEventBrandRulewith a call to the shared composable usingEVENT_BRAND_RULE_HEIGHT, and remove the localMIN_GRADIENT_STOPS.core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EventInfoSheet.kt#L207-L217: replace the inline strip block with the shared composable usingPALETTE_STRIP_HEIGHT, and remove the localMIN_GRADIENT_STOPS.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.kt` around lines 155 - 165, Extract the duplicated palette-strip rendering into a shared EventPaletteStrip composable in core/ui, centralizing the gradient/solid Brush logic and MIN_GRADIENT_STOPS constant. In core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.kt#L155-L165, replace EventBrandRule with EventPaletteStrip using EVENT_BRAND_RULE_HEIGHT and remove the local constant; in core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EventInfoSheet.kt#L207-L217, replace the inline strip with EventPaletteStrip using PALETTE_STRIP_HEIGHT and remove its local constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.kt`:
- Around line 155-165: Extract the duplicated palette-strip rendering into a
shared EventPaletteStrip composable in core/ui, centralizing the gradient/solid
Brush logic and MIN_GRADIENT_STOPS constant. In
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.kt#L155-L165,
replace EventBrandRule with EventPaletteStrip using EVENT_BRAND_RULE_HEIGHT and
remove the local constant; in
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EventInfoSheet.kt#L207-L217,
replace the inline strip with EventPaletteStrip using PALETTE_STRIP_HEIGHT and
remove its local constant.
In
`@core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/LocalEventBranding.kt`:
- Around line 127-132: Update EventFirmwareEdition.brandPalette so the authored
theme palette mapped through parseBrandColor is de-duplicated with distinct()
before returning, matching the fallback named-color path while preserving
palette order.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d74686c6-d1b8-4260-95e7-0c51a6e2f562
⛔ Files ignored due to path filters (1)
core/resources/src/commonMain/composeResources/drawable/img_event_defcon.pngis excluded by!**/*.png,!**/*.png
📒 Files selected for processing (9)
androidApp/src/main/assets/event_firmware.jsonandroidApp/src/main/kotlin/org/meshtastic/app/MainActivity.ktcore/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EventInfoSheet.ktcore/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MainAppBar.ktcore/ui/src/commonMain/kotlin/org/meshtastic/core/ui/theme/ColorContrast.ktcore/ui/src/commonMain/kotlin/org/meshtastic/core/ui/theme/EventFonts.ktcore/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/LocalEventBranding.ktcore/ui/src/commonTest/kotlin/org/meshtastic/core/ui/theme/PickLegibleTest.ktcore/ui/src/commonTest/kotlin/org/meshtastic/core/ui/util/EventBrandingTest.kt
…olors Addresses CodeRabbit nitpicks on #6483. The app bar rule and the info-sheet header strip built the same gradient-or-solid brush and drew the same full-width Box, each with its own private MIN_GRADIENT_STOPS; only the height differed. Extract EventPaletteStrip and pass the height. brandPalette() de-duplicated the named-color fallback but not the authored palette, so a repeated hex became a repeated gradient stop — flattening the gradient over that span. Both paths now de-dupe, preserving authored order. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Both CodeRabbit nitpicks addressed in a679d2b:
No inline review threads were opened on this PR, so there was nothing to reply to or resolve individually. 🤖 Addressed by Claude Code |
🌟 Why
Event branding only ever read one color per edition: the accent wash behind the app bar. For DEF CON 34 that color is
#0D294A— a navy dark enough that washed at 12% over a dark surface it is invisible. Connected to DEF CON firmware, the app showed a generic Meshtastic logo and no visible theming at all.The metadata was never the problem.
event_firmware.jsonalready carries DEF CON's six-color palette, its named brand colors, the theme name ("Agency"), and the tagline. None of it reached the UI.🛠️ What
Logo — bundles the DEF CON 34 mark as
img_event_defcon.png(384×384, 18.6 KB) and registers it ineventIconFor(), and points the edition'siconUrlat the hosted copy shipping in meshtastic/api#109. Hosted first, bundled as the offline fallback — the existingEventBrandingIconcontract, so the icon appears whether or not the API change has landed.Palette —
EventThemenow carries the fullpaletteand a high-contrasthighlightalongside the washaccent. The palette is drawn as a gradient rule under the app bar and as a strip closing the info-sheet header. A single wash color can never show more than one color; the rule is where the rest of the palette lives.Unused metadata — the info sheet now renders the theme name (as a subtitle to the event name) and the tagline.
Contrast — new
pickLegible()inColorContrast.kt. Brand palettes are authored for the event's own print and web materials, not for our light and dark surfaces: DEF CON's navy fails on dark, FAB26's#EAB14Bfails on light. Info-sheet tints now walk highlight → palette →onSurfaceVariant, taking the first that clears WCAG AA for graphical objects.Everything is data-driven off the manifest, so every edition gets whatever colors it publishes. DEF CON is just the first with a full palette to spend; Hamvention and Open Sauce publish one color and render exactly as before.
🎨 Design notes
🧪 Testing performed
EventBrandingTest— new coverage forbrandPalette()(authored palette preferred, malformed hex dropped, falls back to named colors then accent, de-duplicated, empty when nothing is published) andbrandHighlightOrNull()(accent → secondary; a bare primary is the wash color and is never promoted to a highlight).PickLegibleTest— new. Same palette resolving to different colors on light vs dark backgrounds, threshold honoured, fallback when nothing reads../gradlew spotlessApply spotlessCheck detekt assembleDebug test allTests— green.Not yet verified against a physically connected DEF CON device; the branding path itself (hosted icon → bundled fallback → Meshtastic logo) is unchanged, and the palette work is exercised by unit tests.
🔗 Related
defcon34.pngand sets the matchingiconUrlupstream. Independent: this PR's bundled drawable covers the gap until it deploys.🤖 Generated with Claude Code
Summary by CodeRabbit