Closest mode: TOP + deltas vs the CHEAPEST within radius (not the nearest); list stays nearest-first

This commit is contained in:
FuelBoard Contributor
2026-08-11 20:16:32 +01:00
parent 2ca1274b8f
commit 7be98c51ad
2 changed files with 29 additions and 10 deletions
+25 -7
View File
@@ -36,15 +36,32 @@ struct ContentView: View {
}
}
/// The price reference every row's delta + RAG compares against.
/// Cheapest mode the cheapest station in the pool (best value).
/// Closest mode the CLOSEST station: deltas answer "is it worth leaving
/// the station nearest to me?" (+X.Xp pricier / -X.Xp cheaper).
/// The price reference every row's delta + RAG compares against the
/// "best" of the current pool. In BOTH modes that is the CHEAPEST station
/// within the chosen miles radius (the stations you'd actually consider).
/// Cheapest mode's pool already is the radius; Closest mode lists the
/// whole country nearest-first (so it never empties), but best value is
/// still judged against what's practically reachable, so deltas stay local.
/// Fallback: if the radius has no stations, use the pool minimum.
private var baselinePrice: Double? {
if sortMode == .closest {
return sortedStations.first?.prices[selectedFuel]
let pool = poolStations
if sortMode == .closest, let location {
let radiusKM = Double(stationLimit) * 1.60934 // chosen miles km
let within = pool.filter {
$0.distanceKM(to: location.lat, lng2: location.lng) <= radiusKM
}
return poolStations.compactMap { $0.prices[selectedFuel] }.min()
if let localMin = within.compactMap({ $0.prices[selectedFuel] }).min() {
return localMin
}
}
return pool.compactMap { $0.prices[selectedFuel] }.min()
}
/// The "best" station the cheapest in the pool gets the TOP badge.
/// First occurrence in display order wins on price ties.
private var topStationID: String? {
guard let baselinePrice else { return nil }
return displayedStations.first { $0.prices[selectedFuel] == baselinePrice }?.id
}
private var displayedStations: [FuelStation] {
@@ -94,6 +111,7 @@ struct ContentView: View {
sortMode: $sortMode,
stationLimit: $stationLimit,
baselinePrice: baselinePrice,
topStationID: topStationID,
location: location,
favouriteIDs: favouriteIDs,
onToggleFavourite: toggleFavourite,
+4 -3
View File
@@ -10,6 +10,7 @@ struct StationsView: View {
@Binding var sortMode: SortMode
@Binding var stationLimit: Int
let baselinePrice: Double?
let topStationID: String?
let location: Coordinate?
let favouriteIDs: Set<String>
var onToggleFavourite: (FuelStation) -> Void = { _ in }
@@ -28,7 +29,7 @@ struct StationsView: View {
Section {
if let location {
if sortMode == .closest {
Text("Closest \(selectedFuel.displayName) stations — tap a station for directions.")
Text("Closest \(selectedFuel.displayName) stations — nearest first, best value within \(stationLimit) miles.")
.font(.footnote)
.foregroundStyle(.secondary)
} else {
@@ -105,13 +106,13 @@ struct StationsView: View {
Text("No \(selectedFuel.displayName) stations found.")
.foregroundStyle(.secondary)
} else {
ForEach(Array(stations.prefix(visibleCount).enumerated()), id: \.element.id) { index, station in
ForEach(Array(stations.prefix(visibleCount)), id: \.id) { station in
StationRow(
station: station,
fuel: selectedFuel,
location: location,
baselinePrice: baselinePrice,
isTopResult: index == 0,
isTopResult: station.id == topStationID,
isFavourite: favouriteIDs.contains(station.id),
onToggleFavourite: { onToggleFavourite(station) }
)