Files
fuelboard/FuelBoard/AlertsView.swift
T
FuelBoard Contributor 7f7c0fff03 Alerts tab: picker-style config matching Live Activity; move Live Activity there
- Alerts section restyled to mirror the Live Activity section: one section
  with toggle + Fuel picker + Radius picker (was segmented fuel + slider)
- Alert radius options expanded to 1/2/3/5/8/10/15/20 (display unit, snapped
  to nearest option; stored km unchanged; validation widened to 33 km)
- Live Activity section moved from Settings into the Alerts tab so both
  'notify while driving' surfaces sit together
- SettingsView loses the Live Activity bindings/section
2026-08-12 22:30:54 +01:00

109 lines
5.2 KiB
Swift

import SwiftUI
/// Alerts tab — enables the cheapest-station proximity alerts and shows what's
/// being monitored. The fuel being monitored is chosen HERE, independently of
/// the Stations-tab selection: users can browse any fuel without re-targeting
/// their alerts (and vice versa). The Live Activity section also lives here —
/// it mirrors this page's shape (toggle + fuel + distance) so the two
/// "notify me while driving" surfaces sit together.
struct AlertsView: View {
@Binding var enabled: Bool
@Binding var radius: Double // stored in km (monitor + storage)
@Binding var fuel: FuelType // the fuel alerts monitor for
/// Whether the "cheapest nearby" Live Activity is shown on the Lock Screen
/// / Dynamic Island. Tracks its OWN fuel + radius (below) — independent of
/// the Stations tab.
@Binding var liveActivityEnabled: Bool
/// Fuel the Live Activity tracks (independent of the Stations tab).
@Binding var liveActivityFuel: FuelType
/// Search radius (miles, 5/10/15) the Live Activity uses.
@Binding var liveActivityRadiusMiles: Int
let distanceUnit: DistanceUnit
let monitoredCount: Int
let lastAlert: String?
/// The radius picker works in the user's chosen unit; the stored value
/// stays km so ProximityMonitor and persistence never change. Options are
/// snapped to the nearest picker value so any stored radius still selects.
private var radiusOption: Binding<Int> {
Binding(
get: {
let inUnit = distanceUnit.fromKM(radius)
return FuelStore.alertRadiusOptions
.min(by: { abs(Double($0) - inUnit) < abs(Double($1) - inUnit) }) ?? 3
},
set: { value in
radius = distanceUnit.toKM(Double(value))
}
)
}
var body: some View {
NavigationStack {
List {
Section {
Toggle("Cheapest-station alerts", isOn: $enabled)
Picker("Fuel", selection: $fuel) {
ForEach(FuelType.allCases) { fuel in
Text(fuel.displayName).tag(fuel)
}
}
Picker("Radius", selection: radiusOption) {
ForEach(FuelStore.alertRadiusOptions, id: \.self) { value in
Text("\(value) \(distanceUnit.label)").tag(value)
}
}
} header: {
Text("Cheapest-station alerts")
} footer: {
Text("When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Alerts watch for the cheapest \(fuel.displayName.lowercased()) station within the radius.")
}
if enabled {
Section("Monitoring") {
if monitoredCount == 0 {
Text("No stations monitored yet — open the Stations tab to load prices first.")
.font(.caption)
.foregroundStyle(.secondary)
} else {
LabeledContent("Geofenced stations", value: "\(monitoredCount)")
Text("Your favourites for \(fuel.displayName.lowercased()) get priority, then the closest stations selling that fuel fill the rest (18 max, iOS region limit).")
.font(.caption)
.foregroundStyle(.secondary)
Text("Alerts are checked against the cheapest station within the trigger radius for the fuel chosen above. Each station alerts at most once per hour.")
.font(.caption)
.foregroundStyle(.secondary)
}
}
if let lastAlert {
Section("Last alert") {
Label(lastAlert, systemImage: "bell.badge.fill")
.font(.footnote)
}
}
}
Section {
Toggle("Live Activity", isOn: $liveActivityEnabled)
Picker("Fuel", selection: $liveActivityFuel) {
ForEach(FuelType.allCases) { fuel in
Text(fuel.displayName).tag(fuel)
}
}
Picker("Distance", selection: $liveActivityRadiusMiles) {
ForEach(FuelStore.stationRadiusOptions, id: \.self) { miles in
Text("\(miles) \(distanceUnit.label)").tag(miles)
}
}
} header: {
Text("Live Activity")
} footer: {
Text("Shows the cheapest station for the fuel and distance you pick here on the Lock Screen and Dynamic Island — independent of the Stations tab. Updates as you drive; tap to open directions. Live Activities can be disabled in System Settings → Live Activities.")
}
}
.navigationTitle("Alerts")
}
}
}