From ab59aa3a800139e2fe80f7e802dfada2258ab0f6 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 25 Jun 2026 16:24:01 +0800
Subject: [PATCH] Add usage tips close reminder

---
 src/Scripts/usage_tips_qa.sh |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/src/Scripts/usage_tips_qa.sh b/src/Scripts/usage_tips_qa.sh
index 25008cb..be9e0d4 100755
--- a/src/Scripts/usage_tips_qa.sh
+++ b/src/Scripts/usage_tips_qa.sh
@@ -8,6 +8,7 @@
 PREFERENCES_VIEW_SWIFT="$ROOT_DIR/Apptag/PreferencesView.swift"
 APP_DEFAULTS_SWIFT="$ROOT_DIR/Apptag/AppDefaults.swift"
 APP_GRID_THEME_SWIFT="$ROOT_DIR/Apptag/AppGridTheme.swift"
+EDIT_MODE_VIEWS_SWIFT="$ROOT_DIR/Apptag/EditModeViews.swift"
 LOCALIZATION_DIR="$ROOT_DIR/Apptag/Localization"
 
 fail() {
@@ -21,9 +22,10 @@
 [[ -f "$PREFERENCES_VIEW_SWIFT" ]] || fail "missing PreferencesView.swift"
 [[ -f "$APP_DEFAULTS_SWIFT" ]] || fail "missing AppDefaults.swift"
 [[ -f "$APP_GRID_THEME_SWIFT" ]] || fail "missing AppGridTheme.swift"
+[[ -f "$EDIT_MODE_VIEWS_SWIFT" ]] || fail "missing EditModeViews.swift"
 [[ -d "$LOCALIZATION_DIR" ]] || fail "missing Localization directory"
 
-python3 - "$CONTENT_VIEW_SWIFT" "$APP_GRID_SWIFT" "$APPTAG_APP_SWIFT" "$PREFERENCES_VIEW_SWIFT" "$APP_DEFAULTS_SWIFT" "$APP_GRID_THEME_SWIFT" "$LOCALIZATION_DIR" <<'PY'
+python3 - "$CONTENT_VIEW_SWIFT" "$APP_GRID_SWIFT" "$APPTAG_APP_SWIFT" "$PREFERENCES_VIEW_SWIFT" "$APP_DEFAULTS_SWIFT" "$APP_GRID_THEME_SWIFT" "$EDIT_MODE_VIEWS_SWIFT" "$LOCALIZATION_DIR" <<'PY'
 import json
 import pathlib
 import re
@@ -35,7 +37,8 @@
 preferences = pathlib.Path(sys.argv[4]).read_text(encoding="utf-8")
 defaults = pathlib.Path(sys.argv[5]).read_text(encoding="utf-8")
 theme = pathlib.Path(sys.argv[6]).read_text(encoding="utf-8")
-localization_dir = pathlib.Path(sys.argv[7])
+edit_mode_views = pathlib.Path(sys.argv[7]).read_text(encoding="utf-8")
+localization_dir = pathlib.Path(sys.argv[8])
 
 
 def fail(message: str) -> None:
@@ -54,6 +57,10 @@
     "usageTips.previous",
     "usageTips.next",
     "usageTips.close",
+    "usageTips.closeReminder.title",
+    "usageTips.closeReminder.message",
+    "usageTips.closeReminder.doNotRemind",
+    "usageTips.closeReminder.previewCallout",
 ]
 for index in range(1, 9):
     required_keys.append(f"usageTips.tip{index}.title")
@@ -68,6 +75,11 @@
     r'"hideUsageTips"\s*:\s*hideUsageTips',
     defaults,
     "AppDefaults.register must register hideUsageTips",
+)
+require(
+    r'"skipUsageTipsCloseReminder"\s*:\s*false',
+    defaults,
+    "AppDefaults.register must default the usage tips close reminder to visible",
 )
 for source_name, source in {
     "ContentView.swift": content_view,
@@ -114,9 +126,29 @@
     "ContentView must bind usage tip selection to AppGrid",
 )
 require(
-    r"onHideUsageTips\s*:\s*\{\s*hideUsageTips\s*=\s*true\s*\}",
+    r"onHideUsageTips\s*:\s*requestHideUsageTips",
     content_view,
-    "closing the native usage tips banner must persist hideUsageTips",
+    "closing the native usage tips banner must route through the reminder flow",
+)
+require(
+    r'@AppStorage\("skipUsageTipsCloseReminder"\)\s+private\s+var\s+skipUsageTipsCloseReminder\s*=\s*false',
+    content_view,
+    "ContentView must persist the usage tips close reminder suppression flag",
+)
+require(
+    r"private\s+func\s+requestHideUsageTips\s*\(\)\s*\{(?P<body>.*?)skipUsageTipsCloseReminder(?P<body2>.*?)usageTipsCloseReminderVisible\s*=\s*true",
+    content_view,
+    "requestHideUsageTips must show the reminder unless the user suppressed it",
+)
+require(
+    r"private\s+func\s+confirmUsageTipsCloseReminder\s*\(\)\s*\{(?P<body>.*?)skipUsageTipsCloseReminder\s*=\s*true(?P<body2>.*?)hideUsageTips\s*=\s*true",
+    content_view,
+    "confirmUsageTipsCloseReminder must persist suppression only after opt-in and then hide tips",
+)
+require(
+    r"usageTipsCloseReminderVisible",
+    content_view,
+    "usage tips close reminder must participate in modal state and hit testing",
 )
 require(
     r"let\s+onHideUsageTips\s*:\s*\(\)\s*->\s*Void",
@@ -124,15 +156,30 @@
     "AppGridCollectionView must accept an onHideUsageTips callback",
 )
 require(
-    r"closeButton\.action\s*=\s*\{\s*\[weak\s+self\]\s+in\s+self\?\.hideUsageTips\(\)\s*\}",
+    r"closeButton\.action\s*=\s*\{\s*\[weak\s+self\]\s+in\s+self\?\.requestHideUsageTips\(\)\s*\}",
     app_grid,
-    "close button must call the native hideUsageTips handler",
+    "close button must call the native requestHideUsageTips handler",
 )
 require(
     r"coordinator\?\.onHideUsageTips\(\)",
     app_grid,
     "native hideUsageTips must call back to persisted SwiftUI state",
 )
+require(
+    r"struct\s+UsageTipsCloseReminderBubble\s*:\s*View",
+    edit_mode_views,
+    "EditModeViews must provide the close reminder bubble",
+)
+require(
+    r"UsageTipsCloseReminderSettingsPreview\s*\(\s*callout\s*:\s*previewCallout\s*\)",
+    edit_mode_views,
+    "close reminder must pass the localized preview callout into the settings preview",
+)
+require(
+    r"struct\s+UsageTipsCloseReminderSettingsPreview\s*:\s*View(?P<body>.*?)settings\.hideUsageTips",
+    edit_mode_views,
+    "close reminder must include a localized Settings > General preview highlighting Hide usage tips",
+)
 
 require(
     r"private\s+let\s+titlePanelView\s*=\s*NSView\(\)",

--
Gitblit v1.9.3