Add Settings tab: distance units toggle, onboarding replay, £4.99 tip; drop E10/E5 from labels
- FuelType labels: 'Unleaded (E10)'/'Premium (E5)' -> 'Unleaded'/'Premium' - New DistanceUnit (miles/km) preference; all app + widget distances, radii and alert text convert/display in the chosen unit - Settings tab (4th tab): segmented miles/km picker, 'Show introduction' replay button (onboarding moved out of Alerts tab), StoreKit tip £4.99 - ProximityMonitor + widget notifications use the chosen unit - Tests: label expectations updated, DistanceUnit conversion + format tests
This commit is contained in:
@@ -9,6 +9,7 @@ struct ContentView: View {
|
||||
@State private var selectedFuel: FuelType = FuelStore.loadSelectedFuel()
|
||||
@State private var sortMode: SortMode = FuelStore.loadSortMode()
|
||||
@State private var stationLimit: Int = FuelStore.loadStationLimit()
|
||||
@State private var distanceUnit: DistanceUnit = FuelStore.loadDistanceUnit()
|
||||
@State private var favourites: [FuelStation] = FuelStore.loadFavourites()
|
||||
@State private var alertsEnabled: Bool = FuelStore.loadAlertsEnabled()
|
||||
@State private var alertsRadius: Double = FuelStore.loadAlertsRadius()
|
||||
@@ -31,7 +32,7 @@ struct ContentView: View {
|
||||
let selling = stations.filter { $0.prices[selectedFuel] != nil }
|
||||
guard let location else { return selling }
|
||||
if sortMode == .closest { return selling } // radius disabled in Closest
|
||||
let radiusKM = Double(stationLimit) * 1.60934 // chosen miles → km
|
||||
let radiusKM = distanceUnit.toKM(Double(stationLimit)) // chosen units → km
|
||||
return selling.filter {
|
||||
$0.distanceKM(to: location.lat, lng2: location.lng) <= radiusKM
|
||||
}
|
||||
@@ -47,7 +48,7 @@ struct ContentView: View {
|
||||
private var baselinePrice: Double? {
|
||||
let pool = poolStations
|
||||
if sortMode == .closest, let location {
|
||||
let radiusKM = Double(stationLimit) * 1.60934 // chosen miles → km
|
||||
let radiusKM = distanceUnit.toKM(Double(stationLimit)) // chosen units → km
|
||||
let within = pool.filter {
|
||||
$0.distanceKM(to: location.lat, lng2: location.lng) <= radiusKM
|
||||
}
|
||||
@@ -111,6 +112,7 @@ struct ContentView: View {
|
||||
selectedFuel: $selectedFuel,
|
||||
sortMode: $sortMode,
|
||||
stationLimit: $stationLimit,
|
||||
distanceUnit: distanceUnit,
|
||||
baselinePrice: baselinePrice,
|
||||
topStationID: topStationID,
|
||||
location: location,
|
||||
@@ -124,6 +126,7 @@ struct ContentView: View {
|
||||
favourites: refreshedFavourites,
|
||||
selectedFuel: selectedFuel,
|
||||
location: location,
|
||||
distanceUnit: distanceUnit,
|
||||
favouriteIDs: favouriteIDs,
|
||||
onToggleFavourite: toggleFavourite
|
||||
)
|
||||
@@ -132,11 +135,17 @@ struct ContentView: View {
|
||||
AlertsView(
|
||||
enabled: $alertsEnabled,
|
||||
radius: $alertsRadius,
|
||||
distanceUnit: distanceUnit,
|
||||
monitoredCount: monitor.monitoredStationIDs.count,
|
||||
lastAlert: monitor.lastAlert,
|
||||
onShowOnboarding: { showOnboarding = true }
|
||||
lastAlert: monitor.lastAlert
|
||||
)
|
||||
.tabItem { Label("Alerts", systemImage: "bell.fill") }
|
||||
|
||||
SettingsView(
|
||||
distanceUnit: $distanceUnit,
|
||||
onShowOnboarding: { showOnboarding = true }
|
||||
)
|
||||
.tabItem { Label("Settings", systemImage: "gearshape.fill") }
|
||||
}
|
||||
.fullScreenCover(isPresented: $showOnboarding) {
|
||||
OnboardingView {
|
||||
@@ -191,8 +200,9 @@ struct ContentView: View {
|
||||
}
|
||||
.onChange(of: stationLimit) { _, newValue in
|
||||
// Distance filter is LOCAL math now — the cache holds the full-UK
|
||||
// dump, so changing 5/10/15 miles never needs a network fetch.
|
||||
// sortedStations/radiusScopedStations recompute on the next render.
|
||||
// dump, so changing 5/10/15 (miles or km) never needs a network
|
||||
// fetch. sortedStations/radiusScopedStations recompute on the
|
||||
// next render.
|
||||
FuelStore.saveStationLimit(newValue)
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
@@ -259,6 +269,7 @@ struct StationRow: View {
|
||||
let station: FuelStation
|
||||
let fuel: FuelType
|
||||
let location: Coordinate?
|
||||
let distanceUnit: DistanceUnit
|
||||
let baselinePrice: Double?
|
||||
let isTopResult: Bool
|
||||
let isFavourite: Bool
|
||||
@@ -325,7 +336,7 @@ struct StationRow: View {
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
if let location {
|
||||
Text(String(format: "%.1f mi", station.distanceKM(to: location.lat, lng2: location.lng) * 0.621371))
|
||||
Text(distanceUnit.format(station.distanceKM(to: location.lat, lng2: location.lng)))
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
.monospacedDigit()
|
||||
|
||||
Reference in New Issue
Block a user