feat: 添加自定义提醒功能并优化项目配置 - 添加 CustomReminder 模型支持自由文案周期性提醒功能 - 实现自定义提醒的 UI 界面,包括新建、编辑和列表展示 - 集成本地通知服务支持自定义提醒的时间触发 - 更新项目配置文件添加应用显示名称和加密声明 - 修正 iOS 部署目标版本从 26.0 到 17.0 - 修复 FileDownloader 中的线程安全问题 - 优化 ModelManifest 和 Localization 的并发安全性 - 扩展本地化字符串支持多语言提醒相关文本 - 调整项目支持平台范围仅保留 iphoneos 和 iphonesimulator ```
118 lines
4.8 KiB
Markdown
118 lines
4.8 KiB
Markdown
# 自由周期提醒(CustomReminder)— 设计文档
|
|
|
|
**日期**:2026-05-30(W2)
|
|
**作者**:link2026 + Claude
|
|
**关联卖点**:#4 隐私三件套之外的实用粘性功能(本地通知,无云)
|
|
**优先级**:用户明确要求(注:§10.6「用药提醒」原列默认不做,本轮经讨论确认要做,按最小可用实现)
|
|
|
|
---
|
|
|
|
## 1. 一句话定位
|
|
|
|
让用户新建**自由文案的周期性本地提醒**(如「每天 20:00 跑步 5 公里」「每天 12:30 吃 2 片护肝片」),与现有「指标记录提醒」(去录某项指标)并存但相互独立。完全本地 `UserNotifications`,不引云。
|
|
|
|
---
|
|
|
|
## 2. 已确认的设计决策
|
|
|
|
| 决策点 | 选择 |
|
|
|---|---|
|
|
| 模型 | 新建独立 `CustomReminder` @Model,不动现有 `MetricReminder` |
|
|
| 周期粒度 | 每天 / 每周选几天(复用 weekday 约定,覆盖示例)。不做间隔/按月/一次性 |
|
|
| 入口 | 新建 → 开启一个提醒 → `RemindersListView`(提醒中心),顶部「+ 新建提醒」打开编辑 sheet |
|
|
| 列表范围 | 自由提醒 + 指标提醒**合展**(上次删了「我的」入口,指标提醒也只能从这里管) |
|
|
| 量词(5公里/2片) | 写在自由文本 `title` 里,不单设字段 |
|
|
| 多语言 | 所有固定文案走 `String(appLoc:)`,新增中文 key 补 en/ja/ko 到 `Localizable.xcstrings` |
|
|
|
|
---
|
|
|
|
## 3. 数据模型
|
|
|
|
`Models/Models.swift` 新增:
|
|
|
|
```swift
|
|
@Model final class CustomReminder {
|
|
@Attribute(.unique) var id: UUID
|
|
var title: String // 用户文案:"跑步5公里"
|
|
var note: String // 可选备注 → 通知正文
|
|
var hour: Int // 0...23
|
|
var minute: Int // 0...59
|
|
var weekdays: [Int] // 1=日…7=六,全 7 = 每天(复用 MetricReminder 约定)
|
|
var enabled: Bool
|
|
var createdAt: Date
|
|
var updatedAt: Date
|
|
// computed: isEveryDay / frequencyLabel / timeLabel(与 MetricReminder 同款,复用同一批本地化 key)
|
|
}
|
|
```
|
|
|
|
Schema 注册:`App/KangkangApp.swift` 加 `CustomReminder.self`(additive 变更,无需迁移)。
|
|
|
|
---
|
|
|
|
## 4. 通知调度(ReminderService 泛化)
|
|
|
|
抽出私有共享核心,两种提醒复用:
|
|
|
|
```swift
|
|
private static func schedule(idBase:title:body:hour:minute:weekdays:thread:) async
|
|
static func sync(_ custom: CustomReminder) async // 新增
|
|
static func cancel(customId: UUID) // 新增
|
|
static func sync(_ metric: MetricReminder) async // 现有,内部改走共享核心,行为不变
|
|
```
|
|
|
|
- custom 通知:`title` = 提醒标题,`body` = 备注(空则用默认文案「到点啦,记得完成」)。
|
|
- id 前缀 `kangkang.custom.<uuid>.w<weekday>`(与指标的 `kangkang.reminder.<metricId>.w<weekday>` 不冲突)。
|
|
- 保存时调 `requestAuthorization()`;被拒则提示去系统设置。
|
|
|
|
---
|
|
|
|
## 5. UI
|
|
|
|
### 5.1 `CustomReminderEditSheet`(新增)
|
|
创建 / 编辑共用。字段:
|
|
- 标题 TextField(占位:「做点什么?例:跑步5公里 / 吃2片护肝片」),空标题禁用保存。
|
|
- 备注 TextField(可选)。
|
|
- 时间 DatePicker(.hourAndMinute)。
|
|
- 周几选择(复用 RemindersListView 的 chip 行)。
|
|
- 保存 / 取消;编辑态多一个「删除提醒」。
|
|
保存:写 SwiftData → 请求通知权限 → `ReminderService.sync(custom)`。
|
|
|
|
### 5.2 `RemindersListView`(改造为提醒中心)
|
|
- 顶部「+ 新建提醒」按钮 → 打开 `CustomReminderEditSheet`(create)。
|
|
- 「我的提醒」区:`@Query CustomReminder`,每行点开走编辑 sheet,行上 Toggle 控 enabled。
|
|
- 「指标记录提醒」区:`@Query MetricReminder`,保持现有内联编辑不变(仅非空时显示区头)。
|
|
- 表头副文案、空状态文案更新。
|
|
|
|
---
|
|
|
|
## 6. 多语言
|
|
|
|
新增中文 key + en/ja/ko 译文写入 `Localizable.xcstrings`(源语言 zh-Hans,key 即中文)。脚本只增不改,已存在的 key 跳过。复用已有 key:时间/保存/取消/删除提醒/每天/已关闭/周几名等。用户输入的标题/备注是数据,不翻译。
|
|
|
|
---
|
|
|
|
## 7. 文件清单
|
|
|
|
| 文件 | 改动 |
|
|
|---|---|
|
|
| `Models/Models.swift` | +`CustomReminder` |
|
|
| `App/KangkangApp.swift` | schema +`CustomReminder.self` |
|
|
| `Services/ReminderService.swift` | 泛化共享核心 + custom sync/cancel |
|
|
| `Features/Me/CustomReminderEditSheet.swift` | **新增** 编辑表单 |
|
|
| `Features/Me/RemindersListView.swift` | 提醒中心:新建按钮 + 合展两类 |
|
|
| `Localizable.xcstrings` | 新增文案四语言 |
|
|
|
|
---
|
|
|
|
## 8. 红线对齐
|
|
|
|
- 不引云、不碰密码学(纯本地通知)✅
|
|
- 不重构 Tab/RecordSheet 骨架 ✅
|
|
- §10.6「用药提醒默认不做」→ 已讨论确认,最小实现(无贪睡/铃声/间隔)✅
|
|
|
|
---
|
|
|
|
## 9. 验收(真机)
|
|
|
|
① 新建「每天 20:00 跑步 5 公里」→ 列表出现 → 到点收到本地通知(标题=跑步5公里);② 改时间/周几即时重排;③ 关闭 Toggle 取消通知;④ 删除清除 pending;⑤ 切换语言后固定文案随之变化(用户输入文案不变);⑥ 指标提醒仍在同一列表可管。
|