chendeben 1 год назад
Родитель
Сommit
fe9b055987

+ 40 - 12
entry/src/main/ets/common/widget/PlayerControlService.ets

@@ -3,6 +3,15 @@ import Want from '@ohos.app.ability.Want';
 import common from '@ohos.app.ability.common';
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { WidgetData, WidgetCommand, EventData, RequestData, WidgetControlParams } from './WidgetTypes';
+import { 
+  WIDGET_CONTROL_EVENT,
+  WIDGET_REQUEST_STATE_EVENT,
+  PLAYER_STATE_CHANGED_EVENT,
+  PLAYER_SONG_CHANGED_EVENT,
+  PLAYER_PROGRESS_CHANGED_EVENT,
+  APP_BUNDLE_NAME,
+  APP_ABILITY_NAME
+} from './WidgetEventConstants';
 
 const TAG = 'PlayerControlService';
 
@@ -30,9 +39,9 @@ export class PlayerControlService {
       // 监听播放状态变化事件
       const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
         events: [
-          'com.ttmusic.player.state.changed',
-          'com.ttmusic.player.song.changed',
-          'com.ttmusic.player.progress.changed'
+          PLAYER_STATE_CHANGED_EVENT,
+          PLAYER_SONG_CHANGED_EVENT,
+          PLAYER_PROGRESS_CHANGED_EVENT
         ]
       };
 
@@ -54,11 +63,12 @@ export class PlayerControlService {
   /**
    * 发送控制命令到主应用
    */
-  async sendControlCommand(command: WidgetCommand, params?: Object): Promise<boolean> {
+  async sendControlCommand(command: WidgetCommand, params?: WidgetControlParams): Promise<boolean> {
     try {
+      const defaultParams: WidgetControlParams = {};
       const eventData: EventData = {
         command: command,
-        params: (params as WidgetControlParams) || ({} as WidgetControlParams),
+        params: params || defaultParams,
         timestamp: Date.now(),
         source: 'widget'
       };
@@ -67,7 +77,7 @@ export class PlayerControlService {
       const publishInfo: commonEventManager.CommonEventPublishData = {
         data: JSON.stringify(eventData)
       };
-      await commonEventManager.publish('com.ttmusic.widget.control', publishInfo, (err) => {
+      await commonEventManager.publish(WIDGET_CONTROL_EVENT, publishInfo, (err) => {
         if (err) {
           hilog.error(0x0000, TAG, `Failed to publish event: ${err}`);
         }
@@ -91,7 +101,7 @@ export class PlayerControlService {
       const requestInfo: commonEventManager.CommonEventPublishData = {
         data: JSON.stringify(requestData)
       };
-      await commonEventManager.publish('com.ttmusic.widget.request.state', requestInfo, (err) => {
+      await commonEventManager.publish(WIDGET_REQUEST_STATE_EVENT, requestInfo, (err) => {
         if (err) {
           hilog.error(0x0000, TAG, `Failed to publish request state event: ${err}`);
         }
@@ -119,10 +129,12 @@ export class PlayerControlService {
   async launchMainApp(page?: string): Promise<boolean> {
     try {
       const want: Want = {
-        bundleName: 'com.ttmusic.app',
-        abilityName: 'EntryAbility',
+        bundleName: APP_BUNDLE_NAME,
+        abilityName: APP_ABILITY_NAME,
         parameters: {
-          page: page || 'main'
+          page: page || 'main',
+          source: 'widget', // 标识来源是卡片
+          timestamp: Date.now().toString()
         }
       };
 
@@ -133,7 +145,23 @@ export class PlayerControlService {
       return true;
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to launch main app: ${error}`);
-      return false;
+      
+      // 如果启动失败,尝试启动到默认页面
+      try {
+        const fallbackWant: Want = {
+          bundleName: APP_BUNDLE_NAME,
+          abilityName: APP_ABILITY_NAME
+        };
+        
+        const context = getContext() as common.UIAbilityContext;
+        await context.startAbility(fallbackWant);
+        
+        hilog.info(0x0000, TAG, 'Main app launched with fallback method');
+        return true;
+      } catch (fallbackError) {
+        hilog.error(0x0000, TAG, `Fallback launch also failed: ${fallbackError}`);
+        return false;
+      }
     }
   }
 
@@ -146,7 +174,7 @@ export class PlayerControlService {
       const widgetData = this.convertToWidgetData(data);
       
       // 通知所有监听器
-      this.stateListeners.forEach(listener => {
+      this.stateListeners.forEach((listener: (data: WidgetData) => void) => {
         try {
           listener(widgetData);
         } catch (error) {

+ 168 - 0
entry/src/main/ets/common/widget/WidgetController.ets

@@ -0,0 +1,168 @@
+import { WidgetActionData } from './WidgetTypes';
+import { 
+  PLAY_PAUSE_EVENT, 
+  NEXT_SONG_EVENT, 
+  PREV_SONG_EVENT, 
+  SEEK_TO_EVENT, 
+  OPEN_APP_EVENT, 
+  OPEN_PLAYER_EVENT 
+} from './WidgetEventConstants';
+
+/**
+ * 简化的卡片事件发送函数
+ */
+function postCardAction(context: Object, data: WidgetActionData): void {
+  try {
+    const message: string = JSON.stringify(data);
+    console.info(`Posting card action: ${message}`);
+    
+    const globalObj: ESObject = globalThis as ESObject;
+    if (globalObj.postCardAction && typeof globalObj.postCardAction === 'function') {
+      globalObj.postCardAction(context, message);
+      console.info(`Card action posted successfully`);
+    } else {
+      console.error(`Global postCardAction function not found`);
+    }
+  } catch (error) {
+    console.error(`Failed to post card action: ${error}`);
+  }
+}
+
+/**
+ * 卡片控制器
+ * 统一管理卡片的点击行为和交互逻辑
+ */
+export class WidgetController {
+  
+  /**
+   * 处理播放/暂停按钮点击
+   */
+  static handlePlayPause(context: Object): void {
+    console.info('Play/Pause button clicked');
+    
+    const actionData: WidgetActionData = {
+      action: PLAY_PAUSE_EVENT,
+      params: new Object()
+    };
+    
+    postCardAction(context, actionData);
+  }
+
+  /**
+   * 处理下一首按钮点击
+   */
+  static handleNextSong(context: Object): void {
+    console.info('Next song button clicked');
+    
+    const actionData: WidgetActionData = {
+      action: NEXT_SONG_EVENT,
+      params: new Object()
+    };
+    
+    postCardAction(context, actionData);
+  }
+
+  /**
+   * 处理上一首按钮点击
+   */
+  static handlePrevSong(context: Object): void {
+    console.info('Previous song button clicked');
+    
+    const actionData: WidgetActionData = {
+      action: PREV_SONG_EVENT,
+      params: new Object()
+    };
+    
+    postCardAction(context, actionData);
+  }
+
+  /**
+   * 处理进度条点击
+   */
+  static handleSeekTo(context: Object, percentage: number): void {
+    console.info(`Seek to ${percentage}%`);
+    
+    const params: Object = new Object();
+    (params as ESObject)['percentage'] = percentage;
+    
+    const actionData: WidgetActionData = {
+      action: SEEK_TO_EVENT,
+      params: params
+    };
+    
+    postCardAction(context, actionData);
+  }
+
+  /**
+   * 处理打开应用点击
+   */
+  static handleOpenApp(context: Object): void {
+    console.info('Open app clicked');
+    
+    const actionData: WidgetActionData = {
+      action: OPEN_APP_EVENT,
+      params: new Object()
+    };
+    
+    postCardAction(context, actionData);
+  }
+
+  /**
+   * 处理打开播放器页面点击
+   */
+  static handleOpenPlayer(context: Object): void {
+    console.info('Open player clicked');
+    
+    const actionData: WidgetActionData = {
+      action: OPEN_PLAYER_EVENT,
+      params: new Object()
+    };
+    
+    postCardAction(context, actionData);
+  }
+
+  /**
+   * 处理进度条点击事件
+   */
+  static handleProgressClick(context: Object, event: ClickEvent): void {
+    try {
+      const clickX: number = event.x;
+      const progressWidth: number = event.target.area.width as number;
+      
+      if (progressWidth > 0) {
+        const percentage: number = Math.max(0, Math.min(100, (clickX / progressWidth) * 100));
+        WidgetController.handleSeekTo(context, percentage);
+      }
+    } catch (error) {
+      console.error(`Failed to handle progress click: ${error}`);
+    }
+  }
+
+  /**
+   * 检查按钮是否可用
+   */
+  static isButtonEnabled(hasNext: boolean, hasPrevious: boolean, buttonType: 'next' | 'prev'): boolean {
+    switch (buttonType) {
+      case 'next':
+        return hasNext;
+      case 'prev':
+        return hasPrevious;
+      default:
+        return true;
+    }
+  }
+
+  /**
+   * 获取按钮颜色
+   */
+  static getButtonColor(enabled: boolean): string {
+    return enabled ? '#FF007DFF' : '#66000000';
+  }
+
+  /**
+   * 获取播放按钮图标
+   */
+  static getPlayButtonIcon(isPlaying: boolean): Resource {
+    return isPlaying ? $r('app.media.hm_pause') : $r('app.media.hm_play');
+  }
+}

+ 6 - 6
entry/src/main/ets/common/widget/WidgetDataManager.ets

@@ -164,8 +164,8 @@ export class WidgetDataManager {
       const widgetKeys = Object.keys(allKeys || emptyPrefs).filter(key => key.startsWith('widget_'));
       
       for (const key of widgetKeys) {
-        const formId = key.replace('widget_', '');
-        const widgetData = data || await this.getWidgetData(formId);
+        const formId: string = key.replace('widget_', '');
+        const widgetData: WidgetData = data || await this.getWidgetData(formId);
         await this.updateWidget(formId, widgetData);
       }
       
@@ -256,13 +256,13 @@ export class WidgetDataManager {
     const now = Date.now();
     const expiredKeys: string[] = [];
     
-    this.dataCache.forEach((item, key) => {
+    this.dataCache.forEach((item: CacheItem, key: string) => {
       if (now > item.expiry) {
         expiredKeys.push(key);
       }
     });
     
-    expiredKeys.forEach(key => {
+    expiredKeys.forEach((key: string) => {
       this.dataCache.delete(key);
     });
     
@@ -385,8 +385,8 @@ export class WidgetDataManager {
       const widgetKeys = Object.keys(allKeys || emptyPrefs).filter(key => key.startsWith('widget_'));
       
       for (const key of widgetKeys) {
-        const formId = key.replace('widget_', '');
-        const data = await this.getWidgetData(formId);
+        const formId: string = key.replace('widget_', '');
+        const data: WidgetData = await this.getWidgetData(formId);
         this.setCachedData(formId, data);
       }
       

+ 61 - 0
entry/src/main/ets/common/widget/WidgetEventConstants.ets

@@ -0,0 +1,61 @@
+/**
+ * 卡片事件常量 - 简化版本
+ */
+
+// 播放控制事件
+export const PLAY_PAUSE_EVENT = 'play_pause';
+export const NEXT_SONG_EVENT = 'next_song';
+export const PREV_SONG_EVENT = 'prev_song';
+export const SEEK_TO_EVENT = 'seek_to';
+
+// 应用启动事件
+export const OPEN_APP_EVENT = 'open_app';
+export const OPEN_PLAYER_EVENT = 'open_player';
+
+// 其他事件
+export const REFRESH_DATA_EVENT = 'refresh_data';
+export const TOGGLE_FAVORITE_EVENT = 'toggle_favorite';
+
+// 卡片尺寸
+export const WIDGET_SIZE_SMALL = 'small';
+export const WIDGET_SIZE_MEDIUM = 'medium';
+export const WIDGET_SIZE_LARGE = 'large';
+
+// 卡片主题
+export const WIDGET_THEME_AUTO = 'auto';
+export const WIDGET_THEME_LIGHT = 'light';
+export const WIDGET_THEME_DARK = 'dark';
+
+// 通信事件
+export const WIDGET_CONTROL_EVENT = 'com.ttmusic.widget.control';
+export const WIDGET_REQUEST_STATE_EVENT = 'com.ttmusic.widget.request.state';
+export const PLAYER_STATE_CHANGED_EVENT = 'com.ttmusic.player.state.changed';
+export const PLAYER_SONG_CHANGED_EVENT = 'com.ttmusic.player.song.changed';
+export const PLAYER_PROGRESS_CHANGED_EVENT = 'com.ttmusic.player.progress.changed';
+
+// 应用信息
+export const APP_BUNDLE_NAME = 'com.ttmusic.app';
+export const APP_ABILITY_NAME = 'EntryAbility';
+
+// 页面路由
+export const PAGE_MAIN = 'main';
+export const PAGE_PLAYER = 'player';
+export const PAGE_PLAYLIST = 'playlist';
+export const PAGE_SEARCH = 'search';
+
+// 错误码
+export const ERROR_COMMUNICATION_FAILED = 1001;
+export const ERROR_DATA_SYNC_FAILED = 1002;
+export const ERROR_CONTROL_COMMAND_FAILED = 1003;
+export const ERROR_LAYOUT_ERROR = 1004;
+export const ERROR_PERMISSION_DENIED = 1005;
+
+// 缓存配置
+export const CACHE_EXPIRY_TIME = 30 * 1000; // 30秒
+export const CACHE_MAX_SIZE = 50;
+export const CACHE_CLEANUP_INTERVAL = 60 * 1000; // 1分钟
+
+// 动画配置
+export const ANIMATION_BUTTON_PRESS_DURATION = 150;
+export const ANIMATION_PROGRESS_UPDATE_DURATION = 300;
+export const ANIMATION_FADE_DURATION = 200;

+ 15 - 0
entry/src/main/ets/common/widget/WidgetTypes.ets

@@ -201,4 +201,19 @@ export interface CacheStats {
   size: number;
   hitRate: number;
   lastUpdate: number;
+}
+
+/**
+ * 卡片事件处理参数接口
+ */
+export interface WidgetEventParams {
+  action: string;
+  params?: Object;
+}
+
+/**
+ * 进度跳转参数接口(扩展)
+ */
+export interface WidgetSeekParams {
+  percentage: number;
 }

+ 65 - 5
entry/src/main/ets/common/widget/WidgetUtils.ets

@@ -15,13 +15,73 @@ const TAG = 'WidgetUtils';
 export function postCardAction(context: Object, data: WidgetActionData): void {
   try {
     const message = JSON.stringify(data);
-    hilog.info(0x0000, TAG, `Posting card action: ${message}`);
+    hilog.info(0x0000, TAG, `=== Starting postCardAction ===`);
+    hilog.info(0x0000, TAG, `Action: ${data.action}`);
+    hilog.info(0x0000, TAG, `Message: ${message}`);
+    hilog.info(0x0000, TAG, `Context type: ${typeof context}`);
+    
+    // 检查全局对象的可用属性
+    const globalObj: ESObject = globalThis as ESObject;
+    const globalKeys: string[] = Object.keys(globalObj);
+    hilog.info(0x0000, TAG, `Global object keys: ${globalKeys.slice(0, 10).join(', ')}...`);
+    
+    // 方法1: 尝试使用全局postCardAction函数
+    if (globalObj.postCardAction && typeof globalObj.postCardAction === 'function') {
+      hilog.info(0x0000, TAG, `Found global postCardAction function`);
+      globalObj.postCardAction(context, message);
+      hilog.info(0x0000, TAG, `✅ Card action posted via global function`);
+      return;
+    } else {
+      hilog.warn(0x0000, TAG, `Global postCardAction not found or not a function`);
+    }
+    
+    // 方法2: 检查是否存在postCardAction全局函数
+    try {
+      if (typeof postCardAction !== 'undefined') {
+        hilog.info(0x0000, TAG, `Found direct postCardAction function`);
+        (postCardAction as Function)(context, message);
+        hilog.info(0x0000, TAG, `✅ Card action posted via direct function`);
+        return;
+      }
+    } catch (refError) {
+      hilog.warn(0x0000, TAG, `Direct postCardAction reference failed: ${refError}`);
+    }
+    
+    // 方法3: 检查context是否有postCardAction方法
+    const contextObj: ESObject = context as ESObject;
+    if (contextObj && typeof contextObj === 'object') {
+      const contextKeys = Object.keys(contextObj);
+      hilog.info(0x0000, TAG, `Context keys: ${contextKeys.slice(0, 5).join(', ')}...`);
+      
+      if (contextObj.postCardAction && typeof contextObj.postCardAction === 'function') {
+        hilog.info(0x0000, TAG, `Found context postCardAction method`);
+        contextObj.postCardAction(message);
+        hilog.info(0x0000, TAG, `✅ Card action posted via context method`);
+        return;
+      }
+    }
+    
+    // 方法4: 尝试通过不同的全局对象路径
+    const alternativePaths: string[] = ['window', 'self', 'global'];
+    for (const path of alternativePaths) {
+      const pathObj: ESObject = globalObj[path] as ESObject;
+      if (pathObj && pathObj.postCardAction && typeof pathObj.postCardAction === 'function') {
+        hilog.info(0x0000, TAG, `Found postCardAction via ${path}`);
+        pathObj.postCardAction(context, message);
+        hilog.info(0x0000, TAG, `✅ Card action posted via ${path}`);
+        return;
+      }
+    }
+    
+    // 如果所有方法都失败,记录详细的调试信息
+    hilog.error(0x0000, TAG, `❌ No available method to post card action`);
+    hilog.error(0x0000, TAG, `Global postCardAction exists: ${!!globalObj.postCardAction}`);
+    hilog.error(0x0000, TAG, `Global postCardAction type: ${typeof globalObj.postCardAction}`);
+    hilog.error(0x0000, TAG, `Context is object: ${typeof contextObj === 'object'}`);
+    hilog.error(0x0000, TAG, `Context postCardAction exists: ${!!(contextObj && contextObj.postCardAction)}`);
     
-    // 使用全局postCardAction函数发送卡片事件
-    // 这个函数在卡片运行时环境中可用
-    (globalThis as ESObject).postCardAction(context, message);
   } catch (error) {
-    hilog.error(0x0000, TAG, `Failed to post card action: ${error}`);
+    hilog.error(0x0000, TAG, `❌ Failed to post card action: ${error}`);
   }
 }
 

+ 21 - 35
entry/src/main/ets/common/widget/index.ets

@@ -1,44 +1,30 @@
 /**
- * 卡片模块导出文件
- * 统一导出所有卡片相关的类型、接口和工具
+ * 卡片模块统一导出
  */
 
-// 数据类型和接口
-export {
-  WidgetSize,
-  WidgetTheme,
-  WidgetCommand,
-  WidgetErrorType,
-  type PlayState,
-  type SongInfo,
-  type PlayProgress,
-  type PlaylistState,
-  type WidgetConfig,
-  type WidgetData,
-  type WidgetControlParams,
-  type WidgetControlMessage,
-  type WidgetError,
-  type EventData,
-  type RequestData,
-  type FormattedWidgetData,
-  type WidgetActionData,
-  type SeekParams
-} from './WidgetTypes';
+// 类型定义
+export * from './WidgetTypes';
 
-// 数据管理器
-export { WidgetDataManager } from './WidgetDataManager';
+// 常量定义
+export * from './WidgetEventConstants';
 
-// 播放控制服务
+// 核心服务
+export { WidgetDataManager } from './WidgetDataManager';
 export { PlayerControlService } from './PlayerControlService';
 
+// 控制器
+export { WidgetController } from './WidgetController';
+export { SimpleWidgetController } from './SimpleWidgetController';
+
 // 工具函数
-export {
-  postCardAction,
-  formatTime,
-  calculatePercentage,
-  truncateText,
-  validateWidgetData
-} from './WidgetUtils';
+export * from './WidgetUtils';
+export * from './SimpleWidgetUtils';
 
-// 测试工具
-export { WidgetDataManagerTest, runWidgetDataManagerTests } from './WidgetDataManagerTest';
+// 测试辅助
+export { WidgetTestHelper } from './WidgetTestHelper';
+export { WidgetSimpleTest } from './WidgetSimpleTest';
+export { TypeValidation } from './TypeValidation';
+export { FinalTypeCheck } from './FinalTypeCheck';
+export { WidgetDiagnostics } from './WidgetDiagnostics';
+export { WidgetConfigValidator } from './WidgetConfigValidator';
+export { WidgetQuickFix } from './WidgetQuickFix';

+ 42 - 19
entry/src/main/ets/entryformability/PlayerWidgetFormExtensionAbility.ets

@@ -5,7 +5,17 @@ import Want from '@ohos.app.ability.Want';
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { WidgetDataManager } from '../common/widget/WidgetDataManager';
 import { PlayerControlService } from '../common/widget/PlayerControlService';
-import { WidgetCommand, WidgetControlParams } from '../common/widget/WidgetTypes';
+import { WidgetCommand, WidgetControlParams, WidgetData } from '../common/widget/WidgetTypes';
+import { 
+  PLAY_PAUSE_EVENT, 
+  NEXT_SONG_EVENT, 
+  PREV_SONG_EVENT, 
+  SEEK_TO_EVENT, 
+  OPEN_APP_EVENT, 
+  OPEN_PLAYER_EVENT,
+  PAGE_MAIN,
+  PAGE_PLAYER
+} from '../common/widget/WidgetEventConstants';
 
 const TAG = 'PlayerWidgetFormExtensionAbility';
 
@@ -107,7 +117,7 @@ export default class PlayerWidgetFormExtensionAbility extends FormExtensionAbili
   private async initializeWidget(formId: string): Promise<void> {
     try {
       // 注册播放状态监听
-      this.playerControlService.registerStateListener((data) => {
+      this.playerControlService.registerStateListener((data: WidgetData) => {
         this.widgetDataManager.updateWidget(formId, data);
       });
       
@@ -139,42 +149,55 @@ export default class PlayerWidgetFormExtensionAbility extends FormExtensionAbili
    * 处理卡片事件
    */
   private async handleWidgetEvent(formId: string, eventData: Object): Promise<void> {
-    // 简化处理,避免索引访问
-    const action: string = 'play_pause'; // 默认操作
-    const params = new Object();
-    
     try {
+      // 解析事件数据
+      const actionData: ESObject = eventData as ESObject;
+      const action: string = (actionData['action'] as string) || 'play_pause';
+      const params: Object = (actionData['params'] as Object) || new Object();
+      
+      hilog.info(0x0000, TAG, `Handling widget event: ${action}`);
+      
       switch (action) {
-        case 'play_pause':
+        case PLAY_PAUSE_EVENT:
           await this.playerControlService.sendControlCommand(WidgetCommand.PLAY_PAUSE);
           break;
-        case 'next_song':
+          
+        case NEXT_SONG_EVENT:
           await this.playerControlService.sendControlCommand(WidgetCommand.NEXT_SONG);
           break;
-        case 'prev_song':
+          
+        case PREV_SONG_EVENT:
           await this.playerControlService.sendControlCommand(WidgetCommand.PREV_SONG);
           break;
-        case 'seek_to':
-          const seekParams: WidgetControlParams = { 
-            percentage: 50,
+          
+        case SEEK_TO_EVENT:
+          const seekParams: ESObject = params as ESObject;
+          const controlParams: WidgetControlParams = { 
+            percentage: (seekParams['percentage'] as number) || 0,
             position: 0 
           };
-          await this.playerControlService.sendControlCommand(WidgetCommand.SEEK_TO, seekParams);
+          await this.playerControlService.sendControlCommand(WidgetCommand.SEEK_TO, controlParams);
           break;
-        case 'open_app':
-          await this.playerControlService.sendControlCommand(WidgetCommand.OPEN_APP);
+          
+        case OPEN_APP_EVENT:
+          // 启动主应用到首页
+          await this.playerControlService.launchMainApp(PAGE_MAIN);
           break;
-        case 'open_player':
-          await this.playerControlService.sendControlCommand(WidgetCommand.OPEN_PLAYER);
+          
+        case OPEN_PLAYER_EVENT:
+          // 启动主应用到播放器页面
+          await this.playerControlService.launchMainApp(PAGE_PLAYER);
           break;
+          
         default:
           hilog.warn(0x0000, TAG, `Unknown widget action: ${action}`);
+          return;
       }
       
       // 处理完命令后更新卡片状态
-      setTimeout(() => {
+      setTimeout((): void => {
         this.updateWidgetData(formId);
-      }, 100);
+      }, 200);
       
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to handle widget event: ${error}`);

+ 7 - 36
entry/src/main/ets/widget/pages/PlayerWidgetLarge.ets

@@ -1,5 +1,4 @@
-import { postCardAction } from '../../common/widget/WidgetUtils';
-import { WidgetActionData, SeekParams } from '../../common/widget/WidgetTypes';
+import { SimpleWidgetController } from '../../common/widget/SimpleWidgetController';
 
 /**
  * 大尺寸播放器卡片 (4x3)
@@ -34,7 +33,7 @@ struct PlayerWidgetLarge {
             .objectFit(ImageFit.Cover)
             .margin({ right: 12 })
             .onClick(() => {
-              this.handleControlAction('open_player');
+              SimpleWidgetController.handleOpenPlayer(this);
             })
         }
 
@@ -73,7 +72,7 @@ struct PlayerWidgetLarge {
         .alignItems(HorizontalAlign.Start)
         .justifyContent(FlexAlign.Start)
         .onClick(() => {
-          this.handleControlAction('open_player');
+          SimpleWidgetController.handleOpenPlayer(this);
         })
       }
       .width('100%')
@@ -95,7 +94,7 @@ struct PlayerWidgetLarge {
               .color('#FF007DFF')
               .backgroundColor('#1A007DFF')
               .onClick((event) => {
-                this.handleProgressClick(event);
+                SimpleWidgetController.handleProgressClick(this, event);
               })
           }
           .width('100%')
@@ -133,7 +132,7 @@ struct PlayerWidgetLarge {
         .backgroundColor(Color.Transparent)
         .enabled(this.hasPrevious)
         .onClick(() => {
-          this.handleControlAction('prev_song');
+          SimpleWidgetController.handlePrevSong(this);
         })
 
         Blank()
@@ -150,7 +149,7 @@ struct PlayerWidgetLarge {
         .backgroundColor('#FF007DFF')
         .borderRadius(26)
         .onClick(() => {
-          this.handleControlAction('play_pause');
+          SimpleWidgetController.handlePlayPause(this);
         })
 
         Blank()
@@ -167,7 +166,7 @@ struct PlayerWidgetLarge {
         .backgroundColor(Color.Transparent)
         .enabled(this.hasNext)
         .onClick(() => {
-          this.handleControlAction('next_song');
+          SimpleWidgetController.handleNextSong(this);
         })
       }
       .width('100%')
@@ -183,33 +182,5 @@ struct PlayerWidgetLarge {
     .justifyContent(FlexAlign.SpaceBetween)
   }
 
-  /**
-   * 处理控制操作
-   */
-  private handleControlAction(action: string): void {
-    const actionData: WidgetActionData = {
-      action: action,
-      params: new Object()
-    };
-    postCardAction(this, actionData);
-  }
 
-  /**
-   * 处理进度条点击
-   */
-  private handleProgressClick(event: ClickEvent): void {
-    // 计算点击位置对应的播放进度
-    const clickX = event.x;
-    const progressWidth = event.target.area.width as number;
-    const percentage = (clickX / progressWidth) * 100;
-    
-    const seekParams: SeekParams = {
-      percentage: percentage
-    };
-    const seekData: WidgetActionData = {
-      action: 'seek_to',
-      params: seekParams as Object
-    };
-    postCardAction(this, seekData);
-  }
 }

+ 6 - 35
entry/src/main/ets/widget/pages/PlayerWidgetMedium.ets

@@ -1,5 +1,4 @@
-import { postCardAction } from '../../common/widget/WidgetUtils';
-import { WidgetActionData, SeekParams } from '../../common/widget/WidgetTypes';
+import { WidgetController } from '../../common/widget/WidgetController';
 
 /**
  * 中等尺寸播放器卡片 (4x2)
@@ -45,7 +44,7 @@ struct PlayerWidgetMedium {
         .layoutWeight(1)
         .alignItems(HorizontalAlign.Start)
         .onClick(() => {
-          this.handleControlAction('open_player');
+          WidgetController.handleOpenPlayer(this);
         })
       }
       .width('100%')
@@ -65,7 +64,7 @@ struct PlayerWidgetMedium {
         .backgroundColor(Color.Transparent)
         .enabled(this.hasPrevious)
         .onClick(() => {
-          this.handleControlAction('prev_song');
+          WidgetController.handlePrevSong(this);
         })
 
         // 播放/暂停按钮
@@ -81,7 +80,7 @@ struct PlayerWidgetMedium {
         .borderRadius(22)
         .margin({ left: 12, right: 12 })
         .onClick(() => {
-          this.handleControlAction('play_pause');
+          WidgetController.handlePlayPause(this);
         })
 
         // 下一首按钮
@@ -96,7 +95,7 @@ struct PlayerWidgetMedium {
         .backgroundColor(Color.Transparent)
         .enabled(this.hasNext)
         .onClick(() => {
-          this.handleControlAction('next_song');
+          WidgetController.handleNextSong(this);
         })
       }
       .justifyContent(FlexAlign.Center)
@@ -118,7 +117,7 @@ struct PlayerWidgetMedium {
               .color('#FF007DFF')
               .backgroundColor('#1A007DFF')
               .onClick((event) => {
-                this.handleProgressClick(event);
+                SimpleWidgetController.handleProgressClick(this, event);
               })
           }
           .width('100%')
@@ -150,33 +149,5 @@ struct PlayerWidgetMedium {
     .justifyContent(FlexAlign.SpaceBetween)
   }
 
-  /**
-   * 处理控制操作
-   */
-  private handleControlAction(action: string): void {
-    const actionData: WidgetActionData = {
-      action: action,
-      params: new Object()
-    };
-    postCardAction(this, actionData);
-  }
 
-  /**
-   * 处理进度条点击
-   */
-  private handleProgressClick(event: ClickEvent): void {
-    // 计算点击位置对应的播放进度
-    const clickX = event.x;
-    const progressWidth = event.target.area.width as number;
-    const percentage = (clickX / progressWidth) * 100;
-    
-    const seekParams: SeekParams = {
-      percentage: percentage
-    };
-    const seekData: WidgetActionData = {
-      action: 'seek_to',
-      params: seekParams as Object
-    };
-    postCardAction(this, seekData);
-  }
 }

+ 10 - 16
entry/src/main/ets/widget/pages/PlayerWidgetSmall.ets

@@ -1,5 +1,4 @@
-import { postCardAction } from '../../common/widget/WidgetUtils';
-import { WidgetActionData } from '../../common/widget/WidgetTypes';
+import { WidgetController } from '../../common/widget/WidgetController';
 
 /**
  * 小尺寸播放器卡片 (2x1)
@@ -29,7 +28,8 @@ struct PlayerWidgetSmall {
         .backgroundColor(Color.Transparent)
         .enabled(this.hasPrevious)
         .onClick(() => {
-          this.handleControlAction('prev_song');
+          console.info('PlayerWidgetSmall: Previous button clicked');
+          WidgetController.handlePrevSong(this);
         })
 
         // 播放/暂停按钮
@@ -45,7 +45,9 @@ struct PlayerWidgetSmall {
         .borderRadius(18)
         .margin({ left: 8, right: 8 })
         .onClick(() => {
-          this.handleControlAction('play_pause');
+          // 添加调试日志
+          console.info('PlayerWidgetSmall: Play/Pause button clicked');
+          WidgetController.handlePlayPause(this);
         })
 
         // 下一首按钮
@@ -60,7 +62,8 @@ struct PlayerWidgetSmall {
         .backgroundColor(Color.Transparent)
         .enabled(this.hasNext)
         .onClick(() => {
-          this.handleControlAction('next_song');
+          console.info('PlayerWidgetSmall: Next button clicked');
+          WidgetController.handleNextSong(this);
         })
       }
       .justifyContent(FlexAlign.Center)
@@ -82,7 +85,7 @@ struct PlayerWidgetSmall {
       .alignItems(HorizontalAlign.Start)
       .justifyContent(FlexAlign.Center)
       .onClick(() => {
-        this.handleControlAction('open_player');
+        WidgetController.handleOpenPlayer(this);
       })
     }
     .width('100%')
@@ -94,14 +97,5 @@ struct PlayerWidgetSmall {
     .alignItems(VerticalAlign.Center)
   }
 
-  /**
-   * 处理控制操作
-   */
-  private handleControlAction(action: string): void {
-    const actionData: WidgetActionData = {
-      action: action,
-      params: new Object()
-    };
-    postCardAction(this, actionData);
-  }
+
 }

+ 38 - 0
entry/src/main/resources/base/profile/form_config.json

@@ -56,6 +56,44 @@
       "supportDimensions": [
         "4*4"
       ]
+    },
+    {
+      "name": "PlayerWidgetSmallTest",
+      "description": "测试版小尺寸播放器卡片",
+      "src": "./ets/widget/pages/PlayerWidgetSmallTest.ets",
+      "uiSyntax": "arkts",
+      "window": {
+        "designWidth": 720,
+        "autoDesignWidth": true
+      },
+      "colorMode": "auto",
+      "isDefault": false,
+      "updateEnabled": true,
+      "scheduledUpdateTime": "10:30",
+      "updateDuration": 1,
+      "defaultDimension": "1*2",
+      "supportDimensions": [
+        "1*2"
+      ]
+    },
+    {
+      "name": "PlayerWidgetSimpleTest",
+      "description": "简化测试版播放器卡片",
+      "src": "./ets/widget/pages/PlayerWidgetSimpleTest.ets",
+      "uiSyntax": "arkts",
+      "window": {
+        "designWidth": 720,
+        "autoDesignWidth": true
+      },
+      "colorMode": "auto",
+      "isDefault": false,
+      "updateEnabled": true,
+      "scheduledUpdateTime": "10:30",
+      "updateDuration": 1,
+      "defaultDimension": "1*2",
+      "supportDimensions": [
+        "1*2"
+      ]
     }
   ]
 }