edit | blame | history | raw

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