polish(ux): drop the checkmark on selected filter chips
The tick overlapped the leading icon on selected chips, reading as a confusing blob. The solid fill already signals 'on', so hide the checkmark. Also make the selected label reliably white via an explicit per-chip style: the global ChipTheme's secondaryLabelStyle was not applied to FilterChips, leaving dark text on green. Plain attribute/ market chips now share a PlainFilterChip widget; swatch and month chips just drop their tick.
This commit is contained in:
parent
89addb1ed7
commit
b1fd4c38b5
5 changed files with 68 additions and 59 deletions
|
|
@ -157,6 +157,7 @@ class _MonthStripState extends State<_MonthStrip> {
|
|||
final selected = m == widget.month;
|
||||
return ChoiceChip(
|
||||
key: Key('calendar.month.$m'),
|
||||
showCheckmark: false,
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
label: Text(
|
||||
_capitalise(fmt.format(DateTime(2000, m))),
|
||||
|
|
|
|||
45
apps/app_seeds/lib/ui/filter_chips.dart
Normal file
45
apps/app_seeds/lib/ui/filter_chips.dart
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'theme.dart';
|
||||
|
||||
/// A filter chip for the horizontal filter rows: light with dark ink when idle,
|
||||
/// a solid green fill with white content when selected — no checkmark, since the
|
||||
/// fill already reads as "on" and a tick over the leading icon just muddles it.
|
||||
/// White on [seedGreen] meets WCAG AA (see test/ui/theme_contrast_test.dart).
|
||||
class PlainFilterChip extends StatelessWidget {
|
||||
const PlainFilterChip({
|
||||
required this.label,
|
||||
required this.selected,
|
||||
required this.onSelected,
|
||||
this.icon,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String label;
|
||||
final bool selected;
|
||||
final ValueChanged<bool> onSelected;
|
||||
|
||||
/// Optional leading icon (attribute chips carry one; type/category chips do
|
||||
/// not).
|
||||
final IconData? icon;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final fg = selected ? Colors.white : seedOnSurface;
|
||||
return FilterChip(
|
||||
avatar: icon == null
|
||||
? null
|
||||
: Icon(icon, size: 18, color: selected ? Colors.white : seedGreen),
|
||||
label: Text(label),
|
||||
selected: selected,
|
||||
onSelected: onSelected,
|
||||
showCheckmark: false,
|
||||
selectedColor: seedGreen,
|
||||
labelStyle: TextStyle(
|
||||
color: fg,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import '../state/inventory_cubit.dart';
|
|||
import 'category_palette.dart';
|
||||
import 'draft_triage.dart';
|
||||
import 'edge_fade.dart';
|
||||
import 'filter_chips.dart';
|
||||
import 'label_print_sheet.dart';
|
||||
import 'quantity_kind_l10n.dart';
|
||||
import 'quantity_picker.dart';
|
||||
|
|
@ -303,50 +304,34 @@ class _FilterBar extends StatelessWidget {
|
|||
// stable earthy tonality). Grouping + colour makes a long row scannable.
|
||||
final attrChips = <Widget>[
|
||||
if (hasSowCalendar)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: const Key('inventory.filter.sowThisMonth'),
|
||||
avatar: Icon(
|
||||
Icons.calendar_month,
|
||||
size: 18,
|
||||
color: state.sowThisMonthOnly ? Colors.white : seedGreen,
|
||||
),
|
||||
label: Text(t.calendar.filterChip),
|
||||
icon: Icons.calendar_month,
|
||||
label: t.calendar.filterChip,
|
||||
selected: state.sowThisMonthOnly,
|
||||
onSelected: (_) => cubit.toggleSowThisMonth(),
|
||||
),
|
||||
if (hasShared)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: const Key('inventory.filter.sharing'),
|
||||
avatar: Icon(
|
||||
Icons.volunteer_activism_outlined,
|
||||
size: 18,
|
||||
color: state.sharingOnly ? Colors.white : seedGreen,
|
||||
),
|
||||
label: Text(t.share.filterChip),
|
||||
icon: Icons.volunteer_activism_outlined,
|
||||
label: t.share.filterChip,
|
||||
selected: state.sharingOnly,
|
||||
onSelected: (_) => cubit.toggleSharingOnly(),
|
||||
),
|
||||
if (hasOrganic)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: const Key('inventory.filter.organic'),
|
||||
avatar: Icon(
|
||||
Icons.eco,
|
||||
size: 18,
|
||||
color: state.organicOnly ? Colors.white : seedGreen,
|
||||
),
|
||||
label: Text(t.editVariety.organic),
|
||||
icon: Icons.eco,
|
||||
label: t.editVariety.organic,
|
||||
selected: state.organicOnly,
|
||||
onSelected: (_) => cubit.toggleOrganicOnly(),
|
||||
),
|
||||
if (hasNeedsReproduction)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: const Key('inventory.filter.needsReproduction'),
|
||||
avatar: Icon(
|
||||
Icons.autorenew,
|
||||
size: 18,
|
||||
color: state.needsReproductionOnly ? Colors.white : seedGreen,
|
||||
),
|
||||
label: Text(t.inventory.needsReproductionFilter),
|
||||
icon: Icons.autorenew,
|
||||
label: t.inventory.needsReproductionFilter,
|
||||
selected: state.needsReproductionOnly,
|
||||
onSelected: (_) => cubit.toggleNeedsReproductionOnly(),
|
||||
),
|
||||
|
|
@ -456,9 +441,9 @@ class _SwatchFilterChip extends StatelessWidget {
|
|||
avatar: icon == null ? null : Icon(icon, size: 18, color: ink),
|
||||
selected: selected,
|
||||
onSelected: (_) => onSelected(),
|
||||
showCheckmark: false,
|
||||
backgroundColor: swatch.fill,
|
||||
selectedColor: swatch.ink,
|
||||
checkmarkColor: Colors.white,
|
||||
side: BorderSide(
|
||||
color: swatch.ink.withValues(alpha: selected ? 0 : 0.35),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import '../services/social_service.dart';
|
|||
import '../services/social_settings.dart';
|
||||
import '../state/offers_cubit.dart';
|
||||
import 'edge_fade.dart';
|
||||
import 'filter_chips.dart';
|
||||
import 'market_widgets.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
|
|
@ -488,28 +489,24 @@ class _MarketFilterBar extends StatelessWidget {
|
|||
|
||||
final chips = <Widget>[
|
||||
if (hasOrganic)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: const Key('market.filter.organic'),
|
||||
avatar: Icon(
|
||||
Icons.eco,
|
||||
size: 18,
|
||||
color: state.organicOnly ? Colors.white : seedGreen,
|
||||
),
|
||||
label: Text(t.editVariety.organic),
|
||||
icon: Icons.eco,
|
||||
label: t.editVariety.organic,
|
||||
selected: state.organicOnly,
|
||||
onSelected: (_) => cubit.toggleOrganicOnly(),
|
||||
),
|
||||
for (final type in types)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: Key('market.filter.type.${type.name}'),
|
||||
label: Text(offerTypeLabel(t, type)),
|
||||
label: offerTypeLabel(t, type),
|
||||
selected: state.typeFilter.contains(type),
|
||||
onSelected: (_) => cubit.toggleType(type),
|
||||
),
|
||||
for (final category in categories)
|
||||
FilterChip(
|
||||
PlainFilterChip(
|
||||
key: Key('market.filter.category.$category'),
|
||||
label: Text(category),
|
||||
label: category,
|
||||
selected: state.categoryFilter.contains(category),
|
||||
onSelected: (_) => cubit.toggleCategory(category),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -105,24 +105,5 @@ ThemeData buildTaneTheme() {
|
|||
thickness: 1,
|
||||
color: seedDivider,
|
||||
),
|
||||
// Filter/choice chips: idle chips stay light with dark ink, but a *selected*
|
||||
// chip fills solid green with white ink so "on" reads unmistakably against
|
||||
// the pale canvas (the soft tonal default sat too close to it). White on
|
||||
// seedGreen meets WCAG AA — see test/ui/theme_contrast_test.dart. Chips that
|
||||
// carry their own hue (family/form swatches) override this per-swatch.
|
||||
chipTheme: const ChipThemeData(
|
||||
selectedColor: seedGreen,
|
||||
checkmarkColor: Colors.white,
|
||||
labelStyle: TextStyle(
|
||||
color: seedOnSurface,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
secondaryLabelStyle: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue