EntryFormAbility.ets 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
  2. import { Configuration, Want } from '@kit.AbilityKit';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. import { hilog } from '@kit.PerformanceAnalysisKit';
  5. import { WidgetDataManager } from '../common/widget/WidgetDataManager';
  6. import { PlayerControlService } from '../common/widget/PlayerControlService';
  7. import { WidgetCommand, WidgetControlParams, WidgetData, WidgetSize } from '../common/widget/WidgetTypes';
  8. import { FormLayoutManager } from '../common/widget/FormLayoutManager';
  9. import { WidgetSizeAdapter, SizeChangeListener } from '../common/widget/WidgetSizeAdapter';
  10. import { WidgetConfigManager, UserPreferences } from '../common/widget/WidgetConfigManager';
  11. import { ThemeSyncService, ThemeChangeListener, ThemeChangeEvent, ThemeInfo } from '../common/widget/ThemeSyncService';
  12. import {
  13. UserPreferencesService,
  14. PreferencesChangeListener,
  15. PreferencesChangeEvent
  16. } from '../common/widget/UserPreferencesService';
  17. import { ObjectUtils } from '../common/widget/ObjectUtils';
  18. import {
  19. PLAY_PAUSE_EVENT,
  20. NEXT_SONG_EVENT,
  21. PREV_SONG_EVENT,
  22. SEEK_TO_EVENT,
  23. OPEN_APP_EVENT,
  24. OPEN_PLAYER_EVENT,
  25. LONG_PRESS_MENU_EVENT,
  26. WIDGET_SETTINGS_EVENT,
  27. WIDGET_DELETE_EVENT,
  28. WIDGET_CONFIG_PAGE_EVENT,
  29. PAGE_MAIN,
  30. PAGE_PLAYER
  31. } from '../common/widget/WidgetEventConstants';
  32. const TAG = 'Heanup';
  33. /**
  34. * 卡片设置参数接口
  35. */
  36. interface WidgetSettingsParams extends Record<string, Object> {
  37. formId: string;
  38. currentSize: string;
  39. currentConfig: string;
  40. }
  41. /**
  42. * 卡片配置参数接口
  43. */
  44. interface WidgetConfigParams extends Record<string, Object> {
  45. formId: string;
  46. configType: string;
  47. configValue: string;
  48. }
  49. /**
  50. * 桌面播放器卡片扩展能力
  51. * 负责处理卡片的生命周期管理和用户交互事件
  52. * 支持多尺寸适配和UI重构
  53. */
  54. export default class EntryFormAbility extends FormExtensionAbility
  55. implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
  56. private widgetDataManager: WidgetDataManager | null = null;
  57. private playerControlService: PlayerControlService = new PlayerControlService();
  58. private layoutManager: FormLayoutManager = FormLayoutManager.getInstance();
  59. private sizeAdapter: WidgetSizeAdapter = WidgetSizeAdapter.getInstance();
  60. private configManager: WidgetConfigManager = WidgetConfigManager.getInstance();
  61. private themeSyncService: ThemeSyncService = ThemeSyncService.getInstance();
  62. private userPreferencesService: UserPreferencesService = UserPreferencesService.getInstance();
  63. private formSizeMap: Map<string, WidgetSize> = new Map();
  64. /**
  65. * 初始化服务
  66. */
  67. private initializeServices(): void {
  68. if (!this.widgetDataManager) {
  69. this.widgetDataManager = new WidgetDataManager();
  70. hilog.info(0x0000, TAG, 'WidgetDataManager initialized');
  71. }
  72. }
  73. /**
  74. * 卡片创建时调用
  75. */
  76. onAddForm(want: Want): formBindingData.FormBindingData {
  77. hilog.info(0x0000, TAG, 'onAddForm called');
  78. // 初始化服务
  79. this.initializeServices();
  80. const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string;
  81. const formName = want.parameters?.['ohos.extra.param.key.form_name'] as string;
  82. const tempFlag = want.parameters?.['ohos.extra.param.key.form_temporary'] as boolean;
  83. hilog.info(0x0000, TAG, `Form added: ${formId}, name: ${formName}, temp: ${tempFlag}`);
  84. // 检测卡片尺寸
  85. const widgetSize = this.sizeAdapter.detectSizeFromWant(want);
  86. this.formSizeMap.set(formId, widgetSize);
  87. hilog.info(0x0000, TAG, `Detected widget size: ${widgetSize} for form: ${formId}`);
  88. // 注册各种监听器
  89. this.sizeAdapter.registerSizeChangeListener(formId, this);
  90. this.themeSyncService.addThemeChangeListener(this);
  91. this.userPreferencesService.addPreferencesChangeListener(this);
  92. // 初始化卡片数据
  93. this.initializeWidget(formId, widgetSize);
  94. // 添加数据流测试 - 仅在开发环境中
  95. setTimeout(() => {
  96. this.testWidgetDataFlow(formId);
  97. }, 3000);
  98. // 获取当前播放状态而不是初始数据
  99. this.playerControlService.getCurrentPlayState().then((currentState: WidgetData) => {
  100. const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
  101. const formData = formBindingData.createFormBindingData(adaptedData);
  102. // 立即更新卡片以显示当前状态
  103. formProvider.updateForm(formId, formData);
  104. hilog.info(0x0000, TAG, `Widget ${formId} initialized with current state`);
  105. });
  106. // 返回初始数据作为临时显示
  107. const initialData = this.widgetDataManager?.getInitialWidgetData() || this.getDefaultWidgetData();
  108. const adaptedData = this.layoutManager.adaptDataForSize(initialData, widgetSize);
  109. return formBindingData.createFormBindingData(adaptedData);
  110. }
  111. /**
  112. * 获取默认卡片数据
  113. */
  114. private getDefaultWidgetData(): WidgetData {
  115. return {
  116. playState: {
  117. isPlaying: false,
  118. isPaused: true,
  119. isLoading: false
  120. },
  121. currentSong: {
  122. id: '',
  123. title: '暂无播放',
  124. artist: '未知艺术家',
  125. album: '未知专辑',
  126. coverImagePath: '',
  127. duration: 0
  128. },
  129. progress: {
  130. currentPosition: 0,
  131. duration: 0,
  132. percentage: 0,
  133. currentTimeText: '00:00',
  134. totalTimeText: '00:00'
  135. },
  136. playlist: {
  137. hasNext: false,
  138. hasPrevious: false,
  139. currentIndex: 0,
  140. totalCount: 0
  141. },
  142. config: {
  143. size: 'medium' as WidgetSize,
  144. theme: 'auto' as string,
  145. showProgress: true,
  146. showCover: true
  147. }
  148. };
  149. }
  150. /**
  151. * 卡片更新时调用
  152. */
  153. onUpdateForm(formId: string): void {
  154. hilog.info(0x0000, TAG, `onUpdateForm called: ${formId}`);
  155. // 获取最新的播放状态数据
  156. this.updateWidgetData(formId);
  157. // 延迟再次更新,确保数据同步到所有卡片
  158. setTimeout((): void => {
  159. this.updateAllWidgetsData();
  160. }, 200);
  161. }
  162. /**
  163. * 卡片删除时调用
  164. */
  165. onRemoveForm(formId: string): void {
  166. hilog.info(0x0000, TAG, `onRemoveForm called: ${formId}`);
  167. // 注销各种监听器
  168. this.sizeAdapter.unregisterSizeChangeListener(formId);
  169. this.themeSyncService.removeThemeChangeListener(this);
  170. this.userPreferencesService.removePreferencesChangeListener(this);
  171. // 清理卡片尺寸记录
  172. this.formSizeMap.delete(formId);
  173. // 清理卡片相关数据和配置
  174. this.widgetDataManager?.removeWidgetData(formId);
  175. this.configManager.removeWidgetConfig(formId);
  176. }
  177. /**
  178. * 卡片可见性变化时调用
  179. */
  180. onVisibilityChange(newStatus: Record<string, number>): void {
  181. hilog.info(0x0000, TAG, 'onVisibilityChange called');
  182. const formIds = Object.keys(newStatus);
  183. for (let i = 0; i < formIds.length; i++) {
  184. const formId = formIds[i];
  185. const isVisible = newStatus[formId] === 1;
  186. hilog.info(0x0000, TAG, `Form ${formId} visibility: ${isVisible}`);
  187. if (isVisible) {
  188. // 卡片变为可见时,更新数据
  189. this.updateWidgetData(formId);
  190. }
  191. }
  192. }
  193. /**
  194. * 处理卡片事件(用户交互)
  195. */
  196. onFormEvent(formId: string, message: string): void {
  197. hilog.info(0x0000, TAG, `onFormEvent called: ${formId}, message: ${message}`);
  198. try {
  199. const eventData = JSON.parse(message) as Object;
  200. this.handleWidgetEvent(formId, eventData);
  201. } catch (error) {
  202. hilog.error(0x0000, TAG, `Failed to parse form event: ${error}`);
  203. }
  204. }
  205. /**
  206. * 卡片配置更新时调用
  207. */
  208. onConfigurationUpdate(newConfig: Object): void {
  209. hilog.info(0x0000, TAG, 'onConfigurationUpdate called');
  210. // 启动主题同步服务
  211. this.themeSyncService.startThemeSync();
  212. // 更新所有卡片以适应新配置
  213. this.widgetDataManager?.updateAllWidgets();
  214. }
  215. /**
  216. * 实现SizeChangeListener接口
  217. * 处理卡片尺寸变化事件
  218. */
  219. onSizeChanged(formId: string, oldSize: WidgetSize, newSize: WidgetSize): void {
  220. hilog.info(0x0000, TAG, `Size changed for form ${formId}: ${oldSize} -> ${newSize}`);
  221. // 更新尺寸记录
  222. this.formSizeMap.set(formId, newSize);
  223. // 立即更新卡片数据以适应新尺寸
  224. this.updateWidgetData(formId);
  225. }
  226. /**
  227. * 处理卡片尺寸变化(系统调用)
  228. * @param newStatus 新的尺寸状态
  229. */
  230. onAcquireFormState(want: Want): number {
  231. hilog.info(0x0000, TAG, 'onAcquireFormState called');
  232. const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string;
  233. if (formId) {
  234. // 检测新的尺寸
  235. const newSize = this.sizeAdapter.detectSizeFromWant(want);
  236. const oldSize = this.formSizeMap.get(formId);
  237. if (oldSize && this.sizeAdapter.validateSizeChange(oldSize, newSize)) {
  238. // 处理尺寸变化
  239. this.handleFormSizeChange(formId, oldSize, newSize);
  240. }
  241. }
  242. // 返回卡片状态 - 使用数字常量代替枚举
  243. return 1; // READY状态
  244. }
  245. /**
  246. * 实现ThemeChangeListener接口
  247. * 处理主题变化事件
  248. */
  249. onThemeChanged(event: ThemeChangeEvent): void {
  250. hilog.info(0x0000, TAG, `Theme changed: ${event.themeInfo.theme}`);
  251. // 更新所有卡片的主题
  252. this.updateAllWidgetsTheme(event.themeInfo);
  253. }
  254. /**
  255. * 实现PreferencesChangeListener接口
  256. * 处理用户偏好设置变化事件
  257. */
  258. onPreferencesChanged(event: PreferencesChangeEvent): void {
  259. hilog.info(0x0000, TAG, `Preferences changed: ${event.changedKeys.join(', ')}`);
  260. // 根据变化的设置更新卡片
  261. this.handlePreferencesChange(event.changedKeys, event.newPreferences);
  262. }
  263. /**
  264. * 初始化卡片
  265. */
  266. private async initializeWidget(formId: string, widgetSize: WidgetSize): Promise<void> {
  267. try {
  268. // 注册播放状态监听
  269. this.playerControlService.registerStateListener((data: WidgetData) => {
  270. hilog.info(0x0000, TAG, `Widget ${formId} received state update: isPlaying=${data.playState.isPlaying}, title=${data.currentSong.title}, hasNext=${data.playlist.hasNext}, hasPrevious=${data.playlist.hasPrevious}`);
  271. // 根据卡片尺寸适配数据
  272. const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
  273. const adaptedData = this.layoutManager.adaptDataForSize(data, currentSize);
  274. this.widgetDataManager?.updateWidget(formId, adaptedData);
  275. hilog.info(0x0000, TAG, `Widget ${formId} updated successfully`);
  276. });
  277. // 获取当前播放状态
  278. const currentState = await this.playerControlService.getCurrentPlayState();
  279. // 获取卡片个性化配置
  280. const personalConfig = await this.configManager.getWidgetConfig(formId, widgetSize);
  281. // 应用尺寸和个性化配置
  282. currentState.config = ObjectUtils.assign(currentState.config);
  283. currentState.config.showProgress = personalConfig.showProgress;
  284. currentState.config.showCover = personalConfig.showCover;
  285. currentState.config.theme = personalConfig.theme;
  286. // 适配数据到指定尺寸
  287. const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
  288. await this.widgetDataManager?.saveWidgetData(formId, adaptedData);
  289. // 立即请求一次最新状态,并多次重试确保获取到真实状态
  290. setTimeout(() => {
  291. this.updateWidgetData(formId);
  292. }, 500);
  293. setTimeout(() => {
  294. this.updateWidgetData(formId);
  295. }, 2000);
  296. setTimeout(() => {
  297. this.updateWidgetData(formId);
  298. }, 5000);
  299. hilog.info(0x0000, TAG, `Widget ${formId} initialized successfully with size: ${widgetSize}, listeners registered: PlayerControl + AvSession`);
  300. } catch (error) {
  301. hilog.error(0x0000, TAG, `Failed to initialize widget ${formId}: ${error}`);
  302. }
  303. }
  304. /**
  305. * 更新卡片数据
  306. */
  307. private async updateWidgetData(formId: string): Promise<void> {
  308. try {
  309. const currentState = await this.playerControlService.getCurrentPlayState();
  310. // 获取卡片当前尺寸
  311. const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
  312. // 适配数据到当前尺寸
  313. const adaptedData = this.layoutManager.adaptDataForSize(currentState, currentSize);
  314. await this.widgetDataManager?.updateWidget(formId, adaptedData);
  315. hilog.info(0x0000, TAG, `Widget ${formId} updated successfully with size: ${currentSize}`);
  316. } catch (error) {
  317. hilog.error(0x0000, TAG, `Failed to update widget ${formId}: ${error}`);
  318. }
  319. }
  320. /**
  321. * 更新所有卡片数据
  322. */
  323. private async updateAllWidgetsData(): Promise<void> {
  324. try {
  325. const currentState = await this.playerControlService.getCurrentPlayState();
  326. // 遍历所有卡片ID并更新
  327. this.formSizeMap.forEach(async (size: WidgetSize, formId: string) => {
  328. try {
  329. const adaptedData = this.layoutManager.adaptDataForSize(currentState, size);
  330. await this.widgetDataManager?.updateWidget(formId, adaptedData);
  331. hilog.info(0x0000, TAG, `Widget ${formId} updated in batch with size: ${size}`);
  332. } catch (error) {
  333. hilog.error(0x0000, TAG, `Failed to update widget ${formId} in batch: ${error}`);
  334. }
  335. });
  336. hilog.info(0x0000, TAG, `Batch update completed for ${this.formSizeMap.size} widgets`);
  337. } catch (error) {
  338. hilog.error(0x0000, TAG, `Failed to batch update widgets: ${error}`);
  339. }
  340. }
  341. /**
  342. * 处理卡片事件
  343. */
  344. private async handleWidgetEvent(formId: string, eventData: Object): Promise<void> {
  345. try {
  346. // 解析事件数据
  347. const actionData: Record<string, Object> = eventData as Record<string, Object>;
  348. const action: string = (actionData['action'] as string) || 'message';
  349. hilog.info(0x0000, TAG, `Handling widget event,action ${action}`);
  350. hilog.info(0x0000, TAG, `Handling widget event,actionData ${JSON.stringify(actionData)}`);
  351. // 获取事件类型,优先从顶层的func字段获取,如果没有则从params中获取
  352. let eventType: string = (actionData['func'] as string) || '';
  353. let eventParams: Record<string, Object> = {};
  354. if (!eventType) {
  355. // 如果顶层没有func,尝试从params中获取
  356. const params: Record<string, Object> = (actionData['params'] as Record<string, Object>) || {};
  357. eventType = (params['func'] as string) || '';
  358. eventParams = params;
  359. } else {
  360. // 如果顶层有func,则整个actionData就是参数
  361. eventParams = actionData;
  362. }
  363. if (!eventType) {
  364. hilog.warn(0x0000, TAG, `No event type found in widget event data`);
  365. return;
  366. }
  367. hilog.info(0x0000, TAG, `Processing widget event type: ${eventType}`);
  368. switch (eventType) {
  369. case PLAY_PAUSE_EVENT:
  370. await this.playerControlService.sendControlCommand(WidgetCommand.PLAY_PAUSE);
  371. break;
  372. case NEXT_SONG_EVENT:
  373. await this.playerControlService.sendControlCommand(WidgetCommand.NEXT_SONG);
  374. break;
  375. case PREV_SONG_EVENT:
  376. await this.playerControlService.sendControlCommand(WidgetCommand.PREV_SONG);
  377. break;
  378. case SEEK_TO_EVENT:
  379. const percentage = (eventParams['percentage'] as number) || 0;
  380. const controlParams: WidgetControlParams = {
  381. percentage: percentage,
  382. position: 0
  383. };
  384. hilog.info(0x0000, TAG, `Seeking to percentage: ${percentage}`);
  385. await this.playerControlService.sendControlCommand(WidgetCommand.SEEK_TO, controlParams);
  386. break;
  387. case OPEN_APP_EVENT:
  388. // 启动主应用到首页
  389. await this.playerControlService.launchMainApp(PAGE_MAIN);
  390. break;
  391. case OPEN_PLAYER_EVENT:
  392. // 启动主应用到播放器页面
  393. await this.playerControlService.launchMainApp(PAGE_PLAYER);
  394. break;
  395. case LONG_PRESS_MENU_EVENT:
  396. // 处理长按菜单显示(由系统处理,这里记录日志)
  397. hilog.info(0x0000, TAG, 'Long press menu event triggered');
  398. break;
  399. case WIDGET_SETTINGS_EVENT:
  400. // 打开卡片设置页面
  401. await this.handleWidgetSettings(formId);
  402. break;
  403. case WIDGET_DELETE_EVENT:
  404. // 处理卡片删除
  405. await this.handleWidgetDelete(formId);
  406. break;
  407. case WIDGET_CONFIG_PAGE_EVENT:
  408. // 跳转到卡片配置界面
  409. await this.handleWidgetConfigPage(formId);
  410. break;
  411. default:
  412. hilog.warn(0x0000, TAG, `Unknown widget event type: ${eventType}`);
  413. return;
  414. }
  415. // 处理完命令后立即更新当前卡片状态
  416. this.updateWidgetData(formId);
  417. // 延迟更新所有卡片,确保状态同步
  418. setTimeout((): void => {
  419. this.updateAllWidgetsData();
  420. }, 300);
  421. } catch (error) {
  422. hilog.error(0x0000, TAG, `Failed to handle widget event: ${error}`);
  423. }
  424. }
  425. /**
  426. * 处理表单尺寸变化
  427. */
  428. private async handleFormSizeChange(formId: string, oldSize: WidgetSize, newSize: WidgetSize): Promise<void> {
  429. try {
  430. hilog.info(0x0000, TAG, `Handling form size change: ${formId} from ${oldSize} to ${newSize}`);
  431. // 获取当前播放状态
  432. const currentState = await this.playerControlService.getCurrentPlayState();
  433. // 使用适配器处理尺寸变化
  434. const adaptedData = this.sizeAdapter.handleSizeChange(formId, oldSize, newSize, currentState);
  435. // 更新卡片数据
  436. await this.widgetDataManager?.updateWidget(formId, adaptedData);
  437. hilog.info(0x0000, TAG, `Form size change handled successfully for: ${formId}`);
  438. } catch (error) {
  439. hilog.error(0x0000, TAG, `Failed to handle form size change: ${error}`);
  440. }
  441. }
  442. /**
  443. * 更新所有卡片的主题
  444. */
  445. private async updateAllWidgetsTheme(themeInfo: ThemeInfo): Promise<void> {
  446. try {
  447. // 更新所有卡片配置中的主题信息
  448. await this.configManager.updateAllWidgetConfigs((config) => {
  449. const updatedConfig = ObjectUtils.assign(config);
  450. updatedConfig.theme = themeInfo.theme;
  451. updatedConfig.backgroundColor = themeInfo.backgroundColor;
  452. updatedConfig.textColor = themeInfo.textColor;
  453. updatedConfig.accentColor = themeInfo.accentColor;
  454. return updatedConfig;
  455. });
  456. // 刷新所有卡片显示
  457. await this.widgetDataManager?.updateAllWidgets();
  458. hilog.info(0x0000, TAG, 'All widgets theme updated');
  459. } catch (error) {
  460. hilog.error(0x0000, TAG, `Failed to update all widgets theme: ${error}`);
  461. }
  462. }
  463. /**
  464. * 处理偏好设置变化
  465. */
  466. private async handlePreferencesChange(changedKeys: string[], newPreferences: UserPreferences): Promise<void> {
  467. try {
  468. // 检查是否需要重新同步主题
  469. if (changedKeys.includes('syncThemeColor') && newPreferences.syncThemeColor) {
  470. await this.themeSyncService.syncTheme();
  471. }
  472. // 检查是否需要更新缓存设置
  473. if (changedKeys.includes('enableCache') || changedKeys.includes('cacheExpiry')) {
  474. // 这里可以更新缓存相关设置
  475. hilog.info(0x0000, TAG, 'Cache settings updated');
  476. }
  477. // 检查隐私设置变化
  478. const privacyKeys = ['showSongInfo', 'showArtistInfo', 'showAlbumCover'];
  479. const hasPrivacyChange = changedKeys.some(key => privacyKeys.includes(key));
  480. if (hasPrivacyChange) {
  481. // 更新所有卡片的显示配置
  482. await this.configManager.updateAllWidgetConfigs((config) => {
  483. const updatedConfig = ObjectUtils.assign(config);
  484. updatedConfig.showCover = (newPreferences.showAlbumCover as boolean) && config.showCover;
  485. return updatedConfig;
  486. });
  487. // 刷新所有卡片显示
  488. await this.widgetDataManager?.updateAllWidgets();
  489. }
  490. hilog.info(0x0000, TAG, 'Preferences change handled successfully');
  491. } catch (error) {
  492. hilog.error(0x0000, TAG, `Failed to handle preferences change: ${error}`);
  493. }
  494. }
  495. /**
  496. * 处理卡片设置
  497. */
  498. private async handleWidgetSettings(formId: string): Promise<void> {
  499. try {
  500. hilog.info(0x0000, TAG, `Opening widget settings for form: ${formId}`);
  501. // 获取当前卡片配置
  502. const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
  503. const currentConfig = await this.configManager.getWidgetConfig(formId, currentSize);
  504. // 启动主应用到卡片设置页面,传递卡片ID和当前配置
  505. const settingsParams: WidgetSettingsParams = {
  506. formId: formId,
  507. currentSize: currentSize,
  508. currentConfig: JSON.stringify(currentConfig)
  509. };
  510. await this.playerControlService.launchMainApp('widget_settings', settingsParams);
  511. hilog.info(0x0000, TAG, `Widget settings opened for form: ${formId}`);
  512. } catch (error) {
  513. hilog.error(0x0000, TAG, `Failed to open widget settings: ${error}`);
  514. }
  515. }
  516. /**
  517. * 处理卡片删除
  518. */
  519. private async handleWidgetDelete(formId: string): Promise<void> {
  520. try {
  521. hilog.info(0x0000, TAG, `Processing widget delete for form: ${formId}`);
  522. // 显示删除确认对话框(通过主应用)
  523. const deleteParams: WidgetConfigParams = {
  524. formId: formId,
  525. configType: 'delete',
  526. configValue: 'confirm_delete'
  527. };
  528. await this.playerControlService.launchMainApp('widget_delete_confirm', deleteParams);
  529. hilog.info(0x0000, TAG, `Widget delete confirmation shown for form: ${formId}`);
  530. } catch (error) {
  531. hilog.error(0x0000, TAG, `Failed to process widget delete: ${error}`);
  532. }
  533. }
  534. /**
  535. * 处理卡片配置界面跳转
  536. */
  537. private async handleWidgetConfigPage(formId: string): Promise<void> {
  538. try {
  539. hilog.info(0x0000, TAG, `Opening widget config page for form: ${formId}`);
  540. // 获取当前卡片信息
  541. const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
  542. const currentConfig = await this.configManager.getWidgetConfig(formId, currentSize);
  543. // 启动主应用到卡片配置页面
  544. const configParams: WidgetConfigParams = {
  545. formId: formId,
  546. configType: 'full_config',
  547. configValue: JSON.stringify(currentConfig)
  548. };
  549. await this.playerControlService.launchMainApp('widget_config', configParams);
  550. hilog.info(0x0000, TAG, `Widget config page opened for form: ${formId}`);
  551. } catch (error) {
  552. hilog.error(0x0000, TAG, `Failed to open widget config page: ${error}`);
  553. }
  554. }
  555. /**
  556. * 测试卡片数据流(开发调试用)
  557. */
  558. private testWidgetDataFlow(formId: string): void {
  559. hilog.info(0x0000, TAG, `🔍 Testing widget data flow for form: ${formId}`);
  560. // 测试1: 检查监听器状态
  561. hilog.info(0x0000, TAG, `📊 Current listener count: PlayerControlService has listeners registered`);
  562. // 测试2: 手动触发一次数据更新
  563. setTimeout(() => {
  564. hilog.info(0x0000, TAG, `🔄 Manually triggering data update for form: ${formId}`);
  565. this.updateWidgetData(formId);
  566. }, 1000);
  567. // 测试3: 获取AvSession当前数据
  568. setTimeout(() => {
  569. try {
  570. const currentData = this.playerControlService.getCurrentPlayState();
  571. currentData.then((data) => {
  572. hilog.info(0x0000, TAG, `📊 AvSession current data: isPlaying=${data.playState.isPlaying}, hasNext=${data.playlist.hasNext}, hasPrevious=${data.playlist.hasPrevious}, title=${data.currentSong.title}`);
  573. });
  574. } catch (error) {
  575. hilog.error(0x0000, TAG, `❌ Failed to get current data: ${error}`);
  576. }
  577. }, 2000);
  578. }
  579. }