aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-02-02 23:19:57 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-02-02 23:19:57 +0100
commitc676230cbc7da1c2c4d5540f89da32e9228deffd (patch)
treeb47f940282ee552b2608d847a9ce5e06b5749f29 /Hotline
parent77b3ac3c051fc4e8fa126cd21e261be28f4aad1a (diff)
Add autoconnect + reconnect logic
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Application-macOS.swift21
-rw-r--r--Hotline/Hotline.entitlements2
-rw-r--r--Hotline/Hotline/HotlineClient.swift2
-rw-r--r--Hotline/Info.plist2
-rw-r--r--Hotline/Models/Bookmark.swift9
-rw-r--r--Hotline/Models/Server.swift4
-rw-r--r--Hotline/Shared/NetSocket.swift6
-rw-r--r--Hotline/macOS/MessageBoardEditorView.swift2
-rw-r--r--Hotline/macOS/ServerView.swift40
-rw-r--r--Hotline/macOS/TrackerView.swift17
10 files changed, 70 insertions, 35 deletions
diff --git a/Hotline/Application-macOS.swift b/Hotline/Application-macOS.swift
index fe3a828..36f9aa8 100644
--- a/Hotline/Application-macOS.swift
+++ b/Hotline/Application-macOS.swift
@@ -42,25 +42,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
}
}
-
-// if FileManager.default.ubiquityIdentityToken == nil {
-// print("iCloud Unavailable")
-//
-// // We mark CloudKit has available now since we're not waiting on
-// // a server sync or anything.
-// ApplicationState.shared.cloudKitReady = true
-// }
-// else {
-// print("iCloud Available")
-//
-// self.cloudKitObserverToken = NotificationCenter.default.addObserver(forName: NSPersistentCloudKitContainer.eventChangedNotification, object: nil, queue: OperationQueue.main) { [weak self] note in
-// print("iCloud Changed!")
-// ApplicationState.shared.cloudKitReady = true
-//
-// guard let token = self?.cloudKitObserverToken else { return }
-// NotificationCenter.default.removeObserver(token)
-// }
-// }
}
func applicationWillTerminate(_ notification: Notification) {
@@ -86,7 +67,7 @@ struct Application: App {
let schema = Schema([
Bookmark.self
])
- let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .private("iCloud.co.goodmake.hotline"))
+ let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .private("iCloud.pizza.unlimited.hotline"))
let modelContainer = try! ModelContainer(for: schema, configurations: [config])
// Print local SwiftData sqlite file.
diff --git a/Hotline/Hotline.entitlements b/Hotline/Hotline.entitlements
index e15d27d..5baba22 100644
--- a/Hotline/Hotline.entitlements
+++ b/Hotline/Hotline.entitlements
@@ -8,7 +8,7 @@
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
- <string>iCloud.co.goodmake.hotline</string>
+ <string>iCloud.pizza.unlimited.hotline</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
diff --git a/Hotline/Hotline/HotlineClient.swift b/Hotline/Hotline/HotlineClient.swift
index 434285f..063419d 100644
--- a/Hotline/Hotline/HotlineClient.swift
+++ b/Hotline/Hotline/HotlineClient.swift
@@ -33,7 +33,7 @@ private struct HotlineLogin {
protocol HotlineClientDelegate: AnyObject {
func hotlineGetUserInfo() -> (String, UInt16)
- func hotlineStatusChanged(status: HotlineClientStatus)
+ @MainActor func hotlineStatusChanged(status: HotlineClientStatus)
func hotlineReceivedAgreement(text: String)
func hotlineReceivedErrorMessage(code: UInt32, message: String?)
func hotlineReceivedChatMessage(message: String)
diff --git a/Hotline/Info.plist b/Hotline/Info.plist
index b43d991..a84b52a 100644
--- a/Hotline/Info.plist
+++ b/Hotline/Info.plist
@@ -5,6 +5,8 @@
<key>CFBundleDocumentTypes</key>
<array>
<dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
<key>CFBundleTypeName</key>
<string>Hotline Bookmark</string>
<key>LSHandlerRank</key>
diff --git a/Hotline/Models/Bookmark.swift b/Hotline/Models/Bookmark.swift
index 733a6eb..b410f75 100644
--- a/Hotline/Models/Bookmark.swift
+++ b/Hotline/Models/Bookmark.swift
@@ -22,6 +22,9 @@ final class Bookmark {
@Attribute(.allowsCloudEncryption)
var password: String?
+ @Attribute
+ var autoconnect: Bool = false
+
@Attribute(.ephemeral)
var expanded: Bool = false
@@ -69,7 +72,7 @@ final class Bookmark {
return nil
case .server, .temporary:
- return Server(name: self.name, description: self.serverDescription, address: self.address, port: self.port, login: self.login, password: self.password)
+ return Server(name: self.name, description: self.serverDescription, address: self.address, port: self.port, login: self.login, password: self.password, autoconnect: self.autoconnect)
}
}
@@ -79,7 +82,7 @@ final class Bookmark {
Bookmark(type: .tracker, name: "Featured Servers", address: "hltracker.com", port: HotlinePorts.DefaultTrackerPort)
]
- init(type: BookmarkType, name: String, address: String, port: Int, login: String? = nil, password: String? = nil) {
+ init(type: BookmarkType, name: String, address: String, port: Int, login: String? = nil, password: String? = nil, autoconnect: Bool = false) {
self.type = type
self.name = name
self.address = address
@@ -87,6 +90,8 @@ final class Bookmark {
self.login = login
self.password = password
+
+ self.autoconnect = autoconnect
}
init(temporaryServer server: Server) {
diff --git a/Hotline/Models/Server.swift b/Hotline/Models/Server.swift
index e0fe38b..3f4c9e8 100644
--- a/Hotline/Models/Server.swift
+++ b/Hotline/Models/Server.swift
@@ -9,8 +9,9 @@ struct Server: Codable {
var port: Int
var login: String
var password: String
+ var autoconnect: Bool = false
- init(name: String?, description: String?, address: String, port: Int = HotlinePorts.DefaultServerPort, users: Int = 0, login: String? = nil, password: String? = nil) {
+ init(name: String?, description: String?, address: String, port: Int = HotlinePorts.DefaultServerPort, users: Int = 0, login: String? = nil, password: String? = nil, autoconnect: Bool? = false) {
self.name = name
self.description = description
self.address = address.lowercased()
@@ -18,6 +19,7 @@ struct Server: Codable {
self.users = users
self.login = login ?? ""
self.password = password ?? ""
+ self.autoconnect = autoconnect ?? false
}
init?(url: URL) {
diff --git a/Hotline/Shared/NetSocket.swift b/Hotline/Shared/NetSocket.swift
index a7d44ce..263487b 100644
--- a/Hotline/Shared/NetSocket.swift
+++ b/Hotline/Shared/NetSocket.swift
@@ -6,9 +6,9 @@
import Foundation
protocol NetSocketDelegate: AnyObject {
- func netsocketConnected(socket: NetSocket)
- func netsocketDisconnected(socket: NetSocket, error: Error?)
- func netsocketReceived(socket: NetSocket, bytes: [UInt8])
+ @MainActor func netsocketConnected(socket: NetSocket)
+ @MainActor func netsocketDisconnected(socket: NetSocket, error: Error?)
+ @MainActor func netsocketReceived(socket: NetSocket, bytes: [UInt8])
func netsocketSent(socket: NetSocket, count: Int)
}
diff --git a/Hotline/macOS/MessageBoardEditorView.swift b/Hotline/macOS/MessageBoardEditorView.swift
index 029616f..474384e 100644
--- a/Hotline/macOS/MessageBoardEditorView.swift
+++ b/Hotline/macOS/MessageBoardEditorView.swift
@@ -20,7 +20,7 @@ struct MessageBoardEditorView: View {
let cleanedText = text.trimmingCharacters(in: .whitespacesAndNewlines)
- await model.postToMessageBoard(text: cleanedText)
+ model.postToMessageBoard(text: cleanedText)
let _ = await model.getMessageBoard()
// let success = await model.postNewsArticle(title: title, body: text, at: path, parentID: parentID)
diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift
index e9f4a96..1e53e49 100644
--- a/Hotline/macOS/ServerView.swift
+++ b/Hotline/macOS/ServerView.swift
@@ -143,6 +143,8 @@ struct ServerView: View {
@Environment(\.scenePhase) private var scenePhase
@Environment(\.modelContext) private var modelContext
+ @State private var reconnectTimer: Task<Void, Never>?
+ @State private var shouldReconnect: Bool = false
@State private var model: Hotline = Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient())
@State private var state: ServerState = ServerState(selection: .chat)
@State private var agreementShown: Bool = false
@@ -151,6 +153,7 @@ struct ServerView: View {
@State private var connectPassword: String = ""
@State private var connectNameSheetPresented: Bool = false
@State private var connectName: String = ""
+ @State private var autoconnect: Bool = false
@Binding var server: Server
@@ -227,6 +230,16 @@ struct ServerView: View {
.onDisappear {
model.disconnect()
}
+ .onChange(of: model.status) {
+ if model.status == .loggedIn {
+ reconnectTimer?.cancel()
+ shouldReconnect = server.autoconnect
+ }
+ if model.status == .disconnected && shouldReconnect {
+ shouldReconnect = false
+ startReconnectTimer()
+ }
+ }
.alert(model.errorMessage ?? "Server Error", isPresented: $model.errorDisplayed) {
Button("OK") {}
}
@@ -248,6 +261,15 @@ struct ServerView: View {
.focusedSceneValue(\.activeServerState, state)
}
+ private func startReconnectTimer() {
+ reconnectTimer = Task {
+ while !Task.isCancelled {
+ connectToServer()
+ try? await Task.sleep(for: .seconds(5))
+ }
+ }
+ }
+
var connectForm: some View {
VStack(alignment: .center) {
GroupBox {
@@ -297,7 +319,7 @@ struct ServerView: View {
Button("Connect") {
Task {
- await connectToServer()
+ connectToServer()
}
}
@@ -335,6 +357,7 @@ struct ServerView: View {
TextField("Bookmark Name", text: $connectName)
.textFieldStyle(.roundedBorder)
.controlSize(.large)
+ Toggle("Connect on Startup", isOn: $autoconnect)
}
.frame(width: 250)
.padding()
@@ -353,19 +376,24 @@ struct ServerView: View {
connectNameSheetPresented = false
connectName = ""
Task.detached {
- let (host, port) = Server.parseServerAddressAndPort(connectAddress)
- let login: String? = connectLogin.isEmpty ? nil : connectLogin
- let password: String? = connectPassword.isEmpty ? nil : connectPassword
+ let (host, port) = await Server.parseServerAddressAndPort(connectAddress)
+ let login: String? = await connectLogin.isEmpty ? nil : connectLogin
+ let password: String? = await connectPassword.isEmpty ? nil : connectPassword
if !host.isEmpty {
- let newBookmark = Bookmark(type: .server, name: name, address: host, port: port, login: login, password: password)
- Bookmark.add(newBookmark, context: modelContext)
+ let newBookmark = await Bookmark(type: .server, name: name, address: host, port: port, login: login, password: password, autoconnect: autoconnect)
+ await MainActor.run {
+ Bookmark.add(newBookmark, context: modelContext)
+ }
}
}
}
}
}
}
+ .onAppear {
+ autoconnect = false
+ }
}
}
diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift
index 0fac8b0..cdeef7f 100644
--- a/Hotline/macOS/TrackerView.swift
+++ b/Hotline/macOS/TrackerView.swift
@@ -24,6 +24,11 @@ struct TrackerView: View {
List(selection: $selection) {
ForEach(bookmarks, id: \.self) { bookmark in
TrackerItemView(bookmark: bookmark)
+ .onAppear {
+ if bookmark.autoconnect, let server = bookmark.server {
+ openWindow(id: "server", value: server)
+ }
+ }
.tag(bookmark)
if bookmark.type == .tracker && bookmark.expanded {
@@ -403,7 +408,19 @@ struct TrackerItemView: View {
.frame(width: 11, height: 11, alignment: .center)
.opacity(0.5)
.padding(.leading, 3)
+ Image(systemName: "bolt.fill")
+ .resizable()
+ .renderingMode(.template)
+ .aspectRatio(contentMode: .fit)
+ .frame(width: 13, height: 13, alignment: .center)
+ .opacity(0.5)
+ .padding(.leading, 3)
.padding(.trailing, 2)
+ .foregroundStyle(bookmark.autoconnect ? Color.accentColor : Color.gray)
+ .onTapGesture {
+ bookmark.autoconnect.toggle()
+ try? bookmark.modelContext?.save()
+ }
Image("Server")
.resizable()
.scaledToFit()