updated the sheet

This commit is contained in:
2026-08-28 18:16:28 +05:30
parent 69f4f3e909
commit 074cc0eccf
43 changed files with 2617 additions and 1201 deletions

View File

@@ -1,7 +1,6 @@
import 'package:get/get.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:miler/views/helpers/constants/apiconstants.dart';
import 'package:miler/Models/riders/riders_models.dart';
import 'package:miler/providers/Riderlog/riderlog_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -16,6 +15,7 @@ import 'package:miler/background/foreground_service.dart' as fg;
import 'package:miler/utils/kalman_filter.dart';
import 'package:miler/utils/mqtt_service.dart';
import 'package:miler/data/device_telemetry.dart';
import 'package:miler/data/heartbeat.dart';
import 'package:miler/views/helpers/constants/mqtt_constants.dart';
import 'package:battery_plus/battery_plus.dart';
import 'package:miler/controllers/connectivity_mixin.dart';
@@ -235,7 +235,7 @@ class RiderLogController extends GetxController
// ✅ Check if there are active pickup to set status
final bool hasActivePickups = prefs.getBool('has_live_pickup') ?? false;
final String riderStatus = hasActivePickups ? 'active' : 'idle';
final String riderStatus = heartbeatStatus(hasActiveWork: hasActivePickups);
final String orderId = prefs.getString('current_riding_order_id') ?? '';
debugPrint(
'[RIDERLOG][CREATE LOGIN NOW] Active pickup: $hasActivePickups -> status: $riderStatus',
@@ -315,7 +315,7 @@ class RiderLogController extends GetxController
// 1. Lane: Status
mqttService.updateStatus(
riderStatus == 'active' ? 'Active' : MqttConstants.statusOnline,
riderStatus == 'On_Pickup' ? 'Active' : MqttConstants.statusOnline,
);
// 2. Lane: Profile (Send only if significantly changed or first time)
@@ -448,7 +448,7 @@ class RiderLogController extends GetxController
// Check status for offline fallback too
final bool hasActivePickups =
prefs.getBool('has_live_pickup') ?? false;
final String riderStatus = hasActivePickups ? 'active' : 'idle';
final String riderStatus = heartbeatStatus(hasActiveWork: hasActivePickups);
final Map<String, dynamic> payload = {
...baseTemplate,
@@ -520,10 +520,19 @@ class RiderLogController extends GetxController
await prefs.setInt('onduty', on ? 1 : 0);
if (on) {
await createLoginNowV2();
final int interval = prefs.getInt('logseconds') ?? 0;
if (interval > 0) {
startAutoCreateLoginLoop(seconds: interval);
}
// ── Going on duty always starts the heartbeat ──
//
// This was gated on `interval > 0`, reading a stored zero as a
// decision not to beat. The v1 login has no `logseconds` to store, so
// the gate was shut on every rider: duty went on, one log was posted
// by the call above, and nothing followed it — no telemetry trail and
// no location writes for the rest of the shift.
//
// There is no cadence at which a rider on duty should not report, so
// there is no branch here any more. [resolveLogSeconds] supplies the
// floor when the hub has not set one.
final int interval = resolveLogSeconds(prefs.getInt('logseconds'));
startAutoCreateLoginLoop(seconds: interval);
// Ensure foreground logging notification is started when going on-duty
try {
@@ -590,15 +599,45 @@ class RiderLogController extends GetxController
}
}
/// Whether the periodic heartbeat is currently running on the stream path.
///
/// ── Why a test needs to be able to see this ──
///
/// The `logseconds` bug was invisible from outside the class. Duty went on,
/// the API accepted it, one log was posted by the immediate call — and the
/// loop that was supposed to follow it simply never started. Nothing threw,
/// nothing logged an error, and the only symptom was a console panel that had
/// been blank for so long it read as a backend problem.
///
/// Android normally runs the heartbeat as a foreground service instead, and
/// leaves this null; the test host is never Android, so the stream path is
/// the one under test. See [startAutoCreateLoginLoop].
@visibleForTesting
bool get autoLoopRunning => _autoLoginSubscription != null;
// Start periodic createRiderLog calls based on seconds (or prefs 'logseconds')
// ✅ CRITICAL: When there are active pickup, use 30 seconds (same as pickup logs)
// Otherwise, use the configured logseconds interval
void startAutoCreateLoginLoop({int? seconds}) async {
/// `Future<void>`, not `void`. It was fire-and-forget, which meant no caller
/// could wait for the loop to actually be up — and the one place that most
/// wanted to, [setOnDuty], had no way to tell whether the heartbeat it had
/// just asked for existed. Every existing call site ignores the future and is
/// unchanged by this.
Future<void> startAutoCreateLoginLoop({int? seconds}) async {
final prefs = await SharedPreferences.getInstance();
// ✅ Check if there are active pickup - if yes, use 30 seconds (same as pickup logs)
final bool hasActivePickups = prefs.getBool('has_live_pickup') ?? false;
final int baseInterval = seconds ?? (prefs.getInt('logseconds') ?? 0);
// ── The configured cadence, or the floor under it ──
//
// `?? 0` here was the second half of the same bug as the one in
// [setOnDuty]: a caller that passes no `seconds` — the app-resume path in
// `main.dart` is one — fell through to a stored zero and then returned at
// the `interval <= 0` guard below, so the loop the resume was trying to
// revive silently did not start. See [resolveLogSeconds].
final int baseInterval = resolveLogSeconds(
seconds ?? prefs.getInt('logseconds'),
);
// When there are active pickup, post rider logs every 30 seconds (matching pickup logs)
// Otherwise, use the configured interval
@@ -610,12 +649,20 @@ class RiderLogController extends GetxController
);
}
await stopAutoCreateLoginLoop(); // Cancel existing subscription
// Stop before start, which is what keeps this method safe to call from the
// three places that do — going on duty, resuming the app, and a pickup
// going live. Whichever arrives last wins, and there is never a second
// loop: the subscription is cancelled and the foreground service stopped
// before either is created again.
await stopAutoCreateLoginLoop();
// Attempt to flush offline logs on loop start
flushOfflineLogs();
if (interval <= 0) return;
// No `interval <= 0` guard. [resolveLogSeconds] cannot return one, and the
// guard that used to be here is what turned a missing `logseconds` into a
// rider who never reported. Duty state decides whether the loop runs; the
// cadence only decides how often.
final int onduty = prefs.getInt('onduty') ?? 0;
if (onduty != 1) {
debugPrint('[RIDERLOG][AUTO LOOP] Not starting - onduty=$onduty');
@@ -1049,9 +1096,6 @@ class RiderLogController extends GetxController
final breakhoursDouble = duration.inSeconds / 3600.0;
// Debug logs for terminal visibility
debugPrint(
'[BREAK][UPDATE] URL: ${ApiConstants.mainRoute == 'live' ? ApiConstants.updateBreakRiderLogLive : ApiConstants.updateBreakRiderLogDev}',
);
debugPrint(
'[BREAK][UPDATE] Fields: breakid=$breakid, logid=$logid, userid=$userid, partnerid=$partnerid, shiftid=$shiftid, breakend=$breakend, breakhours=$breakhoursDouble, lat=$latitude, lng=$longitude',
);
@@ -1107,7 +1151,7 @@ class RiderLogController extends GetxController
// ✅ Check if there are active pickup to set status
final bool hasActivePickups = prefs.getBool('has_live_pickup') ?? false;
final String riderStatus = hasActivePickups ? 'active' : 'idle';
final String riderStatus = heartbeatStatus(hasActiveWork: hasActivePickups);
// Resolve rider display name (username) from prefs to include in log
String? username = prefs.getString('username');