Live location tracking: continuous foreground updates (250m filter) + significant-change background monitoring; list/widget refresh and geofences follow the user, re-fetch on every move
This commit is contained in:
@@ -96,7 +96,7 @@ struct ContentView: View {
|
|||||||
.tabItem { Label("Alerts", systemImage: "bell.fill") }
|
.tabItem { Label("Alerts", systemImage: "bell.fill") }
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
locationManager.requestUpdate()
|
locationManager.startForegroundTracking()
|
||||||
monitor.update(stations: stations, favourites: refreshedFavourites,
|
monitor.update(stations: stations, favourites: refreshedFavourites,
|
||||||
fuel: selectedFuel, radiusKM: alertsRadius)
|
fuel: selectedFuel, radiusKM: alertsRadius)
|
||||||
monitor.setEnabled(alertsEnabled)
|
monitor.setEnabled(alertsEnabled)
|
||||||
@@ -104,10 +104,12 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.onChange(of: scenePhase) { _, newPhase in
|
.onChange(of: scenePhase) { _, newPhase in
|
||||||
if newPhase == .active {
|
if newPhase == .active {
|
||||||
locationManager.requestUpdate()
|
locationManager.startForegroundTracking()
|
||||||
monitor.update(stations: stations, favourites: refreshedFavourites,
|
monitor.update(stations: stations, favourites: refreshedFavourites,
|
||||||
fuel: selectedFuel, radiusKM: alertsRadius)
|
fuel: selectedFuel, radiusKM: alertsRadius)
|
||||||
Task { await refresh() }
|
Task { await refresh() }
|
||||||
|
} else {
|
||||||
|
locationManager.stopForegroundTracking()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: locationManager.current) { _, newLocation in
|
.onChange(of: locationManager.current) { _, newLocation in
|
||||||
@@ -123,6 +125,9 @@ struct ContentView: View {
|
|||||||
monitor.setEnabled(newValue)
|
monitor.setEnabled(newValue)
|
||||||
monitor.update(stations: stations, favourites: refreshedFavourites,
|
monitor.update(stations: stations, favourites: refreshedFavourites,
|
||||||
fuel: selectedFuel, radiusKM: alertsRadius)
|
fuel: selectedFuel, radiusKM: alertsRadius)
|
||||||
|
if newValue {
|
||||||
|
locationManager.startBackgroundTracking()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: alertsRadius) { _, newValue in
|
.onChange(of: alertsRadius) { _, newValue in
|
||||||
FuelStore.saveAlertsRadius(newValue)
|
FuelStore.saveAlertsRadius(newValue)
|
||||||
@@ -284,15 +289,48 @@ final class LocationManager: NSObject, ObservableObject, @preconcurrency CLLocat
|
|||||||
super.init()
|
super.init()
|
||||||
manager.delegate = self
|
manager.delegate = self
|
||||||
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
||||||
|
manager.distanceFilter = 250 // metres — re-fires while driving
|
||||||
|
manager.pausesLocationUpdatesAutomatically = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestUpdate() {
|
/// Continuous tracking while the app is in the foreground, so the list
|
||||||
|
/// re-fetches around the user's new position as they drive.
|
||||||
|
func startForegroundTracking() {
|
||||||
switch manager.authorizationStatus {
|
switch manager.authorizationStatus {
|
||||||
case .notDetermined:
|
case .notDetermined:
|
||||||
manager.requestWhenInUseAuthorization()
|
manager.requestWhenInUseAuthorization()
|
||||||
manager.requestLocation()
|
manager.requestLocation()
|
||||||
case .authorizedWhenInUse, .authorizedAlways:
|
case .authorizedWhenInUse, .authorizedAlways:
|
||||||
|
manager.startUpdatingLocation()
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One-shot fix (first launch / after permission grant).
|
||||||
|
func requestUpdate() {
|
||||||
manager.requestLocation()
|
manager.requestLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Background wake-ups on significant movement. Needs Always permission;
|
||||||
|
/// called once the user enables alerts so geofences + prices follow them.
|
||||||
|
func startBackgroundTracking() {
|
||||||
|
guard manager.authorizationStatus == .authorizedAlways else { return }
|
||||||
|
manager.startMonitoringSignificantLocationChanges()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopForegroundTracking() {
|
||||||
|
// Significant-change monitoring keeps running in the background.
|
||||||
|
manager.stopUpdatingLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
|
||||||
|
switch manager.authorizationStatus {
|
||||||
|
case .authorizedAlways:
|
||||||
|
manager.startMonitoringSignificantLocationChanges()
|
||||||
|
manager.startUpdatingLocation()
|
||||||
|
case .authorizedWhenInUse:
|
||||||
|
manager.startUpdatingLocation()
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user