浏览代码

卡片数据存到数据库

chendeben 1 年之前
父节点
当前提交
244e9423ec

+ 69 - 0
entry/src/main/ets/common/service/UnifiedPlayerService.ets

@@ -39,6 +39,8 @@ import MediaTable from '../util/MediaTable';
 import { Utility } from '../util/Utility';
 import { FormRdbHelper } from '../../database/FormRdbHelper';
 import { FormInfo } from '../../viewmodel/FormInfo';
+import { WidgetDataRdbHelper } from '../../database/WidgetDataRdbHelper';
+import { WidgetDataInfo } from '../../viewmodel/WidgetDataInfo';
 
 /**
  * 服务就绪状态详情接口
@@ -3232,6 +3234,10 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       // 卡片图片显示必填字段
       formImages: imgMap,
     };
+
+    // 将widgetData存入数据库
+    this.saveWidgetDataToDatabase(widgetData, formData);
+
     return widgetData;
   }
 
@@ -3254,6 +3260,69 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
   }
 
+  /**
+   * 将widgetData存入数据库
+   */
+  private async saveWidgetDataToDatabase(widgetData: widgeData, formData: VideoItem): Promise<void> {
+    try {
+      // 从getContext方法获取context
+      let context = this.getContext();
+      
+      // 如果还是没有context,尝试从AppStorage获取
+      if (!context) {
+        context = AppStorage.get('context') as common.UIAbilityContext;
+      }
+
+      if (!context) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService saveWidgetDataToDatabase: No context available');
+        return;
+      }
+
+      if (!formData || !formData.id) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService saveWidgetDataToDatabase: No valid current song');
+        return;
+      }
+
+      const widgetDataInfo = new WidgetDataInfo();
+      
+      // 基本信息
+      widgetDataInfo.songId = formData.id;
+      widgetDataInfo.name = formData.name || '';
+      widgetDataInfo.artist = formData.artist || '';
+      widgetDataInfo.album = formData.album || '';
+      widgetDataInfo.pixelMapPath = formData.pixelMapPath || '';
+      widgetDataInfo.duration = typeof formData.duration === 'string' ? parseInt(formData.duration || '0') : (formData.duration || 0);
+      widgetDataInfo.filePath = formData.filePath || '';
+      widgetDataInfo.imgName = widgetData.imgName || '';
+      widgetDataInfo.imageColorHex = widgetData.imageColorHex || '2A2A2A';
+      widgetDataInfo.isFavorite = widgetData.isFavorite || false;
+
+      // 播放状态信息
+      widgetDataInfo.isPlaying = widgetData.isPlaying;
+      widgetDataInfo.isPaused = widgetData.isPaused;
+      widgetDataInfo.isLoading = widgetData.isLoading;
+      widgetDataInfo.currentPosition = widgetData.currentPosition;
+      widgetDataInfo.hasNext = widgetData.hasNext;
+      widgetDataInfo.hasPrevious = widgetData.hasPrevious;
+      widgetDataInfo.playMode = widgetData.playMode;
+
+      // 播放列表信息
+      widgetDataInfo.currentIndex = widgetData.currentIndex;
+      widgetDataInfo.totalCount = widgetData.totalCount;
+
+      // 时间信息
+      widgetDataInfo.currentTimeText = widgetData.currentTimeText;
+      widgetDataInfo.totalTimeText = widgetData.totalTimeText;
+      widgetDataInfo.progressPercentage = widgetData.progressPercentage;
+
+      await WidgetDataRdbHelper.getInstance(context).insertOrUpdateWidgetData(widgetDataInfo);
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService saveWidgetDataToDatabase: Widget data saved to database for song: ${formData.name}`);
+      
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService saveWidgetDataToDatabase: Failed to save widget data to database: ${error}`);
+    }
+  }
+
 
   /**
    * 状态变化时更新卡片

+ 323 - 0
entry/src/main/ets/database/WidgetDataRdbHelper.ets

@@ -0,0 +1,323 @@
+import relationalStore from '@ohos.data.relationalStore';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { Context } from '@kit.AbilityKit';
+import { WidgetDataInfo } from '../viewmodel/WidgetDataInfo';
+
+const TAG = 'WidgetDataRdbHelper';
+
+/**
+ * Widget数据数据库操作助手类
+ */
+export class WidgetDataRdbHelper {
+  private static instance: WidgetDataRdbHelper | null = null;
+  private rdbStore: relationalStore.RdbStore | null = null;
+  private context: Context | null = null;
+
+  /**
+   * 数据库配置
+   */
+  private static readonly STORE_CONFIG: relationalStore.StoreConfig = {
+    name: 'WidgetDataDatabase.db',
+    securityLevel: relationalStore.SecurityLevel.S1,
+    encrypt: false
+  };
+
+  /**
+   * 表名
+   */
+  private static readonly WIDGET_DATA_TABLE = 'widget_data_info';
+
+  /**
+   * 创建表的SQL语句
+   */
+  private static readonly CREATE_TABLE_SQL = `CREATE TABLE IF NOT EXISTS ${WidgetDataRdbHelper.WIDGET_DATA_TABLE} (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    song_id TEXT NOT NULL,
+    name TEXT NOT NULL,
+    artist TEXT NOT NULL,
+    album TEXT NOT NULL,
+    pixel_map_path TEXT,
+    duration INTEGER DEFAULT 0,
+    file_path TEXT,
+    img_name TEXT,
+    image_color_hex TEXT DEFAULT '2A2A2A',
+    is_favorite INTEGER DEFAULT 0,
+    is_playing INTEGER DEFAULT 0,
+    is_paused INTEGER DEFAULT 1,
+    is_loading INTEGER DEFAULT 0,
+    current_position INTEGER DEFAULT 0,
+    has_next INTEGER DEFAULT 0,
+    has_previous INTEGER DEFAULT 0,
+    play_mode INTEGER DEFAULT 0,
+    current_index INTEGER DEFAULT 0,
+    total_count INTEGER DEFAULT 0,
+    current_time_text TEXT DEFAULT '',
+    total_time_text TEXT DEFAULT '',
+    progress_percentage REAL DEFAULT 0,
+    create_time TEXT NOT NULL,
+    update_time TEXT NOT NULL
+  )`;
+
+  private constructor() {}
+
+  /**
+   * 获取单例实例
+   */
+  static getInstance(context?: Context): WidgetDataRdbHelper {
+    if (!WidgetDataRdbHelper.instance) {
+      WidgetDataRdbHelper.instance = new WidgetDataRdbHelper();
+    }
+    if (context && !WidgetDataRdbHelper.instance.context) {
+      WidgetDataRdbHelper.instance.context = context;
+    }
+    return WidgetDataRdbHelper.instance;
+  }
+
+  /**
+   * 初始化数据库
+   */
+  private async initDatabase(): Promise<void> {
+    if (this.rdbStore) {
+      return;
+    }
+
+    if (!this.context) {
+      throw new Error('Context is not available');
+    }
+
+    try {
+      this.rdbStore = await relationalStore.getRdbStore(this.context, WidgetDataRdbHelper.STORE_CONFIG);
+      await this.rdbStore.executeSql(WidgetDataRdbHelper.CREATE_TABLE_SQL);
+      hilog.info(0x0000, TAG, 'Widget data database initialized successfully');
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to initialize widget data database: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 获取数据库实例
+   */
+  private async getRdbStore(): Promise<relationalStore.RdbStore> {
+    if (!this.rdbStore) {
+      await this.initDatabase();
+    }
+    return this.rdbStore!;
+  }
+
+  /**
+   * 插入或更新Widget数据信息
+   * 使用 REPLACE INTO 语句,如果记录存在则更新,不存在则插入
+   */
+  async insertOrUpdateWidgetData(widgetDataInfo: WidgetDataInfo): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      
+      // 先删除现有记录(只保留最新的widget数据)
+      await this.clearAllWidgetData();
+      
+      const valueBucket: relationalStore.ValuesBucket = {
+        'song_id': widgetDataInfo.songId,
+        'name': widgetDataInfo.name,
+        'artist': widgetDataInfo.artist,
+        'album': widgetDataInfo.album,
+        'pixel_map_path': widgetDataInfo.pixelMapPath,
+        'duration': widgetDataInfo.duration,
+        'file_path': widgetDataInfo.filePath,
+        'img_name': widgetDataInfo.imgName,
+        'image_color_hex': widgetDataInfo.imageColorHex,
+        'is_favorite': widgetDataInfo.isFavorite ? 1 : 0,
+        'is_playing': widgetDataInfo.isPlaying ? 1 : 0,
+        'is_paused': widgetDataInfo.isPaused ? 1 : 0,
+        'is_loading': widgetDataInfo.isLoading ? 1 : 0,
+        'current_position': widgetDataInfo.currentPosition,
+        'has_next': widgetDataInfo.hasNext ? 1 : 0,
+        'has_previous': widgetDataInfo.hasPrevious ? 1 : 0,
+        'play_mode': widgetDataInfo.playMode,
+        'current_index': widgetDataInfo.currentIndex,
+        'total_count': widgetDataInfo.totalCount,
+        'current_time_text': widgetDataInfo.currentTimeText,
+        'total_time_text': widgetDataInfo.totalTimeText,
+        'progress_percentage': widgetDataInfo.progressPercentage,
+        'create_time': widgetDataInfo.createTime,
+        'update_time': new Date().toISOString(),
+      };
+      
+      await store.insert(WidgetDataRdbHelper.WIDGET_DATA_TABLE, valueBucket);
+      hilog.info(0x0000, TAG, `Widget data inserted successfully for song: ${widgetDataInfo.name}`);
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to insert widget data: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 获取最新的Widget数据信息
+   */
+  async getLatestWidgetData(): Promise<WidgetDataInfo | undefined> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(WidgetDataRdbHelper.WIDGET_DATA_TABLE);
+      predicates.orderByDesc('update_time');
+      
+      const resultSet = await store.query(predicates);
+      if (resultSet.rowCount === 0) {
+        resultSet.close();
+        return undefined;
+      }
+      
+      resultSet.goToFirstRow();
+      const widgetDataInfo = this.mapRowToWidgetDataInfo(resultSet);
+      resultSet.close();
+      
+      hilog.info(0x0000, TAG, `Latest widget data retrieved: ${widgetDataInfo.name}`);
+      return widgetDataInfo;
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to query latest widget data: ${businessError.message}`);
+      return undefined;
+    }
+  }
+
+  /**
+   * 根据歌曲ID查询Widget数据信息
+   */
+  async queryWidgetDataBySongId(songId: string): Promise<WidgetDataInfo | undefined> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(WidgetDataRdbHelper.WIDGET_DATA_TABLE);
+      predicates.equalTo('song_id', songId);
+      
+      const resultSet = await store.query(predicates);
+      if (resultSet.rowCount === 0) {
+        resultSet.close();
+        return undefined;
+      }
+      
+      resultSet.goToFirstRow();
+      const widgetDataInfo = this.mapRowToWidgetDataInfo(resultSet);
+      resultSet.close();
+      
+      hilog.info(0x0000, TAG, `Widget data queried successfully for song: ${songId}`);
+      return widgetDataInfo;
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to query widget data by song ID: ${businessError.message}`);
+      return undefined;
+    }
+  }
+
+  /**
+   * 查询所有Widget数据信息
+   */
+  async queryAllWidgetData(): Promise<WidgetDataInfo[]> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(WidgetDataRdbHelper.WIDGET_DATA_TABLE);
+      predicates.orderByDesc('update_time');
+      
+      const resultSet = await store.query(predicates);
+      
+      const widgetDataList: WidgetDataInfo[] = [];
+      if (resultSet.rowCount > 0) {
+        resultSet.goToFirstRow();
+        do {
+          const widgetDataInfo = this.mapRowToWidgetDataInfo(resultSet);
+          widgetDataList.push(widgetDataInfo);
+        } while (resultSet.goToNextRow());
+      }
+      
+      resultSet.close();
+      hilog.info(0x0000, TAG, `Queried ${widgetDataList.length} widget data records`);
+      return widgetDataList;
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to query all widget data: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 删除Widget数据信息
+   */
+  async deleteWidgetData(songId: string): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(WidgetDataRdbHelper.WIDGET_DATA_TABLE);
+      predicates.equalTo('song_id', songId);
+      
+      await store.delete(predicates);
+      hilog.info(0x0000, TAG, `Widget data deleted successfully for song: ${songId}`);
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to delete widget data: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 清空所有Widget数据信息
+   */
+  async clearAllWidgetData(): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(WidgetDataRdbHelper.WIDGET_DATA_TABLE);
+      
+      await store.delete(predicates);
+      hilog.info(0x0000, TAG, 'All widget data cleared successfully');
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to clear all widget data: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 将查询结果映射为WidgetDataInfo对象
+   */
+  private mapRowToWidgetDataInfo(resultSet: relationalStore.ResultSet): WidgetDataInfo {
+    const widgetDataInfo = new WidgetDataInfo();
+    
+    widgetDataInfo.id = resultSet.getLong(resultSet.getColumnIndex('id'));
+    widgetDataInfo.songId = resultSet.getString(resultSet.getColumnIndex('song_id'));
+    widgetDataInfo.name = resultSet.getString(resultSet.getColumnIndex('name'));
+    widgetDataInfo.artist = resultSet.getString(resultSet.getColumnIndex('artist'));
+    widgetDataInfo.album = resultSet.getString(resultSet.getColumnIndex('album'));
+    widgetDataInfo.pixelMapPath = resultSet.getString(resultSet.getColumnIndex('pixel_map_path'));
+    widgetDataInfo.duration = resultSet.getLong(resultSet.getColumnIndex('duration'));
+    widgetDataInfo.filePath = resultSet.getString(resultSet.getColumnIndex('file_path'));
+    widgetDataInfo.imgName = resultSet.getString(resultSet.getColumnIndex('img_name'));
+    widgetDataInfo.imageColorHex = resultSet.getString(resultSet.getColumnIndex('image_color_hex'));
+    widgetDataInfo.isFavorite = resultSet.getLong(resultSet.getColumnIndex('is_favorite')) === 1;
+    widgetDataInfo.isPlaying = resultSet.getLong(resultSet.getColumnIndex('is_playing')) === 1;
+    widgetDataInfo.isPaused = resultSet.getLong(resultSet.getColumnIndex('is_paused')) === 1;
+    widgetDataInfo.isLoading = resultSet.getLong(resultSet.getColumnIndex('is_loading')) === 1;
+    widgetDataInfo.currentPosition = resultSet.getLong(resultSet.getColumnIndex('current_position'));
+    widgetDataInfo.hasNext = resultSet.getLong(resultSet.getColumnIndex('has_next')) === 1;
+    widgetDataInfo.hasPrevious = resultSet.getLong(resultSet.getColumnIndex('has_previous')) === 1;
+    widgetDataInfo.playMode = resultSet.getLong(resultSet.getColumnIndex('play_mode'));
+    widgetDataInfo.currentIndex = resultSet.getLong(resultSet.getColumnIndex('current_index'));
+    widgetDataInfo.totalCount = resultSet.getLong(resultSet.getColumnIndex('total_count'));
+    widgetDataInfo.currentTimeText = resultSet.getString(resultSet.getColumnIndex('current_time_text'));
+    widgetDataInfo.totalTimeText = resultSet.getString(resultSet.getColumnIndex('total_time_text'));
+    widgetDataInfo.progressPercentage = resultSet.getDouble(resultSet.getColumnIndex('progress_percentage'));
+    widgetDataInfo.createTime = resultSet.getString(resultSet.getColumnIndex('create_time'));
+    widgetDataInfo.updateTime = resultSet.getString(resultSet.getColumnIndex('update_time'));
+    
+    return widgetDataInfo;
+  }
+
+  /**
+   * 关闭数据库
+   */
+  async close(): Promise<void> {
+    if (this.rdbStore) {
+      await this.rdbStore.close();
+      this.rdbStore = null;
+      hilog.info(0x0000, TAG, 'Widget data database closed');
+    }
+  }
+}

+ 48 - 0
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -5,6 +5,8 @@ import { PreferencesUtil } from '../common/utils/PreferencesUtil';
 import { UnifiedPlayerService } from '../common/service/UnifiedPlayerService';
 import { FormRdbHelper } from '../database/FormRdbHelper';
 import { FormInfo } from '../viewmodel/FormInfo';
+import { WidgetDataRdbHelper } from '../database/WidgetDataRdbHelper';
+import { WidgetDataInfo } from '../viewmodel/WidgetDataInfo';
 
 const TAG = 'EntryFormAbility';
 
@@ -90,6 +92,9 @@ export default class EntryFormAbility extends FormExtensionAbility {
     // 异步获取真实数据并更新卡片
     this.updateFormWithRealData(formId);
 
+    // 尝试从数据库获取已保存的widget数据
+    this.loadWidgetDataFromDatabase(formId);
+
     // 立即返回一个加载中的临时数据,以满足同步返回的要求
     const loadingData: GeneratedObjectLiteralInterface_1 = {
       name: '正在加载...',
@@ -127,6 +132,49 @@ export default class EntryFormAbility extends FormExtensionAbility {
     }, 100); // 延迟100ms,给服务一点初始化时间
   }
 
+  /**
+   * 从数据库加载widget数据并更新卡片
+   * @param formId 卡片ID
+   */
+  private loadWidgetDataFromDatabase(formId: string): void {
+    setTimeout(async () => {
+      try {
+        hilog.info(0x0000, TAG, `[${formId}] Loading widget data from database.`);
+        
+        const widgetDataRdbHelper = WidgetDataRdbHelper.getInstance(this.context);
+        const latestWidgetData = await widgetDataRdbHelper.getLatestWidgetData();
+        
+        if (latestWidgetData) {
+          // 将数据库数据转换为卡片需要的格式
+          const formData: GeneratedObjectLiteralInterface_1 = {
+            name: latestWidgetData.name || '暂无歌曲',
+            artist: latestWidgetData.artist || '未知艺术家',
+            album: latestWidgetData.album || '',
+            imageColorHex: latestWidgetData.imageColorHex || '2A2A2A',
+            isPlaying: latestWidgetData.isPlaying || false,
+            isPaused: latestWidgetData.isPaused !== false, // 默认为暂停状态
+            isLoading: latestWidgetData.isLoading || false,
+            currentTimeText: latestWidgetData.currentTimeText || '00:00',
+            totalTimeText: latestWidgetData.totalTimeText || '00:00',
+            progressPercentage: latestWidgetData.progressPercentage || 0,
+            imgName: latestWidgetData.imgName || '',
+            isFavorite: latestWidgetData.isFavorite || false
+          };
+
+          // 更新卡片显示
+          const bindingData = formBindingData.createFormBindingData(formData);
+          await formProvider.updateForm(formId, bindingData);
+          
+          hilog.info(0x0000, TAG, `[${formId}] Successfully updated form with database widget data: ${latestWidgetData.name}`);
+        } else {
+          hilog.info(0x0000, TAG, `[${formId}] No widget data found in database, will wait for real-time data.`);
+        }
+      } catch (error) {
+        hilog.error(0x0000, TAG, `[${formId}] Failed to load widget data from database: ${error}`);
+      }
+    }, 50); // 比updateFormWithRealData稍早一些执行,优先显示数据库数据
+  }
+
 
   /**
    * 卡片更新时调用

+ 135 - 0
entry/src/main/ets/viewmodel/WidgetDataInfo.ets

@@ -0,0 +1,135 @@
+/**
+ * Widget数据信息类
+ * 用于数据库存储的Widget数据模型
+ */
+export class WidgetDataInfo {
+  /**
+   * 数据库主键
+   */
+  id: number = 0;
+
+  /**
+   * 歌曲ID
+   */
+  songId: string = '';
+
+  /**
+   * 歌曲名称
+   */
+  name: string = '';
+
+  /**
+   * 艺术家
+   */
+  artist: string = '';
+
+  /**
+   * 专辑
+   */
+  album: string = '';
+
+  /**
+   * 封面图片路径
+   */
+  pixelMapPath: string = '';
+
+  /**
+   * 歌曲时长(ms)
+   */
+  duration: number = 0;
+
+  /**
+   * 文件路径
+   */
+  filePath: string = '';
+
+  /**
+   * 图片名称
+   */
+  imgName: string = '';
+
+  /**
+   * 图片主色调
+   */
+  imageColorHex: string = '2A2A2A';
+
+  /**
+   * 是否收藏
+   */
+  isFavorite: boolean = false;
+
+  /**
+   * 是否正在播放
+   */
+  isPlaying: boolean = false;
+
+  /**
+   * 是否暂停
+   */
+  isPaused: boolean = true;
+
+  /**
+   * 是否加载中
+   */
+  isLoading: boolean = false;
+
+  /**
+   * 当前播放位置(ms)
+   */
+  currentPosition: number = 0;
+
+  /**
+   * 是否有下一首
+   */
+  hasNext: boolean = false;
+
+  /**
+   * 是否有上一首
+   */
+  hasPrevious: boolean = false;
+
+  /**
+   * 播放模式
+   */
+  playMode: number = 0;
+
+  /**
+   * 当前播放索引
+   */
+  currentIndex: number = 0;
+
+  /**
+   * 播放列表总数
+   */
+  totalCount: number = 0;
+
+  /**
+   * 当前时间文本
+   */
+  currentTimeText: string = '';
+
+  /**
+   * 总时间文本
+   */
+  totalTimeText: string = '';
+
+  /**
+   * 播放进度百分比
+   */
+  progressPercentage: number = 0;
+
+  /**
+   * 创建时间
+   */
+  createTime: string = '';
+
+  /**
+   * 更新时间
+   */
+  updateTime: string = '';
+
+  constructor() {
+    this.createTime = new Date().toISOString();
+    this.updateTime = new Date().toISOString();
+  }
+}