1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
import SwiftUI
extension NSNotification {
static let BookmarkAdded = Notification.Name("BookmarkAdded")
static let BookmarkRemoved = Notification.Name("BookmarkRemoved")
}
enum BookmarkOldType: String, Codable {
case tracker = "tracker"
case server = "server"
}
struct BookmarkOld: Codable, Equatable {
let type: BookmarkOldType
let name: String
let address: String
let port: Int
let login: String?
let password: String?
init(type: BookmarkOldType, 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 BookmarksOld {
var bookmarks: [BookmarkOld]? = nil
static let DefaultBookmarks: [BookmarkOld] = [
BookmarkOld(type: .server, name: "System 7 Today", address: "hotline.system7today.com"),
BookmarkOld(type: .server, name: "The Mobius Strip", address: "67.174.208.111"),
BookmarkOld(type: .tracker, name: "Featured Servers", address: "hltracker.com"),
]
init() {
self.load()
}
func apply(_ newBookmarks: [BookmarkOld], 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([BookmarkOld].self, from: jsonData ?? Data())
if decodedBookmarks == nil || decodedBookmarks?.isEmpty == true {
print("Bookmarks: using default bookmarks")
decodedBookmarks = BookmarksOld.DefaultBookmarks
}
else {
print("Bookmarks: using saved bookmarks")
}
self.bookmarks = [BookmarkOld](decodedBookmarks!)
}
func save() {
var bookmarksToSave = self.bookmarks
if bookmarksToSave == BookmarksOld.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: BookmarkOld, 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: BookmarkOld, 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: BookmarkOld, 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
}
}
|