diff --git a/FuelBoardWidgets/FuelPriceWidget.swift b/FuelBoardWidgets/FuelPriceWidget.swift index 9a4bf82..4661806 100644 --- a/FuelBoardWidgets/FuelPriceWidget.swift +++ b/FuelBoardWidgets/FuelPriceWidget.swift @@ -77,9 +77,10 @@ struct FuelPriceTimelineProvider: AppIntentTimelineProvider { } private func makeEntry(configuration: FuelBoardWidgetConfigurationIntent) async -> FuelPriceEntry { - // Per-widget config: fuel + sort come from THIS widget instance. + // Per-widget config: fuel + sort + distance come from THIS widget instance. let fuel = FuelType(rawValue: configuration.fuel.rawValue) ?? .e10 let sort: SortMode = configuration.sort == .closest ? .closest : .cheapest + let radiusKM = Double(configuration.distance.miles) * 1.60934 // 1) Try a fresh location fix (bounded to a few seconds). var location = await WidgetLocationFetcher.shared.currentLocation().map { @@ -108,7 +109,6 @@ struct FuelPriceTimelineProvider: AppIntentTimelineProvider { // shared cache, then to samples. var stations: [FuelStation] = [] if let location { - let radiusKM = unitToKM() if let fetched = await Self.fetchFocused(near: location, fuel: fuel, radiusKM: radiusKM) { stations = fetched } @@ -116,7 +116,6 @@ struct FuelPriceTimelineProvider: AppIntentTimelineProvider { if stations.isEmpty { stations = FuelStore.loadStations() } if stations.isEmpty { stations = SampleFuelProvider.sampleStations } let unit = FuelStore.loadDistanceUnit() - let radiusKM = unitToKM() if let location { // STRICT: cached data fetched around another location must never // leak out-of-radius stations into the widget. @@ -159,11 +158,6 @@ struct FuelPriceTimelineProvider: AppIntentTimelineProvider { ) } - /// The search radius in km for the widget's own focused relay fetch. - private func unitToKM() -> Double { - FuelStore.loadDistanceUnit().toKM(Double(FuelStore.loadStationLimit())) - } - /// One focused fetch from the relay around the widget's location — small /// response (radius + limit 500), bounded so a dead relay can't stall the /// timeline. Returns nil on any failure so callers fall back to cache. @@ -230,12 +224,12 @@ struct FuelPriceWidgetView: View { .font(.caption2) .foregroundStyle(.secondary) } - Text(station.brand) + Text(station.brand.sanitizedStationTitle) .font(.headline) .lineLimit(1) if let price = station.prices[entry.fuel] { - Text(String(format: "%.1fp", price)) - .font(.system(size: 28, weight: .bold)) + Text(String(format: "£%.3f", price / 100)) + .font(.system(size: 26, weight: .bold).monospaced()) .foregroundStyle(.green) } if let location = entry.location { @@ -269,7 +263,7 @@ struct FuelPriceWidgetView: View { ForEach(entry.stations.prefix(3)) { station in Link(destination: station.mapsDirectionsURL ?? URL(string: "http://maps.apple.com")!) { HStack(spacing: 8) { - Text(station.brand) + Text(station.brand.sanitizedStationTitle) .font(.caption.weight(.semibold)) .lineLimit(1) if let location = entry.location { @@ -283,8 +277,8 @@ struct FuelPriceWidgetView: View { Circle() .fill(ragColor(for: price, cheapest: cheapest)) .frame(width: 6, height: 6) - Text(String(format: "%.1fp", price)) - .font(.caption.weight(.bold)) + Text(String(format: "£%.3f", price / 100)) + .font(.caption.weight(.bold).monospaced()) .foregroundStyle(.primary) } } diff --git a/FuelBoardWidgets/WidgetConfigIntent.swift b/FuelBoardWidgets/WidgetConfigIntent.swift index 68caf67..53e87f2 100644 --- a/FuelBoardWidgets/WidgetConfigIntent.swift +++ b/FuelBoardWidgets/WidgetConfigIntent.swift @@ -33,13 +33,38 @@ enum WidgetSort: String, AppEnum, CaseIterable, Codable { ] } +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 and ordering this widget shows.") + 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 }