New app icon (drip: £ fuel drop, green border, gradient bg) + Alerts radius guidance labels

- AppIcon / AppIcon-dark / AppIcon-tinted swapped for the drip design
  (1024px, dark + tinted variants), onboarding artwork matched
- Alerts tab: live explainer under the Radius picker — situational
  guidance per option (Follow search = set-and-forget mirror of the
  Stations distance; 1 = town driving; 2 = city/suburb commute;
  3 = mixed; 5 = A-roads/motorway exits; 8 = long-distance) — plus the
  trade-off line in the section footer
- 83 tests, Release build green
This commit is contained in:
FuelBoard Contributor
2026-08-15 12:18:56 +01:00
parent 6cbf1dfc8f
commit d1fbac3f05
5 changed files with 32 additions and 1 deletions
+32 -1
View File
@@ -46,6 +46,34 @@ struct AlertsView: View {
return "\(shown) \(distanceUnit.label(for: Double(shown)))"
}
/// Situational guidance for the currently-selected alert radius, shown
/// under the picker so users know what each choice is best for. Labels
/// mirror the picker row text (unit-aware) and explain the trade-off:
/// smaller radii ping more often but later; larger radii ping rarely in
/// town but earlier from afar.
private var alertRadiusGuidance: String {
switch alertChoice.wrappedValue {
case .followSearch:
return "Set-and-forget: alerts behave exactly like the Stations-tab search distance (capped at 8 miles for reliable geofencing)."
case .fixed(let value):
let optionLabel = "\(value) \(distanceUnit.label(for: Double(value)))"
let body: String
switch value {
case 1:
body = "Town driving. Fires most often — you're rarely inside the circle for long, so pings are meaningful. Best for stop-start local trips."
case 2:
body = "City or suburb commute. Slightly earlier heads-up than the smallest option; still fires regularly around town."
case 3:
body = "Mixed driving. Middle ground: heads-up a few minutes out, still works in most towns."
case 5:
body = "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."
default:
body = "Long-distance journeys. Maximum reach: a ping when a cheap station is coming up from far out. In town this essentially never fires."
}
return "\(optionLabel)\(body)"
}
}
private enum AlertRadiusChoice: Hashable {
case followSearch
case fixed(Int)
@@ -115,6 +143,9 @@ struct AlertsView: View {
Text("\(value) \(distanceUnit.label(for: Double(value)))").tag(AlertRadiusChoice.fixed(value))
}
}
Text(alertRadiusGuidance)
.font(.caption)
.foregroundStyle(.secondary)
if enabled && monitoredCount == 0 {
Text("No stations monitored yet — open the Stations tab to load prices first.")
.font(.caption)
@@ -123,7 +154,7 @@ struct AlertsView: View {
} 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. Nearby stations selling \(fuel.displayName.lowercased()) 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.")
Text("When you approach a station that is the cheapest within the radius, FuelBoard sends a notification — even with the app closed. Nearby stations selling \(fuel.displayName.lowercased()) 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.")
}
if enabled, let lastAlert {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB