cb138a3248
Implements the visual theme system specified in mock up software.pdf.
Flutter project — display/:
- pubspec.yaml: ar_autopilot_display v0.4.0+4 (provider + shared_preferences)
- lib/theme/autopilot_theme.dart: AutopilotTheme class with 30+ design tokens
(backgrounds, panels, text, accent, set-point, semantic states, DISENGAGE,
action buttons, glow helpers, backgroundDecoration getter)
- lib/theme/theme_registry.dart: ThemeRegistry with 4 factory themes,
byId() fallback, architecture stub for Sprint 9 custom YAML themes
- lib/theme/theme_provider.dart: AutopilotThemeProvider (ChangeNotifier),
SharedPreferences persistence under 'autopilot.theme.id', NOT sent to ESP32
- lib/theme/themes/: 4 factory themes with exact hex values from spec:
light (cream/navy, accentGlowRadius=0 — daytime no-glow rule)
cyan (deep navy/neon-cyan, default, glowRadius=16)
wine (vinotinto, DISENGAGE=amber not red, glowRadius=18)
ochre (warm brown/gold, okColor=lime for contrast, glowRadius=18)
- lib/screens/settings/appearance_settings.dart: Appearance screen with
4-card theme previews (200x120px), 400ms AnimatedContainer transitions,
triple-tap shortcut note, Sprint-5 placeholders for auto day/night and
ambient light sensor toggles
- lib/widgets/themed/: 4 themed widgets consuming AutopilotThemeProvider:
compass_rose.dart (heading arc, N mark, set-point tick, glow ring)
disengage_button.dart (60x60 min touch target, gradient, glow)
mode_selector.dart (STANDBY/HDG HOLD/TRACK with accent highlight)
rudder_indicator.dart (horizontal bar -35° to +35°, accent knob)
- lib/main.dart: app entry point with ChangeNotifierProvider
Tests — display/test/theme/:
- theme_registry_test.dart: 4 themes load, correct IDs, display order,
no null tokens, glow rules, backgroundGradient rules
- theme_provider_test.dart: default load=cyan, persistence across restarts,
setTheme notifies listeners, unknown ID falls back to default
- theme_contrast_test.dart: WCAG checks — DISENGAGE ≥7:1 AAA,
action buttons ≥4.5:1 AA, textMain ≥4.5:1 AA, setLight/okColor ≥3:1
Also:
- .gitignore: added !display/lib/ exception (lib/ was excluded for Python venv)
Design rules enforced:
- No glow in light mode (accentGlowRadius=0)
- DISENGAGE = amber in wine theme (red would blend into palette)
- North mark = warm colour on all themes (nautical convention)
- Touch targets: 48px nominal, 60px critical
- Theme not sent to ESP32, not synced between displays
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
2.3 KiB
Dart
68 lines
2.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../autopilot_theme.dart';
|
|
|
|
/// **wine** — Vinotinto
|
|
///
|
|
/// Premium yacht / aesthetic preference palette. Deep crimson backgrounds
|
|
/// with rose accent. IMPORTANT: DISENGAGE switches from red to amber-gold
|
|
/// because red blends into the wine cockpit and loses its emergency signal.
|
|
/// The amber still carries the "caution/critical action" cognitive association.
|
|
const AutopilotTheme wineTheme = AutopilotTheme(
|
|
id: 'wine',
|
|
displayName: 'Vinotinto',
|
|
|
|
background: Color(0xFF2A0A14),
|
|
backgroundMid: Color(0xFF2A0A14),
|
|
backgroundDeep: Color(0xFF1A0610),
|
|
backgroundDeepest: Color(0xFF080205),
|
|
backgroundGradient: RadialGradient(
|
|
colors: [Color(0xFF2A0A14), Color(0xFF0F0408)],
|
|
stops: [0.0, 0.7],
|
|
),
|
|
|
|
panelBackground: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Color(0xE630121C), Color(0xE614080E)], // rgba(48,18,28,0.9) → rgba(20,8,14,0.9)
|
|
),
|
|
panelBorder: Color(0x4DBE1746), // rgba(190,23,70,0.3)
|
|
|
|
textMain: Color(0xFFFDE0E7),
|
|
textMuted: Color(0xFF8A5560),
|
|
textSoft: Color(0xFFF9A8B8),
|
|
textDisabled: Color(0xFF6A3848),
|
|
|
|
accentLight: Color(0xFFFB7185),
|
|
accentMid: Color(0xFFE11D48),
|
|
accentDark: Color(0xFF881337),
|
|
accentGlowRadius: 18.0,
|
|
accentGlowColor: Color(0xB3E11D48), // rgba(225,29,72,0.7)
|
|
|
|
setLight: Color(0xFFFBBF24),
|
|
setDark: Color(0xFFA16207),
|
|
setGlow: Color(0x66FBBF24),
|
|
|
|
okColor: Color(0xFFFBBF24), // gold not green — keeps warm palette
|
|
warnColor: Color(0xFFFBBF24),
|
|
northColor: Color(0xFFFDE047), // yellow not red — red is lost on wine background
|
|
|
|
// DISENGAGE: amber-gold instead of red — highest contrast on wine cockpit
|
|
disengageBackground: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Color(0xFFFBBF24), Color(0xFFB45309)],
|
|
),
|
|
disengageText: Color(0xFF1C0A02), // near-black — maximum contrast on amber
|
|
disengageBorder: Color(0xFFFDE047),
|
|
disengageGlow: Color(0x99FBBF24),
|
|
|
|
actionButtonBackground: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Color(0xFF7A1F3A), Color(0xFF3A0E1C)], // improved contrast
|
|
),
|
|
actionButtonBorder: Color(0xFFFB7185), // vivid rose border
|
|
actionButtonText: Color(0xFFFDE0E7),
|
|
actionButtonGlow: Color(0x66FB7185),
|
|
);
|