Alerts: trigger on approach — geofence radius = alert radius
- Region radius changed from fixed 300 m forecourt fence to the alert radius (the Alerts-tab slider), clamped to the device's maximumRegionMonitoringDistance. - Notification now fires when you ENTER the winner's circle while approaching, not when you reach the forecourt. - Cheapest-gate unchanged: still only fires when the entered station is the cheapest within the alert radius (fresh prices). Dedup still 1/ station/hour. 35 tests pass.
This commit is contained in:
@@ -41,6 +41,9 @@ struct TieChoice {
|
|||||||
///
|
///
|
||||||
/// Region budget: iOS allows 20 monitored regions per app — favourites are
|
/// Region budget: iOS allows 20 monitored regions per app — favourites are
|
||||||
/// always registered first, then the closest remaining stations fill the rest.
|
/// always registered first, then the closest remaining stations fill the rest.
|
||||||
|
/// Each region is a circle around a station with radius = the alert radius
|
||||||
|
/// (clamped to the device ceiling), so the notification fires on APPROACH —
|
||||||
|
/// entering the winner's circle — not at the forecourt.
|
||||||
@MainActor
|
@MainActor
|
||||||
final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLocationManagerDelegate, UNUserNotificationCenterDelegate {
|
final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLocationManagerDelegate, UNUserNotificationCenterDelegate {
|
||||||
@Published var monitoredStationIDs: [String] = []
|
@Published var monitoredStationIDs: [String] = []
|
||||||
@@ -117,10 +120,17 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
|
|||||||
candidates.append(contentsOf: others)
|
candidates.append(contentsOf: others)
|
||||||
|
|
||||||
var registered: [String] = []
|
var registered: [String] = []
|
||||||
|
// Trigger radius = the ALERT radius (approach heads-up), not a tiny
|
||||||
|
// forecourt fence: entering the winner's region means you're within
|
||||||
|
// the alert radius of it, and the notification fires as you approach.
|
||||||
|
// Clamp to the device's region-monitoring ceiling — registering a
|
||||||
|
// larger region fails (kCLErrorRegionMonitoringFailure) or is reduced.
|
||||||
|
let maxRegion = manager.maximumRegionMonitoringDistance
|
||||||
|
let triggerRadius = maxRegion > 0 ? min(radiusKM * 1000, maxRegion) : radiusKM * 1000
|
||||||
for station in candidates.prefix(18) where station.prices[fuel] != nil {
|
for station in candidates.prefix(18) where station.prices[fuel] != nil {
|
||||||
let region = CLCircularRegion(
|
let region = CLCircularRegion(
|
||||||
center: CLLocationCoordinate2D(latitude: station.lat, longitude: station.lng),
|
center: CLLocationCoordinate2D(latitude: station.lat, longitude: station.lng),
|
||||||
radius: 300,
|
radius: triggerRadius,
|
||||||
identifier: station.id
|
identifier: station.id
|
||||||
)
|
)
|
||||||
region.notifyOnEntry = true
|
region.notifyOnEntry = true
|
||||||
|
|||||||
Reference in New Issue
Block a user