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:
2026-08-22 05:40:35 +05:30
parent c8350563d9
commit d7348e253f
387 changed files with 80693 additions and 12272 deletions

View File

@@ -32,8 +32,9 @@ void main() {
designSize: const Size(390, 844),
builder: (_, _) => MaterialApp(
builder: (context, child) => MediaQuery(
data: MediaQuery.of(context)
.copyWith(textScaler: TextScaler.linear(textScale)),
data: MediaQuery.of(
context,
).copyWith(textScaler: TextScaler.linear(textScale)),
child: child!,
),
home: CollectPaymentPage(
@@ -64,8 +65,9 @@ void main() {
if (pickupAmt > 0) 'pickupamt': '$pickupAmt',
};
testWidgets('the amount is the booking\'s, and it names who owes it',
(tester) async {
testWidgets('the amount is the booking\'s, and it names who owes it', (
tester,
) async {
await pump(tester, stopOf(due: 450));
expect(find.text('₹450'), findsOneWidget);
@@ -96,14 +98,12 @@ void main() {
await pump(tester, stopOf());
expect(find.byType(QrImageView), findsNothing);
expect(
find.textContaining('Slide — took ₹450 by Cash'),
findsOneWidget,
);
expect(find.textContaining('Slide — took ₹450 by Cash'), findsOneWidget);
});
testWidgets('choosing UPI puts the QR on the page, not behind a dialog',
(tester) async {
testWidgets('choosing UPI puts the QR on the page, not behind a dialog', (
tester,
) async {
await pump(tester, stopOf(due: 450));
expect(find.byType(QrImageView), findsNothing);
@@ -173,8 +173,9 @@ void main() {
expect(find.text('₹50 still owed on this consignment'), findsOneWidget);
});
testWidgets('a separate pickup charge is listed, never added up',
(tester) async {
testWidgets('a separate pickup charge is listed, never added up', (
tester,
) async {
// The office sets what is due. The page explains it; it does not do
// arithmetic the office has not sanctioned.
await pump(tester, stopOf(due: 450, pickupAmt: 60));