aboutsummaryrefslogtreecommitdiff
path: root/Hotline/State/AppState.swift
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-11-27 23:38:04 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-11-27 23:38:04 +0100
commit213710bf5bd6413c747bf126db50816ef5de5a6e (patch)
tree912f8cf87955a08077c92fea8ad934f50b7ab975 /Hotline/State/AppState.swift
parentf466b21dc02f78c984ba6748e703f6780a7a0db4 (diff)
parent6a95b53616a4abfa306ddce43151cf4fefbd20ed (diff)
Merge remote-tracking branch 'upstream/main'
Diffstat (limited to 'Hotline/State/AppState.swift')
-rw-r--r--Hotline/State/AppState.swift114
1 files changed, 114 insertions, 0 deletions
diff --git a/Hotline/State/AppState.swift b/Hotline/State/AppState.swift
new file mode 100644
index 0000000..e268ba2
--- /dev/null
+++ b/Hotline/State/AppState.swift
@@ -0,0 +1,114 @@
+import SwiftUI
+
+extension EnvironmentValues {
+ @Entry var appState: AppState = AppState.shared
+}
+
+@Observable
+final class AppState {
+ static let shared = AppState()
+
+ private init() {
+
+ }
+
+ var bonjourState = BonjourState()
+
+ var activeHotline: HotlineState? = nil
+ var activeServerState: ServerState? = nil
+
+ var cloudKitReady: Bool = false
+
+ // MARK: - Transfers
+
+ /// All active transfers across all servers
+ /// Transfers persist even if you disconnect from the server
+ var transfers: [TransferInfo] = []
+
+ @ObservationIgnored private var transferClients: [UUID: HotlineTransferClient] = [:]
+
+ /// Track download tasks by reference number for cancellation
+ @ObservationIgnored private var transferTasks: [UUID: Task<Void, Never>] = [:]
+
+ /// Add a transfer to the transfer list
+ @MainActor
+ func addTransfer(_ transfer: TransferInfo) {
+ self.transfers.append(transfer)
+ }
+
+ /// Cancel a transfer by transfer ID
+ @MainActor
+ func cancelTransfer(id: UUID) {
+ guard let transferIndex = self.transfers.firstIndex(where: { $0.id == id }) else {
+ return
+ }
+
+ // Cancel the task if it exists
+ if let task = self.transferTasks[id] {
+ task.cancel()
+ self.transferTasks.removeValue(forKey: id)
+ }
+
+ if let client = self.transferClients[id] {
+ client.cancel()
+ self.transferClients.removeValue(forKey: id)
+ }
+
+ // Remove from transfers list
+ self.transfers.remove(at: transferIndex)
+ }
+
+ /// Cancel specified transfers
+ @MainActor
+ func cancelTransfers(ids: [UUID]) {
+ for transferID in ids {
+ self.cancelTransfer(id: transferID)
+ }
+ }
+
+ /// Cancel all active transfers
+ @MainActor
+ func cancelAllTransfers() {
+ for (_, task) in self.transferTasks {
+ task.cancel()
+ }
+ self.transferTasks.removeAll()
+
+ for (_, client) in self.transferClients {
+ client.cancel()
+ }
+ self.transferClients.removeAll()
+
+ // Clear transfers
+ self.transfers.removeAll()
+ }
+
+ /// Remove all completed transfers
+ @MainActor
+ func sweepTransfers() {
+ for t in self.transfers {
+ if t.done {
+ self.cancelTransfer(id: t.id)
+ }
+ }
+ }
+
+ /// Register a transfer task
+ @MainActor
+ func registerTransferTask(_ task: Task<Void, Never>, transferID: UUID) {
+ self.transferTasks[transferID] = task
+ }
+
+ @MainActor
+ func registerTransferTask(_ task: Task<Void, Never>, transferID: UUID, client: HotlineTransferClient) {
+ self.transferTasks[transferID] = task
+ self.transferClients[transferID] = client
+ }
+
+ /// Unregister a download task (called on completion/failure)
+ @MainActor
+ func unregisterTransferTask(for transferID: UUID) {
+ self.transferTasks.removeValue(forKey: transferID)
+ self.transferClients.removeValue(forKey: transferID)
+ }
+}