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:
FuelBoard Contributor
2026-08-12 07:46:08 +01:00
parent fb79cf0788
commit 44c6c38536
10 changed files with 284 additions and 47 deletions
+13 -18
View File
@@ -4,10 +4,14 @@ import SwiftUI
/// being monitored.
struct AlertsView: View {
@Binding var enabled: Bool
@Binding var radius: Double
@Binding var radius: Double // stored in km (monitor + storage)
let distanceUnit: DistanceUnit
let monitoredCount: Int
let lastAlert: String?
var onShowOnboarding: () -> Void = {}
/// The radius slider works in the user's chosen unit; the stored value
/// stays km so ProximityMonitor and persistence never change.
private var radiusInUnit: Double { distanceUnit.fromKM(radius) }
var body: some View {
NavigationStack {
@@ -24,11 +28,15 @@ struct AlertsView: View {
HStack {
Text("Radius")
Spacer()
Text("\(Int(radius)) km")
Text(String(format: "%.1f %@", radiusInUnit, distanceUnit.shortName))
.foregroundStyle(.secondary)
.monospacedDigit()
}
Slider(value: $radius, in: 1...10, step: 1)
// 110 in the user's unit; convert back to km on change.
Slider(value: Binding(
get: { radiusInUnit },
set: { radius = distanceUnit.toKM($0) }
), in: 1...10, step: distanceUnit == .kilometers ? 1 : 0.5)
}
}
@@ -42,7 +50,7 @@ struct AlertsView: View {
Text("Your favourites get priority, then the closest stations fill the rest (18 max, iOS region limit).")
.font(.caption)
.foregroundStyle(.secondary)
Text("Alerts are checked against the cheapest station within \(Int(radius)) km for the selected fuel. Each station alerts at most once per hour.")
Text("Alerts are checked against the cheapest station within the trigger radius for the selected fuel. Each station alerts at most once per hour.")
.font(.caption)
.foregroundStyle(.secondary)
}
@@ -55,19 +63,6 @@ struct AlertsView: View {
}
}
}
// Testing hook in production onboarding shows once at first
// launch; this button re-opens it to verify the flow.
Section {
Button {
onShowOnboarding()
} label: {
Label("Show onboarding (testing)", systemImage: "flag.fill")
.font(.footnote)
}
} footer: {
Text("Testing only — onboarding normally appears once on first launch.")
}
}
.navigationTitle("Alerts")
}