updates themeing to align better with website harmonies
This commit is contained in:
+27
-19
@@ -111,38 +111,46 @@ class AppConfig {{
|
|||||||
def generate_theme_colors(theme: dict) -> str:
|
def generate_theme_colors(theme: dict) -> str:
|
||||||
c = theme["colors"]
|
c = theme["colors"]
|
||||||
|
|
||||||
# Light mode
|
# Light mode — mapped to match companion website color usage
|
||||||
light_props = [
|
light_props = [
|
||||||
("primarySeed", hex_to_rgba(c["primary"])),
|
("headingColor", hex_to_rgba(c["primary"])),
|
||||||
("secondarySeed", hex_to_rgba(c["accent"])),
|
("accentColor", hex_to_rgba(c["accent"])),
|
||||||
("scaffoldGradientStart", hex_to_rgba(c["background"])),
|
("scaffoldGradientStart", hex_to_rgba(c["background"])),
|
||||||
("scaffoldGradientEnd", hex_to_rgba(c["light"])),
|
("scaffoldGradientEnd", hex_to_rgba(c["light"])),
|
||||||
("shellSurface", hex_to_rgba(c["white"], 0.97)),
|
("shellSurface", hex_to_rgba(c["white"], 0.97)),
|
||||||
("shellBorder", hex_to_rgba(c["medium"], 0.10)),
|
("shellBorder", hex_to_rgba(c["medium"], 0.10)),
|
||||||
("accent", hex_to_rgba(c["accent_dark"])),
|
("mutedText", hex_to_rgba(c["medium"])),
|
||||||
("webViewBorder", hex_to_rgba(c["medium"], 0.15)),
|
("textOnDark", hex_to_rgba(c["white"])),
|
||||||
("webViewBackground", hex_to_rgba(c["white"])),
|
("textOnDarkSecondary", hex_to_rgba(c["light"])),
|
||||||
("controlsGradientStart", hex_to_rgba(c["primary_muted"])),
|
("controlsGradientStart", hex_to_rgba(c["primary"])),
|
||||||
("controlsGradientEnd", hex_to_rgba(c["accent_muted"])),
|
("controlsGradientEnd", hex_to_rgba(c["primary_light"])),
|
||||||
("controlsShadow", hex_to_rgba(c["black"], 0.14)),
|
("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 = [
|
dark_props = [
|
||||||
("primarySeed", hex_to_rgba(c["primary_light"])),
|
("headingColor", hex_to_rgba(c["primary_light"])),
|
||||||
("secondarySeed", hex_to_rgba(c["accent_light"])),
|
("accentColor", hex_to_rgba(c["accent_light"])),
|
||||||
("scaffoldGradientStart", hex_to_rgba(c["black"])),
|
("scaffoldGradientStart", hex_to_rgba(c["black"])),
|
||||||
("scaffoldGradientEnd", darken(c["primary_dark"], 0.30)),
|
("scaffoldGradientEnd", darken(c["primary_dark"], 0.30)),
|
||||||
("shellSurface", hex_to_rgba(c["black"], 0.85)),
|
("shellSurface", hex_to_rgba(c["primary_dark"], 0.85)),
|
||||||
("shellBorder", hex_to_rgba(c["accent_light"], 0.20)),
|
("shellBorder", hex_to_rgba(c["medium"], 0.20)),
|
||||||
("accent", hex_to_rgba(c["primary_light"])),
|
("mutedText", hex_to_rgba(c["medium"])),
|
||||||
("webViewBorder", hex_to_rgba(c["accent_light"], 0.20)),
|
("textOnDark", hex_to_rgba(c["white"])),
|
||||||
("webViewBackground", hex_to_rgba(c["black"])),
|
("textOnDarkSecondary", hex_to_rgba(c["light"])),
|
||||||
("controlsGradientStart", hex_to_rgba(c["primary_dark"])),
|
("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)),
|
("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:
|
def props_block(props, indent: str = " ") -> str:
|
||||||
|
|||||||
@@ -4,34 +4,59 @@ import 'generated/theme_colors.dart';
|
|||||||
|
|
||||||
class AppThemeColors {
|
class AppThemeColors {
|
||||||
const AppThemeColors({
|
const AppThemeColors({
|
||||||
required this.primarySeed,
|
required this.headingColor,
|
||||||
required this.secondarySeed,
|
required this.accentColor,
|
||||||
required this.scaffoldGradientStart,
|
required this.scaffoldGradientStart,
|
||||||
required this.scaffoldGradientEnd,
|
required this.scaffoldGradientEnd,
|
||||||
required this.shellSurface,
|
required this.shellSurface,
|
||||||
required this.shellBorder,
|
required this.shellBorder,
|
||||||
required this.accent,
|
required this.mutedText,
|
||||||
required this.webViewBorder,
|
required this.textOnDark,
|
||||||
required this.webViewBackground,
|
required this.textOnDarkSecondary,
|
||||||
required this.controlsGradientStart,
|
required this.controlsGradientStart,
|
||||||
required this.controlsGradientEnd,
|
required this.controlsGradientEnd,
|
||||||
required this.controlsShadow,
|
required this.controlsShadow,
|
||||||
required this.statusText,
|
required this.bodyText,
|
||||||
|
required this.cardSurface,
|
||||||
|
required this.cardBorder,
|
||||||
|
required this.successColor,
|
||||||
|
required this.dangerColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Color primarySeed;
|
/// Website: `primary` → headings (h1–h6)
|
||||||
final Color secondarySeed;
|
final Color headingColor;
|
||||||
|
/// Website: `accent` → links & accent highlights
|
||||||
|
final Color accentColor;
|
||||||
|
/// Page background gradient start — website: `background` (cream)
|
||||||
final Color scaffoldGradientStart;
|
final Color scaffoldGradientStart;
|
||||||
|
/// Page background gradient end — website: `light`
|
||||||
final Color scaffoldGradientEnd;
|
final Color scaffoldGradientEnd;
|
||||||
|
/// Top header card surface
|
||||||
final Color shellSurface;
|
final Color shellSurface;
|
||||||
|
/// Top header card border
|
||||||
final Color shellBorder;
|
final Color shellBorder;
|
||||||
final Color accent;
|
/// Website: `medium` → muted / secondary text
|
||||||
final Color webViewBorder;
|
final Color mutedText;
|
||||||
final Color webViewBackground;
|
/// 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;
|
final Color controlsGradientStart;
|
||||||
|
/// Controls bar / card surface gradient end — website: `primary_dark`
|
||||||
final Color controlsGradientEnd;
|
final Color controlsGradientEnd;
|
||||||
|
/// Shadow color for elevated surfaces
|
||||||
final Color controlsShadow;
|
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 {
|
class AppThemeBusinessObject {
|
||||||
@@ -47,17 +72,17 @@ class AppThemeBusinessObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ThemeData lightTheme() {
|
static ThemeData lightTheme() {
|
||||||
final ColorScheme scheme =
|
final ColorScheme scheme = ColorScheme.light(
|
||||||
ColorScheme.fromSeed(
|
brightness: Brightness.light,
|
||||||
seedColor: lightColors.primarySeed,
|
primary: lightColors.headingColor,
|
||||||
brightness: Brightness.light,
|
onPrimary: lightColors.textOnDark,
|
||||||
).copyWith(
|
secondary: lightColors.accentColor,
|
||||||
primary: lightColors.primarySeed,
|
onSecondary: lightColors.textOnDark,
|
||||||
secondary: lightColors.secondarySeed,
|
surface: lightColors.shellSurface,
|
||||||
tertiary: const Color(0xFF2C85E1),
|
onSurface: lightColors.bodyText,
|
||||||
surface: const Color(0xFFFFFBF7),
|
error: lightColors.dangerColor,
|
||||||
onSurface: lightColors.statusText,
|
onError: lightColors.textOnDark,
|
||||||
);
|
);
|
||||||
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
@@ -77,17 +102,17 @@ class AppThemeBusinessObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ThemeData darkTheme() {
|
static ThemeData darkTheme() {
|
||||||
final ColorScheme scheme =
|
final ColorScheme scheme = ColorScheme.dark(
|
||||||
ColorScheme.fromSeed(
|
brightness: Brightness.dark,
|
||||||
seedColor: darkColors.primarySeed,
|
primary: darkColors.headingColor,
|
||||||
brightness: Brightness.dark,
|
onPrimary: darkColors.textOnDark,
|
||||||
).copyWith(
|
secondary: darkColors.accentColor,
|
||||||
primary: darkColors.primarySeed,
|
onSecondary: darkColors.textOnDark,
|
||||||
secondary: darkColors.secondarySeed,
|
surface: darkColors.shellSurface,
|
||||||
tertiary: const Color(0xFF4E97E8),
|
onSurface: darkColors.bodyText,
|
||||||
surface: const Color(0xFF111A27),
|
error: darkColors.dangerColor,
|
||||||
onSurface: darkColors.statusText,
|
onError: darkColors.textOnDark,
|
||||||
);
|
);
|
||||||
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class LiveInfoPanel extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
Icons.graphic_eq_rounded,
|
Icons.graphic_eq_rounded,
|
||||||
color: themeColors.statusText,
|
color: themeColors.textOnDarkSecondary,
|
||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -67,7 +67,7 @@ class LiveInfoPanel extends StatelessWidget {
|
|||||||
'Live Studio Feed',
|
'Live Studio Feed',
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
color: themeColors.statusText,
|
color: themeColors.textOnDark,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -94,7 +94,9 @@ class LiveInfoPanel extends StatelessWidget {
|
|||||||
child: TrackCard(
|
child: TrackCard(
|
||||||
label: 'Now Playing',
|
label: 'Now Playing',
|
||||||
track: current,
|
track: current,
|
||||||
titleColor: themeColors.statusText,
|
titleColor: themeColors.textOnDark,
|
||||||
|
cardSurface: themeColors.cardSurface,
|
||||||
|
cardBorder: themeColors.cardBorder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -102,7 +104,9 @@ class LiveInfoPanel extends StatelessWidget {
|
|||||||
child: TrackCard(
|
child: TrackCard(
|
||||||
label: 'Coming Next',
|
label: 'Coming Next',
|
||||||
track: 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',
|
label: 'On Air Show',
|
||||||
show: currentShow,
|
show: currentShow,
|
||||||
sourceTimezone: snapshot?.timezone,
|
sourceTimezone: snapshot?.timezone,
|
||||||
titleColor: themeColors.statusText,
|
titleColor: themeColors.textOnDarkSecondary,
|
||||||
|
cardSurface: themeColors.cardSurface,
|
||||||
|
cardBorder: themeColors.cardBorder,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
ShowCard(
|
ShowCard(
|
||||||
label: 'Up Next Show',
|
label: 'Up Next Show',
|
||||||
show: nextShow,
|
show: nextShow,
|
||||||
sourceTimezone: snapshot?.timezone,
|
sourceTimezone: snapshot?.timezone,
|
||||||
titleColor: themeColors.statusText,
|
titleColor: themeColors.textOnDarkSecondary,
|
||||||
|
cardSurface: themeColors.cardSurface,
|
||||||
|
cardBorder: themeColors.cardBorder,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
+2
-2
@@ -400,7 +400,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||||||
style: theme.textTheme.headlineMedium?.copyWith(
|
style: theme.textTheme.headlineMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
letterSpacing: 0.4,
|
letterSpacing: 0.4,
|
||||||
color: themeColors.statusText,
|
color: themeColors.headingColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -469,7 +469,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||||||
_playbackStatusLabel(),
|
_playbackStatusLabel(),
|
||||||
style: theme.textTheme.titleSmall?.copyWith(
|
style: theme.textTheme.titleSmall?.copyWith(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: themeColors.statusText,
|
color: themeColors.textOnDark,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
+13
-4
@@ -10,12 +10,16 @@ class ShowCard extends StatelessWidget {
|
|||||||
required this.show,
|
required this.show,
|
||||||
required this.sourceTimezone,
|
required this.sourceTimezone,
|
||||||
required this.titleColor,
|
required this.titleColor,
|
||||||
|
required this.cardSurface,
|
||||||
|
required this.cardBorder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
final LiveInfoShowInfo? show;
|
final LiveInfoShowInfo? show;
|
||||||
final String? sourceTimezone;
|
final String? sourceTimezone;
|
||||||
final Color titleColor;
|
final Color titleColor;
|
||||||
|
final Color cardSurface;
|
||||||
|
final Color cardBorder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -23,8 +27,8 @@ class ShowCard extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: Colors.black.withValues(alpha: 0.06),
|
color: cardSurface,
|
||||||
border: Border.all(color: Colors.black.withValues(alpha: 0.08)),
|
border: Border.all(color: cardBorder),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -37,7 +41,10 @@ class ShowCard extends StatelessWidget {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(
|
style: Theme.of(
|
||||||
context,
|
context,
|
||||||
).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600),
|
).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: titleColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -46,7 +53,9 @@ class ShowCard extends StatelessWidget {
|
|||||||
show?.starts,
|
show?.starts,
|
||||||
sourceTimezone: sourceTimezone,
|
sourceTimezone: sourceTimezone,
|
||||||
),
|
),
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.labelSmall?.copyWith(color: titleColor),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
+17
-5
@@ -9,11 +9,15 @@ class TrackCard extends StatelessWidget {
|
|||||||
required this.label,
|
required this.label,
|
||||||
required this.track,
|
required this.track,
|
||||||
required this.titleColor,
|
required this.titleColor,
|
||||||
|
required this.cardSurface,
|
||||||
|
required this.cardBorder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
final LiveInfoTrackInfo? track;
|
final LiveInfoTrackInfo? track;
|
||||||
final Color titleColor;
|
final Color titleColor;
|
||||||
|
final Color cardSurface;
|
||||||
|
final Color cardBorder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -24,9 +28,9 @@ class TrackCard extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withValues(alpha: 0.08),
|
color: cardSurface,
|
||||||
borderRadius: BorderRadius.circular(14),
|
borderRadius: BorderRadius.circular(14),
|
||||||
border: Border.all(color: Colors.black.withValues(alpha: 0.12)),
|
border: Border.all(color: cardBorder),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -45,21 +49,29 @@ class TrackCard extends StatelessWidget {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(
|
style: Theme.of(
|
||||||
context,
|
context,
|
||||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700),
|
).textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: titleColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Text(
|
Text(
|
||||||
subtitle.isEmpty ? 'No metadata provided' : subtitle,
|
subtitle.isEmpty ? 'No metadata provided' : subtitle,
|
||||||
maxLines: 6,
|
maxLines: 6,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.bodySmall?.copyWith(color: titleColor),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(
|
Text(
|
||||||
window,
|
window,
|
||||||
style: Theme.of(
|
style: Theme.of(
|
||||||
context,
|
context,
|
||||||
).textTheme.labelMedium?.copyWith(fontWeight: FontWeight.w600),
|
).textTheme.labelMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: titleColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user