From 26e724f48a6ff60fc7d9319890931093ff78586f Mon Sep 17 00:00:00 2001 From: FuelBoard Contributor Date: Thu, 13 Aug 2026 15:33:24 +0100 Subject: [PATCH] Widget config: Distance picker as AppEntity so labels resolve dynamically from the app's units (AppEnum labels are static) --- FuelBoardWidgets/WidgetConfigIntent.swift | 47 ++++++++++++----------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/FuelBoardWidgets/WidgetConfigIntent.swift b/FuelBoardWidgets/WidgetConfigIntent.swift index afed7a2..0a7e03c 100644 --- a/FuelBoardWidgets/WidgetConfigIntent.swift +++ b/FuelBoardWidgets/WidgetConfigIntent.swift @@ -35,35 +35,36 @@ enum WidgetSort: String, AppEnum, CaseIterable, Codable { ] } -enum WidgetDistance: String, AppEnum, CaseIterable, Codable { - case five - case ten - case fifteen +// Per-widget distance filter. Modelled as an AppEntity (not an AppEnum) so +// the option labels can mirror the app's units setting at render time: an +// AppEnum's caseDisplayRepresentations are STATIC, so the Edit-Widget picker +// would always show "5 miles / 10 miles / 15 miles" regardless of the app's +// km mode. An entity query resolves labels per value, so they can read the +// shared unit preference ("8 km" in km mode). +struct WidgetDistance: AppEntity, Identifiable, Hashable, Codable { + /// The distance in miles (5/10/15) — the persisted value. Labels are + /// unit-aware, the stored value stays in miles. + let id: Int - static var typeDisplayRepresentation: TypeDisplayRepresentation = "Distance" + var miles: Int { id } - static var caseDisplayRepresentations: [WidgetDistance: DisplayRepresentation] = [ - .five: "5 miles", - .ten: "10 miles", - .fifteen: "15 miles", - ] - - /// Mirror the app's units setting: the Edit-Widget picker labels show the - /// real distance in the user's chosen unit — "5 miles" in miles mode, - /// "8 km" in km mode (same stored value, labelled truthfully). Keeps the - /// widget config consistent with the Stations/Alerts pickers. var displayRepresentation: DisplayRepresentation { let unit = FuelStore.loadDistanceUnit() - let shown = unit.displayMiles(miles) + let shown = unit.displayMiles(id) return DisplayRepresentation(stringLiteral: "\(shown) \(unit.label(for: Double(shown)))") } - var miles: Int { - switch self { - case .five: return 5 - case .ten: return 10 - case .fifteen: return 15 - } + static var typeDisplayRepresentation: TypeDisplayRepresentation = "Distance" + static var defaultQuery = WidgetDistanceQuery() +} + +struct WidgetDistanceQuery: EntityQuery { + func entities(for identifiers: [Int]) async throws -> [WidgetDistance] { + identifiers.map { WidgetDistance(id: $0) } + } + + func suggestedEntities() async throws -> [WidgetDistance] { + FuelStore.stationRadiusOptions.map { WidgetDistance(id: $0) } } } @@ -77,7 +78,7 @@ struct FuelBoardWidgetConfigurationIntent: WidgetConfigurationIntent { @Parameter(title: "Sort by", default: .cheapest) var sort: WidgetSort - @Parameter(title: "Distance", default: .five) + @Parameter(title: "Distance", default: WidgetDistance(id: 5)) var distance: WidgetDistance /// Edit-Widget UI: the Distance picker only makes sense for Cheapest