import Foundation /// Quell- und Zielordner, persistiert über Security-Scoped Bookmarks statt /// roher Pfade — überlebt damit auch einen späteren Wechsel in den App /// Sandbox (README: "@AppStorage + Security-Scoped Bookmarks"). @MainActor final class AppSettings: ObservableObject { @Published private(set) var sourceFolder: URL? @Published private(set) var targetFolder: URL? private enum DefaultsKey { static let sourceBookmark = "dev.zielke.droptwo.sourceFolderBookmark" static let targetBookmark = "dev.zielke.droptwo.targetFolderBookmark" } init() { sourceFolder = Self.resolveBookmark(forKey: DefaultsKey.sourceBookmark) targetFolder = Self.resolveBookmark(forKey: DefaultsKey.targetBookmark) } func setSourceFolder(_ url: URL) { sourceFolder = url Self.storeBookmark(for: url, key: DefaultsKey.sourceBookmark) } func setTargetFolder(_ url: URL) { targetFolder = url Self.storeBookmark(for: url, key: DefaultsKey.targetBookmark) } private static func storeBookmark(for url: URL, key: String) { do { let data = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) UserDefaults.standard.set(data, forKey: key) } catch { // Best effort: der Ordner bleibt für die laufende Sitzung trotzdem // gesetzt, nur der Neustart-Fall geht dann verloren. } } private static func resolveBookmark(forKey key: String) -> URL? { guard let data = UserDefaults.standard.data(forKey: key) else { return nil } var isStale = false guard let url = try? URL(resolvingBookmarkData: data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) else { return nil } _ = url.startAccessingSecurityScopedResource() return url } }