From 18596d527562396ffb8c6cfd55d89298d0c025af Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 08:40:19 +0800 Subject: [PATCH] Repo // Add BookmarkManager. --- Source/3rdParty/Sandbox/BookmarkManager.swift | 101 ++++++++++++++++++ vChewing.xcodeproj/project.pbxproj | 12 +++ 2 files changed, 113 insertions(+) create mode 100644 Source/3rdParty/Sandbox/BookmarkManager.swift diff --git a/Source/3rdParty/Sandbox/BookmarkManager.swift b/Source/3rdParty/Sandbox/BookmarkManager.swift new file mode 100644 index 00000000..ba1d03f0 --- /dev/null +++ b/Source/3rdParty/Sandbox/BookmarkManager.swift @@ -0,0 +1,101 @@ +// +// Ref: https://stackoverflow.com/a/61695824 +// License: https://creativecommons.org/licenses/by-sa/4.0/ +// + +import Cocoa + +class BookmarkManager { + static let shared = BookmarkManager() + // Save bookmark for URL. Use this inside the NSOpenPanel `begin` closure + func saveBookmark(for url: URL) { + guard let bookmarkDic = getBookmarkData(url: url), + let bookmarkURL = getBookmarkURL() + else { + IME.prtDebugIntel("Error getting data or bookmarkURL") + return + } + + if #available(macOS 10.13, *) { + do { + let data = try NSKeyedArchiver.archivedData(withRootObject: bookmarkDic, requiringSecureCoding: false) + try data.write(to: bookmarkURL) + IME.prtDebugIntel("Did save data to url") + } catch { + IME.prtDebugIntel("Couldn't save bookmarks") + } + } + } + + // Load bookmarks when your app launch for example + func loadBookmarks() { + guard let url = getBookmarkURL() else { + return + } + + if fileExists(url) { + do { + let fileData = try Data(contentsOf: url) + if let fileBookmarks = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(fileData) as! [URL: Data]? { + for bookmark in fileBookmarks { + restoreBookmark(key: bookmark.key, value: bookmark.value) + } + } + } catch { + IME.prtDebugIntel("Couldn't load bookmarks") + } + } + } + + private func restoreBookmark(key: URL, value: Data) { + let restoredUrl: URL? + var isStale = false + + IME.prtDebugIntel("Restoring \(key)") + do { + restoredUrl = try URL( + resolvingBookmarkData: value, options: NSURL.BookmarkResolutionOptions.withSecurityScope, relativeTo: nil, + bookmarkDataIsStale: &isStale + ) + } catch { + IME.prtDebugIntel("Error restoring bookmarks") + restoredUrl = nil + } + + if let url = restoredUrl { + if isStale { + IME.prtDebugIntel("URL is stale") + } else { + if !url.startAccessingSecurityScopedResource() { + IME.prtDebugIntel("Couldn't access: \(url.path)") + } + } + } + } + + private func getBookmarkData(url: URL) -> [URL: Data]? { + let data = try? url.bookmarkData( + options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil + ) + if let data = data { + return [url: data] + } + return nil + } + + private func getBookmarkURL() -> URL? { + let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask) + if let appSupportURL = urls.last { + let url = appSupportURL.appendingPathComponent("Bookmarks.dict") + return url + } + return nil + } + + private func fileExists(_ url: URL) -> Bool { + var isDir = ObjCBool(false) + let exists = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDir) + + return exists + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 42bd02d2..76583ce6 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 5B09307628B6FC3B0021F8C5 /* shortcuts.html in Resources */ = {isa = PBXBuildFile; fileRef = 5B09307828B6FC3B0021F8C5 /* shortcuts.html */; }; 5B0AF8B527B2C8290096FE54 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0AF8B427B2C8290096FE54 /* StringExtension.swift */; }; 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */; }; + 5B20430728BEE30900BFC6FD /* BookmarkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */; }; 5B21176C287539BB000443A9 /* ctlInputMethod_HandleStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */; }; 5B21176E28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176D28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift */; }; 5B21177028753B9D000443A9 /* ctlInputMethod_Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176F28753B9D000443A9 /* ctlInputMethod_Delegates.swift */; }; @@ -217,6 +218,7 @@ 5B18BA7227C7BD8B0056EB19 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-JPN.txt"; sourceTree = ""; }; 5B18BA7427C7BD8C0056EB19 /* LICENSE-CHT.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-CHT.txt"; sourceTree = ""; }; + 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkManager.swift; sourceTree = ""; }; 5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_HandleStates.swift; sourceTree = ""; }; 5B21176D28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_HandleDisplay.swift; sourceTree = ""; }; 5B21176F28753B9D000443A9 /* ctlInputMethod_Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_Delegates.swift; sourceTree = ""; }; @@ -427,6 +429,14 @@ name = MiscRootFiles; sourceTree = ""; }; + 5B20430528BEE2F300BFC6FD /* Sandbox */ = { + isa = PBXGroup; + children = ( + 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */, + ); + path = Sandbox; + sourceTree = ""; + }; 5B2F2BB4286216A500B8557B /* vChewingTests */ = { isa = PBXGroup; children = ( @@ -457,6 +467,7 @@ 5B84579B2871AD2200C93B01 /* HotenkaChineseConverter */, 5B949BD72816DC4400D87B5D /* LineReader */, 5BA58644289BCFAC0077D02F /* Qwertyyb */, + 5B20430528BEE2F300BFC6FD /* Sandbox */, 5BA9FCEA27FED652002DE248 /* SindreSorhus */, 5BA9FD8C28006BA7002DE248 /* VDKComboBox */, ); @@ -1242,6 +1253,7 @@ 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */, 5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */, 5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */, + 5B20430728BEE30900BFC6FD /* BookmarkManager.swift in Sources */, 5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */, 5B2170E8289FACAD00BE7304 /* 5_Vertex.swift in Sources */, 5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */,