Ariver
2026-06-28 8fbe7d9123cdb618de5ecf3cd1b0fb81199a2dac
C1.source/Sources/AlignerCore/Windows/QuickSwitchViewModel.swift
@@ -1,3 +1,4 @@
import CoreGraphics
import Foundation
public struct QuickSwitchViewModel: Equatable, Sendable {
@@ -62,6 +63,7 @@
    public let windowCount: Int
    public let appCount: Int
    public let appNames: [String]
    public let splitViewAppNames: [String]
    public init(
        id: UInt64,
@@ -72,7 +74,8 @@
        isCurrent: Bool = false,
        windowCount: Int,
        appCount: Int,
        appNames: [String] = []
        appNames: [String] = [],
        splitViewAppNames: [String] = []
    ) {
        self.id = id
        self.displayUUID = displayUUID
@@ -83,6 +86,7 @@
        self.windowCount = windowCount
        self.appCount = appCount
        self.appNames = appNames
        self.splitViewAppNames = splitViewAppNames
    }
}
@@ -166,12 +170,14 @@
        let windowCountsBySpace = countWindowsBySpace(windowItems)
        let appCountsBySpace = countAppsBySpace(snapshot.appGroups)
        let appNamesBySpace = appNamesBySpace(snapshot.appGroups)
        let splitViewAppNamesBySpace = splitViewAppNamesBySpace(snapshot.appGroups)
        let displays = displayViewModels(
            from: snapshot.displays,
            currentSpaceIDs: currentSpaceIDs,
            windowCountsBySpace: windowCountsBySpace,
            appCountsBySpace: appCountsBySpace,
            appNamesBySpace: appNamesBySpace
            appNamesBySpace: appNamesBySpace,
            splitViewAppNamesBySpace: splitViewAppNamesBySpace
        )
        let appShelf = appShelfViewModels(from: snapshot.appGroups)
@@ -210,7 +216,8 @@
        currentSpaceIDs: Set<UInt64>,
        windowCountsBySpace: [UInt64: Int],
        appCountsBySpace: [UInt64: Int],
        appNamesBySpace: [UInt64: [String]]
        appNamesBySpace: [UInt64: [String]],
        splitViewAppNamesBySpace: [UInt64: [String]]
    ) -> [QuickSwitchDisplayViewModel] {
        let sortedDisplays = displays
            .sorted { $0.uuid.localizedStandardCompare($1.uuid) == .orderedAscending }
@@ -232,7 +239,8 @@
                            isCurrent: currentSpaceIDs.contains(space.id),
                            windowCount: windowCountsBySpace[space.id] ?? 0,
                            appCount: appCountsBySpace[space.id] ?? 0,
                            appNames: appNamesBySpace[space.id] ?? []
                            appNames: appNamesBySpace[space.id] ?? [],
                            splitViewAppNames: splitViewAppNamesBySpace[space.id] ?? []
                        )
                    }
@@ -309,6 +317,54 @@
        return namesBySpace
    }
    private static func splitViewAppNamesBySpace(_ appGroups: [QuickSwitchAppGroup]) -> [UInt64: [String]] {
        struct Candidate {
            let appName: String
            let windowID: UInt32
            let frame: CGRect
        }
        var candidatesBySpace: [UInt64: [Candidate]] = [:]
        for group in appGroups {
            for item in group.windows {
                guard item.window.isFullscreen,
                      let primarySpaceID = item.primarySpaceID,
                      let frame = item.window.frame,
                      frame.width > 0,
                      frame.height > 0
                else {
                    continue
                }
                candidatesBySpace[primarySpaceID, default: []].append(
                    Candidate(
                        appName: group.app.name,
                        windowID: item.window.id,
                        frame: frame
                    )
                )
            }
        }
        return candidatesBySpace.compactMapValues { candidates in
            guard candidates.count >= 2 else { return nil }
            return candidates
                .sorted { lhs, rhs in
                    if lhs.frame.midX != rhs.frame.midX {
                        return lhs.frame.midX < rhs.frame.midX
                    }
                    if lhs.frame.midY != rhs.frame.midY {
                        return lhs.frame.midY < rhs.frame.midY
                    }
                    return lhs.windowID < rhs.windowID
                }
                .prefix(2)
                .map(\.appName)
        }
    }
    private static func orderedUnique<T: Hashable>(_ values: [T]) -> [T] {
        var seen = Set<T>()
        var result: [T] = []