diff --git a/FuelBoard/ContentView.swift b/FuelBoard/ContentView.swift index 9eb2169..0c5c9c3 100644 --- a/FuelBoard/ContentView.swift +++ b/FuelBoard/ContentView.swift @@ -21,8 +21,20 @@ struct ContentView: View { @State private var locationManager = LocationManager() @StateObject private var monitor = ProximityMonitor() + /// Stations within the alert trigger radius of the current location, used + /// as the pool for "cheapest" (RAG reference, TOP, sorting). Falls back to + /// the full fetch when location is unknown or the radius pool is empty + /// (rural areas) so the list is never blank. + private var radiusScopedStations: [FuelStation] { + guard let location else { return stations } + let within = stations.filter { + $0.distanceKM(to: location.lat, lng2: location.lng) <= alertsRadius + } + return within.isEmpty ? stations : within + } + private var cheapestPrice: Double? { - stations.compactMap { $0.prices[selectedFuel] }.min() + radiusScopedStations.compactMap { $0.prices[selectedFuel] }.min() } private var displayedStations: [FuelStation] { @@ -30,7 +42,7 @@ struct ContentView: View { } private var sortedStations: [FuelStation] { - let available = stations.filter { $0.prices[selectedFuel] != nil } + let available = radiusScopedStations.filter { $0.prices[selectedFuel] != nil } switch sortMode { case .closest: guard let location else { return available.sorted { $0.prices[selectedFuel]! < $1.prices[selectedFuel]! } } @@ -73,6 +85,7 @@ struct ContentView: View { stationLimit: $stationLimit, cheapestPrice: cheapestPrice, location: location, + radiusKM: alertsRadius, favouriteIDs: favouriteIDs, onToggleFavourite: toggleFavourite ) diff --git a/FuelBoard/StationsView.swift b/FuelBoard/StationsView.swift index 9a71b9f..9f839c2 100644 --- a/FuelBoard/StationsView.swift +++ b/FuelBoard/StationsView.swift @@ -11,6 +11,7 @@ struct StationsView: View { @Binding var stationLimit: Int let cheapestPrice: Double? let location: Coordinate? + let radiusKM: Double let favouriteIDs: Set var onToggleFavourite: (FuelStation) -> Void = { _ in } @@ -18,9 +19,15 @@ struct StationsView: View { NavigationStack { List { Section { - Text("\(sortMode == .closest ? "Closest" : "Cheapest") \(selectedFuel.displayName) — tap a station for directions.") - .font(.footnote) - .foregroundStyle(.secondary) + if let location { + Text("\(sortMode == .closest ? "Closest" : "Cheapest") \(selectedFuel.displayName) within \(Int(radiusKM)) km — tap a station for directions.") + .font(.footnote) + .foregroundStyle(.secondary) + } else { + Text("\(sortMode == .closest ? "Closest" : "Cheapest") \(selectedFuel.displayName) — tap a station for directions.") + .font(.footnote) + .foregroundStyle(.secondary) + } } Section("Fuel type") { diff --git a/FuelBoardWidgets/FuelPriceWidget.swift b/FuelBoardWidgets/FuelPriceWidget.swift index 792fe22..845631e 100644 --- a/FuelBoardWidgets/FuelPriceWidget.swift +++ b/FuelBoardWidgets/FuelPriceWidget.swift @@ -84,9 +84,17 @@ struct FuelPriceTimelineProvider: TimelineProvider { FuelStore.saveLocation(lat: location.lat, lng: location.lng) } - // 3) Load stations, then sort by distance-weighted score. + // 3) Load stations, then sort by price (distance tiebreak), scoped to + // the alert trigger radius so the widget's "cheapest" matches the app. var stations = FuelStore.loadStations() if stations.isEmpty { stations = SampleFuelProvider.sampleStations } + let radiusKM = FuelStore.loadAlertsRadius() + if let location { + let within = stations.filter { + $0.distanceKM(to: location.lat, lng2: location.lng) <= radiusKM + } + if !within.isEmpty { stations = within } + } let filtered = stations.filter { $0.prices[fuel] != nil } let sorted: [FuelStation] if let location {