general: screw the close anim

This commit is contained in:
Michael Freno
2026-01-11 16:45:42 -05:00
parent 5488ad286c
commit 37564d0579
2 changed files with 47 additions and 59 deletions

View File

@@ -216,22 +216,43 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
guard let self = self, let settingsManager = self.settingsManager else { return }
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 700, height: 700),
styleMask: [.titled, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
// Check if onboarding window already exists from the WindowGroup
let existingWindow = NSApplication.shared.windows.first { window in
// Check if window contains OnboardingContainerView by examining its content view
if let hostingView = window.contentView as? NSHostingView<OnboardingContainerView> {
return true
}
// Also check for windows with our expected size (onboarding window dimensions)
return window.frame.size.width == 700 && window.frame.size.height == 700
&& window.styleMask.contains(.titled)
&& window.title.isEmpty // WindowGroup windows have empty title by default
}
window.title = "Gaze Onboarding"
window.center()
window.isReleasedWhenClosed = true
window.contentView = NSHostingView(
rootView: OnboardingContainerView(settingsManager: settingsManager)
)
if let window = existingWindow {
// Reuse existing window - just bring it to front
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
} else {
// Create new window matching WindowGroup style
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 700, height: 700),
styleMask: [.titled, .closable, .miniaturizable, .fullSizeContentView],
backing: .buffered,
defer: false
)
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
// Match the WindowGroup style: hiddenTitleBar
window.titleVisibility = .hidden
window.titlebarAppearsTransparent = true
window.center()
window.isReleasedWhenClosed = true
window.contentView = NSHostingView(
rootView: OnboardingContainerView(settingsManager: settingsManager)
)
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
}
}
}

View File

@@ -31,7 +31,6 @@ struct OnboardingContainerView: View {
@State private var postureIntervalMinutes = 30
@State private var launchAtLogin = false
@State private var subtleReminderSize: ReminderSize = .medium
@State private var isAnimatingOut = false
@Environment(\.dismiss) private var dismiss
var body: some View {
@@ -151,8 +150,6 @@ struct OnboardingContainerView: View {
}
}
.frame(minWidth: 1000, minHeight: 800)
.opacity(isAnimatingOut ? 0 : 1)
.scaleEffect(isAnimatingOut ? 0.3 : 1.0)
}
private func completeOnboarding() {
@@ -188,49 +185,19 @@ struct OnboardingContainerView: View {
print("Failed to set launch at login: \(error)")
}
// Perform vacuum animation
performVacuumAnimation()
}
// Close window with standard macOS animation
dismiss()
private func performVacuumAnimation() {
// Get the NSWindow reference
guard
let window = NSApplication.shared.windows.first(where: {
$0.isVisible && $0.contentView != nil
})
else {
// Fallback: just dismiss without animation
dismiss()
return
// After a brief delay, trigger the menu bar extra to open
DispatchQueue.main.asyncAfter(deadline: .now()) {
if let menuBarWindow = NSApp.windows.first(where: {
$0.className.contains("MenuBarExtra") || $0.className.contains("StatusBar")
}),
let statusItem = menuBarWindow.value(forKey: "statusItem") as? NSStatusItem
{
statusItem.button?.performClick(nil)
}
}
// Calculate target position (top-center of screen where menu bar is)
let screen = NSScreen.main?.frame ?? .zero
let targetRect = NSRect(
x: screen.midX,
y: screen.maxY,
width: 0,
height: 0
)
// Start SwiftUI animation for visual effects
withAnimation(.easeInOut(duration: 0.7)) {
isAnimatingOut = true
}
// Animate window frame using AppKit
NSAnimationContext.runAnimationGroup(
{ context in
context.duration = 0.7
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
window.animator().setFrame(targetRect, display: true)
window.animator().alphaValue = 0
},
completionHandler: {
// Close window after animation completes
self.dismiss()
window.close()
})
}
}
#Preview("Onboarding Container") {