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>
96 lines
3.6 KiB
Dart
96 lines
3.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
|
||
import 'package:miler/views/helpers/constants/app_theme.dart';
|
||
import 'package:miler/views/introscreens/introscreen.dart';
|
||
|
||
/// The first-run slides. The illustrations are miniature mock-ups of the real
|
||
/// Home screen rather than a centred Material icon, which means they are made of
|
||
/// fixed-width rows — the hub rail on slide 1 is a dozen sized children in a
|
||
/// single unflexed `Row`. That is exactly the shape that overflows on a narrow
|
||
/// phone, so every slide is laid out at the narrowest screen the app supports.
|
||
void main() {
|
||
Future<void> pump(WidgetTester tester, {required Size screen}) async {
|
||
tester.view.physicalSize = Size(screen.width * 3, screen.height * 3);
|
||
tester.view.devicePixelRatio = 3.0;
|
||
addTearDown(tester.view.resetPhysicalSize);
|
||
addTearDown(tester.view.resetDevicePixelRatio);
|
||
|
||
await tester.pumpWidget(
|
||
ScreenUtilInit(
|
||
designSize: const Size(390, 844),
|
||
builder: (_, _) =>
|
||
MaterialApp(theme: AppTheme.light, home: const Introscreen()),
|
||
),
|
||
);
|
||
await tester.pumpAndSettle();
|
||
}
|
||
|
||
for (final size in const [
|
||
Size(320, 640), // smallest Android still in the fleet
|
||
Size(360, 740),
|
||
Size(390, 844),
|
||
Size(430, 932),
|
||
]) {
|
||
testWidgets('all three slides lay out at ${size.width.toInt()}pt', (
|
||
tester,
|
||
) async {
|
||
await pump(tester, screen: size);
|
||
expect(tester.takeException(), isNull);
|
||
|
||
// Slide 1 — the slot, its load, and the round trip.
|
||
expect(find.text('Your route arrives ready'), findsOneWidget);
|
||
expect(find.text('12:00 PM – 3:00 PM'), findsOneWidget);
|
||
expect(find.text('Next'), findsOneWidget);
|
||
|
||
// A near-full-width drag, so the page always snaps to the next one. A
|
||
// velocity fling does not reliably cross the threshold here, because each
|
||
// slide hosts its own vertical scroll view and the two share the arena.
|
||
final swipe = Offset(-size.width * 0.9, 0);
|
||
|
||
await tester.drag(find.byType(PageView), swipe);
|
||
await tester.pumpAndSettle();
|
||
expect(tester.takeException(), isNull);
|
||
expect(find.text('Work the stops in order'), findsOneWidget);
|
||
expect(find.text('Skipped'), findsOneWidget);
|
||
|
||
await tester.drag(find.byType(PageView), swipe);
|
||
await tester.pumpAndSettle();
|
||
expect(tester.takeException(), isNull);
|
||
expect(find.text('Collect, then close the loop'), findsOneWidget);
|
||
expect(find.text('₹340 cash'), findsOneWidget);
|
||
|
||
// Last slide swaps the CTA and drops Skip.
|
||
expect(find.text('Get started'), findsOneWidget);
|
||
expect(find.text('Skip'), findsNothing);
|
||
});
|
||
}
|
||
|
||
testWidgets('Skip is offered on the first slide', (tester) async {
|
||
await pump(tester, screen: const Size(390, 844));
|
||
expect(find.text('Skip'), findsOneWidget);
|
||
});
|
||
|
||
// The old copy pitched a gig marketplace — "pickups near you", accepted from a
|
||
// feed. This product assigns routes from a hub. Onboarding that teaches the
|
||
// wrong model is worse than none, so the wrong words are pinned out.
|
||
testWidgets('does not promise a marketplace the app does not have', (
|
||
tester,
|
||
) async {
|
||
await pump(tester, screen: const Size(390, 844));
|
||
for (final wrong in [
|
||
'Find pickups near you',
|
||
'Navigate the smart way',
|
||
'Earn more, every shift',
|
||
'Powered by AI',
|
||
]) {
|
||
expect(
|
||
find.text(wrong),
|
||
findsNothing,
|
||
reason: '"$wrong" is not this app',
|
||
);
|
||
}
|
||
});
|
||
}
|