From a80a5b8edd2fc2958252c127ee378112f219841f Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sat, 13 Jun 2026 19:32:08 +0800
Subject: [PATCH] Move usage tip dots below controls

---
 src/Apptag/AppGridCollectionView.swift |   23 +++++++++++------------
 src/Scripts/usage_tips_qa.sh           |   10 ++++++++++
 2 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/Apptag/AppGridCollectionView.swift b/src/Apptag/AppGridCollectionView.swift
index 24ad5f3..e5df3a5 100644
--- a/src/Apptag/AppGridCollectionView.swift
+++ b/src/Apptag/AppGridCollectionView.swift
@@ -944,8 +944,7 @@
         let iconSize: CGFloat = 24
         let iconTextGap: CGFloat = 10
         let titleDetailGap: CGFloat = 22
-        let detailDotsGap: CGFloat = 24
-        let dotsButtonGap: CGFloat = 16
+        let detailControlsGap: CGFloat = 24
         let buttonGap: CGFloat = 6
         let buttonSize: CGFloat = 48
         let dotsWidth = dotsView.preferredWidth
@@ -961,7 +960,7 @@
 
         let titleX = iconView.frame.maxX + iconTextGap
         let buttonsWidth = buttonSize * 2 + buttonGap
-        let trailingWidth = paddingRight + buttonsWidth + dotsButtonGap + dotsWidth + detailDotsGap
+        let trailingWidth = paddingRight + buttonsWidth + detailControlsGap
         let availableTextWidth = max(1, visualFrame.maxX - titleX - titleDetailGap - trailingWidth)
         let minimumReadableDetailWidth: CGFloat = 220
         let titleWidth: CGFloat
@@ -980,28 +979,29 @@
             height: visualFrame.height
         )
 
-        let buttonY = centerY - buttonSize / 2
+        let buttonY = visualFrame.minY + 10
+        let buttonsGroupMinX = visualFrame.maxX - paddingRight - buttonsWidth
         nextButton.frame = NSRect(
-            x: visualFrame.maxX - paddingRight - buttonSize,
+            x: buttonsGroupMinX + buttonSize + buttonGap,
             y: buttonY,
             width: buttonSize,
             height: buttonSize
         )
         previousButton.frame = NSRect(
-            x: nextButton.frame.minX - buttonGap - buttonSize,
+            x: buttonsGroupMinX,
             y: buttonY,
             width: buttonSize,
             height: buttonSize
         )
         dotsView.frame = NSRect(
-            x: previousButton.frame.minX - dotsButtonGap - dotsWidth,
-            y: centerY - 5,
+            x: buttonsGroupMinX + (buttonsWidth - dotsWidth) / 2,
+            y: previousButton.frame.maxY + 6,
             width: dotsWidth,
             height: 10
         )
 
         let detailX = titleLabel.frame.maxX + titleDetailGap
-        let detailRight = dotsView.frame.minX - detailDotsGap
+        let detailRight = previousButton.frame.minX - detailControlsGap
         detailScrollView.frame = NSRect(
             x: detailX,
             y: visualFrame.minY,
@@ -1048,11 +1048,10 @@
 
     func preferredWidth(maxAvailableWidth: CGFloat) -> CGFloat {
         let padding: CGFloat = 22 + 16
-        let fixedWidth: CGFloat = 24 + 10 + 22 + 24 + 16 + 48 + 6 + 48
-        let dotsWidth = dotsView.preferredWidth
+        let fixedWidth: CGFloat = 24 + 10 + 22 + 24 + 48 + 6 + 48
         let titleWidth = ceil(titleLabel.attributedStringValue.size().width)
         let detailWidth = ceil(detailLabel.attributedStringValue.size().width)
-        let contentWidth = padding + fixedWidth + dotsWidth + titleWidth + detailWidth
+        let contentWidth = padding + fixedWidth + titleWidth + detailWidth
         let preferredWidth = max(AppGridUsageTipsMetrics.minWidth, contentWidth)
         return min(maxAvailableWidth, preferredWidth)
     }
diff --git a/src/Scripts/usage_tips_qa.sh b/src/Scripts/usage_tips_qa.sh
index ac03213..78834f8 100755
--- a/src/Scripts/usage_tips_qa.sh
+++ b/src/Scripts/usage_tips_qa.sh
@@ -130,6 +130,16 @@
     "Usage tips layout must allocate text from actual available AppGrid width",
 )
 require(
+    r"dotsView\.frame\s*=\s*NSRect\s*\((?P<body>.*?)x\s*:\s*buttonsGroupMinX\s*\+\s*\(buttonsWidth\s*-\s*dotsWidth\)\s*/\s*2(?P<body2>.*?)y\s*:\s*previousButton\.frame\.maxY\s*\+\s*6",
+    app_grid,
+    "Usage tips page dots must sit centered below the previous/next arrow buttons",
+)
+require(
+    r"detailRight\s*=\s*previousButton\.frame\.minX\s*-\s*detailControlsGap",
+    app_grid,
+    "Usage tips detail text must stop before the arrow controls when dots move below them",
+)
+require(
     r"return\s+min\s*\(\s*maxAvailableWidth\s*,\s*preferredWidth\s*\)",
     app_grid,
     "Usage tips preferred width must expand up to available AppGrid width for long localizations",

--
Gitblit v1.9.3