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.
|
/// 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,
|
||||||
|
|||||||
@@ -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) }
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user