From fb4eaa3834c5c62c5421dc67c3cdb546b1a5a0f9 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 29 May 2026 05:46:37 +0800
Subject: [PATCH] Modularize settings smart start paths
---
Apptag/SmartStartNoticeOverlay.swift | 99 ++++++++++++++++++++++++
TODO.md | 10 +-
Scripts/window_logic_qa.sh | 5
Apptag/ContentView.swift | 102 +------------------------
Apptag/PreferencesView.swift | 10 -
Apptag/AppLibraryController.swift | 14 +++
6 files changed, 131 insertions(+), 109 deletions(-)
diff --git a/Apptag/AppLibraryController.swift b/Apptag/AppLibraryController.swift
index 7737960..090a31b 100644
--- a/Apptag/AppLibraryController.swift
+++ b/Apptag/AppLibraryController.swift
@@ -17,6 +17,11 @@
let summary: SmartStartSummary?
}
+struct AppLibrarySystemSchemeApplyResult {
+ let snapshot: AppLibrarySnapshot
+ let summary: SmartStartSummary?
+}
+
enum AppLibraryController {
static func refresh() -> AppLibraryRefreshResult {
let scannedApps = AppIndexer.scan()
@@ -42,6 +47,15 @@
)
}
+ static func applySystemInitialScheme() -> AppLibrarySystemSchemeApplyResult {
+ let scannedApps = AppIndexer.scan(useCache: false)
+ let result = SmartStartService.applySystemInitialScheme(apps: scannedApps)
+ return AppLibrarySystemSchemeApplyResult(
+ snapshot: makeSnapshot(scannedApps: scannedApps, store: result.store),
+ summary: result.summary
+ )
+ }
+
private static func makeSnapshot(
scannedApps: [AppInfo],
store: TagDatabase.Store
diff --git a/Apptag/ContentView.swift b/Apptag/ContentView.swift
index 033efcc..e5389cd 100644
--- a/Apptag/ContentView.swift
+++ b/Apptag/ContentView.swift
@@ -340,20 +340,6 @@
let tagName: String
}
-private enum SmartStartNoticeMode {
- case autoApplied
- case suggestionOnly
- case manuallyApplied
-}
-
-private struct SmartStartNotice: Identifiable {
- let id = UUID()
- let mode: SmartStartNoticeMode
- let title: String
- let message: String
- let summary: SmartStartSummary
-}
-
struct ContentView: View {
let hideOverlay: () -> Void
private let initialQuickSearchSource: String?
@@ -1100,88 +1086,12 @@
}
private var smartStartNoticeOverlay: some View {
- GeometryReader { proxy in
- if let notice = smartStartNotice {
- let panelWidth = min(560, max(320, proxy.size.width - 64))
-
- ZStack {
- Color.black.opacity(0.10)
- .ignoresSafeArea()
-
- VStack(spacing: 18) {
- Image(systemName: notice.mode == .suggestionOnly ? "sparkles" : "checkmark.seal.fill")
- .font(.system(size: 30, weight: .semibold))
- .foregroundStyle(Color.accentColor)
- .frame(width: 58, height: 58)
- .background(
- Circle()
- .fill(Color.accentColor.opacity(0.12))
- )
-
- VStack(spacing: 8) {
- Text(notice.title)
- .font(.system(size: 21, weight: .semibold))
- .foregroundStyle(.primary)
- .multilineTextAlignment(.center)
-
- Text(notice.message)
- .font(.system(size: 15, weight: .regular))
- .foregroundStyle(.secondary)
- .multilineTextAlignment(.center)
- .lineLimit(4)
- .fixedSize(horizontal: false, vertical: true)
- }
-
- HStack(spacing: 12) {
- switch notice.mode {
- case .suggestionOnly:
- Button(tr("smartstart.later")) {
- dismissSmartStartNotice()
- }
- .buttonStyle(.bordered)
- .controlSize(.large)
-
- Button(tr("smartstart.apply")) {
- applySmartStartSuggestion()
- }
- .buttonStyle(.borderedProminent)
- .controlSize(.large)
- case .autoApplied, .manuallyApplied:
- if notice.summary.backupPath != nil {
- Button(tr("smartstart.undo")) {
- undoSmartStart()
- }
- .buttonStyle(.bordered)
- .controlSize(.large)
- }
- Button(tr("smartstart.ok")) {
- dismissSmartStartNotice()
- }
- .buttonStyle(.borderedProminent)
- .controlSize(.large)
- }
- }
- }
- .padding(.horizontal, 30)
- .padding(.vertical, 26)
- .frame(width: panelWidth)
- .background(
- RoundedRectangle(cornerRadius: 16)
- .fill(.ultraThickMaterial)
- .shadow(color: .black.opacity(0.26), radius: 28, y: 16)
- )
- .overlay(
- RoundedRectangle(cornerRadius: 16)
- .stroke(.white.opacity(0.16), lineWidth: 1)
- )
- }
- .frame(width: proxy.size.width, height: proxy.size.height)
- .transition(.scale(scale: 0.96).combined(with: .opacity))
- .zIndex(650)
- }
- }
- .ignoresSafeArea()
- .allowsHitTesting(smartStartNotice != nil)
+ SmartStartNoticeOverlay(
+ notice: smartStartNotice,
+ onDismiss: dismissSmartStartNotice,
+ onApply: applySmartStartSuggestion,
+ onUndo: undoSmartStart
+ )
}
// MARK: - Edit Tags View
diff --git a/Apptag/PreferencesView.swift b/Apptag/PreferencesView.swift
index 37b2276..3549010 100644
--- a/Apptag/PreferencesView.swift
+++ b/Apptag/PreferencesView.swift
@@ -271,16 +271,12 @@
isApplyingSystemScheme = true
DispatchQueue.global(qos: .userInitiated).async {
- let scannedApps = AppIndexer.scan(useCache: false)
- let result = SmartStartService.applySystemInitialScheme(apps: scannedApps)
- let store = result.store
- let apps = TagEditor.annotate(apps: scannedApps, store: store)
- let colors = store.tags.mapValues { $0.color }
+ let result = AppLibraryController.applySystemInitialScheme()
DispatchQueue.main.async {
isApplyingSystemScheme = false
- allApps = apps
- tagColors = colors
+ allApps = result.snapshot.apps
+ tagColors = result.snapshot.tagColors
refreshDataState()
notifyDataChanged()
diff --git a/Apptag/SmartStartNoticeOverlay.swift b/Apptag/SmartStartNoticeOverlay.swift
new file mode 100644
index 0000000..c034271
--- /dev/null
+++ b/Apptag/SmartStartNoticeOverlay.swift
@@ -0,0 +1,99 @@
+import SwiftUI
+
+enum SmartStartNoticeMode {
+ case autoApplied
+ case suggestionOnly
+ case manuallyApplied
+}
+
+struct SmartStartNotice: Identifiable {
+ let id = UUID()
+ let mode: SmartStartNoticeMode
+ let title: String
+ let message: String
+ let summary: SmartStartSummary
+}
+
+struct SmartStartNoticeOverlay: View {
+ let notice: SmartStartNotice?
+ let onDismiss: () -> Void
+ let onApply: () -> Void
+ let onUndo: () -> Void
+
+ var body: some View {
+ GeometryReader { proxy in
+ if let notice {
+ let panelWidth = min(560, max(320, proxy.size.width - 64))
+
+ ZStack {
+ Color.black.opacity(0.10)
+ .ignoresSafeArea()
+
+ VStack(spacing: 18) {
+ Image(systemName: notice.mode == .suggestionOnly ? "sparkles" : "checkmark.seal.fill")
+ .font(.system(size: 30, weight: .semibold))
+ .foregroundStyle(Color.accentColor)
+ .frame(width: 58, height: 58)
+ .background(
+ Circle()
+ .fill(Color.accentColor.opacity(0.12))
+ )
+
+ VStack(spacing: 8) {
+ Text(notice.title)
+ .font(.system(size: 21, weight: .semibold))
+ .foregroundStyle(.primary)
+ .multilineTextAlignment(.center)
+
+ Text(notice.message)
+ .font(.system(size: 15, weight: .regular))
+ .foregroundStyle(.secondary)
+ .multilineTextAlignment(.center)
+ .lineLimit(4)
+ .fixedSize(horizontal: false, vertical: true)
+ }
+
+ HStack(spacing: 12) {
+ switch notice.mode {
+ case .suggestionOnly:
+ Button(tr("smartstart.later"), action: onDismiss)
+ .buttonStyle(.bordered)
+ .controlSize(.large)
+
+ Button(tr("smartstart.apply"), action: onApply)
+ .buttonStyle(.borderedProminent)
+ .controlSize(.large)
+ case .autoApplied, .manuallyApplied:
+ if notice.summary.backupPath != nil {
+ Button(tr("smartstart.undo"), action: onUndo)
+ .buttonStyle(.bordered)
+ .controlSize(.large)
+ }
+ Button(tr("smartstart.ok"), action: onDismiss)
+ .buttonStyle(.borderedProminent)
+ .controlSize(.large)
+ }
+ }
+ }
+ .padding(.horizontal, 30)
+ .padding(.vertical, 26)
+ .frame(width: panelWidth)
+ .background(
+ RoundedRectangle(cornerRadius: 16)
+ .fill(.ultraThickMaterial)
+ .shadow(color: .black.opacity(0.26), radius: 28, y: 16)
+ )
+ .overlay(
+ RoundedRectangle(cornerRadius: 16)
+ .stroke(.white.opacity(0.16), lineWidth: 1)
+ )
+ }
+ .frame(width: proxy.size.width, height: proxy.size.height)
+ .transition(.scale(scale: 0.96).combined(with: .opacity))
+ .zIndex(650)
+ }
+ }
+ .ignoresSafeArea()
+ .allowsHitTesting(notice != nil)
+ }
+}
diff --git a/Scripts/window_logic_qa.sh b/Scripts/window_logic_qa.sh
index 05fd697..f7dc843 100755
--- a/Scripts/window_logic_qa.sh
+++ b/Scripts/window_logic_qa.sh
@@ -1143,8 +1143,9 @@
SWIFT
done < <(swift "$screens_swift")
else
- rg -Fq 'screenContainingCurrentPointer() ??' "$ROOT_DIR/Apptag/ApptagApp.swift"
- rg -Fq 'NSMouseInRect(mousePoint, $0.frame, false)' "$ROOT_DIR/Apptag/ApptagApp.swift"
+ rg -Fq 'statusMenuScreenForNextOverlay = overlayController.screenContainingCurrentPointer()' "$ROOT_DIR/Apptag/ApptagApp.swift"
+ rg -Fq 'screenContainingCurrentPointer() ??' "$ROOT_DIR/Apptag/OverlayWindowController.swift"
+ rg -Fq 'NSMouseInRect(mousePoint, $0.frame, false)' "$ROOT_DIR/Apptag/OverlayWindowController.swift"
log "PASS screen-following static path: single physical display here; code selects NSScreen under current pointer"
fi
diff --git a/TODO.md b/TODO.md
index 757d5d5..59f85d5 100644
--- a/TODO.md
+++ b/TODO.md
@@ -13,12 +13,14 @@
## Todo
-- [2026-05-28] 设置页和 Smart Start 模块化。
- - 目标: 低频路径后置整理。
- - 验收: 语言、通用、快捷键、标签、数据、关于页都保持现有行为。
-
## Done
+- [2026-05-29] 设置页和 Smart Start 模块化。
+ - 提交: 本次提交
+ - 结果: `SmartStartNoticeOverlay` 已从 `ContentView` 拆出;设置页“应用系统智能化初始分类”的扫描、Smart Start 应用和 snapshot 组装改由 `AppLibraryController` 统一处理;窗口 QA 脚本同步适配 `OverlayWindowController` 的屏幕选择静态检查。
+ - 范围: 不改设置页 UI 布局、不改 Smart Start 分类规则、不改导入/导出/恢复行为。
+ - 验证: `bash build.sh`、`codesign --verify --deep --strict`、设置页语言/通用/快捷键/标签/数据/关于六个 tab 屏幕复核、`Scripts/window_logic_qa.sh` 全部通过。
+
- [2026-05-29] AppLibraryController / 数据刷新管线整理。
- 提交: 本次提交
- 结果: 新增 `AppLibraryController` 和 `AppLibrarySnapshot`,把扫描、reconcile、Smart Start、annotate、Quick Search documents、标签颜色和标签顺序组装从 `ContentView` 的刷新路径中抽离。
--
Gitblit v1.9.3