diff --git a/FuelBoard/ContentView.swift b/FuelBoard/ContentView.swift index c0c070d..f427cc6 100644 --- a/FuelBoard/ContentView.swift +++ b/FuelBoard/ContentView.swift @@ -200,7 +200,7 @@ struct ContentView: View { let fetched = try await FuelPriceProvider.active.fetchStations( near: location?.lat, lng: location?.lng, fuel: selectedFuel, - radiusKM: Double(stationLimit) * 1.60934 // miles → km + radiusKM: nil // full-UK dump; device filters by miles radius ) stations = fetched FuelStore.saveStations(fetched) diff --git a/Shared/FuelPriceProvider.swift b/Shared/FuelPriceProvider.swift index 586497a..09c4b05 100644 --- a/Shared/FuelPriceProvider.swift +++ b/Shared/FuelPriceProvider.swift @@ -13,9 +13,9 @@ import Foundation protocol FuelPriceProviding { /// Fetch stations with prices. `location` may be nil (sort by price only). - /// `radiusKM` bounds the search area (used by the relay). Throws on failure - /// so callers can fall back to cached/sample data. - func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double) async throws -> [FuelStation] + /// `radiusKM` nil = full dataset (device filters); set = focused server-side + /// radius (alert path). Throws on failure so callers can fall back. + func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double?) async throws -> [FuelStation] } enum FuelPriceProvider { @@ -32,15 +32,22 @@ enum FuelPriceProvider { struct RelayFuelProvider: FuelPriceProviding { var baseURL = URL(string: "http://192.168.1.131:8788")! - func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double) async throws -> [FuelStation] { + func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double?) async throws -> [FuelStation] { var components = URLComponents(url: baseURL.appendingPathComponent("api/v1/stations"), resolvingAgainstBaseURL: false)! var query: [URLQueryItem] = [URLQueryItem(name: "fuel", value: fuel.rawValue)] if let lat, let lng { query.append(URLQueryItem(name: "lat", value: String(lat))) query.append(URLQueryItem(name: "lng", value: String(lng))) - query.append(URLQueryItem(name: "radius", value: String(radiusKM))) } - query.append(URLQueryItem(name: "limit", value: "500")) + if let radiusKM { + // Focused fetch (alert path) — small response, server-side radius. + query.append(URLQueryItem(name: "radius", value: String(radiusKM))) + query.append(URLQueryItem(name: "limit", value: "500")) + } else { + // Full-UK dump: NO radius — the device filters locally + // (5/10/15-mile radius, fuel, sort). 10,000 covers the dataset. + query.append(URLQueryItem(name: "limit", value: "10000")) + } components.queryItems = query let (data, response) = try await URLSession.shared.data(from: components.url!) @@ -107,7 +114,7 @@ private struct RelayResponse: Codable { /// Real England-wide data comes from the relay (full-UK Fuel Finder CSV/API). /// Prices in pence/litre. struct SampleFuelProvider: FuelPriceProviding { - func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double) async throws -> [FuelStation] { + func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double?) async throws -> [FuelStation] { try await Task.sleep(nanoseconds: 300_000_000) // simulate fetch return Self.sampleStations } @@ -201,7 +208,7 @@ struct FuelFinderProvider: FuelPriceProviding { let clientID: String let clientSecret: String - func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double) async throws -> [FuelStation] { + func fetchStations(near lat: Double?, lng: Double?, fuel: FuelType, radiusKM: Double?) async throws -> [FuelStation] { // TODO: OAuth token → GET /v1/prices → map to FuelStation. // The live API requires authentication; see notes above. throw FuelProviderError.notImplemented diff --git a/Shared/FuelStore.swift b/Shared/FuelStore.swift index 9d47e5b..076469f 100644 --- a/Shared/FuelStore.swift +++ b/Shared/FuelStore.swift @@ -147,15 +147,19 @@ struct FuelStore { static let lastRefreshKey = "fuelboard.lastRefresh" // TimeInterval (seconds since 1970) // MARK: Stations + // The full-UK dataset (~2.9 MB) lives in app-group UserDefaults only — + // keychain is for small values and cannot hold it. Read order is + // defaults-first for stations (keychain may hold a legacy small set from + // older builds; the full country dump always wins). static func loadStations() -> [FuelStation] { - if let data = keychainData(service: stationsKey), + if let defaults = UserDefaults(suiteName: appGroupSuite), + let data = defaults.data(forKey: stationsKey), let stations = try? JSONDecoder().decode([FuelStation].self, from: data), !stations.isEmpty { return stations } - if let defaults = UserDefaults(suiteName: appGroupSuite), - let data = defaults.data(forKey: stationsKey), + if let data = keychainData(service: stationsKey), let stations = try? JSONDecoder().decode([FuelStation].self, from: data), !stations.isEmpty { return stations @@ -166,7 +170,7 @@ struct FuelStore { static func saveStations(_ stations: [FuelStation]) { if let data = try? JSONEncoder().encode(stations) { UserDefaults(suiteName: appGroupSuite)?.set(data, forKey: stationsKey) - writeKeychain(data: data, service: stationsKey) + // Intentionally NOT written to keychain — 2.9 MB exceeds its limits. } }