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,14 +216,34 @@ 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 }
// 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
}
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( let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 700, height: 700), contentRect: NSRect(x: 0, y: 0, width: 700, height: 700),
styleMask: [.titled, .closable, .miniaturizable], styleMask: [.titled, .closable, .miniaturizable, .fullSizeContentView],
backing: .buffered, backing: .buffered,
defer: false defer: false
) )
window.title = "Gaze Onboarding" // Match the WindowGroup style: hiddenTitleBar
window.titleVisibility = .hidden
window.titlebarAppearsTransparent = true
window.center() window.center()
window.isReleasedWhenClosed = true window.isReleasedWhenClosed = true
window.contentView = NSHostingView( window.contentView = NSHostingView(
@@ -234,6 +254,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
} }
} }
}
private func openSettingsWindow(tab: Int) { private func openSettingsWindow(tab: Int) {
// If window already exists, switch to the tab and bring it to front // If window already exists, switch to the tab and bring it to front

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()
}
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() 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") { #Preview("Onboarding Container") {