Tie alerts: no map, body tap doesn't direct

A tied-cheapest notification now delivers immediately with the choice
buttons and NO map snapshot (a map would only show one arbitrary
station). Tapping the notification body of a tie no longer opens
directions — nothing has been chosen; only the option buttons trigger
directions. Single-station alerts keep the embedded map + tap-to-route.
This commit is contained in:
FuelBoard Contributor
2026-08-12 11:05:21 +01:00
parent 9f579051e5
commit 6f4b6882c9
+27 -14
View File
@@ -259,12 +259,25 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
} }
let identifier = UUID().uuidString let identifier = UUID().uuidString
// Render the map FIRST, then deliver ONE notification with the map // Tie case: no map. A snapshot would only show one arbitrary station
// attached. (Earlier, delivering immediately and "replacing" via a // (the primary), which is misleading the user must pick from the
// second add() showed up as two notifications in LiveContainer the // action buttons. Deliver immediately with the choice buttons.
// replace-in-place contract isn't honoured there.) A timeout if !ties.isEmpty {
// guarantees the alert still fires, without the map, if the snapshot self.registerTieCategory(identifier: identifier, ties: ties)
// hangs. content.categoryIdentifier = "tie-\(identifier)"
mapStatus?("map: none (tie — pick a station)")
UNUserNotificationCenter.current().add(
UNNotificationRequest(identifier: identifier, content: content, trigger: nil)
)
return
}
// Single-station case: render the map FIRST, then deliver ONE
// notification with the map attached. (Earlier, delivering
// immediately and "replacing" via a second add() showed up as two
// notifications in LiveContainer the replace-in-place contract
// isn't honoured there.) A timeout guarantees the alert still fires,
// without the map, if the snapshot hangs.
mapStatus?("map: preparing…") mapStatus?("map: preparing…")
let options = MKMapSnapshotter.Options() let options = MKMapSnapshotter.Options()
@@ -280,10 +293,6 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
let deliver: (String) -> Void = { status in let deliver: (String) -> Void = { status in
guard !finished else { return } guard !finished else { return }
finished = true finished = true
if !ties.isEmpty {
self.registerTieCategory(identifier: identifier, ties: ties)
content.categoryIdentifier = "tie-\(identifier)"
}
mapStatus?(status) mapStatus?(status)
UNUserNotificationCenter.current().add( UNUserNotificationCenter.current().add(
UNNotificationRequest(identifier: identifier, content: content, trigger: nil) UNNotificationRequest(identifier: identifier, content: content, trigger: nil)
@@ -491,14 +500,16 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
/// ///
/// When the notification carried tie-choice action buttons, the tapped /// When the notification carried tie-choice action buttons, the tapped
/// button's identifier ("tie_0", "tie_1", ) selects the corresponding /// button's identifier ("tie_0", "tie_1", ) selects the corresponding
/// station from userInfo["tieStations"]; tapping the body itself falls /// station from userInfo["tieStations"]. Tapping the body of a tie
/// back to the primary station. /// notification does NOT open directions nothing has been chosen yet;
/// only the option buttons make a choice.
nonisolated func userNotificationCenter( nonisolated func userNotificationCenter(
_ center: UNUserNotificationCenter, _ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse, didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void withCompletionHandler completionHandler: @escaping () -> Void
) { ) {
let userInfo = response.notification.request.content.userInfo let userInfo = response.notification.request.content.userInfo
let isTie = userInfo["tieStations"] != nil
let name = userInfo["stationName"] as? String let name = userInfo["stationName"] as? String
let lat = userInfo["stationLat"] as? Double let lat = userInfo["stationLat"] as? Double
let lng = userInfo["stationLng"] as? Double let lng = userInfo["stationLng"] as? Double
@@ -511,12 +522,14 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
let tieLat = ties[index]["lat"] as? Double, let tieLat = ties[index]["lat"] as? Double,
let tieLng = ties[index]["lng"] as? Double { let tieLng = ties[index]["lng"] as? Double {
openDirections(to: tieName, latitude: tieLat, longitude: tieLng) openDirections(to: tieName, latitude: tieLat, longitude: tieLng)
} else if let name, let lat, let lng { } else if !isTie, let name, let lat, let lng {
openDirections(to: name, latitude: lat, longitude: lng) openDirections(to: name, latitude: lat, longitude: lng)
} }
} // Tie body tap: intentionally no directions the user must pick
// an option button to choose a station.
completionHandler() completionHandler()
} }
}
/// Opens Apple Maps with driving directions to the station; falls back to /// Opens Apple Maps with driving directions to the station; falls back to
/// the in-app map sheet when the hand-off fails. /// the in-app map sheet when the hand-off fails.