device infos

This commit is contained in:
2026-08-28 15:07:30 +05:30
parent 5723d373b2
commit 69f4f3e909
84 changed files with 4337 additions and 2339 deletions

View File

@@ -227,7 +227,11 @@ Future<String> resolveConsignmentId(Map<String, dynamic> stop) async {
/// rider can retry this until his battery dies.
/// • **At a hub.** A cross-city parcel is `Inwarded_at_Hub` and will be
/// delivered by somebody else. There is nothing here for him to start.
/// • **Refused.** The server gave a reason and it was thrown away.
/// • **Refused.** The server gave a reason and it was thrown away. It is
/// read now — and *translated*, because the reason arrives as a state
/// machine talking to itself (`consignment is Inwarded_At_Hub, not
/// Collected_By_Miler`) and that is not a sentence for a rider. See
/// [_refusalSentence].
/// • **Unreachable.** The only one where "check your connection" is true.
///
/// Telling a rider to check a working connection, about a parcel that is not
@@ -318,10 +322,10 @@ Future<bool> releaseForDelivery(Map<String, dynamic> stop) async {
// account for, and one 400 carrying the backend's own sentence is worth more
// than a client-side refusal that invents one. A hyperlocal consignment the
// pivot has not finished releasing is let through; a hub-routed one is
// refused by the server, and the rider is told what the server said.
// refused by the server, and the rider is told what the server *meant* —
// translated out of the state machine's vocabulary, see [_refusalSentence].
// A hold that cannot exist on this line is a bad read, not a fact about the
// stop. See [_handoffHoldIsPossible].
final heldElsewhere = state.awaitsHub && _handoffHoldIsPossible;
if (state.awaitsHub && !_handoffHoldIsPossible) {
debugPrint(
'[MILKRUN] $consignmentId read as ${state.name} on a line with no '
@@ -333,11 +337,16 @@ Future<bool> releaseForDelivery(Map<String, dynamic> stop) async {
!(state.awaitsHub && !_handoffHoldIsPossible) &&
state != ConsignmentState.unknown) {
debugPrint('[MILKRUN] $consignmentId is ${state.name} — not releasable');
lastReleaseFailure = heldElsewhere
// The honest answer for a cross-city parcel: it is not his round, and
// saying so without naming a building he has never been to.
? "This one has already been handed on — it's not yours to deliver."
: 'This parcel cannot be started yet. Ask your office to check it.';
// One sentence per state, written once — see
// [ConsignmentStateX.startRefusalSentence]. This branch and the refusal
// below are the same answer arrived at from two directions (a state the
// app read, and a state the server named), and they used to word it
// differently: a cross-city parcel blocked here said "it's not yours to
// deliver" while the identical parcel blocked one request later read out
// a database enum.
lastReleaseFailure =
state.startRefusalSentence ??
'This parcel cannot be started yet. Ask your office to check it.';
return false;
}
@@ -361,16 +370,63 @@ Future<bool> releaseForDelivery(Map<String, dynamic> stop) async {
final after = await ConsignmentGate.stateOf(consignmentId);
if (after.isDeliverable || after.isDelivered) return true;
// `status: 0` is the request never leaving; anything else is the server
// answering, and its own words beat a guess about the network.
// `status: 0` is the request never leaving, and it is the one failure that
// is really about the connection.
lastReleaseFailure = res.status == 0
? 'Could not reach your office. Check your connection and slide again.'
: (res.message.trim().isNotEmpty
? res.message.trim()
: 'Your office would not start this delivery.');
: _refusalSentence(res, after);
return false;
}
/// The rider's version of a refused **Start ride**.
///
/// ── What the rider was actually reading ──
///
/// The server's own words were passed straight to the screen, on the argument
/// that one refusal carrying the backend's reason beats a client-side guess
/// that invents one. That argument holds for *whose* answer it is. It does not
/// hold for what the answer turned out to be: `start-delivery` refuses with an
/// assertion about its own model — **"consignment is Inwarded_At_Hub, not
/// Collected_By_Miler"** — and that is what a rider saw on the slider, in
/// database vocabulary, with no way to tell it from a crash.
///
/// The reason is worth keeping; the wording was never the server's to write.
/// So the state is what travels, and [ConsignmentStateX.startRefusalSentence]
/// says it once, in one place, in words that answer the only two questions he
/// has: is this mine, and will sliding again help.
///
/// ── Three sources for that state, best first ──
///
/// 1. **A fresh read** — [after], asked immediately after the refusal, which
/// is the newest thing anyone knows about the consignment.
/// 2. **The refusal itself.** The read can fail — the row need not carry a
/// status and the detail route 404s on older deployments — and when it
/// does the refusal is the only thing left that knows. See
/// [consignmentStateNamedInRefusal] for why reading it is safe.
/// 3. **The failure code.** `INVALID_STATE` alone still says the one useful
/// thing: the consignment has moved on from the rung this press acts at,
/// so sliding again is not the answer.
///
/// Prose from the server is still preferred over a generic sentence — some
/// routes really do answer in words meant for a person. What is filtered out
/// is the wire vocabulary. See [namesWireState].
String _refusalSentence(ApiResult res, ConsignmentState after) {
final state = after != ConsignmentState.unknown
? after
: consignmentStateNamedInRefusal(res.message);
final fromState = state.startRefusalSentence;
if (fromState != null) return fromState;
final said = res.message.trim();
if (said.isNotEmpty && !namesWireState(said)) return said;
return res.isInvalidState
? 'Your office has already moved this parcel on, so it cannot be '
'started from here. Ask them to check it.'
: 'Your office would not start this delivery.';
}
/// Brings this device into line with a delivery the server already has.
///
/// The same local bookkeeping a successful `deliver` performs — the order