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

+ 1 - 1
entry/src/main/ets/common/widget/AvSessionWidgetListener.ets

@@ -90,7 +90,7 @@ export class AvSessionWidgetListener {
    */
   public getCurrentWidgetData(): WidgetData {
     if (this.lastWidgetData) {
-      hilog.info(0x0000, TAG, `Returning cached widget data: hasNext=${this.lastWidgetData.playlist.hasNext}, hasPrevious=${this.lastWidgetData.playlist.hasPrevious}`);
+      hilog.info(0x0000, TAG, `Returning cached widget data: hasNext=${this.lastWidgetData.playlist.hasNext}, hasPrevious=${this.lastWidgetData.playlist.hasPrevious}, currentIndex=${this.lastWidgetData.playlist.currentIndex}, totalCount=${this.lastWidgetData.playlist.totalCount}`);
       return this.lastWidgetData;
     }
     

+ 97 - 24
entry/src/main/ets/common/widget/PlayerControlService.ets

@@ -49,6 +49,7 @@ export class PlayerControlService {
    */
   private async initializeEventListener(): Promise<void> {
     if (this.isListenerRegistered) {
+      hilog.info(0x0000, TAG, 'Event listener already registered');
       return;
     }
 
@@ -62,11 +63,16 @@ export class PlayerControlService {
         ]
       };
 
+      hilog.info(0x0000, TAG, `Subscribing to events: ${subscribeInfo.events.join(', ')}`);
+
       const subscriber = await commonEventManager.createSubscriber(subscribeInfo);
       
       await commonEventManager.subscribe(subscriber, (err, data: commonEventManager.CommonEventData) => {
         if (!err) {
+          hilog.info(0x0000, TAG, `CommonEvent received: ${data.event}`);
           this.handlePlayerStateChange(data);
+        } else {
+          hilog.error(0x0000, TAG, `CommonEvent error: ${JSON.stringify(err)}`);
         }
       });
 
@@ -246,6 +252,8 @@ export class PlayerControlService {
    */
   private handlePlayerStateChange(eventData: commonEventManager.CommonEventData): void {
     try {
+      hilog.info(0x0000, TAG, `CommonEvent received in form process: ${eventData.event}, data: ${eventData.data}`);
+      
       const data = JSON.parse(eventData.data || '{}') as Object;
       let widgetData: WidgetData;
 
@@ -257,16 +265,22 @@ export class PlayerControlService {
         widgetData = this.convertToWidgetData(data);
       }
       
+      hilog.info(0x0000, TAG, `Notifying ${this.stateListeners.length} CommonEvent listeners`);
+      
       // 通知所有监听器
-      this.stateListeners.forEach((listener: (data: WidgetData) => void) => {
+      this.stateListeners.forEach((listener: (data: WidgetData) => void, index: number) => {
         try {
+          hilog.info(0x0000, TAG, `Calling CommonEvent listener ${index}`);
           listener(widgetData);
         } catch (error) {
-          hilog.error(0x0000, TAG, `Error in state listener: ${error}`);
+          hilog.error(0x0000, TAG, `Error in CommonEvent state listener ${index}: ${error}`);
         }
       });
       
-      hilog.info(0x0000, TAG, `Player ${eventData.event} handled`);
+      // 同时更新AvSession监听器的数据,确保数据同步
+      this.avSessionListener.updateWidgetData(widgetData);
+      
+      hilog.info(0x0000, TAG, `Player ${eventData.event} handled, all listeners notified`);
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to handle player state change: ${error}`);
     }
@@ -278,9 +292,10 @@ export class PlayerControlService {
   private updateProgressData(progressData: Object): WidgetData {
     try {
       const data: Record<string, Object> = progressData as Record<string, Object>;
-      const currentData = this.getDefaultWidgetData();
+      // 获取当前缓存的数据,而不是默认数据
+      const currentData = this.avSessionListener.getCurrentWidgetData();
       
-      // 只更新进度相关数据
+      // 只更新进度相关数据,保持其他状态不变
       currentData.progress = {
         currentPosition: (data['currentPosition'] as number) || 0,
         duration: (data['duration'] as number) || 0,
@@ -289,6 +304,11 @@ export class PlayerControlService {
         totalTimeText: (data['totalTimeText'] as string) || '00:00'
       };
       
+      // 更新缓存
+      this.avSessionListener.updateWidgetData(currentData);
+      
+      hilog.info(0x0000, TAG, `Progress updated: ${currentData.progress.percentage.toFixed(1)}%, ${currentData.progress.currentTimeText}/${currentData.progress.totalTimeText}`);
+      
       return currentData;
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to update progress data: ${error}`);
@@ -303,32 +323,79 @@ export class PlayerControlService {
     try {
       const data: Record<string, Object> = playerData as Record<string, Object>;
       
-      return {
+      // 正确解析PlayerStateBroadcastData结构
+      const playState = (data['playState'] as Record<string, Object>) || {};
+      const currentSong = (data['currentSong'] as Record<string, Object>) || {};
+      const progress = (data['progress'] as Record<string, Object>) || {};
+      const playlist = (data['playlist'] as Record<string, Object>) || {};
+      
+      // 检查是否接收到不完整的数据
+      const isPlaylistDataIncomplete = playlist['hasNext'] === undefined || 
+                                     playlist['hasPrevious'] === undefined || 
+                                     playlist['currentIndex'] === undefined || 
+                                     playlist['totalCount'] === undefined;
+      
+      if (isPlaylistDataIncomplete) {
+        hilog.warn(0x0000, TAG, `Received incomplete playlist data, using cached data`);
+        // 如果接收到不完整的数据,返回当前缓存的数据
+        const cachedData = this.avSessionListener.getCurrentWidgetData();
+        
+        // 只更新非playlist的数据,保持playlist数据不变
+        const updatedData: WidgetData = {
+          playState: {
+            isPlaying: (playState['isPlaying'] as boolean) !== undefined ? (playState['isPlaying'] as boolean) : cachedData.playState.isPlaying,
+            isPaused: (playState['isPaused'] as boolean) !== undefined ? (playState['isPaused'] as boolean) : cachedData.playState.isPaused,
+            isLoading: (playState['isLoading'] as boolean) !== undefined ? (playState['isLoading'] as boolean) : cachedData.playState.isLoading
+          },
+          currentSong: {
+            id: (currentSong['id'] as string) || cachedData.currentSong.id,
+            title: (currentSong['title'] as string) || cachedData.currentSong.title,
+            artist: (currentSong['artist'] as string) || cachedData.currentSong.artist,
+            album: (currentSong['album'] as string) || cachedData.currentSong.album,
+            coverImagePath: (currentSong['coverImagePath'] as string) || cachedData.currentSong.coverImagePath,
+            duration: (currentSong['duration'] as number) || cachedData.currentSong.duration
+          },
+          progress: {
+            currentPosition: (progress['currentPosition'] as number) !== undefined ? (progress['currentPosition'] as number) : cachedData.progress.currentPosition,
+            duration: (progress['duration'] as number) !== undefined ? (progress['duration'] as number) : cachedData.progress.duration,
+            percentage: (progress['percentage'] as number) !== undefined ? (progress['percentage'] as number) : cachedData.progress.percentage,
+            currentTimeText: (progress['currentTimeText'] as string) || cachedData.progress.currentTimeText,
+            totalTimeText: (progress['totalTimeText'] as string) || cachedData.progress.totalTimeText
+          },
+          playlist: cachedData.playlist, // 保持缓存的playlist数据
+          config: cachedData.config
+        };
+        
+        hilog.info(0x0000, TAG, `Using cached playlist data: hasNext=${updatedData.playlist.hasNext}, hasPrevious=${updatedData.playlist.hasPrevious}, currentIndex=${updatedData.playlist.currentIndex}, totalCount=${updatedData.playlist.totalCount}`);
+        return updatedData;
+      }
+      
+      const widgetData: WidgetData = {
         playState: {
-          isPlaying: (data['isPlaying'] as boolean) || false,
-          isPaused: (data['isPaused'] as boolean) || true,
-          isLoading: (data['isLoading'] as boolean) || false
+          isPlaying: (playState['isPlaying'] as boolean) || false,
+          isPaused: (playState['isPaused'] as boolean) || true,
+          isLoading: (playState['isLoading'] as boolean) || false
         },
         currentSong: {
-          id: ((data['currentSong'] as Record<string, Object>)?.['id'] as string) || '',
-          title: ((data['currentSong'] as Record<string, Object>)?.['title'] as string) || '暂无播放',
-          artist: ((data['currentSong'] as Record<string, Object>)?.['artist'] as string) || '未知艺术家',
-          album: ((data['currentSong'] as Record<string, Object>)?.['album'] as string) || '未知专辑',
-          coverImagePath: ((data['currentSong'] as Record<string, Object>)?.['coverImagePath'] as string) || '',
-          duration: ((data['currentSong'] as Record<string, Object>)?.['duration'] as number) || 0
+          id: (currentSong['id'] as string) || '',
+          title: (currentSong['title'] as string) || '暂无播放',
+          artist: (currentSong['artist'] as string) || '未知艺术家',
+          album: (currentSong['album'] as string) || '未知专辑',
+          coverImagePath: (currentSong['coverImagePath'] as string) || '',
+          duration: (currentSong['duration'] as number) || 0
         },
         progress: {
-          currentPosition: ((data['progress'] as Record<string, Object>)?.['currentPosition'] as number) || 0,
-          duration: ((data['progress'] as Record<string, Object>)?.['duration'] as number) || 0,
-          percentage: ((data['progress'] as Record<string, Object>)?.['percentage'] as number) || 0,
-          currentTimeText: ((data['progress'] as Record<string, Object>)?.['currentTimeText'] as string) || '00:00',
-          totalTimeText: ((data['progress'] as Record<string, Object>)?.['totalTimeText'] as string) || '00:00'
+          currentPosition: (progress['currentPosition'] as number) || 0,
+          duration: (progress['duration'] as number) || 0,
+          percentage: (progress['percentage'] as number) || 0,
+          currentTimeText: (progress['currentTimeText'] as string) || '00:00',
+          totalTimeText: (progress['totalTimeText'] as string) || '00:00'
         },
         playlist: {
-          hasNext: ((data['playlist'] as Record<string, Object>)?.['hasNext'] as boolean) || false,
-          hasPrevious: ((data['playlist'] as Record<string, Object>)?.['hasPrevious'] as boolean) || false,
-          currentIndex: ((data['playlist'] as Record<string, Object>)?.['currentIndex'] as number) || 0,
-          totalCount: ((data['playlist'] as Record<string, Object>)?.['totalCount'] as number) || 0
+          hasNext: (playlist['hasNext'] as boolean) !== undefined ? (playlist['hasNext'] as boolean) : false,
+          hasPrevious: (playlist['hasPrevious'] as boolean) !== undefined ? (playlist['hasPrevious'] as boolean) : false,
+          currentIndex: (playlist['currentIndex'] as number) !== undefined ? (playlist['currentIndex'] as number) : 0,
+          totalCount: (playlist['totalCount'] as number) !== undefined ? (playlist['totalCount'] as number) : 0
         },
         config: {
           size: 'medium',
@@ -337,6 +404,12 @@ export class PlayerControlService {
           showCover: true
         }
       };
+      
+      // 添加详细的按钮状态调试日志
+      hilog.info(0x0000, TAG, `Raw playlist data: hasNext=${playlist['hasNext']}, hasPrevious=${playlist['hasPrevious']}, currentIndex=${playlist['currentIndex']}, totalCount=${playlist['totalCount']}`);
+      hilog.info(0x0000, TAG, `Converted widget data: isPlaying=${widgetData.playState.isPlaying}, hasNext=${widgetData.playlist.hasNext}, hasPrevious=${widgetData.playlist.hasPrevious}, currentIndex=${widgetData.playlist.currentIndex}, totalCount=${widgetData.playlist.totalCount}, title=${widgetData.currentSong.title}`);
+      
+      return widgetData;
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to convert player data: ${error}`);
       return this.getDefaultWidgetData();

+ 38 - 23
entry/src/main/ets/common/widget/WidgetDataManager.ets

@@ -25,8 +25,10 @@ export class WidgetDataManager {
   private preferencesStore: preferences.Preferences | null = null;
   private dataCache: Map<string, CacheItem> = new Map();
   private lastUpdateTime: number = 0;
+  private context: object | null = null;
 
-  constructor() {
+  constructor(context?: object) {
+    this.context = context || null;
     this.initPreferences();
     this.startCacheCleanup();
   }
@@ -36,8 +38,13 @@ export class WidgetDataManager {
    */
   private async initPreferences(): Promise<void> {
     try {
-      this.preferencesStore = await preferences.getPreferences(getContext(), WIDGET_PREFERENCES_NAME);
-      hilog.info(0x0000, TAG, 'Preferences initialized successfully');
+      if (this.context) {
+        const store = await preferences.getPreferences(this.context as Context, WIDGET_PREFERENCES_NAME);
+        this.preferencesStore = store;
+        hilog.info(0x0000, TAG, 'Preferences initialized successfully with context');
+      } else {
+        hilog.warn(0x0000, TAG, 'No context provided, preferences initialization skipped');
+      }
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to initialize preferences: ${error}`);
     }
@@ -131,16 +138,20 @@ export class WidgetDataManager {
    */
   async updateWidget(formId: string, data: WidgetData | FormattedWidgetData): Promise<void> {
     try {
+      hilog.info(0x0000, TAG, `Updating widget ${formId} with data type check`);
+      
       let formattedData: FormattedWidgetData;
       
       // 检查数据类型,如果已经是格式化数据则直接使用
       if (this.isFormattedWidgetData(data)) {
+        hilog.info(0x0000, TAG, `Data is already formatted for widget ${formId}`);
         formattedData = data as FormattedWidgetData;
         
         // 如果是格式化数据,需要转换回WidgetData进行存储
         const widgetData = this.convertToWidgetData(formattedData);
         await this.saveWidgetData(formId, widgetData);
       } else {
+        hilog.info(0x0000, TAG, `Formatting raw data for widget ${formId}`);
         // 保存原始数据到本地存储
         await this.saveWidgetData(formId, data as WidgetData);
         
@@ -148,6 +159,8 @@ export class WidgetDataManager {
         formattedData = this.formatDataForWidget(data as WidgetData);
       }
       
+      hilog.info(0x0000, TAG, `Final formatted data for ${formId}: isPlaying=${formattedData.isPlaying}, hasNext=${formattedData.hasNext}, hasPrevious=${formattedData.hasPrevious}, title=${formattedData.songTitle}, coverImage=${formattedData.coverImage ? 'present' : 'empty'}, showCover=${formattedData.showCover}`);
+      
       // 创建卡片绑定数据
       const formData = formBindingData.createFormBindingData(formattedData);
       
@@ -209,30 +222,32 @@ export class WidgetDataManager {
    * 格式化数据用于卡片显示
    */
   private formatDataForWidget(data: WidgetData): FormattedWidgetData {
-    // 修复按钮状态:如果有多首歌但按钮状态为false,强制启用
+    hilog.info(0x0000, TAG, `Formatting data for widget: hasNext=${data.playlist.hasNext}, hasPrevious=${data.playlist.hasPrevious}, currentIndex=${data.playlist.currentIndex}, totalCount=${data.playlist.totalCount}`);
+    
+    // 修复按钮状态:基于当前索引和总数重新计算正确的按钮状态
     let hasNext = data.playlist.hasNext;
     let hasPrevious = data.playlist.hasPrevious;
     
-    // 如果总数大于1,但按钮状态都是false,说明状态可能有问题,进行修复
+    hilog.info(0x0000, TAG, `Original button states: hasNext=${hasNext}, hasPrevious=${hasPrevious}, currentIndex=${data.playlist.currentIndex}, totalCount=${data.playlist.totalCount}`);
+    
+    // 如果有播放列表,重新计算按钮状态
     if (data.playlist.totalCount > 1) {
-      if (!hasNext && !hasPrevious) {
-        // 如果当前索引是0,应该有下一首
-        if (data.playlist.currentIndex === 0) {
-          hasNext = true;
-          hasPrevious = false;
-        }
-        // 如果当前索引是最后一个,应该有上一首
-        else if (data.playlist.currentIndex === data.playlist.totalCount - 1) {
-          hasNext = false;
-          hasPrevious = true;
-        }
-        // 如果在中间,应该都有
-        else {
-          hasNext = true;
-          hasPrevious = true;
-        }
+      const correctHasNext = data.playlist.currentIndex < data.playlist.totalCount - 1;
+      const correctHasPrevious = data.playlist.currentIndex > 0;
+      
+      // 如果计算出的状态与当前状态不一致,进行修复
+      if (hasNext !== correctHasNext || hasPrevious !== correctHasPrevious) {
+        hasNext = correctHasNext;
+        hasPrevious = correctHasPrevious;
         hilog.info(0x0000, TAG, `Fixed button states: hasNext=${hasNext}, hasPrevious=${hasPrevious}, currentIndex=${data.playlist.currentIndex}, totalCount=${data.playlist.totalCount}`);
+      } else {
+        hilog.info(0x0000, TAG, `Button states are correct: hasNext=${hasNext}, hasPrevious=${hasPrevious}`);
       }
+    } else if (data.playlist.totalCount <= 1) {
+      // 如果只有一首歌或没有歌,按钮都应该禁用
+      hasNext = false;
+      hasPrevious = false;
+      hilog.info(0x0000, TAG, `Single or no song, buttons disabled: totalCount=${data.playlist.totalCount}`);
     }
     
     const formattedData: FormattedWidgetData = {
@@ -245,7 +260,7 @@ export class WidgetDataManager {
       songTitle: this.truncateText(data.currentSong.title, 20),
       songArtist: this.truncateText(data.currentSong.artist, 15),
       songAlbum: this.truncateText(data.currentSong.album, 15),
-      coverImage: data.currentSong.coverImagePath || '',
+      coverImage: data.currentSong.coverImagePath && data.currentSong.coverImagePath.trim() !== '' ? data.currentSong.coverImagePath : '',
       
       // 播放进度
       currentTime: data.progress.currentTimeText,
@@ -265,7 +280,7 @@ export class WidgetDataManager {
       timestamp: Date.now()
     };
     
-    hilog.info(0x0000, TAG, `Formatted widget data: hasNext=${formattedData.hasNext}, hasPrevious=${formattedData.hasPrevious}, songTitle=${formattedData.songTitle}`);
+    hilog.info(0x0000, TAG, `Formatted widget data: isPlaying=${formattedData.isPlaying}, hasNext=${formattedData.hasNext}, hasPrevious=${formattedData.hasPrevious}, title=${formattedData.songTitle}`);
     return formattedData;
   }
 

+ 146 - 17
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -58,7 +58,7 @@ interface WidgetConfigParams extends Record<string, Object> {
  */
 export default class EntryFormAbility extends FormExtensionAbility
 implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
-  private widgetDataManager: WidgetDataManager = new WidgetDataManager();
+  private widgetDataManager: WidgetDataManager | null = null;
   private playerControlService: PlayerControlService = new PlayerControlService();
   private layoutManager: FormLayoutManager = FormLayoutManager.getInstance();
   private sizeAdapter: WidgetSizeAdapter = WidgetSizeAdapter.getInstance();
@@ -67,11 +67,24 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
   private userPreferencesService: UserPreferencesService = UserPreferencesService.getInstance();
   private formSizeMap: Map<string, WidgetSize> = new Map();
 
+  /**
+   * 初始化服务
+   */
+  private initializeServices(): void {
+    if (!this.widgetDataManager) {
+      this.widgetDataManager = new WidgetDataManager();
+      hilog.info(0x0000, TAG, 'WidgetDataManager initialized');
+    }
+  }
+
   /**
    * 卡片创建时调用
    */
   onAddForm(want: Want): formBindingData.FormBindingData {
     hilog.info(0x0000, TAG, 'onAddForm called');
+    
+    // 初始化服务
+    this.initializeServices();
 
     const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string;
     const formName = want.parameters?.['ohos.extra.param.key.form_name'] as string;
@@ -93,13 +106,67 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
     // 初始化卡片数据
     this.initializeWidget(formId, widgetSize);
 
-    // 获取适配后的初始数据
-    const initialData = this.widgetDataManager.getInitialWidgetData();
+    // 添加数据流测试 - 仅在开发环境中
+    setTimeout(() => {
+      this.testWidgetDataFlow(formId);
+    }, 3000);
+
+    // 获取当前播放状态而不是初始数据
+    this.playerControlService.getCurrentPlayState().then((currentState: WidgetData) => {
+      const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
+      const formData = formBindingData.createFormBindingData(adaptedData);
+      // 立即更新卡片以显示当前状态
+      formProvider.updateForm(formId, formData);
+      hilog.info(0x0000, TAG, `Widget ${formId} initialized with current state`);
+    });
+
+    // 返回初始数据作为临时显示
+    const initialData = this.widgetDataManager?.getInitialWidgetData() || this.getDefaultWidgetData();
     const adaptedData = this.layoutManager.adaptDataForSize(initialData, widgetSize);
 
     return formBindingData.createFormBindingData(adaptedData);
   }
 
+  /**
+   * 获取默认卡片数据
+   */
+  private getDefaultWidgetData(): WidgetData {
+    return {
+      playState: {
+        isPlaying: false,
+        isPaused: true,
+        isLoading: false
+      },
+      currentSong: {
+        id: '',
+        title: '暂无播放',
+        artist: '未知艺术家',
+        album: '未知专辑',
+        coverImagePath: '',
+        duration: 0
+      },
+      progress: {
+        currentPosition: 0,
+        duration: 0,
+        percentage: 0,
+        currentTimeText: '00:00',
+        totalTimeText: '00:00'
+      },
+      playlist: {
+        hasNext: false,
+        hasPrevious: false,
+        currentIndex: 0,
+        totalCount: 0
+      },
+      config: {
+        size: 'medium' as WidgetSize,
+        theme: 'auto' as string,
+        showProgress: true,
+        showCover: true
+      }
+    };
+  }
+
   /**
    * 卡片更新时调用
    */
@@ -108,6 +175,11 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
 
     // 获取最新的播放状态数据
     this.updateWidgetData(formId);
+    
+    // 延迟再次更新,确保数据同步到所有卡片
+    setTimeout((): void => {
+      this.updateAllWidgetsData();
+    }, 200);
   }
 
   /**
@@ -125,7 +197,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
     this.formSizeMap.delete(formId);
 
     // 清理卡片相关数据和配置
-    this.widgetDataManager.removeWidgetData(formId);
+    this.widgetDataManager?.removeWidgetData(formId);
     this.configManager.removeWidgetConfig(formId);
   }
 
@@ -172,7 +244,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
     this.themeSyncService.startThemeSync();
 
     // 更新所有卡片以适应新配置
-    this.widgetDataManager.updateAllWidgets();
+    this.widgetDataManager?.updateAllWidgets();
   }
 
   /**
@@ -242,11 +314,14 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
     try {
       // 注册播放状态监听
       this.playerControlService.registerStateListener((data: WidgetData) => {
+        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}`);
+        
         // 根据卡片尺寸适配数据
         const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
         const adaptedData = this.layoutManager.adaptDataForSize(data, currentSize);
-        this.widgetDataManager.updateWidget(formId, adaptedData);
-        hilog.info(0x0000, TAG, `Widget ${formId} state updated from listener: hasNext=${data.playlist.hasNext}, hasPrevious=${data.playlist.hasPrevious}, totalCount=${data.playlist.totalCount}`);
+        this.widgetDataManager?.updateWidget(formId, adaptedData);
+        
+        hilog.info(0x0000, TAG, `Widget ${formId} updated successfully`);
       });
 
       // 获取当前播放状态
@@ -256,7 +331,6 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
       const personalConfig = await this.configManager.getWidgetConfig(formId, widgetSize);
 
       // 应用尺寸和个性化配置
-      const sizeConfig = this.layoutManager.getSizeDisplayConfig(widgetSize);
       currentState.config = ObjectUtils.assign(currentState.config);
       currentState.config.showProgress = personalConfig.showProgress;
       currentState.config.showCover = personalConfig.showCover;
@@ -264,7 +338,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
 
       // 适配数据到指定尺寸
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
-      await this.widgetDataManager.saveWidgetData(formId, adaptedData);
+      await this.widgetDataManager?.saveWidgetData(formId, adaptedData);
 
       // 立即请求一次最新状态,并多次重试确保获取到真实状态
       setTimeout(() => {
@@ -279,7 +353,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
         this.updateWidgetData(formId);
       }, 5000);
 
-      hilog.info(0x0000, TAG, `Widget ${formId} initialized successfully with size: ${widgetSize}`);
+      hilog.info(0x0000, TAG, `Widget ${formId} initialized successfully with size: ${widgetSize}, listeners registered: PlayerControl + AvSession`);
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to initialize widget ${formId}: ${error}`);
     }
@@ -297,7 +371,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
 
       // 适配数据到当前尺寸
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, currentSize);
-      await this.widgetDataManager.updateWidget(formId, adaptedData);
+      await this.widgetDataManager?.updateWidget(formId, adaptedData);
 
       hilog.info(0x0000, TAG, `Widget ${formId} updated successfully with size: ${currentSize}`);
     } catch (error) {
@@ -305,6 +379,30 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
     }
   }
 
+  /**
+   * 更新所有卡片数据
+   */
+  private async updateAllWidgetsData(): Promise<void> {
+    try {
+      const currentState = await this.playerControlService.getCurrentPlayState();
+      
+      // 遍历所有卡片ID并更新
+      this.formSizeMap.forEach(async (size: WidgetSize, formId: string) => {
+        try {
+          const adaptedData = this.layoutManager.adaptDataForSize(currentState, size);
+          await this.widgetDataManager?.updateWidget(formId, adaptedData);
+          hilog.info(0x0000, TAG, `Widget ${formId} updated in batch with size: ${size}`);
+        } catch (error) {
+          hilog.error(0x0000, TAG, `Failed to update widget ${formId} in batch: ${error}`);
+        }
+      });
+      
+      hilog.info(0x0000, TAG, `Batch update completed for ${this.formSizeMap.size} widgets`);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to batch update widgets: ${error}`);
+    }
+  }
+
   /**
    * 处理卡片事件
    */
@@ -396,10 +494,13 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
           return;
       }
 
-      // 处理完命令后更新卡片状态
+      // 处理完命令后立即更新当前卡片状态
+      this.updateWidgetData(formId);
+      
+      // 延迟更新所有卡片,确保状态同步
       setTimeout((): void => {
-        this.updateWidgetData(formId);
-      }, 200);
+        this.updateAllWidgetsData();
+      }, 300);
 
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to handle widget event: ${error}`);
@@ -420,7 +521,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
       const adaptedData = this.sizeAdapter.handleSizeChange(formId, oldSize, newSize, currentState);
 
       // 更新卡片数据
-      await this.widgetDataManager.updateWidget(formId, adaptedData);
+      await this.widgetDataManager?.updateWidget(formId, adaptedData);
 
       hilog.info(0x0000, TAG, `Form size change handled successfully for: ${formId}`);
     } catch (error) {
@@ -444,7 +545,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
       });
 
       // 刷新所有卡片显示
-      await this.widgetDataManager.updateAllWidgets();
+      await this.widgetDataManager?.updateAllWidgets();
 
       hilog.info(0x0000, TAG, 'All widgets theme updated');
     } catch (error) {
@@ -481,7 +582,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
         });
 
         // 刷新所有卡片显示
-        await this.widgetDataManager.updateAllWidgets();
+        await this.widgetDataManager?.updateAllWidgets();
       }
 
       hilog.info(0x0000, TAG, 'Preferences change handled successfully');
@@ -563,4 +664,32 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
       hilog.error(0x0000, TAG, `Failed to open widget config page: ${error}`);
     }
   }
+
+  /**
+   * 测试卡片数据流(开发调试用)
+   */
+  private testWidgetDataFlow(formId: string): void {
+    hilog.info(0x0000, TAG, `🔍 Testing widget data flow for form: ${formId}`);
+
+    // 测试1: 检查监听器状态
+    hilog.info(0x0000, TAG, `📊 Current listener count: PlayerControlService has listeners registered`);
+
+    // 测试2: 手动触发一次数据更新
+    setTimeout(() => {
+      hilog.info(0x0000, TAG, `🔄 Manually triggering data update for form: ${formId}`);
+      this.updateWidgetData(formId);
+    }, 1000);
+
+    // 测试3: 获取AvSession当前数据
+    setTimeout(() => {
+      try {
+        const currentData = this.playerControlService.getCurrentPlayState();
+        currentData.then((data) => {
+          hilog.info(0x0000, TAG, `📊 AvSession current data: isPlaying=${data.playState.isPlaying}, hasNext=${data.playlist.hasNext}, hasPrevious=${data.playlist.hasPrevious}, title=${data.currentSong.title}`);
+        });
+      } catch (error) {
+        hilog.error(0x0000, TAG, `❌ Failed to get current data: ${error}`);
+      }
+    }, 2000);
+  }
 }

+ 63 - 32
entry/src/main/ets/view/LocalMusic.ets

@@ -116,30 +116,6 @@ interface HiCarAspectRatio {
   name: string;
 }
 
-interface GeneratedObjectLiteralInterface_1 {
-  assetId: string;
-  title: string;
-  artist: string;
-
-  // 网络资源投播,设置mediaUri; 本地资源投播,将本地文件打开后,相关的文件描述符设置到fdSrc
-  mediaUri: string;
-
-  // 该字段大写,音频'AUDIO',视频'VIDEO'
-  mediaType: string;
-  mediaSize: number;
-
-  //startPosition为投播当前进度,设置该字段可将本机播放进度同步到远端
-  startPosition: number;
-
-  // 投播资源播放时长,设置该字段可将本机播放时长同步到远端显示
-  duration: number;
-  albumCoverUri: string;
-  albumTitle: string;
-  appName: string;
-
-  // DRM资源,需要配置支持的DRM类型, 以chinaDRM为例。
-  drmScheme: string;
-}
 
 const ITEM_HEIGHT_SMALL: number = 48; // 列表项小高度
 const ITEM_HEIGHT: number = 58; // 列表项中高度
@@ -547,6 +523,12 @@ export struct LocalMusic {
       this.broadcastPlayerState();
       LogUtils.getInstance().LOGI(`Delayed state broadcast: songList.length=${this.songList.length}, curIndex=${this.curIndex}`);
     }, 2000);
+    
+    // 定期广播状态更新,确保卡片状态同步
+    setInterval(() => {
+      LogUtils.getInstance().LOGI('Periodic widget state broadcast');
+      this.broadcastPlayerState();
+    }, 10000); // 每10秒广播一次状态
 
     //折叠屏的屏幕显示模式变化
     display.on('foldDisplayModeChange', (data) => {
@@ -848,6 +830,17 @@ export struct LocalMusic {
           this.broadcastPlayerState();
           LogUtils.getInstance().LOGI(`Initial state broadcasted: songList.length=${this.songList.length}, curIndex=${this.curIndex}`);
         }, 100);
+        
+        // 多次广播确保卡片接收到状态
+        setTimeout(() => {
+          this.broadcastPlayerState();
+          LogUtils.getInstance().LOGI(`Second state broadcast: ensuring widget sync`);
+        }, 1000);
+        
+        setTimeout(() => {
+          this.broadcastPlayerState();
+          LogUtils.getInstance().LOGI(`Third state broadcast: final sync attempt`);
+        }, 3000);
       } else {
         this.name = '空空如也'
         // 即使没有歌曲也要广播状态
@@ -11271,6 +11264,11 @@ export struct LocalMusic {
         const targetPosition = (percentage / 100) * this.duration;
         this.seekTo(targetPosition.toString());
         LogUtils.getInstance().LOGI(`Widget seek to: ${percentage}% (${targetPosition}ms)`);
+        
+        // 延迟广播状态更新,确保seekTo操作完成
+        setTimeout(() => {
+          this.broadcastPlayerState();
+        }, 300);
       }
     } catch (error) {
       LogUtils.getInstance().error(`Failed to handle widget seek: ${error}`);
@@ -11339,6 +11337,7 @@ export struct LocalMusic {
    */
   public forceUpdateWidgetState(): void {
     LogUtils.getInstance().LOGI('Force updating widget state...');
+    LogUtils.getInstance().LOGI(`Current state: PlayStatus=${this.CONTROL_PlayStatus}, songTitle=${this.name}, curIndex=${this.curIndex}, songListLength=${this.songList.length}`);
     this.broadcastPlayerState();
   }
 
@@ -11347,11 +11346,15 @@ export struct LocalMusic {
    */
   private broadcastPlayerState(): void {
     try {
+      LogUtils.getInstance().LOGI(`Broadcasting player state: CONTROL_PlayStatus=${this.CONTROL_PlayStatus}, PlayStatus.PLAY=${PlayStatus.PLAY}, PlayStatus.PAUSE=${PlayStatus.PAUSE}`);
+      
       const playState: PlayState = {
         isPlaying: this.CONTROL_PlayStatus === PlayStatus.PLAY,
         isPaused: this.CONTROL_PlayStatus === PlayStatus.PAUSE,
         isLoading: this.CONTROL_PlayStatus === PlayStatus.LOADING
       };
+      
+      LogUtils.getInstance().LOGI(`PlayState created: isPlaying=${playState.isPlaying}, isPaused=${playState.isPaused}, isLoading=${playState.isLoading}`);
 
       const currentSong: SongInfo = {
         id: this.currentSong?.id || '',
@@ -11373,6 +11376,9 @@ export struct LocalMusic {
       const hasNext = this.curIndex < this.songList.length - 1;
       const hasPrevious = this.curIndex > 0;
       
+      // 添加详细的按钮状态日志
+      LogUtils.getInstance().LOGI(`Button state calculation: curIndex=${this.curIndex}, songListLength=${this.songList.length}, hasNext=${hasNext}, hasPrevious=${hasPrevious}`);
+      
       const playlist: PlaylistState = {
         hasNext: hasNext,
         hasPrevious: hasPrevious,
@@ -11385,10 +11391,10 @@ export struct LocalMusic {
 
       // 创建完整的WidgetData对象
       const widgetData: WidgetData = {
-        playState,
-        currentSong,
-        progress,
-        playlist,
+        playState: playState,
+        currentSong: currentSong,
+        progress: progress,
+        playlist: playlist,
         config: {
           size: 'medium',
           theme: 'auto',
@@ -11399,12 +11405,37 @@ export struct LocalMusic {
 
       // 更新AvSession监听器的数据
       this.avSessionWidgetListener.updateWidgetData(widgetData);
+      
+      // 直接通过全局服务更新卡片数据(解决跨进程通信问题)
+      try {
+        interface GlobalWidgetServiceInstance {
+          updateWidgetData(data: WidgetData): void;
+        }
+        
+        interface GlobalWidgetServiceClass {
+          getInstance(): GlobalWidgetServiceInstance;
+        }
+        
+        interface GlobalWidgetServiceModule {
+          GlobalWidgetService: GlobalWidgetServiceClass;
+        }
+        
+        import('../common/widget/GlobalWidgetService').then((module: GlobalWidgetServiceModule) => {
+          const globalWidgetService = module.GlobalWidgetService.getInstance();
+          globalWidgetService.updateWidgetData(widgetData);
+          LogUtils.getInstance().LOGI('Global widget service updated successfully');
+        }).catch((error: Error) => {
+          LogUtils.getInstance().error(`Failed to import GlobalWidgetService: ${error}`);
+        });
+      } catch (error) {
+        LogUtils.getInstance().error(`Direct widget update failed: ${error}`);
+      }
 
       const stateData: PlayerStateBroadcastData = {
-        playState,
-        currentSong,
-        progress,
-        playlist
+        playState: playState,
+        currentSong: currentSong,
+        progress: progress,
+        playlist: playlist
       };
 
       // 广播播放状态变化

+ 144 - 142
entry/src/main/ets/widget/pages/PlayerWidgetLarge.ets

@@ -1,3 +1,4 @@
+import { WidgetController } from '../../common/widget/WidgetController';
 /**
  * 大尺寸播放器卡片 (4x3)
  * 显示专辑封面、完整信息和扩展控制
@@ -20,20 +21,6 @@ struct PlayerWidgetLarge {
   @LocalStorageProp('showCover') showCover: boolean = true;
   @LocalStorageProp('isLoading') isLoading: boolean = false;
 
-  /**
-   * 获取按钮透明度
-   */
-  private getButtonOpacity(enabled: boolean): number {
-    return enabled ? 1.0 : 0.4;
-  }
-
-  /**
-   * 获取按钮颜色
-   */
-  private getButtonColor(enabled: boolean): string {
-    return enabled ? '#FF007DFF' : '#66000000';
-  }
-
   /**
    * 获取播放按钮图标
    */
@@ -62,7 +49,7 @@ struct PlayerWidgetLarge {
    * 获取专辑封面图片
    */
   private getCoverImage(): Resource | string {
-    if (this.coverImage && this.coverImage.trim() !== '') {
+    if (this.coverImage && this.coverImage.trim() !== '' && this.coverImage !== 'undefined') {
       return this.coverImage;
     }
     return $r('app.media.bg_music');
@@ -72,60 +59,70 @@ struct PlayerWidgetLarge {
     Column() {
       // 顶部信息区域
       Row() {
-        // 专辑封面
-        if (this.showCover) {
+        // 专辑封面 - 更大更圆润
+        Stack() {
           Image(this.getCoverImage())
-            .width(60)
-            .height(60)
-            .borderRadius(8)
+            .width(72)
+            .height(72)
+            .borderRadius(16)
             .objectFit(ImageFit.Cover)
-            .margin({ right: 12 })
-            .stateStyles({
-              pressed: {
-                .opacity(0.8)
-                .scale({ x: 0.98, y: 0.98 })
-              },
-              normal: {
-                .opacity(1.0)
-                .scale({ x: 1.0, y: 1.0 })
-              }
-            })
-            .onClick(() => {
-              console.info('Heanup PlayerWidgetLarge: Cover image clicked');
-              postCardAction(this, {
-                'action': 'router',
-                'abilityName': 'EntryAbility'
-              });
-            })
+          
+          // 播放状态指示器 - 简化版本
+          if (this.isPlaying) {
+            Text('♪')
+              .fontSize(12)
+              .fontColor('#FFFFFF')
+              .padding(4)
+              .backgroundColor('#80000000')
+              .borderRadius(6)
+              .position({ x: 4, y: 4 })
+          }
         }
+        .margin({ right: 16 })
+        .stateStyles({
+          pressed: {
+            .opacity(0.7)
+          },
+          normal: {
+            .opacity(1.0)
+          }
+        })
+        .onClick(() => {
+          console.info('Heanup PlayerWidgetLarge: Cover image clicked');
+          postCardAction(this, {
+            'action': 'router',
+            'abilityName': 'EntryAbility'
+          });
+        })
 
-        // 歌曲信息
+        // 歌曲信息 - 更现代的排版
         Column() {
-          // 歌曲标题
+          // 歌曲标题 - 更大更醒目
           Text(this.getDisplayText(this.songTitle, '暂无播放'))
-            .fontSize(16)
-            .fontColor(this.getTextColor(this.songTitle, '暂无播放', '#E6000000'))
-            .fontWeight(this.songTitle === '暂无播放' ? FontWeight.Normal : FontWeight.Medium)
-            .maxLines(1)
+            .fontSize(18)
+            .fontColor(this.getTextColor(this.songTitle, '暂无播放', '#1A1A1A'))
+            .fontWeight(FontWeight.Bold)
+            .maxLines(2)
             .textOverflow({ overflow: TextOverflow.Ellipsis })
             .width('100%')
             .textAlign(TextAlign.Start)
+            .lineHeight(24)
 
-          // 艺术家信息
+          // 艺术家信息 - 更柔和的颜色
           Text(this.getDisplayText(this.songArtist, '未知艺术家'))
-            .fontSize(13)
-            .fontColor('#99000000')
-            .fontWeight(FontWeight.Normal)
+            .fontSize(14)
+            .fontColor('#666666')
+            .fontWeight(FontWeight.Medium)
             .maxLines(1)
             .textOverflow({ overflow: TextOverflow.Ellipsis })
             .width('100%')
             .textAlign(TextAlign.Start)
             .margin({ top: 4 })
 
-          // 专辑信息
+          // 专辑信息 - 更小更淡
           Text(this.getDisplayText(this.songAlbum, '未知专辑'))
-            .fontSize(11)
-            .fontColor('#66000000')
+            .fontSize(12)
+            .fontColor('#999999')
             .fontWeight(FontWeight.Normal)
             .maxLines(1)
             .textOverflow({ overflow: TextOverflow.Ellipsis })
@@ -138,7 +135,7 @@ struct PlayerWidgetLarge {
         .justifyContent(FlexAlign.Start)
         .stateStyles({
           pressed: {
-            .opacity(0.8)
+            .opacity(0.7)
           },
           normal: {
             .opacity(1.0)
@@ -155,91 +152,95 @@ struct PlayerWidgetLarge {
       }
       .width('100%')
       .alignItems(VerticalAlign.Top)
-      .margin({ bottom: 16 })
+      .margin({ bottom: 20 })
 
-      // 播放进度区域
+      // 播放进度区域 - 重新设计
       if (this.showProgress) {
         Column() {
-          // 进度条
-          Row() {
-            Progress({
-              value: this.progressPercentage,
-              total: 100,
-              type: ProgressType.Linear
-            })
+          // 进度条 - 更粗更现代
+          Stack() {
+            // 背景进度条
+            Row()
               .width('100%')
-              .height(4)
-              .color('#FF007DFF')
-              .backgroundColor('#1A007DFF')
-              .borderRadius(2)
-              .stateStyles({
-                pressed: {
-                  .opacity(0.8)
-                },
-                normal: {
-                  .opacity(1.0)
-                }
-              })
-              .onClick((event) => {
-                if (!this.isLoading) {
-                  console.info('Heanup PlayerWidgetLarge: Progress bar clicked');
-                  const width = Number(event.target.area.width);
-                  const percentage = width > 0 ? (event.x / width * 100) : 0;
-                  postCardAction(this, {
-                    'action': 'message',
-                    'params': {
-                      "func":"seek_to",
-                      'percentage': percentage
-                    }
-                  });
-                }
-              })
+              .height(6)
+              .backgroundColor('#F0F0F0')
+              .borderRadius(3)
+            
+            // 当前进度
+            Row()
+              .width(`${this.progressPercentage}%`)
+              .height(6)
+              .backgroundColor('#FF6B6B')  // 使用纯色替代渐变
+              .borderRadius(3)
           }
           .width('100%')
-          .margin({ bottom: 6 })
+          .stateStyles({
+            pressed: {
+              .opacity(0.7)
+            },
+            normal: {
+              .opacity(1.0)
+            }
+          })
+          .onClick((event) => {
+            if (!this.isLoading) {
+              console.info('Heanup PlayerWidgetLarge: Progress bar clicked');
+              const width = Number(event.target.area.width);
+              const percentage = width > 0 ? (event.x / width * 100) : 0;
+              postCardAction(this, {
+                'action': 'message',
+                'params': {
+                  "func":"seek_to",
+                  'percentage': percentage
+                }
+              });
+            }
+          })
 
-          // 时间显示
+          // 时间显示 - 更现代的样式
           Row() {
             Text(this.currentTime)
-              .fontSize(11)
-              .fontColor('#99000000')
-              .fontWeight(FontWeight.Normal)
+              .fontSize(12)
+              .fontColor('#666666')
+              .fontWeight(FontWeight.Medium)
 
             Blank()
 
             Text(this.totalTime)
-              .fontSize(11)
-              .fontColor('#99000000')
-              .fontWeight(FontWeight.Normal)
+              .fontSize(12)
+              .fontColor('#666666')
+              .fontWeight(FontWeight.Medium)
           }
           .width('100%')
+          .margin({ top: 8 })
         }
         .width('100%')
-        .margin({ bottom: 16 })
+        .margin({ bottom: 20 })
       }
 
-      // 播放控制区域
+      // 播放控制区域 - 重新设计
       Row() {
-        // 上一首按钮
+        // 上一首按钮 - 更现代的设计
         Button() {
-          Image($r('app.media.ic_previous2'))
-            .width(20)
-            .height(20)
-            .fillColor(this.getButtonColor(this.hasPrevious))
+          Image($r('app.media.ic_previous'))
+            .width(24)
+            .height(24)
+            .fillColor(this.hasPrevious ? '#333333' : '#CCCCCC')
         }
-        .width(40)
-        .height(40)
-        .backgroundColor(Color.Transparent)
-        .enabled(!this.isLoading)  // 临时启用按钮进行测试
-        .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
+        .width(48)
+        .height(48)
+        .backgroundColor('#F8F8F8')
+        .borderRadius(24)
+        .enabled(!this.isLoading)
+        .opacity(this.hasPrevious ? 1.0 : 0.6)
         .stateStyles({
           pressed: {
-            .scale({ x: 0.95, y: 0.95 })
-            .opacity(0.8)
+            .opacity(0.7)
+            .backgroundColor('#EEEEEE')
           },
           normal: {
-            .scale({ x: 1.0, y: 1.0 })
-            .opacity(this.getButtonOpacity(this.hasPrevious))
+            .opacity(this.hasPrevious ? 1.0 : 0.6)
+            .backgroundColor('#F8F8F8')
           }
         })
         .onClick(() => {
@@ -259,26 +260,26 @@ struct PlayerWidgetLarge {
 
         Blank()
 
-        // 播放/暂停按钮
+        // 播放/暂停按钮 - 更大更突出
         Button() {
           Image(this.getPlayButtonIcon())
-            .width(28)
-            .height(28)
+            .width(32)
+            .height(32)
             .fillColor('#FFFFFF')
         }
-        .width(52)
-        .height(52)
-        .backgroundColor(this.isLoading ? '#99007DFF' : '#FF007DFF')
-        .borderRadius(26)
+        .width(64)
+        .height(64)
+        .backgroundColor(this.isLoading ? '#CCCCCC' : '#FF6B6B')  // 使用纯色替代渐变
+        .borderRadius(32)
         .enabled(!this.isLoading)
         .stateStyles({
           pressed: {
-            .scale({ x: 0.95, y: 0.95 })
-            .backgroundColor('#CC007DFF')
+            .opacity(0.8)
+            .backgroundColor(this.isLoading ? '#AAAAAA' : '#FF5252')
           },
           normal: {
-            .scale({ x: 1.0, y: 1.0 })
-            .backgroundColor(this.isLoading ? '#99007DFF' : '#FF007DFF')
+            .opacity(1.0)
+            .backgroundColor(this.isLoading ? '#CCCCCC' : '#FF6B6B')
           }
         })
         .onClick(() => {
@@ -295,31 +296,32 @@ struct PlayerWidgetLarge {
 
         Blank()
 
-        // 下一首按钮
+        // 下一首按钮 - 与上一首对称
         Button() {
-          Image($r('app.media.ic_next2'))
-            .width(20)
-            .height(20)
-            .fillColor(this.getButtonColor(this.hasNext))
+          Image($r('app.media.ic_next'))
+            .width(24)
+            .height(24)
+            .fillColor(this.hasNext ? '#333333' : '#CCCCCC')
         }
-        .width(40)
-        .height(40)
-        .backgroundColor(Color.Transparent)
-        .enabled(!this.isLoading)  // 临时启用按钮进行测试
-        .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
+        .width(48)
+        .height(48)
+        .backgroundColor('#F8F8F8')
+        .borderRadius(24)
+        .enabled(!this.isLoading && this.hasNext)  // 确保按钮状态正确
+        .opacity(this.hasNext ? 1.0 : 0.6)
         .stateStyles({
           pressed: {
-            .scale({ x: 0.95, y: 0.95 })
-            .opacity(0.8)
+            .opacity(0.7)
+            .backgroundColor('#EEEEEE')
           },
           normal: {
-            .scale({ x: 1.0, y: 1.0 })
-            .opacity(this.getButtonOpacity(this.hasNext))
+            .opacity(this.hasNext ? 1.0 : 0.6)
+            .backgroundColor('#F8F8F8')
           }
         })
         .onClick(() => {
           console.info(`Heanup PlayerWidgetLarge: Next button clicked, hasNext=${this.hasNext}, isLoading=${this.isLoading}`);
-          if (!this.isLoading) {
+          if (!this.isLoading && this.hasNext) {
             console.info('Heanup PlayerWidgetLarge: Next button action sent');
             postCardAction(this, {
               'action': 'message',
@@ -328,7 +330,7 @@ struct PlayerWidgetLarge {
               }
             });
           } else {
-            console.info('Heanup PlayerWidgetLarge: Next button disabled due to loading');
+            console.info('Heanup PlayerWidgetLarge: Next button disabled due to loading or no next song');
           }
         })
       }
@@ -338,16 +340,16 @@ struct PlayerWidgetLarge {
     }
     .width('100%')
     .height('100%')
-    .padding(16)
+    .padding(20)
     .backgroundColor('#FFFFFF')
-    .borderRadius(12)
+    .borderRadius(20)
     .alignItems(HorizontalAlign.Start)
     .justifyContent(FlexAlign.SpaceBetween)
     .shadow({
       radius: 8,
-      color: '#1A000000',
+      color: '#20000000',
       offsetX: 0,
-      offsetY: 2
+      offsetY: 4
     })
     // 移除手势支持,form应用不支持复杂交互
   }

+ 7 - 8
entry/src/main/ets/widget/pages/PlayerWidgetMedium.ets

@@ -1,4 +1,3 @@
-import { WidgetController } from '../../common/widget/WidgetController';
 /**
  * 小尺寸播放器卡片 (2x1)
  * 显示基本播放控制和歌曲名称
@@ -33,7 +32,7 @@ struct PlayerWidgetSmall {
    */
   private getPlayButtonIcon(): Resource {
     if (this.isLoading) {
-      return $r('app.media.hm_play'); // 加载状态图标
+      return $r('app.media.hm_more'); // 加载状态图标
     }
     return this.isPlaying ? $r('app.media.hm_pause') : $r('app.media.hm_play');
   }
@@ -54,7 +53,7 @@ struct PlayerWidgetSmall {
       Row() {
         // 上一首按钮
         Button() {
-          Image($r('app.media.ic_previous2'))
+          Image($r('app.media.ic_previous'))
             .width(16)
             .height(16)
             .fillColor(this.getButtonColor(this.hasPrevious))
@@ -94,7 +93,7 @@ struct PlayerWidgetSmall {
           Image(this.getPlayButtonIcon())
             .width(20)
             .height(20)
-            .fillColor('#FFFFFF')
+            .fillColor($r('sys.color.comp_background_list_card'))
         }
         .width(36)
         .height(36)
@@ -126,7 +125,7 @@ struct PlayerWidgetSmall {
 
         // 下一首按钮
         Button() {
-          Image($r('app.media.ic_next2'))
+          Image($r('app.media.ic_next'))
             .width(16)
             .height(16)
             .fillColor(this.getButtonColor(this.hasNext))
@@ -134,7 +133,7 @@ struct PlayerWidgetSmall {
         .width(32)
         .height(32)
         .backgroundColor(Color.Transparent)
-        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .enabled(!this.isLoading && this.hasNext)  // 确保按钮状态正确
         .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
           pressed: {
@@ -148,7 +147,7 @@ struct PlayerWidgetSmall {
         })
         .onClick(() => {
           console.info(`Heanup PlayerWidgetMedium: Next button clicked, hasNext=${this.hasNext}, isLoading=${this.isLoading}`);
-          if (!this.isLoading) {
+          if (!this.isLoading && this.hasNext) {
             console.info('Heanup PlayerWidgetMedium: Next button action sent');
             postCardAction(this, {
               'action': 'message',
@@ -157,7 +156,7 @@ struct PlayerWidgetSmall {
               }
             });
           } else {
-            console.info('Heanup PlayerWidgetMedium: Next button disabled due to loading');
+            console.info('Heanup PlayerWidgetMedium: Next button disabled due to loading or no next song');
           }
         })
       }

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

@@ -35,6 +35,7 @@ struct PlayerWidgetSmall {
     if (this.isLoading) {
       return $r('app.media.hm_play'); // 加载状态图标
     }
+    console.log('Heanup 当前播放状态:'+this.isPlaying)
     return this.isPlaying ? $r('app.media.hm_pause') : $r('app.media.hm_play');
   }
 
@@ -55,13 +56,13 @@ struct PlayerWidgetSmall {
         // 上一首按钮
         Button() {
           Image($r('app.media.ic_previous2'))
-            .width(16)
-            .height(16)
-            .fillColor(this.getButtonColor(this.hasPrevious))
+            .width(24)
+            .height(24)
+            .fillColor("#FF007DFF")
         }
         .width(32)
         .height(32)
-        .backgroundColor(Color.Transparent)
+        .backgroundColor(Color.White)
         .enabled(!this.isLoading)  // 临时启用按钮进行测试
         .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
@@ -127,15 +128,15 @@ struct PlayerWidgetSmall {
         // 下一首按钮
         Button() {
           Image($r('app.media.ic_next2'))
-            .width(16)
-            .height(16)
-            .fillColor(this.getButtonColor(this.hasNext))
+            .width(24)
+            .height(24)
+            .fillColor("#FF007DFF")
         }
         .width(32)
         .height(32)
-        .backgroundColor(Color.Transparent)
+        .backgroundColor(Color.White)
         .enabled(!this.isLoading)  // 临时启用按钮进行测试
-        .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
+        .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
           pressed: {
             .scale({ x: 0.95, y: 0.95 })