| Apptag/AppLibraryController.swift | ●●●●● patch | view | raw | blame | history | |
| Apptag/ContentView.swift | ●●●●● patch | view | raw | blame | history | |
| TODO.md | ●●●●● patch | view | raw | blame | history |
Apptag/AppLibraryController.swift
New file @@ -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() ) } } 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, 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` 中收口出去。