Widget config: Distance picker as AppEntity so labels resolve dynamically from the app's units (AppEnum labels are static)

This commit is contained in:
FuelBoard Contributor
2026-08-13 15:33:24 +01:00
parent 64330f96a8
commit 26e724f48a
+23 -22
View File
@@ -35,35 +35,36 @@ enum WidgetSort: String, AppEnum, CaseIterable, Codable {
] ]
} }
enum WidgetDistance: String, AppEnum, CaseIterable, Codable { // Per-widget distance filter. Modelled as an AppEntity (not an AppEnum) so
case five // the option labels can mirror the app's units setting at render time: an
case ten // AppEnum's caseDisplayRepresentations are STATIC, so the Edit-Widget picker
case fifteen // 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 { var displayRepresentation: DisplayRepresentation {
let unit = FuelStore.loadDistanceUnit() let unit = FuelStore.loadDistanceUnit()
let shown = unit.displayMiles(miles) let shown = unit.displayMiles(id)
return DisplayRepresentation(stringLiteral: "\(shown) \(unit.label(for: Double(shown)))") return DisplayRepresentation(stringLiteral: "\(shown) \(unit.label(for: Double(shown)))")
} }
var miles: Int { static var typeDisplayRepresentation: TypeDisplayRepresentation = "Distance"
switch self { static var defaultQuery = WidgetDistanceQuery()
case .five: return 5
case .ten: return 10
case .fifteen: return 15
} }
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) @Parameter(title: "Sort by", default: .cheapest)
var sort: WidgetSort var sort: WidgetSort
@Parameter(title: "Distance", default: .five) @Parameter(title: "Distance", default: WidgetDistance(id: 5))
var distance: WidgetDistance var distance: WidgetDistance
/// Edit-Widget UI: the Distance picker only makes sense for Cheapest /// Edit-Widget UI: the Distance picker only makes sense for Cheapest