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:
220
test/deliveries_shots_test.dart
Normal file
220
test/deliveries_shots_test.dart
Normal file
@@ -0,0 +1,220 @@
|
||||
@Tags(['shots'])
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'support/golden_fonts.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:miler/data/service_profile.dart';
|
||||
import 'package:miler/views/Dashboard/home/trip.dart';
|
||||
import 'package:miler/views/Dashboard/home/trip_progress_rail.dart';
|
||||
// `card.dart` is a `part of` this library, so [PickupCard] comes through it.
|
||||
import 'package:miler/views/Dashboard/pickups/pickups.dart';
|
||||
import 'package:miler/views/helpers/constants/Colorconstants.dart';
|
||||
import 'package:miler/views/helpers/constants/Font_constant.dart';
|
||||
|
||||
/// Visual harness for the Deliveries tab's two public pieces.
|
||||
///
|
||||
/// `_MyPickupsState` cannot be pumped — Get, SharedPreferences, Geolocator and
|
||||
/// a 3s poll — and the queue's three quieter tiers (`_NextCard`, `_LaterRow`,
|
||||
/// `_SkippedRow`) are private to `card.dart`. What is reachable is exactly the
|
||||
/// pair the redesign is about: [TripProgressRail], which is the head of the
|
||||
/// screen, and [PickupCard], which is the one live card under it.
|
||||
///
|
||||
/// The rail is shot at four route lengths because the documented gap against it
|
||||
/// is that "a 21-stop route overflows it" — a claim about layout, which is
|
||||
/// answerable by looking. Run with `--update-goldens`.
|
||||
void main() {
|
||||
setUpAll(() async {
|
||||
// Same reasoning as `home_shots_test`: a golden rendered without the app's
|
||||
// own family is a picture of the fallback, and Poppins ships one file per
|
||||
// weight so each has to be registered under the family by hand.
|
||||
await loadGoldenFonts();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
Get.reset();
|
||||
ServiceProfile.setActive(ServiceProfile.parcel);
|
||||
});
|
||||
|
||||
Map<String, dynamic> drop(
|
||||
String id,
|
||||
String customer, {
|
||||
String status = 'picked',
|
||||
String bag = '',
|
||||
}) => {
|
||||
'orderid': id,
|
||||
'tripid': 'T1',
|
||||
'type': 'delivery',
|
||||
'pickupcustomer': customer,
|
||||
'name': customer,
|
||||
'sourcename': 'DailyGrubs RS Puram Kitchen',
|
||||
'kitchenid': 'K1',
|
||||
'kitchenname': 'DailyGrubs RS Puram Kitchen',
|
||||
'pickupaddress': '4 Cross, RS Puram, Coimbatore 641002',
|
||||
'dropaddress': '12, SNS Colony, Peelamedu, Coimbatore 641004',
|
||||
'deliveryaddress': '12, SNS Colony, Peelamedu, Coimbatore 641004',
|
||||
'orderstatus': status,
|
||||
'pickupcontactno': '9787698259',
|
||||
'deliverycontactno': '9787698259',
|
||||
if (bag.isNotEmpty) 'baglabel': bag,
|
||||
'Quantity': 1,
|
||||
'pickuplat': 11.0168,
|
||||
'pickuplon': 76.9558,
|
||||
'droplat': 11.0208,
|
||||
'droplon': 76.9598,
|
||||
};
|
||||
|
||||
Future<void> frame(
|
||||
WidgetTester tester,
|
||||
String name,
|
||||
Widget child, {
|
||||
double height = 400,
|
||||
double width = 390,
|
||||
}) async {
|
||||
ServiceProfile.setActive(ServiceProfile.milkMan);
|
||||
SharedPreferences.setMockInitialValues({'userid': 1});
|
||||
|
||||
tester.view.physicalSize = Size(width * 3, height * 3);
|
||||
tester.view.devicePixelRatio = 3.0;
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
await tester.pumpWidget(
|
||||
ScreenUtilInit(
|
||||
// Design size == surface, so `.w`/`.h` are both exactly 1 and the shot
|
||||
// does not lie about spacing. See the note in `home_shots_test`.
|
||||
designSize: Size(width, height),
|
||||
builder: (_, _) => MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: Scaffold(
|
||||
backgroundColor: ColorConstants.daylightSurface,
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await expectLater(
|
||||
find.byType(MaterialApp),
|
||||
matchesGoldenFile('shots/deliveries_$name.png'),
|
||||
);
|
||||
}
|
||||
|
||||
/// A route of [total] stops with [done] delivered and the rider standing at
|
||||
/// the next one — the shape the rail is actually asked to draw mid-round.
|
||||
List<StopProgress> route(int total, {int done = 0}) => [
|
||||
for (var i = 0; i < total; i++)
|
||||
if (i < done)
|
||||
StopProgress.done
|
||||
else if (i == done)
|
||||
StopProgress.current
|
||||
else
|
||||
StopProgress.pending,
|
||||
];
|
||||
|
||||
group('the route rail', () {
|
||||
testWidgets('a short round lays out across the full width', (tester) async {
|
||||
await frame(
|
||||
tester,
|
||||
'rail_short',
|
||||
TripProgressRail(
|
||||
progress: route(5, done: 2),
|
||||
slotLabel: 'Trip 1 · 10:00 AM – 1:00 PM',
|
||||
remaining: const Duration(minutes: 74),
|
||||
),
|
||||
height: 150,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('the documented 21-stop round', (tester) async {
|
||||
await frame(
|
||||
tester,
|
||||
'rail_21',
|
||||
TripProgressRail(
|
||||
progress: route(21, done: 6),
|
||||
slotLabel: 'Trip 1 · 10:00 AM – 1:00 PM',
|
||||
remaining: const Duration(minutes: 110),
|
||||
),
|
||||
height: 150,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('nothing delivered yet — the whole load still aboard', (
|
||||
tester,
|
||||
) async {
|
||||
await frame(
|
||||
tester,
|
||||
'rail_21_fresh',
|
||||
TripProgressRail(
|
||||
progress: route(21),
|
||||
slotLabel: 'Trip 1 · 10:00 AM – 1:00 PM',
|
||||
remaining: const Duration(minutes: 130),
|
||||
),
|
||||
height: 150,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('a 320pt phone at 1.3x text scale', (tester) async {
|
||||
await frame(
|
||||
tester,
|
||||
'rail_21_small',
|
||||
MediaQuery(
|
||||
data: const MediaQueryData(textScaler: TextScaler.linear(1.3)),
|
||||
child: TripProgressRail(
|
||||
progress: route(21, done: 6),
|
||||
slotLabel: 'Trip 1 · 10:00 AM – 1:00 PM',
|
||||
remaining: const Duration(minutes: 110),
|
||||
),
|
||||
),
|
||||
height: 170,
|
||||
width: 320,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('the live card', () {
|
||||
testWidgets('picked, waiting to be taken out', (tester) async {
|
||||
await frame(
|
||||
tester,
|
||||
'card_picked',
|
||||
PickupCard(
|
||||
item: drop('D1', 'Joe Mathew', bag: 'Bag 8'),
|
||||
displayStep: 7,
|
||||
distanceMeters: 1100,
|
||||
bag: 'Bag 8',
|
||||
collectedIds: const {'D1'},
|
||||
),
|
||||
height: 320,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('active — the rider has set off', (tester) async {
|
||||
await frame(
|
||||
tester,
|
||||
'card_active',
|
||||
PickupCard(
|
||||
item: drop('D1', 'Joe Mathew', bag: 'Bag 8'),
|
||||
displayStep: 7,
|
||||
distanceMeters: 1100,
|
||||
bag: 'Bag 8',
|
||||
collectedIds: const {'D1'},
|
||||
outForDeliveryIds: const {'D1'},
|
||||
),
|
||||
height: 320,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user