From 4bff63dc00afdd12711f74df8412f28949e66ef6 Mon Sep 17 00:00:00 2001 From: Beingpax Date: Sat, 1 Nov 2025 10:14:17 +0545 Subject: [PATCH] Prevent UI stuck state when switching between mini and notch recorders --- VoiceInk/Views/Recorder/MiniWindowManager.swift | 9 +++++---- VoiceInk/Views/Recorder/NotchRecorderPanel.swift | 4 +--- VoiceInk/Views/Recorder/NotchWindowManager.swift | 7 +++---- VoiceInk/Whisper/WhisperState+UI.swift | 2 -- VoiceInk/Whisper/WhisperState.swift | 13 +++++++++++++ 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/VoiceInk/Views/Recorder/MiniWindowManager.swift b/VoiceInk/Views/Recorder/MiniWindowManager.swift index 3817e03..9bff15b 100644 --- a/VoiceInk/Views/Recorder/MiniWindowManager.swift +++ b/VoiceInk/Views/Recorder/MiniWindowManager.swift @@ -32,17 +32,17 @@ class MiniWindowManager: ObservableObject { } func show() { if isVisible { return } - + let activeScreen = NSApp.keyWindow?.screen ?? NSScreen.main ?? NSScreen.screens[0] - + initializeWindow(screen: activeScreen) self.isVisible = true miniPanel?.show() } - + func hide() { guard isVisible else { return } - + self.isVisible = false self.miniPanel?.hide { [weak self] in guard let self = self else { return } @@ -70,6 +70,7 @@ class MiniWindowManager: ObservableObject { } private func deinitializeWindow() { + miniPanel?.orderOut(nil) windowController?.close() windowController = nil miniPanel = nil diff --git a/VoiceInk/Views/Recorder/NotchRecorderPanel.swift b/VoiceInk/Views/Recorder/NotchRecorderPanel.swift index d598a0d..58aed4a 100644 --- a/VoiceInk/Views/Recorder/NotchRecorderPanel.swift +++ b/VoiceInk/Views/Recorder/NotchRecorderPanel.swift @@ -69,9 +69,7 @@ class NotchRecorderPanel: KeyablePanel { // Make window transparent to mouse events except for the content self.ignoresMouseEvents = false self.isMovable = false - - print("NotchRecorderPanel initialized") - + NotificationCenter.default.addObserver( self, selector: #selector(handleScreenParametersChange), diff --git a/VoiceInk/Views/Recorder/NotchWindowManager.swift b/VoiceInk/Views/Recorder/NotchWindowManager.swift index f22f7c6..ab819ae 100644 --- a/VoiceInk/Views/Recorder/NotchWindowManager.swift +++ b/VoiceInk/Views/Recorder/NotchWindowManager.swift @@ -41,11 +41,9 @@ class NotchWindowManager: ObservableObject { func hide() { guard isVisible else { return } - - // Remove animation for instant state change + self.isVisible = false - - // Don't wait for animation, clean up immediately + self.notchPanel?.hide { [weak self] in guard let self = self else { return } self.deinitializeWindow() @@ -72,6 +70,7 @@ class NotchWindowManager: ObservableObject { } private func deinitializeWindow() { + notchPanel?.orderOut(nil) windowController?.close() windowController = nil notchPanel = nil diff --git a/VoiceInk/Whisper/WhisperState+UI.swift b/VoiceInk/Whisper/WhisperState+UI.swift index eae3e21..7cebeda 100644 --- a/VoiceInk/Whisper/WhisperState+UI.swift +++ b/VoiceInk/Whisper/WhisperState+UI.swift @@ -12,13 +12,11 @@ extension WhisperState { if recorderType == "notch" { if notchWindowManager == nil { notchWindowManager = NotchWindowManager(whisperState: self, recorder: recorder) - logger.info("Created new notch window manager") } notchWindowManager?.show() } else { if miniWindowManager == nil { miniWindowManager = MiniWindowManager(whisperState: self, recorder: recorder) - logger.info("Created new mini window manager") } miniWindowManager?.show() } diff --git a/VoiceInk/Whisper/WhisperState.swift b/VoiceInk/Whisper/WhisperState.swift index af46a0e..3014ad1 100644 --- a/VoiceInk/Whisper/WhisperState.swift +++ b/VoiceInk/Whisper/WhisperState.swift @@ -31,6 +31,19 @@ class WhisperState: NSObject, ObservableObject { @Published var recorderType: String = UserDefaults.standard.string(forKey: "RecorderType") ?? "mini" { didSet { + if isMiniRecorderVisible { + if oldValue == "notch" { + notchWindowManager?.hide() + notchWindowManager = nil + } else { + miniWindowManager?.hide() + miniWindowManager = nil + } + Task { @MainActor in + try? await Task.sleep(nanoseconds: 50_000_000) + showRecorderPanel() + } + } UserDefaults.standard.set(recorderType, forKey: "RecorderType") } }