From 28be00ea53666fd5500a702a3c187c0e27dd90ad Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sat, 27 Jun 2026 16:26:30 +0800
Subject: [PATCH] Simplify SmartStart default categories

---
 src/Apptag/AppGridCollectionView.swift |   74 +++++++++++++++++++++++++++++++++---
 1 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/src/Apptag/AppGridCollectionView.swift b/src/Apptag/AppGridCollectionView.swift
index 13fe190..8807590 100644
--- a/src/Apptag/AppGridCollectionView.swift
+++ b/src/Apptag/AppGridCollectionView.swift
@@ -564,6 +564,17 @@
         }
     }
 
+    func canPreviewEmptyDrop(path: String, source: String, screenPoint: NSPoint, copy: Bool) -> Bool {
+        guard let coordinator,
+              coordinator.displayStyle != .flat
+        else { return false }
+        return !coordinator.shouldCancelEmptyDropForActiveReorder(
+            path: path,
+            screenPoint: screenPoint,
+            copy: copy
+        )
+    }
+
     private func setup() {
         wantsLayer = true
         layer?.backgroundColor = NSColor.clear.cgColor
@@ -1134,7 +1145,7 @@
         detailScrollView.borderType = .noBorder
         detailScrollView.documentView = detailLabel
 
-        closeButton.action = { [weak self] in self?.hideUsageTips() }
+        closeButton.action = { [weak self] in self?.requestHideUsageTips() }
         previousButton.action = { [weak self] in self?.selectUsageTip(offset: -1) }
         nextButton.action = { [weak self] in self?.selectUsageTip(offset: 1) }
 
@@ -1194,10 +1205,9 @@
         applyCoordinatorState()
     }
 
-    private func hideUsageTips() {
+    private func requestHideUsageTips() {
         Diagnostics.log("usageTips.hud.close")
         clearHoverState()
-        isHidden = true
         coordinator?.onHideUsageTips()
     }
 
@@ -1206,7 +1216,7 @@
         let closeHitOutset: CGFloat = 8
         if closeButton.frame.insetBy(dx: -closeHitOutset, dy: -closeHitOutset).contains(point) {
             closeButton.performPressFeedback()
-            hideUsageTips()
+            requestHideUsageTips()
             return true
         }
         let hitOutset: CGFloat = 6
@@ -1767,7 +1777,7 @@
 
     private struct LayoutItem {
         let index: Int
-        let frame: NSRect
+        var frame: NSRect
     }
 
     private struct LayoutPlan {
@@ -1903,8 +1913,20 @@
         let columnWidth = floor((availableWidth - gap * CGFloat(columnCount - 1)) / CGFloat(columnCount))
         var columnHeights = Array(repeating: outerPadding, count: columnCount)
         var items: [LayoutItem] = []
+        var lastItemIndexForColumn = Array<Int?>(repeating: nil, count: columnCount)
+        let bottomPinnedGroups = groups.enumerated()
+            .filter { bottomPinnedPriority(for: $0.element.containerID) != nil }
+            .sorted {
+                let lhsPriority = bottomPinnedPriority(for: $0.element.containerID) ?? Int.max
+                let rhsPriority = bottomPinnedPriority(for: $1.element.containerID) ?? Int.max
+                if lhsPriority != rhsPriority { return lhsPriority < rhsPriority }
+                return $0.offset < $1.offset
+            }
+        let bottomPinnedIndexes = Set(bottomPinnedGroups.map { $0.offset })
 
         for (index, group) in groups.enumerated() {
+            if bottomPinnedIndexes.contains(index) { continue }
+
             let columnIndex = columnHeights.indices.min { columnHeights[$0] < columnHeights[$1] } ?? 0
             let x = outerPadding + CGFloat(columnIndex) * (columnWidth + gap)
             let y = columnHeights[columnIndex]
@@ -1919,11 +1941,38 @@
                     frame: NSRect(x: x, y: y, width: columnWidth, height: height)
                 )
             )
+            lastItemIndexForColumn[columnIndex] = items.count - 1
             columnHeights[columnIndex] = y + height + gap
         }
 
-        let tallest = columnHeights.max() ?? outerPadding
-        let contentHeight = (groups.isEmpty ? outerPadding * 2 : tallest - gap + outerPadding)
+        var contentBottom = columnHeights.max() ?? outerPadding
+        if !bottomPinnedGroups.isEmpty {
+            let alignedBottom = max(outerPadding, contentBottom - gap)
+            for itemIndex in lastItemIndexForColumn.compactMap({ $0 }) {
+                let currentFrame = items[itemIndex].frame
+                let alignedHeight = alignedBottom - currentFrame.minY
+                if alignedHeight > currentFrame.height {
+                    items[itemIndex].frame.size.height = alignedHeight
+                }
+            }
+        }
+        for (index, group) in bottomPinnedGroups {
+            let y = max(outerPadding, contentBottom)
+            let height = AppGridCollectionMetrics.cardHeight(
+                appCount: group.apps.count,
+                width: availableWidth,
+                iconSize: iconSize
+            )
+            items.append(
+                LayoutItem(
+                    index: index,
+                    frame: NSRect(x: outerPadding, y: y, width: availableWidth, height: height)
+                )
+            )
+            contentBottom = y + height + gap
+        }
+
+        let contentHeight = (items.isEmpty ? outerPadding * 2 : contentBottom - gap + outerPadding)
             + max(0, bottomContentPadding)
         return LayoutPlan(
             items: items,
@@ -1931,6 +1980,17 @@
         )
     }
 
+    private static func bottomPinnedPriority(for containerID: String) -> Int? {
+        switch containerID {
+        case AppContainerID.uncategorized:
+            return 0
+        case AppContainerID.appleBuiltIn:
+            return 1
+        default:
+            return nil
+        }
+    }
+
     private struct RowItem {
         let index: Int
         let width: CGFloat

--
Gitblit v1.9.3