feat: honour Tap station action on notification and Live Activity taps

Notification body/action taps route through StationTapAction:
Open map opens Apple Maps (existing); More info presents the
in-app detail sheet (falls back to the map sheet when the
station is not in cache).

Live Activity Lock Screen card and island station row pick
their Link destination the same way: Maps URL for Open map,
fuelboard://station deep link for More info, handled in
FuelBoardApp and observed by ContentView.

Also adds the small non-interactive map preview above the
Directions button in the More info sheet.
This commit is contained in:
FuelBoard Contributor
2026-09-16 13:11:36 +01:00
parent 1299b4a004
commit 465e6cd4d4
6 changed files with 108 additions and 14 deletions
+29 -5
View File
@@ -84,6 +84,9 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
@Published var lastAlert: String?
@Published private(set) var lastTestResult: String?
@Published var pendingStationMap: StationMapRequest?
/// Station tapped via notification when Settings Tap station = More info.
/// ContentView presents this as a StationDetailView sheet.
@Published var pendingDetailStation: FuelStation?
/// Debug-only snapshot for the Settings Debug section. Recomputed on
/// every location/stations change via `refreshDebugStatus()`.
@Published private(set) var debugStatus: DebugLocationStatus?
@@ -791,9 +794,11 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
}
}
/// Tapping a notification opens Apple Maps directions to the station from
/// the user's current location. If Apple Maps can't be opened (e.g. inside
/// LiveContainer), an in-app map sheet with directions is shown instead.
/// Tapping a notification honours Settings Tap station: Open map opens
/// Apple Maps directions to the station from the user's current location;
/// More info opens the station's detail sheet in the app instead. If Apple
/// Maps can't be opened (e.g. inside LiveContainer), an in-app map sheet
/// with directions is shown instead.
///
/// When the notification carried tie-choice action buttons, the tapped
/// button's identifier ("tie_0", "tie_1", ) selects the corresponding
@@ -818,9 +823,9 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
let tieName = ties[index]["name"] as? String,
let tieLat = ties[index]["lat"] as? Double,
let tieLng = ties[index]["lng"] as? Double {
openDirections(to: tieName, latitude: tieLat, longitude: tieLng)
routeNotificationTap(name: tieName, latitude: tieLat, longitude: tieLng)
} else if !isTie, let name, let lat, let lng {
openDirections(to: name, latitude: lat, longitude: lng)
routeNotificationTap(name: name, latitude: lat, longitude: lng)
}
// Tie body tap: intentionally no directions the user must pick
// an option button to choose a station.
@@ -828,6 +833,25 @@ final class ProximityMonitor: NSObject, ObservableObject, @preconcurrency CLLoca
}
}
/// Routes a resolved notification tap through the user's Tap station
/// preference: Open map Apple Maps; More info in-app detail sheet
/// (falling back to the map sheet when the station isn't in cache).
@MainActor
private func routeNotificationTap(name: String, latitude: Double, longitude: Double) {
guard FuelStore.loadStationTapAction() == .showDetails else {
openDirections(to: name, latitude: latitude, longitude: longitude)
return
}
if let station = stations.first(where: { $0.lat == latitude && $0.lng == longitude })
?? stations.first(where: { $0.name == name }) {
pendingDetailStation = station
} else {
// Station not in cache (e.g. data refreshed since the alert fired)
// fall back to the map sheet so the tap still shows something.
pendingStationMap = StationMapRequest(name: name, latitude: latitude, longitude: longitude)
}
}
/// Opens Apple Maps with driving directions to the station; falls back to
/// the in-app map sheet when the hand-off fails.
@MainActor