diff --git a/FuelBoardWidgets/WidgetConfigIntent.swift b/FuelBoardWidgets/WidgetConfigIntent.swift index 1dae805..a3e4465 100644 --- a/FuelBoardWidgets/WidgetConfigIntent.swift +++ b/FuelBoardWidgets/WidgetConfigIntent.swift @@ -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