From f069fcdbfbbf39d5f3a9db36b2c9f2134d5bf34a Mon Sep 17 00:00:00 2001 From: kfj001 Date: Sun, 12 Jul 2026 01:38:14 -0700 Subject: [PATCH] updates themeing to align better with website harmonies --- build_whitelabel.py | 46 +++++++++------ lib/app_theme_business_object.dart | 93 +++++++++++++++++++----------- lib/live_info_panel.dart | 20 +++++-- lib/main.dart | 4 +- lib/show_card.dart | 17 ++++-- lib/track_card.dart | 22 +++++-- 6 files changed, 132 insertions(+), 70 deletions(-) diff --git a/build_whitelabel.py b/build_whitelabel.py index 37bbf52..e73b18e 100644 --- a/build_whitelabel.py +++ b/build_whitelabel.py @@ -111,38 +111,46 @@ class AppConfig {{ def generate_theme_colors(theme: dict) -> str: c = theme["colors"] - # Light mode + # Light mode — mapped to match companion website color usage light_props = [ - ("primarySeed", hex_to_rgba(c["primary"])), - ("secondarySeed", hex_to_rgba(c["accent"])), + ("headingColor", hex_to_rgba(c["primary"])), + ("accentColor", hex_to_rgba(c["accent"])), ("scaffoldGradientStart", hex_to_rgba(c["background"])), ("scaffoldGradientEnd", hex_to_rgba(c["light"])), ("shellSurface", hex_to_rgba(c["white"], 0.97)), ("shellBorder", hex_to_rgba(c["medium"], 0.10)), - ("accent", hex_to_rgba(c["accent_dark"])), - ("webViewBorder", hex_to_rgba(c["medium"], 0.15)), - ("webViewBackground", hex_to_rgba(c["white"])), - ("controlsGradientStart", hex_to_rgba(c["primary_muted"])), - ("controlsGradientEnd", hex_to_rgba(c["accent_muted"])), + ("mutedText", hex_to_rgba(c["medium"])), + ("textOnDark", hex_to_rgba(c["white"])), + ("textOnDarkSecondary", hex_to_rgba(c["light"])), + ("controlsGradientStart", hex_to_rgba(c["primary"])), + ("controlsGradientEnd", hex_to_rgba(c["primary_light"])), ("controlsShadow", hex_to_rgba(c["black"], 0.14)), - ("statusText", hex_to_rgba(c["text"])), + ("bodyText", hex_to_rgba(c["text"])), + ("cardSurface", hex_to_rgba(c["white"], 0.08)), + ("cardBorder", hex_to_rgba(c["white"], 0.12)), + ("successColor", hex_to_rgba(c["success"])), + ("dangerColor", hex_to_rgba(c["danger"])), ] - # Dark mode + # Dark mode — mapped to match companion website color usage dark_props = [ - ("primarySeed", hex_to_rgba(c["primary_light"])), - ("secondarySeed", hex_to_rgba(c["accent_light"])), + ("headingColor", hex_to_rgba(c["primary_light"])), + ("accentColor", hex_to_rgba(c["accent_light"])), ("scaffoldGradientStart", hex_to_rgba(c["black"])), ("scaffoldGradientEnd", darken(c["primary_dark"], 0.30)), - ("shellSurface", hex_to_rgba(c["black"], 0.85)), - ("shellBorder", hex_to_rgba(c["accent_light"], 0.20)), - ("accent", hex_to_rgba(c["primary_light"])), - ("webViewBorder", hex_to_rgba(c["accent_light"], 0.20)), - ("webViewBackground", hex_to_rgba(c["black"])), + ("shellSurface", hex_to_rgba(c["primary_dark"], 0.85)), + ("shellBorder", hex_to_rgba(c["medium"], 0.20)), + ("mutedText", hex_to_rgba(c["medium"])), + ("textOnDark", hex_to_rgba(c["white"])), + ("textOnDarkSecondary", hex_to_rgba(c["light"])), ("controlsGradientStart", hex_to_rgba(c["primary_dark"])), - ("controlsGradientEnd", hex_to_rgba(c["accent_dark"])), + ("controlsGradientEnd", hex_to_rgba(c["primary"])), ("controlsShadow", hex_to_rgba(c["black"], 0.27)), - ("statusText", hex_to_rgba(c["light"])), + ("bodyText", hex_to_rgba(c["light"])), + ("cardSurface", hex_to_rgba(c["white"], 0.08)), + ("cardBorder", hex_to_rgba(c["white"], 0.12)), + ("successColor", hex_to_rgba(c["success"])), + ("dangerColor", hex_to_rgba(c["danger"])), ] def props_block(props, indent: str = " ") -> str: diff --git a/lib/app_theme_business_object.dart b/lib/app_theme_business_object.dart index 9a58370..a37b335 100644 --- a/lib/app_theme_business_object.dart +++ b/lib/app_theme_business_object.dart @@ -4,34 +4,59 @@ import 'generated/theme_colors.dart'; class AppThemeColors { const AppThemeColors({ - required this.primarySeed, - required this.secondarySeed, + required this.headingColor, + required this.accentColor, required this.scaffoldGradientStart, required this.scaffoldGradientEnd, required this.shellSurface, required this.shellBorder, - required this.accent, - required this.webViewBorder, - required this.webViewBackground, + required this.mutedText, + required this.textOnDark, + required this.textOnDarkSecondary, required this.controlsGradientStart, required this.controlsGradientEnd, required this.controlsShadow, - required this.statusText, + required this.bodyText, + required this.cardSurface, + required this.cardBorder, + required this.successColor, + required this.dangerColor, }); - final Color primarySeed; - final Color secondarySeed; + /// Website: `primary` → headings (h1–h6) + final Color headingColor; + /// Website: `accent` → links & accent highlights + final Color accentColor; + /// Page background gradient start — website: `background` (cream) final Color scaffoldGradientStart; + /// Page background gradient end — website: `light` final Color scaffoldGradientEnd; + /// Top header card surface final Color shellSurface; + /// Top header card border final Color shellBorder; - final Color accent; - final Color webViewBorder; - final Color webViewBackground; + /// Website: `medium` → muted / secondary text + final Color mutedText; + /// Website: `white` → text on dark surfaces + final Color textOnDark; + /// Website: `light` → secondary text on dark surfaces + final Color textOnDarkSecondary; + /// Controls bar / card surface gradient start — website: `primary_dark` final Color controlsGradientStart; + /// Controls bar / card surface gradient end — website: `primary_dark` final Color controlsGradientEnd; + /// Shadow color for elevated surfaces final Color controlsShadow; - final Color statusText; + /// Website: `text` → body text + final Color bodyText; + /// Inner card background overlay — derived from `primary_dark` / `primary_light` + final Color cardSurface; + /// Inner card border — derived from `primary_dark` / `primary_light` + final Color cardBorder; + /// Website: `success` → live indicator, success states + final Color successColor; + /// Website: `danger` → error states + final Color dangerColor; } class AppThemeBusinessObject { @@ -47,17 +72,17 @@ class AppThemeBusinessObject { } static ThemeData lightTheme() { - final ColorScheme scheme = - ColorScheme.fromSeed( - seedColor: lightColors.primarySeed, - brightness: Brightness.light, - ).copyWith( - primary: lightColors.primarySeed, - secondary: lightColors.secondarySeed, - tertiary: const Color(0xFF2C85E1), - surface: const Color(0xFFFFFBF7), - onSurface: lightColors.statusText, - ); + final ColorScheme scheme = ColorScheme.light( + brightness: Brightness.light, + primary: lightColors.headingColor, + onPrimary: lightColors.textOnDark, + secondary: lightColors.accentColor, + onSecondary: lightColors.textOnDark, + surface: lightColors.shellSurface, + onSurface: lightColors.bodyText, + error: lightColors.dangerColor, + onError: lightColors.textOnDark, + ); return ThemeData( useMaterial3: true, @@ -77,17 +102,17 @@ class AppThemeBusinessObject { } static ThemeData darkTheme() { - final ColorScheme scheme = - ColorScheme.fromSeed( - seedColor: darkColors.primarySeed, - brightness: Brightness.dark, - ).copyWith( - primary: darkColors.primarySeed, - secondary: darkColors.secondarySeed, - tertiary: const Color(0xFF4E97E8), - surface: const Color(0xFF111A27), - onSurface: darkColors.statusText, - ); + final ColorScheme scheme = ColorScheme.dark( + brightness: Brightness.dark, + primary: darkColors.headingColor, + onPrimary: darkColors.textOnDark, + secondary: darkColors.accentColor, + onSecondary: darkColors.textOnDark, + surface: darkColors.shellSurface, + onSurface: darkColors.bodyText, + error: darkColors.dangerColor, + onError: darkColors.textOnDark, + ); return ThemeData( useMaterial3: true, diff --git a/lib/live_info_panel.dart b/lib/live_info_panel.dart index 6393af9..d442a31 100644 --- a/lib/live_info_panel.dart +++ b/lib/live_info_panel.dart @@ -58,7 +58,7 @@ class LiveInfoPanel extends StatelessWidget { children: [ Icon( Icons.graphic_eq_rounded, - color: themeColors.statusText, + color: themeColors.textOnDarkSecondary, size: 20, ), const SizedBox(width: 8), @@ -67,7 +67,7 @@ class LiveInfoPanel extends StatelessWidget { 'Live Studio Feed', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w800, - color: themeColors.statusText, + color: themeColors.textOnDark, ), ), ), @@ -94,7 +94,9 @@ class LiveInfoPanel extends StatelessWidget { child: TrackCard( label: 'Now Playing', track: current, - titleColor: themeColors.statusText, + titleColor: themeColors.textOnDark, + cardSurface: themeColors.cardSurface, + cardBorder: themeColors.cardBorder, ), ), const SizedBox(width: 8), @@ -102,7 +104,9 @@ class LiveInfoPanel extends StatelessWidget { child: TrackCard( label: 'Coming Next', track: next, - titleColor: themeColors.statusText, + titleColor: themeColors.textOnDark, + cardSurface: themeColors.cardSurface, + cardBorder: themeColors.cardBorder, ), ), ], @@ -113,14 +117,18 @@ class LiveInfoPanel extends StatelessWidget { label: 'On Air Show', show: currentShow, sourceTimezone: snapshot?.timezone, - titleColor: themeColors.statusText, + titleColor: themeColors.textOnDarkSecondary, + cardSurface: themeColors.cardSurface, + cardBorder: themeColors.cardBorder, ), const SizedBox(height: 6), ShowCard( label: 'Up Next Show', show: nextShow, sourceTimezone: snapshot?.timezone, - titleColor: themeColors.statusText, + titleColor: themeColors.textOnDarkSecondary, + cardSurface: themeColors.cardSurface, + cardBorder: themeColors.cardBorder, ), const SizedBox(height: 6), Text( diff --git a/lib/main.dart b/lib/main.dart index 9b59f3c..61125d6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -400,7 +400,7 @@ class _MainPageState extends State with WidgetsBindingObserver { style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.w900, letterSpacing: 0.4, - color: themeColors.statusText, + color: themeColors.headingColor, ), ), ), @@ -469,7 +469,7 @@ class _MainPageState extends State with WidgetsBindingObserver { _playbackStatusLabel(), style: theme.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w700, - color: themeColors.statusText, + color: themeColors.textOnDark, ), ), ], diff --git a/lib/show_card.dart b/lib/show_card.dart index 1a94805..48f11b3 100644 --- a/lib/show_card.dart +++ b/lib/show_card.dart @@ -10,12 +10,16 @@ class ShowCard extends StatelessWidget { required this.show, required this.sourceTimezone, required this.titleColor, + required this.cardSurface, + required this.cardBorder, }); final String label; final LiveInfoShowInfo? show; final String? sourceTimezone; final Color titleColor; + final Color cardSurface; + final Color cardBorder; @override Widget build(BuildContext context) { @@ -23,8 +27,8 @@ class ShowCard extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), - color: Colors.black.withValues(alpha: 0.06), - border: Border.all(color: Colors.black.withValues(alpha: 0.08)), + color: cardSurface, + border: Border.all(color: cardBorder), ), child: Row( children: [ @@ -37,7 +41,10 @@ class ShowCard extends StatelessWidget { overflow: TextOverflow.ellipsis, style: Theme.of( context, - ).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600), + ).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: titleColor, + ), ), ), const SizedBox(width: 8), @@ -46,7 +53,9 @@ class ShowCard extends StatelessWidget { show?.starts, sourceTimezone: sourceTimezone, ), - style: Theme.of(context).textTheme.labelSmall, + style: Theme.of( + context, + ).textTheme.labelSmall?.copyWith(color: titleColor), ), ], ), diff --git a/lib/track_card.dart b/lib/track_card.dart index 81ad1d7..5180b77 100644 --- a/lib/track_card.dart +++ b/lib/track_card.dart @@ -9,11 +9,15 @@ class TrackCard extends StatelessWidget { required this.label, required this.track, required this.titleColor, + required this.cardSurface, + required this.cardBorder, }); final String label; final LiveInfoTrackInfo? track; final Color titleColor; + final Color cardSurface; + final Color cardBorder; @override Widget build(BuildContext context) { @@ -24,9 +28,9 @@ class TrackCard extends StatelessWidget { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: Colors.black.withValues(alpha: 0.08), + color: cardSurface, borderRadius: BorderRadius.circular(14), - border: Border.all(color: Colors.black.withValues(alpha: 0.12)), + border: Border.all(color: cardBorder), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -45,21 +49,29 @@ class TrackCard extends StatelessWidget { overflow: TextOverflow.ellipsis, style: Theme.of( context, - ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700), + ).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: titleColor, + ), ), const SizedBox(height: 6), Text( subtitle.isEmpty ? 'No metadata provided' : subtitle, maxLines: 6, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodySmall, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: titleColor), ), const Spacer(), Text( window, style: Theme.of( context, - ).textTheme.labelMedium?.copyWith(fontWeight: FontWeight.w600), + ).textTheme.labelMedium?.copyWith( + fontWeight: FontWeight.w600, + color: titleColor, + ), ), ], ),