From ca6f9be3818641e87d854a82646d2ea2aff6e545 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 12 Jun 2026 12:52:43 +0800
Subject: [PATCH] Add Quick Switch view mode entry

---
 C1.source/Sources/Aligner/AlignerApplicationDelegate.swift |  156 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 147 insertions(+), 9 deletions(-)

diff --git a/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift b/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
index b2d0fa9..ad68641 100644
--- a/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
+++ b/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
@@ -3,10 +3,11 @@
 import AlignerCore
 
 @MainActor
-final class AlignerApplicationDelegate: NSObject, NSApplicationDelegate {
+final class AlignerApplicationDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
     private static let quickSwitchConfirmBeforeCloseDefaultsKey = "QuickSwitchConfirmBeforeClose"
 
     private let permissionChecker = SystemPermissionChecker()
+    private let preferenceStore = UserDefaultsPreferenceStore()
     private let launchOptions = Round0DebugLaunchOptions.parse(arguments: ProcessInfo.processInfo.arguments)
     private let round1PoCOptions = Round1PerformancePoCOptions.parse(arguments: ProcessInfo.processInfo.arguments)
     private let round1TriggerProbeOptions = Round1TriggerProbeOptions.parse(arguments: ProcessInfo.processInfo.arguments)
@@ -21,6 +22,8 @@
     private var quickSwitchTriggerService: CGEventTapTriggerService?
     private var isRunningQuickSwitchLifecycle = false
     private var statusItem: NSStatusItem?
+    private var verticalWaterfallViewModeMenuItem: NSMenuItem?
+    private var horizontalWaterfallViewModeMenuItem: NSMenuItem?
 
     func applicationDidFinishLaunching(_ notification: Notification) {
         let bundlePathSummary = DevelopmentDiagnostics.pathSummary(Bundle.main.bundlePath)
@@ -91,21 +94,68 @@
         item.button?.title = "A"
 
         let menu = NSMenu()
-        menu.addItem(NSMenuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ","))
+        menu.delegate = self
+        menu.addItem(menuItem(title: "About Aligner...", action: #selector(showAbout), keyEquivalent: ""))
         menu.addItem(.separator())
-        menu.addItem(NSMenuItem(title: "Show Quick Switch", action: #selector(showQuickSwitchFromMenu), keyEquivalent: ""))
-        menu.addItem(NSMenuItem(title: "Hide Quick Switch", action: #selector(hideQuickSwitchFromMenu), keyEquivalent: ""))
+        menu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ","))
         menu.addItem(.separator())
-        menu.addItem(NSMenuItem(title: "Show Round0 Debug Overlay", action: #selector(showRound0DebugOverlay), keyEquivalent: "d"))
-        menu.addItem(NSMenuItem(title: "Hide Round0 Debug Overlay", action: #selector(hideRound0DebugOverlay), keyEquivalent: ""))
+        menu.addItem(menuItem(title: "Show Quick Switch", action: #selector(showQuickSwitchFromMenu), keyEquivalent: ""))
+        menu.addItem(menuItem(title: "Hide Quick Switch", action: #selector(hideQuickSwitchFromMenu), keyEquivalent: ""))
+        menu.addItem(quickSwitchViewModeMenuItem())
         menu.addItem(.separator())
-        menu.addItem(NSMenuItem(title: "Quit Aligner", action: #selector(quit), keyEquivalent: "q"))
+        menu.addItem(menuItem(title: "Show Round0 Debug Overlay", action: #selector(showRound0DebugOverlay), keyEquivalent: "d"))
+        menu.addItem(menuItem(title: "Hide Round0 Debug Overlay", action: #selector(hideRound0DebugOverlay), keyEquivalent: ""))
+        menu.addItem(.separator())
+        menu.addItem(menuItem(title: "Quit Aligner", action: #selector(quit), keyEquivalent: "q"))
         item.menu = menu
 
         statusItem = item
+        updateWaterfallViewModeMenuState()
         DevelopmentDiagnostics.log("app.statusItem.configure.end", [
-            "hasButton": item.button != nil
+            "hasButton": item.button != nil,
+            "hasAboutItem": true,
+            "hasWaterfallViewModeItems": verticalWaterfallViewModeMenuItem != nil
+                && horizontalWaterfallViewModeMenuItem != nil
         ])
+    }
+
+    func menuWillOpen(_ menu: NSMenu) {
+        updateWaterfallViewModeMenuState()
+    }
+
+    private func menuItem(title: String, action: Selector?, keyEquivalent: String) -> NSMenuItem {
+        let item = NSMenuItem(title: title, action: action, keyEquivalent: keyEquivalent)
+        item.target = self
+        return item
+    }
+
+    private func quickSwitchViewModeMenuItem() -> NSMenuItem {
+        let submenu = NSMenu(title: "Quick Switch View")
+        let verticalItem = menuItem(
+            title: "Vertical Columns",
+            action: #selector(useVerticalWaterfallViewMode),
+            keyEquivalent: ""
+        )
+        let horizontalItem = menuItem(
+            title: "Horizontal Waterfall",
+            action: #selector(useHorizontalWaterfallViewMode),
+            keyEquivalent: ""
+        )
+        submenu.addItem(verticalItem)
+        submenu.addItem(horizontalItem)
+
+        verticalWaterfallViewModeMenuItem = verticalItem
+        horizontalWaterfallViewModeMenuItem = horizontalItem
+
+        let rootItem = NSMenuItem(title: "Quick Switch View", action: nil, keyEquivalent: "")
+        rootItem.submenu = submenu
+        return rootItem
+    }
+
+    private func updateWaterfallViewModeMenuState() {
+        let mode = quickSwitchWaterfallViewMode()
+        verticalWaterfallViewModeMenuItem?.state = mode == .verticalColumns ? .on : .off
+        horizontalWaterfallViewModeMenuItem?.state = mode == .horizontalMasonry ? .on : .off
     }
 
     private func showPermissionsIfNeeded() {
@@ -354,8 +404,10 @@
             let controller = QuickSwitchSessionController(
                 snapshotLoader: quickSwitchSnapshotLoader(),
                 windowActivationService: quickSwitchWindowActivationService(),
+                spaceActivationService: quickSwitchSpaceActivationService(),
                 windowCloseService: quickSwitchWindowCloseService(),
                 disableScreenshotRefresh: round1QuickSwitchOptions.disableScreenshotRefresh,
+                waterfallViewMode: quickSwitchWaterfallViewMode(),
                 closeConfirmationRequired: quickSwitchConfirmBeforeClose,
                 onCloseConfirmationDisabled: { [weak self] in
                     self?.setQuickSwitchConfirmBeforeClose(false)
@@ -428,8 +480,10 @@
             let controller = QuickSwitchSessionController(
                 snapshotLoader: quickSwitchSnapshotLoader(),
                 windowActivationService: quickSwitchWindowActivationService(),
+                spaceActivationService: quickSwitchSpaceActivationService(),
                 windowCloseService: quickSwitchWindowCloseService(),
                 disableScreenshotRefresh: round1QuickSwitchOptions.disableScreenshotRefresh,
+                waterfallViewMode: quickSwitchWaterfallViewMode(),
                 closeConfirmationRequired: quickSwitchConfirmBeforeClose,
                 onCloseConfirmationDisabled: { [weak self] in
                     self?.setQuickSwitchConfirmBeforeClose(false)
@@ -464,13 +518,19 @@
         guard !isRunningQuickSwitchLifecycle else { return }
         let reportPathSummary = DevelopmentDiagnostics.pathSummary(reportPath)
 
-        let report = quickSwitchSessionController?.reportDictionary() ?? [
+        var report: [String: Any] = quickSwitchSessionController?.reportDictionary() ?? [
             "snapshotLoaded": false,
             "quickSwitchVisible": false,
             "permissionStatus": "\(accessibilityStatus())",
             "diagnosticLogLocationKind": DevelopmentDiagnostics.pathSummary(DevelopmentDiagnostics.logPath)["locationKind"] ?? "unknown",
             "diagnosticLogBasename": DevelopmentDiagnostics.pathSummary(DevelopmentDiagnostics.logPath)["basename"] ?? "aligner-dev.log"
         ]
+        let versionBuild = appVersionBuild()
+        report["preferenceWaterfallViewMode"] = preferenceStore.read().quickSwitchWaterfallViewMode.rawValue
+        report["resolvedWaterfallViewMode"] = quickSwitchWaterfallViewMode().rawValue
+        report["aboutVersion"] = versionBuild.version
+        report["aboutBuild"] = versionBuild.build
+        report["statusMenu"] = statusMenuReportDictionary()
 
         do {
             let data = try JSONSerialization.data(withJSONObject: report, options: [.prettyPrinted, .sortedKeys])
@@ -546,6 +606,19 @@
         return CGWindowAXWindowService(spaceIDsByWindowIDProvider: { _ in [:] })
     }
 
+    private func quickSwitchWaterfallViewMode() -> QuickSwitchWaterfallViewMode {
+        round1QuickSwitchOptions.waterfallViewMode
+            ?? preferenceStore.read().quickSwitchWaterfallViewMode
+    }
+
+    private func quickSwitchSpaceActivationService() -> any SpaceActivationServiceProtocol {
+        if round1QuickSwitchOptions.debugWindowActivation {
+            return DebugSpaceActivationService()
+        }
+
+        return PrivateSpaceActivationService()
+    }
+
     private func quickSwitchWindowCloseService() -> any WindowCloseServiceProtocol {
         if round1QuickSwitchOptions.debugWindowClose {
             return DebugWindowCloseService()
@@ -566,6 +639,71 @@
         ])
     }
 
+    private func setQuickSwitchWaterfallViewMode(_ mode: QuickSwitchWaterfallViewMode) {
+        let preferences = preferenceStore.read()
+        let updatedPreferences = AlignerPreferences(
+            showMinimizedWindows: preferences.showMinimizedWindows,
+            showFullscreenWindows: preferences.showFullscreenWindows,
+            quickSwitchWaterfallViewMode: mode,
+            theme: preferences.theme,
+            language: preferences.language,
+            spaceDisplayStrategy: preferences.spaceDisplayStrategy
+        )
+        preferenceStore.write(updatedPreferences)
+        quickSwitchSessionController?.setWaterfallViewMode(mode)
+        updateWaterfallViewModeMenuState()
+        writeQuickSwitchReportIfNeeded()
+        DevelopmentDiagnostics.log("app.quickSwitch.waterfallViewModePreferenceChanged", [
+            "mode": mode.rawValue,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
+        ])
+    }
+
+    private func appVersionBuild() -> (version: String, build: String) {
+        let info = Bundle.main.infoDictionary ?? [:]
+        let version = info["CFBundleShortVersionString"] as? String ?? "Unknown"
+        let build = info["CFBundleVersion"] as? String ?? "Unknown"
+        return (version, build)
+    }
+
+    private func statusMenuReportDictionary() -> [String: Any] {
+        updateWaterfallViewModeMenuState()
+        return [
+            "hasAboutItem": statusItem?.menu?.item(withTitle: "About Aligner...") != nil,
+            "hasQuickSwitchViewSubmenu": statusItem?.menu?.item(withTitle: "Quick Switch View")?.submenu != nil,
+            "hasVerticalColumnsItem": verticalWaterfallViewModeMenuItem != nil,
+            "hasHorizontalWaterfallItem": horizontalWaterfallViewModeMenuItem != nil,
+            "verticalColumnsState": verticalWaterfallViewModeMenuItem?.state == .on ? "on" : "off",
+            "horizontalWaterfallState": horizontalWaterfallViewModeMenuItem?.state == .on ? "on" : "off"
+        ]
+    }
+
+    @objc private func showAbout() {
+        let versionBuild = appVersionBuild()
+        DevelopmentDiagnostics.log("app.menu.showAbout", [
+            "version": versionBuild.version,
+            "build": versionBuild.build
+        ])
+
+        NSApp.setActivationPolicy(.regular)
+        let alert = NSAlert()
+        alert.messageText = "Aligner"
+        alert.informativeText = "Version / Build: \(versionBuild.version) / \(versionBuild.build)"
+        alert.alertStyle = .informational
+        alert.addButton(withTitle: "OK")
+        alert.icon = NSApp.applicationIconImage
+        NSApp.activate(ignoringOtherApps: true)
+        alert.runModal()
+    }
+
+    @objc private func useVerticalWaterfallViewMode() {
+        setQuickSwitchWaterfallViewMode(.verticalColumns)
+    }
+
+    @objc private func useHorizontalWaterfallViewMode() {
+        setQuickSwitchWaterfallViewMode(.horizontalMasonry)
+    }
+
     @objc private func showPermissions() {
         DevelopmentDiagnostics.log("app.permissions.show", [
             "accessibility": permissionStatusString(accessibilityStatus()),

--
Gitblit v1.9.3