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:
57
lib/xpress/views/helpers/constants/Colorconstants.dart
Normal file
57
lib/xpress/views/helpers/constants/Colorconstants.dart
Normal file
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// The delivery line's palette.
|
||||
///
|
||||
/// ── Why these three values changed and nothing else did ──
|
||||
///
|
||||
/// The delivery screens are a verbatim port of the Xpress-rider app: same
|
||||
/// layout, same components, same 4-tab bottom bar. What was *not* kept is the
|
||||
/// brand. Xpress-rider was purple (#662582) with a lilac tint (#E7D3EF), and a
|
||||
/// rider signing in to Doormile should not be looking at another company's
|
||||
/// colour — the whole point of the port is that both lines are Doormile.
|
||||
///
|
||||
/// So the primary and its two tints are now the Doormile red the parcel line
|
||||
/// uses (`lib/views/helpers/constants/Colorconstants.dart`, `primary`), and
|
||||
/// every other entry below is untouched. Those others are semantic — greens for
|
||||
/// success, ambers for categories — and carry no brand.
|
||||
class ColorConstants {
|
||||
/// Doormile red. Was #662582, Xpress-rider's purple.
|
||||
static const primaryColor = Color(0xFF960019);
|
||||
|
||||
/// The 8%-ish wash behind selected rows and icon badges. Was #E7D3EF, the
|
||||
/// lilac derived from the purple; now the red's equivalent, so a tinted
|
||||
/// surface still reads as "the brand, quietly" rather than as a second hue.
|
||||
static Color? primaryColor1 = const Color(0xFFF6E0E2);
|
||||
static Color? secondaryColor = Colors.white;
|
||||
|
||||
/// Same wash as [primaryColor1], reached through the hex-string helper the
|
||||
/// ported screens use on a handful of call sites.
|
||||
static Color? ternaryColor = "#F6E0E2".toColor();
|
||||
static Color? darkGreyColor = "575756".toColor();
|
||||
static Color? lightGrey = "b2b2b2".toColor();
|
||||
static Color? lightGreyBg = Colors.grey.shade100;
|
||||
static Color? greenColor = "00b894".toColor();
|
||||
static Color? mintColor = "69c0ac".toColor();
|
||||
static Color restaurantColor = Colors.amber[100]!;
|
||||
static Color groceriesColor = Colors.purple[100]!;
|
||||
static Color shoppingColor = Colors.orange[100]!;
|
||||
static Color healthColor = Colors.cyan[100]!;
|
||||
static Color handymanColor = Colors.red[100]!;
|
||||
static const blueColor = 0xff007AC2;
|
||||
static const redColor = 0xffEF3F42;
|
||||
static const orangeColor = 0xffFAAB53;
|
||||
static Color? lightColor = const Color.fromRGBO(244, 244, 244, 1);
|
||||
}
|
||||
|
||||
extension ColorExtenstion on String {
|
||||
// ignore: body_might_complete_normally_nullable
|
||||
Color? toColor() {
|
||||
var hexColor = replaceAll("#", "");
|
||||
if (hexColor.length == 6) {
|
||||
hexColor = "FF$hexColor";
|
||||
}
|
||||
if (hexColor.length == 8) {
|
||||
return Color(int.parse("0x$hexColor"));
|
||||
}
|
||||
}
|
||||
}
|
||||
111
lib/xpress/views/helpers/constants/Font_constant.dart
Normal file
111
lib/xpress/views/helpers/constants/Font_constant.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
// ignore: file_names
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FontConstants {
|
||||
static String fontFamily = 'Proxima Nova';
|
||||
|
||||
// Base screen width for scaling (iPhone standard: 375)
|
||||
static const double _baseWidth = 375.0;
|
||||
|
||||
// Base font sizes (for baseWidth = 375)
|
||||
static const double _baseExtraSmall = 10.0;
|
||||
static const double _baseSmall = 12.0;
|
||||
static const double _baseMedium = 14.0;
|
||||
static const double _baseRegular = 16.0;
|
||||
static const double _baseLarge = 20.0;
|
||||
static const double _baseXLarge = 21.0;
|
||||
static const double _baseXXLarge = 22.0;
|
||||
static const double _baseXXXLarge = 24.0;
|
||||
static const double _baseHuge = 30.0;
|
||||
|
||||
/// Get fixed font size (no width scaling) so small & large phones look same.
|
||||
static double getResponsiveFontSize(BuildContext context, double baseSize) {
|
||||
return baseSize;
|
||||
}
|
||||
|
||||
/// Extra Small Text (10px base) - For labels, captions
|
||||
static double extraSmall(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseExtraSmall);
|
||||
|
||||
/// Small Text (12px base) - For small labels, timestamps
|
||||
static double small(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseSmall);
|
||||
|
||||
/// Medium Text (14px base) - For body text, descriptions
|
||||
static double medium(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseMedium);
|
||||
|
||||
/// Regular Text (16px base) - Standard body text, most common
|
||||
static double regular(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseRegular);
|
||||
|
||||
/// Large Text (18px base) - For subheadings, important text
|
||||
static double large(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseLarge);
|
||||
|
||||
/// Extra Large Text (20px base) - For headings, titles
|
||||
static double xLarge(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseXLarge);
|
||||
|
||||
/// 2X Large Text (22px base) - For main headings
|
||||
static double xxLarge(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseXXLarge);
|
||||
|
||||
/// 3X Large Text (24px base) - For prominent headings
|
||||
static double xxxLarge(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseXXXLarge);
|
||||
|
||||
/// Huge Text (26px base) - For hero text, very prominent headings
|
||||
static double huge(BuildContext context) =>
|
||||
getResponsiveFontSize(context, _baseHuge);
|
||||
}
|
||||
|
||||
class ReusableTextWidget extends StatelessWidget {
|
||||
final String text;
|
||||
final double? fontSize;
|
||||
final double? textHeight;
|
||||
final String? fontFamily;
|
||||
final FontWeight? fontWeight;
|
||||
final FontStyle? fontStyle;
|
||||
final Color? color;
|
||||
final TextAlign? textAlign;
|
||||
final int? maxLines;
|
||||
final TextDecoration? isUnderText;
|
||||
|
||||
const ReusableTextWidget({
|
||||
super.key,
|
||||
required this.text,
|
||||
this.fontSize,
|
||||
this.textHeight,
|
||||
this.fontFamily,
|
||||
this.fontWeight,
|
||||
this.fontStyle,
|
||||
this.color,
|
||||
this.textAlign,
|
||||
this.maxLines,
|
||||
this.isUnderText,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Text(
|
||||
text,
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize ?? FontConstants.medium(context),
|
||||
decoration: isUnderText,
|
||||
fontFamily: fontFamily ?? FontConstants.fontFamily,
|
||||
decorationColor: color,
|
||||
fontWeight: fontWeight ?? FontWeight.normal,
|
||||
fontStyle: fontStyle ?? FontStyle.normal,
|
||||
color: color ?? Colors.grey.shade900,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
decorationStyle: TextDecorationStyle.solid,
|
||||
decorationThickness: 1,
|
||||
height: textHeight,
|
||||
),
|
||||
maxLines: maxLines,
|
||||
textAlign: textAlign ?? TextAlign.start,
|
||||
);
|
||||
}
|
||||
}
|
||||
81
lib/xpress/views/helpers/constants/apiconstants.dart
Normal file
81
lib/xpress/views/helpers/constants/apiconstants.dart
Normal file
@@ -0,0 +1,81 @@
|
||||
import 'package:miler/xpress/data/delivery_api.dart';
|
||||
|
||||
/// The delivery line's endpoint names, kept as a thin façade over [DeliveryApi].
|
||||
///
|
||||
/// ── Why this class still exists ──
|
||||
///
|
||||
/// The ported screens reference `ApiConstants.currentDeliveryLive` and friends
|
||||
/// on roughly thirty call sites, most of them inside 1000-line `part` files that
|
||||
/// were brought over verbatim. Renaming those call sites would mean editing the
|
||||
/// ported flow, which is the one thing this port was meant not to do.
|
||||
///
|
||||
/// So the names survive and the values now resolve to Doormile routes. Every
|
||||
/// URL — including the ones that used to be inline in `homepage.dart`,
|
||||
/// `cartpage.dart`, `deliveries.dart` and `summary.dart` — is defined once, in
|
||||
/// [DeliveryApi], with a LIVE / MAPPED / ABSENT marker saying whether the route
|
||||
/// exists on the backend today. Read that file before trusting any call here.
|
||||
///
|
||||
/// ── The dev/live pairs collapsed ──
|
||||
///
|
||||
/// The old backend had a `dev` and a `live` deployment selected by a string
|
||||
/// (`mainRoute`), so every endpoint came in two. Doormile has one API and one
|
||||
/// base URL, so both members of each pair now return the same value. They are
|
||||
/// kept only so the ported call sites — which branch on
|
||||
/// `ApiConstants.mainRoute == 'live'` — keep compiling and land on the same
|
||||
/// place either way.
|
||||
class ApiConstants {
|
||||
/// Retained because ported call sites branch on it. Both branches now resolve
|
||||
/// to the same Doormile route.
|
||||
static String mainDev = "dev";
|
||||
static String mainRoute = "live";
|
||||
|
||||
//Delivery Queue — MAPPED to /miler/assignments
|
||||
static String get deliveryQueueDev => DeliveryApi.deliveryQueue;
|
||||
static String get deliveryQueueLive => DeliveryApi.deliveryQueue;
|
||||
|
||||
//Current Delivery — MAPPED to /miler/bookings
|
||||
static String get currentDeliveryDev => DeliveryApi.currentDeliveries;
|
||||
static String get currentDeliveryLive => DeliveryApi.currentDeliveries;
|
||||
|
||||
//Current Delivery V3 (was date-bounded) — MAPPED to /miler/bookings
|
||||
static String get currentDeliveryV3Dev => DeliveryApi.currentDeliveries;
|
||||
static String get currentDeliveryV3Live => DeliveryApi.currentDeliveries;
|
||||
|
||||
//Update Delivery — ABSENT, see DeliveryApi.updateDelivery
|
||||
static String get updateDeliveryDev => DeliveryApi.updateDelivery;
|
||||
static String get updateDeliveryLive => DeliveryApi.updateDelivery;
|
||||
|
||||
//Get Rider Log — LIVE
|
||||
static String get getRiderLogDev => DeliveryApi.getRiderLog;
|
||||
static String get getRiderLogLive => DeliveryApi.getRiderLog;
|
||||
|
||||
//Create Rider Log — LIVE
|
||||
static String get createRiderLogDev => DeliveryApi.createRiderLog;
|
||||
static String get createRiderLogLive => DeliveryApi.createRiderLog;
|
||||
|
||||
//Update Rider Log — LIVE (same collection, PUT semantics at the call site)
|
||||
static String get updateRiderLogDev => DeliveryApi.createRiderLog;
|
||||
static String get updateRiderLogLive => DeliveryApi.createRiderLog;
|
||||
|
||||
//Get Rider Count — ABSENT on Doormile; nearest real read is duty status.
|
||||
static String get getRiderCountDev => DeliveryApi.currentDuty;
|
||||
static String get getRiderCountLive => DeliveryApi.currentDuty;
|
||||
|
||||
//Create Break Rider Log — LIVE
|
||||
static String get createBreakRiderLogDev => DeliveryApi.startBreak;
|
||||
static String get createBreakRiderLogLive => DeliveryApi.startBreak;
|
||||
|
||||
//Update Break Rider Log — LIVE
|
||||
static String get updateBreakRiderLogDev => DeliveryApi.endBreak;
|
||||
static String get updateBreakRiderLogLive => DeliveryApi.endBreak;
|
||||
|
||||
//Create Delivery Log — ABSENT, see DeliveryApi.createDeliveryLog
|
||||
static String get createDeliveryLogDev => DeliveryApi.createDeliveryLog;
|
||||
static String get createDeliveryLogLive => DeliveryApi.createDeliveryLog;
|
||||
|
||||
//Summary — LIVE (/miler/earnings)
|
||||
static String get summaryApiLive => DeliveryApi.earnings;
|
||||
|
||||
//Summary Rider Weekly KMs — ABSENT, see DeliveryApi.weeklyKms
|
||||
static String get summaryriderkmLive => DeliveryApi.weeklyKms;
|
||||
}
|
||||
19
lib/xpress/views/helpers/constants/mqtt_constants.dart
Normal file
19
lib/xpress/views/helpers/constants/mqtt_constants.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
class MqttConstants {
|
||||
static const String brokerHost = '66.116.225.226'; // Updated with VPS IP
|
||||
static const int brokerPort = 1883;
|
||||
static const String username = 'admin';
|
||||
static const String passwordString = 'Package@321#'; // Provided by user
|
||||
|
||||
// Topic Structure
|
||||
static const String topicRiderStatus = 'doormile/riders/{riderId}/status';
|
||||
static const String topicRiderProfile = 'doormile/riders/{riderId}/profile';
|
||||
static const String topicRiderLocation = 'doormile/riders/{riderId}/location';
|
||||
static const String topicRiderTelemetry =
|
||||
'doormile/riders/{riderId}/telemetry';
|
||||
static const String topicRiderLogs = 'doormile/riders/{riderId}/logs';
|
||||
|
||||
// Status Values
|
||||
static const String statusOnline = 'Online';
|
||||
static const String statusOffline = 'Offline';
|
||||
static const String statusIdle = 'Idle';
|
||||
}
|
||||
Reference in New Issue
Block a user