Widget favourites defaults: auto-populate Fuel and Favourite rows when Sort = Favourites. FavouriteFuelQuery gains defaultResult() (first fuel with a favourite, Unleaded→Diesel order) and strict entities(for:) — a stored fuel that no longer has favourites fails resolution and falls back to the default. WidgetFavouriteQuery gains defaultResult() (first favourite of the Fuel row's fuel, else first favourite overall) and strict entities(for:) — the empty static default ('fuel|') and removed favourites now resolve to nil so the sheet pre-selects a real favourite instead of showing a placeholder. Provider fallback (cheapest favourite of the fuel) unchanged.

This commit is contained in:
FuelBoard Contributor
2026-08-13 18:28:23 +01:00
parent 906f8a8429
commit b1765b5611
+47 -9
View File
@@ -92,14 +92,31 @@ struct FavouriteFuel: AppEntity, Identifiable, Hashable, Codable {
}
struct FavouriteFuelQuery: EntityQuery {
/// Strict: a fuel only resolves if it ACTUALLY has favourites. A stored
/// value for a fuel that lost all its favourites (or the static .e10
/// default on a fresh widget) fails resolution and falls back to
/// defaultResult() the first fuel that has a favourite.
func entities(for identifiers: [String]) async throws -> [FavouriteFuel] {
identifiers.compactMap { FuelType(rawValue: $0) }.map { FavouriteFuel(fuel: $0) }
let fuels = Set(FuelStore.loadFavourites().map(\.fuel))
return identifiers.compactMap { id in
guard let fuel = FuelType(rawValue: id), fuels.contains(fuel) else { return nil }
return FavouriteFuel(fuel: fuel)
}
}
func suggestedEntities() async throws -> [FavouriteFuel] {
let fuels = Set(FuelStore.loadFavourites().map(\.fuel))
return FuelType.allCases.filter { fuels.contains($0) }.map { FavouriteFuel(fuel: $0) }
}
/// Fresh widget / unresolved value auto-populate the Fuel row with the
/// FIRST fuel that has a favourite (Unleaded, Premium, Diesel order).
func defaultResult() async -> FavouriteFuel? {
let fuels = Set(FuelStore.loadFavourites().map(\.fuel))
return FuelType.allCases.first { fuels.contains($0) }
.map { FavouriteFuel(fuel: $0) }
?? FavouriteFuel(fuel: .e10)
}
}
// A pinned favourite station, selectable on SMALL widgets (which show a single
@@ -147,15 +164,16 @@ struct WidgetFavouriteQuery: EntityQuery {
func entities(for identifiers: [String]) async throws -> [WidgetFavourite] {
let favourites = FuelStore.loadFavourites()
return identifiers.map { id in
let parts = id.split(separator: "|", maxSplits: 1)
let fuel = FuelType(rawValue: String(parts.first ?? "")) ?? .e10
let stationID = String(parts.last ?? "")
let entry = favourites.first { $0.id == id }
return identifiers.compactMap { id in
// Strict: only real, existing favourites resolve. The empty
// static default (id "fuel|") and removed favourites fail
// resolution so the sheet falls back to defaultResult().
guard !id.hasSuffix("|"),
let entry = favourites.first(where: { $0.id == id }) else { return nil }
return WidgetFavourite(
fuel: fuel,
stationID: stationID,
stationName: entry?.station.name ?? ""
fuel: entry.fuel,
stationID: entry.station.id,
stationName: entry.station.name
)
}
}
@@ -176,6 +194,26 @@ struct WidgetFavouriteQuery: EntityQuery {
)
}
}
/// Fresh widget / unresolved value auto-populate the Favourite row with
/// the FIRST favourite of the Fuel row's fuel (falling back to the first
/// favourite of any fuel if the fuel has none, e.g. mid-change).
func defaultResult() async -> WidgetFavourite? {
let favourites = FuelStore.loadFavourites()
guard !favourites.isEmpty else { return nil }
let entry: FavouriteEntry
if let fuel = smallIntent?.favouriteFuel.fuel,
let scoped = favourites.first(where: { $0.fuel == fuel }) {
entry = scoped
} else {
entry = favourites[0]
}
return WidgetFavourite(
fuel: entry.fuel,
stationID: entry.station.id,
stationName: entry.station.name
)
}
}
// The knobs both the medium-list and small-single widget intents expose, so