| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import { MusicCardActionConstants } from '../../common/player/MusicCardActionConstants'
- import Logger from '../../common/util/Logger'
- import {
- clampMusicCardWidgetProgress,
- formatMusicCardWidgetTime,
- resolveMusicCardWidgetCoverSource
- } from '../common/MusicPlayerWidgetHelper'
- const wideCardStorage: LocalStorage = new LocalStorage()
- const ENTRY_ABILITY_NAME = 'EntryAbility'
- const SLIDER_CHANGE_MODE_END = 2
- const TAG = 'MusicPlayerWidgetWideCard'
- @Entry(wideCardStorage)
- @Component
- struct MusicPlayerWidgetWideCard {
- @LocalStorageProp('formId') formId: string = ''
- @LocalStorageProp('title') title: string = '未在播放'
- @LocalStorageProp('artist') artist: string = '点击打开播放器'
- @LocalStorageProp('coverPath') coverPath: string = ''
- @LocalStorageProp('coverImageName') coverImageName: string = ''
- @LocalStorageProp('hasCoverImage') hasCoverImage: boolean = false
- @LocalStorageProp('hasSong') hasSong: boolean = false
- @LocalStorageProp('isPlaying') isPlaying: boolean = false
- @LocalStorageProp('currentPositionMs') @Watch('syncSliderFromPlayback') currentPositionMs: number = 0
- @LocalStorageProp('durationMs') @Watch('syncSliderFromPlayback') durationMs: number = 0
- @LocalStorageProp('currentTimeText') currentTimeText: string = '00:00'
- @LocalStorageProp('durationTimeText') durationTimeText: string = '00:00'
- @State isDragging: boolean = false
- @State dragProgressMs: number = 0
- @State sliderProgressMs: number = 0
- aboutToAppear(): void {
- Logger.info(TAG,
- `musicCard wide aboutToAppear formId=${this.formId}, title=${this.title}, artist=${this.artist}, ` +
- `coverImageName=${this.coverImageName}, coverPath=${this.coverPath}, hasCoverImage=${this.hasCoverImage}, ` +
- `hasSong=${this.hasSong}, isPlaying=${this.isPlaying}, currentPositionMs=${this.currentPositionMs}, ` +
- `durationMs=${this.durationMs}`)
- this.syncSliderFromPlayback()
- }
- private syncSliderFromPlayback(): void {
- if (this.isDragging) {
- return
- }
- this.sliderProgressMs = clampMusicCardWidgetProgress(this.currentPositionMs, this.durationMs)
- }
- private postControlAction(action: string): void {
- Logger.info(TAG, `musicCard wide postControlAction formId=${this.formId}, action=${action}`)
- postCardAction(this, {
- action: 'call',
- abilityName: ENTRY_ABILITY_NAME,
- params: {
- method: MusicCardActionConstants.CALL_METHOD_HANDLE_ACTION,
- ttmusic_music_card_form_id: this.formId,
- ttmusic_music_card_action: action,
- ttmusic_music_card_source: MusicCardActionConstants.ACTION_SOURCE_WIDGET
- }
- })
- }
- private postSeekAction(positionMs: number): void {
- Logger.info(TAG, `musicCard wide postSeekAction formId=${this.formId}, positionMs=${positionMs}`)
- postCardAction(this, {
- action: 'call',
- abilityName: ENTRY_ABILITY_NAME,
- params: {
- method: MusicCardActionConstants.CALL_METHOD_HANDLE_ACTION,
- ttmusic_music_card_form_id: this.formId,
- ttmusic_music_card_action: MusicCardActionConstants.ACTION_SEEK_TO,
- ttmusic_music_card_seek_position_ms: `${Math.max(0, Math.floor(positionMs))}`,
- ttmusic_music_card_source: MusicCardActionConstants.ACTION_SOURCE_WIDGET
- }
- })
- }
- private postRouterAction(action: string): void {
- Logger.info(TAG, `musicCard wide postRouterAction formId=${this.formId}, action=${action}`)
- postCardAction(this, {
- action: 'router',
- abilityName: ENTRY_ABILITY_NAME,
- params: {
- ttmusic_music_card_form_id: this.formId,
- ttmusic_music_card_action: action,
- ttmusic_music_card_source: MusicCardActionConstants.ACTION_SOURCE_WIDGET
- }
- })
- }
- private resolveCoverSource(): string | Resource {
- return resolveMusicCardWidgetCoverSource(this.coverImageName, this.coverPath, this.hasCoverImage)
- }
- private resolveSliderValue(): number {
- if (this.isDragging) {
- return this.dragProgressMs
- }
- return this.sliderProgressMs
- }
- private resolveCurrentTimeText(): string {
- if (this.isDragging) {
- return formatMusicCardWidgetTime(this.dragProgressMs)
- }
- return this.currentTimeText
- }
- private handleSliderChange(value: number, mode: SliderChangeMode): void {
- const nextValue = clampMusicCardWidgetProgress(value, this.durationMs)
- if (mode !== SLIDER_CHANGE_MODE_END) {
- Logger.info(TAG, `musicCard wide slider dragging formId=${this.formId}, value=${nextValue}, mode=${mode}`)
- this.isDragging = true
- this.dragProgressMs = nextValue
- return
- }
- Logger.info(TAG, `musicCard wide slider end formId=${this.formId}, value=${nextValue}, mode=${mode}`)
- this.dragProgressMs = nextValue
- this.sliderProgressMs = nextValue
- this.isDragging = false
- this.postSeekAction(nextValue)
- }
- @Builder
- private ControlButton(imageResource: Resource, action: string, buttonSize: number, symbolSize: number) {
- Button({ type: ButtonType.Circle, stateEffect: true }) {
- SymbolGlyph(imageResource)
- .fontSize(symbolSize)
- .fontColor([Color.White])
- .effectStrategy(SymbolEffectStrategy.HIERARCHICAL)
- }
- .width(buttonSize * 1.35)
- .height(buttonSize * 1.35)
- .backgroundColor(Color.Transparent)
- .onClick(() => this.postControlAction(action))
- }
- private hasCoverBackground(): boolean {
- if (this.hasCoverImage && this.coverImageName.length > 0) {
- return true;
- }
- return this.coverPath.length > 0;
- }
- private resolveTitleArtistText(): string {
- const safeTitle = this.title?.trim() ?? ''
- const safeArtist = this.artist?.trim() ?? ''
- if (safeTitle !== '' && safeArtist !== '') {
- return `${safeTitle} - ${safeArtist}`
- }
- if (safeTitle !== '') {
- return safeTitle
- }
- if (safeArtist !== '') {
- return safeArtist
- }
- return '未在播放'
- }
- build() {
- Stack() {
- if (this.hasCoverBackground()) {
- Column()
- .width('100%')
- .height('100%')
- .backgroundImage(this.resolveCoverSource())
- .backgroundImageSize({ width: '100%' })
- .backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK)
- } else {
- Column()
- .width('100%')
- .height('100%')
- .linearGradient( { direction: GradientDirection.Right, colors:[['#00BC70',0.0],['#ff37a0fc',0.5],['#D81B60',1.0]]})
- }
- Column({ space: 16 }) {
- Row({ space: 16 }) {
- Image(this.resolveCoverSource())
- .width(120)
- .height(120)
- .borderRadius(10)
- .objectFit(ImageFit.Cover)
- Column({ space: 12 }) {
- Column({ space: 4 }) {
- Text(this.title)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor(Color.White)
- .maxLines(2)
- .textAlign(TextAlign.Center)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- Text(this.artist)
- .fontSize(15)
- .fontWeight(FontWeight.Bold)
- .fontColor('#E6FFFFFF')
- .maxLines(1)
- .margin({top:4})
- .textAlign(TextAlign.Center)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- }
- .width('100%')
- .alignItems(HorizontalAlign.Center)
- Column() {
- Slider({
- value: this.resolveSliderValue(),
- min: 0,
- max: Math.max(this.durationMs, 1),
- step: 1000,
- style: SliderStyle.InSet
- })
- .width('100%')
- .height(6)
- .blockColor(Color.White)
- .trackColor('#50FFFFFF')
- .selectedColor('#FFF6E8')
- .trackThickness(3)
- .showSteps(false)
- .showTips(false)
- .enabled(this.hasSong && this.durationMs > 0)
- .onChange((value: number, mode: SliderChangeMode) => {
- this.handleSliderChange(value, mode)
- })
- Row() {
- Text(this.resolveCurrentTimeText())
- .fontSize(9)
- .fontColor('#CFFBFFFF')
- Text(this.durationTimeText)
- .fontSize(9)
- .fontColor('#CFFBFFFF')
- }
- .width('90%')
- .justifyContent(FlexAlign.SpaceBetween)
- .alignItems(VerticalAlign.Center)
- }
- .width('100%')
- .height(8)
- .justifyContent(FlexAlign.Center)
- .padding({top:5,left:2,right:2})
- Row({space:2}) {
- this.ControlButton($r('sys.symbol.backward_end_fill'),
- MusicCardActionConstants.ACTION_PREVIOUS, 30, 28)
- Button({ type: ButtonType.Circle, stateEffect: true }) {
- SymbolGlyph(this.isPlaying ? $r('sys.symbol.pause_fill') : $r('sys.symbol.play_fill'))
- .fontSize(34)
- .fontColor([Color.White])
- .effectStrategy(SymbolEffectStrategy.HIERARCHICAL)
- }
- .width(36)
- .height(36)
- .backgroundColor(Color.Transparent)
- .onClick(() => this.postControlAction(MusicCardActionConstants.ACTION_PLAY_PAUSE))
- this.ControlButton($r('sys.symbol.forward_end_fill'),
- MusicCardActionConstants.ACTION_NEXT, 30, 28)
- }
- .justifyContent(FlexAlign.SpaceBetween)
- .width('100%')
- .alignItems(VerticalAlign.Center)
- }
- .width('100%')
- .justifyContent(FlexAlign.Center)
- .alignItems(HorizontalAlign.Center)
- .layoutWeight(1)
- }
- }
- .width('100%')
- .height('100%')
- .padding({ left: 18, right: 18, top: 18, bottom: 18 })
- }
- .width('100%')
- .height('100%')
- .clip(true)
- .onClick(() => this.postRouterAction(MusicCardActionConstants.ACTION_OPEN_PLAYER))
- }
- }
|