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 | |
| parent | 8e85fbbdadcb993cd270ff4bf60d2280b9e7ad56 (diff) | |
Added server and tracker bookmarks. Reordering in Servers window. Delete. All stored securely in Keychain.
Diffstat (limited to 'Hotline/Models')
| -rw-r--r-- | Hotline/Models/Bookmarks.swift | 126 | ||||
| -rw-r--r-- | Hotline/Models/Hotline.swift | 67 | ||||
| -rw-r--r-- | Hotline/Models/Tracker.swift | 7 |
3 files changed, 133 insertions, 67 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 + } +} diff --git a/Hotline/Models/Hotline.swift b/Hotline/Models/Hotline.swift index 77d4d59..6b5e3a7 100644 --- a/Hotline/Models/Hotline.swift +++ b/Hotline/Models/Hotline.swift @@ -103,73 +103,6 @@ final class Hotline: HotlineClientDelegate, HotlineFileClientDelegate { 6029, 6030, 6031, 6032, 6033, 6034, 6035 ] - static let defaultIconSet: [Int: String] = [ - 414: "๐", - 2000: "๐", - 2001: "๐", - 2002: "๐ชฉ", - 2003: "๐ฅ", - 2004: "๐", - 2014: "๐", - 2006: "๐ ", - 2007: "๐ฆ ", - 2008: "๐ช", - 2009: "๐", - 2010: "๐", - 2011: "๐", - 2012: "๐ฆ", - 145: "๐", - 2015: "๐ป", - 2016: "๐ป", - 2017: "โ๏ธ", - 2018: "โก๏ธ", - 417: "๐งโโ๏ธ", - 140: "๐จ", - 141: "๐ฝ", - 142: "๐", - 143: "๐ท๏ธ", - 138: "๐บ", - 146: "๐
", - 149: "๐ฎ", - 150: "๐ฆ", - 151: "๐งป", - 154: "๐", - 182: "โ", - 207: "โ ๏ธ", - 2061: "โ๏ธ", - 2063: "๐ฎ", - 2064: "๐", - 2065: "๐", - 2066: "๐ญ", - 2067: "๐ญ", - 2013: "๐ง", - 2037: "โ ๏ธ", - 2055: "โก๏ธ", - 2400: "๐จ๐ฆ", - 2036: "โฃ๏ธ", - 4134: "๐ฆ", - 4247: "๐", - 135: "โฏ๏ธ", - 137: "๐", - 144: "๐", - 165: "๐ถ", - 166: "โค๏ธ", - 2549: "๐ฎ๐ฑ", - 2553: "๐บ๐ธ", - 2555: "๐จ๐ฆ", - 2552: "๐ฎ๐ณ", - 2556: "๐ฆ๐บ", - 2565: "๐ฌ๐ง", - 2567: "๐ฏ๐ต", - 2566: "๐ซ๐ท", - 2564: "๐ฉ๐ช", - 2563: "๐ฎ๐น", - 2550: "๐ญ๐บ", - 2551: "๐ต๐ฑ", - 2560: "๐ช๐ธ", - 2561: "๐ธ๐ช", - ] - var status: HotlineClientStatus = .disconnected var server: Server? { diff --git a/Hotline/Models/Tracker.swift b/Hotline/Models/Tracker.swift index e9961e9..171cb35 100644 --- a/Hotline/Models/Tracker.swift +++ b/Hotline/Models/Tracker.swift @@ -8,4 +8,11 @@ import SwiftUI self.address = address self.port = port } + + static func parseTrackerAddressAndPort(_ address: String) -> (String, Int) { + let url = URL(string: "hotlinetracker://\(address)") + let port = url?.port ?? HotlinePorts.DefaultTrackerPort + let host = url?.host(percentEncoded: false) ?? "" + return (host.lowercased().trimmingCharacters(in: .whitespacesAndNewlines), port) + } } |