device infos
This commit is contained in:
@@ -254,8 +254,17 @@ class Trip {
|
||||
///
|
||||
/// Returns `this` unchanged when nothing has been collected yet, so the
|
||||
/// common case allocates nothing.
|
||||
/// ── Declined work is not outstanding work ──
|
||||
///
|
||||
/// [rejectedIds] is the set the rider's own decision writes, and it has to be
|
||||
/// passed in because a decline is **local first**: the stop stays in the
|
||||
/// payload reading `assigned` until the backend catches up, so
|
||||
/// `stopStatusOf` cannot see it and the figures counted a stop the rider had
|
||||
/// refused. He declined four of eight and the card still measured the
|
||||
/// kilometres to all eight.
|
||||
Trip outstanding({
|
||||
Set<String> collectedIds = const <String>{},
|
||||
Set<String> rejectedIds = const <String>{},
|
||||
double? originLat,
|
||||
double? originLng,
|
||||
}) {
|
||||
@@ -263,7 +272,9 @@ class Trip {
|
||||
for (final s in stops)
|
||||
if (!WorkBoundary.pickupComplete(s, collectedIds: collectedIds) &&
|
||||
!stopStatusOf(s).isCancelled &&
|
||||
!stopStatusOf(s).isSkipped)
|
||||
!stopStatusOf(s).isSkipped &&
|
||||
!stopStatusOf(s).isRejected &&
|
||||
!rejectedIds.contains((s['orderid'] ?? '').toString()))
|
||||
s,
|
||||
];
|
||||
if (left.length == stops.length) return this;
|
||||
@@ -300,6 +311,35 @@ class Trip {
|
||||
'${RouteMetricsHelper.formatClock(e)}';
|
||||
}
|
||||
|
||||
/// The slot as a **clock range**, or `''` when it has none.
|
||||
///
|
||||
/// ── Why a day part is not printed at clock position ──
|
||||
///
|
||||
/// [slotLabel] answers "what is this trip called" and names a whole day part
|
||||
/// as *Morning* / *Afternoon* / *Evening*, which is right for a heading.
|
||||
/// It is wrong wherever the app is printing a live figure.
|
||||
///
|
||||
/// Two things happen when it lands there. The word is a **label pretending to
|
||||
/// be data**: it sits where "3h 10m left" sits, in the corner a rider checks
|
||||
/// for how much time he has, and answers with a noun he cannot act on. And it
|
||||
/// is redundant twice over — the trip is already numbered `Trip 1`, and the
|
||||
/// number *is* the day part, so `Trip 1 · Morning` says one thing twice.
|
||||
///
|
||||
/// This became visible when trips started being placed by day part at all:
|
||||
/// before that they carried no window, [slotLabel] fell through to "Today's
|
||||
/// route", and the same call sites printed nothing. So the fix is not to undo
|
||||
/// the placement — it is to stop reading a heading as a measurement.
|
||||
///
|
||||
/// Returns a range only when the hub sent a real one: `10:00 AM – 1:00 PM`.
|
||||
String get slotClockLabel {
|
||||
final s = slotStart;
|
||||
final e = slotEnd;
|
||||
if (s == null || e == null) return '';
|
||||
if (DayPart.spans(s, e)) return '';
|
||||
return '${RouteMetricsHelper.formatClock(s)} – '
|
||||
'${RouteMetricsHelper.formatClock(e)}';
|
||||
}
|
||||
|
||||
/// True when the slot window has already closed.
|
||||
bool isExpired([DateTime? now]) {
|
||||
final e = slotEnd;
|
||||
@@ -410,15 +450,47 @@ class Trip {
|
||||
DateTime? get _earliestDue {
|
||||
DateTime? best;
|
||||
for (final s in stops) {
|
||||
final due = _parseTimestamp(
|
||||
s['expected_pickup_time'] ?? s['expectedpickuptime'] ?? s['eta'],
|
||||
);
|
||||
final due = dayPartTimeOf(s);
|
||||
if (due == null) continue;
|
||||
if (best == null || due.isBefore(best)) best = due;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/// The clock that decides which part of the day a stop belongs to.
|
||||
///
|
||||
/// ── Due time first, assignment time second ──
|
||||
///
|
||||
/// The right answer is when the work is *due*: an order to be collected at
|
||||
/// 10am is morning work whenever the hub happened to raise it. That is
|
||||
/// `expected_pickup_time`, and where the backend sends it nothing here
|
||||
/// changes.
|
||||
///
|
||||
/// Where it does not — which is the live Doormile contract today — the day
|
||||
/// part had nothing to read at all, and every stop fell into the undated
|
||||
/// `day:` bucket. One trip, no day part, and [TripSlots.slots] put it in the
|
||||
/// first free slot: **everything was Trip 1, all day**. A rider given an
|
||||
/// evening run opened Home to find it filed under the morning.
|
||||
///
|
||||
/// So the fallback is when the work reached him — `assignedat`, merged onto
|
||||
/// the row by [WorkRepository] from the assignment ledger. It is the hub's
|
||||
/// own act as the phone observed it, and it is what dispatch means on the
|
||||
/// telephone: work handed over in the morning is the morning run. Approximate
|
||||
/// where a due time would be exact, and exactly right for the common case,
|
||||
/// which is a slot assigned at the top of the slot it is for.
|
||||
///
|
||||
/// `eta` is read last and usually answers nothing — on the v1 adapter it is
|
||||
/// a duration, not a clock, and [_parseTimestamp] rejects it rather than
|
||||
/// inventing a 15th of the month out of "15 min".
|
||||
static DateTime? dayPartTimeOf(Map<String, dynamic> stop) =>
|
||||
_parseTimestamp(
|
||||
stop['expected_pickup_time'] ??
|
||||
stop['expectedpickuptime'] ??
|
||||
stop['assignedat'] ??
|
||||
stop['assignedon'] ??
|
||||
stop['eta'],
|
||||
);
|
||||
|
||||
/// Address components every stop on this trip shares — city, state,
|
||||
/// pincode and so on. Cached per build by the caller.
|
||||
List<String> get sharedAddressTail => commonAddressTail([
|
||||
@@ -663,11 +735,11 @@ class Trip {
|
||||
from = slotFrom;
|
||||
to = slotTo;
|
||||
} else {
|
||||
final due = _parseTimestamp(
|
||||
stop['expected_pickup_time'] ??
|
||||
stop['expectedpickuptime'] ??
|
||||
stop['eta'],
|
||||
);
|
||||
// Due time where the hub sends one, and the moment the work reached
|
||||
// the rider where it does not — see [Trip.dayPartTimeOf]. Without the
|
||||
// second half every stop landed in the undated bucket below and the
|
||||
// whole day rendered as Trip 1.
|
||||
final due = dayPartTimeOf(stop);
|
||||
if (due != null) {
|
||||
// Morning, afternoon or evening — see [DayPart]. Not a rolling
|
||||
// window: two stops due an hour apart are on the same run, and the
|
||||
|
||||
Reference in New Issue
Block a user