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

+ 127 - 118
entry/src/main/ets/common/widget/FormLayoutManager.ets

@@ -32,7 +32,7 @@ export class FormLayoutManager {
    * @returns 适配后的格式化数据
    */
   public adaptDataForSize(widgetData: WidgetData, size: WidgetSize): FormattedWidgetData {
-    hilog.info(0x0000, TAG, `Adapting data for size: ${size}`);
+    hilog.info(0x0000, TAG, `Adapting data for size: ${size}, coverImagePath: ${widgetData.currentSong.coverImagePath}`);
 
     const baseData = this.formatBaseData(widgetData);
     
@@ -49,6 +49,127 @@ export class FormLayoutManager {
     }
   }
 
+  /**
+   * 格式化基础数据
+   */
+  private formatBaseData(data: WidgetData): FormattedWidgetData {
+    hilog.info(0x0000, TAG, `Formatting base data: coverImagePath=${data.currentSong.coverImagePath}`);
+    
+    return {
+      // 播放状态
+      isPlaying: data.playState.isPlaying,
+      isPaused: data.playState.isPaused,
+      isLoading: data.playState.isLoading,
+      
+      // 歌曲信息
+      songTitle: this.truncateText(data.currentSong.title, 30),
+      songArtist: this.truncateText(data.currentSong.artist, 20),
+      songAlbum: this.truncateText(data.currentSong.album, 20),
+      coverImage: data.currentSong.coverImagePath || '',
+      
+      // 播放进度
+      currentTime: data.progress.currentTimeText,
+      totalTime: data.progress.totalTimeText,
+      progressPercentage: data.progress.percentage,
+      
+      // 控制按钮状态
+      hasNext: data.playlist.hasNext,
+      hasPrevious: data.playlist.hasPrevious,
+      
+      // 卡片配置
+      showProgress: data.config.showProgress,
+      showCover: data.config.showCover,
+      widgetSize: data.config.size as string,
+      
+      // 时间戳用于强制更新
+      timestamp: Date.now()
+    };
+  }
+
+  /**
+   * 适配小尺寸卡片
+   */
+  private adaptForSmallWidget(baseData: FormattedWidgetData, widgetData: WidgetData): FormattedWidgetData {
+    return {
+      isPlaying: baseData.isPlaying,
+      isPaused: baseData.isPaused,
+      isLoading: baseData.isLoading,
+      songTitle: this.truncateText(widgetData.currentSong.title, 15),
+      songArtist: this.truncateText(widgetData.currentSong.artist, 12),
+      songAlbum: baseData.songAlbum,
+      coverImage: baseData.coverImage,
+      currentTime: baseData.currentTime,
+      totalTime: baseData.totalTime,
+      progressPercentage: baseData.progressPercentage,
+      hasNext: baseData.hasNext,
+      hasPrevious: baseData.hasPrevious,
+      showProgress: false,
+      showCover: false,
+      widgetSize: baseData.widgetSize,
+      timestamp: baseData.timestamp
+    };
+  }
+
+  /**
+   * 适配中等尺寸卡片
+   */
+  private adaptForMediumWidget(baseData: FormattedWidgetData, widgetData: WidgetData): FormattedWidgetData {
+    hilog.info(0x0000, TAG, `Adapting for medium widget: coverImage=${baseData.coverImage}`);
+    
+    return {
+      isPlaying: baseData.isPlaying,
+      isPaused: baseData.isPaused,
+      isLoading: baseData.isLoading,
+      songTitle: this.truncateText(widgetData.currentSong.title, 25),
+      songArtist: this.truncateText(widgetData.currentSong.artist, 18),
+      songAlbum: baseData.songAlbum,
+      coverImage: widgetData.currentSong.coverImagePath || '', // 确保coverImage被正确传递
+      currentTime: baseData.currentTime,
+      totalTime: baseData.totalTime,
+      progressPercentage: baseData.progressPercentage,
+      hasNext: baseData.hasNext,
+      hasPrevious: baseData.hasPrevious,
+      showProgress: false,
+      showCover: true,
+      widgetSize: baseData.widgetSize,
+      timestamp: baseData.timestamp
+    };
+  }
+
+  /**
+   * 适配大尺寸卡片
+   */
+  private adaptForLargeWidget(baseData: FormattedWidgetData, widgetData: WidgetData): FormattedWidgetData {
+    return {
+      isPlaying: baseData.isPlaying,
+      isPaused: baseData.isPaused,
+      isLoading: baseData.isLoading,
+      songTitle: this.truncateText(widgetData.currentSong.title, 35),
+      songArtist: this.truncateText(widgetData.currentSong.artist, 25),
+      songAlbum: baseData.songAlbum,
+      coverImage: baseData.coverImage,
+      currentTime: baseData.currentTime,
+      totalTime: baseData.totalTime,
+      progressPercentage: baseData.progressPercentage,
+      hasNext: baseData.hasNext,
+      hasPrevious: baseData.hasPrevious,
+      showProgress: true,
+      showCover: true,
+      widgetSize: baseData.widgetSize,
+      timestamp: baseData.timestamp
+    };
+  }
+
+  /**
+   * 截断文本
+   */
+  private truncateText(text: string, maxLength: number): string {
+    if (!text || text.length <= maxLength) {
+      return text || '';
+    }
+    return text.substring(0, maxLength - 1) + '…';
+  }
+
   /**
    * 获取卡片尺寸对应的页面路径
    * @param size 卡片尺寸
@@ -95,29 +216,26 @@ export class FormLayoutManager {
 
     switch (size) {
       case WidgetSize.SMALL:
-        const smallConfig: WidgetConfig = {
+        return {
           size: baseConfig.size,
           theme: baseConfig.theme,
           showProgress: false,
           showCover: false
         };
-        return smallConfig;
       case WidgetSize.MEDIUM:
-        const mediumConfig: WidgetConfig = {
+        return {
           size: baseConfig.size,
           theme: baseConfig.theme,
-          showProgress: true,
-          showCover: false
+          showProgress: false,
+          showCover: true
         };
-        return mediumConfig;
       case WidgetSize.LARGE:
-        const largeConfig: WidgetConfig = {
+        return {
           size: baseConfig.size,
           theme: baseConfig.theme,
           showProgress: true,
           showCover: true
         };
-        return largeConfig;
       default:
         return baseConfig;
     }
@@ -230,113 +348,4 @@ export class FormLayoutManager {
         return this.getResponsiveLayoutParams(WidgetSize.MEDIUM);
     }
   }
-
-  /**
-   * 格式化基础数据
-   */
-  private formatBaseData(widgetData: WidgetData): FormattedWidgetData {
-    return {
-      isPlaying: widgetData.playState.isPlaying,
-      isPaused: widgetData.playState.isPaused,
-      isLoading: widgetData.playState.isLoading,
-      songTitle: widgetData.currentSong.title || '暂无播放',
-      songArtist: widgetData.currentSong.artist || '未知艺术家',
-      songAlbum: widgetData.currentSong.album || '未知专辑',
-      coverImage: widgetData.currentSong.coverImagePath || '',
-      currentTime: widgetData.progress.currentTimeText || '00:00',
-      totalTime: widgetData.progress.totalTimeText || '00:00',
-      progressPercentage: widgetData.progress.percentage || 0,
-      hasNext: widgetData.playlist.hasNext,
-      hasPrevious: widgetData.playlist.hasPrevious,
-      showProgress: widgetData.config.showProgress,
-      showCover: widgetData.config.showCover,
-      widgetSize: widgetData.config.size.toString(),
-      timestamp: Date.now()
-    };
-  }
-
-  /**
-   * 适配小尺寸卡片数据
-   */
-  private adaptForSmallWidget(baseData: FormattedWidgetData, widgetData: WidgetData): FormattedWidgetData {
-    const result: FormattedWidgetData = {
-      isPlaying: baseData.isPlaying,
-      isPaused: baseData.isPaused,
-      isLoading: baseData.isLoading,
-      songTitle: this.truncateText(baseData.songTitle, 20), // 小卡片只显示歌曲标题,如果标题过长则截断
-      songArtist: baseData.songArtist,
-      songAlbum: baseData.songAlbum,
-      coverImage: baseData.coverImage,
-      currentTime: baseData.currentTime,
-      totalTime: baseData.totalTime,
-      progressPercentage: baseData.progressPercentage,
-      hasNext: baseData.hasNext,
-      hasPrevious: baseData.hasPrevious,
-      showProgress: false,
-      showCover: false,
-      widgetSize: WidgetSize.SMALL,
-      timestamp: baseData.timestamp
-    };
-    return result;
-  }
-
-  /**
-   * 适配中等尺寸卡片数据
-   */
-  private adaptForMediumWidget(baseData: FormattedWidgetData, widgetData: WidgetData): FormattedWidgetData {
-    const result: FormattedWidgetData = {
-      isPlaying: baseData.isPlaying,
-      isPaused: baseData.isPaused,
-      isLoading: baseData.isLoading,
-      songTitle: this.truncateText(baseData.songTitle, 30), // 中等卡片显示更多信息,但仍需要适当截断
-      songArtist: this.truncateText(baseData.songArtist, 25),
-      songAlbum: this.truncateText(baseData.songAlbum, 25),
-      coverImage: baseData.coverImage,
-      currentTime: baseData.currentTime,
-      totalTime: baseData.totalTime,
-      progressPercentage: baseData.progressPercentage,
-      hasNext: baseData.hasNext,
-      hasPrevious: baseData.hasPrevious,
-      showProgress: true,
-      showCover: false,
-      widgetSize: WidgetSize.MEDIUM,
-      timestamp: baseData.timestamp
-    };
-    return result;
-  }
-
-  /**
-   * 适配大尺寸卡片数据
-   */
-  private adaptForLargeWidget(baseData: FormattedWidgetData, widgetData: WidgetData): FormattedWidgetData {
-    const result: FormattedWidgetData = {
-      isPlaying: baseData.isPlaying,
-      isPaused: baseData.isPaused,
-      isLoading: baseData.isLoading,
-      songTitle: this.truncateText(baseData.songTitle, 40), // 大卡片可以显示完整信息
-      songArtist: this.truncateText(baseData.songArtist, 35),
-      songAlbum: this.truncateText(baseData.songAlbum, 35),
-      coverImage: baseData.coverImage,
-      currentTime: baseData.currentTime,
-      totalTime: baseData.totalTime,
-      progressPercentage: baseData.progressPercentage,
-      hasNext: baseData.hasNext,
-      hasPrevious: baseData.hasPrevious,
-      showProgress: true,
-      showCover: true,
-      widgetSize: WidgetSize.LARGE,
-      timestamp: baseData.timestamp
-    };
-    return result;
-  }
-
-  /**
-   * 截断文本
-   */
-  private truncateText(text: string, maxLength: number): string {
-    if (!text || text.length <= maxLength) {
-      return text;
-    }
-    return text.substring(0, maxLength - 3) + '...';
-  }
 }

+ 0 - 203
entry/src/main/ets/common/widget/WidgetDataFlowTest.ets

@@ -1,203 +0,0 @@
-import { hilog } from '@kit.PerformanceAnalysisKit';
-import { PlayerControlService } from './PlayerControlService';
-import { AvSessionWidgetListener } from './AvSessionWidgetListener';
-import { WidgetDataManager } from './WidgetDataManager';
-import { WidgetData, WidgetSize, WidgetTheme } from './WidgetTypes';
-
-const TAG = 'WidgetDataFlowTest';
-
-/**
- * 卡片数据流测试工具
- * 用于调试和验证数据流是否正常工作
- */
-export class WidgetDataFlowTest {
-  private playerControlService: PlayerControlService;
-  private avSessionListener: AvSessionWidgetListener;
-  private widgetDataManager: WidgetDataManager;
-
-  constructor() {
-    this.playerControlService = new PlayerControlService();
-    this.avSessionListener = AvSessionWidgetListener.getInstance();
-    this.widgetDataManager = new WidgetDataManager();
-  }
-
-  /**
-   * 测试数据流
-   */
-  public async testDataFlow(): Promise<void> {
-    hilog.info(0x0000, TAG, '🔍 Starting widget data flow test...');
-
-    // 1. 测试 AvSession 监听器
-    await this.testAvSessionListener();
-
-    // 2. 测试 PlayerControlService
-    await this.testPlayerControlService();
-
-    // 3. 测试 WidgetDataManager
-    await this.testWidgetDataManager();
-
-    // 4. 测试端到端数据流
-    await this.testEndToEndFlow();
-
-    hilog.info(0x0000, TAG, '✅ Widget data flow test completed');
-  }
-
-  /**
-   * 测试 AvSession 监听器
-   */
-  private async testAvSessionListener(): Promise<void> {
-    hilog.info(0x0000, TAG, '📡 Testing AvSession listener...');
-
-    const testData = this.createTestWidgetData();
-
-    // 注册监听器
-    this.avSessionListener.addStateListener((data: WidgetData) => {
-      hilog.info(0x0000, TAG, `✅ AvSession listener received data: isPlaying=${data.playState.isPlaying}, title=${data.currentSong.title}`);
-    });
-
-    // 更新数据
-    this.avSessionListener.updateWidgetData(testData);
-
-    // 获取当前数据
-    const currentData = this.avSessionListener.getCurrentWidgetData();
-    hilog.info(0x0000, TAG, `📊 AvSession current data: hasNext=${currentData.playlist.hasNext}, hasPrevious=${currentData.playlist.hasPrevious}`);
-  }
-
-  /**
-   * 测试 PlayerControlService
-   */
-  private async testPlayerControlService(): Promise<void> {
-    hilog.info(0x0000, TAG, '🎮 Testing PlayerControlService...');
-
-    // 注册监听器
-    this.playerControlService.registerStateListener((data: WidgetData) => {
-      hilog.info(0x0000, TAG, `✅ PlayerControlService listener received data: isPlaying=${data.playState.isPlaying}, title=${data.currentSong.title}`);
-    });
-
-    // 获取当前状态
-    const currentState = await this.playerControlService.getCurrentPlayState();
-    hilog.info(0x0000, TAG, `📊 PlayerControlService current state: hasNext=${currentState.playlist.hasNext}, hasPrevious=${currentState.playlist.hasPrevious}`);
-  }
-
-  /**
-   * 测试 WidgetDataManager
-   */
-  private async testWidgetDataManager(): Promise<void> {
-    hilog.info(0x0000, TAG, '📋 Testing WidgetDataManager...');
-
-    const testFormId = 'test_form_123';
-    const testData = this.createTestWidgetData();
-
-    // 保存数据
-    await this.widgetDataManager.saveWidgetData(testFormId, testData);
-    hilog.info(0x0000, TAG, `💾 Test data saved for form: ${testFormId}`);
-
-    // 读取数据
-    const retrievedData = await this.widgetDataManager.getWidgetData(testFormId);
-    hilog.info(0x0000, TAG, `📖 Test data retrieved: title=${retrievedData.currentSong.title}, hasNext=${retrievedData.playlist.hasNext}`);
-
-    // 模拟更新卡片(不会真正更新,因为formId是测试用的)
-    try {
-      await this.widgetDataManager.updateWidget(testFormId, testData);
-      hilog.info(0x0000, TAG, `🔄 Mock widget update completed for: ${testFormId}`);
-    } catch (error) {
-      hilog.error(0x0000, TAG, `❌ Widget update failed (expected for test): ${error}`);
-    }
-
-    // 清理测试数据
-    await this.widgetDataManager.removeWidgetData(testFormId);
-    hilog.info(0x0000, TAG, `🗑️ Test data cleaned up for form: ${testFormId}`);
-  }
-
-  /**
-   * 测试端到端数据流
-   */
-  private async testEndToEndFlow(): Promise<void> {
-    hilog.info(0x0000, TAG, '🔄 Testing end-to-end data flow...');
-
-    let receivedByPlayerControl = false;
-    let receivedByAvSession = false;
-
-    // 注册 PlayerControlService 监听器
-    this.playerControlService.registerStateListener((data: WidgetData) => {
-      receivedByPlayerControl = true;
-      hilog.info(0x0000, TAG, `✅ End-to-end: PlayerControlService received data`);
-    });
-
-    // 注册 AvSession 监听器
-    this.avSessionListener.addStateListener((data: WidgetData) => {
-      receivedByAvSession = true;
-      hilog.info(0x0000, TAG, `✅ End-to-end: AvSession received data`);
-    });
-
-    // 模拟数据更新
-    const testData = this.createTestWidgetData();
-    this.avSessionListener.updateWidgetData(testData);
-
-    // 检查结果
-    setTimeout(() => {
-      hilog.info(0x0000, TAG, `📊 End-to-end test results:`);
-      hilog.info(0x0000, TAG, `   PlayerControlService received: ${receivedByPlayerControl}`);
-      hilog.info(0x0000, TAG, `   AvSession received: ${receivedByAvSession}`);
-      
-      if (receivedByPlayerControl && receivedByAvSession) {
-        hilog.info(0x0000, TAG, `✅ End-to-end data flow is working correctly!`);
-      } else {
-        hilog.warn(0x0000, TAG, `⚠️ End-to-end data flow has issues!`);
-      }
-    }, 1000);
-  }
-
-  /**
-   * 创建测试用的 WidgetData
-   */
-  private createTestWidgetData(): WidgetData {
-    return {
-      playState: {
-        isPlaying: true,
-        isPaused: false,
-        isLoading: false
-      },
-      currentSong: {
-        id: 'test_song_123',
-        title: '测试歌曲',
-        artist: '测试艺术家',
-        album: '测试专辑',
-        coverImagePath: '/test/cover.jpg',
-        duration: 240
-      },
-      progress: {
-        currentPosition: 60,
-        duration: 240,
-        percentage: 25,
-        currentTimeText: '01:00',
-        totalTimeText: '04:00'
-      },
-      playlist: {
-        hasNext: true,
-        hasPrevious: true,
-        currentIndex: 1,
-        totalCount: 5
-      },
-      config: {
-        size: WidgetSize.MEDIUM,
-        theme: WidgetTheme.AUTO,
-        showProgress: true,
-        showCover: true
-      }
-    };
-  }
-
-  /**
-   * 打印当前所有监听器状态
-   */
-  public printListenerStatus(): void {
-    hilog.info(0x0000, TAG, '📊 Current listener status:');
-    hilog.info(0x0000, TAG, `   PlayerControlService listeners: Available`);
-    hilog.info(0x0000, TAG, `   AvSession listeners: Available`);
-    
-    // 获取当前数据
-    const avSessionData = this.avSessionListener.getCurrentWidgetData();
-    hilog.info(0x0000, TAG, `   Current AvSession data: isPlaying=${avSessionData.playState.isPlaying}, title=${avSessionData.currentSong.title}`);
-  }
-}

+ 6 - 6
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -203,7 +203,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
       // 根据卡片尺寸适配数据
       const adaptedData = this.layoutManager.adaptDataForSize(data, size);
       
-      hilog.info(0x0000, TAG, `Heanup widget ${formId} calling formProvider.updateForm with isPlaying=${adaptedData.isPlaying}, hasNext=${adaptedData.hasNext}, hasPrevious=${adaptedData.hasPrevious}`);
+      hilog.info(0x0000, TAG, `Heanup widget ${formId} calling formProvider.updateForm with isPlaying=${adaptedData.isPlaying}, hasNext=${adaptedData.hasNext}, hasPrevious=${adaptedData.hasPrevious}, coverImage=${adaptedData.coverImage || 'empty'}`);
       
       // 直接使用系统API更新卡片
       const formData = formBindingData.createFormBindingData(adaptedData);
@@ -346,8 +346,8 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
 
     // 确保widget已注册到GlobalWidgetManager
     if (!this.globalWidgetManager.hasWidget(formId)) {
-      hilog.info(0x0000, TAG, `Heanup EntryFormAbility widget ${formId} not registered in onUpdateForm, registering as LARGE size`);
-      this.globalWidgetManager.registerWidget(formId, 'large' as WidgetSize);
+      hilog.info(0x0000, TAG, `Heanup EntryFormAbility widget ${formId} not registered in onUpdateForm, registering as MEDIUM size`);
+      this.globalWidgetManager.registerWidget(formId, 'medium' as WidgetSize);
     }
 
     // 只更新指定的卡片,避免重复更新
@@ -418,9 +418,9 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
 
     // 确保widget已注册到GlobalWidgetManager
     if (!this.globalWidgetManager.hasWidget(formId)) {
-      hilog.info(0x0000, TAG, `Heanup EntryFormAbility [${processId}] widget ${formId} not registered, registering as LARGE size`);
-      // 默认注册为LARGE尺寸,实际尺寸可以后续检测
-      this.globalWidgetManager.registerWidget(formId, 'large' as WidgetSize);
+      hilog.info(0x0000, TAG, `Heanup EntryFormAbility [${processId}] widget ${formId} not registered, registering as MEDIUM size`);
+      // 默认注册为MEDIUM尺寸,这样2*4卡片就能正确使用medium适配
+      this.globalWidgetManager.registerWidget(formId, 'medium' as WidgetSize);
     }
 
     try {

+ 146 - 115
entry/src/main/ets/widget/pages/PlayerWidgetMedium.ets

@@ -1,17 +1,45 @@
 /**
- * 小尺寸播放器卡片 (2x1)
- * 显示基本播放控制和歌曲名称
+ * 中等尺寸播放器卡片 (2x4)
+ * 显示专辑封面、歌曲信息和播放控制
  * 需求: 5.1, 1.4, 1.5
  */
-@Entry
+
+// 定义对齐规则
+const SingerAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
+  'top': { 'anchor': 'musicTitle', 'align': VerticalAlign.Bottom },
+  'left': { 'anchor': 'musicCover', 'align': HorizontalAlign.End }
+};
+
+const CoverAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
+  'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start },
+  'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }
+};
+
+const TitleAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
+  'left': { 'anchor': 'musicCover', 'align': HorizontalAlign.End },
+  'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }
+};
+
+const PlayControlAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
+  'bottom': { 'anchor': '__container__', 'align': VerticalAlign.Bottom },
+  'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start },
+  'right': { 'anchor': '__container__', 'align': HorizontalAlign.End }
+};
+
+let storageUpdateCall = new LocalStorage();
+
+@Entry(storageUpdateCall)
 @Component
-struct PlayerWidgetSmall {
+struct PlayerWidgetMedium {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
-  @LocalStorageProp('songTitle') songTitle: string = '暂无播放';
+  @LocalStorageProp('songTitle') songTitle: string = 'Dream It Possible';
+  @LocalStorageProp('songArtist') songArtist: string = 'Delacey';
+  @LocalStorageProp('coverImage') coverImage: string = '';
   @LocalStorageProp('hasNext') hasNext: boolean = false;
   @LocalStorageProp('hasPrevious') hasPrevious: boolean = false;
   @LocalStorageProp('isLoading') isLoading: boolean = false;
+  @LocalStorageProp('imageColorHex') imageColorHex: string = '2A2A2A';
 
   /**
    * 获取按钮透明度
@@ -47,73 +75,117 @@ struct PlayerWidgetSmall {
     return this.songTitle;
   }
 
+  /**
+   * 格式化艺术家显示
+   */
+  private getDisplayArtist(): string {
+    if (!this.songArtist || this.songArtist.trim() === '') {
+      return '未知艺术家';
+    }
+    return this.songArtist;
+  }
+
+  /**
+   * 获取专辑封面
+   */
+  private getCoverImage(): Resource {
+    // 如果有封面图片,使用封面图片,否则使用默认图片
+    if (this.coverImage && this.coverImage.trim() !== '') {
+      return $rawfile(this.coverImage);
+    }
+    return $r('app.media.ic_avatar4'); // 使用默认专辑封面
+  }
+
   build() {
-    Row() {
+    RelativeContainer() {
+      // 歌曲标题
+      Text(this.getDisplayTitle())
+        .fontSize(16)
+        .fontWeight(FontWeight.Bold)
+        .width('60%')
+        .fontColor(Color.White)
+        .textOverflow({ overflow: TextOverflow.Ellipsis })
+        .maxLines(1)
+        .alignRules(TitleAlignRules)
+        .margin({ left: 16, top: 8 })
+        .id('musicTitle')
+
+      // 艺术家名称
+      Text(this.getDisplayArtist())
+        .fontSize(12)
+        .fontColor('#CCFFFFFF')
+        .fontWeight(FontWeight.Normal)
+        .maxLines(1)
+        .alignRules(SingerAlignRules)
+        .margin({ left: 16, top: 2 })
+        .id('singerText')
+
+      // 专辑封面
+      Stack({ alignContent: Alignment.Center }) {
+        // 黑胶唱片背景
+        Image($r('app.media.ic_music_bg_mini'))
+          .height(88)
+          .width(88)
+        
+        // 专辑封面
+        Button()
+          .backgroundImage(this.getCoverImage())
+          .backgroundImageSize(ImageSize.Cover)
+          .height(58)
+          .width(58)
+          .borderRadius(29)
+      }
+      .alignRules(CoverAlignRules)
+      .id('musicCover')
+      .onClick(() => {
+        console.info('Heanup PlayerWidgetMedium: Album cover clicked');
+        postCardAction(this, {
+          'action': 'router',
+          'abilityName': 'EntryAbility'
+        });
+      })
+
       // 播放控制按钮区域
       Row() {
         // 上一首按钮
         Button() {
-          Image($r('app.media.ic_previous'))
-            .width(16)
-            .height(16)
-            .fillColor(this.getButtonColor(this.hasPrevious))
+          Image($r('app.media.hm_previous'))
+            .width(20)
+            .height(20)
+            .fillColor('#E5FFFFFF')
         }
-        .width(32)
-        .height(32)
+        .width(40)
+        .height(40)
         .backgroundColor(Color.Transparent)
-        .enabled(!this.isLoading)  // 临时启用按钮进行测试
-        .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
-        .stateStyles({
-          pressed: {
-            .scale({ x: 0.95, y: 0.95 })
-            .opacity(0.8)
-          },
-          normal: {
-            .scale({ x: 1.0, y: 1.0 })
-            .opacity(this.getButtonOpacity(this.hasPrevious))
-          }
-        })
+        .enabled(!this.isLoading && this.hasPrevious)
+        .opacity(this.hasPrevious ? 1.0 : 0.5)
         .onClick(() => {
-          console.info(`Heanup PlayerWidgetMedium: Previous button clicked, hasPrevious=${this.hasPrevious}, isLoading=${this.isLoading}`);
-          if (!this.isLoading) {
-            console.info('Heanup PlayerWidgetMedium: Previous button action sent');
+          console.info(`Heanup PlayerWidgetMedium: Previous button clicked`);
+          if (!this.isLoading && this.hasPrevious) {
             postCardAction(this, {
               'action': 'message',
               'params': {
                 "func":"prev_song"
               }
             });
-          } else {
-            console.info('Heanup PlayerWidgetMedium: Previous button disabled due to loading');
           }
         })
 
         // 播放/暂停按钮
         Button() {
-          Image(this.getPlayButtonIcon())
-            .width(20)
-            .height(20)
-            .fillColor($r('sys.color.comp_background_list_card'))
+          SymbolGlyph(this.isPlaying ? $r('sys.symbol.pause_round_triangle_fill') : $r('sys.symbol.play_round_triangle_fill'))
+            .fontSize(36)
+            .symbolEffect(new ReplaceSymbolEffect(EffectScope.WHOLE), true)
+            .fontColor(['#E5FFFFFF'])
         }
-        .width(36)
-        .height(36)
-        .backgroundColor(this.isLoading ? '#99007DFF' : '#FF007DFF')
-        .borderRadius(18)
-        .margin({ left: 8, right: 8 })
+        .width(48)
+        .height(48)
+        .backgroundColor(Color.Transparent)
+        .margin({ left: 20, right: 20 })
         .enabled(!this.isLoading)
-        .stateStyles({
-          pressed: {
-            .scale({ x: 0.95, y: 0.95 })
-            .backgroundColor('#CC007DFF')
-          },
-          normal: {
-            .scale({ x: 1.0, y: 1.0 })
-            .backgroundColor(this.isLoading ? '#99007DFF' : '#FF007DFF')
-          }
-        })
         .onClick(() => {
+          console.info('Heanup PlayerWidgetMedium: Play/Pause button clicked');
           if (!this.isLoading) {
-            console.info('Heanup PlayerWidgetSmall: Play/Pause button clicked');
             postCardAction(this, {
               'action': 'message',
               'params': {
@@ -125,88 +197,47 @@ struct PlayerWidgetSmall {
 
         // 下一首按钮
         Button() {
-          Image($r('app.media.ic_next'))
-            .width(16)
-            .height(16)
-            .fillColor(this.getButtonColor(this.hasNext))
+          Image($r('app.media.hm_next'))
+            .width(20)
+            .height(20)
+            .fillColor('#E5FFFFFF')
         }
-        .width(32)
-        .height(32)
+        .width(40)
+        .height(40)
         .backgroundColor(Color.Transparent)
-        .enabled(!this.isLoading && this.hasNext)  // 确保按钮状态正确
-        .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
-        .stateStyles({
-          pressed: {
-            .scale({ x: 0.95, y: 0.95 })
-            .opacity(0.8)
-          },
-          normal: {
-            .scale({ x: 1.0, y: 1.0 })
-            .opacity(this.getButtonOpacity(this.hasNext))
-          }
-        })
+        .enabled(!this.isLoading && this.hasNext)
+        .opacity(this.hasNext ? 1.0 : 0.5)
         .onClick(() => {
-          console.info(`Heanup PlayerWidgetMedium: Next button clicked, hasNext=${this.hasNext}, isLoading=${this.isLoading}`);
+          console.info(`Heanup PlayerWidgetMedium: Next button clicked`);
           if (!this.isLoading && this.hasNext) {
-            console.info('Heanup PlayerWidgetMedium: Next button action sent');
             postCardAction(this, {
               'action': 'message',
               'params': {
                 "func":"next_song"
               }
             });
-          } else {
-            console.info('Heanup PlayerWidgetMedium: Next button disabled due to loading or no next song');
           }
         })
       }
+      .width('100%')
       .justifyContent(FlexAlign.Center)
-      .alignItems(VerticalAlign.Center)
-
-      // 歌曲信息区域
-      Column() {
-        Text(this.getDisplayTitle())
-          .fontSize(14)
-          .fontColor(this.songTitle === '暂无播放' ? '#99000000' : '#E6000000')
-          .fontWeight(this.songTitle === '暂无播放' ? FontWeight.Normal : FontWeight.Medium)
-          .maxLines(1)
-          .textOverflow({ overflow: TextOverflow.Ellipsis })
-          .width('100%')
-          .textAlign(TextAlign.Start)
-      }
-      .layoutWeight(1)
-      .margin({ left: 12 })
-      .alignItems(HorizontalAlign.Start)
-      .justifyContent(FlexAlign.Center)
-      .stateStyles({
-        pressed: {
-          .opacity(0.8)
-        },
-        normal: {
-          .opacity(1.0)
-        }
-      })
-      .onClick(() => {
-        console.info('Heanup PlayerWidgetMedium: Song info area clicked');
-        postCardAction(this, {
-          'action': 'router',
-          'abilityName': 'EntryAbility'
-        });
-      })
+      .alignRules(PlayControlAlignRules)
+      .id('playControls')
     }
-    .width('100%')
     .height('100%')
-    .padding({ left: 16, right: 16, top: 8, bottom: 8 })
-    .backgroundColor('#FFFFFF')
-    .borderRadius(12)
-    .justifyContent(FlexAlign.Start)
-    .alignItems(VerticalAlign.Center)
-    .shadow({
-      radius: 8,
-      color: '#1A000000',
-      offsetX: 0,
-      offsetY: 2
+    .width('100%')
+    .linearGradient({
+      direction: GradientDirection.Bottom,
+      repeating: false,
+      colors: [[`#ff${this.imageColorHex}`, 0.0], [`#ff${this.imageColorHex}`, 0.5], [`#ff${this.imageColorHex}`, 1.0]]
+    })
+    .padding(12)
+    .onClick(() => {
+      console.info('Heanup PlayerWidgetMedium: Container clicked, jumping to main app');
+      postCardAction(this, {
+        'action': 'router',
+        'abilityName': 'EntryAbility'
+      });
     })
-    // 移除手势支持,form应用不支持复杂交互
   }
 }