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.
125 lines
4.1 KiB
Dart
125 lines
4.1 KiB
Dart
import 'package:tane/ui/edge_fade.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
// A horizontal strip of [count] fixed-width boxes inside an EdgeFade-wrapped
|
|
// SingleChildScrollView, laid out at the default 800px test surface width.
|
|
Widget harness({
|
|
required int count,
|
|
TextDirection direction = TextDirection.ltr,
|
|
ScrollController? controller,
|
|
}) {
|
|
return Directionality(
|
|
textDirection: direction,
|
|
child: EdgeFade(
|
|
child: SingleChildScrollView(
|
|
controller: controller,
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
children: [
|
|
for (var i = 0; i < count; i++)
|
|
const SizedBox(width: 100, height: 40),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
EdgeFadeState state(WidgetTester tester) =>
|
|
tester.state<EdgeFadeState>(find.byType(EdgeFade));
|
|
|
|
testWidgets('no fade on either edge when content fits', (tester) async {
|
|
await tester.pumpWidget(harness(count: 3)); // 300px < 800px
|
|
await tester.pump(); // let the post-layout metrics notification land
|
|
expect(state(tester).fadeLeft, isFalse);
|
|
expect(state(tester).fadeRight, isFalse);
|
|
});
|
|
|
|
testWidgets('LTR: at start only the trailing (right) edge fades',
|
|
(tester) async {
|
|
await tester.pumpWidget(harness(count: 20)); // 2000px > 800px
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isFalse);
|
|
expect(state(tester).fadeRight, isTrue);
|
|
});
|
|
|
|
testWidgets('LTR: in the middle both edges fade', (tester) async {
|
|
final controller = ScrollController();
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(harness(count: 20, controller: controller));
|
|
await tester.pump();
|
|
controller.jumpTo(600);
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isTrue);
|
|
expect(state(tester).fadeRight, isTrue);
|
|
});
|
|
|
|
testWidgets('LTR: at the end only the leading (left) edge fades',
|
|
(tester) async {
|
|
final controller = ScrollController();
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(harness(count: 20, controller: controller));
|
|
await tester.pump();
|
|
controller.jumpTo(controller.position.maxScrollExtent);
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isTrue);
|
|
expect(state(tester).fadeRight, isFalse);
|
|
});
|
|
|
|
testWidgets('RTL: at start only the LEFT edge fades (mirrored)',
|
|
(tester) async {
|
|
await tester
|
|
.pumpWidget(harness(count: 20, direction: TextDirection.rtl));
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isTrue);
|
|
expect(state(tester).fadeRight, isFalse);
|
|
});
|
|
|
|
testWidgets('RTL: at the end only the RIGHT edge fades (mirrored)',
|
|
(tester) async {
|
|
final controller = ScrollController();
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(harness(
|
|
count: 20,
|
|
direction: TextDirection.rtl,
|
|
controller: controller,
|
|
));
|
|
await tester.pump();
|
|
controller.jumpTo(controller.position.maxScrollExtent);
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isFalse);
|
|
expect(state(tester).fadeRight, isTrue);
|
|
});
|
|
|
|
testWidgets('RTL: no fade when content fits', (tester) async {
|
|
await tester.pumpWidget(harness(count: 3, direction: TextDirection.rtl));
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isFalse);
|
|
expect(state(tester).fadeRight, isFalse);
|
|
});
|
|
|
|
testWidgets('fades clear when content shrinks to fit', (tester) async {
|
|
await tester.pumpWidget(harness(count: 20));
|
|
await tester.pump();
|
|
expect(state(tester).fadeRight, isTrue);
|
|
|
|
await tester.pumpWidget(harness(count: 3));
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isFalse);
|
|
expect(state(tester).fadeRight, isFalse);
|
|
});
|
|
|
|
testWidgets('scrolling by drag updates the fades', (tester) async {
|
|
await tester.pumpWidget(harness(count: 20));
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isFalse);
|
|
|
|
await tester.drag(
|
|
find.byType(SingleChildScrollView), const Offset(-300, 0));
|
|
await tester.pump();
|
|
expect(state(tester).fadeLeft, isTrue);
|
|
expect(state(tester).fadeRight, isTrue);
|
|
});
|
|
}
|