Something went wrong. Try again.
forked from cranci1/sora
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201//// LibraryManager.swift// Sora//// Created by Francesco on 12/01/25.//
import Foundationimport SwiftUIimport NukeUIimport Nuke
struct BookmarkCollection: Codable, Identifiable { let id: UUID let name: String var bookmarks: [LibraryItem] let dateCreated: Date init(name: String, bookmarks: [LibraryItem] = []) { self.id = UUID() self.name = name self.bookmarks = bookmarks self.dateCreated = Date() }}
struct LibraryItem: Codable, Identifiable { let id: UUID let title: String let imageUrl: String let href: String let moduleId: String let moduleName: String let dateAdded: Date init(title: String, imageUrl: String, href: String, moduleId: String, moduleName: String) { self.id = UUID() self.title = title self.imageUrl = imageUrl self.href = href self.moduleId = moduleId self.moduleName = moduleName self.dateAdded = Date() }}
class LibraryManager: ObservableObject { @Published var collections: [BookmarkCollection] = [] @Published var isShowingCollectionPicker: Bool = false @Published var bookmarkToAdd: LibraryItem? private let collectionsKey = "bookmarkCollections" private let oldBookmarksKey = "bookmarkedItems" init() { migrateOldBookmarks() loadCollections() NotificationCenter.default.addObserver(self, selector: #selector(handleiCloudSync), name: .iCloudSyncDidComplete, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleModuleRemoval), name: .moduleRemoved, object: nil) } @objc private func handleiCloudSync() { DispatchQueue.main.async { self.loadCollections() } } @objc private func handleModuleRemoval(_ notification: Notification) { if let moduleId = notification.object as? String { cleanupBookmarksForModule(moduleId: moduleId) } } private func cleanupBookmarksForModule(moduleId: String) { var didChange = false for (collectionIndex, collection) in collections.enumerated() { let originalCount = collection.bookmarks.count collections[collectionIndex].bookmarks.removeAll { $0.moduleId == moduleId } if collections[collectionIndex].bookmarks.count != originalCount { didChange = true } } if didChange { ImagePipeline.shared.cache.removeAll() saveCollections() } } private func migrateOldBookmarks() { guard let data = UserDefaults.standard.data(forKey: oldBookmarksKey) else { return } do { let oldBookmarks = try JSONDecoder().decode([LibraryItem].self, from: data) if !oldBookmarks.isEmpty { if let existingIndex = collections.firstIndex(where: { $0.name == "Old Bookmarks" }) { for bookmark in oldBookmarks { if !collections[existingIndex].bookmarks.contains(where: { $0.href == bookmark.href }) { collections[existingIndex].bookmarks.insert(bookmark, at: 0) } } } else { let oldCollection = BookmarkCollection(name: "Old Bookmarks", bookmarks: oldBookmarks) collections.append(oldCollection) } saveCollections() } UserDefaults.standard.removeObject(forKey: oldBookmarksKey) } catch { Logger.shared.log("Failed to migrate old bookmarks: \(error)", type: "Error") } } private func loadCollections() { guard let data = UserDefaults.standard.data(forKey: collectionsKey) else { Logger.shared.log("No collections data found in UserDefaults.", type: "Debug") return } do { collections = try JSONDecoder().decode([BookmarkCollection].self, from: data) } catch { Logger.shared.log("Failed to decode collections: \(error.localizedDescription)", type: "Error") } } private func saveCollections() { do { let encoded = try JSONEncoder().encode(collections) UserDefaults.standard.set(encoded, forKey: collectionsKey) } catch { Logger.shared.log("Failed to save collections: \(error)", type: "Error") } } func createCollection(name: String) { let newCollection = BookmarkCollection(name: name) collections.append(newCollection) saveCollections() } func deleteCollection(id: UUID) { collections.removeAll { $0.id == id } saveCollections() } func addBookmarkToCollection(bookmark: LibraryItem, collectionId: UUID) { if let index = collections.firstIndex(where: { $0.id == collectionId }) { if !collections[index].bookmarks.contains(where: { $0.href == bookmark.href }) { collections[index].bookmarks.insert(bookmark, at: 0) saveCollections() } } } func removeBookmarkFromCollection(bookmarkId: UUID, collectionId: UUID) { if let collectionIndex = collections.firstIndex(where: { $0.id == collectionId }) { collections[collectionIndex].bookmarks.removeAll { $0.id == bookmarkId } saveCollections() } } func isBookmarked(href: String, moduleName: String) -> Bool { for collection in collections { if collection.bookmarks.contains(where: { $0.href == href }) { return true } } return false } func toggleBookmark(title: String, imageUrl: String, href: String, moduleId: String, moduleName: String) { for (collectionIndex, collection) in collections.enumerated() { if let bookmarkIndex = collection.bookmarks.firstIndex(where: { $0.href == href }) { collections[collectionIndex].bookmarks.remove(at: bookmarkIndex) saveCollections() return } } let bookmark = LibraryItem(title: title, imageUrl: imageUrl, href: href, moduleId: moduleId, moduleName: moduleName) bookmarkToAdd = bookmark isShowingCollectionPicker = true } func renameCollection(id: UUID, newName: String) { if let index = collections.firstIndex(where: { $0.id == id }) { var updated = collections[index] updated = BookmarkCollection(name: newName, bookmarks: updated.bookmarks) collections[index] = BookmarkCollection(name: newName, bookmarks: updated.bookmarks) saveCollections() } }}