Make the custom accent-color picker actually retint the app

NooColors (the color source for nearly the whole redesigned UI) only
had two states: the fixed violet palette, or a Material You dynamic
scheme when "Match wallpaper" was on. The 5-swatch custom accent
picker still wrote to SettingsController.seedColor, but nothing read
it back into NooColors - it only reached the underlying Material
ColorScheme, which the Noo-styled UI doesn't use, so every custom
swatch looked identically purple.

Add NooColors.fromSeed, which retints just the accent/accentText/
accentSoft roles from a chosen seed color via ColorScheme.fromSeed
(bg/surface/fg etc. stay the fixed warm-neutral palette, unlike
dynamic color which reshapes everything to match the wallpaper), and
wire it into AppTheme.light/dark. Add a "Default" (Noo violet) swatch
to the picker, and move SettingsController's initial seed color to
that same violet so a fresh install - or any device without dynamic
color - keeps today's look instead of picking up the leftover
Nextcloud-blue default from before seed colors did anything visible.
This commit is contained in:
2026-09-28 13:11:11 -04:00
parent c9889c69b8
commit 72472c771a
6 changed files with 149 additions and 34 deletions
+37 -11
View File
@@ -7,13 +7,13 @@ import 'package:google_fonts/google_fonts.dart';
/// `Theme.of(context).extension<NooColors>()!` (or a `context.nooColors`
/// getter, once one exists) instead of the Material [ColorScheme] roles.
///
/// Two independent sources feed this, matching the app's color settings:
/// the fixed [light]/[dark] palettes below (the design system's own
/// default look), or [NooColors.fromDynamicScheme] when the user has
/// Material You dynamic color turned on - there's no third option (no
/// custom accent picker), since the design system explicitly rules out
/// "add new colors". [withAmoled] layers on top of either source when the
/// user's AMOLED toggle is on.
/// Three sources feed this, matching the app's color settings: the fixed
/// [light]/[dark] palettes below (the design system's own default look,
/// also what the accent picker's "Default" violet swatch selects),
/// [NooColors.fromDynamicScheme] when the user has Material You dynamic
/// color turned on, or [NooColors.fromSeed] for a custom accent-picker
/// swatch. [withAmoled] layers on top of any of the three when the user's
/// AMOLED toggle is on.
@immutable
class NooColors extends ThemeExtension<NooColors> {
final Color bg;
@@ -161,6 +161,34 @@ class NooColors extends ThemeExtension<NooColors> {
);
}
/// Derives an accent-only variant of the fixed [light]/[dark] palette for
/// a user-chosen custom seed color (Settings' accent-color picker) -
/// unlike [fromDynamicScheme], only the accent roles change; bg/surface/
/// fg etc. stay the Noo warm-neutral palette, since picking a named
/// accent ("Ocean Teal") is meant to retint the brand color, not reshape
/// the whole surface to match a wallpaper the way dynamic color does.
/// [seedColor] equal to the fixed palette's own accent (the picker's
/// "Default" violet swatch) returns the untouched fixed palette, so the
/// out-of-box look stays pixel-identical rather than going through
/// [ColorScheme.fromSeed]'s tonal-palette math for no reason.
factory NooColors.fromSeed(Color seedColor, Brightness brightness) {
final fixed = brightness == Brightness.dark ? dark : light;
if (seedColor == light.accent) return fixed;
final cs = ColorScheme.fromSeed(
seedColor: seedColor,
brightness: brightness,
);
return fixed.copyWith(
accent: seedColor,
// Light accentText matches accent exactly, same as the fixed
// palette - dark needs a lighter, desaturated tint for contrast
// against a dark surface, which is exactly what Material's tonal
// primary (tone ~80 in dark mode) is designed to give.
accentText: brightness == Brightness.dark ? cs.primary : seedColor,
accentSoft: cs.primaryContainer,
);
}
/// True OLED black across every surface tone - not just [bg] - so cards,
/// bars and sheets all go black too instead of the dark palette's warm
/// dark-grey tones. Mirrors the AMOLED handling this replaces in
@@ -391,10 +419,8 @@ class NooText {
fontWeight: FontWeight.w400,
);
static TextStyle get label => GoogleFonts.instrumentSans(
fontSize: 13,
fontWeight: FontWeight.w600,
);
static TextStyle get label =>
GoogleFonts.instrumentSans(fontSize: 13, fontWeight: FontWeight.w600);
static TextStyle get meta => GoogleFonts.instrumentSans(
fontSize: 13,