Commit Graph
6 Commits
Author SHA1 Message Date
laoyang 413900bbce feat(待办): 提醒 / 左滑删除 / 优先级标签地点 / 编辑热区 / 卡片刷新 (#38 #39 #40 #41 #42)
一次性完成待办模块的 5 项缺口。

## #38 待办提醒
`ReminderService` 原本只服务 `kind='event'`,待办完全不提醒。

- `EventDb.queryRemindableTodos`:查未完成待办,**额外要求 `completed=0`**
  (否则做完的待办到期还会弹)
- `refreshReminders` 合并日程 + 待办两路查询,文案按 kind 分支:
  待办是「将在 X 分钟后到期」/`该待办已到期`,日程仍为「开始」
- `IcsUtil.buildTodo` 写 VALARM;`rewriteTodoFields` 编辑时整段重建 VALARM
  (逐行改 TRIGGER 容易漏 ACTION/DESCRIPTION)
- 待办弹层加提醒芯片(不提醒 / 5 / 15 / 30 分钟 / 1 小时 / 1 天,多选)
- 三个写操作后调 `refreshReminders`,保证改完立刻重排

协议要点:VTODO 的 VALARM `TRIGGER` 相对 **DUE**(RFC 5545 §3.8.6.3),
所以 `TRIGGER:-PT5M` 就是"到期前 5 分钟",无需额外写 RELATED=END。

## #39 待办列表左滑删除
`swipeAction` 只能挂 ListItem,而原结构是 `Scroll + Column + ForEach`。

- 外层 Scroll → List,分组改用 `ListItemGroup`(保留"色点+本名+条数"分组头)
- 每个 ListItem 挂 `swipeAction({ end: ... })`,滑出红底「删除」
- 点击复用现有 `askDeleteTodo`(二次确认)→ `doDeleteTodo`(软删 + 服务器 DELETE)
- 未完成 / 已完成两个清单都支持

## #40 优先级 / 标签 / 地点
- 表加 `priority`(INTEGER) / `categories`(TEXT);`location` 本来就有
- PRIORITY 存 **iCal 原生值**(1 最高 … 9 最低,0 未设置),写回零转换
- ICS:`parseTodos` 读 PRIORITY/CATEGORIES,`buildTodo` 与 `rewriteTodoFields` 写
- 新增 `todoExtras()` 供新建与改写共用,避免两处生成结构不一致
- `rewriteTodoFields` 用 `priority=-1` 做"不改"哨兵(0 是合法语义:清空)
- 弹层加优先级芯片(高/中/低)、标签输入、地点输入

## #41 重复待办打勾推进
核查结论:**已实现且完整**。`toggleTodo` 已按 `recurRule !== ''` 分流到
`completeRecurringRound`,且该方法会保留"基准→DUE 偏移"、复位 STATUS 后推进。
本次未改逻辑,仅补了完成后刷新卡片与提醒。

## #42 编辑入口热区
内容区 `Column` 原来高度只到文字高度,行内上下留白点不到。
加 `.height('100%')` + `justifyContent(Center)` 撑满行高。
勾选圈仍是独立 onClick(ArkUI 不冒泡),点圈只切完成态、不进编辑。

## 顺带修复(共性遗漏)
`toggleTodo` / `saveTodoEdit` / `saveNewTodo` / `doDeleteTodo` 四处
改完库只刷 `this.todos`,**都没推送桌面卡片** —— 卡片停在旧数据。
四处统一补 `CardDataService.pushToAllForms`。

## 验证
- 编译 `BUILD SUCCESSFUL`
- 真机 dump 确认弹层新 UI 全部渲染:优先级(高/中/低)、
  提醒(不提醒/提前5分钟/15/30/1小时/1天)、标签、地点
- ICS 生成逻辑用等价实现校验:PRIORITY、CATEGORIES(逗号转义 \,
  LOCATION、VALARM(TRIGGER:-PT5M 位于 VTODO 内、结构闭合)全部通过

## 未验证
端到端「填字段→创建→查服务器 ICS」未跑通:`uitest inputText` 按坐标输入时
多个输入框会累积到同一个(把标签/地点内容追加进了标题框),是自动化限制而非代码问题。
需人工建一条带各字段的待办,确认服务器端 ICS 与上述结构一致。
提醒能否实际弹出依赖代理提醒权限(此前有配额为 0 的记录)。
2026-11-04 08:23:42 +08:00
laoyang d890a2b053 0.0.8 提醒修复(补):已镜像的本由系统日历全权负责,且判据改为"镜像真实存在"
用户要求:如果用户已把自己的日历同步到系统日历里,那么本应用就**完全不再提醒**了
—— 因为那必然是重复提醒。

采纳。同时修正上一版实现的一个**会漏提醒的弱点**:

问题:上一版按"**用户勾选了要镜像的本**"来跳过 App 提醒。但"勾选"只是**意图**,
本可能还没真正写进系统日历(如刚勾选未点「立即执行镜像」、系统日历里还没有对应账户)
→ 按意图跳过会导致**两边都不提醒(漏提醒)**。

改法:判据改为「**镜像账户真实存在**」,新增 `SystemCalendarMirror.mirroredCalKeys(context)`:
  1. 镜像开关未开 / 无系统日历权限 → 直接返回**空集**(不跳过任何本);
  2. 读系统日历全部账户,取出 name 以 `synccalendar.mirror.` 开头者的 **bookId**;
  3. 与 `listBooks()` 的 `bookId → calKey` 对照 → 只有**账户真实存在**的本才计入。
  安全阀:任何异常 → 空集 → 不跳过 → **宁可多提醒,绝不漏提醒**。

`ReminderService.mirroredKeys()` 改为委托给它(保留 30 秒缓存与 `invalidateMirrorCache()`);
`refreshReminders` / `tickReminders` 两处仍照旧跳过这些本(跳过即"App 完全不再提醒")。

交互完整性(不变):镜像开关开启/关闭、勾选本变化、权限被回收 四处
均 `invalidateMirrorCache()` + 立即 `refreshReminders()`,
确保**关闭镜像后这些本立刻恢复由 App 提醒**。

验证:编译通过(BUILD SUCCESSFUL);手机未连接 → 未装机。
2026-10-14 14:28:42 +08:00
laoyang 19cfe3cf34 0.0.8 修复:系统日历重复提醒 / 已过日程仍提醒
用户反馈:① 日程已开始/已过去,系统日历仍提醒;② 同一提前量(如提前 15 分钟)
提醒两次;③ 怀疑"打开 App 后又写一次系统日历"就多提醒一次。
诊断见《系统日历重复提醒-根因诊断.md》。用户怀疑正确,确为两个 bug。

修复一:消除双通道重复提醒(提醒两次)
- 根因:镜像到系统日历后,**系统日历自己会提醒**(条目 reminderTime),
  而 ReminderService 为**所有**本地日程排代理提醒、**完全不区分**该本是否已镜像
  → 同一条日程、同一提前量被两个应用各弹一次。
- 改法:新增 `ReminderService.mirroredKeys()` —— 取"已镜像到系统日历"的日历本 calKey
  集合(仅在「镜像开关已开 + 有系统日历权限 + 有选中本」时才非空),
  `refreshReminders` 与 `tickReminders` **两处都跳过**这些本,改由系统日历提醒。
- ⚠️ 保守设计:判定失败一律返回**空集**(不跳过任何本)→ 宁可多提醒,绝不漏提醒。
- ⚠️ 交互完整性:镜像开关变化时必须**立即失效缓存并重排提醒**(否则会漏提醒):
  · 开启镜像 → 交回系统日历负责;· 关闭镜像 → **立刻恢复 App 提醒**;
  · 勾选本变化、权限被系统回收 → 同样失效缓存并重排。
  新增 `ReminderService.invalidateMirrorCache()`。

修复二:消除"已过去的日程仍提醒"
- 根因:镜像窗口含**过去 12 个月**(windowStart 往前推 12 月),过去的日程也在系统日历里;
  而 `updateEvent` 是**整条覆写**(带 reminderTime),系统在覆写时会**重新计算提醒时刻**,
  时刻已过就**立刻补发**一条 → 表现为"过去了还提醒"。
- 改法:`toSystemEvent` 写入时只带**提醒时刻尚未到**的提醒(新增 `futureReminders()`)。
  已过期提醒已无意义 → 不写,从根上消除覆写补发。
  ⭐ 全天日程按系统口径以**当天 09:00** 为提醒基准(新增 `reminderBaseMs()`)。
- 刻意**不收缩镜像窗口**:保住历史日程在系统日历中的可见性,只去掉提醒。

修复三:让"改了提醒时间"能同步到系统日历(反向 bug)
- 根因:`diffOf` 只比较 title/isAllDay/start/end/description/location,
  **不比较 reminderTime** → 用户改了提醒时间被判"无差异",永不触发 updateEvent
  → 系统日历侧提醒一直不更新。
- 改法:`diffOf` 纳入 `reminderTime` 比较,用规范化 key(排序去重)避免因顺序/重复误判,
  且与修复二同口径(只比"会被写入的"提醒),不会导致每轮都重写。

验证:
- 编译通过(BUILD SUCCESSFUL)。
- 离线用例全部通过:
  · 修复二:已过去/提醒刚过/昨天全天 → 不写提醒;未来日程/明天全天 → 保留;
  · 修复三:提醒改了/新增 → 触发覆写;相同集合(顺序不同、含重复)→ 不覆写。
- 手机未连接 → 未装机(待用户插线测试)。
2026-10-14 14:00:58 +08:00
laoyang 6899a5074b 修改了通知相关的功能,能够正常通知了。 2026-09-13 23:35:52 +08:00
laoyang d9c212785d 新增了提醒静音功能,可以在设置中关闭某个日历本的提醒。 2026-09-13 21:56:51 +08:00
laoyang bbb3ec5334 首次提交:SyncCalendar 项目 2026-09-13 15:50:37 +08:00