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

@@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:miler/views/helpers/widgets/page_transitions.dart';
import 'package:miler/views/onboardscreens/otp_page.dart';
import 'package:miler/views/onboardscreens/auth_scaffold.dart';
import 'package:miler/widget/Bottom_page.dart';
import 'package:miler/helpers/rider_shell.dart';
import 'package:miler/controllers/auth.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -57,6 +58,15 @@ class _MpinViewState extends State<_MpinView> {
bool isVerifying = false;
bool _rejected = false;
/// What actually went wrong, from [AuthController.lastPinFailure].
///
/// This screen used to hard-code "Incorrect MPIN. Try again." for every
/// failure the controller reported — including the ones that never reached
/// the server. A rider whose sign-in was dying on a device-id lookup was told
/// his PIN was wrong, so the one thing he could report was the one thing that
/// was not true. Whatever the controller knows, the screen now says.
String? _failure;
String _riderName = '';
@override
@@ -101,7 +111,10 @@ class _MpinViewState extends State<_MpinView> {
}
setState(() {
if (_rejected) _rejected = false;
if (_rejected) {
_rejected = false;
_failure = null;
}
});
if (_isComplete) {
@@ -117,7 +130,12 @@ class _MpinViewState extends State<_MpinView> {
c.clear();
}
_focusNodes[0].requestFocus();
if (mounted) setState(() => _rejected = true);
if (mounted) {
setState(() {
_rejected = true;
_failure = _auth.lastPinFailure;
});
}
}
Future<void> _submitMpin() async {
@@ -130,14 +148,27 @@ class _MpinViewState extends State<_MpinView> {
);
if (!mounted) return;
setState(() => isVerifying = false);
setState(() {
isVerifying = false;
// Say it on the screen, not only inside a sheet the rider dismisses.
if (!ok) {
_rejected = true;
_failure = _auth.lastPinFailure;
}
});
if (ok) {
// Straight to the app. There used to be a "Go on duty" gate between the
// PIN and the tabs, which made every launch a two-step sign-in for a
// decision the rider can make — and change — from the switch in Home's
// app bar at any moment of the shift.
Get.offAll(() => const BottomPage());
//
// Which app depends on the tenant the login just resolved: `loginParsed`
// persists `tenantid`/`tenantname` and calls `TenantController.load()`
// before returning, so by this line the answer is settled. A delivery
// rider lands in the ported Xpress flow, everyone else in the parcel
// dashboard. See [riderShell].
Get.offAll(() => riderShell());
}
}
@@ -161,7 +192,7 @@ class _MpinViewState extends State<_MpinView> {
children: [
AuthPrimaryButton(
label: 'Unlock',
icon: Icons.lock_open_rounded,
icon: LucideIcons.lockOpen,
loading: isVerifying,
onPressed: isVerifying || !_isComplete ? null : _submitMpin,
),
@@ -190,7 +221,9 @@ class _MpinViewState extends State<_MpinView> {
// rejected and the boxes were reset — otherwise they empty themselves
// with no stated reason.
AuthInlineError(
message: _rejected ? 'Incorrect MPIN. Try again.' : null,
message: _rejected
? (_failure ?? 'Incorrect MPIN. Try again.')
: null,
),
],
);