FavoritesManager.swift

2.5 KB · raw

1import Foundation23class FavoritesManager: ObservableObject {4  static let shared = FavoritesManager()56  @Published var favorites: [Wallpaper] = []7  /// Latest persistence failure, surfaced so the UI/app layer can react.8  /// Corrupt or unwritable stored data no longer fails silently — the9  /// manager keeps the in-memory list intact but exposes the cause.10  @Published var persistenceError: String?1112  private let key = "favoriteWallpapers"13  private let defaults: UserDefaults14  private let encoder: JSONEncoder15  private let decoder: JSONDecoder1617  init(18    defaults: UserDefaults = .standard,19    encoder: JSONEncoder = JSONEncoder(),20    decoder: JSONDecoder = JSONDecoder()21  ) {22    self.defaults = defaults23    self.encoder = encoder24    self.decoder = decoder25    loadFavorites()26  }2728  func toggleFavorite(_ wallpaper: Wallpaper) {29    if let index = favorites.firstIndex(where: { $0.id == wallpaper.id }) {30      favorites.remove(at: index)31    } else {32      favorites.insert(wallpaper, at: 0)33    }34    saveFavorites()35  }3637  func isFavorite(_ wallpaper: Wallpaper) -> Bool {38    return favorites.contains(where: { $0.id == wallpaper.id })39  }4041  private func saveFavorites() {42    persist(currentFavorites())43  }4445  /// Public for diagnostics/testing. Encodes the current state through the46  /// configured encoder and reports the first failure through47  /// `persistenceError`.48  func persist(_ wallpapers: [Wallpaper]) {49    do {50      let data = try encoder.encode(wallpapers)51      defaults.set(data, forKey: key)52      persistenceError = nil53    } catch {54      persistenceError = "Failed to save favorites: \(error.localizedDescription)"55    }56  }5758  /// Decodes the persisted list through the configured decoder. Public to59  /// keep the load path testable while letting the manager choose its own60  /// defaults in production. Sets `persistenceError` when the stored data is61  /// missing or undecodable so callers can react without inspecting logs.62  func decodeFavorites(from data: Data?) -> [Wallpaper]? {63    guard let data else {64      persistenceError = nil65      return nil66    }67    do {68      let decoded = try decoder.decode([Wallpaper].self, from: data)69      persistenceError = nil70      return decoded71    } catch {72      persistenceError = "Failed to load favorites: \(error.localizedDescription)"73      return nil74    }75  }7677  private func loadFavorites() {78    favorites = currentFavorites()79  }8081  private func currentFavorites() -> [Wallpaper] {82    let stored = defaults.data(forKey: key)83    return decodeFavorites(from: stored) ?? favorites84  }85}