Files
fuelboard/FuelBoardWidgets/WidgetConfigIntent.swift
T
FuelBoard Contributor 1dcd47c6cd Fix widget distance menu + geofence notification chain
Widget distance menu: the Distance picker only makes sense for
Cheapest ordering. It was hidden for Favourites but Closest still
showed it (regressed when the per-widget Distance picker was added).
parameterSummary now nests When clauses: Distance visible for
Cheapest only; Closest and Favourites hide it.

Notifications: three compounding defects kept real geofence alerts
from ever firing while the app was suspended:

1. Always permission was never properly requested. requestPermissions
   fired WhenInUse and Always back-to-back; iOS ignores the second
   call while the first prompt is pending, leaving the app stuck on
   WhenInUse — and region entries are never delivered in the
   background. Added locationManagerDidChangeAuthorization to
   ProximityMonitor: escalate WhenInUse -> Always, and re-register
   geofences on grant (regions registered under WhenInUse-only won't
   deliver in the background).

2. The 18-region window was frozen in the background. Re-registration
   lived in SwiftUI .onChange(of: locationManager.current), which
   never runs while suspended. Added a delegate hook
   (LocationManager.onLocationUpdate) fired from didUpdateLocations on
   every fix including background significant-change wake-ups; the app
   wires it to re-register geofences around the new position.

3. Region-registration failures were invisible. monitoringDidFailFor
   was never implemented, so a failed startMonitoring (region budget,
   auth, radius) silently stopped alerts. Now surfaced as
   monitor.lastRegionError and shown in Settings -> Debug; cleared on
   the next successful registration.
2026-08-12 18:18:24 +01:00

98 lines
2.9 KiB
Swift

import AppIntents
import Foundation
// Per-widget configuration intent (iOS 17+). Every widget instance carries
// its OWN fuel + sort choices, edited directly on the home screen (long-press
// → Edit Widget), independent of what the app has selected. This is what
// allows several FuelBoard widgets to show different fuels/orderings side by
// side.
enum WidgetFuel: String, AppEnum, CaseIterable, Codable {
case e10
case e5
case diesel
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Fuel"
static var caseDisplayRepresentations: [WidgetFuel: DisplayRepresentation] = [
.e10: "Unleaded",
.e5: "Premium",
.diesel: "Diesel",
]
}
enum WidgetSort: String, AppEnum, CaseIterable, Codable {
case cheapest
case closest
case favourites
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Sort by"
static var caseDisplayRepresentations: [WidgetSort: DisplayRepresentation] = [
.cheapest: "Cheapest",
.closest: "Closest",
.favourites: "Favourites",
]
}
enum WidgetDistance: String, AppEnum, CaseIterable, Codable {
case five
case ten
case fifteen
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Distance"
static var caseDisplayRepresentations: [WidgetDistance: DisplayRepresentation] = [
.five: "5 miles",
.ten: "10 miles",
.fifteen: "15 miles",
]
var miles: Int {
switch self {
case .five: return 5
case .ten: return 10
case .fifteen: return 15
}
}
}
struct FuelBoardWidgetConfigurationIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource = "Fuel & Sort"
static var description = IntentDescription("Which fuel, ordering and search radius this widget shows.")
@Parameter(title: "Fuel", default: .e10)
var fuel: WidgetFuel
@Parameter(title: "Sort by", default: .cheapest)
var sort: WidgetSort
@Parameter(title: "Distance", default: .five)
var distance: WidgetDistance
/// Edit-Widget UI: the Distance picker only makes sense for Cheapest
/// ordering — Closest is inherently "nearest within range" and Favourites
/// is not radius-bound. Show it for Cheapest only; hide for both others.
static var parameterSummary: some ParameterSummary {
When(\.$sort, .equalTo, WidgetSort.cheapest) {
Summary("Show \(\.$fuel) by \(\.$sort) within \(\.$distance)") {
\.$fuel
\.$sort
\.$distance
}
} otherwise: {
When(\.$sort, .equalTo, WidgetSort.favourites) {
Summary("Show \(\.$fuel) favourites") {
\.$fuel
\.$sort
}
} otherwise: {
Summary("Show \(\.$fuel) by \(\.$sort)") {
\.$fuel
\.$sort
}
}
}
}
}