v90 新增观影卡与任务卡(2x2/2x4):卡片按类型分流推数据,key 带 version 前缀

This commit is contained in:
2026-10-24 23:44:46 +08:00
parent 7ebe18b2d1
commit 6711197a94
9 changed files with 1196 additions and 42 deletions
@@ -20,29 +20,43 @@
* 系统定时刷新**不能**把用户翻走的日期拽回今天。
*/
import { FormExtensionAbility, formBindingData, formProvider } from '@kit.FormKit';
import { FormExtensionAbility, formBindingData, formProvider, formInfo } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { FbCardData, fbCardBuild } from '../data/FbCardData';
import { fbCardDataByKind } from '../data/FbCardMediaData';
import { FB_CARD_FORMS } from '../data/FbCardForms';
import { FB_BG_SYNC } from '../common/FbBackgroundSync';
const DOMAIN: number = 0x0000;
const TAG: string = 'FbForm';
/** 卡片名 → 数据类型(v90 起不止日程卡)。
* ⚠️ 名字来自 `form_config.json` 的 `name` 字段(Want 里的 `form_name`),
* 两边改名必须同步 —— 改一边的表现是"新卡永远拿日程数据",编译不报错。 */
function kindOfFormName(name: string): string {
if (name.indexOf('FbMovieCard') === 0) {
return 'movies';
}
if (name.indexOf('FbTaskCard') === 0) {
return 'tasks';
}
return 'calendar';
}
export default class FbFormAbility extends FormExtensionAbility {
/**
* 重新算一遍并推给指定卡片。
*
* ⚠️ 四块卡(2×2 / 2×4 / 4×4 / 6×4)共用这份数据:它们只是**排版不同**,
* 数字与条目必须是同一个 —— 多算一遍既慢又可能口径不一致。
* ⚠️ v90 起按类型分流:日程卡吃 `dayOffset`(翻页);
* 观影/任务卡没有"看哪一天"的概念,`dayOffset` 固定传 0。
*/
private push(formId: string, dayOffset: number): void {
fbCardBuild(this.context, dayOffset).then((data: FbCardData): void => {
private push(formId: string, kind: string, dayOffset: number): void {
fbCardDataByKind(this.context, kind, dayOffset).then((data: Object): void => {
const binding: formBindingData.FormBindingData = formBindingData.createFormBindingData(data);
formProvider.updateForm(formId, binding).then((): void => {
hilog.info(DOMAIN, TAG, '卡片 %{public}s 已更新(偏移 %{public}d)', formId, data.dayOffset);
hilog.info(DOMAIN, TAG, '卡片 %{public}s(%{public}s) 已更新(偏移 %{public}d)',
formId, kind, dayOffset);
}).catch((err: BusinessError): void => {
// 卡片可能已经被用户删了 —— 打一条日志就够,不要重试
hilog.warn(DOMAIN, TAG, '卡片 %{public}s 更新失败:%{public}s', formId, err.message);
@@ -61,21 +75,31 @@ export default class FbFormAbility extends FormExtensionAbility {
return typeof raw === 'string' ? raw : '';
}
/** 从 Want 里取卡片名(`ohos.extra.param.key.form_name`,即 form_config 的 name) */
private formNameOf(want: Want): string {
if (want.parameters === undefined) {
return '';
}
const raw: Object | undefined = want.parameters[formInfo.FormParam.NAME_KEY];
return typeof raw === 'string' ? raw : '';
}
onAddForm(want: Want): formBindingData.FormBindingData {
const formId: string = this.formIdOf(want);
hilog.info(DOMAIN, TAG, '添加卡片:%{public}s', formId);
const kind: string = kindOfFormName(this.formNameOf(want));
hilog.info(DOMAIN, TAG, '添加卡片:%{public}s(%{public}s)', formId, kind);
if (formId !== '') {
// 异步:登记 + 补真实数据(不 await:见文件头约束 ①)
FB_CARD_FORMS.register(this.context, formId).then((): void => {
this.push(formId, 0);
FB_CARD_FORMS.register(this.context, formId, kind).then((): void => {
this.push(formId, kind, 0);
}).catch((err: BusinessError): void => {
hilog.warn(DOMAIN, TAG, '卡片登记失败:%{public}s', err.message);
});
}
// 先给一份"正在取"的壳 —— 卡片上会显示空态,而不是白屏
const shell: FbCardData = new FbCardData();
shell.state = 'loading';
shell.hint = '正在取数据…';
const shell: Record<string, string> = {};
shell['state'] = 'loading';
shell['hint'] = '正在取数据…';
return formBindingData.createFormBindingData(shell);
}
@@ -100,11 +124,21 @@ export default class FbFormAbility extends FormExtensionAbility {
⚠️ 节流:系统刷新可能漂移或重入,`runThrottledByCard` 内部用时间戳挡了一道,
并且**先写时间戳再跑**,避免卡片进程与主进程并发拉同一批数据。 */
// ⚠️ 必须按**这张卡自己的偏移**重建,否则定时刷新会把用户翻走的日期拽回今天
FB_CARD_FORMS.getOffset(this.context, formId).then((off: number): void => {
this.push(formId, off);
// 🔴 v90:偏移量只对日程卡有意义;观影/任务卡按类型直接推。
FB_CARD_FORMS.kindOf(this.context, formId).then((kind: string): void => {
if (kind !== 'calendar') {
this.push(formId, kind, 0);
return;
}
FB_CARD_FORMS.getOffset(this.context, formId).then((off: number): void => {
this.push(formId, kind, off);
}).catch((err: BusinessError): void => {
hilog.warn(DOMAIN, TAG, '读卡片偏移失败:%{public}s', err.message);
this.push(formId, kind, 0);
});
}).catch((err: BusinessError): void => {
hilog.warn(DOMAIN, TAG, '读卡片偏移失败:%{public}s', err.message);
this.push(formId, 0);
hilog.warn(DOMAIN, TAG, '读卡片类型失败(按日程处理):%{public}s', err.message);
this.push(formId, 'calendar', 0);
});
/* ⚠️ 这一句必须放在**推送之后**(原因见上面的 ①:卡片刷新只有几秒的窗口,
不能被 12 个模块的同步挤掉)。两条都是"发起即返回",不会互相阻塞。 */
@@ -116,26 +150,35 @@ export default class FbFormAbility extends FormExtensionAbility {
onFormEvent(formId: string, message: string): void {
/* 卡片上的按钮都走 `action: 'message'`,`message` 是 JSON 字符串。
⚠️ 不解析 JSON:不同版本系统给的形态可能是 `{params:{...}}` 或直接 `{...}`,
子串匹配更稳(与 SyncCalendar 同一个取舍)。 */
子串匹配更稳(与 SyncCalendar 同一个取舍)。
⚠️ v90:只有日程卡有 ‹ / › / 今 三个按钮;观影/任务卡不发 message 事件,
收到也直接忽略(不把 message 撞进偏移量里)。 */
hilog.info(DOMAIN, TAG, '卡片事件:%{public}s %{public}s', formId, message);
FB_CARD_FORMS.getOffset(this.context, formId).then((cur: number): void => {
let next: number = cur;
if (message.indexOf('prev') >= 0) {
next = cur - 1;
} else if (message.indexOf('next') >= 0) {
next = cur + 1;
} else if (message.indexOf('today') >= 0) {
next = 0;
FB_CARD_FORMS.kindOf(this.context, formId).then((kind: string): void => {
if (kind !== 'calendar') {
return;
}
FB_CARD_FORMS.setOffset(this.context, formId, next).then((off: number): void => {
this.push(formId, off);
FB_CARD_FORMS.getOffset(this.context, formId).then((cur: number): void => {
let next: number = cur;
if (message.indexOf('prev') >= 0) {
next = cur - 1;
} else if (message.indexOf('next') >= 0) {
next = cur + 1;
} else if (message.indexOf('today') >= 0) {
next = 0;
}
FB_CARD_FORMS.setOffset(this.context, formId, next).then((off: number): void => {
this.push(formId, kind, off);
}).catch((err: BusinessError): void => {
hilog.warn(DOMAIN, TAG, '卡片翻页失败:%{public}s', err.message);
this.push(formId, kind, cur);
});
}).catch((err: BusinessError): void => {
hilog.warn(DOMAIN, TAG, '卡片翻页失败:%{public}s', err.message);
this.push(formId, cur);
hilog.warn(DOMAIN, TAG, '读卡片偏移失败(按今天处理):%{public}s', err.message);
this.push(formId, kind, 0);
});
}).catch((err: BusinessError): void => {
hilog.warn(DOMAIN, TAG, '读卡片偏移失败(按今天处理):%{public}s', err.message);
this.push(formId, 0);
hilog.warn(DOMAIN, TAG, '读卡片类型失败:%{public}s', err.message);
});
}