From 29898d5dff19403ef3de4fe11ceeba8a5c206ef8 Mon Sep 17 00:00:00 2001 From: laoyang Date: Wed, 21 Oct 2026 07:11:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E6=94=B9=E4=BA=86?= =?UTF-8?q?=E6=97=A5=E5=8E=86=E6=9C=AC=E9=A2=9C=E8=89=B2=EF=BC=8C=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E6=97=A5=E5=8E=86=E9=95=9C=E5=83=8F=E9=A2=9C=E8=89=B2?= =?UTF-8?q?=E4=B8=8D=E8=B7=9F=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:SyncEngine.refreshCalendarColors 每轮同步都 PROPFIND 服务器把新 calendar-color 写进**内存**里的账号对象,但从不 saveAll(唯一落盘点是 removeDeadBooks 的"服务器删本"分支)。而镜像 listBooks 是重新 AccountStore.loadAll 从磁盘读 → 拿到的永远是旧颜色 → ensureCalendar setConfig(旧色) → 系统日历颜色永远不变。 用户在「账号设置」页看到的是**当场 PROPFIND** 的新颜色,所以表现为 "设置页颜色对、系统日历颜色错"。 修法: 1) refreshCalendarColors 返回 boolean(颜色/写权限是否有实际变化, 含数组长度补齐);syncAccountInner 在有变化时立刻 loadAll+saveAll 落盘(同 removeDeadBooks 的既有模式),镜像同轮即可读到新色; 2) SystemCalendarMirror.ensureCalendar 的 setConfig 失败由静默改为 写日志(新建/复用两处),"颜色不变"从此可排查。 验证:assembleHap BUILD SUCCESSFUL;已 install -r 到真机。 --- entry/src/main/ets/common/SyncEngine.ets | 37 +++++++++++++++++-- .../main/ets/common/SystemCalendarMirror.ets | 7 +++- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/entry/src/main/ets/common/SyncEngine.ets b/entry/src/main/ets/common/SyncEngine.ets index 9e3f0fc..6862d61 100644 --- a/entry/src/main/ets/common/SyncEngine.ets +++ b/entry/src/main/ets/common/SyncEngine.ets @@ -122,7 +122,23 @@ export class SyncEngine { private static async syncAccountInner(context: common.Context, acc: DavAccount): Promise { const auth: string = DavClient.authHeader(acc.username, acc.password); // 0) 刷新服务器端日历本颜色(每次同步都校正) - await SyncEngine.refreshCalendarColors(acc, auth); + // ⭐ 有变化就立刻落盘:镜像 listBooks 从磁盘重新 loadAll, + // 不落盘的话镜像 setConfig 的永远是旧颜色(系统日历颜色不跟服务器变)。 + const colorChanged: boolean = await SyncEngine.refreshCalendarColors(acc, auth); + if (colorChanged) { + try { + const all: DavAccount[] = await AccountStore.loadAll(context); + const idx: number = all.findIndex((a: DavAccount): boolean => a.id === acc.id); + if (idx >= 0) { + all[idx] = acc; + await AccountStore.saveAll(context, all); + LogUtil.write('日历本颜色/权限有变化,已落盘(镜像将使用新颜色)'); + } + } catch (err) { + const e = err as BusinessError; + LogUtil.write(`颜色/权限落盘失败(不影响同步): ${e.message}`); + } + } // 1) 推送该账号日历本下的本地修改 await SyncEngine.pushDirtyForAccount(context, acc, auth); // 2) 拉取远端变更:REPORT 仅取 etag;新增/变化的资源用 GET 补拉完整 ICS。 @@ -363,8 +379,13 @@ export class SyncEngine { /** * 刷新服务器端日历本颜色:PROPFIND getcolor → 按集合路径匹配更新 acc.calendarColors * 失败静默(颜色不影响数据正确性) + * ⭐ 返回**是否有实际变化**(颜色或写权限)——调用方据此落盘。 + * (0.0.9 修复:此前变化只留在内存、从不 saveAll ⇒ 镜像 listBooks 从磁盘读到的 + * 永远是旧颜色 ⇒ setConfig 旧色 ⇒ 系统日历颜色永远不跟服务器变; + * 而账号设置页是当场 PROPFIND 的,所以"页面上是新色、系统日历是旧色"。) */ - static async refreshCalendarColors(acc: DavAccount, auth: string): Promise { + static async refreshCalendarColors(acc: DavAccount, auth: string): Promise { + let changed: boolean = false; let entries: DavColorEntry[] = []; try { entries = await DavClient.propfindColors(acc.serverUrl, auth); @@ -382,9 +403,11 @@ export class SyncEngine { if (found !== undefined && found.color !== '') { while (acc.calendarColors.length <= i) { acc.calendarColors.push(''); + changed = true; // 长度补齐也视作变化(旧账号可能还没这一位) } if (acc.calendarColors[i] !== found.color) { LogUtil.write(`日历本[${i}] 颜色更新:${acc.calendarColors[i] === '' ? '(空)' : acc.calendarColors[i]} → ${found.color}`); + changed = true; } acc.calendarColors[i] = found.color; } else if (found === undefined) { @@ -396,17 +419,23 @@ export class SyncEngine { acc.calendarWritable.push('1'); } const calName: string = i < acc.calendarNames.length ? acc.calendarNames[i] : `日历本${i}`; + let writable: string; if (found !== undefined && found.privilegeKnown) { // 服务器声明了权限:直接采用 - acc.calendarWritable[i] = found.writable ? '1' : '0'; + writable = found.writable ? '1' : '0'; LogUtil.write(`日历本[${i}]「${calName}」写权限(privilege):${found.writable ? '可写' : '只读'}`); } else { // 服务器未声明权限(如部分 Synology 配置)或 PROPFIND 未匹配到该本:真实写探测 const w: boolean = await DavClient.probeWritable(target, auth); - acc.calendarWritable[i] = w ? '1' : '0'; + writable = w ? '1' : '0'; LogUtil.write(`日历本[${i}]「${calName}」写权限(探测):${w ? '可写' : '只读'}`); } + if (acc.calendarWritable[i] !== writable) { + changed = true; + } + acc.calendarWritable[i] = writable; } + return changed; } /** Map 追加一行(没有该 key 就建数组) */ diff --git a/entry/src/main/ets/common/SystemCalendarMirror.ets b/entry/src/main/ets/common/SystemCalendarMirror.ets index 4142f57..e676879 100644 --- a/entry/src/main/ets/common/SystemCalendarMirror.ets +++ b/entry/src/main/ets/common/SystemCalendarMirror.ets @@ -1146,7 +1146,9 @@ export class SystemCalendarMirror { try { await cal.setConfig({ enableReminder: true, color: ref.color }); } catch (err) { - // 设色失败不影响镜像本身 + // 设色失败不影响镜像本身,但要留痕(否则"颜色不变"无从排查) + const e = err as BusinessError; + LogUtil.write(`镜像账户设色失败 ${accountName}: ${e.message}`); } return cal; } @@ -1159,7 +1161,8 @@ export class SystemCalendarMirror { try { await cal.setConfig({ enableReminder: true, color: ref.color }); } catch (err) { - // 同上 + const e = err as BusinessError; + LogUtil.write(`镜像账户设色失败(新建) ${accountName}: ${e.message}`); } return cal; }