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

@@ -131,10 +131,49 @@ Future<void> stampOrderEvent(
/// Stamps one event against several orders at once — a kitchen handover, an
/// accept-all, a released round.
Future<void> stampOrderEvents(Iterable<Object> orderIds, String event) async {
final at = DateTime.now();
for (final id in orderIds) {
await stampOrderEvent(id, event, at: at);
Future<void> stampOrderEvents(Iterable<Object> orderIds, String event) async =>
stampOrderEventsAndRead(orderIds, event);
/// [stampOrderEvents], and hands back the whole ledger it just wrote.
///
/// ── Why the batch is one read and one write ──
///
/// [stampOrderEvent] is a read-modify-write of the entire ledger, and the loop
/// that called it did that **once per order**. A rider holding sixty bookings
/// therefore paid sixty decodes and sixty encodes of a JSON blob that grows
/// with his day, on every poll — which is why the call site had to fire it into
/// the dark with `unawaited` and could never use the result.
///
/// It is used now: [WorkRepository] merges the assignment stamp back onto the
/// rows it just fetched, so "when did this reach me" is a fact on the stop
/// rather than a second store every screen has to join for itself. That needs
/// the ledger *after* the write, which is the other half of why this exists.
///
/// Still written once — an order that already carries [event] keeps the clock
/// it has.
Future<Map<String, Map<String, String>>> stampOrderEventsAndRead(
Iterable<Object> orderIds,
String event,
) async {
try {
final prefs = await SharedPreferences.getInstance();
final all = await _read(prefs);
final at = DateTime.now().toIso8601String();
var added = 0;
for (final raw in orderIds) {
final id = raw.toString().trim();
if (id.isEmpty) continue;
final mine = all.putIfAbsent(id, () => <String, String>{});
if (mine.containsKey(event)) continue;
mine[event] = at;
added++;
}
if (added > 0) await prefs.setString(_kKey, jsonEncode(all));
return all;
} catch (e) {
debugPrint('[EVENTS] could not stamp $event on a batch: $e');
return const {};
}
}
@@ -170,9 +209,24 @@ Future<void> clearOrderEvents(Object orderId) async {
///
/// The ledger is per-order and nothing prunes it on read, so without this it
/// grows for the life of the install — the same trap `removeCollectedOrderIds`
/// exists to avoid. Two days rather than one, because a shift that crosses
/// midnight must not lose its own morning.
Future<void> pruneOrderEvents({int keepDays = 2}) async {
/// exists to avoid.
///
/// ── Why two days was not enough once Home read this ──
///
/// It was two, on the reasoning that a shift crossing midnight must not lose
/// its own morning. That is the right floor for a *timeline*, which is all this
/// fed. It is the wrong floor for a **day filter**.
///
/// [OrderEvent.assigned] is now what dates a booking the backend dates with
/// nothing, and an order still sitting in the queue undecided carries that one
/// stamp and no other. At two days it was pruned on the third morning, the next
/// fetch stamped it afresh with *that* day's clock, and a booking from Monday
/// reappeared on Thursday's Home as Thursday's work — the precise failure the
/// filter was added to stop, arriving three days late.
///
/// A fortnight is well past any open booking's life, and the cost is a few
/// hundred bytes: the entry is an id and up to five short strings.
Future<void> pruneOrderEvents({int keepDays = 14}) async {
try {
final prefs = await SharedPreferences.getInstance();
final all = await _read(prefs);