Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,7 @@ The app never checks its own version: it sends `APP-<x.y.z>` (store) or `APP-<ep
- **Session Format**: Each session has a filename (`YYYY-MM-DD.json`), creation timestamp, ping count, device info, and the wardrive data payload
- **Upload**: Sessions can be uploaded from Settings → Data when connectivity is restored
- **Non-persistent**: Offline mode is never persisted — always off on app restart. Users must re-enable if needed.
- **When pings are written**: pings collect in memory (`ApiQueueService` offline buffer, cleared on every app launch) and reach the session file at these points: a 60 s auto-save that runs for as long as Offline Mode is on (it stops only when Offline Mode is turned off or the switch back to online succeeds, never on a save), a snapshot whenever the app is backgrounded, and a final save on mode stop, mode switch, user disconnect and the BLE-drop cleanup after a reconnect gives up. The noise floor session is stored on those same teardowns, so a teardown that skipped the final save left a drive in Session History with no offline file. The final save finalizes the file, so the next connect starts a new one.
- **Maintenance integration**: When maintenance mode is detected while disconnected, the UI suggests using Offline Mode
- **Airborne pause**: while the airborne latch is set, no fix is appended to the offline recording (`ApiQueueService.setOfflineRecordingPaused`); the session itself ends through the normal airborne block. See GPS & Zone Validation.
- **File**: `lib/services/offline_session_service.dart`
Expand Down
20 changes: 17 additions & 3 deletions lib/providers/app_state_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6662,6 +6662,11 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver {
// Stop RX logger
_rxLogger?.stopWardriving(trigger: 'ble_disconnect');

// Save offline pings, as disconnect() does. The noise floor session above
// is already stored, so skipping this left a drive in History with no
// offline file once the unsaved pings were gone (no-op with no pings).
await _saveOfflineSession();

// Force upload any pending items BEFORE releasing session
if (flushQueue && _apiService.hasSession) {
debugLog('[CONN] Flushing API queue before session release');
Expand Down Expand Up @@ -9352,6 +9357,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver {

// 5. Auth successful - update state
switchSucceeded = true;
// Offline Mode is off for good now (the finally only rolls back a
// failed switch), so its auto-save stops here.
_stopOfflineAutoSaveTimer();

// 6. Update regional channels from auth response
final channels = result['channels'];
Expand Down Expand Up @@ -9466,7 +9474,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver {
String? get _offlineDeviceName => _isAnonymousRenamed
? 'Anonymous'
: (_meshCoreConnection?.selfInfo?.name ??
connectedDeviceName?.replaceFirst('MeshCore-', ''));
connectedDeviceName?.replaceFirst('MeshCore-', '') ??
// A reconnect that gave up has already dropped the connection.
_displayDeviceName);

/// Save accumulated offline pings to a session file
Future<void> _saveOfflineSession() async {
Expand All @@ -9492,7 +9502,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver {
devicePublicKey: _devicePublicKey,
deviceName: offlineDeviceName,
contactUri: _offlineContactUri,
radioConfig: _meshCoreConnection?.selfInfo?.radioConfigApi,
// The remembered config covers a reconnect that gave up, which has
// already dropped the connection.
radioConfig: liveRadioConfig ?? _lastRadioConfig,
deviceModel: _meshCoreConnection?.deviceModel?.manufacturer ??
_meshCoreConnection?.deviceInfo?.manufacturer ??
_manufacturerString,
Expand All @@ -9501,7 +9513,9 @@ class AppStateProvider extends ChangeNotifier with WidgetsBindingObserver {
);
_offlineSessionService.finalizeCurrentSession();
debugLog('[APP] Saved offline session with ${pings.length} pings');
_stopOfflineAutoSaveTimer();
// The auto-save keeps running: Offline Mode is still on, and the next
// connect or mode start in this stint needs it. It stops when Offline
// Mode is turned off.
notifyListeners();
}

Expand Down
Loading