# 2026-06-26 Pro底层门禁 ## 用户目标 只在以下 4 个文件内完成“免费版 + Pro”首期的底层能力接入,不处理设置页 UI: - `src/Apptag/ProEntitlement.swift` - `src/Apptag/DataLayer.swift` - `src/Apptag/ApptagApp.swift` - `src/Apptag/AppGridTheme.swift` 目标包括: 1. 修复 `ProEntitlement.swift` 当前编译问题。 2. 补底层错误类型和辅助方法,供上层门禁使用。 3. 在启动链路接入 `ProEntitlementCenter.shared.start()`。 4. 在主题枚举中补免费 / 高级主题判断。 5. 给导入 / 导出 / 应用排序 / 应用备注写入补硬门禁。 ## 已完成事项 ### 1. `ProEntitlement.swift` - 修复 `createDirectory` 缺少 `attributes:` 参数导致的编译错误。 - 新增 `ProEntitlementError`: - `featureLocked(ProFeature)` - `noteQuotaExceeded(ProNoteQuotaStatus)` - 新增 `ProEntitlementPolicy` 辅助方法: - `lockedErrorIfNeeded(for:)` - `requireUnlocked(_:)` - `requireNoteSave(note:for:in:)` - 调整 `noteSaveDecision(note:for:in:)`: - 免费用户第 6 个新的手动备注返回 `blocked`。 - 允许编辑已有手动备注。 - 允许删除备注。 - `allow` 时返回的是“保存后”的额度状态,便于上层只改一个 callsite 使用。 - 补齐当前文件自身的编译兼容: - `start()` 里对 `loadProductIfNeeded()` 改为 `try? await` - `themePreviewTask` 去掉无意义 `await` - `Transaction.currentEntitlements(for:)` 改为兼容 macOS 14 的 `Transaction.currentEntitlements` + `productID` 过滤 ### 2. `DataLayer.swift` - `TagDatabase.exportTo(_:)` 增加 `layoutExport` 硬门禁,未解锁直接 `throw`。 - `TagDatabase.importFrom(_:)` 增加 `layoutImport` 硬门禁,未解锁直接 `throw`。 - `TagEditor.reorderApps(...)` 增加 `persistentAppSorting` 硬门禁,免费态直接不落盘返回。 - `TagEditor.setAppNote(...)` 改为: - `@discardableResult` - 返回 `ProNoteSaveDecision` - 先做额度判断,再决定是否写入 - 免费第 6 个新备注不落盘 - 现有手动备注可继续改 - 删除备注照常允许 ### 3. `ApptagApp.swift` - 在 `applicationDidFinishLaunching` 中接入 `ProEntitlementCenter.shared.start()`。 ### 4. `AppGridTheme.swift` - 新增: - `static freeThemes` - `static premiumThemes` - `isFreeTheme` - `requiresPro` - `isPremiumTheme` ## 关键决策 - 本轮只做底层门禁和启动接入,不扩展到设置页 UI。 - `reorderApps` 维持现有签名,免费态只禁止持久化,不主动改上层预览行为。 - `setAppNote` 通过返回 `ProNoteSaveDecision` 让上层只需调整一个 callsite 即可接门禁反馈。 ## 文件变更 - 修改:`src/Apptag/ProEntitlement.swift` - 修改:`src/Apptag/DataLayer.swift` - 修改:`src/Apptag/ApptagApp.swift` - 修改:`src/Apptag/AppGridTheme.swift` ## QA / 构建结论 - 使用 `bash ./build.sh` 完成整包编译验证。 - 构建成功,产物: - `src/build/TagLauncher.app` ## 未决问题 - 上层 UI / 设置页尚未接这些门禁返回值与错误类型: - `TagEditor.setAppNote(...)` 的 `ProNoteSaveDecision` - `TagDatabase.exportTo/importFrom(...)` 的 `ProEntitlementError` - 主题点击 / Pro 状态展示仍待主线程继续接 ## 后续建议 - 主线程下一步优先接: 1. 设置页 Theme / Data 的 Pro 交互 2. `ContentView.commitBubbleNote()` 对 `ProNoteSaveDecision` 的处理 3. 免费排序预览与 Pro 提示 UI