| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- /**
- * 矩形封面播放器卡片 (2x4)
- * 显示专辑封面、歌曲信息和播放控制
- */
- // 定义对齐规则
- const RectangleSingerAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
- 'top': { 'anchor': 'musicTitle', 'align': VerticalAlign.Bottom },
- 'left': { 'anchor': 'musicCover', 'align': HorizontalAlign.End }
- };
- const RectangleCoverAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
- 'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start },
- 'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }
- };
- const RectangleTitleAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
- 'left': { 'anchor': 'musicCover', 'align': HorizontalAlign.End },
- 'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }
- };
- const RectanglePlayControlAlignRules: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = {
- 'bottom': { 'anchor': '__container__', 'align': VerticalAlign.Bottom },
- 'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start },
- 'right': { 'anchor': '__container__', 'align': HorizontalAlign.End }
- };
- @Entry
- @Component
- struct PlayerWidgetRectangle {
- // 卡片数据属性 - 适配新的数据结构
- @LocalStorageProp('formId') formId: string = '202504'; // New formId for this card
- // VideoItem 主要数据
- @LocalStorageProp('id') songId: string = '';
- @LocalStorageProp('name') songTitle: string = 'Dream It Possible';
- @LocalStorageProp('artist') songArtist: string = 'Delacey';
- @LocalStorageProp('album') songAlbum: string = '未知专辑';
- @LocalStorageProp('pixelMapPath') coverImage: string = '';
- @LocalStorageProp('duration') songDuration: number = 0;
- @LocalStorageProp('filePath') songFilePath: string = '';
- // PlayerState 播放状态数据
- @LocalStorageProp('playerState') playerState: Record<string, Object> = {};
- // 平铺状态数据(优先使用)
- @LocalStorageProp('isPlaying') isPlaying: boolean = false;
- @LocalStorageProp('isPaused') isPaused: boolean = true;
- @LocalStorageProp('isLoading') isLoading: boolean = false;
- @LocalStorageProp('hasNext') hasNext: boolean = false;
- @LocalStorageProp('hasPrevious') hasPrevious: boolean = false;
- // 播放列表信息
- @LocalStorageProp('playlistInfo') playlistInfo: Record<string, Object> = {};
- @LocalStorageProp('currentIndex') currentIndex: number = 0;
- @LocalStorageProp('totalCount') totalCount: number = 0;
- // 时间信息
- @LocalStorageProp('timeInfo') timeInfo: Record<string, Object> = {};
- @LocalStorageProp('currentTimeText') currentTimeText: string = '00:00';
- @LocalStorageProp('totalTimeText') totalTimeText: string = '00:00';
- @LocalStorageProp('progressPercentage') progressPercentage: number = 0;
- // 兼容性属性(用于获取复合状态)
- @LocalStorageProp('imgName') imgName: string = ''; // 图片文件名,用于memory://协议
- @LocalStorageProp('isFavorite') isFavorite: boolean = false;
- /**
- * 格式化歌曲标题显示
- */
- 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;
- }
- /**
- * 检查是否为网络URL
- */
- private isNetworkUrl(url: string): boolean {
- return url.startsWith('http://') || url.startsWith('https://');
- }
- /**
- * 获取专辑封面
- */
- private getCoverImage(): Resource | string {
- console.info(`Heanup PlayerWidgetRectangle: getCoverImage called, coverImage='${this.coverImage}', imgName='${this.imgName}'`);
- // 优先使用通过formImages传递的本地图片(支持网络图片下载后的显示)
- if (this.imgName && this.imgName.trim() !== '') {
- const memoryUrl = 'memory://' + this.imgName;
- console.info(`Heanup PlayerWidgetRectangle: Using memory image: ${memoryUrl}`);
- return memoryUrl;
- }
- // 如果有coverImage且不是网络URL,使用本地路径
- if (this.coverImage && this.coverImage.trim() !== '' && !this.isNetworkUrl(this.coverImage)) {
- console.info(`Heanup PlayerWidgetRectangle: Using local cover image: ${this.coverImage}`);
- return this.coverImage;
- }
- // 默认使用内置图片
- console.info(`Heanup PlayerWidgetRectangle: Using default cover image`);
- return $r('app.media.ic_avatar4'); // 使用默认专辑封面
- }
- build() {
- Stack() {
- // 背景和主要内容
- RelativeContainer() {
- // 歌曲标题
- Text(this.getDisplayTitle())
- .fontSize(16)
- .fontWeight(FontWeight.Bold)
- .width('60%')
- .fontColor(Color.White)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- .maxLines(1)
- .alignRules(RectangleTitleAlignRules)
- .margin({ left: 16, top: 8 })
- .id('musicTitle')
- // 艺术家名称
- Text(this.getDisplayArtist())
- .fontSize(12)
- .fontColor('#CCFFFFFF')
- .fontWeight(FontWeight.Normal)
- .maxLines(1)
- .alignRules(RectangleSingerAlignRules)
- .margin({ left: 16, top: 2 })
- .id('singerText')
- // 专辑封面
- Image(this.getCoverImage())
- .width(88)
- .height(88)
- .borderRadius(8) // Square cover with rounded corners
- .alignRules(RectangleCoverAlignRules)
- .id('musicCover')
- .onClick(() => {
- postCardAction(this, {
- 'action': 'router',
- 'abilityName': 'EntryAbility'
- });
- })
- // 播放控制按钮区域
- Row() {
- // 上一首按钮
- Button() {
- SymbolGlyph($r('sys.symbol.backward_end_fill'))
- .fontSize(36)
- .fontColor(['#E5FFFFFF'])
- }
- .width(40)
- .height(40)
- .backgroundColor(Color.Transparent)
- .opacity(this.hasPrevious ? 1.0 : 0.5)
- .onClick(() => {
- console.info(`Heanup PlayerWidgetRectangle: Previous button clicked`);
- if (!this.isLoading && this.hasPrevious) {
- postCardAction(this, {
- 'action': 'call',
- 'abilityName': 'EntryAbility',
- 'params': {
- 'formId': this.formId,
- 'method': 'prevSong'
- }
- });
- }
- })
- // 播放/暂停按钮
- Button() {
- 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'])
- }
- .width(48)
- .height(48)
- .backgroundColor(Color.Transparent)
- .margin({ left: 20, right: 20 })
- .onClick(() => {
- console.info('Heanup PlayerWidgetRectangle: Play/Pause button clicked');
- if (!this.isLoading) {
- postCardAction(this, {
- 'action': 'call',
- 'abilityName': 'EntryAbility',
- 'params': {
- 'formId': this.formId,
- 'method': 'playPause',
- 'widgetIsPlaying': this.isPlaying // 传递卡片当前显示的播放状态
- }
- });
- }
- })
- // 下一首按钮
- Button() {
- SymbolGlyph($r('sys.symbol.forward_end_fill'))
- .fontSize(36)
- .fontColor(['#E5FFFFFF'])
- }
- .width(40)
- .height(40)
- .backgroundColor(Color.Transparent)
- .opacity(this.hasNext ? 1.0 : 0.5)
- .onClick(() => {
- console.info(`Heanup PlayerWidgetRectangle: Next button clicked`);
- if (!this.isLoading && this.hasNext) {
- postCardAction(this, {
- 'action': 'call',
- 'abilityName': 'EntryAbility',
- 'params': {
- 'formId': this.formId,
- 'method': 'nextSong'
- }
- });
- }
- })
- }
- .width('100%')
- .justifyContent(FlexAlign.Center)
- .alignRules(RectanglePlayControlAlignRules)
- .id('playControls')
- }
- .height('100%')
- .width('100%')
- .padding(12)
- .backgroundImage(this.getCoverImage())
- .backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK)
- .backgroundImageSize(ImageSize.Cover)
- .onClick(() => {
- console.info('Heanup PlayerWidgetRectangle: Container clicked, jumping to main app');
- postCardAction(this, {
- 'action': 'router',
- 'abilityName': 'EntryAbility'
- });
- })
- // 收藏按钮放在Stack顶层,确保可以正常点击
- Button() {
- SymbolGlyph(this.isFavorite ? $r('sys.symbol.heart_fill') : $r('sys.symbol.heart'))
- .fontSize(24)
- .symbolEffect(new ReplaceSymbolEffect(EffectScope.WHOLE), true)
- .fontColor(['#E5FFFFFF'])
- }
- .width(40)
- .height(40)
- .backgroundColor(Color.Transparent)
- .onClick(() => {
- console.info(`Heanup PlayerWidgetRectangle: Favorite button clicked`);
- postCardAction(this, {
- 'action': 'call',
- 'abilityName': 'EntryAbility',
- 'params': {
- 'formId': this.formId,
- 'method': 'toggleFavorite'
- }
- });
- })
- .position({
- x: '100%',
- y: 0
- })
- .translate({ x: -52, y: 12 }) // 调整到右上角位置
- }
- .height('100%')
- .width('100%')
- }
- }
|