Tabs (Stations/Favourites/Alerts): favourites with cheapest-first ranking, proximity geofence alerts (favourites priority, 3km default radius, 1h dedup), Always location + background mode

This commit is contained in:
FuelBoard Contributor
2026-08-11 15:17:26 +01:00
parent 54403ed4b3
commit 60d25164d6
7 changed files with 591 additions and 136 deletions
+58
View File
@@ -127,6 +127,9 @@ struct FuelStore {
static let fuelKey = "fuelboard.selectedFuel" // FuelType raw value
static let sortModeKey = "fuelboard.sortMode" // SortMode raw value
static let stationLimitKey = "fuelboard.stationLimit" // Int (10/25/50/75/100)
static let favouritesKey = "fuelboard.favourites" // [FuelStation] JSON
static let alertsEnabledKey = "fuelboard.alertsEnabled" // Bool
static let alertsRadiusKey = "fuelboard.alertsRadius" // Double km
// MARK: Stations
@@ -204,6 +207,61 @@ struct FuelStore {
saveString(String(limit), service: stationLimitKey)
}
// MARK: Favourites
static func loadFavourites() -> [FuelStation] {
if let data = keychainData(service: favouritesKey),
let favs = try? JSONDecoder().decode([FuelStation].self, from: data) {
return favs
}
if let defaults = UserDefaults(suiteName: appGroupSuite),
let data = defaults.data(forKey: favouritesKey),
let favs = try? JSONDecoder().decode([FuelStation].self, from: data) {
return favs
}
return []
}
static func saveFavourites(_ favourites: [FuelStation]) {
if let data = try? JSONEncoder().encode(favourites) {
UserDefaults(suiteName: appGroupSuite)?.set(data, forKey: favouritesKey)
writeKeychain(data: data, service: favouritesKey)
}
}
/// Returns favourites with fresh prices applied from the given station list
/// (favourites keep their cached snapshot when not in the current results).
static func refreshedFavourites(_ favourites: [FuelStation], from stations: [FuelStation]) -> [FuelStation] {
var updated = favourites
for (i, fav) in favourites.enumerated() {
if let fresh = stations.first(where: { $0.id == fav.id }) {
updated[i] = fresh
}
}
return updated
}
// MARK: Alerts
static func loadAlertsEnabled() -> Bool {
loadString(service: alertsEnabledKey) == "1"
}
static func saveAlertsEnabled(_ enabled: Bool) {
saveString(enabled ? "1" : "0", service: alertsEnabledKey)
}
static func loadAlertsRadius() -> Double {
if let raw = loadString(service: alertsRadiusKey), let value = Double(raw), value >= 1, value <= 10 {
return value
}
return 3.0
}
static func saveAlertsRadius(_ radius: Double) {
saveString(String(radius), service: alertsRadiusKey)
}
// MARK: Low-level keychain helpers
private static func keychainData(service: String) -> Data? {