Files
FamilyBook_harmonyos/entry/src/main/ets/data/FbCalSettings.ets
T

161 lines
5.5 KiB
Plaintext
Raw Normal View History

/**
* 家书 FamilyBook · 日程设置(鸿蒙端)
*
* 存"日程模块自己的偏好"——它们是**这台设备上的人怎么看日历**,
* 与服务器无关、也不该同步给别人。
*
* 🔴 用户 2026-10-15:「我们家书的日程功能模块,包括它的界面设计和功能,
* 跟 SyncCalendar 做得一样,就差不多。……有几种不同的视图方式,
* 然后包括下面日程的显示啊什么之类的。」
* ⇒ 对齐 SyncCalendar 的设置项:
* · **默认视图**(月 / 周 / 列表)—— 打开日程页时先用哪个
* · **日程显示方式**(时间轴 / 列表)—— 同一天里日程怎么画
* · **新建日程落到哪本日历**(默认日历本)
* · **哪些日历本可见**(隐藏不想看的那几本)
*
* 🔴 为什么用 `preferences` 而不是本地库:都是**单个键值**,
* 不是多行记录(同一范式见 `FbTokenStore` 的说明)。
* ⚠️ 必须**同步读**(`get*()`):页面一渲染就要知道用哪个视图,
* 若只能 await,每个调用点都要 async、把简单逻辑搞碎。
* ⇒ 用"启动时预加载进内存 + 写时同时更新内存"(同 FbTokenStore)。
*/
import { preferences } from '@kit.ArkData';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { common } from '@kit.AbilityKit';
const DOMAIN: number = 0x0000;
const TAG: string = 'FbCalSettings';
/** preferences 实例名 */
const STORE_NAME: string = 'fb_calendar';
const K_VIEW: string = 'default_view'; // month | week | agenda
const K_STYLE: string = 'display_style'; // timeline | list
const K_BOOK: string = 'default_book_id'; // 新建日程默认落到哪本
const K_HIDDEN: string = 'hidden_books'; // 逗号分隔的日历本 id
/** 视图:月 / 周 / 列表(与 SyncCalendar 的 VIEW_ORDER 同一套) */
export type FbCalView = 'month' | 'week' | 'agenda';
/** 日程画法:时间轴 / 列表(与 SyncCalendar 的 displayStyle 同一套) */
export type FbCalStyle = 'timeline' | 'list';
class FbCalSettingsImpl {
private view: FbCalView = 'month';
private style: FbCalStyle = 'timeline';
private bookId: number = 0;
private hidden: string = '';
private store: preferences.Preferences | null = null;
private ready: boolean = false;
/** 预加载进内存(应用启动时调一次;幂等) */
async init(ctx: common.Context): Promise<void> {
if (this.ready) {
return;
}
try {
this.store = await preferences.getPreferences(ctx, STORE_NAME);
const v: preferences.ValueType = await this.store.get(K_VIEW, 'month');
const s: preferences.ValueType = await this.store.get(K_STYLE, 'timeline');
const b: preferences.ValueType = await this.store.get(K_BOOK, 0);
const h: preferences.ValueType = await this.store.get(K_HIDDEN, '');
this.view = (v === 'week' || v === 'agenda') ? v : 'month';
this.style = (s === 'list') ? 'list' : 'timeline';
this.bookId = typeof b === 'number' ? b : 0;
this.hidden = typeof h === 'string' ? h : '';
this.ready = true;
hilog.info(DOMAIN, TAG, '日程设置预加载完成:%{public}s / %{public}s', this.view, this.style);
} catch (err) {
// ⚠️ 读不到就用默认值,**不要**让启动挂掉
hilog.warn(DOMAIN, TAG, '日程设置预加载失败:%{public}s', JSON.stringify(err));
this.ready = true;
}
}
isReady(): boolean {
return this.ready;
}
// ---- 同步读 ----
getView(): FbCalView {
return this.view;
}
getStyle(): FbCalStyle {
return this.style;
}
getBookId(): number {
return this.bookId;
}
/** 被隐藏的日历本 id 列表 */
hiddenIds(): number[] {
const out: number[] = [];
if (this.hidden === '') {
return out;
}
for (const s of this.hidden.split(',')) {
const n: number = parseInt(s, 10);
if (!isNaN(n) && n > 0) {
out.push(n);
}
}
return out;
}
/** 某本日历是否可见(默认都可见) */
isVisible(id: number): boolean {
return this.hiddenIds().indexOf(id) < 0;
}
// ---- 异步写(同时更新内存) ----
async setView(v: FbCalView): Promise<void> {
this.view = v;
await this.put(K_VIEW, v);
}
async setStyle(s: FbCalStyle): Promise<void> {
this.style = s;
await this.put(K_STYLE, s);
}
async setBookId(id: number): Promise<void> {
this.bookId = id;
await this.put(K_BOOK, id);
}
/** 设置某本日历的可见性 */
async setVisible(id: number, visible: boolean): Promise<void> {
const ids: number[] = this.hiddenIds();
const at: number = ids.indexOf(id);
if (visible && at >= 0) {
ids.splice(at, 1);
} else if (!visible && at < 0) {
ids.push(id);
}
const parts: string[] = [];
for (const n of ids) {
parts.push(n.toString());
}
this.hidden = parts.join(',');
await this.put(K_HIDDEN, this.hidden);
}
private async put(key: string, val: preferences.ValueType): Promise<void> {
try {
if (this.store === null) {
hilog.warn(DOMAIN, TAG, '还没有 store,设置没能落盘(重启会丢)');
return;
}
await this.store.put(key, val);
// ⚠️ `put` 只写内存,**必须 `flush`** 才落盘(同 FbTokenStore 的坑)
await this.store.flush();
} catch (err) {
hilog.error(DOMAIN, TAG, '日程设置保存失败:%{public}s', JSON.stringify(err));
}
}
}
/** 全局单例 */
export const FB_CAL_SETTINGS: FbCalSettingsImpl = new FbCalSettingsImpl();