import Foundation class GIFStorageService { static let shared = GIFStorageService() private let userDefaults = UserDefaults(suiteName: "group.gifcollector") private let savedGIFsKey = "savedGIFs" private let pendingGIFsKey = "pendingGIFs" private init() { // Make sure the shared UserDefaults exists if userDefaults == nil { print("Error: Could not create UserDefaults with app group") } // Process any pending GIFs from the Share Extension checkForSharedGIFs() } func saveGIF(data: Data, fromURL urlString: String, completion: @escaping (GIF?) -> Void) { // First store the GIF data to disk guard let localPath = GIFFileManager.shared.storeGIF(data: data, fromURL: urlString) else { completion(nil) return } // Create and save the GIF model let gif = GIF(localFilePath: localPath, originalURL: urlString) var savedGIFs = fetchGIFs() // Don't save duplicates of the same URL if !savedGIFs.contains(where: { $0.originalURL == urlString }) { savedGIFs.append(gif) saveToUserDefaults(gifs: savedGIFs) } // Perform cleanup if needed GIFFileManager.shared.performStorageCleanupIfNeeded() completion(gif) } func fetchGIFs() -> [GIF] { guard let data = userDefaults?.data(forKey: savedGIFsKey), let gifs = try? JSONDecoder().decode([GIF].self, from: data) else { return [] } // Filter out any GIFs whose files no longer exist let validGIFs = gifs.filter { GIFFileManager.shared.fileExists(at: $0.localFilePath) } // If we filtered any out, save the updated list if validGIFs.count != gifs.count { saveToUserDefaults(gifs: validGIFs) } return validGIFs.sorted(by: { $0.createdAt > $1.createdAt }) } func deleteGIF(with id: UUID) { var savedGIFs = fetchGIFs() // Find the GIF to delete if let gifToDelete = savedGIFs.first(where: { $0.id == id }) { // Delete the file from storage GIFFileManager.shared.deleteGIF(at: gifToDelete.localFilePath) // Remove from the list savedGIFs.removeAll(where: { $0.id == id }) saveToUserDefaults(gifs: savedGIFs) } } func clearAllGIFs() { // Delete all GIF files fetchGIFs().forEach { gif in GIFFileManager.shared.deleteGIF(at: gif.localFilePath) } // Clear the list saveToUserDefaults(gifs: []) } private func saveToUserDefaults(gifs: [GIF]) { guard let data = try? JSONEncoder().encode(gifs) else { return } userDefaults?.set(data, forKey: savedGIFsKey) } func getGIFData(for gif: GIF) -> Data? { return GIFFileManager.shared.loadGIFData(from: gif.localFilePath) } // MARK: - Share Extension Integration func checkForSharedGIFs() { guard let pendingGIFsData = userDefaults?.array(forKey: pendingGIFsKey) as? [[String: Any]] else { return } guard !pendingGIFsData.isEmpty else { return } var savedGIFs = fetchGIFs() var newGIFsAdded = false for gifInfo in pendingGIFsData { if let localFilePath = gifInfo["localFilePath"] as? String, let originalURL = gifInfo["originalURL"] as? String, let createdAt = gifInfo["createdAt"] as? TimeInterval { // Create a GIF object let gif = GIF( localFilePath: localFilePath, originalURL: originalURL ) // Don't add duplicates if !savedGIFs.contains(where: { $0.localFilePath == localFilePath }) { savedGIFs.append(gif) newGIFsAdded = true } } } // Save updated GIFs list and clear pending ones if newGIFsAdded { saveToUserDefaults(gifs: savedGIFs) } // Clear pending GIFs userDefaults?.removeObject(forKey: pendingGIFsKey) } }