Эх сурвалжийг харах

Move launcher header into native titlebar for reliable interaction.

Use a transparent full-size titled window with hidden traffic lights so drag and search behavior remain stable after hide/reopen, and tighten top spacing to preserve the existing visual design.

Made-with: Cursor
huzaifahayat12 3 сар өмнө
parent
commit
0f50e8fc35

+ 22 - 11
google_apps/AppDelegate.swift

@@ -10,6 +10,16 @@ import Cocoa
 @main
 class AppDelegate: NSObject, NSApplicationDelegate {
     private var statusItem: NSStatusItem?
+    private weak var launcherWindowReference: NSWindow?
+
+    private var launcherWindow: NSWindow? {
+        if let launcherWindowReference {
+            return launcherWindowReference
+        }
+        let resolved = NSApp.windows.first
+        launcherWindowReference = resolved
+        return resolved
+    }
 
     func applicationDidFinishLaunching(_ aNotification: Notification) {
         applyBundledAppIcon()
@@ -99,9 +109,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
     @objc
     private func toggleMainWindowFromStatusBar() {
         configureMainWindowIfNeeded()
-        guard let window = NSApp.windows.first else { return }
+        guard let window = launcherWindow else { return }
 
-        if window.isVisible {
+        if window.isVisible && window.isKeyWindow {
             hideMainWindow()
             return
         }
@@ -110,7 +120,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
     }
 
     private func hideMainWindow() {
-        guard let window = NSApp.windows.first else { return }
+        guard let window = launcherWindow else { return }
         if window.isMiniaturized {
             window.deminiaturize(nil)
         }
@@ -121,26 +131,29 @@ class AppDelegate: NSObject, NSApplicationDelegate {
         configureMainWindowIfNeeded()
         NSApp.setActivationPolicy(.regular)
         NSApp.activate(ignoringOtherApps: true)
-        guard let window = NSApp.windows.first else { return }
+        guard let window = launcherWindow else { return }
         if window.isMiniaturized {
             window.deminiaturize(nil)
         }
+        window.orderFrontRegardless()
         window.makeKeyAndOrderFront(nil)
     }
 
     private func configureMainWindowIfNeeded() {
-        guard let window = NSApp.windows.first else { return }
+        guard let window = launcherWindow else { return }
         window.title = "My Apps"
-        window.styleMask.remove(.titled)
+        window.styleMask.insert(.titled)
         window.isOpaque = false
         window.backgroundColor = .clear
         applyRoundedCorners(to: window)
         window.titlebarAppearsTransparent = true
         window.titleVisibility = .hidden
         window.styleMask.insert(.fullSizeContentView)
-        // Avoid treating SwiftUI search fields as the draggable window background (clicks/typing fail otherwise).
-        window.isMovableByWindowBackground = false
+        window.isMovableByWindowBackground = true
         window.minSize = NSSize(width: 760, height: 520)
+        window.standardWindowButton(.closeButton)?.isHidden = true
+        window.standardWindowButton(.miniaturizeButton)?.isHidden = true
+        window.standardWindowButton(.zoomButton)?.isHidden = true
 
         let targetContentSize = NSSize(width: 980, height: 700)
         if window.contentRect(forFrameRect: window.frame).size.width < targetContentSize.width ||
@@ -167,9 +180,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
         // Insert code here to tear down your application
     }
 
-    func applicationDidResignActive(_ notification: Notification) {
-        hideMainWindow()
-    }
+    func applicationDidResignActive(_ notification: Notification) {}
 
     func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
         showMainWindow()

+ 3 - 25
google_apps/LauncherRootView.swift

@@ -146,7 +146,7 @@ struct LauncherRootView: View {
                         restoreAllHiddenApps()
                     }
                 )
-                .padding(.top, 12)
+                .padding(.top, 8)
 
                 PromoBanner(
                     isPremiumUnlocked: premiumStore.isPremiumUnlocked,
@@ -165,14 +165,10 @@ struct LauncherRootView: View {
                 appsPage
             }
             .padding(.horizontal, 10)
-            .padding(.top, 14)
+            .padding(.top, 5)
             .padding(.bottom, 8)
-            .overlay(alignment: .top) {
-                WindowDragHandle()
-                    .frame(height: 6)
-                    .padding(.horizontal, 12)
-            }
         }
+        .ignoresSafeArea(.container, edges: .top)
         .sheet(item: $selectedApp) { app in
             AppDetailView(app: app)
                 .frame(minWidth: 360, minHeight: 220)
@@ -535,24 +531,6 @@ struct LauncherRootView: View {
     }
 }
 
-/// Dedicated drag strip so the window remains movable while text fields stay fully interactive.
-private struct WindowDragHandle: NSViewRepresentable {
-    func makeNSView(context: Context) -> DragHandleView {
-        let view = DragHandleView()
-        view.wantsLayer = true
-        view.layer?.backgroundColor = NSColor.clear.cgColor
-        return view
-    }
-
-    func updateNSView(_ nsView: DragHandleView, context: Context) {}
-}
-
-private final class DragHandleView: NSView {
-    override func mouseDown(with event: NSEvent) {
-        window?.performDrag(with: event)
-    }
-}
-
 private struct TileReorderDropDelegate: DropDelegate {
     let destinationAppID: UUID
     @Binding var draggedAppID: UUID?