onecold пре 4 месеци
родитељ
комит
7c85db2039

+ 113 - 18
entry/src/main/ets/entryability/EntryAbility.ets

@@ -63,6 +63,11 @@ class EmptyRpcParcelable implements rpc.Parcelable {
  * - 事件分发
  */
 export default class EntryAbility extends UIAbility {
+    /**
+     * 处理音乐卡片通过 callee/call 方式发来的控制请求。
+     * 这里会从 RPC 文本中解析动作、来源、卡片实例和拖动进度,
+     * 记录卡片实例后再把动作转发到统一的播放控制分发入口。
+     */
     private readonly musicCardCallHandler = (data: rpc.MessageSequence): rpc.Parcelable => {
         try {
             const rawText: string = data.readString() ?? '';
@@ -84,6 +89,11 @@ export default class EntryAbility extends UIAbility {
         }
         return new EmptyRpcParcelable();
     }
+
+    /**
+     * 处理应用内 eventHub 转发过来的音乐卡片控制事件。
+     * 该入口主要服务于运行时已启动的播放器场景,按动作直接调用播放器控制器。
+     */
     private readonly musicCardActionForwardHandler = (data?: Object): void => {
         const payloadText: string = data ? JSON.stringify(data) : '';
         const action = this.resolveMusicCardActionFromText(payloadText);
@@ -122,13 +132,10 @@ export default class EntryAbility extends UIAbility {
     // private awareness: smartMobilityCommon.SmartMobilityAwareness = smartMobilityCommon.getSmartMobilityAwareness();
     // private awareness: smartMobilityCommon.SmartMobilityAwareness|undefined = canIUse("SystemCapability.CarService.DistributedEngine")?smartMobilityCommon.getSmartMobilityAwareness():undefined;
     private awareness?: smartMobilityCommon.SmartMobilityAwareness;//修复api23 报错问题
+
     /**
-     * 窗口尺寸变化回调函数
-     * @param windowSize 新的窗口尺寸对象
-     * 功能:
-     * 1. 获取最新的窗口断点尺寸
-     * 2. 更新AppStorage中的尺寸状态
-     * 3. 记录尺寸变化日志
+     * 主窗口尺寸变化时同步更新全局窗口状态。
+     * 包括宽高断点、实际尺寸以及横竖屏标记,供页面响应式布局读取。
      */
     private onWindowSizeChange: (windowSize: window.Size) => void = async (windowSize: window.Size) => {
         // 获取宽度断点并更新全局状态
@@ -154,7 +161,10 @@ export default class EntryAbility extends UIAbility {
     };
 
 
-
+    /**
+     * 监听系统避让区域变化,并把状态栏/导航条高度写入全局存储。
+     * 页面可以据此修正顶部和底部安全区域占位。
+     */
     onAvoidAreaChange = (data: window.AvoidAreaOptions) => {
         if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
             let topRectHeight =  px2vp(data.area.topRect.height);
@@ -165,6 +175,11 @@ export default class EntryAbility extends UIAbility {
         }
 
     }
+
+    /**
+     * 监听窗口显示设备变化,识别当前窗口是否切换到 HiCar 等车机场景。
+     * 结果会同步到 AppStorage,供界面和播放策略判断使用。
+     */
     onDisplayIdChange=(displayId: number)=> {
         let curDisplay = display.getDisplayByIdSync(displayId);
         console.info('twocold curDisplay 2 = '+curDisplay.name);
@@ -174,6 +189,11 @@ export default class EntryAbility extends UIAbility {
         this.logHiCar('info', `curDisplayIsHiCar=${isHiCarDisplay}`);
     }
 
+    /**
+     * Ability 首次创建时执行应用级初始化。
+     * 这里会建立上下文、初始化偏好与后台播放宿主、注册音乐卡片控制入口,
+     * 同时处理冷启动 Want、分享拉起、WebDAV 初始化和 HiCar 状态读取。
+     */
     async onCreate(want:Want, launchParam:AbilityConstant.LaunchParam) {
         AppUtil.init(this.context);
         AppStorage.setOrCreate('context', this.context);
@@ -208,12 +228,8 @@ export default class EntryAbility extends UIAbility {
     }
 
     /**
-     * 初始化WebDAV管理器
-     * 功能:
-     * 1. 设置Context
-     * 2. 初始化数据库和Preferences
-     * 3. 创建WebDAV数据库表
-     * 4. 加载WebDAV账户信息
+     * 初始化 WebDAV 相关基础设施。
+     * 包括数据库上下文注入、RemoteDriveManager 初始化、建表、账户恢复和历史数据加载。
      */
     private async initWebDAV() {
         try {
@@ -248,6 +264,10 @@ export default class EntryAbility extends UIAbility {
         }
     }
 
+    /**
+     * Ability 已存在时处理新的 Want。
+     * 该流程会重复必要初始化,并重新分发卡片动作、外部 URI、分享数据等入口事件。
+     */
     async onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
         hilog.info(0x0000, 'testTag', `onNewWant, want=${JSON.stringify(want)}`);
         super.onNewWant(want, launchParam);
@@ -266,6 +286,10 @@ export default class EntryAbility extends UIAbility {
 
     }
 
+    /**
+     * 从 Want 参数中提取音乐卡片动作并进行统一分发。
+     * 如果该动作会被 call 通道优先处理,则在这里直接忽略,避免重复执行。
+     */
     private handleMusicCardActionFromWant(want: Want): void {
         const parameters = want.parameters as Object | undefined;
         if (parameters === undefined) {
@@ -290,6 +314,10 @@ export default class EntryAbility extends UIAbility {
         this.dispatchMusicCardAction(action, 'want', seekPositionMs);
     }
 
+    /**
+     * 根据动作类型把音乐卡片控制命令路由到前台运行时或后台播放宿主。
+     * 支持播放/暂停、上一首、下一首、打开播放器以及拖动进度等动作。
+     */
     private dispatchMusicCardAction(action: string, source: string, seekPositionMs: string = ''): void {
         Logger.info('EntryAbility', `[MusicCast] dispatch action=${action}, source=${source}, seek=${seekPositionMs}`);
         const playbackController: MusicPlaybackController = MusicPlaybackController.getInstance();
@@ -347,6 +375,9 @@ export default class EntryAbility extends UIAbility {
         Logger.warn('EntryAbility', `[MusicCast] action ignored unsupported action=${action}, source=${source}`);
     }
 
+    /**
+     * 注册音乐卡片 call 通道处理器,使卡片能够通过 callee 接口直接控制播放。
+     */
     private registerMusicCardCallHandler(): void {
         try {
             this.callee.on(MusicCardActionConstants.CALL_METHOD_HANDLE_ACTION, this.musicCardCallHandler);
@@ -356,6 +387,9 @@ export default class EntryAbility extends UIAbility {
         }
     }
 
+    /**
+     * 注销音乐卡片 call 通道处理器,避免 Ability 销毁后仍残留调用入口。
+     */
     private unregisterMusicCardCallHandler(): void {
         try {
             this.callee.off(MusicCardActionConstants.CALL_METHOD_HANDLE_ACTION);
@@ -365,6 +399,10 @@ export default class EntryAbility extends UIAbility {
         }
     }
 
+    /**
+     * 当动作来源确认为桌面卡片时,登记对应的卡片实例 ID。
+     * 这样后续播放器状态变更时可以正确回推到对应卡片。
+     */
     private registerMusicCardFormIdIfNeeded(formId: string, source: string): void {
         if (source !== MusicCardActionConstants.ACTION_SOURCE_WIDGET) {
             return;
@@ -375,6 +413,10 @@ export default class EntryAbility extends UIAbility {
         MusicCardFormStore.addFormId(this.context, formId);
     }
 
+    /**
+     * 从文本化参数中解析音乐卡片动作字段。
+     * 解析失败或字段缺失时返回空字符串。
+     */
     private resolveMusicCardActionFromText(payloadText: string): string {
         if (StrUtil.isEmpty(payloadText)) {
             return '';
@@ -386,6 +428,9 @@ export default class EntryAbility extends UIAbility {
         return match[1];
     }
 
+    /**
+     * 从文本化参数中解析动作来源字段,用于区分 widget、call 等入口。
+     */
     private resolveMusicCardSourceFromText(payloadText: string): string {
         if (StrUtil.isEmpty(payloadText)) {
             return '';
@@ -397,6 +442,9 @@ export default class EntryAbility extends UIAbility {
         return match[1];
     }
 
+    /**
+     * 从文本化参数中解析卡片 formId,兼容字符串和数字两种序列化形式。
+     */
     private resolveMusicCardFormIdFromText(payloadText: string): string {
         if (StrUtil.isEmpty(payloadText)) {
             return '';
@@ -412,6 +460,9 @@ export default class EntryAbility extends UIAbility {
         return '';
     }
 
+    /**
+     * 从文本化参数中解析 seek 目标位置,兼容字符串和数字两种格式。
+     */
     private resolveMusicCardSeekPositionFromText(payloadText: string): string {
         if (StrUtil.isEmpty(payloadText)) {
             return '';
@@ -427,6 +478,10 @@ export default class EntryAbility extends UIAbility {
         return '';
     }
 
+    /**
+     * 按当前播放器运行状态决定打开方式。
+     * 如果前台播放器已可直接展示,则唤起播放器页,否则请求后台恢复后打开。
+     */
     private routeToMusicPlayerPage(): void {
         const openRoute = PlaybackRestoreCoordinator.resolveMusicCardOpenRoute(
             PlaybackCoordinator.getInstance().hasRuntime()
@@ -438,11 +493,17 @@ export default class EntryAbility extends UIAbility {
         requestPlaybackPlayerOpen();
     }
 
+    /**
+     * 处理微信等第三方通过 Want 拉起应用时的回调数据。
+     */
     private handleWeChatCallIfNeed(want: Want) {
         WXApi.handleWant(want, WXEventHandler)
     }
 
-    //处理其他app点击其他应用打开播放器播放视频或者音频
+    /**
+     * 处理其他应用通过 URI 拉起本应用的场景。
+     * 当 Want 中带有可播放媒体地址时,继续向应用内广播打开事件。
+     */
     loadDoWant(want: Want){
         // console.info('onecold KnockController  碰一碰 want ='+JSON.stringify(want));
         let uri = want.uri;
@@ -454,7 +515,11 @@ export default class EntryAbility extends UIAbility {
 
         this.doSendEmit(uri)
     }
-    //广播通知打开播放器播放视频或者音频
+
+    /**
+     * 根据 URI 媒体类型发送应用内广播,通知播放器打开音频或视频资源。
+     * 这里使用短延时,给前台页面和订阅方留出初始化时间。
+     */
     doSendEmit(uri:string){
         setTimeout(async ()=>{
             let eventData: emitter.EventData = {
@@ -471,8 +536,10 @@ export default class EntryAbility extends UIAbility {
 
     }
 
-    // 华为分享拉起接收   处理分享数据
-    // 1. 改造 handleParam 为异步函数,让其返回 Promise
+    /**
+     * 处理华为系统分享拉起的数据。
+     * 从分享记录中提取 URI 后转发给统一的媒体打开广播入口。
+     */
     async handleParam(want: Want) {
         try {
             // 通过 await 等待异步操作完成
@@ -492,6 +559,9 @@ export default class EntryAbility extends UIAbility {
         }
     }
 
+    /**
+     * Ability 销毁时清理注册的事件、卡片 call 处理器以及智慧出行状态监听。
+     */
     onDestroy() {
         try {
         this.context.eventHub?.off('musicCardActionForward', this.musicCardActionForwardHandler);
@@ -513,6 +583,10 @@ export default class EntryAbility extends UIAbility {
     }
 
 
+    /**
+     * 主窗口创建完成后初始化窗口级状态。
+     * 包括全屏布局、避让区域监听、显示设备识别、断点尺寸同步以及首页内容加载。
+     */
     onWindowStageCreate(windowStage: window.WindowStage) {
         // Main window is created, set main page for this ability
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
@@ -597,22 +671,35 @@ export default class EntryAbility extends UIAbility {
         DemoConstants.windowStage = windowStage
     }
 
+    /**
+     * 主窗口销毁时触发,用于记录窗口生命周期结束。
+     */
     onWindowStageDestroy() {
         // Main window is destroyed, release UI related resources
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
     }
 
+    /**
+     * Ability 回到前台时触发。
+     */
     onForeground() {
         // Ability has brought to foreground
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
     }
 
+    /**
+     * Ability 进入后台时触发。
+     */
     onBackground() {
         // Ability has back to background
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
     }
 
 
+    /**
+     * 查询并监听 HiCar 连接状态。
+     * 初始化时会读取当前状态并注册监听;当车机断开时会同步更新全局状态并触发播放相关广播。
+     */
     getHiCarStatus(){
         try {
             if (!this.awareness){
@@ -671,12 +758,17 @@ export default class EntryAbility extends UIAbility {
 
     }
 
-    //发送广播通知更新UI
+    /**
+     * 发送设置变更广播,通知相关页面刷新 UI 状态。
+     */
     sendChangeEvent() {
         const eventData: emitter.EventData = {};
         emitter.emit({ eventId: EventConstants.EVENT_SETTING_UPDATE }, eventData); // 发送广播通知更新doSwipBack
     }
 
+    /**
+     * 统一输出 HiCar 状态相关服务端日志。
+     */
     private logHiCar(level: 'info' | 'warn' | 'error' | 'debug', message: string) {
         const tag = 'HiCarStatus';
         switch (level) {
@@ -697,6 +789,9 @@ export default class EntryAbility extends UIAbility {
         }
     }
 
+    /**
+     * 统一输出网盘/WebDAV 初始化相关服务端日志。
+     */
     private logNetDisk(level: 'info' | 'warn' | 'error', message: string) {
         const tag = 'NetDiskInit';
         switch (level) {

+ 42 - 0
entry/src/main/ets/entryformability/MusicCardFormAbility.ets

@@ -26,6 +26,10 @@ class MusicCardColdStartParameters {
 }
 
 export default class MusicCardFormAbility extends FormExtensionAbility {
+  /**
+   * 新增音乐卡片实例时构建首份绑定数据。
+   * 这里会先解析并登记 formId,再基于当前播放器快照生成卡片渲染数据返回给系统。
+   */
   onAddForm(want: Want): formBindingData.FormBindingData {
     const formId = this.resolveFormIdFromWant(want)
     Logger.info(TAG, `musicCard onAddForm formId=${formId}`)
@@ -33,6 +37,10 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     return formBindingData.createFormBindingData(this.buildPayload(formId))
   }
 
+  /**
+   * 系统请求刷新卡片时重新构建并推送绑定数据。
+   * 如果更新失败,会记录日志但不抛出异常,避免影响卡片宿主流程。
+   */
   onUpdateForm(formId: string): void {
     Logger.info(TAG, `musicCard onUpdateForm formId=${formId}`)
     MusicCardFormStore.addFormId(this.context, formId)
@@ -42,6 +50,10 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     })
   }
 
+  /**
+   * 处理用户在卡片上的交互事件。
+   * 事件会先交给卡片管理器分发;若当前应用未运行到可直接处理的状态,则补发冷启动拉起流程。
+   */
   onFormEvent(formId: string, message: string): void {
     Logger.info(TAG, `musicCard onFormEvent formId=${formId}, message=${message}`)
     MusicCardFormStore.addFormId(this.context, formId)
@@ -58,14 +70,25 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
       })
   }
 
+  /**
+   * 卡片被移除时注销对应的 formId,避免后续继续向无效卡片推送状态。
+   */
   onRemoveForm(formId: string): void {
     MusicCardFormStore.removeFormId(this.context, formId)
   }
 
+  /**
+   * 返回当前卡片的可用状态。
+   * 这里固定声明为 READY,表示卡片已准备好被系统创建和展示。
+   */
   onAcquireFormState(_want: Want): number {
     return formInfo.FormState.READY
   }
 
+  /**
+   * 基于当前播放器快照组装卡片完整绑定数据。
+   * 同时会解析封面资源,生成适用于卡片渲染的图片字段和播放状态字段。
+   */
   private buildPayload(formId: string): MusicCardFormBindingData {
     const snapshot = MusicCardSnapshotStore.readSnapshot(this.context)
     const source = buildMusicCardBindingData(snapshot)
@@ -98,6 +121,10 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     return payload
   }
 
+  /**
+   * 当卡片事件需要冷启动主界面处理时,构造带动作参数的 Want 并拉起 EntryAbility。
+   * 该流程用于应用未处于可直接响应的运行态时的兜底转发。
+   */
   private launchEntryAbilityForColdStart(result: MusicCardFormActionDispatchResult): void {
     const parameters = new MusicCardColdStartParameters()
     parameters.ttmusic_music_card_form_id = result.formId
@@ -129,6 +156,10 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     })
   }
 
+  /**
+   * 从系统下发的 Want 中解析卡片 formId。
+   * 解析时会兼容不同序列化类型;若值存在但格式不受支持,会输出告警日志。
+   */
   private resolveFormIdFromWant(want: Want): string {
     const parameters = want.parameters as Object | undefined
     if (!parameters) {
@@ -142,6 +173,10 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     return formId
   }
 
+  /**
+   * 从 Want 参数对象中读取原始 formId 值。
+   * 兼容字符串、数字和布尔值等序列化结果,便于后续统一规范化处理。
+   */
   private readFormIdValue(parameters: Object): string | number | boolean | Object | undefined {
     const parametersText = JSON.stringify(parameters)
     if (!parametersText || parametersText.indexOf(FORM_ID_PARAM_KEY) < 0) {
@@ -169,6 +204,10 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     return parametersText
   }
 
+  /**
+   * 将解析出的原始 formId 转换为标准字符串形式。
+   * 仅接受去空格后的字符串或安全整数,其余类型统一视为无效值。
+   */
   private normalizeFormId(value: string | number | boolean | Object | undefined): string {
     if (typeof value === 'string') {
       return value.trim()
@@ -179,6 +218,9 @@ export default class MusicCardFormAbility extends FormExtensionAbility {
     return ''
   }
 
+  /**
+   * 将异常对象格式化为日志可直接输出的字符串。
+   */
   private formatError(error: Object): string {
     return `${error}`
   }

+ 30 - 0
entry/src/main/ets/lyric/extensions/Extension.ts

@@ -0,0 +1,30 @@
+import hilog from '@ohos.hilog';
+
+const TAG = "LyricView"
+
+export function printD(msg: string) {
+    hilog.debug(0, TAG, msg)
+}
+
+export function printW(msg: string) {
+    hilog.warn(0, TAG, msg)
+}
+
+export function duration2text(duration: number): string {
+    let seconds = Math.round(duration / 1000)
+    let minute = Math.floor(seconds / 60)
+    let second = seconds - minute * 60
+    let s1 = minute.toString()
+    let s2 = second >= 10 ? second.toString() : "0" + second
+    return s1 + ":" + s2
+}
+
+export function seconds2text(seconds: number) {
+    let minute = Math.floor(seconds / 60)
+    let second = seconds - minute * 60
+    if (second < 10) {
+        return minute + ":0" + second
+    } else {
+        return minute + ":" + second
+    }
+}

+ 7 - 0
entry/src/main/ets/lyric/parse/IParser.ts

@@ -0,0 +1,7 @@
+import { Lyric } from '../bean/Lyric';
+
+export interface IParser {
+
+    parse(source: any): Lyric
+
+}

+ 1 - 22
entry/src/main/ets/pages/NewIndex.ets

@@ -67,7 +67,6 @@ import {
   resolveMiniPlayerMorphTarget,
 } from '../common/util/PlayerDismissHelper';
 import { shouldShowMiniPlayerBar } from '../common/util/MiniPlayerHostViewHelper';
-import { resolvePlayerPageOpenDelayMs } from '../common/util/PlayerPageOpenDispatchHelper';
 import { resolveMiniPlayerMirrorState } from '../common/util/MiniPlayerMirrorStateHelper';
 import {
   MiniPlayerOrbTapAction,
@@ -1318,27 +1317,7 @@ struct NewIndex {
     if (this.isMiniPlayerModeTransitioning) {
       return
     }
-    const openDelayMs = resolvePlayerPageOpenDelayMs(this.mType)
-    if (this.mType !== 0) {
-      LogUtil.info(TAG, `[MiniState] setShowPlayTrue switch host page mType=${this.mType} -> 0`)
-      this.mType = 0
-      this.tabSelectedIndexes = [0]
-    }
-    if (this.pendingPlayerPageOpenTimer >= 0) {
-      clearTimeout(this.pendingPlayerPageOpenTimer)
-      this.pendingPlayerPageOpenTimer = -1
-    }
-    if (openDelayMs <= 0) {
-      LogUtil.info(TAG, '[MiniState] setShowPlayTrue dispatch open immediately')
-      void this.playbackController.showPlayerView()
-      return
-    }
-    LogUtil.info(TAG, `[MiniState] setShowPlayTrue defer open delayMs=${openDelayMs}`)
-    this.pendingPlayerPageOpenTimer = setTimeout(() => {
-      this.pendingPlayerPageOpenTimer = -1
-      LogUtil.info(TAG, '[MiniState] deferred open -> showPlayerView')
-      void this.playbackController.showPlayerView()
-    }, openDelayMs)
+    this.playbackController.showPlayerView()
   }
 
   // 右侧圆球内部内容:封面、暗罩、白色环形进度和中心播放状态指示。

+ 36 - 0
entry/src/main/ets/widget/pages/MusicPlayerWidgetCard.ets

@@ -29,6 +29,9 @@ struct MusicPlayerWidgetCard {
   @State isChangeBg: boolean = true
   @State sliderProgressMs: number = 0
 
+  /**
+   * 组件挂载时记录当前卡片状态,并同步一次进度条显示。
+   */
   aboutToAppear(): void {
     Logger.info(TAG,
       `musicCard small aboutToAppear formId=${this.formId}, title=${this.title}, artist=${this.artist}, ` +
@@ -38,10 +41,16 @@ struct MusicPlayerWidgetCard {
     this.syncSliderFromPlayback()
   }
 
+  /**
+   * 根据当前播放进度与总时长刷新本地进度值,避免越界。
+   */
   private syncSliderFromPlayback(): void {
     this.sliderProgressMs = clampMusicCardWidgetProgress(this.currentPositionMs, this.durationMs)
   }
 
+  /**
+   * 向卡片宿主发送播放控制动作,按动作类型选择 call 或 router 分发。
+   */
   private postControlAction(action: string): void {
     Logger.info(TAG, `musicCard small postControlAction formId=${this.formId}, action=${action}`)
     const useCallDispatch = shouldDispatchMusicCardActionByCall(action)
@@ -53,6 +62,9 @@ struct MusicPlayerWidgetCard {
     })
   }
 
+  /**
+   * 通过 router 方式跳转到主界面,并携带卡片来源与动作参数。
+   */
   private postRouterAction(action: string): void {
     Logger.info(TAG, `musicCard small postRouterAction formId=${this.formId}, action=${action}`)
     postCardAction(this, {
@@ -66,10 +78,16 @@ struct MusicPlayerWidgetCard {
     })
   }
 
+  /**
+   * 解析卡片封面的实际数据源,优先使用卡片中已缓存的封面资源。
+   */
   private resolveCoverSource(): string | Resource {
     return resolveMusicCardWidgetCoverSource(this.coverImageName, this.coverPath, this.hasCoverImage)
   }
 
+  /**
+   * 将毫秒级播放进度换算为环形进度条使用的百分比值。
+   */
   private resolveProgressValue(): number {
     if (this.durationMs <= 0) {
       return 0
@@ -77,6 +95,9 @@ struct MusicPlayerWidgetCard {
     return Math.min(100, Math.max(0, Math.floor(this.sliderProgressMs * 100 / this.durationMs)))
   }
 
+  /**
+   * 拼接标题与歌手文本,缺省时返回占位文案。
+   */
   private resolveTitleArtistText(): string {
     const safeTitle = this.title?.trim() ?? ''
     const safeArtist = this.artist?.trim() ?? ''
@@ -92,10 +113,16 @@ struct MusicPlayerWidgetCard {
     return '未在播放'
   }
 
+  /**
+   * 根据当前播放状态返回播放或暂停图标。
+   */
   private resolvePlayPauseIcon(): Resource {
     return this.isPlaying ? $r('sys.symbol.pause_fill') : $r('sys.symbol.play_fill')
   }
 
+  /**
+   * 构建上一首、下一首等通用控制按钮。
+   */
   @Builder
   private ControlButton(imageResource: Resource, action: string, buttonSize: number, symbolSize: number) {
     Button() {
@@ -112,6 +139,9 @@ struct MusicPlayerWidgetCard {
     .onClick(() => this.postControlAction(action))
   }
 
+  /**
+   * 构建带环形进度指示的播放/暂停按钮。
+   */
   @Builder
   private PlayProgressButton() {
     Stack({ alignContent: Alignment.Center }) {
@@ -138,6 +168,9 @@ struct MusicPlayerWidgetCard {
     .height(34)
   }
 
+  /**
+   * 判断当前是否具备可用于背景展示的封面资源。
+   */
   private hasCoverBackground(): boolean {
     if (this.hasCoverImage && this.coverImageName.length > 0) {
       return true;
@@ -145,6 +178,9 @@ struct MusicPlayerWidgetCard {
     return this.coverPath.length > 0;
   }
 
+  /**
+   * 构建音乐播放卡片主体界面,并绑定卡片交互事件。
+   */
   build() {
     Stack() {