Own and dispose app-level stream subscriptions#7
Merged
MrAlders0n merged 2 commits intoMeshMapper:devfrom Mar 8, 2026
Merged
Conversation
MrAlders0n
approved these changes
Mar 8, 2026
Contributor
MrAlders0n
left a comment
There was a problem hiding this comment.
Good catch — these three stream subscriptions were the last unowned listeners in AppStateProvider. The fix mirrors the existing pattern used for _adapterStateSubscription, _logRxDataSubscription, _noiseFloorSubscription, and _batterySubscription. Clean and consistent.
MrAlders0n
added a commit
that referenced
this pull request
Mar 20, 2026
* Add offline mode prompt when zone check fails due to no internet When the zone status check fails with a network error, show a full-screen UI with an "Enable Offline Mode" button (matching the maintenance mode pattern) instead of the generic "Zone Check Failed" message. Also adds a red "No Internet" indicator in the zone status bar. Non-network errors retain the existing behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Added option to disable carpeater RSSI filter under settings * Multi-hop CARpeater packets now strip the CARpeater hop and report coverage from the underlying repeater with null SNR/RSSI, instead of being dropped entirely. Single-hop packets and discovery responses are still dropped. The -30 dBm failsafe is bypassed for packets matching your CARpeater prefix but stays active for everything else. * Added Code of Conduct & Security * Update links * Exclude .vscode/ from version control Editor-specific configs shouldn't be tracked in a public repo so contributors can use their own setups. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Bug fixes: - [#98](MeshMapper/MeshMapper_Project#98) - The heard repeaters panel now scrolls and dynamically expands to accommodate larger lists of heard repeaters - [#95](MeshMapper/MeshMapper_Project#95) - Fixed the IATA popup panel being hidden behind the Android navigation bar - Fixed a bug where a stale BLE device name was used instead of the current one * Anonymous Mode — New privacy option in Settings that renames your device to "Anonymous" for all mesh pings. When enabled, other mesh users cannot see your companion name in wardrive broadcasts. Your device's public key is still used to authenticate your session with the MeshMapper API (geo-auth), but neither your sessions nor your pings are linked to it on the server. Toggling Anonymous Mode while connected automatically disconnects and reconnects with the new identity, switching to the Connection tab so you can see reconnection progress. On proper disconnect, the original device name is restored. Persisted across app restarts. * Update repeater endpoint from /repeaters.json to /get_repeaters.php Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * ### New Features - Automatic map tile refresh after successful data upload, so new coverage appears on the map within the app near real-time - Deterministic 5-second upload timer for TX and discovery pings, replacing the old batch system that could take up to 20 seconds ### Bug Fixes - Fixed tile refresh race condition that caused half-rendered tiles and ghost tiles at certain zoom levels - Fixed Light (OSM) and Satellite (ArcGIS) tiles failing to load at low zoom on iOS retina displays ### Improvements - Faster ping cycle with reduced listen window (7s to 5s) for TX echo, discovery response, and auto-ping cooldown - Map zoom range adjusted to 3-17 - Updated repeater endpoint from /repeaters.json to /get_repeaters.php - Immediate upload on disconnect with no wait period * Regional Flood Scoping: TX pings(Active Mode) are now scoped to your region's flood zone. Regional Admins set a scope in the admin panel, so only repeaters in your region forward wardriving pings. Discovery pings are unaffected. If no scope is assigned, pings flood globally as before. * New Features Regional admins can now enforce hybrid mode per-zone via the API; when enabled, hybrid mode is automatically activated and the toggle is locked on the Settings screen with a "Forced Enabled by Regional Admin" label Regional admins can set a minimum auto-ping interval per-zone; interval options below the minimum are greyed out in Settings with a "Disabled by Regional Admin" label If a user's saved interval falls below the admin-configured minimum, it is automatically bumped up on connect * ### Improvements - Admin-enforced settings now include reworded messaging with a brief explanation of why the constraint benefits the mesh * ## Bug Fixes - Fixed RX carpeater detection checking the wrong hop position. On RX packets, the carpeater is co-located with the wardriver so it only appears as the last hop (delivery repeater), not the first. The check now correctly evaluates the last hop. * Debug logging is now enabled by default on all builds (not just dev builds), and the user's toggle preference is persisted across app restarts via Hive * The API returns "scopes":["#*"] for zones with no regional scope. The code only checked for '*' as the wildcard, so '#*' fell through to the scope-setting path. * Added dialog to upload logs window * Add Discovery Drop feature — failed discovery requests can now be reported to the API as failed pings (repeater_id: "None"), helping identify dead zones. Includes user toggle in Settings (default off), API-enforced override via disc_drop auth field, red markers on map/noise floor chart for failed discoveries when enabled. * New Feature MeshCore firmware v1.14.0+ supports multi-byte path hashes (1, 2, or 3 bytes per hop), expanding repeater ID space from 256 to 65K or 16M unique IDs. The app now fully supports this protocol change. * Add hopBytes support and update repeater display logic - Introduced hopBytes property in Repeater model to manage bytes per hop. - Updated AppStateProvider to reflect changes in path hash mode. - Enhanced connection_screen and settings_screen to accommodate hopBytes settings. - Modified map_widget to display repeater markers based on hopBytes. - Improved repeater_id_chip to show hex ID badges with dynamic sizing. * Refactor settings screen theme and unit toggles to use SwitchListTile; improve UI text for clarity * Repeater markers now rotate with the map and stay upright Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Prevent duplicate GPS stream subscriptions on restart (#6) Clean fix, guarding startWatching() against stacked subscriptions. Placement at the top of the method is correct (before any early returns). Pattern matches existing subscription management elsewhere in the codebase. * Own and dispose app-level stream subscriptions (#7) Good catch. These three stream subscriptions were the last unowned listeners in AppStateProvider. The fix mirrors the existing pattern used for _adapterStateSubscription, _logRxDataSubscription, _noiseFloorSubscription, and _batterySubscription. Clean and consistent. * Fix mobile BLE scan stream completion and cleanup (#8) Fixes a real issue: the scan stream had no termination path, which could leave callers hanging. The three cleanup paths (natural stop, manual stop, finally) cover all cases well. The identical() check on _scanController is a nice detail for rapid re-scan scenarios. Minor note: the unawaited watcher on isScanning could theoretically fire before scan results arrive if isScanning briefly emits false during startup, but the !controller.isClosed guards prevent any actual breakage. * Bump version to 1.2.0 and enhance authentication flow with staged public_key and contact_uri registration * - **Hive corruption fallback for ping queue:** When the `api_queue` Hive box fails to open (e.g. corruption), `_safeWrite()` was silently returning false and dropping all enqueued pings. A full wardrive session could complete with zero ping data uploaded, as all POSTs would be heartbeats only. Fixed by adding a `_memoryQueue` in-memory fallback: failed writes go to memory instead of being dropped, `_uploadBatch` drains both Hive and memory queues, `queueSize` reflects both, and all clear/disconnect/init paths also flush `_memoryQueue`. * Add heartbeat retry, local session expiry tracking, and offline queue preservation - Heartbeat retries on network failure with exponential backoff (5 attempts, 30s-120s) - Local session deadline timer fires at expires_at, triggers session error if backend is unreachable - On session expiry, queued wardrive data is saved as an offline session instead of discarded * Cancel stale auto-ping restore timers (#10) LGTM. Right fix, matches the pattern used by _reconnectTimer and _reconnectTimeoutTimer. The generation counter is slightly defensive given Dart's single-threaded model but adds no complexity so no complaints. * Recheck location permission after disclosure (#11) Clean separation of disclosure (show once) from permission (always recheck), plus proper permanently-denied handling * - Discovery pings now extract repeater IDs using the region's hop byte count instead of always assuming 1 byte. In multi-byte regions, TX/RX logs showed full IDs like "4E7A" while discovery logs still showed the truncated "4E" * fixed overflow in disc request byte count fix * - Added option to keep the #wardriving channel after exiting a session (#149, @skye) * - Minimum ping distance is now configurable for TX and discovery pings. The default 25m floor stays the same, but users can increase it to reduce unnecessary pings in dense city driving or stop-and-go traffic. RX batch flushing distance is unaffected. * - GPS-related zone check errors (inaccurate/stale) no longer retry every 5 seconds or auto-switch to the error tab. The next zone check waits until the user moves 100m instead of hammering retries while stationary. The zone status bar now shows a GPS icon with "GPS Unavailable" in orange, and the full-screen error view displays a specific title and message with a manual "Retry Zone Check" button. * lib/screens/settings_screen.dart — Replaced the radio button dialog with a text field. Users type any number they want (minimum 25m enforced). The field shows "meters" as a suffix and "Minimum 25m" as helper text. Save button only accepts valid integers >= 25. * - Hybrid mode now defaults to enabled for new users and existing users who haven't explicitly toggled it off. Saved preferences are preserved. * Implmented Trace Mode * - Fixed a regression where device firmware version was no longer being parsed correctly * - Redesigned the Connection tab for clarity. The previous layout was getting cluttered and hard to navigate. - Offline data session management is now always visible under Settings. * ### Bug Fixes - Fixed offline wardrive pings being lost when the app was killed by the OS, backgrounded, or disconnected mid-session - Offline pings now auto-save periodically, so at most ~60 seconds of data is lost in a worst-case app kill - Disconnecting while in offline mode now saves accumulated pings before cleanup - App backgrounding/suspension now triggers an immediate save of offline ping data * Bug 1 — Trace Mode fails after path byte mode switch: - lib/services/ping_service.dart:71: Changed final int _hopBytes to int _hopBytes and added a set hopBytes setter - lib/providers/app_state_provider.dart:1961: Added _pingService?.hopBytes = newHopBytes; in _applyLivePathHashMode() so PingService stays in sync when the user changes path mode at runtime Bug 2 — "No log files available" when only active log exists: - lib/widgets/upload_logs_dialog.dart:67: Changed DebugFileLogger.listUploadableLogFiles() to widget.appState.prepareDebugLogsForUpload() — this rotates the active log first (same pattern as BugReportSheet), so the rotated file appears in the list * ### Improvements - Auto-ping now shows "Skipped Xs" when a ping is skipped due to insufficient movement (25m minimum), replacing the generic countdown label across all UI layouts * ### New Features - Auto-stop after idle: auto-ping now automatically stops after 30 minutes of continuous skipped pings (no movement), saving battery and radio activity - New "Auto-Stop After Idle" toggle in Settings (default: ON), located under Min Ping Distance * fix trace bytes * Added Repeater Picker dropdown for traces * Final fixes for trace mode * Log tab redesign * Resigned log & settings screen * **New Features** - Live repeater snapshot: enable it in Settings to see the top 3 responded repeaters from your last ping, updating live as you wardrive **Improvements** - Redesigned the Log tab - Redesigned the Settings tab * ### Bug Fixes - Connection screen now shows a "Server Unreachable" message with offline mode suggestion when auth fails due to network errors, instead of a generic error. - Fixed zone check flooding when driving with no network. Previously, every GPS update triggered an API call when the network was down. Position is now tracked even on failed calls, so retries are handled by the 5-second timer instead. ### Improvements - Online/offline toggle redesigned to look more clearly like a button. * - Updated landscape controls to match the new portrait layout and added Trace mode support. - Updated the UI for the top heard repeaters display. * - Added text scale clamping for device accessibility settings. Previously the system text scale factor was applied unclamped across the entire app, which could break layouts at larger text sizes. * Fixing some font sizing and layouts * Fixed trace mode chip and trace icon * ### New Features - Persistent radio power overrides: custom TX power settings are now saved per device, similar to antenna selection. On connect, your previously set power override is automatically applied with a visual indicator showing it's been overridden. A "Reset to Auto" button in the power selector restores the auto-detected power for your device model. ### Improvements - Redesigned the Top Heard overlay. Now shows the repeaters that heard your most recent ping sorted by SNR, with color-coded indicators per ping type (green for TX, purple for Discovery, cyan for Trace, blue for RX). Top 3 slots show the best results from your latest ping and fully replace on each new ping. A separate RX slot shows the strongest passively overheard repeater within a rolling 5-second window. Overlay clears on auto-ping stop, mode switch, disconnect, or log clear. --------- Co-authored-by: Rob Ekl <ekl.rob@gmail.com>
MrAlders0n
added a commit
that referenced
this pull request
Mar 20, 2026
* Add offline mode prompt when zone check fails due to no internet When the zone status check fails with a network error, show a full-screen UI with an "Enable Offline Mode" button (matching the maintenance mode pattern) instead of the generic "Zone Check Failed" message. Also adds a red "No Internet" indicator in the zone status bar. Non-network errors retain the existing behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Added option to disable carpeater RSSI filter under settings * Multi-hop CARpeater packets now strip the CARpeater hop and report coverage from the underlying repeater with null SNR/RSSI, instead of being dropped entirely. Single-hop packets and discovery responses are still dropped. The -30 dBm failsafe is bypassed for packets matching your CARpeater prefix but stays active for everything else. * Added Code of Conduct & Security * Update links * Exclude .vscode/ from version control Editor-specific configs shouldn't be tracked in a public repo so contributors can use their own setups. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Bug fixes: - [#98](MeshMapper/MeshMapper_Project#98) - The heard repeaters panel now scrolls and dynamically expands to accommodate larger lists of heard repeaters - [#95](MeshMapper/MeshMapper_Project#95) - Fixed the IATA popup panel being hidden behind the Android navigation bar - Fixed a bug where a stale BLE device name was used instead of the current one * Anonymous Mode — New privacy option in Settings that renames your device to "Anonymous" for all mesh pings. When enabled, other mesh users cannot see your companion name in wardrive broadcasts. Your device's public key is still used to authenticate your session with the MeshMapper API (geo-auth), but neither your sessions nor your pings are linked to it on the server. Toggling Anonymous Mode while connected automatically disconnects and reconnects with the new identity, switching to the Connection tab so you can see reconnection progress. On proper disconnect, the original device name is restored. Persisted across app restarts. * Update repeater endpoint from /repeaters.json to /get_repeaters.php Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * ### New Features - Automatic map tile refresh after successful data upload, so new coverage appears on the map within the app near real-time - Deterministic 5-second upload timer for TX and discovery pings, replacing the old batch system that could take up to 20 seconds ### Bug Fixes - Fixed tile refresh race condition that caused half-rendered tiles and ghost tiles at certain zoom levels - Fixed Light (OSM) and Satellite (ArcGIS) tiles failing to load at low zoom on iOS retina displays ### Improvements - Faster ping cycle with reduced listen window (7s to 5s) for TX echo, discovery response, and auto-ping cooldown - Map zoom range adjusted to 3-17 - Updated repeater endpoint from /repeaters.json to /get_repeaters.php - Immediate upload on disconnect with no wait period * Regional Flood Scoping: TX pings(Active Mode) are now scoped to your region's flood zone. Regional Admins set a scope in the admin panel, so only repeaters in your region forward wardriving pings. Discovery pings are unaffected. If no scope is assigned, pings flood globally as before. * New Features Regional admins can now enforce hybrid mode per-zone via the API; when enabled, hybrid mode is automatically activated and the toggle is locked on the Settings screen with a "Forced Enabled by Regional Admin" label Regional admins can set a minimum auto-ping interval per-zone; interval options below the minimum are greyed out in Settings with a "Disabled by Regional Admin" label If a user's saved interval falls below the admin-configured minimum, it is automatically bumped up on connect * ### Improvements - Admin-enforced settings now include reworded messaging with a brief explanation of why the constraint benefits the mesh * ## Bug Fixes - Fixed RX carpeater detection checking the wrong hop position. On RX packets, the carpeater is co-located with the wardriver so it only appears as the last hop (delivery repeater), not the first. The check now correctly evaluates the last hop. * Debug logging is now enabled by default on all builds (not just dev builds), and the user's toggle preference is persisted across app restarts via Hive * The API returns "scopes":["#*"] for zones with no regional scope. The code only checked for '*' as the wildcard, so '#*' fell through to the scope-setting path. * Added dialog to upload logs window * Add Discovery Drop feature — failed discovery requests can now be reported to the API as failed pings (repeater_id: "None"), helping identify dead zones. Includes user toggle in Settings (default off), API-enforced override via disc_drop auth field, red markers on map/noise floor chart for failed discoveries when enabled. * New Feature MeshCore firmware v1.14.0+ supports multi-byte path hashes (1, 2, or 3 bytes per hop), expanding repeater ID space from 256 to 65K or 16M unique IDs. The app now fully supports this protocol change. * Add hopBytes support and update repeater display logic - Introduced hopBytes property in Repeater model to manage bytes per hop. - Updated AppStateProvider to reflect changes in path hash mode. - Enhanced connection_screen and settings_screen to accommodate hopBytes settings. - Modified map_widget to display repeater markers based on hopBytes. - Improved repeater_id_chip to show hex ID badges with dynamic sizing. * Refactor settings screen theme and unit toggles to use SwitchListTile; improve UI text for clarity * Repeater markers now rotate with the map and stay upright Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Prevent duplicate GPS stream subscriptions on restart (#6) Clean fix, guarding startWatching() against stacked subscriptions. Placement at the top of the method is correct (before any early returns). Pattern matches existing subscription management elsewhere in the codebase. * Own and dispose app-level stream subscriptions (#7) Good catch. These three stream subscriptions were the last unowned listeners in AppStateProvider. The fix mirrors the existing pattern used for _adapterStateSubscription, _logRxDataSubscription, _noiseFloorSubscription, and _batterySubscription. Clean and consistent. * Fix mobile BLE scan stream completion and cleanup (#8) Fixes a real issue: the scan stream had no termination path, which could leave callers hanging. The three cleanup paths (natural stop, manual stop, finally) cover all cases well. The identical() check on _scanController is a nice detail for rapid re-scan scenarios. Minor note: the unawaited watcher on isScanning could theoretically fire before scan results arrive if isScanning briefly emits false during startup, but the !controller.isClosed guards prevent any actual breakage. * Bump version to 1.2.0 and enhance authentication flow with staged public_key and contact_uri registration * - **Hive corruption fallback for ping queue:** When the `api_queue` Hive box fails to open (e.g. corruption), `_safeWrite()` was silently returning false and dropping all enqueued pings. A full wardrive session could complete with zero ping data uploaded, as all POSTs would be heartbeats only. Fixed by adding a `_memoryQueue` in-memory fallback: failed writes go to memory instead of being dropped, `_uploadBatch` drains both Hive and memory queues, `queueSize` reflects both, and all clear/disconnect/init paths also flush `_memoryQueue`. * Add heartbeat retry, local session expiry tracking, and offline queue preservation - Heartbeat retries on network failure with exponential backoff (5 attempts, 30s-120s) - Local session deadline timer fires at expires_at, triggers session error if backend is unreachable - On session expiry, queued wardrive data is saved as an offline session instead of discarded * Cancel stale auto-ping restore timers (#10) LGTM. Right fix, matches the pattern used by _reconnectTimer and _reconnectTimeoutTimer. The generation counter is slightly defensive given Dart's single-threaded model but adds no complexity so no complaints. * Recheck location permission after disclosure (#11) Clean separation of disclosure (show once) from permission (always recheck), plus proper permanently-denied handling * - Discovery pings now extract repeater IDs using the region's hop byte count instead of always assuming 1 byte. In multi-byte regions, TX/RX logs showed full IDs like "4E7A" while discovery logs still showed the truncated "4E" * fixed overflow in disc request byte count fix * - Added option to keep the #wardriving channel after exiting a session (#149, @skye) * - Minimum ping distance is now configurable for TX and discovery pings. The default 25m floor stays the same, but users can increase it to reduce unnecessary pings in dense city driving or stop-and-go traffic. RX batch flushing distance is unaffected. * - GPS-related zone check errors (inaccurate/stale) no longer retry every 5 seconds or auto-switch to the error tab. The next zone check waits until the user moves 100m instead of hammering retries while stationary. The zone status bar now shows a GPS icon with "GPS Unavailable" in orange, and the full-screen error view displays a specific title and message with a manual "Retry Zone Check" button. * lib/screens/settings_screen.dart — Replaced the radio button dialog with a text field. Users type any number they want (minimum 25m enforced). The field shows "meters" as a suffix and "Minimum 25m" as helper text. Save button only accepts valid integers >= 25. * - Hybrid mode now defaults to enabled for new users and existing users who haven't explicitly toggled it off. Saved preferences are preserved. * Implmented Trace Mode * - Fixed a regression where device firmware version was no longer being parsed correctly * - Redesigned the Connection tab for clarity. The previous layout was getting cluttered and hard to navigate. - Offline data session management is now always visible under Settings. * ### Bug Fixes - Fixed offline wardrive pings being lost when the app was killed by the OS, backgrounded, or disconnected mid-session - Offline pings now auto-save periodically, so at most ~60 seconds of data is lost in a worst-case app kill - Disconnecting while in offline mode now saves accumulated pings before cleanup - App backgrounding/suspension now triggers an immediate save of offline ping data * Bug 1 — Trace Mode fails after path byte mode switch: - lib/services/ping_service.dart:71: Changed final int _hopBytes to int _hopBytes and added a set hopBytes setter - lib/providers/app_state_provider.dart:1961: Added _pingService?.hopBytes = newHopBytes; in _applyLivePathHashMode() so PingService stays in sync when the user changes path mode at runtime Bug 2 — "No log files available" when only active log exists: - lib/widgets/upload_logs_dialog.dart:67: Changed DebugFileLogger.listUploadableLogFiles() to widget.appState.prepareDebugLogsForUpload() — this rotates the active log first (same pattern as BugReportSheet), so the rotated file appears in the list * ### Improvements - Auto-ping now shows "Skipped Xs" when a ping is skipped due to insufficient movement (25m minimum), replacing the generic countdown label across all UI layouts * ### New Features - Auto-stop after idle: auto-ping now automatically stops after 30 minutes of continuous skipped pings (no movement), saving battery and radio activity - New "Auto-Stop After Idle" toggle in Settings (default: ON), located under Min Ping Distance * fix trace bytes * Added Repeater Picker dropdown for traces * Final fixes for trace mode * Log tab redesign * Resigned log & settings screen * **New Features** - Live repeater snapshot: enable it in Settings to see the top 3 responded repeaters from your last ping, updating live as you wardrive **Improvements** - Redesigned the Log tab - Redesigned the Settings tab * ### Bug Fixes - Connection screen now shows a "Server Unreachable" message with offline mode suggestion when auth fails due to network errors, instead of a generic error. - Fixed zone check flooding when driving with no network. Previously, every GPS update triggered an API call when the network was down. Position is now tracked even on failed calls, so retries are handled by the 5-second timer instead. ### Improvements - Online/offline toggle redesigned to look more clearly like a button. * - Updated landscape controls to match the new portrait layout and added Trace mode support. - Updated the UI for the top heard repeaters display. * - Added text scale clamping for device accessibility settings. Previously the system text scale factor was applied unclamped across the entire app, which could break layouts at larger text sizes. * Fixing some font sizing and layouts * Fixed trace mode chip and trace icon * ### New Features - Persistent radio power overrides: custom TX power settings are now saved per device, similar to antenna selection. On connect, your previously set power override is automatically applied with a visual indicator showing it's been overridden. A "Reset to Auto" button in the power selector restores the auto-detected power for your device model. ### Improvements - Redesigned the Top Heard overlay. Now shows the repeaters that heard your most recent ping sorted by SNR, with color-coded indicators per ping type (green for TX, purple for Discovery, cyan for Trace, blue for RX). Top 3 slots show the best results from your latest ping and fully replace on each new ping. A separate RX slot shows the strongest passively overheard repeater within a rolling 5-second window. Overlay clears on auto-ping stop, mode switch, disconnect, or log clear. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Rob Ekl <ekl.rob@gmail.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Owns and disposes long-lived
AppStateProviderstream subscriptions to prevent leaked listeners and duplicate callbacks across provider lifecycle events.Problem
AppStateProvidercreated listeners for:connectionStreamstatusStreampositionStreambut did not keep/cancel those subscriptions explicitly in
dispose().That can cause lingering listeners and repeated state updates after re-init/hot-reload/provider recreation.
Changes
_connectionSubscription_gpsStatusSubscription_gpsPositionSubscription_initialize():dispose():Why this works
All app-level stream listeners are now lifecycle-owned by the provider instance and deterministically cancelled at teardown.