From b7f869facbb64b6415a31af0b5c46b5b3df14800 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 29 May 2026 05:23:24 +0800
Subject: [PATCH] Extract app library refresh pipeline
---
TODO.md | 10 +++--
Apptag/ContentView.swift | 53 +++++++++-----------------
Apptag/AppLibraryController.swift | 57 ++++++++++++++++++++++++++++
3 files changed, 82 insertions(+), 38 deletions(-)
diff --git a/Apptag/AppLibraryController.swift b/Apptag/AppLibraryController.swift
new file mode 100644
index 0000000..7737960
--- /dev/null
+++ b/Apptag/AppLibraryController.swift
@@ -0,0 +1,57 @@
+import Foundation
+
+struct AppLibrarySnapshot {
+ let apps: [AppInfo]
+ let quickSearchDocuments: [QuickSearchDocument]
+ let tagColors: [String: Int]
+ let tagOrder: [String]
+}
+
+struct AppLibraryRefreshResult {
+ let snapshot: AppLibrarySnapshot
+ let smartStartResult: SmartStartRunResult
+}
+
+struct AppLibrarySmartStartApplyResult {
+ let snapshot: AppLibrarySnapshot
+ let summary: SmartStartSummary?
+}
+
+enum AppLibraryController {
+ static func refresh() -> AppLibraryRefreshResult {
+ let scannedApps = AppIndexer.scan()
+ let reconciledStore = TagEditor.reconcileScannedApps(scannedApps)
+ let smartStartResult = SmartStartService.runIfNeeded(
+ apps: scannedApps,
+ store: reconciledStore
+ )
+ return AppLibraryRefreshResult(
+ snapshot: makeSnapshot(scannedApps: scannedApps, store: smartStartResult.store),
+ smartStartResult: smartStartResult
+ )
+ }
+
+ static func applySmartStartSuggestion(
+ _ draft: SmartCategorizationDraft,
+ scannedApps: [AppInfo]
+ ) -> AppLibrarySmartStartApplyResult {
+ let result = SmartStartService.applySuggestion(draft)
+ return AppLibrarySmartStartApplyResult(
+ snapshot: makeSnapshot(scannedApps: scannedApps, store: result.store),
+ summary: result.summary
+ )
+ }
+
+ private static func makeSnapshot(
+ scannedApps: [AppInfo],
+ store: TagDatabase.Store
+ ) -> AppLibrarySnapshot {
+ let apps = TagEditor.annotate(apps: scannedApps, store: store)
+ return AppLibrarySnapshot(
+ apps: apps,
+ quickSearchDocuments: QuickSearchEngine.makeDocuments(apps: apps, store: store),
+ tagColors: store.tags.mapValues { $0.color },
+ tagOrder: TagEditor.orderedTagNames()
+ )
+ }
+}
diff --git a/Apptag/ContentView.swift b/Apptag/ContentView.swift
index 900cf4d..033efcc 100644
--- a/Apptag/ContentView.swift
+++ b/Apptag/ContentView.swift
@@ -1702,23 +1702,14 @@
let scannedApps = allApps
DispatchQueue.global(qos: .userInitiated).async {
- let result = SmartStartService.applySuggestion(draft)
- let store = result.store
- let apps = TagEditor.annotate(apps: scannedApps, store: store)
- let quickSearchDocs = QuickSearchEngine.makeDocuments(apps: apps, store: store)
- let colors = store.tags.mapValues { $0.color }
- let order = TagEditor.orderedTagNames()
+ let result = AppLibraryController.applySmartStartSuggestion(
+ draft,
+ scannedApps: scannedApps
+ )
DispatchQueue.main.async {
pendingSmartStartDraft = nil
- allApps = apps
- quickSearchDocuments = quickSearchDocs
- tagColors = colors
- draggedTagNames = order
- rebuildDisplayGroups(apps: apps, tagOrder: order)
- if quickSearchVisible {
- refreshQuickSearchResults()
- }
+ applyAppLibrarySnapshot(result.snapshot)
if let summary = result.summary {
showSmartStartNotice(mode: .manuallyApplied, summary: summary)
} else {
@@ -2370,27 +2361,10 @@
refreshInProgress = true
DispatchQueue.global(qos: .userInitiated).async {
- let scannedApps = AppIndexer.scan()
- let reconciledStore = TagEditor.reconcileScannedApps(scannedApps)
- let smartStartResult = SmartStartService.runIfNeeded(
- apps: scannedApps,
- store: reconciledStore
- )
- let store = smartStartResult.store
- let apps = TagEditor.annotate(apps: scannedApps, store: store)
- let quickSearchDocs = QuickSearchEngine.makeDocuments(apps: apps, store: store)
- let colors = store.tags.mapValues { $0.color }
- let order = TagEditor.orderedTagNames()
+ let result = AppLibraryController.refresh()
DispatchQueue.main.async {
- allApps = apps
- quickSearchDocuments = quickSearchDocs
- tagColors = colors
- draggedTagNames = order
- rebuildDisplayGroups(apps: apps, tagOrder: order)
- if quickSearchVisible {
- refreshQuickSearchResults()
- }
- handleSmartStartRunResult(smartStartResult)
+ applyAppLibrarySnapshot(result.snapshot)
+ handleSmartStartRunResult(result.smartStartResult)
if forceLayoutRefresh {
finishDropRefreshAfterMinimumDuration()
}
@@ -2405,6 +2379,17 @@
}
}
+ private func applyAppLibrarySnapshot(_ snapshot: AppLibrarySnapshot) {
+ allApps = snapshot.apps
+ quickSearchDocuments = snapshot.quickSearchDocuments
+ tagColors = snapshot.tagColors
+ draggedTagNames = snapshot.tagOrder
+ rebuildDisplayGroups(apps: snapshot.apps, tagOrder: snapshot.tagOrder)
+ if quickSearchVisible {
+ refreshQuickSearchResults()
+ }
+ }
+
private func launchApp(
_ app: AppInfo,
closeQuickSearchOnSuccess: Bool = false,
diff --git a/TODO.md b/TODO.md
index ce466f2..757d5d5 100644
--- a/TODO.md
+++ b/TODO.md
@@ -13,16 +13,18 @@
## Todo
-- [2026-05-28] AppLibraryController / 数据刷新管线整理。
- - 目标: 把扫描、reconcile、Smart Start、annotate、Quick Search documents 更新从 `ContentView` 中抽离。
- - 验收: 启动扫描、拖拽改标签、Quick Search 索引同步、新安装 App 后刷新。
-
- [2026-05-28] 设置页和 Smart Start 模块化。
- 目标: 低频路径后置整理。
- 验收: 语言、通用、快捷键、标签、数据、关于页都保持现有行为。
## Done
+- [2026-05-29] AppLibraryController / 数据刷新管线整理。
+ - 提交: 本次提交
+ - 结果: 新增 `AppLibraryController` 和 `AppLibrarySnapshot`,把扫描、reconcile、Smart Start、annotate、Quick Search documents、标签颜色和标签顺序组装从 `ContentView` 的刷新路径中抽离。
+ - 范围: 不改扫描、数据库、搜索匹配、拖拽改标签逻辑;`ContentView` 只应用 snapshot 并刷新 UI。
+ - 验证: `bash build.sh`、`codesign --verify --deep --strict`、启动 App Grid 屏幕复核、Quick Search `sor` 索引复核、上下键复核、`Scripts/window_logic_qa.sh` 全部通过。
+
- [2026-05-29] OverlayWindowController 收口。
- 提交: 本次提交
- 结果: 新增 `OverlayWindowController`,将 overlay window 实例、generation、Space 避让、show/focus/hide 编排、panel 创建、屏幕选择、全屏/Split View 判定从 `AppDelegate` 中收口出去。
--
Gitblit v1.9.3