Ariver
2026-06-04 a465f1f6f733940df3d28550b2af45296ad644b8
C1.source/Sources/Aligner/QuickSwitchRootView.swift
@@ -9,7 +9,10 @@
@MainActor
final class QuickSwitchRootView: NSView {
    private let backdropBlurView = NSVisualEffectView()
    private let layerHostView = NSView()
    private let backgroundLayer = CAGradientLayer()
    private let safeAreaFillLayer = CALayer()
    private let glassLayer = CALayer()
    private let laneLayer = CALayer()
    private let spaceLaneContentLayer = CALayer()
@@ -118,6 +121,14 @@
        static let maxRows = 2
    }
    private enum RootLayoutMetrics {
        static let horizontalMargin: CGFloat = 24
        static let topContentMargin: CGFloat = 24
        static let shelfGap: CGFloat = 16
        static let waterfallTopGap: CGFloat = 14
        static let bottomMargin: CGFloat = 34
    }
    private enum WaterfallMetrics {
        static let gap: CGFloat = 16
        static let columnWidth: CGFloat = 252
@@ -143,12 +154,16 @@
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        setupBackdropBlurView()
        setupLayerHostView()
        wantsLayer = true
        setupLayers()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupBackdropBlurView()
        setupLayerHostView()
        wantsLayer = true
        setupLayers()
    }
@@ -176,6 +191,8 @@
    override func layout() {
        super.layout()
        backdropBlurView.frame = bounds
        layerHostView.frame = bounds
        layoutLayers()
    }
@@ -443,7 +460,12 @@
            "viewClass": String(describing: Self.self),
            "isLayerBacked": wantsLayer,
            "bounds": dictionary(from: bounds),
            "safeAreaTopInset": Double(topSafeAreaInset),
            "safeAreaFillFrame": dictionary(from: safeAreaFillLayer.frame),
            "glassFrame": dictionary(from: glassLayer.frame),
            "glassCornerRadius": Double(glassLayer.cornerRadius),
            "glassBorderWidth": Double(glassLayer.borderWidth),
            "glassShadowOpacity": Double(glassLayer.shadowOpacity),
            "spaceLaneFrame": dictionary(from: laneLayer.frame),
            "spaceLaneContentWidth": Double(spaceLaneContentWidth),
            "spaceLaneVisibleWidth": Double(laneLayer.bounds.width),
@@ -1162,35 +1184,54 @@
        value ?? NSNull()
    }
    private func setupBackdropBlurView() {
        backdropBlurView.material = .fullScreenUI
        backdropBlurView.blendingMode = .behindWindow
        backdropBlurView.state = .active
        backdropBlurView.isEmphasized = false
        backdropBlurView.frame = bounds
        backdropBlurView.autoresizingMask = [.width, .height]
        addSubview(backdropBlurView, positioned: .below, relativeTo: nil)
    }
    private func setupLayerHostView() {
        layerHostView.wantsLayer = true
        layerHostView.frame = bounds
        layerHostView.autoresizingMask = [.width, .height]
        layerHostView.layer?.masksToBounds = true
        layerHostView.layer?.backgroundColor = NSColor.clear.cgColor
        addSubview(layerHostView, positioned: .above, relativeTo: backdropBlurView)
    }
    private func setupLayers() {
        guard let rootLayer = layer else { return }
        guard let rootLayer = layerHostView.layer else { return }
        rootLayer.masksToBounds = true
        backgroundLayer.colors = [
            NSColor.windowBackgroundColor.withAlphaComponent(0.72).cgColor,
            NSColor.controlBackgroundColor.withAlphaComponent(0.62).cgColor
            NSColor.windowBackgroundColor.withAlphaComponent(0.58).cgColor,
            NSColor.controlBackgroundColor.withAlphaComponent(0.48).cgColor
        ]
        backgroundLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
        backgroundLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
        rootLayer.addSublayer(backgroundLayer)
        glassLayer.cornerRadius = 24
        glassLayer.backgroundColor = NSColor.windowBackgroundColor.withAlphaComponent(0.72).cgColor
        glassLayer.borderColor = NSColor.separatorColor.withAlphaComponent(0.35).cgColor
        glassLayer.borderWidth = 1
        glassLayer.shadowColor = NSColor.black.cgColor
        glassLayer.shadowOpacity = 0.16
        glassLayer.shadowRadius = 24
        glassLayer.shadowOffset = CGSize(width: 0, height: -8)
        safeAreaFillLayer.backgroundColor = NSColor.black.cgColor
        rootLayer.addSublayer(safeAreaFillLayer)
        glassLayer.cornerRadius = 0
        glassLayer.backgroundColor = NSColor.clear.cgColor
        glassLayer.borderColor = NSColor.clear.cgColor
        glassLayer.borderWidth = 0
        glassLayer.shadowOpacity = 0
        rootLayer.addSublayer(glassLayer)
        laneLayer.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.50).cgColor
        laneLayer.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.68).cgColor
        laneLayer.cornerRadius = 16
        laneLayer.masksToBounds = true
        glassLayer.addSublayer(laneLayer)
        laneLayer.addSublayer(spaceLaneContentLayer)
        shelfLayer.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.42).cgColor
        shelfLayer.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.60).cgColor
        shelfLayer.cornerRadius = 16
        shelfLayer.masksToBounds = true
        glassLayer.addSublayer(shelfLayer)
@@ -1251,17 +1292,12 @@
            badge.masksToBounds = true
            let selectedIndicator = CALayer()
            selectedIndicator.cornerRadius = 2
            selectedIndicator.backgroundColor = (item.appGroupIndex == selectedAppGroupIndex
                ? NSColor.controlAccentColor
                : NSColor.clear
            ).cgColor
            selectedIndicator.isHidden = true
            container.addSublayer(background)
            container.addSublayer(icon)
            container.addSublayer(label)
            container.addSublayer(badge)
            container.addSublayer(selectedIndicator)
            appShelfContentLayer.addSublayer(container)
            return AppShelfItemLayers(
@@ -1287,12 +1323,12 @@
            container.name = column.app.name
            container.cornerRadius = 14
            container.masksToBounds = true
            container.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.34).cgColor
            container.borderColor = NSColor.separatorColor.withAlphaComponent(0.28).cgColor
            container.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.56).cgColor
            container.borderColor = NSColor.separatorColor.withAlphaComponent(0.34).cgColor
            container.borderWidth = 1
            let header = CALayer()
            header.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.58).cgColor
            header.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.68).cgColor
            let appName = makeTextLayer(
                string: column.app.name,
@@ -1464,33 +1500,40 @@
        backgroundLayer.frame = bounds
        let horizontalInset = max(36, bounds.width * 0.045)
        let topInset = max(36, bounds.height * 0.055)
        glassLayer.frame = bounds.insetBy(dx: horizontalInset, dy: topInset)
        let safeAreaTopInset = topSafeAreaInset
        safeAreaFillLayer.frame = CGRect(
            x: 0,
            y: max(0, bounds.height - safeAreaTopInset),
            width: bounds.width,
            height: safeAreaTopInset
        )
        safeAreaFillLayer.isHidden = safeAreaTopInset <= 0.5
        glassLayer.frame = bounds
        let contentBounds = glassLayer.bounds
        let horizontalMargin: CGFloat = 22
        let horizontalMargin = RootLayoutMetrics.horizontalMargin
        let topMargin = safeAreaTopInset + RootLayoutMetrics.topContentMargin
        let laneHeight = min(104, max(82, contentBounds.height * 0.12))
        let availableContentWidth = contentBounds.width - horizontalMargin * 2
        appShelfLayout = appShelfLayout(for: availableContentWidth)
        let shelfHeight = appShelfHeight(forRows: appShelfLayout.rows)
        laneLayer.frame = CGRect(
            x: horizontalMargin,
            y: contentBounds.height - horizontalMargin - laneHeight,
            y: contentBounds.height - topMargin - laneHeight,
            width: availableContentWidth,
            height: laneHeight
        )
        shelfLayer.frame = CGRect(
            x: horizontalMargin,
            y: laneLayer.frame.minY - 16 - shelfHeight,
            y: laneLayer.frame.minY - RootLayoutMetrics.shelfGap - shelfHeight,
            width: laneLayer.frame.width,
            height: shelfHeight
        )
        waterfallLayer.frame = CGRect(
            x: shelfLayer.frame.minX,
            y: 34,
            y: RootLayoutMetrics.bottomMargin,
            width: shelfLayer.frame.width,
            height: shelfLayer.frame.minY - 48
            height: max(1, shelfLayer.frame.minY - RootLayoutMetrics.bottomMargin - RootLayoutMetrics.waterfallTopGap)
        )
        layoutSpaceLaneSegments()
@@ -1498,6 +1541,10 @@
        layoutWaterfallColumns()
        CATransaction.commit()
    }
    private var topSafeAreaInset: CGFloat {
        max(0, window?.screen?.safeAreaInsets.top ?? safeAreaInsets.top)
    }
    private func appShelfLayout(for availableWidth: CGFloat) -> AppShelfLayout {
@@ -1837,21 +1884,13 @@
            : NSColor.controlAccentColor.withAlphaComponent(0.90)
        ).cgColor
        item.badgeLayer.frame = CGRect(
            x: iconX + visualIconSize - badgeWidth + 3,
            y: iconY + visualIconSize - 14,
            x: iconX - 3,
            y: iconY - 2,
            width: badgeWidth,
            height: 16
        )
        item.selectedIndicatorLayer.frame = CGRect(
            x: bounds.midX - 8,
            y: 0,
            width: 16,
            height: 4
        )
        item.selectedIndicatorLayer.backgroundColor = (isSelected
            ? NSColor.controlAccentColor
            : NSColor.clear
        ).cgColor
        item.selectedIndicatorLayer.frame = .zero
        item.selectedIndicatorLayer.backgroundColor = NSColor.clear.cgColor
    }
    private func appShelfRows() -> [[AppShelfItemLayers]] {