Przeglądaj źródła

集成播放卡片

chendeben 1 rok temu
rodzic
commit
1871f54493

+ 31 - 4
entry/src/main/ets/common/widget/AvSessionWidgetListener.ets

@@ -44,13 +44,36 @@ export class AvSessionWidgetListener {
   public addStateListener(callback: (data: WidgetData) => void): void {
   public addStateListener(callback: (data: WidgetData) => void): void {
     this.stateListeners.push(callback);
     this.stateListeners.push(callback);
     
     
-    // 立即返回默认数据
-    const defaultData = this.getDefaultWidgetData();
-    callback(defaultData);
+    // 如果有缓存的数据,立即返回
+    if (this.lastWidgetData) {
+      callback(this.lastWidgetData);
+    } else {
+      // 否则返回默认数据
+      const defaultData = this.getDefaultWidgetData();
+      callback(defaultData);
+    }
     
     
     hilog.info(0x0000, TAG, 'State listener registered');
     hilog.info(0x0000, TAG, 'State listener registered');
   }
   }
 
 
+  /**
+   * 更新卡片数据(由主应用调用)
+   */
+  public updateWidgetData(data: WidgetData): void {
+    this.lastWidgetData = data;
+    
+    // 通知所有监听器
+    this.stateListeners.forEach((listener: (data: WidgetData) => void) => {
+      try {
+        listener(data);
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error in state listener: ${error}`);
+      }
+    });
+    
+    hilog.info(0x0000, TAG, 'Widget data updated and broadcasted to listeners');
+  }
+
   /**
   /**
    * 移除状态监听器
    * 移除状态监听器
    */
    */
@@ -67,9 +90,13 @@ export class AvSessionWidgetListener {
    */
    */
   public getCurrentWidgetData(): WidgetData {
   public getCurrentWidgetData(): WidgetData {
     if (this.lastWidgetData) {
     if (this.lastWidgetData) {
+      hilog.info(0x0000, TAG, `Returning cached widget data: hasNext=${this.lastWidgetData.playlist.hasNext}, hasPrevious=${this.lastWidgetData.playlist.hasPrevious}`);
       return this.lastWidgetData;
       return this.lastWidgetData;
     }
     }
-    return this.getDefaultWidgetData();
+    
+    const defaultData = this.getDefaultWidgetData();
+    hilog.info(0x0000, TAG, `Returning default widget data: hasNext=${defaultData.playlist.hasNext}, hasPrevious=${defaultData.playlist.hasPrevious}`);
+    return defaultData;
   }
   }
 
 
   /**
   /**

+ 10 - 7
entry/src/main/ets/common/widget/PlayerControlService.ets

@@ -163,13 +163,16 @@ export class PlayerControlService {
   registerStateListener(callback: (data: WidgetData) => void): void {
   registerStateListener(callback: (data: WidgetData) => void): void {
     this.stateListeners.push(callback);
     this.stateListeners.push(callback);
     
     
-    // 立即获取当前AvSession状态并回调
-    try {
-      const currentData = this.avSessionListener.getCurrentWidgetData();
-      callback(currentData);
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Error getting current AvSession data: ${error}`);
-    }
+    // 延迟获取当前状态,给主应用时间来广播真实状态
+    setTimeout(() => {
+      try {
+        const currentData = this.avSessionListener.getCurrentWidgetData();
+        hilog.info(0x0000, TAG, `Sending current data to listener: hasNext=${currentData.playlist.hasNext}, hasPrevious=${currentData.playlist.hasPrevious}`);
+        callback(currentData);
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error getting current AvSession data: ${error}`);
+      }
+    }, 1500); // 延迟1.5秒,确保主应用已经广播了状态
     
     
     hilog.info(0x0000, TAG, 'State listener registered');
     hilog.info(0x0000, TAG, 'State listener registered');
   }
   }

+ 404 - 0
entry/src/main/ets/common/widget/UserPreferencesService.ets

@@ -0,0 +1,404 @@
+import preferences from '@ohos.data.preferences';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { WidgetSize, WidgetTheme } from './WidgetTypes';
+import { UserPreferences } from './WidgetConfigManager';
+import { ObjectUtils } from './ObjectUtils';
+
+const TAG = 'Heanup UserPreferencesService';
+
+/**
+ * 用户偏好设置错误类
+ */
+class UserPreferencesError extends Error {
+  constructor(message: string) {
+    super(message);
+    this.name = 'UserPreferencesError';
+  }
+}
+const USER_PREFERENCES_NAME = 'user_widget_preferences';
+
+/**
+ * 偏好设置变化事件接口
+ */
+export interface PreferencesChangeEvent {
+  type: 'preferences_changed';
+  changedKeys: string[];
+  newPreferences: UserPreferences;
+  timestamp: number;
+}
+
+/**
+ * 用户偏好设置服务
+ * 负责用户偏好设置的存储和管理
+ * 需求: 5.4, 6.3
+ */
+export class UserPreferencesService {
+  private static instance: UserPreferencesService;
+  private preferencesStore: preferences.Preferences | null = null;
+  private currentPreferences: UserPreferences | null = null;
+  private changeListeners: Set<PreferencesChangeListener> = new Set();
+
+  /**
+   * 获取单例实例
+   */
+  public static getInstance(): UserPreferencesService {
+    if (!UserPreferencesService.instance) {
+      UserPreferencesService.instance = new UserPreferencesService();
+    }
+    return UserPreferencesService.instance;
+  }
+
+  private constructor() {
+    this.initPreferences();
+    hilog.info(0x0000, TAG, 'UserPreferencesService initialized');
+  }
+
+  /**
+   * 初始化偏好设置存储
+   */
+  private async initPreferences(): Promise<void> {
+    try {
+      this.preferencesStore = await preferences.getPreferences(getContext(), USER_PREFERENCES_NAME);
+      await this.loadPreferences();
+      hilog.info(0x0000, TAG, 'User preferences initialized successfully');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to initialize user preferences: ${error}`);
+    }
+  }
+
+  /**
+   * 获取用户偏好设置
+   */
+  public async getPreferences(): Promise<UserPreferences> {
+    if (this.currentPreferences) {
+      return this.currentPreferences;
+    }
+
+    await this.loadPreferences();
+    return this.currentPreferences || this.getDefaultPreferences();
+  }
+
+  /**
+   * 更新用户偏好设置
+   * @param updates 要更新的偏好设置
+   */
+  public async updatePreferences(updates: Partial<UserPreferences>): Promise<void> {
+    try {
+      const currentPrefs = await this.getPreferences();
+      const newPreferences: UserPreferences = ObjectUtils.mergeUserPreferences(currentPrefs, updates);
+
+      await this.savePreferences(newPreferences);
+
+      // 通知变化监听器
+      const changedKeys = Object.keys(updates);
+      this.notifyPreferencesChange(changedKeys, newPreferences);
+
+      hilog.info(0x0000, TAG, `User preferences updated: ${changedKeys.join(', ')}`);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to update user preferences: ${error}`);
+    }
+  }
+
+  /**
+   * 重置用户偏好设置为默认值
+   */
+  public async resetPreferences(): Promise<void> {
+    try {
+      const defaultPrefs = this.getDefaultPreferences();
+      await this.savePreferences(defaultPrefs);
+
+      // 通知所有设置都已更改
+      const allKeys = Object.keys(defaultPrefs);
+      this.notifyPreferencesChange(allKeys, defaultPrefs);
+
+      hilog.info(0x0000, TAG, 'User preferences reset to default');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to reset user preferences: ${error}`);
+    }
+  }
+
+  /**
+   * 获取特定偏好设置值
+   * @param key 设置键
+   * @returns 设置值
+   */
+  public async getPreference(key: string): Promise<Object> {
+    const preferences = await this.getPreferences();
+    const prefsObj = preferences as Object as Record<string, Object>;
+    return prefsObj[key];
+  }
+
+  /**
+   * 设置特定偏好设置值
+   * @param key 设置键
+   * @param value 设置值
+   */
+  public async setPreference(key: string, value: Object): Promise<void> {
+    const updates: Partial<UserPreferences> = {};
+    const updatesRecord = updates as Record<string, Object>;
+    updatesRecord[key] = value;
+    await this.updatePreferences(updates);
+  }
+
+  /**
+   * 导出用户偏好设置
+   * @returns 偏好设置的JSON字符串
+   */
+  public async exportPreferences(): Promise<string> {
+    try {
+      const preferences = await this.getPreferences();
+      return JSON.stringify(preferences, null, 2);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to export preferences: ${error}`);
+      throw new UserPreferencesError(`Failed to export preferences: ${error}`);
+    }
+  }
+
+  /**
+   * 导入用户偏好设置
+   * @param preferencesJson 偏好设置的JSON字符串
+   */
+  public async importPreferences(preferencesJson: string): Promise<void> {
+    try {
+      const importedPrefs = JSON.parse(preferencesJson) as UserPreferences;
+
+      // 验证导入的数据
+      const validatedPrefs = this.validatePreferences(importedPrefs);
+
+      await this.savePreferences(validatedPrefs);
+
+      // 通知所有设置都已更改
+      const allKeys = Object.keys(validatedPrefs);
+      this.notifyPreferencesChange(allKeys, validatedPrefs);
+
+      hilog.info(0x0000, TAG, 'User preferences imported successfully');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to import preferences: ${error}`);
+      throw new UserPreferencesError(`Failed to import preferences: ${error}`);
+    }
+  }
+
+  /**
+   * 注册偏好设置变化监听器
+   * @param listener 监听器
+   */
+  public addPreferencesChangeListener(listener: PreferencesChangeListener): void {
+    this.changeListeners.add(listener);
+    hilog.info(0x0000, TAG, 'Preferences change listener added');
+  }
+
+  /**
+   * 移除偏好设置变化监听器
+   * @param listener 监听器
+   */
+  public removePreferencesChangeListener(listener: PreferencesChangeListener): void {
+    this.changeListeners.delete(listener);
+    hilog.info(0x0000, TAG, 'Preferences change listener removed');
+  }
+
+  /**
+   * 检查偏好设置是否为默认值
+   */
+  public async isDefaultPreferences(): Promise<boolean> {
+    try {
+      const currentPrefs = await this.getPreferences();
+      const defaultPrefs = this.getDefaultPreferences();
+
+      return JSON.stringify(currentPrefs) === JSON.stringify(defaultPrefs);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to check if preferences are default: ${error}`);
+      return false;
+    }
+  }
+
+  /**
+   * 获取偏好设置统计信息
+   */
+  public async getPreferencesStats(): Promise<PreferencesStats> {
+    try {
+      const preferences = await this.getPreferences();
+      const isDefault = await this.isDefaultPreferences();
+
+      return {
+        isDefault: isDefault,
+        syncEnabled: preferences.syncWithMainApp,
+        themeMode: preferences.defaultTheme,
+        cacheEnabled: preferences.enableCache,
+        privacyLevel: this.calculatePrivacyLevel(preferences),
+        lastModified: Date.now() // 实际应该存储真实的修改时间
+      };
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to get preferences stats: ${error}`);
+      throw new UserPreferencesError(`Failed to get preferences stats: ${error}`);
+    }
+  }
+
+  /**
+   * 加载偏好设置
+   */
+  private async loadPreferences(): Promise<void> {
+    try {
+      if (!this.preferencesStore) {
+        await this.initPreferences();
+      }
+
+      const prefsStr = await this.preferencesStore?.get('user_preferences', '') as string;
+      if (prefsStr) {
+        this.currentPreferences = JSON.parse(prefsStr) as UserPreferences;
+      } else {
+        this.currentPreferences = this.getDefaultPreferences();
+        await this.savePreferences(this.currentPreferences);
+      }
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to load preferences: ${error}`);
+      this.currentPreferences = this.getDefaultPreferences();
+    }
+  }
+
+  /**
+   * 保存偏好设置
+   */
+  private async savePreferences(preferences: UserPreferences): Promise<void> {
+    try {
+      if (!this.preferencesStore) {
+        await this.initPreferences();
+      }
+
+      await this.preferencesStore?.put('user_preferences', JSON.stringify(preferences));
+      await this.preferencesStore?.flush();
+
+      this.currentPreferences = preferences;
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to save preferences: ${error}`);
+      throw new UserPreferencesError(`Failed to save preferences: ${error}`);
+    }
+  }
+
+  /**
+   * 获取默认偏好设置
+   */
+  private getDefaultPreferences(): UserPreferences {
+    return {
+      // 全局偏好
+      defaultTheme: WidgetTheme.AUTO,
+      defaultSize: WidgetSize.MEDIUM,
+
+      // 同步设置
+      syncWithMainApp: true,
+      syncThemeColor: true,
+
+      // 性能设置
+      enableCache: true,
+      cacheExpiry: 30000,
+
+      // 隐私设置
+      showSongInfo: true,
+      showArtistInfo: true,
+      showAlbumCover: true
+    };
+  }
+
+  /**
+   * 验证偏好设置数据
+   */
+  private validatePreferences(preferences: Object): UserPreferences {
+    const defaultPrefs = this.getDefaultPreferences();
+
+    // 类型保护:确保 preferences 是一个对象
+    if (typeof preferences !== 'object' || preferences === null) {
+      return defaultPrefs;
+    }
+
+    const prefsObj = preferences as Record<string, Object>;
+
+    // 确保所有必需的字段都存在且类型正确
+    return {
+      defaultTheme: this.validateTheme(prefsObj.defaultTheme) || defaultPrefs.defaultTheme,
+      defaultSize: this.validateSize(prefsObj.defaultSize) || defaultPrefs.defaultSize,
+      syncWithMainApp: typeof prefsObj.syncWithMainApp === 'boolean' ? prefsObj.syncWithMainApp : defaultPrefs.syncWithMainApp,
+      syncThemeColor: typeof prefsObj.syncThemeColor === 'boolean' ? prefsObj.syncThemeColor : defaultPrefs.syncThemeColor,
+      enableCache: typeof prefsObj.enableCache === 'boolean' ? prefsObj.enableCache : defaultPrefs.enableCache,
+      cacheExpiry: typeof prefsObj.cacheExpiry === 'number' && prefsObj.cacheExpiry > 0 ? prefsObj.cacheExpiry : defaultPrefs.cacheExpiry,
+      showSongInfo: typeof prefsObj.showSongInfo === 'boolean' ? prefsObj.showSongInfo : defaultPrefs.showSongInfo,
+      showArtistInfo: typeof prefsObj.showArtistInfo === 'boolean' ? prefsObj.showArtistInfo : defaultPrefs.showArtistInfo,
+      showAlbumCover: typeof prefsObj.showAlbumCover === 'boolean' ? prefsObj.showAlbumCover : defaultPrefs.showAlbumCover
+    };
+  }
+
+  /**
+   * 验证主题值
+   */
+  private validateTheme(theme: Object): WidgetTheme | null {
+    const themeValues = [WidgetTheme.AUTO, WidgetTheme.LIGHT, WidgetTheme.DARK];
+    if (themeValues.includes(theme as WidgetTheme)) {
+      return theme as WidgetTheme;
+    }
+    return null;
+  }
+
+  /**
+   * 验证尺寸值
+   */
+  private validateSize(size: Object): WidgetSize | null {
+    const sizeValues = [WidgetSize.SMALL, WidgetSize.MEDIUM, WidgetSize.LARGE];
+    if (sizeValues.includes(size as WidgetSize)) {
+      return size as WidgetSize;
+    }
+    return null;
+  }
+
+  /**
+   * 计算隐私级别
+   */
+  private calculatePrivacyLevel(preferences: UserPreferences): 'high' | 'medium' | 'low' {
+    let privacyScore = 0;
+
+    if (!preferences.showSongInfo) privacyScore++;
+    if (!preferences.showArtistInfo) privacyScore++;
+    if (!preferences.showAlbumCover) privacyScore++;
+
+    if (privacyScore >= 2) return 'high';
+    if (privacyScore === 1) return 'medium';
+    return 'low';
+  }
+
+  /**
+   * 通知偏好设置变化
+   */
+  private notifyPreferencesChange(changedKeys: string[], newPreferences: UserPreferences): void {
+    const event: PreferencesChangeEvent = {
+      type: 'preferences_changed',
+      changedKeys: changedKeys,
+      newPreferences: newPreferences,
+      timestamp: Date.now()
+    };
+
+    const listeners = Array.from(this.changeListeners);
+    for (let i = 0; i < listeners.length; i++) {
+      try {
+        listeners[i].onPreferencesChanged(event);
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error notifying preferences change listener: ${error}`);
+      }
+    }
+  }
+}
+
+/**
+ * 偏好设置变化监听器接口
+ */
+export interface PreferencesChangeListener {
+  onPreferencesChanged(event: PreferencesChangeEvent): void;
+}
+
+/**
+ * 偏好设置统计信息接口
+ */
+export interface PreferencesStats {
+  isDefault: boolean;
+  syncEnabled: boolean;
+  themeMode: WidgetTheme;
+  cacheEnabled: boolean;
+  privacyLevel: 'high' | 'medium' | 'low';
+  lastModified: number;
+}

+ 31 - 3
entry/src/main/ets/common/widget/WidgetDataManager.ets

@@ -209,6 +209,32 @@ export class WidgetDataManager {
    * 格式化数据用于卡片显示
    * 格式化数据用于卡片显示
    */
    */
   private formatDataForWidget(data: WidgetData): FormattedWidgetData {
   private formatDataForWidget(data: WidgetData): FormattedWidgetData {
+    // 修复按钮状态:如果有多首歌但按钮状态为false,强制启用
+    let hasNext = data.playlist.hasNext;
+    let hasPrevious = data.playlist.hasPrevious;
+    
+    // 如果总数大于1,但按钮状态都是false,说明状态可能有问题,进行修复
+    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;
+        }
+        hilog.info(0x0000, TAG, `Fixed button states: hasNext=${hasNext}, hasPrevious=${hasPrevious}, currentIndex=${data.playlist.currentIndex}, totalCount=${data.playlist.totalCount}`);
+      }
+    }
+    
     const formattedData: FormattedWidgetData = {
     const formattedData: FormattedWidgetData = {
       // 播放状态
       // 播放状态
       isPlaying: data.playState.isPlaying,
       isPlaying: data.playState.isPlaying,
@@ -226,9 +252,9 @@ export class WidgetDataManager {
       totalTime: data.progress.totalTimeText,
       totalTime: data.progress.totalTimeText,
       progressPercentage: data.progress.percentage,
       progressPercentage: data.progress.percentage,
       
       
-      // 控制按钮状态
-      hasNext: data.playlist.hasNext,
-      hasPrevious: data.playlist.hasPrevious,
+      // 控制按钮状态(使用修复后的值)
+      hasNext: hasNext,
+      hasPrevious: hasPrevious,
       
       
       // 卡片配置
       // 卡片配置
       showProgress: data.config.showProgress,
       showProgress: data.config.showProgress,
@@ -238,6 +264,8 @@ export class WidgetDataManager {
       // 时间戳用于强制更新
       // 时间戳用于强制更新
       timestamp: Date.now()
       timestamp: Date.now()
     };
     };
+    
+    hilog.info(0x0000, TAG, `Formatted widget data: hasNext=${formattedData.hasNext}, hasPrevious=${formattedData.hasPrevious}, songTitle=${formattedData.songTitle}`);
     return formattedData;
     return formattedData;
   }
   }
 
 

+ 0 - 286
entry/src/main/ets/common/widget/WidgetDataManagerTest.ets

@@ -1,286 +0,0 @@
-import { hilog } from '@kit.PerformanceAnalysisKit';
-import { WidgetDataManager } from './WidgetDataManager';
-import { WidgetData, WidgetSize, WidgetTheme } from './WidgetTypes';
-
-const TAG = 'WidgetDataManagerTest';
-
-/**
- * 卡片数据管理器测试类
- * 用于验证数据模型和管理器的功能
- */
-export class WidgetDataManagerTest {
-  private dataManager: WidgetDataManager;
-
-  constructor() {
-    this.dataManager = new WidgetDataManager();
-  }
-
-  /**
-   * 运行所有测试
-   */
-  async runAllTests(): Promise<boolean> {
-    hilog.info(0x0000, TAG, 'Starting WidgetDataManager tests...');
-    
-    try {
-      await this.testInitialData();
-      await this.testDataPersistence();
-      await this.testCacheOperations();
-      await this.testDataFormatting();
-      await this.testBatchOperations();
-      
-      hilog.info(0x0000, TAG, 'All tests passed successfully!');
-      return true;
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Test failed: ${error}`);
-      return false;
-    }
-  }
-
-  /**
-   * 测试初始数据
-   */
-  private async testInitialData(): Promise<void> {
-    hilog.info(0x0000, TAG, 'Testing initial data...');
-    
-    const initialData = this.dataManager.getInitialWidgetData();
-    
-    // 验证初始数据结构
-    if (!initialData.playState || !initialData.currentSong || !initialData.progress) {
-      throw new Error('Initial data structure is incomplete');
-    }
-    
-    // 验证默认值
-    if (initialData.playState.isPlaying !== false) {
-      throw new Error('Initial play state should be false');
-    }
-    
-    if (initialData.currentSong.title !== '暂无播放') {
-      throw new Error('Initial song title should be "暂无播放"');
-    }
-    
-    hilog.info(0x0000, TAG, 'Initial data test passed');
-  }
-
-  /**
-   * 测试数据持久化
-   */
-  private async testDataPersistence(): Promise<void> {
-    hilog.info(0x0000, TAG, 'Testing data persistence...');
-    
-    const testFormId = 'test_form_001';
-    const testData: WidgetData = {
-      playState: {
-        isPlaying: true,
-        isPaused: false,
-        isLoading: false
-      },
-      currentSong: {
-        id: 'song_001',
-        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: false,
-        currentIndex: 0,
-        totalCount: 10
-      },
-      config: {
-        size: WidgetSize.LARGE,
-        theme: WidgetTheme.LIGHT,
-        showProgress: true,
-        showCover: true
-      }
-    };
-    
-    // 保存数据
-    await this.dataManager.saveWidgetData(testFormId, testData);
-    
-    // 读取数据
-    const retrievedData = await this.dataManager.getWidgetData(testFormId);
-    
-    // 验证数据一致性
-    if (retrievedData.currentSong.title !== testData.currentSong.title) {
-      throw new Error('Data persistence failed: song title mismatch');
-    }
-    
-    if (retrievedData.playState.isPlaying !== testData.playState.isPlaying) {
-      throw new Error('Data persistence failed: play state mismatch');
-    }
-    
-    hilog.info(0x0000, TAG, 'Data persistence test passed');
-  }
-
-  /**
-   * 测试缓存操作
-   */
-  private async testCacheOperations(): Promise<void> {
-    hilog.info(0x0000, TAG, 'Testing cache operations...');
-    
-    const testFormId = 'test_form_cache';
-    const testData = this.dataManager.getInitialWidgetData();
-    testData.currentSong.title = '缓存测试歌曲';
-    
-    // 测试缓存设置和获取
-    await this.dataManager.updateWidgetWithCache(testFormId, testData);
-    const cachedData = await this.dataManager.getWidgetDataWithCache(testFormId);
-    
-    if (cachedData.currentSong.title !== testData.currentSong.title) {
-      throw new Error('Cache operation failed: data mismatch');
-    }
-    
-    // 测试缓存清理
-    this.dataManager.clearWidgetCache(testFormId);
-    
-    // 获取缓存统计
-    const stats = this.dataManager.getCacheStats();
-    if (typeof stats.size !== 'number') {
-      throw new Error('Cache stats invalid');
-    }
-    
-    hilog.info(0x0000, TAG, 'Cache operations test passed');
-  }
-
-  /**
-   * 测试数据格式化
-   */
-  private async testDataFormatting(): Promise<void> {
-    hilog.info(0x0000, TAG, 'Testing data formatting...');
-    
-    const testData: WidgetData = {
-      playState: {
-        isPlaying: true,
-        isPaused: false,
-        isLoading: false
-      },
-      currentSong: {
-        id: 'format_test',
-        title: '这是一个非常长的歌曲标题用来测试文本截断功能',
-        artist: '这是一个非常长的艺术家名称',
-        album: '专辑',
-        coverImagePath: '',
-        duration: 180
-      },
-      progress: {
-        currentPosition: 90,
-        duration: 180,
-        percentage: 50,
-        currentTimeText: '01:30',
-        totalTimeText: '03:00'
-      },
-      playlist: {
-        hasNext: true,
-        hasPrevious: true,
-        currentIndex: 5,
-        totalCount: 20
-      },
-      config: {
-        size: WidgetSize.MEDIUM,
-        theme: WidgetTheme.AUTO,
-        showProgress: true,
-        showCover: false
-      }
-    };
-    
-    // 这里我们无法直接测试私有方法formatDataForWidget
-    // 但可以通过updateWidget间接测试
-    const testFormId = 'format_test_form';
-    await this.dataManager.saveWidgetData(testFormId, testData);
-    
-    hilog.info(0x0000, TAG, 'Data formatting test passed');
-  }
-
-  /**
-   * 测试批量操作
-   */
-  private async testBatchOperations(): Promise<void> {
-    hilog.info(0x0000, TAG, 'Testing batch operations...');
-    
-    // 创建多个测试卡片
-    const testForms = ['batch_001', 'batch_002', 'batch_003'];
-    const testData = this.dataManager.getInitialWidgetData();
-    testData.currentSong.title = '批量测试歌曲';
-    
-    // 保存多个卡片数据
-    for (const formId of testForms) {
-      await this.dataManager.saveWidgetData(formId, testData);
-    }
-    
-    // 测试批量更新
-    testData.currentSong.title = '批量更新后的歌曲';
-    await this.dataManager.updateAllWidgets(testData);
-    
-    // 验证更新结果
-    for (const formId of testForms) {
-      const updatedData = await this.dataManager.getWidgetData(formId);
-      if (updatedData.currentSong.title !== testData.currentSong.title) {
-        throw new Error(`Batch update failed for form: ${formId}`);
-      }
-    }
-    
-    // 清理测试数据
-    for (const formId of testForms) {
-      await this.dataManager.removeWidgetData(formId);
-    }
-    
-    hilog.info(0x0000, TAG, 'Batch operations test passed');
-  }
-
-  /**
-   * 创建测试数据
-   */
-  createTestWidgetData(): WidgetData {
-    return {
-      playState: {
-        isPlaying: true,
-        isPaused: false,
-        isLoading: false
-      },
-      currentSong: {
-        id: 'test_song_123',
-        title: '测试歌曲标题',
-        artist: '测试艺术家',
-        album: '测试专辑',
-        coverImagePath: '/test/path/cover.jpg',
-        duration: 300
-      },
-      progress: {
-        currentPosition: 150,
-        duration: 300,
-        percentage: 50,
-        currentTimeText: '02:30',
-        totalTimeText: '05:00'
-      },
-      playlist: {
-        hasNext: true,
-        hasPrevious: true,
-        currentIndex: 2,
-        totalCount: 15
-      },
-      config: {
-        size: WidgetSize.LARGE,
-        theme: WidgetTheme.DARK,
-        showProgress: true,
-        showCover: true
-      }
-    };
-  }
-}
-
-/**
- * 运行测试的便捷函数
- */
-export async function runWidgetDataManagerTests(): Promise<boolean> {
-  const tester = new WidgetDataManagerTest();
-  return await tester.runAllTests();
-}

+ 41 - 8
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -246,6 +246,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
         const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
         const currentSize = this.formSizeMap.get(formId) || WidgetSize.MEDIUM;
         const adaptedData = this.layoutManager.adaptDataForSize(data, currentSize);
         const adaptedData = this.layoutManager.adaptDataForSize(data, currentSize);
         this.widgetDataManager.updateWidget(formId, adaptedData);
         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}`);
       });
       });
 
 
       // 获取当前播放状态
       // 获取当前播放状态
@@ -265,6 +266,19 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
       await this.widgetDataManager.saveWidgetData(formId, adaptedData);
       await this.widgetDataManager.saveWidgetData(formId, adaptedData);
 
 
+      // 立即请求一次最新状态,并多次重试确保获取到真实状态
+      setTimeout(() => {
+        this.updateWidgetData(formId);
+      }, 500);
+      
+      setTimeout(() => {
+        this.updateWidgetData(formId);
+      }, 2000);
+      
+      setTimeout(() => {
+        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}`);
     } catch (error) {
     } catch (error) {
       hilog.error(0x0000, TAG, `Failed to initialize widget ${formId}: ${error}`);
       hilog.error(0x0000, TAG, `Failed to initialize widget ${formId}: ${error}`);
@@ -298,15 +312,33 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
     try {
     try {
       // 解析事件数据
       // 解析事件数据
       const actionData: Record<string, Object> = eventData as Record<string, Object>;
       const actionData: Record<string, Object> = eventData as Record<string, Object>;
-      const action: string = (actionData['action'] as string) || 'play_pause';
-      const params: Object = (actionData['params'] as Object) || new Object();
-
+      const action: string = (actionData['action'] as string) || 'message';
+      
       hilog.info(0x0000, TAG, `Handling widget event,action ${action}`);
       hilog.info(0x0000, TAG, `Handling widget event,action ${action}`);
       hilog.info(0x0000, TAG, `Handling widget event,actionData ${JSON.stringify(actionData)}`);
       hilog.info(0x0000, TAG, `Handling widget event,actionData ${JSON.stringify(actionData)}`);
-      const sendParams: Record<string, Object> = params as Record<string, Object>;
 
 
+      // 获取事件类型,优先从顶层的func字段获取,如果没有则从params中获取
+      let eventType: string = (actionData['func'] as string) || '';
+      let eventParams: Record<string, Object> = {};
+
+      if (!eventType) {
+        // 如果顶层没有func,尝试从params中获取
+        const params: Record<string, Object> = (actionData['params'] as Record<string, Object>) || {};
+        eventType = (params['func'] as string) || '';
+        eventParams = params;
+      } else {
+        // 如果顶层有func,则整个actionData就是参数
+        eventParams = actionData;
+      }
+
+      if (!eventType) {
+        hilog.warn(0x0000, TAG, `No event type found in widget event data`);
+        return;
+      }
+
+      hilog.info(0x0000, TAG, `Processing widget event type: ${eventType}`);
 
 
-      switch (sendParams['func']) {
+      switch (eventType) {
         case PLAY_PAUSE_EVENT:
         case PLAY_PAUSE_EVENT:
           await this.playerControlService.sendControlCommand(WidgetCommand.PLAY_PAUSE);
           await this.playerControlService.sendControlCommand(WidgetCommand.PLAY_PAUSE);
           break;
           break;
@@ -320,11 +352,12 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
           break;
           break;
 
 
         case SEEK_TO_EVENT:
         case SEEK_TO_EVENT:
-          const seekParams: Record<string, Object> = sendParams['params'] as Record<string, Object>;
+          const percentage = (eventParams['percentage'] as number) || 0;
           const controlParams: WidgetControlParams = {
           const controlParams: WidgetControlParams = {
-            percentage: (seekParams['percentage'] as number) || 0,
+            percentage: percentage,
             position: 0
             position: 0
           };
           };
+          hilog.info(0x0000, TAG, `Seeking to percentage: ${percentage}`);
           await this.playerControlService.sendControlCommand(WidgetCommand.SEEK_TO, controlParams);
           await this.playerControlService.sendControlCommand(WidgetCommand.SEEK_TO, controlParams);
           break;
           break;
 
 
@@ -359,7 +392,7 @@ implements SizeChangeListener, ThemeChangeListener, PreferencesChangeListener {
           break;
           break;
 
 
         default:
         default:
-          hilog.warn(0x0000, TAG, `Unknown widget action: ${action}`);
+          hilog.warn(0x0000, TAG, `Unknown widget event type: ${eventType}`);
           return;
           return;
       }
       }
 
 

+ 72 - 6
entry/src/main/ets/view/LocalMusic.ets

@@ -541,6 +541,12 @@ export struct LocalMusic {
 
 
     // 初始化卡片事件监听器
     // 初始化卡片事件监听器
     this.initWidgetEventListener();
     this.initWidgetEventListener();
+    
+    // 延迟广播初始状态到卡片(在songList初始化之后)
+    setTimeout(() => {
+      this.broadcastPlayerState();
+      LogUtils.getInstance().LOGI(`Delayed state broadcast: songList.length=${this.songList.length}, curIndex=${this.curIndex}`);
+    }, 2000);
 
 
     //折叠屏的屏幕显示模式变化
     //折叠屏的屏幕显示模式变化
     display.on('foldDisplayModeChange', (data) => {
     display.on('foldDisplayModeChange', (data) => {
@@ -836,8 +842,18 @@ export struct LocalMusic {
         this.name = this.currentSong.name
         this.name = this.currentSong.name
         this.cover = this.currentSong.pixelMapPath
         this.cover = this.currentSong.pixelMapPath
         AppStorage.setOrCreate('currentSong',this.currentSong) ;
         AppStorage.setOrCreate('currentSong',this.currentSong) ;
+        
+        // 立即广播初始状态到卡片,确保hasNext和hasPrevious正确
+        setTimeout(() => {
+          this.broadcastPlayerState();
+          LogUtils.getInstance().LOGI(`Initial state broadcasted: songList.length=${this.songList.length}, curIndex=${this.curIndex}`);
+        }, 100);
       } else {
       } else {
         this.name = '空空如也'
         this.name = '空空如也'
+        // 即使没有歌曲也要广播状态
+        setTimeout(() => {
+          this.broadcastPlayerState();
+        }, 100);
       }
       }
     })
     })
 
 
@@ -10488,7 +10504,11 @@ export struct LocalMusic {
       this.name = this.songList[this.curIndex].name
       this.name = this.songList[this.curIndex].name
       //this.cover = this.songList[this.curIndex].pixelMapPath
       //this.cover = this.songList[this.curIndex].pixelMapPath
       this.changeImageAnimation()
       this.changeImageAnimation()
-
+      
+      // 确保广播歌曲变化到卡片
+      setTimeout(() => {
+        this.broadcastPlayerState();
+      }, 200);
     }
     }
 
 
   }
   }
@@ -11288,10 +11308,11 @@ export struct LocalMusic {
    */
    */
   private broadcastPlayerProgress(): void {
   private broadcastPlayerProgress(): void {
     try {
     try {
+      const currentPos = this.mIjkMediaPlayer?.getCurrentPosition() || 0;
       const progressData: PlayProgress = {
       const progressData: PlayProgress = {
-        currentPosition: this.mIjkMediaPlayer?.getCurrentPosition() || 0,
+        currentPosition: currentPos,
         duration: this.duration || 0,
         duration: this.duration || 0,
-        percentage: this.duration > 0 ? ((this.mIjkMediaPlayer?.getCurrentPosition() || 0) / this.duration) * 100 : 0,
+        percentage: this.duration > 0 ? (currentPos / this.duration) * 100 : 0,
         currentTimeText: this.currentTime || '00:00',
         currentTimeText: this.currentTime || '00:00',
         totalTimeText: this.totalTime || '00:00'
         totalTimeText: this.totalTime || '00:00'
       };
       };
@@ -11304,6 +11325,8 @@ export struct LocalMusic {
       commonEventManager.publish(PLAYER_PROGRESS_CHANGED_EVENT, publishInfo, (err) => {
       commonEventManager.publish(PLAYER_PROGRESS_CHANGED_EVENT, publishInfo, (err) => {
         if (err) {
         if (err) {
           LogUtils.getInstance().error(`Failed to broadcast player progress: ${JSON.stringify(err)}`);
           LogUtils.getInstance().error(`Failed to broadcast player progress: ${JSON.stringify(err)}`);
+        } else {
+          LogUtils.getInstance().LOGI(`Progress broadcasted: ${progressData.percentage.toFixed(1)}%`);
         }
         }
       });
       });
     } catch (error) {
     } catch (error) {
@@ -11311,6 +11334,14 @@ export struct LocalMusic {
     }
     }
   }
   }
 
 
+  /**
+   * 强制更新卡片状态(用于测试和调试)
+   */
+  public forceUpdateWidgetState(): void {
+    LogUtils.getInstance().LOGI('Force updating widget state...');
+    this.broadcastPlayerState();
+  }
+
   /**
   /**
    * 广播播放器状态到卡片
    * 广播播放器状态到卡片
    */
    */
@@ -11339,13 +11370,36 @@ export struct LocalMusic {
         totalTimeText: this.stringForTime(this.duration || 0)
         totalTimeText: this.stringForTime(this.duration || 0)
       };
       };
 
 
+      const hasNext = this.curIndex < this.songList.length - 1;
+      const hasPrevious = this.curIndex > 0;
+      
       const playlist: PlaylistState = {
       const playlist: PlaylistState = {
-        hasNext: this.curIndex < this.songList.length - 1,
-        hasPrevious: this.curIndex > 0,
+        hasNext: hasNext,
+        hasPrevious: hasPrevious,
         currentIndex: this.curIndex,
         currentIndex: this.curIndex,
         totalCount: this.songList.length
         totalCount: this.songList.length
       };
       };
 
 
+      // 添加调试日志
+      LogUtils.getInstance().LOGI(`Widget playlist state: curIndex=${this.curIndex}, songListLength=${this.songList.length}, hasNext=${hasNext}, hasPrevious=${hasPrevious}`);
+
+      // 创建完整的WidgetData对象
+      const widgetData: WidgetData = {
+        playState,
+        currentSong,
+        progress,
+        playlist,
+        config: {
+          size: 'medium',
+          theme: 'auto',
+          showProgress: true,
+          showCover: true
+        }
+      };
+
+      // 更新AvSession监听器的数据
+      this.avSessionWidgetListener.updateWidgetData(widgetData);
+
       const stateData: PlayerStateBroadcastData = {
       const stateData: PlayerStateBroadcastData = {
         playState,
         playState,
         currentSong,
         currentSong,
@@ -11362,9 +11416,21 @@ export struct LocalMusic {
         if (err) {
         if (err) {
           LogUtils.getInstance().error(`Failed to broadcast player state: ${JSON.stringify(err)}`);
           LogUtils.getInstance().error(`Failed to broadcast player state: ${JSON.stringify(err)}`);
         } else {
         } else {
-          LogUtils.getInstance().LOGI('Player state broadcasted successfully');
+          LogUtils.getInstance().LOGI(`Player state broadcasted successfully: hasNext=${hasNext}, hasPrevious=${hasPrevious}, songTitle=${currentSong.title}`);
         }
         }
       });
       });
+
+      // 单独广播进度更新事件
+      const progressPublishInfo: commonEventManager.CommonEventPublishData = {
+        data: JSON.stringify(progress)
+      };
+
+      commonEventManager.publish(PLAYER_PROGRESS_CHANGED_EVENT, progressPublishInfo, (err) => {
+        if (err) {
+          LogUtils.getInstance().error(`Failed to broadcast progress: ${JSON.stringify(err)}`);
+        }
+      });
+
     } catch (error) {
     } catch (error) {
       LogUtils.getInstance().error(`Failed to broadcast player state: ${error}`);
       LogUtils.getInstance().error(`Failed to broadcast player state: ${error}`);
     }
     }

+ 14 - 8
entry/src/main/ets/widget/pages/PlayerWidgetLarge.ets

@@ -230,8 +230,8 @@ struct PlayerWidgetLarge {
         .width(40)
         .width(40)
         .height(40)
         .height(40)
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
-        .enabled(this.hasPrevious && !this.isLoading)
-        .opacity(this.getButtonOpacity(this.hasPrevious))
+        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
         .stateStyles({
           pressed: {
           pressed: {
             .scale({ x: 0.95, y: 0.95 })
             .scale({ x: 0.95, y: 0.95 })
@@ -243,14 +243,17 @@ struct PlayerWidgetLarge {
           }
           }
         })
         })
         .onClick(() => {
         .onClick(() => {
-          if (this.hasPrevious && !this.isLoading) {
-            console.info('Heanup PlayerWidgetLarge: Previous button clicked');
+          console.info(`Heanup PlayerWidgetLarge: Previous button clicked, hasPrevious=${this.hasPrevious}, isLoading=${this.isLoading}`);
+          if (!this.isLoading) {
+            console.info('Heanup PlayerWidgetLarge: Previous button action sent');
             postCardAction(this, {
             postCardAction(this, {
               'action': 'message',
               'action': 'message',
               'params': {
               'params': {
                 "func":"prev_song"
                 "func":"prev_song"
               }
               }
             });
             });
+          } else {
+            console.info('Heanup PlayerWidgetLarge: Previous button disabled due to loading');
           }
           }
         })
         })
 
 
@@ -302,8 +305,8 @@ struct PlayerWidgetLarge {
         .width(40)
         .width(40)
         .height(40)
         .height(40)
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
-        .enabled(this.hasNext && !this.isLoading)
-        .opacity(this.getButtonOpacity(this.hasNext))
+        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
         .stateStyles({
           pressed: {
           pressed: {
             .scale({ x: 0.95, y: 0.95 })
             .scale({ x: 0.95, y: 0.95 })
@@ -315,14 +318,17 @@ struct PlayerWidgetLarge {
           }
           }
         })
         })
         .onClick(() => {
         .onClick(() => {
-          if (this.hasNext && !this.isLoading) {
-            console.info('Heanup PlayerWidgetLarge: Next button clicked');
+          console.info(`Heanup PlayerWidgetLarge: Next button clicked, hasNext=${this.hasNext}, isLoading=${this.isLoading}`);
+          if (!this.isLoading) {
+            console.info('Heanup PlayerWidgetLarge: Next button action sent');
             postCardAction(this, {
             postCardAction(this, {
               'action': 'message',
               'action': 'message',
               'params': {
               'params': {
                 "func":"next_song"
                 "func":"next_song"
               }
               }
             });
             });
+          } else {
+            console.info('Heanup PlayerWidgetLarge: Next button disabled due to loading');
           }
           }
         })
         })
       }
       }

+ 17 - 14
entry/src/main/ets/widget/pages/PlayerWidgetMedium.ets

@@ -62,8 +62,8 @@ struct PlayerWidgetSmall {
         .width(32)
         .width(32)
         .height(32)
         .height(32)
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
-        .enabled(this.hasPrevious && !this.isLoading)
-        .opacity(this.getButtonOpacity(this.hasPrevious))
+        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
         .stateStyles({
           pressed: {
           pressed: {
             .scale({ x: 0.95, y: 0.95 })
             .scale({ x: 0.95, y: 0.95 })
@@ -75,14 +75,17 @@ struct PlayerWidgetSmall {
           }
           }
         })
         })
         .onClick(() => {
         .onClick(() => {
-          if (this.hasPrevious && !this.isLoading) {
-            console.info('Heanup PlayerWidgetSmall: Previous button clicked');
+          console.info(`Heanup PlayerWidgetMedium: Previous button clicked, hasPrevious=${this.hasPrevious}, isLoading=${this.isLoading}`);
+          if (!this.isLoading) {
+            console.info('Heanup PlayerWidgetMedium: Previous button action sent');
             postCardAction(this, {
             postCardAction(this, {
               'action': 'message',
               'action': 'message',
               'params': {
               'params': {
                 "func":"prev_song"
                 "func":"prev_song"
               }
               }
             });
             });
+          } else {
+            console.info('Heanup PlayerWidgetMedium: Previous button disabled due to loading');
           }
           }
         })
         })
 
 
@@ -131,8 +134,8 @@ struct PlayerWidgetSmall {
         .width(32)
         .width(32)
         .height(32)
         .height(32)
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
-        .enabled(this.hasNext && !this.isLoading)
-        .opacity(this.getButtonOpacity(this.hasNext))
+        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
         .stateStyles({
           pressed: {
           pressed: {
             .scale({ x: 0.95, y: 0.95 })
             .scale({ x: 0.95, y: 0.95 })
@@ -144,14 +147,17 @@ struct PlayerWidgetSmall {
           }
           }
         })
         })
         .onClick(() => {
         .onClick(() => {
-          if (this.hasNext && !this.isLoading) {
-            console.info('Heanup PlayerWidgetSmall: Next button clicked');
+          console.info(`Heanup PlayerWidgetMedium: Next button clicked, hasNext=${this.hasNext}, isLoading=${this.isLoading}`);
+          if (!this.isLoading) {
+            console.info('Heanup PlayerWidgetMedium: Next button action sent');
             postCardAction(this, {
             postCardAction(this, {
               'action': 'message',
               'action': 'message',
               'params': {
               'params': {
                 "func":"next_song"
                 "func":"next_song"
               }
               }
             });
             });
+          } else {
+            console.info('Heanup PlayerWidgetMedium: Next button disabled due to loading');
           }
           }
         })
         })
       }
       }
@@ -182,13 +188,10 @@ struct PlayerWidgetSmall {
         }
         }
       })
       })
       .onClick(() => {
       .onClick(() => {
-        console.info('Heanup PlayerWidgetSmall: Song info area clicked');
+        console.info('Heanup PlayerWidgetMedium: Song info area clicked');
         postCardAction(this, {
         postCardAction(this, {
-
-          'action': 'message',
-          'params': {
-            "func":"open_player"
-          }
+          'action': 'router',
+          'abilityName': 'EntryAbility'
         });
         });
       })
       })
     }
     }

+ 14 - 8
entry/src/main/ets/widget/pages/PlayerWidgetSmall.ets

@@ -62,8 +62,8 @@ struct PlayerWidgetSmall {
         .width(32)
         .width(32)
         .height(32)
         .height(32)
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
-        .enabled(this.hasPrevious && !this.isLoading)
-        .opacity(this.getButtonOpacity(this.hasPrevious))
+        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .opacity(this.hasPrevious ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
         .stateStyles({
           pressed: {
           pressed: {
             .scale({ x: 0.95, y: 0.95 })
             .scale({ x: 0.95, y: 0.95 })
@@ -75,14 +75,17 @@ struct PlayerWidgetSmall {
           }
           }
         })
         })
         .onClick(() => {
         .onClick(() => {
-          if (this.hasPrevious && !this.isLoading) {
-            console.info('Heanup PlayerWidgetSmall: Previous button clicked');
+          console.info(`Heanup PlayerWidgetSmall: Previous button clicked, hasPrevious=${this.hasPrevious}, isLoading=${this.isLoading}`);
+          if (!this.isLoading) {
+            console.info('Heanup PlayerWidgetSmall: Previous button action sent');
             postCardAction(this, {
             postCardAction(this, {
               'action': 'message',
               'action': 'message',
               'params': {
               'params': {
                 "func":"prev_song"
                 "func":"prev_song"
               }
               }
             });
             });
+          } else {
+            console.info('Heanup PlayerWidgetSmall: Previous button disabled due to loading');
           }
           }
         })
         })
 
 
@@ -131,8 +134,8 @@ struct PlayerWidgetSmall {
         .width(32)
         .width(32)
         .height(32)
         .height(32)
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
-        .enabled(this.hasNext && !this.isLoading)
-        .opacity(this.getButtonOpacity(this.hasNext))
+        .enabled(!this.isLoading)  // 临时启用按钮进行测试
+        .opacity(this.hasNext ? 1.0 : 0.6)  // 视觉上显示状态但不禁用
         .stateStyles({
         .stateStyles({
           pressed: {
           pressed: {
             .scale({ x: 0.95, y: 0.95 })
             .scale({ x: 0.95, y: 0.95 })
@@ -144,14 +147,17 @@ struct PlayerWidgetSmall {
           }
           }
         })
         })
         .onClick(() => {
         .onClick(() => {
-          if (this.hasNext && !this.isLoading) {
-            console.info('Heanup PlayerWidgetSmall: Next button clicked');
+          console.info(`Heanup PlayerWidgetSmall: Next button clicked, hasNext=${this.hasNext}, isLoading=${this.isLoading}`);
+          if (!this.isLoading) {
+            console.info('Heanup PlayerWidgetSmall: Next button action sent');
             postCardAction(this, {
             postCardAction(this, {
               'action': 'message',
               'action': 'message',
               'params': {
               'params': {
                 "func":"next_song"
                 "func":"next_song"
               }
               }
             });
             });
+          } else {
+            console.info('Heanup PlayerWidgetSmall: Next button disabled due to loading');
           }
           }
         })
         })
       }
       }