feat(ux): edge fades hint that filter rows scroll horizontally
Chips clipped at the viewport edge with no cue that more filters exist. New reusable EdgeFade widget (ShaderMask + dstIn) fades an edge only while content remains beyond it, driven by scroll metrics; RTL mirrors via Directionality. Applied to the inventory filter bar, market filter bar and calendar month strip.
This commit is contained in:
parent
1ab243f29e
commit
bfff95fe8d
5 changed files with 262 additions and 46 deletions
|
|
@ -8,6 +8,7 @@ import '../data/variety_repository.dart';
|
|||
import '../domain/crop_calendar.dart';
|
||||
import '../i18n/strings.g.dart';
|
||||
import 'category_palette.dart';
|
||||
import 'edge_fade.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
/// One crop-calendar phase as shown on the "this month" screen: its label,
|
||||
|
|
@ -145,30 +146,32 @@ class _MonthStripState extends State<_MonthStrip> {
|
|||
final fmt = DateFormat.MMM(locale.toLanguageTag());
|
||||
return SizedBox(
|
||||
height: 56,
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
itemCount: 12,
|
||||
separatorBuilder: (_, _) => const SizedBox(width: 8),
|
||||
itemBuilder: (context, i) {
|
||||
final m = i + 1;
|
||||
final selected = m == widget.month;
|
||||
return ChoiceChip(
|
||||
key: Key('calendar.month.$m'),
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
label: Text(
|
||||
_capitalise(fmt.format(DateTime(2000, m))),
|
||||
key: selected ? _selectedKey : null,
|
||||
),
|
||||
selected: selected,
|
||||
onSelected: (_) => widget.onSelect(m),
|
||||
selectedColor: seedPrimaryContainer,
|
||||
labelStyle: TextStyle(
|
||||
color: selected ? seedOnPrimaryContainer : seedMuted,
|
||||
fontWeight: selected ? FontWeight.w600 : FontWeight.w400,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: EdgeFade(
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
itemCount: 12,
|
||||
separatorBuilder: (_, _) => const SizedBox(width: 8),
|
||||
itemBuilder: (context, i) {
|
||||
final m = i + 1;
|
||||
final selected = m == widget.month;
|
||||
return ChoiceChip(
|
||||
key: Key('calendar.month.$m'),
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
label: Text(
|
||||
_capitalise(fmt.format(DateTime(2000, m))),
|
||||
key: selected ? _selectedKey : null,
|
||||
),
|
||||
selected: selected,
|
||||
onSelected: (_) => widget.onSelect(m),
|
||||
selectedColor: seedPrimaryContainer,
|
||||
labelStyle: TextStyle(
|
||||
color: selected ? seedOnPrimaryContainer : seedMuted,
|
||||
fontWeight: selected ? FontWeight.w600 : FontWeight.w400,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue