import 'package:flutter/widgets.dart'; /// A full color palette for one selectable app theme. Immutable; the app swaps /// which instance is [TimbreColors._active] when the user changes theme. class TimbrePalette { const TimbrePalette({ required this.brightness, required this.background, required this.surface, required this.foreground, required this.dimmed, required this.border, required this.borderActive, required this.accentDefault, }); final Brightness brightness; final Color background; final Color surface; final Color foreground; final Color dimmed; final Color border; final Color borderActive; final Color accentDefault; /// The original near-black, low-contrast theme (the app's default). static const TimbrePalette dark = TimbrePalette( brightness: Brightness.dark, background: Color(0xFF1A1A1A), surface: Color(0xFF161616), foreground: Color(0xFFD4D0C8), dimmed: Color(0xFF5A5858), border: Color(0xFF252525), borderActive: Color(0xFF3A3A3A), accentDefault: Color(0xFFFF8C00), ); /// A light theme: lavender canvas, slightly-deeper-lavender panels, deep-indigo /// text and accent. The accent is locked to [accentDefault] while this theme /// is active (see `main.dart`). static const TimbrePalette lavender = TimbrePalette( brightness: Brightness.light, background: Color(0xFFD3D3FF), // lavender canvas (primary) surface: Color(0xFFC6C6F4), // slightly darker lavender panels foreground: Color(0xFF2E2A45), // deep-indigo text dimmed: Color(0xFF6A6688), // muted indigo-grey border: Color(0xFFB9B9E8), // deeper-lavender hairline borderActive: Color(0xFF2E2A45), // accent-toned active border accentDefault: Color(0xFF2E2A45), // deep indigo (accent) ); } /// Design tokens mirroring Timbre's `dynamic`/`static` theme defaults /// (see timbre `docs/sample-config.toml`, `theme.rs`, `color.rs`). /// /// The palette is intentionally near-black and low-contrast in the default /// theme; the *accent* is the one lively color and, in the `dynamic` theme, is /// extracted live from the current album art. The base colors are no longer /// compile-time constants — they resolve through [_active] so a user-selected /// theme (see [TimbrePalette]) recolors the whole app. `applyPalette` is called /// once per build by `TimbreApp` before the theme is built. class TimbreColors { const TimbreColors._(); static TimbrePalette _active = TimbrePalette.dark; /// Swap the active palette. Called by `TimbreApp.build` from the persisted /// theme setting; a re-keyed subtree remount then re-reads these getters. static void applyPalette(TimbrePalette p) => _active = p; /// Brightness of the active theme (drives `ThemeData`/`ColorScheme`). static Brightness get brightness => _active.brightness; /// App canvas. static Color get background => _active.background; /// Panel/surface fill (slightly offset from the canvas). static Color get surface => _active.surface; /// Primary text. static Color get foreground => _active.foreground; /// Secondary/muted text. static Color get dimmed => _active.dimmed; /// Hairline borders (inactive). static Color get border => _active.border; /// Hairline borders when a pane is focused. static Color get borderActive => _active.borderActive; /// Default accent when no art-derived accent applies. static Color get accentDefault => _active.accentDefault; } /// Spacing scale — dense, "player as instrument" rather than airy mobile cards. class TimbreSpacing { const TimbreSpacing._(); static const double xs = 2; static const double sm = 4; static const double md = 8; static const double lg = 12; static const double xl = 16; /// Minimum touch target per Apple/Material guidance — keep rows dense /// visually but pad hit areas to at least this. static const double minTouchTarget = 44; }