Small widget favourites: fuel row returns to the config sheet (picks the default favourite); pinned favourite wins, fuel-tagged picker rows when favourites span >1 fuel; fallback = selected fuel's cheapest favourite

This commit is contained in:
FuelBoard Contributor
2026-08-13 16:51:21 +01:00
parent 1bdef59d78
commit 7357eb98c3
2 changed files with 35 additions and 22 deletions
+18 -7
View File
@@ -162,21 +162,32 @@ struct FuelPriceTimelineProvider<Configuration: WidgetConfigurationIntent & Widg
.filter { $0.station.prices[$0.fuel] != nil } .filter { $0.station.prices[$0.fuel] != nil }
// Small widget, pinned favourite: exactly ONE station, its own // Small widget, pinned favourite: exactly ONE station, its own
// fuel, no radius. Freshen its price when a focused fetch covers it. // fuel, no radius. Freshen its price when a focused fetch covers
if let chosen = configuration.favouriteChoice, // it. The chosen favourite wins; when it's missing or stale (fresh
let entry = favourites.first(where: { $0.id == chosen.id }) { // widget, favourite removed, fuel row changed) fall back to the
var station = entry.station // Fuel row's cheapest favourite so the face is never blank.
if let chosen = configuration.favouriteChoice {
let pinned = favourites.first { $0.id == chosen.id }
?? favourites
.filter { $0.fuel == fuel && $0.station.prices[fuel] != nil }
.min { lhs, rhs in
(lhs.station.prices[fuel] ?? .infinity) <
(rhs.station.prices[fuel] ?? .infinity)
}
if let pinned {
var station = pinned.station
if let location, if let location,
let fetched = await Self.fetchFocused(near: location, fuel: entry.fuel, radiusKM: radiusKM), let fetched = await Self.fetchFocused(near: location, fuel: pinned.fuel, radiusKM: radiusKM),
let fresh = fetched.first(where: { $0.id == entry.station.id }) { let fresh = fetched.first(where: { $0.id == pinned.station.id }) {
station = fresh station = fresh
} }
return FuelPriceEntry( return FuelPriceEntry(
date: Date(), stations: [station], date: Date(), stations: [station],
fuel: entry.fuel, sort: .cheapest, isFavourites: true, fuel: pinned.fuel, sort: .cheapest, isFavourites: true,
location: location, locationSource: source, unit: unit location: location, locationSource: source, unit: unit
) )
} }
}
// List mode (medium): pinned stations for THIS fuel, cheapest-first. // List mode (medium): pinned stations for THIS fuel, cheapest-first.
// Not radius-bound a favourite in Edinburgh shows on a widget in // Not radius-bound a favourite in Edinburgh shows on a widget in
+11 -9
View File
@@ -84,12 +84,12 @@ struct WidgetFavourite: AppEntity, Identifiable, Hashable, Codable {
return DisplayRepresentation(stringLiteral: "Favourite") return DisplayRepresentation(stringLiteral: "Favourite")
} }
let name = entry.station.name let name = entry.station.name
// Same station pinned for another fuel? Disambiguate with the fuel tag. // If favourites span more than one fuel type, tag EVERY option with its
let hasOtherFuel = favourites.contains { // fuel so the picker stays unambiguous (different stations can share a
$0.station.id == entry.station.id && $0.fuel != entry.fuel // name; the same station can be pinned for two fuels).
} let multiFuel = Set(favourites.map(\.fuel)).count > 1
return DisplayRepresentation( return DisplayRepresentation(
stringLiteral: hasOtherFuel ? "\(name) · \(entry.fuel.displayName)" : name stringLiteral: multiFuel ? "\\(name) · \\(entry.fuel.displayName)" : name
) )
} }
@@ -167,9 +167,10 @@ struct FuelBoardWidgetConfigurationIntent: WidgetConfigurationIntent, WidgetConf
// SMALL widget intent: same knobs as the list widget, PLUS a pinned-favourite // SMALL widget intent: same knobs as the list widget, PLUS a pinned-favourite
// picker for Favourites sort (a small widget shows exactly ONE station, so the // picker for Favourites sort (a small widget shows exactly ONE station, so the
// user chooses which favourite). In Favourites mode the Fuel + Distance rows // user chooses which favourite). Favourites mode keeps the Fuel row it
// are hidden the chosen favourite carries its own fuel, and there is no // mirrors the app's Favourites tab: pick the fuel, then the favourite. The
// radius when a station is pinned. // pinned favourite wins when set; the Fuel row picks the default favourite on
// a fresh widget. Distance stays hidden (a pinned station has no radius).
struct FuelBoardSmallWidgetConfigurationIntent: WidgetConfigurationIntent, WidgetConfigValues { struct FuelBoardSmallWidgetConfigurationIntent: WidgetConfigurationIntent, WidgetConfigValues {
static var title: LocalizedStringResource = "Fuel & Sort" static var title: LocalizedStringResource = "Fuel & Sort"
static var description = IntentDescription("Which fuel, ordering, radius and pinned favourite this small widget shows.") static var description = IntentDescription("Which fuel, ordering, radius and pinned favourite this small widget shows.")
@@ -190,8 +191,9 @@ struct FuelBoardSmallWidgetConfigurationIntent: WidgetConfigurationIntent, Widge
static var parameterSummary: some ParameterSummary { static var parameterSummary: some ParameterSummary {
When(\.$sort, .equalTo, WidgetSort.favourites) { When(\.$sort, .equalTo, WidgetSort.favourites) {
Summary("Show \(\.$favourite)") { Summary("Show \(\.$fuel) favourite \(\.$favourite)") {
\.$sort \.$sort
\.$fuel
\.$favourite \.$favourite
} }
} otherwise: { } otherwise: {