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. /// The price reference every row's delta + RAG compares against the
/// Cheapest mode the cheapest station in the pool (best value). /// "best" of the current pool. In BOTH modes that is the CHEAPEST station
/// Closest mode the CLOSEST station: deltas answer "is it worth leaving /// within the chosen miles radius (the stations you'd actually consider).
/// the station nearest to me?" (+X.Xp pricier / -X.Xp cheaper). /// 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? { private var baselinePrice: Double? {
if sortMode == .closest { let pool = poolStations
return sortedStations.first?.prices[selectedFuel] 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
}
if let localMin = within.compactMap({ $0.prices[selectedFuel] }).min() {
return localMin
}
} }
return poolStations.compactMap { $0.prices[selectedFuel] }.min() 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] { private var displayedStations: [FuelStation] {
@@ -94,6 +111,7 @@ struct ContentView: View {
sortMode: $sortMode, sortMode: $sortMode,
stationLimit: $stationLimit, stationLimit: $stationLimit,
baselinePrice: baselinePrice, baselinePrice: baselinePrice,
topStationID: topStationID,
location: location, location: location,
favouriteIDs: favouriteIDs, favouriteIDs: favouriteIDs,
onToggleFavourite: toggleFavourite, onToggleFavourite: toggleFavourite,
+4 -3
View File
@@ -10,6 +10,7 @@ struct StationsView: View {
@Binding var sortMode: SortMode @Binding var sortMode: SortMode
@Binding var stationLimit: Int @Binding var stationLimit: Int
let baselinePrice: Double? let baselinePrice: Double?
let topStationID: String?
let location: Coordinate? let location: Coordinate?
let favouriteIDs: Set<String> let favouriteIDs: Set<String>
var onToggleFavourite: (FuelStation) -> Void = { _ in } var onToggleFavourite: (FuelStation) -> Void = { _ in }
@@ -28,7 +29,7 @@ struct StationsView: View {
Section { Section {
if let location { if let location {
if sortMode == .closest { 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) .font(.footnote)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} else { } else {
@@ -105,13 +106,13 @@ struct StationsView: View {
Text("No \(selectedFuel.displayName) stations found.") Text("No \(selectedFuel.displayName) stations found.")
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} else { } else {
ForEach(Array(stations.prefix(visibleCount).enumerated()), id: \.element.id) { index, station in ForEach(Array(stations.prefix(visibleCount)), id: \.id) { station in
StationRow( StationRow(
station: station, station: station,
fuel: selectedFuel, fuel: selectedFuel,
location: location, location: location,
baselinePrice: baselinePrice, baselinePrice: baselinePrice,
isTopResult: index == 0, isTopResult: station.id == topStationID,
isFavourite: favouriteIDs.contains(station.id), isFavourite: favouriteIDs.contains(station.id),
onToggleFavourite: { onToggleFavourite(station) } onToggleFavourite: { onToggleFavourite(station) }
) )