1.增加了重力感应,也就是横屏响应式布局。
2.修改了沉浸式布局。 3.修改了添加日程和编辑日程页面,增加了重复、提醒等功能。 4.修改了权限问题,如果日历本是只读,则有删除线做标识。同时,对于只读的日程,点击后将不再进入编辑页面,而是展示详情。 5.系统日历的处理。给用户两个选择,第一个选择就是只显示系统日历。第二种选择,用户可以选择一个caldav账户中的某一个日历本,把系统日历中的日程,包括日历日程和应用创建的日程,都读取出来,然后加入到这个日历本下,最后同步到caldav的服务器上,这样的好处是,手机丢失了,或者换了手机品牌型号,手机上的日程仍然在自己的caldav服务器上有一个备份。当然,系统日历中的caldav日历,就不会再读取了。
This commit is contained in:
@@ -1,19 +1,32 @@
|
||||
// entry/src/main/ets/pages/SettingsPage.ets
|
||||
// 设置页:系统日历混合显示开关 + 自动同步间隔
|
||||
// 设置页:系统日历模式(仅显示/备份到 CalDAV)+ 混合显示开关 + 自动同步间隔 + 后台同步
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { common } from '@kit.AbilityKit';
|
||||
import { AppSettings } from '../common/AppSettings';
|
||||
import { BackgroundSyncService } from '../common/BackgroundSyncService';
|
||||
import { AccountStore, DavAccount } from '../common/AccountStore';
|
||||
import { LogUtil } from '../common/LogUtil';
|
||||
|
||||
const INTERVAL_OPTIONS: number[] = [1, 5, 15, 30, 60];
|
||||
|
||||
/** 日历本选项(备份目标 / 只读标记共用) */
|
||||
class BackupTarget {
|
||||
calKey: string = '';
|
||||
label: string = '';
|
||||
serverWritable: boolean = true; // 服务器探测结果
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct SettingsPage {
|
||||
@State showSystem: boolean = true;
|
||||
@State intervalMinutes: number = 1;
|
||||
@State backgroundSync: boolean = false;
|
||||
@State sysMode: string = 'display'; // display | backup
|
||||
@State backupKey: string = '';
|
||||
@State backupTargets: BackupTarget[] = [];
|
||||
@State allBooks: BackupTarget[] = []; // 全部 DAV 日历本(只读标记管理用)
|
||||
@State manualKeys: string[] = []; // 手动标记只读的 calKey
|
||||
private context?: common.Context;
|
||||
|
||||
aboutToAppear(): void {
|
||||
@@ -32,6 +45,128 @@ struct SettingsPage {
|
||||
AppSettings.getBackgroundSync(ctx).then((v: boolean): void => {
|
||||
this.backgroundSync = v;
|
||||
});
|
||||
AppSettings.getSysCalMode(ctx).then((v: string): void => {
|
||||
this.sysMode = v;
|
||||
});
|
||||
AppSettings.getManualReadonlyKeys(ctx).then((v: string[]): void => {
|
||||
this.manualKeys = v;
|
||||
});
|
||||
this.loadBackupSettings();
|
||||
this.loadAllBooks();
|
||||
}
|
||||
|
||||
/** 加载全部 DAV 日历本(含探测到的写权限,只读标记管理用) */
|
||||
private async loadAllBooks(): Promise<void> {
|
||||
if (this.context === undefined) {
|
||||
return;
|
||||
}
|
||||
const accounts: DavAccount[] = await AccountStore.loadAll(this.context);
|
||||
const books: BackupTarget[] = [];
|
||||
for (const acc of accounts) {
|
||||
if (acc.type !== 'caldav') {
|
||||
continue;
|
||||
}
|
||||
for (let i = 0; i < acc.calendarHrefs.length; i++) {
|
||||
const b = new BackupTarget();
|
||||
b.calKey = `${acc.id}_${i}`;
|
||||
const bookName: string = i < acc.calendarNames.length ? acc.calendarNames[i] : `日历本 ${i + 1}`;
|
||||
b.label = `${acc.name} · ${bookName}`;
|
||||
b.serverWritable = acc.calendarWritable.length > i ? acc.calendarWritable[i] !== '0' : true;
|
||||
books.push(b);
|
||||
}
|
||||
}
|
||||
this.allBooks = books;
|
||||
}
|
||||
|
||||
/** 手动标记/取消只读 */
|
||||
private async toggleManualBook(b: BackupTarget): Promise<void> {
|
||||
if (this.context === undefined) {
|
||||
return;
|
||||
}
|
||||
const list: string[] = [...this.manualKeys];
|
||||
const idx: number = list.indexOf(b.calKey);
|
||||
if (idx >= 0) {
|
||||
list.splice(idx, 1);
|
||||
} else {
|
||||
list.push(b.calKey);
|
||||
}
|
||||
this.manualKeys = list;
|
||||
await AppSettings.setManualReadonlyKeys(this.context, list);
|
||||
await this.loadBackupSettings(); // 备份目标候选同步排除
|
||||
this.getUIContext().getPromptAction().showToast({
|
||||
message: idx >= 0 ? '已恢复为可写,返回首页生效' : '已标记为只读,返回首页生效'
|
||||
});
|
||||
}
|
||||
|
||||
/** 日历本当前只读状态文案 */
|
||||
private bookStateLabel(b: BackupTarget): string {
|
||||
if (this.manualKeys.includes(b.calKey)) {
|
||||
return '只读(手动)';
|
||||
}
|
||||
return b.serverWritable ? '可写' : '只读';
|
||||
}
|
||||
|
||||
/** 加载备份目标候选(可写 DAV 日历本)+ 当前选择 */
|
||||
private async loadBackupSettings(): Promise<void> {
|
||||
if (this.context === undefined) {
|
||||
return;
|
||||
}
|
||||
const accounts: DavAccount[] = await AccountStore.loadAll(this.context);
|
||||
const targets: BackupTarget[] = [];
|
||||
for (const acc of accounts) {
|
||||
if (acc.type !== 'caldav') {
|
||||
continue;
|
||||
}
|
||||
for (let i = 0; i < acc.calendarHrefs.length; i++) {
|
||||
const writable: boolean = acc.calendarWritable.length > i
|
||||
? acc.calendarWritable[i] !== '0' : true;
|
||||
if (!writable) {
|
||||
continue;
|
||||
}
|
||||
const t = new BackupTarget();
|
||||
t.calKey = `${acc.id}_${i}`;
|
||||
const bookName: string = i < acc.calendarNames.length ? acc.calendarNames[i] : `日历本 ${i + 1}`;
|
||||
t.label = `${acc.name} · ${bookName}`;
|
||||
t.serverWritable = writable;
|
||||
targets.push(t);
|
||||
}
|
||||
}
|
||||
// 手动标记只读的本不可作为备份目标
|
||||
const manual: string[] = await AppSettings.getManualReadonlyKeys(this.context);
|
||||
this.backupTargets = targets.filter((t: BackupTarget): boolean => !manual.includes(t.calKey));
|
||||
this.backupTargets = targets;
|
||||
const saved: string = await AppSettings.getBackupCalKey(this.context);
|
||||
this.backupKey = targets.some((t: BackupTarget): boolean => t.calKey === saved) ? saved : '';
|
||||
}
|
||||
|
||||
private async saveSysMode(mode: string): Promise<void> {
|
||||
if (this.context === undefined) {
|
||||
return;
|
||||
}
|
||||
this.sysMode = mode;
|
||||
await AppSettings.setSysCalMode(this.context, mode);
|
||||
if (mode === 'backup' && this.backupKey === '') {
|
||||
// 自动选中第一个可写日历本
|
||||
if (this.backupTargets.length > 0) {
|
||||
this.backupKey = this.backupTargets[0].calKey;
|
||||
await AppSettings.setBackupCalKey(this.context, this.backupKey);
|
||||
}
|
||||
}
|
||||
this.getUIContext().getPromptAction().showToast({
|
||||
message: mode === 'backup'
|
||||
? '已开启备份:下次同步时把系统本地日程导入所选日历本'
|
||||
: '已切换为仅显示:不再把系统日程备份到 CalDAV'
|
||||
});
|
||||
}
|
||||
|
||||
private async saveBackupTarget(calKey: string): Promise<void> {
|
||||
if (this.context === undefined) {
|
||||
return;
|
||||
}
|
||||
this.backupKey = calKey;
|
||||
await AppSettings.setBackupCalKey(this.context, calKey);
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: '备份目标已更新,下次同步生效' });
|
||||
}
|
||||
|
||||
private async saveShowSystem(value: boolean): Promise<void> {
|
||||
@@ -96,7 +231,125 @@ struct SettingsPage {
|
||||
|
||||
Scroll() {
|
||||
Column({ space: 12 }) {
|
||||
// 系统日历混合显示
|
||||
// 系统日历模式:仅显示 / 备份到 CalDAV
|
||||
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%')
|
||||
Select([{ value: '仅显示(不做备份)' }, { value: '备份到 CalDAV 日历本' }] as SelectOption[])
|
||||
.selected(this.sysMode === 'backup' ? 1 : 0)
|
||||
.value(this.sysMode === 'backup' ? '备份到 CalDAV 日历本' : '仅显示(不做备份)')
|
||||
.fontColor($r('app.color.text_primary'))
|
||||
.font({ size: 14 })
|
||||
.optionFont({ size: 14 })
|
||||
.selectedOptionFont({ size: 14 })
|
||||
.width('100%')
|
||||
.onSelect((index: number) => {
|
||||
const mode: string = index === 1 ? 'backup' : 'display';
|
||||
if (mode !== this.sysMode) {
|
||||
this.saveSysMode(mode);
|
||||
}
|
||||
})
|
||||
if (this.sysMode === 'backup') {
|
||||
Text(this.backupTargets.length > 0
|
||||
? '备份目标(可写日历本):导入后随同步上传服务器,换机/丢失也有备份'
|
||||
: '没有可写的 CalDAV 日历本,请先添加账号或检查日历本权限')
|
||||
.fontSize(12)
|
||||
.fontColor(this.backupTargets.length > 0
|
||||
? $r('app.color.text_secondary') : $r('app.color.error'))
|
||||
.width('100%')
|
||||
if (this.backupTargets.length > 0) {
|
||||
Select(this.backupTargets.map((t: BackupTarget): SelectOption => {
|
||||
return { value: t.label } as SelectOption;
|
||||
}) as SelectOption[])
|
||||
.selected(this.backupTargets.findIndex((t: BackupTarget): boolean => t.calKey === this.backupKey))
|
||||
.value(this.backupTargets.find((t: BackupTarget): boolean => t.calKey === this.backupKey)?.label
|
||||
?? '请选择日历本')
|
||||
.fontColor($r('app.color.text_primary'))
|
||||
.font({ size: 14 })
|
||||
.optionFont({ size: 14 })
|
||||
.selectedOptionFont({ size: 14 })
|
||||
.width('100%')
|
||||
.onSelect((index: number) => {
|
||||
if (index >= 0 && index < this.backupTargets.length) {
|
||||
this.saveBackupTarget(this.backupTargets[index].calKey);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.width('100%')
|
||||
.padding(14)
|
||||
.borderRadius(12)
|
||||
.backgroundColor($r('app.color.card_bg'))
|
||||
.border({ width: 1, color: $r('app.color.shadow_color') })
|
||||
|
||||
// 日历本只读标记(部分服务器不在 CalDAV 层拒绝写入,自动探测无法区分时手动标记)
|
||||
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.bookStateLabel(b))
|
||||
.fontSize(11)
|
||||
.fontColor(this.bookStateLabel(b) === '可写'
|
||||
? $r('app.color.success') : $r('app.color.error'))
|
||||
.padding({ left: 8, right: 8, top: 3, bottom: 3 })
|
||||
.borderRadius(10)
|
||||
.backgroundColor(this.bookStateLabel(b) === '可写'
|
||||
? $r('app.color.success_bg') : $r('app.color.error_bg'))
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ top: 6, bottom: 6 })
|
||||
.onClick(() => {
|
||||
this.toggleManualBook(b);
|
||||
})
|
||||
}, (b: BackupTarget) => `${b.calKey}_${this.manualKeys.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 }) {
|
||||
Text('混合显示系统日历')
|
||||
|
||||
Reference in New Issue
Block a user