Siri: cheapest [fuel] near me intent + App Shortcuts (cached-first, freshness label)
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import Foundation
|
||||
|
||||
/// Pure, testable logic behind the Siri "cheapest fuel near me" intent.
|
||||
/// Foundation-only on purpose: `Shared/` joins both the app and widget
|
||||
/// targets, and FuelBoardTests exercises this directly.
|
||||
enum SiriCheapestLookup {
|
||||
|
||||
/// The cheapest station selling `fuel`, tie-broken by distance from the
|
||||
/// given point. Stations without a price for `fuel` are skipped entirely.
|
||||
/// Returns nil when no station sells the fuel.
|
||||
static func cheapest(
|
||||
in stations: [FuelStation],
|
||||
fuel: FuelType,
|
||||
fromLat lat: Double,
|
||||
lng: Double
|
||||
) -> FuelStation? {
|
||||
stations
|
||||
.filter { $0.prices[fuel] != nil }
|
||||
.min { lhs, rhs in
|
||||
guard let lp = lhs.prices[fuel], let rp = rhs.prices[fuel] else {
|
||||
return false
|
||||
}
|
||||
if lp != rp { return lp < rp }
|
||||
return lhs.distanceKM(to: lat, lng2: lng) < rhs.distanceKM(to: lat, lng2: lng)
|
||||
}
|
||||
}
|
||||
|
||||
/// A short freshness stamp for the dialog: "as of 6:30 AM".
|
||||
/// Prefers the GOV.UK `data_updated` stamp carried by the relay (ISO 8601
|
||||
/// with or without fractional seconds); falls back to the local
|
||||
/// last-refresh date; returns "" when there is no data at all.
|
||||
static func freshnessLabel(updated: String?, lastRefresh: Date?, now: Date = Date()) -> String {
|
||||
let date: Date?
|
||||
if let updated {
|
||||
date = Self.parseISO(updated) ?? lastRefresh
|
||||
} else {
|
||||
date = lastRefresh
|
||||
}
|
||||
guard let date else { return "" }
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "h:mm a"
|
||||
formatter.locale = Locale(identifier: "en_GB")
|
||||
return "as of \(formatter.string(from: date))"
|
||||
}
|
||||
|
||||
private static func parseISO(_ string: String) -> Date? {
|
||||
let withFraction = ISO8601DateFormatter()
|
||||
withFraction.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
if let date = withFraction.date(from: string) { return date }
|
||||
let plain = ISO8601DateFormatter()
|
||||
plain.formatOptions = [.withInternetDateTime]
|
||||
return plain.date(from: string)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user