Tabs (Stations/Favourites/Alerts): favourites with cheapest-first ranking, proximity geofence alerts (favourites priority, 3km default radius, 1h dedup), Always location + background mode
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import SwiftUI
|
||||
|
||||
/// Favourites tab — starred stations, ranked cheapest-first for the selected
|
||||
/// fuel, with the cheapest favourite called out at the top.
|
||||
struct FavouritesView: View {
|
||||
let favourites: [FuelStation]
|
||||
let selectedFuel: FuelType
|
||||
let location: Coordinate?
|
||||
let favouriteIDs: Set<String>
|
||||
var onToggleFavourite: (FuelStation) -> Void = { _ in }
|
||||
|
||||
/// Favourites that sell the selected fuel, cheapest first (distance tiebreak).
|
||||
private var ranked: [FuelStation] {
|
||||
let available = favourites.filter { $0.prices[selectedFuel] != nil }
|
||||
return available.sorted { lhs, rhs in
|
||||
let lPrice = lhs.prices[selectedFuel]!
|
||||
let rPrice = rhs.prices[selectedFuel]!
|
||||
if lPrice != rPrice { return lPrice < rPrice }
|
||||
guard let location else { return false }
|
||||
return lhs.distanceKM(to: location.lat, lng2: location.lng) <
|
||||
rhs.distanceKM(to: location.lat, lng2: location.lng)
|
||||
}
|
||||
}
|
||||
|
||||
private var cheapest: FuelStation? { ranked.first }
|
||||
private var cheapestPrice: Double? { cheapest?.prices[selectedFuel] }
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
if favourites.isEmpty {
|
||||
Section {
|
||||
VStack(spacing: 10) {
|
||||
Image(systemName: "star")
|
||||
.font(.system(size: 40))
|
||||
.foregroundStyle(.secondary)
|
||||
Text("No favourites yet")
|
||||
.font(.headline)
|
||||
Text("Tap the star on any station in the Stations tab to pin it here, ranked by which is cheapest.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 24)
|
||||
}
|
||||
} else {
|
||||
Section {
|
||||
if let cheapest, let price = cheapestPrice {
|
||||
HStack(spacing: 10) {
|
||||
Image(systemName: "crown.fill")
|
||||
.foregroundStyle(.yellow)
|
||||
Text("Cheapest favourite: \(cheapest.name) — \(String(format: "%.1fp", price))")
|
||||
.font(.footnote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section("Favourites — cheapest first") {
|
||||
ForEach(Array(ranked.enumerated()), id: \.element.id) { index, station in
|
||||
StationRow(
|
||||
station: station,
|
||||
fuel: selectedFuel,
|
||||
location: location,
|
||||
cheapestPrice: cheapestPrice,
|
||||
isTopResult: index == 0,
|
||||
isFavourite: favouriteIDs.contains(station.id),
|
||||
onToggleFavourite: { onToggleFavourite(station) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if let cheapest = cheapest {
|
||||
Section {
|
||||
Text("\(cheapest.name) is your cheapest favourite for \(selectedFuel.displayName). Add the same stations to the Alerts tab to get pinged when you drive past a cheaper one.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Favourites")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user