fix: complete Command presentation teardown
This commit is contained in:
@@ -192,8 +192,8 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
}
|
||||
}
|
||||
|
||||
func close() {
|
||||
guard isShown else { return }
|
||||
func close(animated: Bool = true) {
|
||||
guard viewIfLoaded?.superview != nil, !isClosing || !animated else { return }
|
||||
transitionGeneration += 1
|
||||
let generation = transitionGeneration
|
||||
isClosing = true
|
||||
@@ -202,13 +202,23 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat
|
||||
if let mouseMonitor { NSEvent.removeMonitor(mouseMonitor) }
|
||||
mouseMonitor = nil
|
||||
coveredPill?.setAccessibilityHidden(false)
|
||||
if !animated {
|
||||
view.removeFromSuperview()
|
||||
coveredPill?.layer?.removeAllAnimations()
|
||||
coveredPill?.alphaValue = coveredPillAlpha
|
||||
coveredPill = nil
|
||||
isClosing = false
|
||||
closed?()
|
||||
return
|
||||
}
|
||||
// Finish teardown even if the presenting Command releases this controller.
|
||||
NSAnimationContext.runAnimationGroup { context in
|
||||
context.duration = NSWorkspace.shared.accessibilityDisplayShouldReduceMotion ? 0 : 0.12
|
||||
view.animator().alphaValue = 0
|
||||
coveredPill?.animator().alphaValue = coveredPillAlpha
|
||||
} completionHandler: { [weak self] in
|
||||
} completionHandler: { [self] in
|
||||
MainActor.assumeIsolated {
|
||||
guard let self, self.transitionGeneration == generation, self.isClosing else { return }
|
||||
guard self.transitionGeneration == generation, self.isClosing else { return }
|
||||
self.view.removeFromSuperview()
|
||||
self.coveredPill = nil
|
||||
self.isClosing = false
|
||||
|
||||
@@ -110,10 +110,10 @@ final class EmojiPickerController: NSViewController, NSCollectionViewDataSource,
|
||||
|
||||
@objc private func categoryChanged() { inputChanged() }
|
||||
@objc func goBack() {
|
||||
if actions.isShown { actions.close() } else { closed?() }
|
||||
if actions.isShown { actions.close() } else { close() }
|
||||
}
|
||||
func close() {
|
||||
actions.close()
|
||||
actions.close(animated: false)
|
||||
closed?()
|
||||
}
|
||||
override func cancelOperation(_ sender: Any?) { goBack() }
|
||||
@@ -254,7 +254,7 @@ final class EmojiPickerController: NSViewController, NSCollectionViewDataSource,
|
||||
var recent = defaults.stringArray(forKey: "recentEmoji") ?? []
|
||||
recent.removeAll { $0 == value }
|
||||
defaults.set(Array(([value] + recent).prefix(30)), forKey: "recentEmoji")
|
||||
closed?()
|
||||
actions.close(animated: false)
|
||||
if pasting { pasteRequested?() } else { copied?() }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
private let sectionLabel = NSTextField(labelWithString: "Applications")
|
||||
private let openButton = NSButton(title: "Open Application", target: nil, action: nil)
|
||||
private let history: LaunchHistory
|
||||
private let defaults: UserDefaults
|
||||
private let pasteboard: NSPasteboard
|
||||
private var applications: [Application] = Application.commands
|
||||
private var results: [Application] = []
|
||||
private var calculation: CalculatorResult?
|
||||
@@ -49,9 +51,12 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
}()
|
||||
|
||||
init(history: LaunchHistory = LaunchHistory(), uninstaller: ApplicationUninstaller = ApplicationUninstaller()) {
|
||||
init(history: LaunchHistory = LaunchHistory(), uninstaller: ApplicationUninstaller = ApplicationUninstaller(),
|
||||
defaults: UserDefaults = .standard, pasteboard: NSPasteboard = .general) {
|
||||
self.history = history
|
||||
self.uninstaller = uninstaller
|
||||
self.defaults = defaults
|
||||
self.pasteboard = pasteboard
|
||||
let window = LauncherPanel(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 750, height: 474),
|
||||
styleMask: [.borderless],
|
||||
@@ -118,7 +123,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
return
|
||||
}
|
||||
closeCommand()
|
||||
actions.close()
|
||||
actions.close(animated: false)
|
||||
(window as? LauncherPanel)?.beginNumberHintSession()
|
||||
let frontmost = NSWorkspace.shared.frontmostApplication
|
||||
if frontmost?.processIdentifier != ProcessInfo.processInfo.processIdentifier {
|
||||
@@ -145,8 +150,6 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
guard !isLaunching, window?.attachedSheet == nil else { return }
|
||||
if window?.isVisible == true, window?.isKeyWindow == true,
|
||||
launcherFrameBeforeReview == nil, activeCommand == command {
|
||||
closeCommand()
|
||||
actions.close()
|
||||
dismiss()
|
||||
} else {
|
||||
present(command: command)
|
||||
@@ -156,12 +159,9 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
func dismiss(restoringFocus: Bool = true) {
|
||||
guard !restoringFocus || (!isLaunching && window?.attachedSheet == nil) else { return }
|
||||
if let review = uninstallReview { review.goBack(); return }
|
||||
if isCommandOpen {
|
||||
goBackCommand()
|
||||
if restoringFocus { return }
|
||||
}
|
||||
closeCommand()
|
||||
guard launcherFrameBeforeReview == nil else { return }
|
||||
actions.close()
|
||||
actions.close(animated: false)
|
||||
alignmentGuides?.end()
|
||||
let previous = previousApplication
|
||||
previousApplication = nil
|
||||
@@ -712,7 +712,6 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
guard !isLaunching, !isCommandOpen, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return }
|
||||
if let calculation {
|
||||
guard tableView.selectedRow == 0, let value = calculation.copyValue else { return }
|
||||
let pasteboard = NSPasteboard.general
|
||||
pasteboard.clearContents()
|
||||
if pasteboard.setString(value, forType: .string) {
|
||||
dismiss()
|
||||
@@ -763,7 +762,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
|
||||
private func pasteEmoji() {
|
||||
let target = previousApplication
|
||||
let changeCount = NSPasteboard.general.changeCount
|
||||
let changeCount = pasteboard.changeCount
|
||||
dismiss()
|
||||
guard let target, !target.isTerminated,
|
||||
target.processIdentifier != ProcessInfo.processInfo.processIdentifier,
|
||||
@@ -774,7 +773,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
for _ in 0..<20 {
|
||||
try? await Task.sleep(for: .milliseconds(25))
|
||||
guard let self, self.window?.isVisible == false, !target.isTerminated,
|
||||
NSPasteboard.general.changeCount == changeCount else { return }
|
||||
self.pasteboard.changeCount == changeCount else { return }
|
||||
guard NSWorkspace.shared.frontmostApplication?.processIdentifier == target.processIdentifier else { continue }
|
||||
guard let down = CGEvent(keyboardEventSource: nil, virtualKey: 9, keyDown: true),
|
||||
let up = CGEvent(keyboardEventSource: nil, virtualKey: 9, keyDown: false) else { return }
|
||||
@@ -812,7 +811,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
placeholder = "Enter English text to translate…"
|
||||
accessibilityLabel = "English text to translate into Japanese"
|
||||
case .emoji:
|
||||
let tool = EmojiPickerController()
|
||||
let tool = EmojiPickerController(defaults: defaults, pasteboard: pasteboard)
|
||||
emojiPicker = tool
|
||||
tool.input = { [weak self] in self?.searchField.stringValue ?? "" }
|
||||
tool.focusSearch = { [weak self] in self?.window?.makeFirstResponder(self?.searchField) }
|
||||
@@ -847,7 +846,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
translation?.closed = close
|
||||
emojiPicker?.closed = close
|
||||
actions.close()
|
||||
actions.close(animated: false)
|
||||
(window as? LauncherPanel)?.resetNumberHints()
|
||||
openButton.keyEquivalent = ""
|
||||
searchSymbol.isHidden = true
|
||||
|
||||
Reference in New Issue
Block a user