From d890a2b053c48c1111681bdaaaf3b0b5fd8f71ae Mon Sep 17 00:00:00 2001 From: laoyang Date: Wed, 14 Oct 2026 14:28:42 +0800 Subject: [PATCH] =?UTF-8?q?0.0.8=20=E6=8F=90=E9=86=92=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=EF=BC=88=E8=A1=A5=EF=BC=89=EF=BC=9A=E5=B7=B2=E9=95=9C=E5=83=8F?= =?UTF-8?q?=E7=9A=84=E6=9C=AC=E7=94=B1=E7=B3=BB=E7=BB=9F=E6=97=A5=E5=8E=86?= =?UTF-8?q?=E5=85=A8=E6=9D=83=E8=B4=9F=E8=B4=A3=EF=BC=8C=E4=B8=94=E5=88=A4?= =?UTF-8?q?=E6=8D=AE=E6=94=B9=E4=B8=BA"=E9=95=9C=E5=83=8F=E7=9C=9F?= =?UTF-8?q?=E5=AE=9E=E5=AD=98=E5=9C=A8"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户要求:如果用户已把自己的日历同步到系统日历里,那么本应用就**完全不再提醒**了 —— 因为那必然是重复提醒。 采纳。同时修正上一版实现的一个**会漏提醒的弱点**: 问题:上一版按"**用户勾选了要镜像的本**"来跳过 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);手机未连接 → 未装机。 --- entry/src/main/ets/common/ReminderService.ets | 27 +++------- .../main/ets/common/SystemCalendarMirror.ets | 50 +++++++++++++++++++ 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/entry/src/main/ets/common/ReminderService.ets b/entry/src/main/ets/common/ReminderService.ets index 5557c0d..9dcf3bd 100644 --- a/entry/src/main/ets/common/ReminderService.ets +++ b/entry/src/main/ets/common/ReminderService.ets @@ -12,7 +12,7 @@ import { BusinessError } from '@kit.BasicServicesKit'; import { EventDb, LocalEvent } from './EventDb'; import { AppSettings } from './AppSettings'; import { AccountStore } from './AccountStore'; -import { SystemCalendarMirror, BookRef } from './SystemCalendarMirror'; +import { SystemCalendarMirror } from './SystemCalendarMirror'; import { LogUtil } from './LogUtil'; export class ReminderService { @@ -34,32 +34,21 @@ export class ReminderService { /** * ⭐⭐ 取"已镜像到系统日历"的日历本 calKey 集合(0.0.8 修复双通道重复提醒)。 * - * 背景:镜像到系统日历后,**系统日历自己会提醒**(条目的 reminderTime)。 - * 若 App 再为同一个本排代理提醒 → 同一条日程提醒两次。 - * 因此这里返回"该由系统日历负责提醒"的本,App 侧跳过它们。 + * 镜像到系统日历后,**系统日历自己会提醒**(条目的 reminderTime); + * 若 App 再为同一个本排代理提醒 → 同一条日程提醒两次。 + * 因此这里返回"该由系统日历负责提醒"的本,App 侧**完全不再提醒**它们。 * + * ⚠️ 判据是"**镜像账户真实存在**"(`SystemCalendarMirror.mirroredCalKeys`), + * 而不是"用户勾选了要镜像"—— 后者只是意图,本可能还没被真正写进系统日历; + * 按意图跳过会导致"两边都不提醒"(漏提醒)。 * ⚠️ 返回空集 = 不跳过任何本(保守:宁可多提醒,不可漏提醒)。 - * 仅在「镜像开关已开 + 有系统日历权限 + 有选中本」时才真正跳过。 */ private static async mirroredKeys(context: common.Context): Promise> { if (Date.now() - ReminderService.mirroredLoadedAt < 30000 && ReminderService.mirroredCalKeys.size > 0) { return ReminderService.mirroredCalKeys; } - const out: Set = new Set(); - try { - const on: boolean = await AppSettings.getMirrorEnabled(context); - if (on && await SystemCalendarMirror.hasPermission()) { - const refs: BookRef[] = await SystemCalendarMirror.selectedBookRefs(context); - for (const r of refs) { - if (r.calKey !== '') { - out.add(r.calKey); - } - } - } - } catch (err) { - // 判定失败 → 返回空集(不跳过,避免漏提醒) - } + const out: Set = await SystemCalendarMirror.mirroredCalKeys(context); ReminderService.mirroredCalKeys = out; ReminderService.mirroredLoadedAt = Date.now(); return out; diff --git a/entry/src/main/ets/common/SystemCalendarMirror.ets b/entry/src/main/ets/common/SystemCalendarMirror.ets index 2b50ff4..0458727 100644 --- a/entry/src/main/ets/common/SystemCalendarMirror.ets +++ b/entry/src/main/ets/common/SystemCalendarMirror.ets @@ -239,6 +239,56 @@ export class SystemCalendarMirror { return name.startsWith(SystemCalendarMirror.ACCOUNT_PREFIX); } + /** + * ⭐⭐ 取"**确实已经镜像到系统日历**"的日历本 calKey 集合(按镜像账户的**真实存在性**判定)。 + * + * 与"用户勾选了要镜像的本"不同 —— 后者只是**意图**,本可能还没被真正写进系统日历 + * (如刚勾选但没点「立即执行镜像」、或根本没开镜像开关)。 + * 若按"意图"跳过 App 提醒,而系统日历里其实还没有 → **两边都不提醒 = 漏提醒**。 + * 故这里只认**镜像账户真实存在**这一条。 + * + * ⚠️ 返回**空集**=不跳过任何本(读不到账户时保守处理,宁可多提醒)。 + * ⚠️ 未开启镜像开关时直接返回空集(省一次系统查询)。 + */ + static async mirroredCalKeys(context: common.Context): Promise> { + const out: Set = new Set(); + try { + if (!await AppSettings.getMirrorEnabled(context)) { + return out; // 未开启镜像 → 没有任何本由系统日历负责 + } + if (!await SystemCalendarMirror.hasPermission()) { + return out; // 无权限 → 系统日历里不可能有我们的条目 + } + const cm: calendarManager.CalendarManager = calendarManager.getCalendarManager(context); + const all: calendarManager.Calendar[] = []; + const cals: calendarManager.Calendar[] = await cm.getAllCalendars(); + for (const c of cals) { + all.push(c); + } + // 存在镜像账户 → 其 bookId 对应的本由系统日历负责 + const presentBookIds: Set = new Set(); + for (const c of all) { + const name: string = c.getAccount().name; + if (name.startsWith(SystemCalendarMirror.ACCOUNT_PREFIX)) { + presentBookIds.add(name.substring(SystemCalendarMirror.ACCOUNT_PREFIX.length)); + } + } + if (presentBookIds.size === 0) { + return out; + } + // bookId → calKey(从当前账号配置解析) + const refs: BookRef[] = await SystemCalendarMirror.listBooks(context); + for (const r of refs) { + if (presentBookIds.has(r.bookId) && r.calKey !== '') { + out.add(r.calKey); + } + } + } catch (err) { + LogUtil.write(`判定"已镜像本"失败(按未镜像处理): ${(err as BusinessError).message}`); + } + return out; + } + /* ==================== 账户身份判定(0.0.8) ==================== */ /**