feat(theme): optional per-feature color accents#693
Conversation
The desktop master-detail pane renders _AppearanceSectionContent, a separate widget from AppearancePage, so the toggles were phone-only. Same duplication hid header accents behind the eight list-content compact app bars, which render their own styled title instead of an AppBar; FeatureAppBarTitle now takes an optional style so those can adopt it without changing their typography.
There was a problem hiding this comment.
Pull request overview
Adds an opt-in “feature accent colors” system that tints icons across navigation, page headers, and selected list/settings surfaces, controlled by three per-diver toggles persisted in Drift (v135) and synced across devices.
Changes:
- Introduces
FeatureAccentColorsThemeExtension(light/dark palettes) and registers it across all theme presets, with contrast/completeness tests. - Adds three diver settings toggles (
accentNavIcons,accentSectionHeaders,accentListIcons) with schema v135 migration + sync-default hydration for legacy payloads. - Applies accent-driven icon tinting to navigation (bar/rail/overflow), feature page AppBar titles, and selected list/settings leading icons; refactors rail destinations to iterate
kNavDestinationswith a regression test for ordering.
Reviewed changes
Copilot reviewed 72 out of 72 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/shared/widgets/nav/rail_destination_order_test.dart | Locks canonical rail destination ordering/route mapping after rail refactor. |
| test/shared/widgets/main_scaffold_test.dart | Extends scaffold tests to cover nav accent behavior. |
| test/shared/widgets/feature_accent_test.dart | Widget tests for FeatureAccentIcon / FeatureAppBarTitle behavior and fallbacks. |
| test/helpers/mock_providers.dart | Adds accent-toggle setters to MockSettingsNotifier. |
| test/features/statistics/presentation/pages/records_page_test.dart | Updates mock SettingsNotifier to implement new accent setters. |
| test/features/settings/presentation/providers/settings_notifier_real_test.dart | Adds real-notifier tests for accent toggle independence/providers. |
| test/features/settings/presentation/pages/settings_page_test.dart | Adds tests for settings section palette resolution + appearance hub accent toggles. |
| test/features/settings/presentation/pages/settings_page_shared_data_test.dart | Updates mock SettingsNotifier to implement new accent setters. |
| test/features/settings/presentation/pages/appearance_page_test.dart | Adds tests asserting the three accent toggles appear and behave independently. |
| test/features/settings/data/repositories/diver_settings_repository_accents_test.dart | DB-backed persistence tests for the three new accent columns. |
| test/features/equipment/presentation/widgets/equipment_tile_service_badge_test.dart | Stubs settings provider for tiles that now read accent toggles. |
| test/features/equipment/presentation/widgets/equipment_tile_accent_test.dart | Tests list-icon accents and ensures overdue-service colors win over accents. |
| test/features/equipment/presentation/widgets/equipment_list_content_test.dart | Stubs settings provider for equipment list content tests (accent reads). |
| test/core/theme/theme_preset_accents_test.dart | Verifies all theme presets register FeatureAccentColors in both modes. |
| test/core/theme/feature_accent_colors_test.dart | Validates palette completeness, lerp/copyWith, and WCAG-ish contrast guards. |
| test/core/services/sync/sync_diver_settings_fallback_test.dart | Ensures pre-v135 sync payloads hydrate new non-nullable accent fields safely. |
| test/core/database/migration_v135_accent_columns_test.dart | Migration coverage for v135 accent toggle columns + schema tripwire. |
| test/core/database/media_compressed_columns_migration_test.dart | Relaxes previous “latest schema” tripwire now that v135 exists. |
| lib/shared/widgets/main_scaffold.dart | Refactors rail to iterate kNavDestinations and applies nav icon accents (bar/rail/overflow). |
| lib/shared/widgets/feature_accent.dart | Adds shared accent resolution helper + FeatureAccentIcon/FeatureAppBarTitle. |
| lib/features/trips/presentation/widgets/trip_list_content.dart | Applies header accents and list-avatar accent tinting for trips. |
| lib/features/transfer/presentation/pages/transfer_page.dart | Applies header accents to Transfer page AppBar. |
| lib/features/statistics/presentation/pages/statistics_page.dart | Applies header accents to Statistics page AppBar. |
| lib/features/settings/presentation/widgets/settings_list_content.dart | Moves settings section colors to palette lookup (removes per-section hardcoded colors). |
| lib/features/settings/presentation/providers/settings_providers.dart | Adds accent fields to AppSettings, setters on SettingsNotifier, and narrow gate providers. |
| lib/features/settings/presentation/pages/settings_page.dart | Adds desktop appearance-pane toggles + uses accent icons; settings tile colors now resolve from palette. |
| lib/features/settings/presentation/pages/appearance_page.dart | Adds “Color accents” toggle group and tints appearance-page leading icons via FeatureAccentIcon. |
| lib/features/settings/data/repositories/diver_settings_repository.dart | Maps new accent fields to/from Drift diver_settings rows. |
| lib/features/planning/presentation/pages/planning_page.dart | Applies header accents to Planning page AppBar. |
| lib/features/gps_log/presentation/pages/gps_logger_page.dart | Applies header accents to GPS Logger page AppBar. |
| lib/features/equipment/presentation/widgets/equipment_set_list_content.dart | Applies list-icon accents to equipment set avatar. |
| lib/features/equipment/presentation/widgets/equipment_list_content.dart | Applies header accents + list avatar accents; preserves overdue error colors. |
| lib/features/equipment/presentation/pages/equipment_list_page.dart | Applies header accents to equipment list page AppBar. |
| lib/features/dive_sites/presentation/widgets/site_list_content.dart | Applies header accents to sites list AppBars (regular + compact). |
| lib/features/dive_log/presentation/widgets/dive_list_content.dart | Applies header accents to dive list AppBars (regular + compact). |
| lib/features/dive_centers/presentation/widgets/dive_center_list_content.dart | Applies header accents + list-icon accents to dive center search/list leading icon container. |
| lib/features/courses/presentation/widgets/course_list_content.dart | Applies header accents to courses list AppBars (regular + compact). |
| lib/features/certifications/presentation/widgets/certification_list_content.dart | Applies header accents to certifications list AppBars (regular + compact). |
| lib/features/buddies/presentation/widgets/buddy_list_content.dart | Applies header accents to buddies list AppBars (regular + compact). |
| lib/core/theme/full_themes/tropical_theme.dart | Registers FeatureAccentColors extension on tropical themes. |
| lib/core/theme/full_themes/submersion_theme.dart | Registers FeatureAccentColors extension on default themes. |
| lib/core/theme/full_themes/minimalist_theme.dart | Registers FeatureAccentColors extension on minimalist themes. |
| lib/core/theme/full_themes/deep_theme.dart | Registers FeatureAccentColors extension on deep themes. |
| lib/core/theme/full_themes/console_theme.dart | Registers FeatureAccentColors extension on console themes. |
| lib/core/theme/feature_accent_colors.dart | Implements curated accent palettes as a ThemeExtension with lerp/copyWith. |
| lib/core/services/sync/sync_data_serializer.dart | Seeds sync defaults for new accent fields to handle legacy payloads. |
| lib/core/database/database.dart | Adds v135 accent columns + idempotent migration/backstop and bumps schema version. |
| lib/l10n/arb/app_zh.arb | Adds 7 new localized strings for color accents (ZH). |
| lib/l10n/arb/app_pt.arb | Adds 7 new localized strings for color accents (PT). |
| lib/l10n/arb/app_nl.arb | Adds 7 new localized strings for color accents (NL). |
| lib/l10n/arb/app_localizations.dart | Adds generated getters for accent toggle strings. |
| lib/l10n/arb/app_localizations_zh.dart | Adds generated ZH implementations for new strings. |
| lib/l10n/arb/app_localizations_pt.dart | Adds generated PT implementations for new strings. |
| lib/l10n/arb/app_localizations_nl.dart | Adds generated NL implementations for new strings. |
| lib/l10n/arb/app_localizations_it.dart | Adds generated IT implementations for new strings. |
| lib/l10n/arb/app_localizations_hu.dart | Adds generated HU implementations for new strings. |
| lib/l10n/arb/app_localizations_he.dart | Adds generated HE implementations for new strings. |
| lib/l10n/arb/app_localizations_fr.dart | Adds generated FR implementations for new strings. |
| lib/l10n/arb/app_localizations_es.dart | Adds generated ES implementations for new strings. |
| lib/l10n/arb/app_localizations_en.dart | Adds generated EN implementations for new strings. |
| lib/l10n/arb/app_localizations_de.dart | Adds generated DE implementations for new strings. |
| lib/l10n/arb/app_localizations_ar.dart | Adds generated AR implementations for new strings. |
| lib/l10n/arb/app_it.arb | Adds 7 new localized strings for color accents (IT). |
| lib/l10n/arb/app_hu.arb | Adds 7 new localized strings for color accents (HU). |
| lib/l10n/arb/app_he.arb | Adds 7 new localized strings for color accents (HE). |
| lib/l10n/arb/app_fr.arb | Adds 7 new localized strings for color accents (FR). |
| lib/l10n/arb/app_es.arb | Adds 7 new localized strings for color accents (ES). |
| lib/l10n/arb/app_en.arb | Adds 7 new English strings for color accents. |
| lib/l10n/arb/app_de.arb | Adds 7 new localized strings for color accents (DE). |
| lib/l10n/arb/app_ar.arb | Adds 7 new localized strings for color accents (AR). |
| docs/superpowers/specs/2026-07-23-color-accents-design.md | Adds design spec for the feature accent system. |
| docs/superpowers/plans/2026-07-23-color-accents.md | Adds detailed implementation plan and task breakdown. |
Comments suppressed due to low confidence (1)
test/features/settings/presentation/pages/settings_page_test.dart:830
- The wide-screen Appearance hub tests below assert English labels ('Color accents', 'Dives', etc.), but buildAppearanceWidget's MaterialApp.router doesn't pin locale, so these can fail under a non-English platform locale. Repo convention is to pin locale: const Locale('en') for deterministic string finders (test/helpers/test_app.dart:17-19).
| child: MaterialApp.router( | ||
| routerConfig: router, | ||
| theme: theme, | ||
| localizationsDelegates: AppLocalizations.localizationsDelegates, | ||
| supportedLocales: AppLocalizations.supportedLocales, |
| child: ProviderScope( | ||
| overrides: getOverrides(), | ||
| child: MaterialApp( | ||
| locale: locale, | ||
| theme: theme, |
| group('AppearancePage color accents', () { | ||
| testWidgets('shows the three accent toggles, all off by default', ( | ||
| tester, | ||
| ) async { | ||
| await tester.binding.setSurfaceSize(const Size(400, 2000)); | ||
| addTearDown(() => tester.binding.setSurfaceSize(null)); | ||
|
|
|
📦 Build artifacts for this PR · commit
Artifacts expire in 7 days. Downloading requires being signed in to GitHub. The macOS build is ad-hoc signed — right-click → Open on first launch. Updated automatically on each push. |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Summary
Adds an optional per-feature-area color accent system. Each feature area gets a
curated identity color that can tint main-menu icons, page-header icons, and
list/settings icons. Three independent toggles live in Settings > Appearance and
all default off, so the app looks exactly as it does today until a toggle is
switched on.
Design spec and implementation plan are committed under
docs/superpowers/(2026-07-23-color-accents-*).Changes
Palette
FeatureAccentColorsThemeExtension (lib/core/theme/feature_accent_colors.dart)holding curated light and dark maps keyed by the stable
NavDestination.idstrings, plus
settings-<sectionId>entries. Registered on all five themepresets, so accents resolve per brightness and lerp smoothly across theme
changes.
mode degrades to the app's current appearance rather than throwing.
accent clears the 3:1 WCAG ratio for graphical objects in light mode; a test
enforces this for any accent added later.
Settings, persistence, sync
accentNavIcons/accentSectionHeaders/accentListIcons, schema v135 ondiver_settings(idempotent_assertAccentColorSettingsColumnscalled from bothonUpgradeand thebeforeOpenbackstop)._exportDiverSettingsserializes whole rows via the generatedtoJson().AppearancePageandthe desktop master-detail
_AppearanceSectionContent.Surfaces
sentinel is never tinted (it has no palette entry by design).
the feature's icon, accent-tinted, beside the title. Applied to both the
standard
AppBarand the compact app bars used in master-detail layouts.dive centers. Tiles with no leading icon today are untouched — the toggle
never adds icons to list rows.
Colors.*. Thoseexact values moved into the shared palette under
settings-*keys, so thereis now one source of truth. The root stays always-colored and visually
unchanged.
Refactor (behavior-preserving)
main_scaffold.dart'sNavigationRailhardcoded all 14 destinations plus twoindex/route switch statements. It now iterates the shared
kNavDestinationslist like the mobile bar already did (-129 lines, +19). A new
rail_destination_order_test.dartlocks the previous index-to-route contractso the refactor cannot silently reorder navigation.
Test Plan
flutter testpasses — 13,719 passed, 14 skipped, 0 failedflutter analyzepasses — no issuesdart format .— 0 files changedNew coverage includes palette completeness and contrast guards, theme-preset
registration, the v135 migration on both the upgrade and fresh-database paths,
sync hydration of pre-v135 payloads, per-column persistence independence, the
FeatureAccentIconon/off/unknown-id/dark-mode matrix, nav accents on bar, railand overflow sheet, and a test asserting that an overdue equipment service
keeps its error color even with accents on — a cosmetic preference must not be
able to hide a maintenance warning.
Note: four inherited settings-row colors (Data, Notifications, Shared data,
Debug) sit below 3:1 contrast in light mode. They reproduce what the settings
screen renders today and were deliberately left unchanged; raising them is worth
doing as its own change.