Small widget: fuel-only relay fetch when no location, so default/Cheapest/Closest faces populate with real stations instead of sample data. Root cause of the persistent skeleton: favourites mode reads keychain (works on free accounts), but the non-favourites path needs stations — the app-group cache can be absent on free accounts and keychain can't hold the station dump, so with no location fix the widget fell through to SampleFuelProvider and never populated. Now when location is nil the widget fetches /api/v1/stations?fuel=X&limit=500 (fuel-only, cheapest-first, verified against the relay).
This commit is contained in:
@@ -226,6 +226,16 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
if let fetched = await Self.fetchFocused(near: location, fuel: fuel, radiusKM: radiusKM) {
|
||||
stations = fetched
|
||||
}
|
||||
} else {
|
||||
// No location (permission not granted / fix timed out): fetch
|
||||
// fuel-only UK-wide so a fresh/default widget STILL populates
|
||||
// with real stations. The app-group cache can be unavailable
|
||||
// on free accounts and keychain can't hold the station dump,
|
||||
// so the old fallback ended on sample data — the "skeleton"
|
||||
// face that never populated.
|
||||
if let fetched = await Self.fetchFuelOnly(fuel: fuel, limit: 500) {
|
||||
stations = fetched
|
||||
}
|
||||
}
|
||||
if stations.isEmpty { stations = FuelStore.loadStations() }
|
||||
if stations.isEmpty { stations = SampleFuelProvider.sampleStations }
|
||||
@@ -296,6 +306,30 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Fuel-only UK-wide fetch (no lat/lng/radius) — the relay returns the
|
||||
/// cheapest-first dataset for the fuel, bounded by limit. Used when the
|
||||
/// widget has no location fix so the face shows real stations instead of
|
||||
/// sample data. Same timeout/bounded semantics as fetchFocused.
|
||||
private static func fetchFuelOnly(fuel: FuelType, limit: Int) async -> [FuelStation]? {
|
||||
var components = URLComponents(
|
||||
url: RelayFuelProvider().baseURL.appendingPathComponent("api/v1/stations"),
|
||||
resolvingAgainstBaseURL: false
|
||||
)!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "fuel", value: fuel.rawValue),
|
||||
URLQueryItem(name: "limit", value: String(limit)),
|
||||
]
|
||||
var request = URLRequest(url: components.url!)
|
||||
request.timeoutInterval = 5
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else { return nil }
|
||||
return try? FuelPriceProvider.decodeStations(from: data)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FuelPriceWidgetView: View {
|
||||
|
||||
Reference in New Issue
Block a user