Skip to content

Commit 97912e4

Browse files
authored
fix: prevent welcome window freeze when opening database files from Finder (#455)
* fix: prevent welcome window freeze when opening database files from Finder * fix: restore welcome window when suppression times out after 15s * refactor: replace polling with event-driven welcome window suppression * fix: move suppression flag to connection handlers, fix sidebar width, add tests
1 parent a63c497 commit 97912e4

File tree

5 files changed

+337
-37
lines changed

5 files changed

+337
-37
lines changed

TablePro/AppDelegate+ConnectionHandler.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ extension AppDelegate {
7070
openNewConnectionWindow(for: connection)
7171

7272
Task { @MainActor in
73+
defer { self.endFileOpenSuppression() }
7374
do {
7475
try await DatabaseManager.shared.connectToSession(connection)
7576
for window in NSApp.windows where self.isWelcomeWindow(window) {
@@ -116,6 +117,7 @@ extension AppDelegate {
116117
openNewConnectionWindow(for: connection)
117118

118119
Task { @MainActor in
120+
defer { self.endFileOpenSuppression() }
119121
do {
120122
try await DatabaseManager.shared.connectToSession(connection)
121123
for window in NSApp.windows where self.isWelcomeWindow(window) {
@@ -161,6 +163,7 @@ extension AppDelegate {
161163
openNewConnectionWindow(for: connection)
162164

163165
Task { @MainActor in
166+
defer { self.endFileOpenSuppression() }
164167
do {
165168
try await DatabaseManager.shared.connectToSession(connection)
166169
for window in NSApp.windows where self.isWelcomeWindow(window) {
@@ -206,6 +209,7 @@ extension AppDelegate {
206209
openNewConnectionWindow(for: connection)
207210

208211
Task { @MainActor in
212+
defer { self.endFileOpenSuppression() }
209213
do {
210214
try await DatabaseManager.shared.connectToSession(connection)
211215
for window in NSApp.windows where self.isWelcomeWindow(window) {
@@ -252,7 +256,7 @@ extension AppDelegate {
252256
case .genericDatabaseFile(let url, let dbType): self.handleGenericDatabaseFile(url, type: dbType)
253257
}
254258
}
255-
self.scheduleWelcomeWindowSuppression()
259+
// Flag management is handled by endFileOpenSuppression() in each handler
256260
}
257261
}
258262

TablePro/AppDelegate+FileOpen.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extension AppDelegate {
5353
suppressWelcomeWindow()
5454
Task { @MainActor in
5555
for url in databaseURLs { self.handleDatabaseURL(url) }
56-
self.scheduleWelcomeWindowSuppression()
56+
// Flag management is handled by endFileOpenSuppression() in each handler
5757
}
5858
}
5959

@@ -72,7 +72,7 @@ extension AppDelegate {
7272
self.handleGenericDatabaseFile(url, type: dbType)
7373
}
7474
}
75-
self.scheduleWelcomeWindowSuppression()
75+
// Flag management is handled by endFileOpenSuppression() in each handler
7676
}
7777
}
7878

@@ -87,7 +87,7 @@ extension AppDelegate {
8787
window.close()
8888
}
8989
NotificationCenter.default.post(name: .openSQLFiles, object: sqlFiles)
90-
scheduleWelcomeWindowSuppression()
90+
endFileOpenSuppression()
9191
} else {
9292
queuedFileURLs.append(contentsOf: sqlFiles)
9393
openWelcomeWindow()

TablePro/AppDelegate+WindowConfig.swift

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -190,26 +190,24 @@ extension AppDelegate {
190190

191191
// MARK: - Welcome Window Suppression
192192

193-
func scheduleWelcomeWindowSuppression() {
194-
Task { @MainActor [weak self] in
195-
try? await Task.sleep(for: .milliseconds(200))
196-
self?.closeWelcomeWindowIfMainExists()
197-
try? await Task.sleep(for: .milliseconds(500))
198-
guard let self else { return }
199-
self.closeWelcomeWindowIfMainExists()
200-
self.fileOpenSuppressionCount = max(0, self.fileOpenSuppressionCount - 1)
201-
if self.fileOpenSuppressionCount == 0 {
202-
self.isHandlingFileOpen = false
203-
}
193+
/// Called by connection handlers when the file-open connection attempt finishes
194+
/// (success or failure). Decrements the suppression counter and resets the flag
195+
/// when all outstanding file opens have completed.
196+
func endFileOpenSuppression() {
197+
fileOpenSuppressionCount = max(0, fileOpenSuppressionCount - 1)
198+
if fileOpenSuppressionCount == 0 {
199+
isHandlingFileOpen = false
204200
}
205201
}
206202

207-
private func closeWelcomeWindowIfMainExists() {
203+
@discardableResult
204+
private func closeWelcomeWindowIfMainExists() -> Bool {
208205
let hasMainWindow = NSApp.windows.contains { isMainWindow($0) && $0.isVisible }
209-
guard hasMainWindow else { return }
206+
guard hasMainWindow else { return false }
210207
for window in NSApp.windows where isWelcomeWindow(window) {
211208
window.close()
212209
}
210+
return true
213211
}
214212

215213
// MARK: - Window Notifications
@@ -219,9 +217,13 @@ extension AppDelegate {
219217
let windowId = ObjectIdentifier(window)
220218

221219
if isWelcomeWindow(window) && isHandlingFileOpen {
222-
window.close()
223-
for mainWin in NSApp.windows where isMainWindow(mainWin) {
220+
// Only close welcome if a main window exists to take its place;
221+
// otherwise just hide it so the user doesn't see a flash.
222+
if let mainWin = NSApp.windows.first(where: { isMainWindow($0) }) {
223+
window.close()
224224
mainWin.makeKeyAndOrderFront(nil)
225+
} else {
226+
window.orderOut(nil)
225227
}
226228
return
227229
}
@@ -236,6 +238,10 @@ extension AppDelegate {
236238
configuredWindows.insert(windowId)
237239
}
238240

241+
if isMainWindow(window) && isHandlingFileOpen {
242+
closeWelcomeWindowIfMainExists()
243+
}
244+
239245
if isMainWindow(window) && !configuredWindows.contains(windowId) {
240246
window.tabbingMode = .preferred
241247
let pendingId = MainActor.assumeIsolated { WindowOpener.shared.consumePendingConnectionId() }

TablePro/ContentView.swift

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ struct ContentView: View {
157157

158158
@ViewBuilder
159159
private var mainContent: some View {
160-
if let currentSession = currentSession, let rightPanelState, let sessionState {
161-
NavigationSplitView(columnVisibility: $columnVisibility) {
162-
// MARK: - Sidebar (Left) - Table Browser
160+
NavigationSplitView(columnVisibility: $columnVisibility) {
161+
// MARK: - Sidebar (Left) - Table Browser
162+
if let currentSession = currentSession, let sessionState {
163163
VStack(spacing: 0) {
164164
SidebarView(
165165
tables: sessionTablesBinding,
@@ -198,8 +198,13 @@ struct ContentView: View {
198198
prompt: sidebarSearchPrompt(for: currentSession.connection.id)
199199
)
200200
.navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 600)
201-
} detail: {
202-
// MARK: - Detail (Main workspace with optional right sidebar)
201+
} else {
202+
Color.clear
203+
.navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 600)
204+
}
205+
} detail: {
206+
// MARK: - Detail (Main workspace with optional right sidebar)
207+
if let currentSession = currentSession, let rightPanelState, let sessionState {
203208
HStack(spacing: 0) {
204209
MainContentView(
205210
connection: currentSession.connection,
@@ -235,21 +240,20 @@ struct ContentView: View {
235240
}
236241
}
237242
.animation(.easeInOut(duration: 0.2), value: rightPanelState.isPresented)
243+
} else {
244+
VStack(spacing: 16) {
245+
ProgressView()
246+
.scaleEffect(1.5)
247+
248+
Text("Connecting...")
249+
.font(.headline)
250+
.foregroundStyle(.secondary)
251+
}
252+
.frame(maxWidth: .infinity, maxHeight: .infinity)
238253
}
239-
.navigationTitle(windowTitle)
240-
.navigationSubtitle(currentSession.connection.name)
241-
} else {
242-
VStack(spacing: 16) {
243-
ProgressView()
244-
.scaleEffect(1.5)
245-
246-
Text("Connecting...")
247-
.font(.headline)
248-
.foregroundStyle(.secondary)
249-
}
250-
.frame(maxWidth: .infinity, maxHeight: .infinity)
251-
.navigationTitle("TablePro")
252254
}
255+
.navigationTitle(windowTitle)
256+
.navigationSubtitle(currentSession?.connection.name ?? "")
253257
}
254258

255259
// Removed: newConnectionSheet and editConnectionSheet helpers

0 commit comments

Comments
 (0)