From 6a9b5df4f1fd6b2778efbd27f868a59a5f28072e Mon Sep 17 00:00:00 2001 From: FuelBoard Contributor Date: Sat, 17 Oct 2026 13:41:11 +0100 Subject: [PATCH] Alerts tab: disable option rows when their setting is off --- FuelBoard/AlertsView.swift | 106 ++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/FuelBoard/AlertsView.swift b/FuelBoard/AlertsView.swift index 75a3112..4be101d 100644 --- a/FuelBoard/AlertsView.swift +++ b/FuelBoard/AlertsView.swift @@ -145,18 +145,64 @@ struct AlertsView: View { ) } + /// The radius currently selected, in the user's unit — shown by the disabled + /// row in place of the picker. + private var alertRadiusValueLabel: String { + switch alertChoice.wrappedValue { + case .followSearch: + return String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel) + case .fixed(let value): + return String(format: String(localized: "%lld %@", comment: "Distance label"), value, distanceUnit.label(for: Double(value))) + } + } + + private var laDistanceValueLabel: String { + switch laChoice.wrappedValue { + case .followSearch: + return String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel) + case .fixed(let miles): + return distanceLabel(forMiles: miles) + } + } + + /// An option row that belongs to a toggle. When the toggle is off the control + /// is replaced by a dimmed, static value row: `.disabled` is not enough here + /// because an inline-style picker in a List still expands its options when + /// tapped while disabled. + @ViewBuilder + private func optionRow(_ title: String, + value: String, + isEnabled: Bool, + @ViewBuilder picker: () -> Content) -> some View { + if isEnabled { + picker() + } else { + HStack { + Text(title) + Spacer() + Text(value) + } + .foregroundStyle(.tertiary) + } + } + var body: some View { NavigationStack { List { Section { Toggle(String(localized: "Cheapest favourite", comment: "Favourite price-drop alert toggle"), isOn: $favouriteDropEnabled) - Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $favouriteDropFuel) { - ForEach(FuelType.allCases) { fuel in - Text(fuel.displayName).tag(fuel) + optionRow(String(localized: "Fuel", comment: "Fuel picker title"), + value: favouriteDropFuel.displayName, + isEnabled: favouriteDropEnabled) { + Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $favouriteDropFuel) { + ForEach(FuelType.allCases) { fuel in + Text(fuel.displayName).tag(fuel) + } } } Button(String(localized: "Check now", comment: "Manual favourite price-drop check button"), action: onCheckFavouriteDropNow) .disabled(!favouriteDropEnabled) + .allowsHitTesting(favouriteDropEnabled) Text(String(localized: "Get notified when a different favourite becomes the cheapest, or your cheapest favourite drops in price.", comment: "Favourite price alerts section description")) .font(.footnote) .foregroundStyle(.secondary) @@ -166,9 +212,13 @@ struct AlertsView: View { Section { Toggle(String(localized: "Cheapest station", comment: "Proximity alert toggle"), isOn: $enabled) - Picker(String(localized: "Alert type", comment: "Proximity alert type picker title"), selection: $alertMode) { - ForEach(AlertMode.allCases.filter { mode in mode != .bestValue || bestValueConfigured }) { mode in - Text(mode.displayName).tag(mode) + optionRow(String(localized: "Alert type", comment: "Proximity alert type picker title"), + value: alertMode.displayName, + isEnabled: enabled) { + Picker(String(localized: "Alert type", comment: "Proximity alert type picker title"), selection: $alertMode) { + ForEach(AlertMode.allCases.filter { mode in mode != .bestValue || bestValueConfigured }) { mode in + Text(mode.displayName).tag(mode) + } } } if !bestValueConfigured { @@ -188,15 +238,23 @@ struct AlertsView: View { .font(.footnote) .foregroundStyle(.secondary) } - Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $fuel) { - ForEach(FuelType.allCases) { fuel in - Text(fuel.displayName).tag(fuel) + optionRow(String(localized: "Fuel", comment: "Fuel picker title"), + value: fuel.displayName, + isEnabled: enabled) { + Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $fuel) { + ForEach(FuelType.allCases) { fuel in + Text(fuel.displayName).tag(fuel) + } } } - Picker(String(localized: "Radius", comment: "Alert radius picker title"), selection: alertChoice) { - Text(String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel)).tag(AlertRadiusChoice.followSearch) - ForEach(FuelStore.alertRadiusOptions, id: \.self) { value in - Text(String(format: String(localized: "%lld %@", comment: "Distance label"), value, distanceUnit.label(for: Double(value)))).tag(AlertRadiusChoice.fixed(value)) + optionRow(String(localized: "Radius", comment: "Alert radius picker title"), + value: alertRadiusValueLabel, + isEnabled: enabled) { + Picker(String(localized: "Radius", comment: "Alert radius picker title"), selection: alertChoice) { + Text(String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel)).tag(AlertRadiusChoice.followSearch) + ForEach(FuelStore.alertRadiusOptions, id: \.self) { value in + Text(String(format: String(localized: "%lld %@", comment: "Distance label"), value, distanceUnit.label(for: Double(value)))).tag(AlertRadiusChoice.fixed(value)) + } } } Text(alertRadiusDescription) @@ -223,15 +281,23 @@ struct AlertsView: View { Section { Toggle(String(localized: "Cheapest station", comment: "Live Activity toggle"), isOn: $liveActivityEnabled) - Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $liveActivityFuel) { - ForEach(FuelType.allCases) { fuel in - Text(fuel.displayName).tag(fuel) + optionRow(String(localized: "Fuel", comment: "Fuel picker title"), + value: liveActivityFuel.displayName, + isEnabled: liveActivityEnabled) { + Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $liveActivityFuel) { + ForEach(FuelType.allCases) { fuel in + Text(fuel.displayName).tag(fuel) + } } } - Picker(String(localized: "Distance", comment: "Distance picker title"), selection: laChoice) { - Text(String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel)).tag(LADistanceChoice.followSearch) - ForEach(FuelStore.stationRadiusOptions, id: \.self) { miles in - Text(distanceLabel(forMiles: miles)).tag(LADistanceChoice.fixed(miles)) + optionRow(String(localized: "Distance", comment: "Distance picker title"), + value: laDistanceValueLabel, + isEnabled: liveActivityEnabled) { + Picker(String(localized: "Distance", comment: "Distance picker title"), selection: laChoice) { + Text(String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel)).tag(LADistanceChoice.followSearch) + ForEach(FuelStore.stationRadiusOptions, id: \.self) { miles in + Text(distanceLabel(forMiles: miles)).tag(LADistanceChoice.fixed(miles)) + } } } if liveActivityFollowsSearch {