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.
98 lines
2.9 KiB
Swift
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|