diff options
| author | Dustin Mierau <dustin@mierau.me> | 2024-01-17 23:18:27 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2024-01-17 23:18:27 -0800 |
| commit | 1b303803e53dbeb24dab1a7c714d71ee14f002db (patch) | |
| tree | 4616861b23642d26c9b58b5925315232c1fdb975 /Hotline/Models/Bookmarks.swift | |
| parent | 8e85fbbdadcb993cd270ff4bf60d2280b9e7ad56 (diff) | |
Added server and tracker bookmarks. Reordering in Servers window. Delete. All stored securely in Keychain.
Diffstat (limited to 'Hotline/Models/Bookmarks.swift')
| -rw-r--r-- | Hotline/Models/Bookmarks.swift | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/Hotline/Models/Bookmarks.swift b/Hotline/Models/Bookmarks.swift new file mode 100644 index 0000000..3f4971c --- /dev/null +++ b/Hotline/Models/Bookmarks.swift @@ -0,0 +1,126 @@ +import SwiftUI + +extension NSNotification { + static let BookmarkAdded = Notification.Name("BookmarkAdded") + static let BookmarkRemoved = Notification.Name("BookmarkRemoved") +} + +enum BookmarkType: String, Codable { + case tracker = "tracker" + case server = "server" +} + +struct Bookmark: Codable, Equatable { + let type: BookmarkType + let name: String + let address: String + let port: Int + let login: String? + let password: String? + + init(type: BookmarkType, name: String, address: String, port: Int = HotlinePorts.DefaultServerPort, login: String? = nil, password: String? = nil) { + self.type = type + self.name = name + self.address = address + self.port = port + self.login = login + self.password = password + } +} + +@Observable final class Bookmarks { + var bookmarks: [Bookmark]? = nil + + static let DefaultBookmarks: [Bookmark] = [ + Bookmark(type: .server, name: "System 7 Today", address: "hotline.system7today.com"), + Bookmark(type: .server, name: "The Mobius Strip", address: "67.174.208.111"), + Bookmark(type: .tracker, name: "Featured Servers", address: "hltracker.com"), + ] + + init() { + self.load() + } + + func apply(_ newBookmarks: [Bookmark], save shouldSave: Bool = true) { + self.bookmarks = newBookmarks + if shouldSave { + self.save() + } + } + + func load() { + let jsonString: String? = DAKeychain.shared["Hotline Bookmarks"] + let jsonData: Data? = jsonString?.data(using: .utf8, allowLossyConversion: false) + + let decoder = JSONDecoder() + var decodedBookmarks = try? decoder.decode([Bookmark].self, from: jsonData ?? Data()) + if decodedBookmarks == nil || decodedBookmarks?.isEmpty == true { + print("Bookmarks: using default bookmarks") + decodedBookmarks = Bookmarks.DefaultBookmarks + } + else { + print("Bookmarks: using saved bookmarks") + } + + self.bookmarks = [Bookmark](decodedBookmarks!) + } + + func save() { + var bookmarksToSave = self.bookmarks + if bookmarksToSave == Bookmarks.DefaultBookmarks { + print("Bookmarks: skipping saving default bookmarks") + bookmarksToSave = [] + } + + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + if let jsonData = try? encoder.encode(bookmarksToSave) { + if let jsonString = String(data: jsonData, encoding: .utf8) { + DAKeychain.shared["Hotline Bookmarks"] = jsonString + } + } + } + + // MARK: - + + func add(_ bookmark: Bookmark, save shouldSave: Bool = true) { + self.bookmarks?.insert(bookmark, at: 0) + + if shouldSave { + self.save() + } + + DispatchQueue.main.async { + NotificationCenter.default.post(name: NSNotification.BookmarkAdded, object: nil, userInfo: ["index": 0]) + } + } + + func delete(_ bookmark: Bookmark, save shouldSave: Bool = true) -> Bool { + if let i = self.bookmarks?.firstIndex(where: { b in b.address.lowercased() == bookmark.address.lowercased() && b.port == bookmark.port }) { + self.bookmarks?.remove(at: i) + + if shouldSave { + self.save() + } + + DispatchQueue.main.async { + NotificationCenter.default.post(name: NSNotification.BookmarkRemoved, object: nil, userInfo: ["index": i]) + } + return true + } + + return false + } + + func update(_ bookmark: Bookmark, save shouldSave: Bool = true) -> Bool { + if let i = self.bookmarks?.firstIndex(where: { b in b.address.lowercased() == bookmark.address.lowercased() && b.port == bookmark.port }) { + self.bookmarks?[i] = bookmark + if shouldSave { + self.save() + } + return true + } + + return false + } +} |