import Foundation class HistoryManager: ObservableObject { static let shared = HistoryManager() @Published var history: [Wallpaper] = [] /// Latest persistence failure, surfaced so callers can react. The /// in-memory history still updates when persistence fails — the manager /// no longer hides corruption or unwritable storage behind `try?`. @Published var persistenceError: String? private let key = "wallpaperHistory" private let maxHistoryItems: Int private let defaults: UserDefaults private let encoder: JSONEncoder private let decoder: JSONDecoder init( defaults: UserDefaults = .standard, encoder: JSONEncoder = JSONEncoder(), decoder: JSONDecoder = JSONDecoder(), maxHistoryItems: Int = 50 ) { self.defaults = defaults self.encoder = encoder self.decoder = decoder self.maxHistoryItems = maxHistoryItems loadHistory() } func addToHistory(_ wallpaper: Wallpaper) { // Remove if existing to promote to top if let index = history.firstIndex(where: { $0.id == wallpaper.id }) { history.remove(at: index) } history.insert(wallpaper, at: 0) if history.count > maxHistoryItems { history = Array(history.prefix(maxHistoryItems)) } persist(history) } func clearHistory() { history = [] persist(history) } /// Public for diagnostics/testing. Encodes the supplied list through the /// configured encoder, writes through the configured `UserDefaults`, /// and records the first failure through `persistenceError`. Keeping the /// encoder/userdefaults injectable lets us assert failure paths in tests /// without hijacking the shared `UserDefaults.standard` instance. func persist(_ entries: [Wallpaper]) { do { let data = try encoder.encode(entries) defaults.set(data, forKey: key) persistenceError = nil } catch { persistenceError = "Failed to save history: \(error.localizedDescription)" } } /// Decodes the stored history. Public for testability. Returns nil when /// the stored data is missing or undecodable and records the failure /// reason through `persistenceError` so the app can react. func decodeHistory(from data: Data?) -> [Wallpaper]? { guard let data else { persistenceError = nil return nil } do { let decoded = try decoder.decode([Wallpaper].self, from: data) persistenceError = nil return decoded } catch { persistenceError = "Failed to load history: \(error.localizedDescription)" return nil } } private func loadHistory() { let stored = defaults.data(forKey: key) history = decodeHistory(from: stored) ?? history } }