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 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
guard let self = self, let settingsManager = self.settingsManager else { return } guard let self = self, let settingsManager = self.settingsManager else { return }
let window = NSWindow( // Check if onboarding window already exists from the WindowGroup
contentRect: NSRect(x: 0, y: 0, width: 700, height: 700), let existingWindow = NSApplication.shared.windows.first { window in
styleMask: [.titled, .closable, .miniaturizable], // Check if window contains OnboardingContainerView by examining its content view
backing: .buffered, if let hostingView = window.contentView as? NSHostingView<OnboardingContainerView> {
defer: false 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" if let window = existingWindow {
window.center() // Reuse existing window - just bring it to front
window.isReleasedWhenClosed = true window.makeKeyAndOrderFront(nil)
window.contentView = NSHostingView( NSApp.activate(ignoringOtherApps: true)
rootView: OnboardingContainerView(settingsManager: settingsManager) } 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) // Match the WindowGroup style: hiddenTitleBar
NSApp.activate(ignoringOtherApps: true) 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 postureIntervalMinutes = 30
@State private var launchAtLogin = false @State private var launchAtLogin = false
@State private var subtleReminderSize: ReminderSize = .medium @State private var subtleReminderSize: ReminderSize = .medium
@State private var isAnimatingOut = false
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
var body: some View { var body: some View {
@@ -151,8 +150,6 @@ struct OnboardingContainerView: View {
} }
} }
.frame(minWidth: 1000, minHeight: 800) .frame(minWidth: 1000, minHeight: 800)
.opacity(isAnimatingOut ? 0 : 1)
.scaleEffect(isAnimatingOut ? 0.3 : 1.0)
} }
private func completeOnboarding() { private func completeOnboarding() {
@@ -188,49 +185,19 @@ struct OnboardingContainerView: View {
print("Failed to set launch at login: \(error)") print("Failed to set launch at login: \(error)")
} }
// Perform vacuum animation // Close window with standard macOS animation
performVacuumAnimation() dismiss()
}
private func performVacuumAnimation() { // After a brief delay, trigger the menu bar extra to open
// Get the NSWindow reference DispatchQueue.main.asyncAfter(deadline: .now()) {
guard if let menuBarWindow = NSApp.windows.first(where: {
let window = NSApplication.shared.windows.first(where: { $0.className.contains("MenuBarExtra") || $0.className.contains("StatusBar")
$0.isVisible && $0.contentView != nil }),
}) let statusItem = menuBarWindow.value(forKey: "statusItem") as? NSStatusItem
else { {
// Fallback: just dismiss without animation statusItem.button?.performClick(nil)
dismiss() }
return
} }
// 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") { #Preview("Onboarding Container") {