Closest mode: TOP + deltas vs the CHEAPEST within radius (not the nearest); list stays nearest-first
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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) }
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user