新增了提醒静音功能,可以在设置中关闭某个日历本的提醒。

This commit is contained in:
2026-09-13 21:56:51 +08:00
parent 0fef40c7f3
commit d9c212785d
3 changed files with 120 additions and 1 deletions
+28
View File
@@ -13,6 +13,7 @@ export class AppSettings {
private static readonly KEY_SYS_MODE: string = 'sys_cal_mode'; // 'display' | 'backup' 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_BACKUP_KEY: string = 'sys_backup_cal_key'; // 备份目标 DAV 日历本
private static readonly KEY_MANUAL_READONLY: string = 'manual_readonly_keys'; // 手动标记只读的 calKey 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'; // 一次性全量重拉已完成 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<string[]> {
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<void> {
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 日历本 */ /** 系统日历模式:display = 仅混合显示;backup = 本地系统日程备份到选定 CalDAV 日历本 */
static async getSysCalMode(context: common.Context): Promise<string> { static async getSysCalMode(context: common.Context): Promise<string> {
try { try {
@@ -5,6 +5,7 @@ import { reminderAgentManager } from '@kit.BackgroundTasksKit';
import { common } from '@kit.AbilityKit'; import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit'; import { BusinessError } from '@kit.BasicServicesKit';
import { EventDb, LocalEvent } from './EventDb'; import { EventDb, LocalEvent } from './EventDb';
import { AppSettings } from './AppSettings';
import { LogUtil } from './LogUtil'; import { LogUtil } from './LogUtil';
export class ReminderService { export class ReminderService {
@@ -18,8 +19,13 @@ export class ReminderService {
const now: number = Date.now(); const now: number = Date.now();
const rows: LocalEvent[] = const rows: LocalEvent[] =
await EventDb.queryRemindable(context, now, now + ReminderService.WINDOW); await EventDb.queryRemindable(context, now, now + ReminderService.WINDOW);
// 提醒静音的日历本(如别人分享的本):其中所有日程都不再提醒
const muted: string[] = await AppSettings.getMutedReminderKeys(context);
let published: number = 0; let published: number = 0;
for (const e of rows) { for (const e of rows) {
if (muted.includes(e.calKey)) {
continue;
}
if (published >= ReminderService.MAX_REMINDERS) { if (published >= ReminderService.MAX_REMINDERS) {
break; break;
} }
@@ -50,7 +56,7 @@ export class ReminderService {
await reminderAgentManager.publishReminder(request); await reminderAgentManager.publishReminder(request);
published++; published++;
} }
LogUtil.write(`提醒刷新完成:发布 ${published} 个提醒(窗口 7 天)`); LogUtil.write(`提醒刷新完成:发布 ${published} 个提醒(窗口 7 天,静音日历本 ${muted.length} 个`);
} catch (err) { } catch (err) {
const e = err as BusinessError; const e = err as BusinessError;
LogUtil.write(`提醒刷新失败: ${e.code} - ${e.message}`); LogUtil.write(`提醒刷新失败: ${e.code} - ${e.message}`);
+85
View File
@@ -5,6 +5,7 @@ import { common } from '@kit.AbilityKit';
import { AppSettings } from '../common/AppSettings'; import { AppSettings } from '../common/AppSettings';
import { BackgroundSyncService } from '../common/BackgroundSyncService'; import { BackgroundSyncService } from '../common/BackgroundSyncService';
import { AccountStore, DavAccount } from '../common/AccountStore'; import { AccountStore, DavAccount } from '../common/AccountStore';
import { ReminderService } from '../common/ReminderService';
import { LogUtil } from '../common/LogUtil'; import { LogUtil } from '../common/LogUtil';
const INTERVAL_OPTIONS: number[] = [1, 5, 15, 30, 60]; const INTERVAL_OPTIONS: number[] = [1, 5, 15, 30, 60];
@@ -27,6 +28,7 @@ struct SettingsPage {
@State backupTargets: BackupTarget[] = []; @State backupTargets: BackupTarget[] = [];
@State allBooks: BackupTarget[] = []; // 全部 DAV 日历本(只读标记管理用) @State allBooks: BackupTarget[] = []; // 全部 DAV 日历本(只读标记管理用)
@State manualKeys: string[] = []; // 手动标记只读的 calKey @State manualKeys: string[] = []; // 手动标记只读的 calKey
@State mutedKeys: string[] = []; // 提醒静音的 calKey
private context?: common.Context; private context?: common.Context;
aboutToAppear(): void { aboutToAppear(): void {
@@ -51,6 +53,9 @@ struct SettingsPage {
AppSettings.getManualReadonlyKeys(ctx).then((v: string[]): void => { AppSettings.getManualReadonlyKeys(ctx).then((v: string[]): void => {
this.manualKeys = v; this.manualKeys = v;
}); });
AppSettings.getMutedReminderKeys(ctx).then((v: string[]): void => {
this.mutedKeys = v;
});
this.loadBackupSettings(); this.loadBackupSettings();
this.loadAllBooks(); this.loadAllBooks();
} }
@@ -106,6 +111,33 @@ struct SettingsPage {
return b.serverWritable ? '可写' : '只读'; return b.serverWritable ? '可写' : '只读';
} }
/** 切换日历本提醒静音:静音后该本所有日程不再发布系统提醒 */
private async toggleMuteBook(b: BackupTarget): Promise<void> {
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 日历本)+ 当前选择 */ /** 加载备份目标候选(可写 DAV 日历本)+ 当前选择 */
private async loadBackupSettings(): Promise<void> { private async loadBackupSettings(): Promise<void> {
if (this.context === undefined) { if (this.context === undefined) {
@@ -379,6 +411,59 @@ struct SettingsPage {
.backgroundColor($r('app.color.card_bg')) .backgroundColor($r('app.color.card_bg'))
.border({ width: 1, color: $r('app.color.shadow_color') }) .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 }) { Row({ space: 10 }) {
Column({ space: 2 }) { Column({ space: 2 }) {