Miler rider app: surface system, visible design language, backend lifecycle
Design system - MilerSurface ladder (canvas → working → raised → floating) with MilerPanel as layer 1; canvas moved to #DEE3EA so white separates at 1.290:1. - Visible vocabulary applied across Home, Deliveries, Activity, Account and the sheets: hero heads (tabular numeral + small caption, clamped at 1.3x), canvas wells for anything that opens, small filled tags for shelf labels, demoted placeholders. Recorded in DESIGN_SYSTEM.md §6. - One icon family: 222 Material glyphs migrated to Lucide; none left outside lib/xpress. - Colour semantics corrected: amber only for what is genuinely owed, brand red reserved for the live stop, disabled primaries go neutral rather than pale. Data and lifecycle - lib/data/lifecycle.dart reads mutations for what they prove; route_order.dart makes admin sequence the single ordering authority; service_day.dart, and stop_area.dart rewritten against live Coimbatore addresses (digit-token stripping, city stoplist, street suffixes, stammer collapse). - countLabel states the load once, in bags. Testing - 1440 tests passing; golden shot harnesses for Home, Deliveries, Activity, sheets and verify, with test/failures/ now gitignored (diff debris). - New pins: home_gutter_test, stop_area_test, plus updated structural bounds. Note: this commit also carries pre-existing working-tree deletions that were present before this work (API_SPEC.md, README.md, demo test fixtures). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -62,7 +62,11 @@ void main() {
|
||||
child: Container(key: barKey, height: 96, color: Colors.white),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(key: contentKey, height: 2000, color: Colors.grey),
|
||||
child: Container(
|
||||
key: contentKey,
|
||||
height: 2000,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -80,8 +84,11 @@ void main() {
|
||||
// Not merely pushed off-screen — a sliver that leaves the viewport and its
|
||||
// cache extent is unmounted outright, so the duty toggle stopped existing
|
||||
// rather than just moving. This is the behaviour being fixed.
|
||||
expect(find.byKey(barKey), findsNothing,
|
||||
reason: 'this is the behaviour that hid the duty toggle');
|
||||
expect(
|
||||
find.byKey(barKey),
|
||||
findsNothing,
|
||||
reason: 'this is the behaviour that hid the duty toggle',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('as a Column child, the bar does not move', (tester) async {
|
||||
@@ -92,15 +99,21 @@ void main() {
|
||||
await tester.dragFrom(inScrollArea, const Offset(0, -300));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(tester.getRect(find.byKey(barKey)), before,
|
||||
reason: 'the app bar is fixed');
|
||||
expect(
|
||||
tester.getRect(find.byKey(barKey)),
|
||||
before,
|
||||
reason: 'the app bar is fixed',
|
||||
);
|
||||
// And the page really did scroll underneath it.
|
||||
expect(tester.getRect(find.byKey(contentKey)).top,
|
||||
lessThan(contentBefore - 200));
|
||||
expect(
|
||||
tester.getRect(find.byKey(contentKey)).top,
|
||||
lessThan(contentBefore - 200),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('the bar stays put through a long scroll and back',
|
||||
(tester) async {
|
||||
testWidgets('the bar stays put through a long scroll and back', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(pinned());
|
||||
final rect = tester.getRect(find.byKey(barKey));
|
||||
|
||||
@@ -111,13 +124,18 @@ void main() {
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('pull to refresh still fires below the fixed bar',
|
||||
(tester) async {
|
||||
testWidgets('pull to refresh still fires below the fixed bar', (
|
||||
tester,
|
||||
) async {
|
||||
var fired = 0;
|
||||
await tester.pumpWidget(pinned(onRefresh: () async {
|
||||
fired++;
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
}));
|
||||
await tester.pumpWidget(
|
||||
pinned(
|
||||
onRefresh: () async {
|
||||
fired++;
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
},
|
||||
),
|
||||
);
|
||||
final rect = tester.getRect(find.byKey(barKey));
|
||||
|
||||
await tester.flingFrom(inScrollArea, const Offset(0, 320), 1200);
|
||||
@@ -131,11 +149,16 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('the refresh spinner comes down below the bar, not behind it',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(pinned(onRefresh: () async {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 400));
|
||||
}));
|
||||
testWidgets('the refresh spinner comes down below the bar, not behind it', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(
|
||||
pinned(
|
||||
onRefresh: () async {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 400));
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await tester.flingFrom(inScrollArea, const Offset(0, 320), 1200);
|
||||
await tester.pump();
|
||||
@@ -145,8 +168,10 @@ void main() {
|
||||
expect(spinner, findsOneWidget);
|
||||
// `edgeOffset` is no longer needed precisely because the scroll viewport now
|
||||
// starts under the bar — so the indicator is already in clear space.
|
||||
expect(tester.getRect(spinner).top,
|
||||
greaterThanOrEqualTo(tester.getRect(find.byKey(barKey)).bottom - 0.01));
|
||||
expect(
|
||||
tester.getRect(spinner).top,
|
||||
greaterThanOrEqualTo(tester.getRect(find.byKey(barKey)).bottom - 0.01),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user