polish(ux): AA-contrast chip inks, 14-tone palette, calendar month auto-scroll

Blind-build polish pass over the recent sales/chips/calendar work:

- Chip label contrast: 7 palette inks (terracotta, ochre, rose, seedling,
  plant, bulb, cutting) sat below WCAG AA on their own fill; darkened
  (hue preserved) to ≥4.8:1. New category_palette_contrast_test locks it.
- Palette expanded 8 → 14 earthy tones (hues spread around the wheel) so
  family colours rarely collide for a typical 6–10 family inventory,
  keeping the stable-by-name, cross-screen-consistent scheme. Every new
  ink meets AA on its fill.
- Calendar month strip now actually scrolls the selected month into view
  (the comment promised it but it was never wired) — late-year months are
  no longer left off-screen when the screen opens.
- Minor: dead code removed from the month chip.

dart analyze clean; palette/contrast/calendar/quantity/overflow/inventory
suites green.
This commit is contained in:
vjrj 2026-07-11 06:48:19 +02:00
parent a476f17cdf
commit 62ed4f79b3
3 changed files with 97 additions and 16 deletions

View file

@ -102,13 +102,43 @@ class _CalendarScreenState extends State<CalendarScreen> {
}
/// A horizontally scrolling strip of the twelve months; the picked one is
/// filled. Scrolls the picked month into view on first build.
class _MonthStrip extends StatelessWidget {
/// filled. Scrolls the picked month into view (so late-year months aren't left
/// off-screen when the screen opens in, say, November).
class _MonthStrip extends StatefulWidget {
const _MonthStrip({required this.month, required this.onSelect});
final int month;
final ValueChanged<int> onSelect;
@override
State<_MonthStrip> createState() => _MonthStripState();
}
class _MonthStripState extends State<_MonthStrip> {
final _selectedKey = GlobalKey();
@override
void initState() {
super.initState();
_revealSelected();
}
@override
void didUpdateWidget(_MonthStrip old) {
super.didUpdateWidget(old);
if (old.month != widget.month) _revealSelected();
}
void _revealSelected() {
WidgetsBinding.instance.addPostFrameCallback((_) {
final ctx = _selectedKey.currentContext;
if (ctx != null) {
Scrollable.ensureVisible(ctx,
alignment: 0.5, duration: const Duration(milliseconds: 250));
}
});
}
@override
Widget build(BuildContext context) {
final locale = materialLocaleFor(Localizations.localeOf(context));
@ -122,12 +152,16 @@ class _MonthStrip extends StatelessWidget {
separatorBuilder: (_, _) => const SizedBox(width: 8),
itemBuilder: (context, i) {
final m = i + 1;
final selected = m == month;
final selected = m == widget.month;
return ChoiceChip(
key: Key('calendar.month.$m'),
label: Text(_capitalise(fmt.format(DateTime(2000, m)))),
labelPadding: const EdgeInsets.symmetric(horizontal: 6),
label: Text(
_capitalise(fmt.format(DateTime(2000, m))),
key: selected ? _selectedKey : null,
),
selected: selected,
onSelected: (_) => onSelect(m),
onSelected: (_) => widget.onSelect(m),
selectedColor: seedPrimaryContainer,
labelStyle: TextStyle(
color: selected ? seedOnPrimaryContainer : seedMuted,