From 8945190da54aaaff2e0255e9527ac127c8014db8 Mon Sep 17 00:00:00 2001 From: FuelBoard Contributor Date: Tue, 18 Aug 2026 17:59:03 +0100 Subject: [PATCH] fix: keep live activity in sync with motion --- FuelBoard/ContentView.swift | 45 +++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/FuelBoard/ContentView.swift b/FuelBoard/ContentView.swift index bd6a956..7563435 100644 --- a/FuelBoard/ContentView.swift +++ b/FuelBoard/ContentView.swift @@ -32,6 +32,24 @@ struct ContentView: View { private var effectiveAlertsRadiusKM: Double { FuelStore.effectiveAlertsRadiusKM(followsSearch: alertsFollowsSearch, manualKM: alertsRadius) } + + private func installLocationUpdateHook() { + locationManager.onLocationUpdate = { [weak monitor] in + monitor?.update(stations: stations, favourites: refreshedFavourites, + fuel: alertsFuel, radiusKM: effectiveAlertsRadiusKM) + // The Live Activity follows the same wake-ups — this hook + // fires on every fix incl. background significant-change + // wake-ups, so the Lock Screen pill stays live while driving. + updateLiveActivity() + } + } + + private func ensureBackgroundMotionTrackingIfNeeded() { + if alertsEnabled || liveActivityEnabled { + locationManager.startBackgroundTracking() + } + } + @State private var isLoading = false @State private var statusMessage = "" /// What data is on screen, driving which (if any) status banner shows @@ -266,20 +284,12 @@ struct ContentView: View { if FuelStore.loadHasCompletedOnboarding() || shouldSkipOnboarding { locationManager.startForegroundTracking() - // Geofences must follow the user even in the background: - // wire the delegate hook (fires on every fix incl. background - // significant-change wake-ups) to re-register the region - // window around the new position. SwiftUI onChange alone - // never runs while suspended, so alerts would otherwise stay - // frozen around the last foreground fix. - locationManager.onLocationUpdate = { [weak monitor] in - monitor?.update(stations: stations, favourites: refreshedFavourites, - fuel: alertsFuel, radiusKM: effectiveAlertsRadiusKM) - // The Live Activity follows the same wake-ups — this hook - // fires on every fix incl. background significant-change - // wake-ups, so the Lock Screen pill stays live while driving. - updateLiveActivity() - } + // Geofences and the Live Activity must follow the user even in + // the background: wire the delegate hook (fires on every fix + // incl. background significant-change wake-ups) so SwiftUI's + // foreground-only onChange isn't the only update path. + installLocationUpdateHook() + ensureBackgroundMotionTrackingIfNeeded() monitor.update(stations: stations, favourites: refreshedFavourites, fuel: alertsFuel, radiusKM: effectiveAlertsRadiusKM) monitor.setEnabled(alertsEnabled) @@ -310,6 +320,8 @@ struct ContentView: View { // empty on a brand-new install. if !showing, FuelStore.loadHasCompletedOnboarding() { locationManager.startForegroundTracking() + installLocationUpdateHook() + ensureBackgroundMotionTrackingIfNeeded() monitor.update(stations: stations, favourites: refreshedFavourites, fuel: alertsFuel, radiusKM: effectiveAlertsRadiusKM) updateLiveActivity() @@ -373,9 +385,7 @@ struct ContentView: View { monitor.setEnabled(newValue) monitor.update(stations: stations, favourites: refreshedFavourites, fuel: alertsFuel, radiusKM: effectiveAlertsRadiusKM) - if newValue { - locationManager.startBackgroundTracking() - } + ensureBackgroundMotionTrackingIfNeeded() } .onChange(of: alertsRadius) { _, newValue in FuelStore.saveAlertsRadius(newValue) @@ -406,6 +416,7 @@ struct ContentView: View { // Toggling the Live Activity on starts it with the current best // station; toggling off ends any running activity. FuelStore.saveLiveActivityEnabled(newValue) + ensureBackgroundMotionTrackingIfNeeded() updateLiveActivity() } .onChange(of: liveActivityFuel) { _, newValue in