/** * 方形播放器卡片 (2x2) * 显示专辑封面、歌曲信息和播放按钮 * 参考华为官方设计,移除收藏功能 * 需求: 5.1, 1.4, 1.5 */ // 定义对齐规则 - 参考华为官方代码 const SquareSingerAlignRules: Record> = { 'top': { 'anchor': 'musicTitle', 'align': VerticalAlign.Bottom }, 'left': { 'anchor': 'musicCover', 'align': HorizontalAlign.End } }; const SquareCoverAlignRules: Record> = { 'bottom': { 'anchor': '__container__', 'align': VerticalAlign.Bottom } }; const PlayAlignRules: Record> = { 'bottom': { 'anchor': '__container__', 'align': VerticalAlign.Bottom }, 'right': { 'anchor': '__container__', 'align': HorizontalAlign.End } }; @Entry @Component struct PlayerWidgetSquare { // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信 @LocalStorageProp('formId') formId: string = '12400633174999288'; @LocalStorageProp('isPlaying') isPlaying: boolean = false; @LocalStorageProp('songTitle') songTitle: string = 'Dream It Possible'; @LocalStorageProp('songArtist') songArtist: string = 'Delacey'; @LocalStorageProp('coverImage') coverImage: string = ''; @LocalStorageProp('isLoading') isLoading: boolean = false; @LocalStorageProp('imageColorHex') imageColorHex: string = '2A2A2A'; @LocalStorageProp('imgName') imgName: string = ''; // 图片文件名,用于memory://协议 /** * 格式化歌曲标题显示 */ private getDisplayTitle(): string { if (!this.songTitle || this.songTitle.trim() === '') { return '暂无播放'; } return this.songTitle; } /** * 格式化艺术家显示 */ private getDisplayArtist(): string { if (!this.songArtist || this.songArtist.trim() === '') { return '未知艺术家'; } return this.songArtist; } /** * 获取专辑封面 */ private getCoverImage(): Resource | string { console.info(`Heanup PlayerWidgetSquare: getCoverImage called, coverImage='${this.coverImage}', imgName='${this.imgName}'`); // 优先使用通过formImages传递的本地图片(支持网络图片下载后的显示) if (this.imgName && this.imgName.trim() !== '') { const memoryUrl = 'memory://' + this.imgName; console.info(`Heanup PlayerWidgetSquare: Using memory image: ${memoryUrl}`); return memoryUrl; } // 如果有coverImage且不是网络URL,使用本地路径 if (this.coverImage && this.coverImage.trim() !== '' && !this.isNetworkUrl(this.coverImage)) { console.info(`Heanup PlayerWidgetSquare: Using local cover image: ${this.coverImage}`); return this.coverImage; } // 默认使用内置图片 console.info(`Heanup PlayerWidgetSquare: Using default cover image`); return $r('app.media.ic_avatar4'); // 使用默认专辑封面 } /** * 检查是否为网络URL */ private isNetworkUrl(url: string): boolean { return url.startsWith('http://') || url.startsWith('https://'); } build() { RelativeContainer() { // 歌曲标题 - 参考华为官方样式 Text(this.getDisplayTitle()) .fontSize(14) .fontWeight(700) .width('85%') .fontColor(Color.White) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(1) .id('musicTitle') // 艺术家名称 - 参考华为官方样式 Text(this.getDisplayArtist()) .fontSize(12) .fontColor('#CCFFFFFF') .fontWeight(500) .maxLines(1) .alignRules(SquareSingerAlignRules) .margin({ top: 2 }) .id('singerText') // 专辑封面 - 参考华为官方黑胶唱片设计 Stack({ alignContent: Alignment.Center }) { Image($r('app.media.ic_music_bg_mini')) .height(88) .width(88) Button() .backgroundImage(this.getCoverImage()) .backgroundImageSize(ImageSize.Cover) .height(58) .width(58) .borderRadius(29) } .alignRules(SquareCoverAlignRules) .id('musicCover') .onClick(() => { console.info('Heanup PlayerWidgetSquare: Album cover clicked'); postCardAction(this, { 'action': 'router', 'abilityName': 'EntryAbility' }); }) // 播放按钮 - 参考华为官方样式 SymbolGlyph(this.isPlaying ? $r('sys.symbol.pause_round_triangle_fill') : $r('sys.symbol.play_round_triangle_fill')) .fontSize(36) .symbolEffect(new ReplaceSymbolEffect(EffectScope.WHOLE), true) .fontColor(['#E5FFFFFF']) .alignRules(PlayAlignRules) .onClick(() => { console.info('Heanup PlayerWidgetSquare: Play/Pause button clicked'); if (!this.isLoading) { postCardAction(this, { 'action': 'call', 'abilityName': 'EntryAbility', 'params': { 'formId': this.formId, 'method': 'playPause', 'widgetIsPlaying': this.isPlaying // 传递卡片当前显示的播放状态 } }); } }) } .height('100%') .width('100%') .linearGradient({ direction: GradientDirection.Bottom, repeating: false, colors: [[`#ff${this.imageColorHex}`, 0.0], [`#ff${this.imageColorHex}`, 0.5], [`#ff${this.imageColorHex}`, 1.0]] }) .padding(12) .onClick(() => { console.info('Heanup PlayerWidgetSquare: Container clicked, jumping to main app'); postCardAction(this, { 'action': 'router', 'abilityName': 'EntryAbility' }); }) } }