diff --git a/entry/src/main/ets/common/AppSettings.ets b/entry/src/main/ets/common/AppSettings.ets index ef9bdee..f054da4 100644 --- a/entry/src/main/ets/common/AppSettings.ets +++ b/entry/src/main/ets/common/AppSettings.ets @@ -13,6 +13,7 @@ export class AppSettings { private static readonly KEY_SYS_MODE: string = 'sys_cal_mode'; // 'display' | 'backup' private static readonly KEY_BACKUP_KEY: string = 'sys_backup_cal_key'; // 备份目标 DAV 日历本 private static readonly KEY_MANUAL_READONLY: string = 'manual_readonly_keys'; // 手动标记只读的 calKey + private static readonly KEY_MUTED_REMINDER: string = 'muted_reminder_keys'; // 提醒静音的 calKey private static readonly KEY_FULL_REFETCH: string = 'full_refetch_done'; // 一次性全量重拉已完成 /** @@ -86,6 +87,33 @@ export class AppSettings { } } + /** + * 提醒静音的日历本 calKey 列表。 + * 适用于别人分享的日历本:静音后其中所有日程都不再发布系统提醒(日程本身仍正常显示)。 + */ + static async getMutedReminderKeys(context: common.Context): Promise { + try { + const store: preferences.Preferences = + await preferences.getPreferences(context, AppSettings.STORE); + const raw: string = await store.get(AppSettings.KEY_MUTED_REMINDER, '') as string; + return raw === '' ? [] : raw.split(';'); + } catch (err) { + return []; + } + } + + static async setMutedReminderKeys(context: common.Context, keys: string[]): Promise { + try { + const store: preferences.Preferences = + await preferences.getPreferences(context, AppSettings.STORE); + await store.put(AppSettings.KEY_MUTED_REMINDER, keys.join(';')); + await store.flush(); + } catch (err) { + const e = err as BusinessError; + console.error(`保存提醒静音标记失败: ${e.message}`); + } + } + /** 系统日历模式:display = 仅混合显示;backup = 本地系统日程备份到选定 CalDAV 日历本 */ static async getSysCalMode(context: common.Context): Promise { try { diff --git a/entry/src/main/ets/common/ReminderService.ets b/entry/src/main/ets/common/ReminderService.ets index 6b957ff..1126ca7 100644 --- a/entry/src/main/ets/common/ReminderService.ets +++ b/entry/src/main/ets/common/ReminderService.ets @@ -5,6 +5,7 @@ import { reminderAgentManager } from '@kit.BackgroundTasksKit'; import { common } from '@kit.AbilityKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { EventDb, LocalEvent } from './EventDb'; +import { AppSettings } from './AppSettings'; import { LogUtil } from './LogUtil'; export class ReminderService { @@ -18,8 +19,13 @@ export class ReminderService { const now: number = Date.now(); const rows: LocalEvent[] = await EventDb.queryRemindable(context, now, now + ReminderService.WINDOW); + // 提醒静音的日历本(如别人分享的本):其中所有日程都不再提醒 + const muted: string[] = await AppSettings.getMutedReminderKeys(context); let published: number = 0; for (const e of rows) { + if (muted.includes(e.calKey)) { + continue; + } if (published >= ReminderService.MAX_REMINDERS) { break; } @@ -50,7 +56,7 @@ export class ReminderService { await reminderAgentManager.publishReminder(request); published++; } - LogUtil.write(`提醒刷新完成:发布 ${published} 个提醒(窗口 7 天)`); + LogUtil.write(`提醒刷新完成:发布 ${published} 个提醒(窗口 7 天,静音日历本 ${muted.length} 个)`); } catch (err) { const e = err as BusinessError; LogUtil.write(`提醒刷新失败: ${e.code} - ${e.message}`); diff --git a/entry/src/main/ets/pages/SettingsPage.ets b/entry/src/main/ets/pages/SettingsPage.ets index 7796a9e..f8c2e9b 100644 --- a/entry/src/main/ets/pages/SettingsPage.ets +++ b/entry/src/main/ets/pages/SettingsPage.ets @@ -5,6 +5,7 @@ import { common } from '@kit.AbilityKit'; import { AppSettings } from '../common/AppSettings'; import { BackgroundSyncService } from '../common/BackgroundSyncService'; import { AccountStore, DavAccount } from '../common/AccountStore'; +import { ReminderService } from '../common/ReminderService'; import { LogUtil } from '../common/LogUtil'; const INTERVAL_OPTIONS: number[] = [1, 5, 15, 30, 60]; @@ -27,6 +28,7 @@ struct SettingsPage { @State backupTargets: BackupTarget[] = []; @State allBooks: BackupTarget[] = []; // 全部 DAV 日历本(只读标记管理用) @State manualKeys: string[] = []; // 手动标记只读的 calKey + @State mutedKeys: string[] = []; // 提醒静音的 calKey private context?: common.Context; aboutToAppear(): void { @@ -51,6 +53,9 @@ struct SettingsPage { AppSettings.getManualReadonlyKeys(ctx).then((v: string[]): void => { this.manualKeys = v; }); + AppSettings.getMutedReminderKeys(ctx).then((v: string[]): void => { + this.mutedKeys = v; + }); this.loadBackupSettings(); this.loadAllBooks(); } @@ -106,6 +111,33 @@ struct SettingsPage { return b.serverWritable ? '可写' : '只读'; } + /** 切换日历本提醒静音:静音后该本所有日程不再发布系统提醒 */ + private async toggleMuteBook(b: BackupTarget): Promise { + if (this.context === undefined) { + return; + } + const list: string[] = [...this.mutedKeys]; + const idx: number = list.indexOf(b.calKey); + if (idx >= 0) { + list.splice(idx, 1); + } else { + list.push(b.calKey); + } + this.mutedKeys = list; + await AppSettings.setMutedReminderKeys(this.context, list); + // 立即重建提醒(全量取消后按新静音规则重发),无需等下次同步 + try { + await ReminderService.refreshReminders(this.context as common.UIAbilityContext); + } catch (err) { + // 重建失败不影响设置保存,下次同步时会再刷新 + } + this.getUIContext().getPromptAction().showToast({ + message: idx >= 0 + ? '已恢复提醒' + : '已静音:该日历本的所有日程不再提醒' + }); + } + /** 加载备份目标候选(可写 DAV 日历本)+ 当前选择 */ private async loadBackupSettings(): Promise { if (this.context === undefined) { @@ -379,6 +411,59 @@ struct SettingsPage { .backgroundColor($r('app.color.card_bg')) .border({ width: 1, color: $r('app.color.shadow_color') }) + // 日历本提醒静音(如别人分享的日历本,静音后其中所有日程不再提醒) + Column({ space: 8 }) { + Row({ space: 10 }) { + Column({ space: 2 }) { + Text('日历本提醒静音') + .fontSize(15) + .fontWeight(FontWeight.Medium) + .fontColor($r('app.color.text_primary')) + Text('点击日历本切换静音:静音后该日历本的所有日程都不再提醒(日程仍正常显示)') + .fontSize(12) + .fontColor($r('app.color.text_secondary')) + } + .alignItems(HorizontalAlign.Start) + .layoutWeight(1) + } + .width('100%') + if (this.allBooks.length === 0) { + Text('暂无 CalDAV 日历本') + .fontSize(12) + .fontColor($r('app.color.text_hint')) + .width('100%') + } + ForEach(this.allBooks, (b: BackupTarget) => { + Row({ space: 8 }) { + Text(b.label) + .fontSize(13) + .fontColor($r('app.color.text_primary')) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .layoutWeight(1) + Text(this.mutedKeys.includes(b.calKey) ? '已静音' : '提醒中') + .fontSize(11) + .fontColor(this.mutedKeys.includes(b.calKey) + ? $r('app.color.error') : $r('app.color.success')) + .padding({ left: 8, right: 8, top: 3, bottom: 3 }) + .borderRadius(10) + .backgroundColor(this.mutedKeys.includes(b.calKey) + ? $r('app.color.error_bg') : $r('app.color.success_bg')) + } + .width('100%') + .padding({ top: 6, bottom: 6 }) + .onClick(() => { + this.toggleMuteBook(b); + }) + }, (b: BackupTarget) => `mute_${b.calKey}_${this.mutedKeys.includes(b.calKey) ? 1 : 0}`) + } + .alignItems(HorizontalAlign.Start) + .width('100%') + .padding(14) + .borderRadius(12) + .backgroundColor($r('app.color.card_bg')) + .border({ width: 1, color: $r('app.color.shadow_color') }) + // 数据修复:手动触发一次性全量重拉(重建提醒等本地残缺字段) Row({ space: 10 }) { Column({ space: 2 }) {