PlayerWidgetMedium.ets 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * 中等尺寸播放器卡片 (4x2)
  3. * 显示完整信息、播放控制和进度条
  4. */
  5. @Entry
  6. @Component
  7. struct PlayerWidgetMedium {
  8. @LocalStorageProp('isPlaying') isPlaying: boolean = false;
  9. @LocalStorageProp('songTitle') songTitle: string = '暂无播放';
  10. @LocalStorageProp('songArtist') songArtist: string = '未知艺术家';
  11. @LocalStorageProp('currentTime') currentTime: string = '00:00';
  12. @LocalStorageProp('totalTime') totalTime: string = '00:00';
  13. @LocalStorageProp('progressPercentage') progressPercentage: number = 0;
  14. @LocalStorageProp('hasNext') hasNext: boolean = false;
  15. @LocalStorageProp('hasPrevious') hasPrevious: boolean = false;
  16. @LocalStorageProp('showProgress') showProgress: boolean = true;
  17. build() {
  18. Column() {
  19. // 歌曲信息区域
  20. Row() {
  21. Column() {
  22. Text(this.songTitle)
  23. .fontSize(16)
  24. .fontColor('#E6000000')
  25. .fontWeight(FontWeight.Medium)
  26. .maxLines(1)
  27. .textOverflow({ overflow: TextOverflow.Ellipsis })
  28. .width('100%')
  29. .textAlign(TextAlign.Start)
  30. Text(this.songArtist)
  31. .fontSize(12)
  32. .fontColor('#99000000')
  33. .fontWeight(FontWeight.Normal)
  34. .maxLines(1)
  35. .textOverflow({ overflow: TextOverflow.Ellipsis })
  36. .width('100%')
  37. .textAlign(TextAlign.Start)
  38. .margin({ top: 2 })
  39. }
  40. .layoutWeight(1)
  41. .alignItems(HorizontalAlign.Start)
  42. .onClick(() => {
  43. this.handleControlAction('open_player');
  44. })
  45. }
  46. .width('100%')
  47. .margin({ bottom: 12 })
  48. // 播放控制区域
  49. Row() {
  50. // 上一首按钮
  51. Button() {
  52. Image($r('app.media.ic_previous2'))
  53. .width(18)
  54. .height(18)
  55. .fillColor(this.hasPrevious ? '#FF007DFF' : '#66000000')
  56. }
  57. .width(36)
  58. .height(36)
  59. .backgroundColor(Color.Transparent)
  60. .enabled(this.hasPrevious)
  61. .onClick(() => {
  62. this.handleControlAction('prev_song');
  63. })
  64. // 播放/暂停按钮
  65. Button() {
  66. Image(this.isPlaying ? $r('app.media.hm_pause') : $r('app.media.hm_play'))
  67. .width(24)
  68. .height(24)
  69. .fillColor('#FFFFFF')
  70. }
  71. .width(44)
  72. .height(44)
  73. .backgroundColor('#FF007DFF')
  74. .borderRadius(22)
  75. .margin({ left: 12, right: 12 })
  76. .onClick(() => {
  77. this.handleControlAction('play_pause');
  78. })
  79. // 下一首按钮
  80. Button() {
  81. Image($r('app.media.ic_next2'))
  82. .width(18)
  83. .height(18)
  84. .fillColor(this.hasNext ? '#FF007DFF' : '#66000000')
  85. }
  86. .width(36)
  87. .height(36)
  88. .backgroundColor(Color.Transparent)
  89. .enabled(this.hasNext)
  90. .onClick(() => {
  91. this.handleControlAction('next_song');
  92. })
  93. }
  94. .justifyContent(FlexAlign.Center)
  95. .width('100%')
  96. .margin({ bottom: this.showProgress ? 8 : 0 })
  97. // 播放进度区域
  98. if (this.showProgress) {
  99. Column() {
  100. // 进度条
  101. Row() {
  102. Progress({
  103. value: this.progressPercentage,
  104. total: 100,
  105. type: ProgressType.Linear
  106. })
  107. .width('100%')
  108. .height(4)
  109. .color('#FF007DFF')
  110. .backgroundColor('#1A007DFF')
  111. .onClick((event) => {
  112. this.handleProgressClick(event);
  113. })
  114. }
  115. .width('100%')
  116. .margin({ bottom: 4 })
  117. // 时间显示
  118. Row() {
  119. Text(this.currentTime)
  120. .fontSize(10)
  121. .fontColor('#99000000')
  122. Blank()
  123. Text(this.totalTime)
  124. .fontSize(10)
  125. .fontColor('#99000000')
  126. }
  127. .width('100%')
  128. }
  129. .width('100%')
  130. }
  131. }
  132. .width('100%')
  133. .height('100%')
  134. .padding(16)
  135. .backgroundColor('#FFFFFF')
  136. .borderRadius(12)
  137. .alignItems(HorizontalAlign.Start)
  138. .justifyContent(FlexAlign.SpaceBetween)
  139. }
  140. /**
  141. * 处理控制操作
  142. */
  143. private handleControlAction(action: string): void {
  144. postCardAction(this, {
  145. action: action,
  146. params: {}
  147. });
  148. }
  149. /**
  150. * 处理进度条点击
  151. */
  152. private handleProgressClick(event: ClickEvent): void {
  153. // 计算点击位置对应的播放进度
  154. const clickX = event.x;
  155. const progressWidth = event.target.area.width as number;
  156. const percentage = (clickX / progressWidth) * 100;
  157. postCardAction(this, {
  158. action: 'seek_to',
  159. params: {
  160. percentage: percentage
  161. }
  162. });
  163. }
  164. }