Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a9b5df4f1 | ||
|
|
1cd4d86a69 |
+146
-63
@@ -6,8 +6,8 @@ import SwiftUI
|
|||||||
/// versa). The Live Activity section also lives here — it mirrors this page's
|
/// versa). The Live Activity section also lives here — it mirrors this page's
|
||||||
/// shape (toggle + fuel + distance) so the two "notify me while driving"
|
/// shape (toggle + fuel + distance) so the two "notify me while driving"
|
||||||
/// surfaces sit together. Geofence plumbing (count, 18-limit) lives in
|
/// surfaces sit together. Geofence plumbing (count, 18-limit) lives in
|
||||||
/// Settings → Debug; the user-facing page keeps a plain-language explainer
|
/// Settings → Debug; the user-facing page keeps short descriptions that follow
|
||||||
/// plus a 0-stations hint.
|
/// the selected alert type and radius, plus a 0-stations hint.
|
||||||
struct AlertsView: View {
|
struct AlertsView: View {
|
||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
@Binding var radius: Double // stored in km (monitor + storage)
|
@Binding var radius: Double // stored in km (monitor + storage)
|
||||||
@@ -55,31 +55,40 @@ struct AlertsView: View {
|
|||||||
return String(format: String(localized: "%lld %@", comment: "Distance label"), shown, distanceUnit.label(for: Double(shown)))
|
return String(format: String(localized: "%lld %@", comment: "Distance label"), shown, distanceUnit.label(for: Double(shown)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Situational guidance for the currently-selected alert radius, shown
|
/// The distance the geofence actually caps "Follow search" at, in miles
|
||||||
/// under the picker so users know what each choice is best for. Labels
|
/// (FuelStore stores the cap in km so the monitor and storage are unit-free).
|
||||||
/// mirror the picker row text (unit-aware) and explain the trade-off:
|
private var followSearchCapMiles: Int {
|
||||||
/// smaller radii ping more often but later; larger radii ping rarely in
|
Int((FuelStore.alertFollowCapKM / FuelSavingsCalculator.kilometresPerMile).rounded())
|
||||||
/// town but earlier from afar.
|
}
|
||||||
private var alertRadiusGuidance: String {
|
|
||||||
|
/// What the selected alert type actually does. Swapped with the picker so
|
||||||
|
/// the copy can never describe the wrong mode.
|
||||||
|
private var alertModeDescription: String {
|
||||||
|
switch alertMode {
|
||||||
|
case .cheapest:
|
||||||
|
return String(localized: "Get notified when you're near one of the cheapest stations for your chosen fuel.", comment: "Cheapest station proximity alert description")
|
||||||
|
case .bestValue:
|
||||||
|
return String(localized: "Get notified when you're near a station that could save you money after travel costs.", comment: "Best Value proximity alert description")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The radius the selected option really monitors, stated in the user's
|
||||||
|
/// unit — e.g. "Get alerts when you're within 2 miles of a matching
|
||||||
|
/// station." "Follow search" mirrors the Stations-tab distance, which the
|
||||||
|
/// geofence caps; said plainly, and only when the search distance really
|
||||||
|
/// exceeds the cap, so the sentence never contradicts the picker row.
|
||||||
|
private var alertRadiusDescription: String {
|
||||||
switch alertChoice.wrappedValue {
|
switch alertChoice.wrappedValue {
|
||||||
case .followSearch:
|
case .followSearch:
|
||||||
return String(localized: "Set-and-forget: alerts behave exactly like the Stations-tab search distance (capped at 8 miles for reliable geofencing).", comment: "Alert radius guidance for following search distance")
|
let capped = stationLimit > followSearchCapMiles
|
||||||
case .fixed(let value):
|
let label = distanceLabel(forMiles: capped ? followSearchCapMiles : stationLimit)
|
||||||
let optionLabel = String(format: String(localized: "%lld %@", comment: "Distance label"), value, distanceUnit.label(for: Double(value)))
|
if capped {
|
||||||
let body: String
|
return String(format: String(localized: "Get alerts when you're within %@ of a matching station (your search distance is capped for reliable alerts).", comment: "Proximity alert radius description, follow search capped"), label)
|
||||||
switch value {
|
|
||||||
case 1:
|
|
||||||
body = String(localized: "Town driving. Fires most often — you're rarely inside the circle for long, so pings are meaningful. Best for stop-start local trips.", comment: "Alert radius guidance")
|
|
||||||
case 2:
|
|
||||||
body = String(localized: "City or suburb commute. Slightly earlier heads-up than the smallest option; still fires regularly around town.", comment: "Alert radius guidance")
|
|
||||||
case 3:
|
|
||||||
body = String(localized: "Mixed driving. Middle ground: heads-up a few minutes out, still works in most towns.", comment: "Alert radius guidance")
|
|
||||||
case 5:
|
|
||||||
body = String(localized: "A-roads and motorway exits. Wide early warning for longer trips — but in town it rarely fires, because you're usually already inside the circle.", comment: "Alert radius guidance")
|
|
||||||
default:
|
|
||||||
body = String(localized: "Long-distance journeys. Maximum reach: a ping when a cheap station is coming up from far out. In town this essentially never fires.", comment: "Alert radius guidance")
|
|
||||||
}
|
}
|
||||||
return String(format: String(localized: "%@ — %@", comment: "Alert radius guidance with option label"), optionLabel, body)
|
return String(format: String(localized: "Get alerts when you're within %@ of a matching station.", comment: "Proximity alert radius description"), label)
|
||||||
|
case .fixed(let value):
|
||||||
|
let label = String(format: String(localized: "%lld %@", comment: "Distance label"), value, distanceUnit.label(for: Double(value)))
|
||||||
|
return String(format: String(localized: "Get alerts when you're within %@ of a matching station.", comment: "Proximity alert radius description"), label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,49 +145,89 @@ 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<Content: View>(_ 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 {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
Section {
|
Section {
|
||||||
Toggle(String(localized: "Cheapest favourite", comment: "Favourite price-drop alert toggle"), isOn: $favouriteDropEnabled)
|
Toggle(String(localized: "Cheapest favourite", comment: "Favourite price-drop alert toggle"), isOn: $favouriteDropEnabled)
|
||||||
Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $favouriteDropFuel) {
|
optionRow(String(localized: "Fuel", comment: "Fuel picker title"),
|
||||||
ForEach(FuelType.allCases) { fuel in
|
value: favouriteDropFuel.displayName,
|
||||||
Text(fuel.displayName).tag(fuel)
|
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)
|
Button(String(localized: "Check now", comment: "Manual favourite price-drop check button"), action: onCheckFavouriteDropNow)
|
||||||
.disabled(!favouriteDropEnabled)
|
.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)
|
||||||
} header: {
|
} header: {
|
||||||
Text(String(localized: "Price-drop alerts", comment: "Favourite price-drop alerts section title"))
|
Text(String(localized: "Favourite price alerts", comment: "Favourite price alerts section title"))
|
||||||
} footer: {
|
|
||||||
Text(String(localized: "Watches your cheapest saved favourite for the fuel you pick here. FuelBoard alerts when a different favourite becomes the cheapest, or when your current cheapest favourite drops by at least 1.0p. This is separate from the nearby-geofence alert, so you can monitor favourites without extra location noise.", comment: "Favourite price-drop alerts section footer"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Toggle(String(localized: "Cheapest station", comment: "Proximity alert toggle"), isOn: $enabled)
|
Toggle(String(localized: "Cheapest station", comment: "Proximity alert toggle"), isOn: $enabled)
|
||||||
Picker(String(localized: "Alert type", comment: "Proximity alert type picker title"), selection: $alertMode) {
|
optionRow(String(localized: "Alert type", comment: "Proximity alert type picker title"),
|
||||||
ForEach(AlertMode.allCases.filter { mode in mode != .bestValue || bestValueConfigured }) { mode in
|
value: alertMode.displayName,
|
||||||
Text(mode.displayName).tag(mode)
|
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 {
|
if !bestValueConfigured {
|
||||||
Text(String(localized: "Set up Best Value first so Best Value alerts can account for your fill size, MPG and travel cost.", comment: "Best Value alert unavailable hint"))
|
Text(String(localized: "Set up Best Value first so Best Value alerts can account for your fill size, MPG and travel cost.", comment: "Best Value alert unavailable hint"))
|
||||||
.font(.caption)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $fuel) {
|
Text(alertModeDescription)
|
||||||
ForEach(FuelType.allCases) { fuel in
|
.font(.footnote)
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text(alertRadiusGuidance)
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
if alertMode == .bestValue {
|
if alertMode == .bestValue {
|
||||||
// The threshold is edited in Settings → Fuel Savings: it
|
// The threshold is edited in Settings → Fuel Savings: it
|
||||||
@@ -186,21 +235,41 @@ struct AlertsView: View {
|
|||||||
// alert, so it lives with the fill size and MPG that
|
// alert, so it lives with the fill size and MPG that
|
||||||
// produce the saving. Read back here, not offered twice.
|
// produce the saving. Read back here, not offered twice.
|
||||||
Text(String(format: String(localized: "Minimum saving %@ — change in Settings, Fuel Savings.", comment: "Best Value alert threshold read-back"), FuelSavingsFormat.money(bestValueThresholdGBP)))
|
Text(String(format: String(localized: "Minimum saving %@ — change in Settings, Fuel Savings.", comment: "Best Value alert threshold read-back"), FuelSavingsFormat.money(bestValueThresholdGBP)))
|
||||||
.font(.caption)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
if enabled && monitoredCount == 0 {
|
if enabled && monitoredCount == 0 {
|
||||||
Text(String(localized: "No stations monitored yet — open the Stations tab to load prices first.", comment: "No monitored stations hint"))
|
Text(String(localized: "No stations monitored yet — open the Stations tab to load prices first.", comment: "No monitored stations hint"))
|
||||||
.font(.caption)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
Text(String(localized: "Background alerts depend on when your iPhone allows them; each station alerts at most once an hour.", comment: "Proximity alerts background limitation note"))
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
} header: {
|
} header: {
|
||||||
Text(String(localized: "Proximity alerts", comment: "Proximity alerts section title"))
|
Text(String(localized: "Proximity alerts", comment: "Proximity alerts section title"))
|
||||||
} footer: {
|
|
||||||
let modeDescription = alertMode == .bestValue
|
|
||||||
? String(format: String(localized: "When you approach the Best Value station within the radius, FuelBoard sends a notification if it could leave you at least %@ better off after extra return travel. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour.", comment: "Best Value proximity alerts section footer"), FuelSavingsFormat.money(bestValueThresholdGBP), fuel.displayName.lowercased())
|
|
||||||
: String(format: String(localized: "When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour. Follow search mirrors the Stations-tab distance, capped at 8 miles for reliable geofencing. Smaller radii ping more often but later; larger radii ping rarely in town but earlier from afar.", comment: "Proximity alerts section footer"), fuel.displayName.lowercased())
|
|
||||||
Text(modeDescription)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if enabled, let lastAlert {
|
if enabled, let lastAlert {
|
||||||
@@ -212,21 +281,35 @@ struct AlertsView: View {
|
|||||||
|
|
||||||
Section {
|
Section {
|
||||||
Toggle(String(localized: "Cheapest station", comment: "Live Activity toggle"), isOn: $liveActivityEnabled)
|
Toggle(String(localized: "Cheapest station", comment: "Live Activity toggle"), isOn: $liveActivityEnabled)
|
||||||
Picker(String(localized: "Fuel", comment: "Fuel picker title"), selection: $liveActivityFuel) {
|
optionRow(String(localized: "Fuel", comment: "Fuel picker title"),
|
||||||
ForEach(FuelType.allCases) { fuel in
|
value: liveActivityFuel.displayName,
|
||||||
Text(fuel.displayName).tag(fuel)
|
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) {
|
optionRow(String(localized: "Distance", comment: "Distance picker title"),
|
||||||
Text(String(format: String(localized: "Follow search (%@)", comment: "Follow current station search distance option"), searchInUnitLabel)).tag(LADistanceChoice.followSearch)
|
value: laDistanceValueLabel,
|
||||||
ForEach(FuelStore.stationRadiusOptions, id: \.self) { miles in
|
isEnabled: liveActivityEnabled) {
|
||||||
Text(distanceLabel(forMiles: miles)).tag(LADistanceChoice.fixed(miles))
|
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 {
|
||||||
|
Text(String(localized: "Uses the same distance as your station search.", comment: "Live Activity distance description, follow search"))
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
Text(String(localized: "See the cheapest nearby station on your Lock Screen and Dynamic Island, with updates as you travel.", comment: "Live Activity section description"))
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
} header: {
|
} header: {
|
||||||
Text(String(localized: "Live Activity", comment: "Live Activity section title"))
|
Text(String(localized: "Live Activity", comment: "Live Activity section title"))
|
||||||
} footer: {
|
|
||||||
Text(String(localized: "Shows the cheapest station for the fuel and distance you pick here on the Lock Screen and Dynamic Island — independent of the Stations tab (choose Follow search to mirror its distance instead). Updates as you drive; tap to open directions. Live Activities can be disabled in System Settings → Live Activities.", comment: "Live Activity section footer"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(String(localized: "Alerts", comment: "Alerts tab title"))
|
.navigationTitle(String(localized: "Alerts", comment: "Alerts tab title"))
|
||||||
|
|||||||
@@ -58,11 +58,9 @@
|
|||||||
"Radius" = "Radius";
|
"Radius" = "Radius";
|
||||||
"%lld %@" = "%lld %@";
|
"%lld %@" = "%lld %@";
|
||||||
"Follow search (%@)" = "Follow search (%@)";
|
"Follow search (%@)" = "Follow search (%@)";
|
||||||
"When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour. Follow search mirrors the Stations-tab distance, capped at 8 miles for reliable geofencing." = "When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour. Follow search mirrors the Stations-tab distance, capped at 8 miles for reliable geofencing.";
|
|
||||||
"No stations monitored yet — open the Stations tab to load prices first." = "No stations monitored yet — open the Stations tab to load prices first.";
|
"No stations monitored yet — open the Stations tab to load prices first." = "No stations monitored yet — open the Stations tab to load prices first.";
|
||||||
"Last alert" = "Last alert";
|
"Last alert" = "Last alert";
|
||||||
"Live Activity" = "Live Activity";
|
"Live Activity" = "Live Activity";
|
||||||
"Shows the cheapest station for the fuel and distance you pick here on the Lock Screen and Dynamic Island — independent of the Stations tab (choose Follow search to mirror its distance instead). Updates as you drive; tap to open directions. Live Activities can be disabled in System Settings → Live Activities." = "Shows the cheapest station for the fuel and distance you pick here on the Lock Screen and Dynamic Island — independent of the Stations tab (choose Follow search to mirror its distance instead). Updates as you drive; tap to open directions. Live Activities can be disabled in System Settings → Live Activities.";
|
|
||||||
|
|
||||||
/* Settings tab */
|
/* Settings tab */
|
||||||
"Units" = "Units";
|
"Units" = "Units";
|
||||||
@@ -214,8 +212,6 @@
|
|||||||
/* Alerts and favourites localisation pass */
|
/* Alerts and favourites localisation pass */
|
||||||
"Cheapest favourite" = "Cheapest favourite";
|
"Cheapest favourite" = "Cheapest favourite";
|
||||||
"Check now" = "Check now";
|
"Check now" = "Check now";
|
||||||
"Price-drop alerts" = "Price-drop alerts";
|
|
||||||
"Watches your cheapest saved favourite for the fuel you pick here. FuelBoard alerts when a different favourite becomes the cheapest, or when your current cheapest favourite drops by at least 1.0p. This is separate from the nearby-geofence alert, so you can monitor favourites without extra location noise." = "Watches your cheapest saved favourite for the fuel you pick here. FuelBoard alerts when a different favourite becomes the cheapest, or when your current cheapest favourite drops by at least 1.0p. This is separate from the nearby-geofence alert, so you can monitor favourites without extra location noise.";
|
|
||||||
"Cheapest station" = "Cheapest station";
|
"Cheapest station" = "Cheapest station";
|
||||||
"Alert type" = "Alert type";
|
"Alert type" = "Alert type";
|
||||||
"Best Value" = "Best Value";
|
"Best Value" = "Best Value";
|
||||||
@@ -224,16 +220,7 @@
|
|||||||
"Minimum saving %@ — change in Settings, Fuel Savings." = "Minimum saving %@ — change in Settings, Fuel Savings.";
|
"Minimum saving %@ — change in Settings, Fuel Savings." = "Minimum saving %@ — change in Settings, Fuel Savings.";
|
||||||
"Set up Best Value first so FuelBoard can account for your fill size, MPG and travel cost." = "Set up Best Value first so FuelBoard can account for your fill size, MPG and travel cost.";
|
"Set up Best Value first so FuelBoard can account for your fill size, MPG and travel cost." = "Set up Best Value first so FuelBoard can account for your fill size, MPG and travel cost.";
|
||||||
"Set up Best Value first so Best Value alerts can account for your fill size, MPG and travel cost." = "Set up Best Value first so Best Value alerts can account for your fill size, MPG and travel cost.";
|
"Set up Best Value first so Best Value alerts can account for your fill size, MPG and travel cost." = "Set up Best Value first so Best Value alerts can account for your fill size, MPG and travel cost.";
|
||||||
"When you approach the Best Value station within the radius, FuelBoard sends a notification if it could leave you at least %@ better off after extra return travel. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour." = "When you approach the Best Value station within the radius, FuelBoard sends a notification if it could leave you at least %@ better off after extra return travel. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour.";
|
|
||||||
"Proximity alerts" = "Proximity alerts";
|
"Proximity alerts" = "Proximity alerts";
|
||||||
"When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour. Follow search mirrors the Stations-tab distance, capped at 8 miles for reliable geofencing. Smaller radii ping more often but later; larger radii ping rarely in town but earlier from afar." = "When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Nearby stations selling %@ are watched — favourites get priority — and each station alerts at most once per hour. Follow search mirrors the Stations-tab distance, capped at 8 miles for reliable geofencing. Smaller radii ping more often but later; larger radii ping rarely in town but earlier from afar.";
|
|
||||||
"Set-and-forget: alerts behave exactly like the Stations-tab search distance (capped at 8 miles for reliable geofencing)." = "Set-and-forget: alerts behave exactly like the Stations-tab search distance (capped at 8 miles for reliable geofencing).";
|
|
||||||
"Town driving. Fires most often — you're rarely inside the circle for long, so pings are meaningful. Best for stop-start local trips." = "Town driving. Fires most often — you're rarely inside the circle for long, so pings are meaningful. Best for stop-start local trips.";
|
|
||||||
"City or suburb commute. Slightly earlier heads-up than the smallest option; still fires regularly around town." = "City or suburb commute. Slightly earlier heads-up than the smallest option; still fires regularly around town.";
|
|
||||||
"Mixed driving. Middle ground: heads-up a few minutes out, still works in most towns." = "Mixed driving. Middle ground: heads-up a few minutes out, still works in most towns.";
|
|
||||||
"A-roads and motorway exits. Wide early warning for longer trips — but in town it rarely fires, because you're usually already inside the circle." = "A-roads and motorway exits. Wide early warning for longer trips — but in town it rarely fires, because you're usually already inside the circle.";
|
|
||||||
"Long-distance journeys. Maximum reach: a ping when a cheap station is coming up from far out. In town this essentially never fires." = "Long-distance journeys. Maximum reach: a ping when a cheap station is coming up from far out. In town this essentially never fires.";
|
|
||||||
"%@ — %@" = "%@ — %@";
|
|
||||||
|
|
||||||
/* Best Value calculation and station price age */
|
/* Best Value calculation and station price age */
|
||||||
"£ compares the litres your budget buys at each station; Litres compares one fixed quantity." = "£ compares the litres your budget buys at each station; Litres compares one fixed quantity.";
|
"£ compares the litres your budget buys at each station; Litres compares one fixed quantity." = "£ compares the litres your budget buys at each station; Litres compares one fixed quantity.";
|
||||||
@@ -246,3 +233,14 @@
|
|||||||
"May be outdated" = "May be outdated";
|
"May be outdated" = "May be outdated";
|
||||||
"Fuel you'll receive" = "Fuel you'll receive";
|
"Fuel you'll receive" = "Fuel you'll receive";
|
||||||
"Compared with your closest station." = "Compared with your closest station.";
|
"Compared with your closest station." = "Compared with your closest station.";
|
||||||
|
|
||||||
|
/* Alerts tab — refined copy (sections, descriptions, limitations) */
|
||||||
|
"Favourite price alerts" = "Favourite price alerts";
|
||||||
|
"Get notified when a different favourite becomes the cheapest, or your cheapest favourite drops in price." = "Get notified when a different favourite becomes the cheapest, or your cheapest favourite drops in price.";
|
||||||
|
"Get notified when you're near one of the cheapest stations for your chosen fuel." = "Get notified when you're near one of the cheapest stations for your chosen fuel.";
|
||||||
|
"Get notified when you're near a station that could save you money after travel costs." = "Get notified when you're near a station that could save you money after travel costs.";
|
||||||
|
"Get alerts when you're within %@ of a matching station." = "Get alerts when you're within %@ of a matching station.";
|
||||||
|
"Get alerts when you're within %@ of a matching station (your search distance is capped for reliable alerts)." = "Get alerts when you're within %@ of a matching station (your search distance is capped for reliable alerts).";
|
||||||
|
"Uses the same distance as your station search." = "Uses the same distance as your station search.";
|
||||||
|
"See the cheapest nearby station on your Lock Screen and Dynamic Island, with updates as you travel." = "See the cheapest nearby station on your Lock Screen and Dynamic Island, with updates as you travel.";
|
||||||
|
"Background alerts depend on when your iPhone allows them; each station alerts at most once an hour." = "Background alerts depend on when your iPhone allows them; each station alerts at most once an hour.";
|
||||||
|
|||||||
Reference in New Issue
Block a user