Add Worth the Drive fuel savings with road-routed estimates
Optional Fuel Savings feature (off by default): vehicle MPG in UK imperial gallons, fill amount in pounds or litres, persisted through the existing keychain/app-group store. Ranks the WHOLE station pool by estimated net saving (fuel-price saving at each pump minus the extra return-trip driving cost) using MapKit road distances with a straight-line fallback marked (est.). The closest station with a valid price for the selected fuel is the comparison baseline and is labelled "Closest station"; other rows read "Save £X.XX after travel" / "£X.XX worse off after travel" / "Break even". Labels live in the shared model so they are unit-tested. The TOP badge still marks the cheapest pump price and reads "CHEAPEST" when the list is ranked by net saving. Road routing now prioritises the Worth-the-Drive candidates plus the baseline and merges cache entries instead of replacing them, so far-out stations get real routes rather than permanent straight-line estimates. Numeric fields gain a Done button above the keypad (decimalPad has no Return key); the fill-up control is hidden unless the feature is configured; Favourites shares one session fill amount with the station list. 131 tests.
This commit is contained in:
@@ -81,6 +81,14 @@ struct MirrorFuelProvider: FuelPriceProviding {
|
||||
)
|
||||
}
|
||||
|
||||
static func cachedStations(near lat: Double? = nil, lng: Double? = nil,
|
||||
fuel: FuelType = .e10, radiusKM: Double? = nil) -> [FuelStation]? {
|
||||
guard let cache = loadDumpCache(),
|
||||
let stations = try? FuelPriceProvider.decodeStations(from: cache.data) else { return nil }
|
||||
latestMeta = FuelPriceProvider.decodeRelayMeta(from: cache.data)
|
||||
return focused(stations, near: lat, lng: lng, fuel: fuel, radiusKM: radiusKM)
|
||||
}
|
||||
|
||||
func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double?) async throws -> [FuelStation] {
|
||||
// 1. Tiny pointer fetch — the freshest snapshot day.
|
||||
guard let latest = await FuelHistoryStore.fetchLatest(base: baseURL),
|
||||
@@ -104,10 +112,16 @@ struct MirrorFuelProvider: FuelPriceProviding {
|
||||
throw FuelProviderError.mirrorUnavailable
|
||||
}
|
||||
Self.saveDumpCache(day: day, data: fetched)
|
||||
#if DEBUG
|
||||
print("FB-STORAGE dump cached day=\(day) bytes=\(fetched.count) reuse=\(Self.canReuseCache(cachedDay: Self.loadDumpCache()?.day, latestDay: day))")
|
||||
#endif
|
||||
data = fetched
|
||||
}
|
||||
let stations = try FuelPriceProvider.decodeStations(from: data)
|
||||
Self.latestMeta = FuelPriceProvider.decodeRelayMeta(from: data)
|
||||
#if DEBUG
|
||||
print("FB-MIRROR day=\(day) bytes=\(data.count) decoded=\(stations.count)")
|
||||
#endif
|
||||
return Self.focused(stations, near: lat, lng: lng, fuel: fuel, radiusKM: radiusKM)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user