# TagLauncher 当前底层信息架构 生成日期:2026-05-20 ## 1. 总体架构图 ```mermaid flowchart TD User["用户"] MenuBar["菜单栏 / Dock / 全局快捷键"] AppDelegate["AppDelegate
窗口、菜单、快捷键、生命周期"] Overlay["ContentView 主覆盖层"] Settings["PreferencesView 设置窗口"] Scanner["AppIndexer
本机 App 扫描"] Store["TagDatabase Store
tags.json"] SmartStart["SmartStartService
本地智能分类"] Search["QuickSearchEngine
快速搜索索引与排序"] UIState["SwiftUI 展示状态
allApps / displayGroups / quickSearchDocuments"] Resources["Bundle Resources
Localization / SmartStart catalog / icons"] System["macOS APIs
NSWorkspace / Carbon Hotkey / LaunchAgent"] User --> MenuBar MenuBar --> AppDelegate AppDelegate --> Overlay AppDelegate --> Settings AppDelegate --> System Overlay --> Scanner Scanner --> UIState Overlay --> Store Store --> UIState Overlay --> SmartStart SmartStart --> Store SmartStart --> Resources Overlay --> Search Search --> UIState Settings --> Store Settings --> Resources Resources --> Overlay ``` ## 2. 架构分层 ### 2.1 入口与系统集成层 主要文件: - `Apptag/ApptagApp.swift` - `Apptag/AppDefaults.swift` 职责: - App 启动与生命周期。 - 菜单栏状态项。 - Dock 显示策略。 - 覆盖层窗口创建和隐藏。 - 设置窗口管理。 - Carbon 全局快捷键注册。 - LaunchAgent 开机登录。 - App 菜单裁剪和本地化刷新。 关键状态: - `overlayWindow` - `settingsWindow` - `mainHotkeyRef` - `quickSearchHotkeyRef` - `isQuickSearchOpen` - `isInEditMode` - `isEditingAppNote` - `isModalInteractionActive` ### 2.2 展示与交互层 主要文件: - `Apptag/ContentView.swift` - `Apptag/TagGroupView.swift` - `Apptag/AppGridItem.swift` - `Apptag/EditModeViews.swift` - `Apptag/TagEditorView.swift` - `Apptag/PreferencesView.swift` 职责: - 主界面布局。 - 分组和 App 图标展示。 - 容器视图、网格容器视图和平铺视图。 - 标签导航、标签排序。 - 批量编辑 App 标签。 - App hover 气泡和备注编辑。 - Quick Search 浮层挂载。 - 设置页各模块。 核心展示状态: | 状态 | 含义 | |---|---| | `allApps` | 已扫描并标注后的 App 列表 | | `displayGroups` | 当前用于展示的分组结果 | | `tagColors` | 标签到颜色索引的映射 | | `draggedTagNames` | 当前标签显示顺序 | | `quickSearchDocuments` | Quick Search 搜索文档 | | `quickSearchResults` | 当前搜索结果 | | `editPhase` | 当前编辑模式 | | `hoveredBubble` / `editingBubble` | App 用途气泡状态 | | `pendingUncategorizedDrop` | 拖到未分类后的待确认状态 | ### 2.3 本机 App 索引层 主要文件: - `Apptag/DataLayer.swift` 核心对象: ```swift struct AppInfo { let name: String let path: URL let tags: [String] let bundleIdentifier: String? let localizedNames: [String] let icon: NSImage var isUncommon: Bool var note: String? } ``` 职责: - 扫描标准 App 目录。 - 收集 bundle identifier。 - 读取本地化 App 名称。 - 预加载图标。 - 识别 Apple App。 - 去重。 - 输出可被 TagEditor 标注的基础 App 列表。 ### 2.4 本地数据存储层 主要文件: - `Apptag/DataLayer.swift` 存储位置: ```text ~/Library/Application Support/Apptag/tags.json ``` 备份目录: ```text ~/Library/Application Support/Apptag/SmartStartBackups ~/Library/Application Support/Apptag/CategorySchemeBackups ``` 核心 store: ```swift struct Store { var version: Int var tags: [String: TagDef] var appTags: [String: [String]] var tagOrder: [String] var uncommonAppPaths: [String] var uncommonSources: [String: UncommonSource] var appOpenCounts: [String: Int] var appLastOpenedAt: [String: Date] var knownAppPaths: [String] var appNotes: [String: String] var disabledSystemCategoryIDs: [SmartCategoryID] var smartStart: SmartStartState var categoryScheme: CategorySchemeState } ``` 核心身份: - App 身份:优先 path 存储用户数据。 - 标签身份:普通标签用名称;系统标签额外有 `SmartCategoryID`。 - 不常用身份:path 集合 + source。 - 分类方案身份:名称 + 创建时间 + previous backup path。 ### 2.5 标签编辑领域层 主要文件: - `Apptag/DataLayer.swift` 职责: - 创建、重命名、删除标签。 - 调整标签颜色和顺序。 - 给 App 添加、移除、移动标签。 - 设置 App 备注。 - 记录从 TagLauncher 启动 App 的行为数据。 - 扫描后 reconcile 新旧 App。 - 维护分类方案自动快照。 领域约束: - 用户数据写入都围绕 `TagDatabase.Store`。 - 影响分类方案的操作走 `saveUserCategorySchemeMutation`,用于记录 previous scheme。 - 新安装 App 的发现不触发分类方案快照。 - 记录打开历史不触发分类方案快照。 ### 2.6 Smart Start 领域层 主要文件: - `Apptag/SmartCategorization/SmartStartService.swift` - `Apptag/SmartCategorization/SmartCategorizationDraft.swift` - `Apptag/SmartCategorization/SmartCategory.swift` 内置资源: ```text build/TagLauncher.app/Contents/Resources/SmartStartUltimateDefaultCatalog.json build/TagLauncher.app/Contents/Resources/SmartStartUltimateDefaultCatalog.csv ``` 源资源: ```text Research/SmartStart/UltimateDefaultCatalog/SmartStart_UltimateDefaultCatalog.json Research/SmartStart/UltimateDefaultCatalog/SmartStart_UltimateDefaultCatalog.csv ``` 职责: - 加载本地分类目录。 - 根据扫描 App 生成 `SmartCategorizationDraft`。 - 决定自动应用还是只提示建议。 - 应用系统分类和默认备注。 - 备份和恢复 Smart Start 前状态。 - 语言切换时重本地化默认备注。 核心数据: ```swift SmartCategorizationDraft SmartAppCategorizationAssignment SmartUnassignedApp SmartCategoryID SmartStartState ``` ### 2.7 Quick Search 领域层 主要文件: - `Apptag/QuickSearch.swift` - `Apptag/ContentView.swift` 核心对象: ```swift struct QuickSearchDocument { let app: AppInfo let localizedNames: [String] let internalBundleNames: [String] let tagNames: [String] let note: String let bundleIdentifier: String let lastOpenedAt: Date? let openCount: Int } struct QuickSearchResult { let document: QuickSearchDocument let finalScore: Double let textScore: Double let bestFieldRank: Int let matchedTagName: String? let noteSnippet: String? } ``` 职责: - 从已标注 App 和 store 生成搜索文档。 - 预计算规范化字段、缩写和拉丁化候选。 - 执行多字段多 token 搜索。 - 排序结果。 - 空查询时生成快速建议。 ### 2.8 本地化资源层 主要文件: - `Apptag/L10n.swift` - `Apptag/Localization/*.json` 职责: - 启动时加载语言。 - 切换语言。 - 提供 `tr(key)`。 - 读取其他语言中的系统标签文案,用于旧数据迁移和系统标签重本地化。 支持语言: ```text ar, ar-Najdi, cs, da, de, en, es, fr, id, it, ja, ko, ms, nb, nl, nn, no, pl, pt-BR, ro, ru, sr-Cyrl, sv, th, tr, uk, vi, zh-Hans, zh-Hant ``` ## 3. 核心数据流 ### 3.1 App 启动流 ```mermaid sequenceDiagram participant App as TagLauncherApp participant Delegate as AppDelegate participant Defaults as AppDefaults participant L10n as L10n participant DB as TagDatabase participant Hotkey as Carbon Hotkey App->>Delegate: applicationDidFinishLaunching Delegate->>Defaults: register() Delegate->>L10n: setup() Delegate->>DB: seedDefaultTags() Delegate->>Delegate: setup menu bar / app menu Delegate->>Hotkey: register main and quick search hotkeys Delegate->>Delegate: install observers Delegate->>Delegate: setup launch at login ``` ### 3.2 主界面刷新流 ```mermaid sequenceDiagram participant UI as ContentView participant Scanner as AppIndexer participant Editor as TagEditor participant SS as SmartStartService participant Search as QuickSearchEngine participant Store as TagDatabase.Store UI->>Scanner: scan() Scanner-->>UI: raw AppInfo[] UI->>Editor: reconcileScannedApps(apps) Editor-->>UI: reconciled Store UI->>SS: runIfNeeded(apps, store) SS-->>UI: SmartStartRunResult UI->>Editor: annotate(apps, store) Editor-->>UI: annotated AppInfo[] UI->>Search: makeDocuments(apps, store) Search-->>UI: QuickSearchDocument[] UI->>UI: rebuildDisplayGroups() ``` ### 3.3 App 启动记录流 ```mermaid sequenceDiagram participant UI as ContentView / Quick Search participant System as NSWorkspace participant Editor as TagEditor participant Store as tags.json UI->>System: openApplication(app.path) System-->>UI: success UI->>Editor: recordLauncherOpen(path) Editor->>Store: openCount + 1, lastOpenedAt = now Editor->>Store: auto uncommon count >= 100 时移除 auto uncommon UI->>UI: close Quick Search / overlay ``` ### 3.4 标签变更流 ```mermaid sequenceDiagram participant UI as 编辑界面 / 拖拽 participant Editor as TagEditor participant DB as TagDatabase participant Store as tags.json UI->>Editor: append/remove/move/rename/delete/reorder/setColor Editor->>DB: load() DB-->>Editor: previousStore Editor->>Editor: mutate store Editor->>DB: saveUserCategorySchemeMutation(store, previous) DB->>DB: 必要时创建 previous scheme backup DB->>Store: save() UI->>UI: refreshApps() ``` ### 3.5 Smart Start 应用流 ```mermaid sequenceDiagram participant UI as ContentView / Settings participant SS as SmartStartService participant Catalog as SmartStart Catalog participant DB as TagDatabase UI->>SS: runIfNeeded 或 applySystemInitialScheme SS->>Catalog: loadRuntimeCatalog() SS->>SS: match by bundleIdentifier, fallback normalizedName SS->>DB: backup(previous store) SS->>DB: ensureSystemTag / assign appTags / seed notes SS->>DB: save smartStart and categoryScheme state SS-->>UI: summary and optional draft ``` ### 3.6 Quick Search 搜索流 ```mermaid sequenceDiagram participant UI as QuickSearchOverlay participant Engine as QuickSearchEngine participant Docs as QuickSearchDocument[] participant App as NSWorkspace UI->>Engine: search(query, documents) Engine->>Docs: match fields and rank Engine-->>UI: results UI->>UI: select first or preserve manual selection UI->>App: Enter / click launches selected app ``` ### 3.7 语言切换流 ```mermaid sequenceDiagram participant Settings as PreferencesView / Menu participant L10n as L10n participant DB as TagDatabase participant SS as SmartStartService participant UI as ContentView Settings->>L10n: switchTo(code) L10n->>DB: relocalizeSystemTagsForCurrentLanguage() L10n->>Settings: post appLanguageDidChange UI->>SS: relocalizeDefaultNotesForCurrentLanguage(apps) UI->>UI: refreshApps(forceLayoutRefresh) ``` ## 4. 持久化位置 ### 4.1 UserDefaults 主要键: | Key | 含义 | |---|---| | `appLanguage` | 用户选择的界面语言 | | `tagFontSize` | 标签字号 | | `iconSize` | 图标大小 | | `tagPosition` | 标签位置 | | `defaultGroupName` | 默认分组中性名称,逻辑上保持 `Other` | | `displayMode` | App 列表样式 | | `hideAppNames` | 是否隐藏 App 名称 | | `showDockIcon` | 是否显示 Dock 图标 | | `launchAtLogin` | 是否开机登录 | | `showUncommonAppBubbles` | 是否仅不常用 App 显示气泡 | | `mainHotkeyRegistrationState` | 主快捷键注册状态 | | `quickSearchHotkeyRegistrationState` | Quick Search 快捷键注册状态 | | `mainHotkeyRegistrationFailureCode` | 主快捷键失败码 | | `quickSearchHotkeyRegistrationFailureCode` | Quick Search 快捷键失败码 | ### 4.2 tags.json 保存用户核心业务数据: - 标签定义 - App 与标签关系 - 标签排序 - 不常用 App - App 备注 - App 启动历史 - 已知 App 路径 - 禁用的系统分类 - Smart Start 状态 - 分类方案状态 ### 4.3 Bundle Resources 打包进入 App 的资源: - 本地化 JSON - Smart Start 运行时 JSON - Smart Start CSV - App 图标 - 菜单栏 SVG 图标 ## 5. 关键架构不变量 | 编号 | 不变量 | |---|---| | INV-01 | 扫描出的 App 是事实层,用户分类和备注来自 store 标注。 | | INV-02 | App 用户数据以 path 为主要存储 key。 | | INV-03 | 系统标签必须有稳定 `SmartCategoryID`,显示名可以随语言变化。 | | INV-04 | “Mac 自带”是客观属性分组,不是用户普通标签。 | | INV-05 | “未分类”是无普通标签状态,不是必须写入 App 的标签。 | | INV-06 | 不常用是特殊 marker,不应混入普通 tag 语义。 | | INV-07 | Smart Start 只能基于本地目录运行,不依赖在线服务。 | | INV-08 | Quick Search 不改变 App 列表布局,是覆盖层中的第二启动入口。 | | INV-09 | 启动历史只在成功从 TagLauncher 打开 App 后写入。 | | INV-10 | 用户手写备注优先级高于系统默认备注。 | | INV-11 | 构建过程不应回写源码 `Info.plist`。 | ## 6. 当前已知架构边界 - 没有账号系统。 - 没有云同步。 - 没有远程搜索。 - 没有文件、联系人、浏览器历史搜索。 - 没有用户自定义快捷键的当前落地能力。 - 没有独立数据库,使用 JSON 文件作为本地 store。 - Smart Start notes 当前仍在单一运行时 JSON 中,尚未按语言拆分资源。