-
-
Notifications
You must be signed in to change notification settings - Fork 143
Expand file tree
/
Copy pathWindowOpener.swift
More file actions
86 lines (74 loc) · 3.35 KB
/
WindowOpener.swift
File metadata and controls
86 lines (74 loc) · 3.35 KB
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
//
// WindowOpener.swift
// TablePro
//
// Bridges SwiftUI's openWindow environment action to imperative code.
// Stored on appear by ContentView, WelcomeViewModel, or ConnectionFormView.
//
import os
import SwiftUI
@MainActor
internal final class WindowOpener {
private static let logger = Logger(subsystem: "com.TablePro", category: "WindowOpener")
internal static let shared = WindowOpener()
private var readyContinuations: [CheckedContinuation<Void, Never>] = []
/// Set on appear by ContentView, WelcomeViewModel, or ConnectionFormView.
/// Safe to store — OpenWindowAction is app-scoped, not view-scoped.
internal var openWindow: OpenWindowAction? {
didSet {
if openWindow != nil {
for continuation in readyContinuations {
continuation.resume()
}
readyContinuations.removeAll()
}
}
}
/// Suspends until openWindow is set. Returns immediately if already available.
internal func waitUntilReady() async {
if openWindow != nil { return }
await withCheckedContinuation { continuation in
if openWindow != nil {
continuation.resume()
} else {
readyContinuations.append(continuation)
}
}
}
/// Ordered queue of pending payloads — windows requested via openNativeTab
/// but not yet acknowledged by MainContentView.configureWindow.
/// Ordered so consumeOldestPendingConnectionId returns the correct entry
/// when multiple windows open in quick succession (e.g., tab restore).
internal private(set) var pendingPayloads: [(id: UUID, connectionId: UUID)] = []
/// Whether any payloads are pending — used for orphan detection in windowDidBecomeKey.
internal var hasPendingPayloads: Bool { !pendingPayloads.isEmpty }
/// Opens a new native window tab with the given payload.
/// Falls back to .openMainWindow notification if openWindow is not yet available
/// (cold launch from Dock menu before any SwiftUI view has appeared).
internal func openNativeTab(_ payload: EditorTabPayload) {
pendingPayloads.append((id: payload.id, connectionId: payload.connectionId))
if let openWindow {
openWindow(id: "main", value: payload)
} else {
Self.logger.info("openWindow not set — falling back to .openMainWindow notification")
NotificationCenter.default.post(name: .openMainWindow, object: payload)
}
}
/// Called by MainContentView.configureWindow after the window is fully set up.
internal func acknowledgePayload(_ id: UUID) {
pendingPayloads.removeAll { $0.id == id }
}
/// Consumes and returns the connectionId for the oldest pending payload.
/// Removes the entry so subsequent calls return the next payload in order.
internal func consumeOldestPendingConnectionId() -> UUID? {
guard !pendingPayloads.isEmpty else { return nil }
return pendingPayloads.removeFirst().connectionId
}
/// Returns the tabbingIdentifier for a connection.
internal static func tabbingIdentifier(for connectionId: UUID) -> String {
if AppSettingsManager.shared.tabs.groupAllConnectionTabs {
return "com.TablePro.main"
}
return "com.TablePro.main.\(connectionId.uuidString)"
}
}