|
|
@@ -59,9 +59,12 @@ import { ServerLogUtil } from '../common/util/ServerLogUtil';
|
|
|
import { PlayStatus } from '../common/PlayStatus';
|
|
|
import { PointLightDefaultButton } from '../view/PointLight/PointLightDeFaultButton';
|
|
|
import { PointLightContentButton } from '../view/PointLight/PointLightContentButton';
|
|
|
+import { PlayingIndicator } from '../view/PlayingIndicator';
|
|
|
import { FindView } from '../view/FindView';
|
|
|
import { hdsEffect } from '@kit.UIDesignKit';
|
|
|
-import { resolveMiniPlayerMorphTarget } from '../common/util/PlayerDismissHelper';
|
|
|
+import {
|
|
|
+ resolveMiniPlayerMorphTarget,
|
|
|
+} from '../common/util/PlayerDismissHelper';
|
|
|
|
|
|
// import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
|
|
|
|
|
|
@@ -88,13 +91,26 @@ struct NewIndex {
|
|
|
@Provide CONTROL_PlayStatus: number = PlayStatus.INIT;
|
|
|
@Provide progressValue: number = 0;
|
|
|
@State isShowPrecious: boolean = false //播控条显示上一首按钮
|
|
|
- @State bottomBarHeight: number = 70;
|
|
|
+ @State bottomBarHeight: number = 64;
|
|
|
+ // 迷你播放条的整体形变状态,既用于出现/消失,也用于 full bar <-> orb 切换。
|
|
|
@State miniPlayerScaleX: number = 1;
|
|
|
@State miniPlayerScaleY: number = 1;
|
|
|
@State miniPlayerOpacity: number = 1;
|
|
|
@State miniPlayerBorderRadius: number = 200;
|
|
|
@State miniPlayerProxySize: number = 0;
|
|
|
@State miniPlayerProxyOpacity: number = 0;
|
|
|
+ // 内容层和圆球层分开控制,保证收拢到右侧圆球时有独立位移/透明度/缩放。
|
|
|
+ @State miniPlayerContentScaleY: number = 1;
|
|
|
+ @State miniPlayerContentTranslateY: number = 0;
|
|
|
+ @State miniPlayerFullContentTranslateX: number = 0;
|
|
|
+ @State miniPlayerTranslateY: number = 0;
|
|
|
+ @State miniPlayerSurfaceWidth: number = 0;
|
|
|
+ @State miniPlayerSurfaceHeight: number = 0;
|
|
|
+ @State miniPlayerFullContentOpacity: number = 1;
|
|
|
+ @State miniPlayerOrbOpacity: number = 0;
|
|
|
+ @State miniPlayerOrbScale: number = 1;
|
|
|
+ @State miniPlayerOrbTranslateX: number = 0;
|
|
|
+ @State isMiniPlayerOrbMode: boolean = false;
|
|
|
@State isMiniPlayerMounted: boolean = true;
|
|
|
@StorageProp('bottomSafeHeight') bottomSafeHeight: number = 0;
|
|
|
@Provide cover: string | undefined = '';
|
|
|
@@ -134,10 +150,10 @@ struct NewIndex {
|
|
|
/** 本地音乐列表,持久化存储 */
|
|
|
@StorageLink('musicLocalList') musicLocalList: Array<VideoItem> = []
|
|
|
@Provide isFavMusic: boolean = false
|
|
|
- @StorageProp('windowWidth') windowWidth: number = 0;
|
|
|
- @StorageProp('windowHeight') windowHeight: number = 0;
|
|
|
+ @StorageProp('windowWidth') @Watch('onMiniPlayerLayoutContextChange') windowWidth: number = 0;
|
|
|
+ @StorageProp('windowHeight') @Watch('onMiniPlayerLayoutContextChange') windowHeight: number = 0;
|
|
|
@StorageProp('isHiCarStatus') isHiCarStatus: boolean = false;
|
|
|
- @StorageProp('curDisplayIsHiCar') curDisplayIsHiCar: boolean = false;
|
|
|
+ @StorageProp('curDisplayIsHiCar') @Watch('onMiniPlayerLayoutContextChange') curDisplayIsHiCar: boolean = false;
|
|
|
/**
|
|
|
* 是否显示更新日志开关
|
|
|
*/
|
|
|
@@ -161,7 +177,8 @@ struct NewIndex {
|
|
|
*/
|
|
|
private breakpointSystem: BreakpointSystem = new BreakpointSystem();
|
|
|
/** 当前断点类型(如大屏/小屏) */
|
|
|
- @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD;
|
|
|
+ @StorageProp('currentBreakpoint') @Watch('onMiniPlayerLayoutContextChange') currentBreakpoint: string =
|
|
|
+ BreakpointTypeEnum.MD;
|
|
|
/** 记录上一次点击返回键的时间戳,用于双击退出 */
|
|
|
private backTime: number = 0;
|
|
|
private isFindDefaultPromptShowing: boolean = false;
|
|
|
@@ -178,10 +195,22 @@ struct NewIndex {
|
|
|
}
|
|
|
})
|
|
|
@State @Watch('tabSelectedIndexesChanged') tabSelectedIndexes: number[] = [0]
|
|
|
+ // 播放条动画拆成多个阶段,用定时器串起抖动、回弹和最终落位。
|
|
|
private miniPlayerAnimationTimer: number = -1;
|
|
|
private miniPlayerCleanupTimer: number = -1;
|
|
|
- private readonly miniPlayerMorphDuration: number = 220;
|
|
|
- private readonly miniPlayerDotDuration: number = 140;
|
|
|
+ private miniPlayerShakeTimer: number = -1;
|
|
|
+ private miniPlayerShakeSettleTimer: number = -1;
|
|
|
+ private miniPlayerModeAnimationTimer: number = -1;
|
|
|
+ private miniPlayerModeSettleTimer: number = -1;
|
|
|
+ private miniPlayerModeCompleteTimer: number = -1;
|
|
|
+ private readonly miniPlayerMorphDuration: number = 240;
|
|
|
+ private readonly miniPlayerDotDuration: number = 190;
|
|
|
+ private readonly miniPlayerShakeFirstDuration: number = 110;
|
|
|
+ private readonly miniPlayerShakeSecondDuration: number = 140;
|
|
|
+ private readonly miniPlayerShakeSettleDuration: number = 170;
|
|
|
+ private readonly miniPlayerModeDuration: number = 360;
|
|
|
+ private readonly miniPlayerModeBounceDuration: number = 220;
|
|
|
+ private isMiniPlayerModeTransitioning: boolean = false;
|
|
|
//当胶囊按钮的选择发生变化时调用此函数
|
|
|
tabSelectedIndexesChanged() {
|
|
|
if(this.tabSelectedIndexes[0]==1){
|
|
|
@@ -593,38 +622,154 @@ struct NewIndex {
|
|
|
clearTimeout(this.miniPlayerCleanupTimer)
|
|
|
this.miniPlayerCleanupTimer = -1
|
|
|
}
|
|
|
+ if (this.miniPlayerShakeTimer >= 0) {
|
|
|
+ clearTimeout(this.miniPlayerShakeTimer)
|
|
|
+ this.miniPlayerShakeTimer = -1
|
|
|
+ }
|
|
|
+ if (this.miniPlayerShakeSettleTimer >= 0) {
|
|
|
+ clearTimeout(this.miniPlayerShakeSettleTimer)
|
|
|
+ this.miniPlayerShakeSettleTimer = -1
|
|
|
+ }
|
|
|
+ if (this.miniPlayerModeAnimationTimer >= 0) {
|
|
|
+ clearTimeout(this.miniPlayerModeAnimationTimer)
|
|
|
+ this.miniPlayerModeAnimationTimer = -1
|
|
|
+ }
|
|
|
+ if (this.miniPlayerModeSettleTimer >= 0) {
|
|
|
+ clearTimeout(this.miniPlayerModeSettleTimer)
|
|
|
+ this.miniPlayerModeSettleTimer = -1
|
|
|
+ }
|
|
|
+ if (this.miniPlayerModeCompleteTimer >= 0) {
|
|
|
+ clearTimeout(this.miniPlayerModeCompleteTimer)
|
|
|
+ this.miniPlayerModeCompleteTimer = -1
|
|
|
+ }
|
|
|
+ this.isMiniPlayerModeTransitioning = false
|
|
|
+ }
|
|
|
+
|
|
|
+ // 窗口尺寸、断点或显示设备切换时,重新同步播放条表面尺寸。
|
|
|
+ // 这样从手机态切到 HiCar 横屏后,surface 会立即按当前显示环境重新拉伸。
|
|
|
+ private onMiniPlayerLayoutContextChange(): void {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.syncMiniPlayerVisibility(false)
|
|
|
}
|
|
|
|
|
|
+ // 解析当前屏宽下播放条完整宽度,为 full/orb 切换提供统一目标值。
|
|
|
private resolveMiniPlayerMorphMetrics() {
|
|
|
const viewportWidthVp = this.windowWidth > 0 ? px2vp(this.windowWidth) : 360
|
|
|
const miniPlayerHeightVp = this.bottomBarHeight > 0 ? this.bottomBarHeight : 70
|
|
|
return resolveMiniPlayerMorphTarget(viewportWidthVp, 0.9, miniPlayerHeightVp)
|
|
|
}
|
|
|
|
|
|
+ // orb 直径跟随播放条高度,但限制在较稳定的范围内,避免不同设备上忽大忽小。
|
|
|
+ private resolveMiniPlayerOrbSize(): number {
|
|
|
+ const barHeightVp = this.bottomBarHeight > 0 ? this.bottomBarHeight : 70
|
|
|
+ return Math.max(54, Math.min(60, barHeightVp - 8))
|
|
|
+ }
|
|
|
+
|
|
|
+ private resolveMiniPlayerSurfaceTargetWidth(): number {
|
|
|
+ return this.isMiniPlayerOrbMode ? this.resolveMiniPlayerOrbSize() : this.resolveMiniPlayerMorphMetrics().barWidth
|
|
|
+ }
|
|
|
+
|
|
|
+ private resolveMiniPlayerSurfaceTargetHeight(): number {
|
|
|
+ return this.isMiniPlayerOrbMode ? this.resolveMiniPlayerOrbSize() : this.bottomBarHeight
|
|
|
+ }
|
|
|
+
|
|
|
+ private resolveMiniPlayerSurfaceTargetRadius(): number {
|
|
|
+ return this.isMiniPlayerOrbMode ? this.resolveMiniPlayerOrbSize() / 2 : 200
|
|
|
+ }
|
|
|
+
|
|
|
+ private applyMiniPlayerPresentationState(): void {
|
|
|
+ this.miniPlayerSurfaceWidth = this.resolveMiniPlayerSurfaceTargetWidth()
|
|
|
+ this.miniPlayerSurfaceHeight = this.resolveMiniPlayerSurfaceTargetHeight()
|
|
|
+ this.miniPlayerBorderRadius = this.resolveMiniPlayerSurfaceTargetRadius()
|
|
|
+ this.miniPlayerFullContentOpacity = this.isMiniPlayerOrbMode ? 0 : 1
|
|
|
+ this.miniPlayerOrbOpacity = this.isMiniPlayerOrbMode ? 1 : 0
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置到稳定停留态,避免中途中断动画后状态残留。
|
|
|
private resetMiniPlayerAnimationState(): void {
|
|
|
this.miniPlayerScaleX = 1
|
|
|
this.miniPlayerScaleY = 1
|
|
|
this.miniPlayerOpacity = 1
|
|
|
- this.miniPlayerBorderRadius = 200
|
|
|
this.miniPlayerProxySize = 0
|
|
|
this.miniPlayerProxyOpacity = 0
|
|
|
+ this.miniPlayerContentScaleY = 1
|
|
|
+ this.miniPlayerContentTranslateY = 0
|
|
|
+ this.miniPlayerFullContentTranslateX = 0
|
|
|
+ this.miniPlayerTranslateY = 0
|
|
|
+ this.miniPlayerOrbScale = 1
|
|
|
+ this.miniPlayerOrbTranslateX = 0
|
|
|
+ this.applyMiniPlayerPresentationState()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 播放条重新出现时做一次上下抖动,带动内部封面/文字/按钮一起轻微回弹。
|
|
|
+ private startMiniPlayerRevealShake(): void {
|
|
|
+ this.miniPlayerContentScaleY = 1
|
|
|
+ this.miniPlayerContentTranslateY = 0
|
|
|
+ this.getUIContext()?.animateTo({
|
|
|
+ duration: this.miniPlayerShakeFirstDuration,
|
|
|
+ curve: Curve.Sharp
|
|
|
+ }, () => {
|
|
|
+ this.miniPlayerScaleX = 1.012
|
|
|
+ this.miniPlayerScaleY = 0.9
|
|
|
+ this.miniPlayerContentScaleY = 0.965
|
|
|
+ this.miniPlayerContentTranslateY = 1.2
|
|
|
+ })
|
|
|
+ this.miniPlayerShakeTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerShakeTimer = -1
|
|
|
+ this.getUIContext()?.animateTo({
|
|
|
+ duration: this.miniPlayerShakeSecondDuration,
|
|
|
+ curve: Curve.Friction
|
|
|
+ }, () => {
|
|
|
+ this.miniPlayerScaleX = 0.996
|
|
|
+ this.miniPlayerScaleY = 1.036
|
|
|
+ this.miniPlayerContentScaleY = 1.018
|
|
|
+ this.miniPlayerContentTranslateY = -0.8
|
|
|
+ })
|
|
|
+ }, this.miniPlayerShakeFirstDuration + 16)
|
|
|
+ this.miniPlayerShakeSettleTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerShakeSettleTimer = -1
|
|
|
+ this.getUIContext()?.animateTo({
|
|
|
+ duration: this.miniPlayerShakeSettleDuration,
|
|
|
+ curve: Curve.Friction
|
|
|
+ }, () => {
|
|
|
+ this.miniPlayerScaleX = 1
|
|
|
+ this.miniPlayerScaleY = 1
|
|
|
+ this.miniPlayerContentScaleY = 1
|
|
|
+ this.miniPlayerContentTranslateY = 0
|
|
|
+ })
|
|
|
+ }, this.miniPlayerShakeFirstDuration + this.miniPlayerShakeSecondDuration + 32)
|
|
|
}
|
|
|
|
|
|
private isMiniPlayerFullyVisible(): boolean {
|
|
|
+ const targetWidth = this.resolveMiniPlayerSurfaceTargetWidth()
|
|
|
+ const targetRadius = this.resolveMiniPlayerSurfaceTargetRadius()
|
|
|
+ const targetFullContentOpacity = this.isMiniPlayerOrbMode ? 0 : 1
|
|
|
+ const targetOrbOpacity = this.isMiniPlayerOrbMode ? 1 : 0
|
|
|
return this.isMiniPlayerMounted
|
|
|
&& this.miniPlayerOpacity >= 0.99
|
|
|
&& this.miniPlayerScaleX >= 0.999
|
|
|
&& this.miniPlayerScaleY >= 0.999
|
|
|
&& this.miniPlayerProxySize <= 0
|
|
|
+ && Math.abs(this.miniPlayerSurfaceWidth - targetWidth) < 1
|
|
|
+ && Math.abs(this.miniPlayerSurfaceHeight - this.resolveMiniPlayerSurfaceTargetHeight()) < 1
|
|
|
+ && Math.abs(this.miniPlayerBorderRadius - targetRadius) < 1
|
|
|
+ && Math.abs(this.miniPlayerFullContentOpacity - targetFullContentOpacity) < 0.05
|
|
|
+ && Math.abs(this.miniPlayerOrbOpacity - targetOrbOpacity) < 0.05
|
|
|
+ && Math.abs(this.miniPlayerContentScaleY - 1) < 0.01
|
|
|
+ && Math.abs(this.miniPlayerContentTranslateY) < 0.2
|
|
|
+ && Math.abs(this.miniPlayerTranslateY) < 1
|
|
|
}
|
|
|
|
|
|
private shouldShowMiniPlayer(): boolean {
|
|
|
return !(this.isMultiSelect || (this.mType > 0 && this.mType < 6) || this.isShowPlay)
|
|
|
}
|
|
|
|
|
|
+ // 同步播放条挂载与显示状态。
|
|
|
+ // show: 直接挂载后做抖动;hide: 向下轻压并淡出。
|
|
|
private syncMiniPlayerVisibility(animated: boolean = true): void {
|
|
|
const shouldShow = this.shouldShowMiniPlayer()
|
|
|
- const target = this.resolveMiniPlayerMorphMetrics()
|
|
|
this.clearMiniPlayerAnimationTimer()
|
|
|
if (!animated) {
|
|
|
this.isMiniPlayerMounted = shouldShow
|
|
|
@@ -635,76 +780,177 @@ struct NewIndex {
|
|
|
if (this.isMiniPlayerFullyVisible()) {
|
|
|
return
|
|
|
}
|
|
|
- if (!this.isMiniPlayerMounted) {
|
|
|
- this.isMiniPlayerMounted = true
|
|
|
- this.miniPlayerScaleX = target.circleScaleX
|
|
|
- this.miniPlayerScaleY = target.circleScaleY
|
|
|
- this.miniPlayerOpacity = 0
|
|
|
- this.miniPlayerBorderRadius = target.circleDiameter / 2
|
|
|
- this.miniPlayerProxySize = target.dotDiameter
|
|
|
- this.miniPlayerProxyOpacity = 1
|
|
|
- } else if (this.miniPlayerProxySize <= 0) {
|
|
|
- this.miniPlayerProxySize = target.circleDiameter
|
|
|
- this.miniPlayerProxyOpacity = 1
|
|
|
+ this.isMiniPlayerMounted = true
|
|
|
+ this.resetMiniPlayerAnimationState()
|
|
|
+ this.miniPlayerAnimationTimer = setTimeout(() => {
|
|
|
+ if (!this.shouldShowMiniPlayer() || !this.isMiniPlayerMounted) {
|
|
|
+ this.miniPlayerAnimationTimer = -1
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.miniPlayerAnimationTimer = -1
|
|
|
+ this.startMiniPlayerRevealShake()
|
|
|
+ }, 16)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.isMiniPlayerMounted) {
|
|
|
+ this.resetMiniPlayerAnimationState()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.getUIContext()?.animateTo({
|
|
|
+ duration: this.miniPlayerDotDuration,
|
|
|
+ curve: Curve.Ease
|
|
|
+ }, () => {
|
|
|
+ this.miniPlayerScaleX = 0.96
|
|
|
+ this.miniPlayerScaleY = 0.88
|
|
|
+ this.miniPlayerOpacity = 0
|
|
|
+ this.miniPlayerBorderRadius = 200
|
|
|
+ this.miniPlayerProxySize = 0
|
|
|
+ this.miniPlayerProxyOpacity = 0
|
|
|
+ this.miniPlayerContentScaleY = 0.96
|
|
|
+ this.miniPlayerContentTranslateY = 0.8
|
|
|
+ this.miniPlayerTranslateY = 18
|
|
|
+ })
|
|
|
+ this.miniPlayerCleanupTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerCleanupTimer = -1
|
|
|
+ if (!this.shouldShowMiniPlayer()) {
|
|
|
+ this.isMiniPlayerMounted = false
|
|
|
+ }
|
|
|
+ this.resetMiniPlayerAnimationState()
|
|
|
+ }, this.miniPlayerDotDuration + 16)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 点击左侧封面后,把完整播放条收拢成右侧圆球,并在右侧做一次左右回弹。
|
|
|
+ private collapseMiniPlayerToOrb(): void {
|
|
|
+ if (this.isMiniPlayerOrbMode || !this.isMiniPlayerMounted || this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const fullWidth = this.resolveMiniPlayerMorphMetrics().barWidth
|
|
|
+ const orbSize = this.resolveMiniPlayerOrbSize()
|
|
|
+ const collapseOvershootWidth = Math.min(fullWidth, orbSize + 10)
|
|
|
+ this.clearMiniPlayerAnimationTimer()
|
|
|
+ this.isMiniPlayerModeTransitioning = true
|
|
|
+ this.miniPlayerScaleX = 1
|
|
|
+ this.miniPlayerScaleY = 1
|
|
|
+ this.miniPlayerOpacity = 1
|
|
|
+ this.miniPlayerContentScaleY = 1
|
|
|
+ this.miniPlayerContentTranslateY = 0
|
|
|
+ this.miniPlayerFullContentTranslateX = 0
|
|
|
+ this.miniPlayerTranslateY = 0
|
|
|
+ this.miniPlayerOrbScale = 0.82
|
|
|
+ this.miniPlayerOrbTranslateX = 10
|
|
|
+ this.isMiniPlayerOrbMode = true
|
|
|
+ this.miniPlayerFullContentOpacity = 1
|
|
|
+ this.miniPlayerOrbOpacity = 0
|
|
|
+ this.getUIContext()?.animateTo({
|
|
|
+ duration: this.miniPlayerModeDuration,
|
|
|
+ curve: Curve.Sharp
|
|
|
+ }, () => {
|
|
|
+ this.miniPlayerSurfaceWidth = orbSize
|
|
|
+ this.miniPlayerSurfaceHeight = orbSize
|
|
|
+ this.miniPlayerBorderRadius = orbSize / 2
|
|
|
+ this.miniPlayerFullContentOpacity = 0
|
|
|
+ this.miniPlayerFullContentTranslateX = 24
|
|
|
+ this.miniPlayerOrbOpacity = 1
|
|
|
+ this.miniPlayerOrbScale = 1.06
|
|
|
+ this.miniPlayerOrbTranslateX = 0
|
|
|
+ })
|
|
|
+ this.miniPlayerModeAnimationTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerModeAnimationTimer = -1
|
|
|
+ if (!this.isMiniPlayerOrbMode || !this.isMiniPlayerMounted) {
|
|
|
+ return
|
|
|
}
|
|
|
this.getUIContext()?.animateTo({
|
|
|
- duration: this.miniPlayerDotDuration,
|
|
|
- curve: Curve.Sharp
|
|
|
+ duration: this.miniPlayerModeBounceDuration,
|
|
|
+ curve: Curve.Friction
|
|
|
}, () => {
|
|
|
- this.miniPlayerProxySize = target.circleDiameter
|
|
|
- this.miniPlayerProxyOpacity = 1
|
|
|
+ this.miniPlayerSurfaceWidth = collapseOvershootWidth
|
|
|
+ this.miniPlayerBorderRadius = collapseOvershootWidth / 2
|
|
|
+ this.miniPlayerOrbScale = 0.97
|
|
|
})
|
|
|
- this.miniPlayerAnimationTimer = setTimeout(() => {
|
|
|
- this.miniPlayerAnimationTimer = -1
|
|
|
+ this.miniPlayerModeSettleTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerModeSettleTimer = -1
|
|
|
+ if (!this.isMiniPlayerOrbMode || !this.isMiniPlayerMounted) {
|
|
|
+ return
|
|
|
+ }
|
|
|
this.getUIContext()?.animateTo({
|
|
|
- duration: this.miniPlayerMorphDuration,
|
|
|
+ duration: this.miniPlayerModeBounceDuration,
|
|
|
curve: Curve.Friction
|
|
|
}, () => {
|
|
|
- this.miniPlayerScaleX = 1
|
|
|
- this.miniPlayerScaleY = 1
|
|
|
- this.miniPlayerOpacity = 1
|
|
|
- this.miniPlayerBorderRadius = 200
|
|
|
- this.miniPlayerProxySize = target.circleDiameter
|
|
|
- this.miniPlayerProxyOpacity = 0
|
|
|
+ this.miniPlayerSurfaceWidth = orbSize
|
|
|
+ this.miniPlayerBorderRadius = orbSize / 2
|
|
|
+ this.miniPlayerOrbScale = 1
|
|
|
+ this.miniPlayerFullContentTranslateX = 0
|
|
|
})
|
|
|
- }, this.miniPlayerDotDuration + 16)
|
|
|
- return
|
|
|
- }
|
|
|
- if (!this.isMiniPlayerMounted) {
|
|
|
- this.resetMiniPlayerAnimationState()
|
|
|
+ }, this.miniPlayerModeBounceDuration + 16)
|
|
|
+ this.miniPlayerModeCompleteTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerModeCompleteTimer = -1
|
|
|
+ this.isMiniPlayerModeTransitioning = false
|
|
|
+ this.miniPlayerOrbScale = 1
|
|
|
+ this.miniPlayerOrbTranslateX = 0
|
|
|
+ this.miniPlayerFullContentTranslateX = 0
|
|
|
+ }, this.miniPlayerModeBounceDuration * 2 + 32)
|
|
|
+ }, this.miniPlayerModeDuration + 16)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 再次点击右侧圆球时,从右向左展开回完整播放条,并保留回弹的收尾。
|
|
|
+ private expandMiniPlayerFromOrb(): void {
|
|
|
+ if (!this.isMiniPlayerOrbMode || !this.isMiniPlayerMounted || this.isMiniPlayerModeTransitioning) {
|
|
|
return
|
|
|
}
|
|
|
+ const fullWidth = this.resolveMiniPlayerMorphMetrics().barWidth
|
|
|
+ const orbSize = this.resolveMiniPlayerOrbSize()
|
|
|
+ const expandOvershootWidth = fullWidth + 16
|
|
|
+ this.clearMiniPlayerAnimationTimer()
|
|
|
+ this.isMiniPlayerModeTransitioning = true
|
|
|
+ this.miniPlayerScaleX = 1
|
|
|
+ this.miniPlayerScaleY = 1
|
|
|
+ this.miniPlayerOpacity = 1
|
|
|
+ this.miniPlayerContentScaleY = 1
|
|
|
+ this.miniPlayerContentTranslateY = 0
|
|
|
+ this.miniPlayerFullContentTranslateX = 24
|
|
|
+ this.miniPlayerTranslateY = 0
|
|
|
+ this.miniPlayerOrbScale = 1
|
|
|
+ this.miniPlayerOrbTranslateX = 0
|
|
|
+ this.isMiniPlayerOrbMode = false
|
|
|
+ this.miniPlayerSurfaceWidth = orbSize
|
|
|
+ this.miniPlayerSurfaceHeight = orbSize
|
|
|
+ this.miniPlayerBorderRadius = orbSize / 2
|
|
|
+ this.miniPlayerFullContentOpacity = 0
|
|
|
+ this.miniPlayerOrbOpacity = 1
|
|
|
this.getUIContext()?.animateTo({
|
|
|
- duration: this.miniPlayerMorphDuration,
|
|
|
+ duration: this.miniPlayerModeDuration,
|
|
|
curve: Curve.Friction
|
|
|
}, () => {
|
|
|
- this.miniPlayerScaleX = target.circleScaleX
|
|
|
- this.miniPlayerScaleY = target.circleScaleY
|
|
|
- this.miniPlayerOpacity = 0
|
|
|
- this.miniPlayerBorderRadius = target.circleDiameter / 2
|
|
|
- this.miniPlayerProxySize = target.circleDiameter
|
|
|
- this.miniPlayerProxyOpacity = 1
|
|
|
+ this.miniPlayerSurfaceWidth = expandOvershootWidth
|
|
|
+ this.miniPlayerSurfaceHeight = this.bottomBarHeight
|
|
|
+ this.miniPlayerBorderRadius = 200
|
|
|
+ this.miniPlayerFullContentOpacity = 1
|
|
|
+ this.miniPlayerFullContentTranslateX = -10
|
|
|
+ this.miniPlayerOrbOpacity = 0
|
|
|
+ this.miniPlayerOrbScale = 0.82
|
|
|
+ this.miniPlayerOrbTranslateX = 12
|
|
|
})
|
|
|
- this.miniPlayerAnimationTimer = setTimeout(() => {
|
|
|
- this.miniPlayerAnimationTimer = -1
|
|
|
- this.miniPlayerOpacity = 0
|
|
|
- this.miniPlayerProxySize = target.circleDiameter
|
|
|
- this.miniPlayerProxyOpacity = 1
|
|
|
+ this.miniPlayerModeAnimationTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerModeAnimationTimer = -1
|
|
|
+ if (this.isMiniPlayerOrbMode || !this.isMiniPlayerMounted) {
|
|
|
+ return
|
|
|
+ }
|
|
|
this.getUIContext()?.animateTo({
|
|
|
- duration: this.miniPlayerDotDuration,
|
|
|
- curve: Curve.EaseIn
|
|
|
+ duration: this.miniPlayerModeBounceDuration,
|
|
|
+ curve: Curve.Friction
|
|
|
}, () => {
|
|
|
- this.miniPlayerProxySize = target.dotDiameter
|
|
|
- this.miniPlayerProxyOpacity = 0
|
|
|
+ this.miniPlayerSurfaceWidth = fullWidth
|
|
|
+ this.miniPlayerBorderRadius = 200
|
|
|
+ this.miniPlayerFullContentTranslateX = 0
|
|
|
})
|
|
|
- this.miniPlayerCleanupTimer = setTimeout(() => {
|
|
|
- this.miniPlayerCleanupTimer = -1
|
|
|
- if (!this.shouldShowMiniPlayer()) {
|
|
|
- this.isMiniPlayerMounted = false
|
|
|
- }
|
|
|
- this.resetMiniPlayerAnimationState()
|
|
|
- }, this.miniPlayerDotDuration + 16)
|
|
|
- }, this.miniPlayerMorphDuration + 16)
|
|
|
+ this.miniPlayerModeCompleteTimer = setTimeout(() => {
|
|
|
+ this.miniPlayerModeCompleteTimer = -1
|
|
|
+ this.isMiniPlayerModeTransitioning = false
|
|
|
+ this.miniPlayerOrbScale = 1
|
|
|
+ this.miniPlayerOrbTranslateX = 0
|
|
|
+ this.miniPlayerFullContentTranslateX = 0
|
|
|
+ }, this.miniPlayerModeBounceDuration + 16)
|
|
|
+ }, this.miniPlayerModeDuration + 16)
|
|
|
}
|
|
|
|
|
|
@Builder
|
|
|
@@ -806,6 +1052,61 @@ struct NewIndex {
|
|
|
|
|
|
@State private pointLightOptions: hdsEffect.PointLightOptions | undefined = undefined
|
|
|
|
|
|
+ // 迷你播放条挂载后统一走这个 Builder,避免 build() 里堆叠过多手机/HiCar/orb 分支。
|
|
|
+ @Builder
|
|
|
+ private MiniPlayerBarBuilder() {
|
|
|
+ Row() {
|
|
|
+ Stack() {
|
|
|
+ // 完整播放条层在收拢时向右退出,展开时再从右侧拉回。
|
|
|
+ if (!this.isMiniPlayerOrbMode || this.miniPlayerFullContentOpacity > 0.02) {
|
|
|
+ Stack() {
|
|
|
+ if (this.curDisplayIsHiCar) {
|
|
|
+ this.HiCarPlayController()
|
|
|
+ } else {
|
|
|
+ this.PlayController()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .opacity(this.miniPlayerFullContentOpacity)
|
|
|
+ .translate({ x: this.miniPlayerFullContentTranslateX })
|
|
|
+ }
|
|
|
+
|
|
|
+ // orb 层固定贴右侧,负责接住收拢后的封面并作为展开入口。
|
|
|
+ if (this.isMiniPlayerOrbMode || this.miniPlayerOrbOpacity > 0.02) {
|
|
|
+ Row() {
|
|
|
+ this.MiniPlayerOrbControl()
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .justifyContent(FlexAlign.End)
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.miniPlayerProxySize > 0) {
|
|
|
+ this.MiniPlayerMorphProxyDot()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .width(this.miniPlayerSurfaceWidth)
|
|
|
+ .height(this.miniPlayerSurfaceHeight)
|
|
|
+ .borderRadius(this.miniPlayerBorderRadius)
|
|
|
+ .backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK)
|
|
|
+ .backgroundImage(StrUtil.isEmpty(this.cover) ? $r('app.media.alt') : this.cover)
|
|
|
+ .backgroundImageSize({ width: '100%' })
|
|
|
+ .scale({ x: this.miniPlayerScaleX, y: this.miniPlayerScaleY, centerX: '50%', centerY: '50%' })
|
|
|
+ .opacity(Math.min(0.99, this.miniPlayerOpacity))
|
|
|
+ .clip(true)
|
|
|
+ .clickEffect({ level: ClickEffectLevel.HEAVY })
|
|
|
+ }
|
|
|
+ .width('90%')
|
|
|
+ .height(this.bottomBarHeight)
|
|
|
+ .justifyContent(FlexAlign.End)
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
+ .translate({ y: this.miniPlayerTranslateY })
|
|
|
+ .margin({ bottom: DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_2IN1 || this.curDisplayIsHiCar
|
|
|
+ ? 30 : this.bottomSafeHeight })
|
|
|
+ }
|
|
|
+
|
|
|
build() {
|
|
|
SideBarContainer(SideBarContainerType.AUTO) {
|
|
|
Column() {
|
|
|
@@ -815,30 +1116,7 @@ struct NewIndex {
|
|
|
Stack() {
|
|
|
this.ContentBuild()
|
|
|
if (this.isMiniPlayerMounted) {
|
|
|
- Stack({ alignContent: Alignment.Center }) {
|
|
|
- Stack() {
|
|
|
- this.PlayController()
|
|
|
- }
|
|
|
- .width('100%')
|
|
|
- .height('100%')
|
|
|
- .borderRadius(this.miniPlayerBorderRadius)
|
|
|
- .backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK)
|
|
|
- .backgroundImage(StrUtil.isEmpty(this.cover) ?$r('app.media.alt'):this.cover)
|
|
|
- .backgroundImageSize( { width: '100%' })
|
|
|
- .scale({ x: this.miniPlayerScaleX, y: this.miniPlayerScaleY, centerX: '50%', centerY: '50%' })
|
|
|
- .opacity(Math.min(0.99, this.miniPlayerOpacity))
|
|
|
- .clip(true)
|
|
|
- .clickEffect({ level: ClickEffectLevel.HEAVY })
|
|
|
-
|
|
|
- if (this.miniPlayerProxySize > 0) {
|
|
|
- this.MiniPlayerMorphProxyDot()
|
|
|
- }
|
|
|
- }
|
|
|
- .width('90%')
|
|
|
- .height(this.bottomBarHeight)
|
|
|
- .borderRadius(200)
|
|
|
- .margin({ bottom:DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_2IN1||this.curDisplayIsHiCar
|
|
|
- ? 30 :this.bottomSafeHeight })
|
|
|
+ this.MiniPlayerBarBuilder()
|
|
|
}
|
|
|
}
|
|
|
.alignContent(Alignment.Bottom)
|
|
|
@@ -891,34 +1169,88 @@ struct NewIndex {
|
|
|
}
|
|
|
|
|
|
setShowPlayTrue(){
|
|
|
- if (this.isShowPlay) {
|
|
|
+ if (this.isShowPlay || this.isMiniPlayerModeTransitioning) {
|
|
|
return
|
|
|
}
|
|
|
this.getUIContext().getHostContext()!.eventHub.emit('openPlayerViewFromMiniBar');
|
|
|
}
|
|
|
|
|
|
+ // 右侧圆球内部内容:封面、暗罩、白色环形进度和中心播放状态指示。
|
|
|
@Builder
|
|
|
- PlayController() {
|
|
|
- Row() {
|
|
|
- this.playConLeft(!this.curDisplayIsHiCar)
|
|
|
- if(!this.curDisplayIsHiCar){
|
|
|
- this.playConRigth()
|
|
|
- }
|
|
|
- if(this.curDisplayIsHiCar){
|
|
|
- Column(){
|
|
|
- this.centerName()
|
|
|
- }
|
|
|
- .layoutWeight(1)
|
|
|
- .onClick(()=>{
|
|
|
- this.setShowPlayTrue()
|
|
|
+ private buildMiniPlayerOrbButtonContent(orbSize: number) {
|
|
|
+ Stack({ alignContent: Alignment.Center }) {
|
|
|
+ Image(StrUtil.isNotEmpty(this.cover) ? this.cover as string : $r('app.media.alt'))
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .objectFit(ImageFit.Cover)
|
|
|
+ .alt($r('app.media.alt'))
|
|
|
+ .borderRadius(100)
|
|
|
+ Column()
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .backgroundColor('#66000000')
|
|
|
+
|
|
|
+ Progress({
|
|
|
+ value: Math.floor(this.progressValue),
|
|
|
+ total: 100,
|
|
|
+ type: ProgressType.Ring,
|
|
|
+ })
|
|
|
+ .color(Color.White)
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .style({ strokeWidth: 3 })
|
|
|
+
|
|
|
+ if (this.CONTROL_PlayStatus === PlayStatus.PLAY) {
|
|
|
+ PlayingIndicator({
|
|
|
+ isActive: true,
|
|
|
+ indicatorSize: Math.max(16, Math.floor(orbSize * 0.34)),
|
|
|
+ indicatorColor: '#FFFFFF'
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
.width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .clip(true)
|
|
|
+ .borderRadius(100)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 右侧圆球外层按钮,负责点光、缩放、位移和点击展开。
|
|
|
+ @Builder
|
|
|
+ private MiniPlayerOrbControl() {
|
|
|
+ PointLightContentButton({
|
|
|
+ pointColor: this.themeColor,
|
|
|
+ buttonRadius: this.resolveMiniPlayerOrbSize() / 2,
|
|
|
+ pointLightHeight: 96,
|
|
|
+ pressScale: 0.94,
|
|
|
+ useShadow: true,
|
|
|
+ builder: (): void => {
|
|
|
+ this.buildMiniPlayerOrbButtonContent(this.resolveMiniPlayerOrbSize())
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .width(this.resolveMiniPlayerOrbSize())
|
|
|
+ .height(this.resolveMiniPlayerOrbSize())
|
|
|
+ .opacity(this.miniPlayerOrbOpacity)
|
|
|
+ .borderRadius(this.resolveMiniPlayerOrbSize() / 2)
|
|
|
+ .scale({ x: this.miniPlayerOrbScale, y: this.miniPlayerOrbScale, centerX: '50%', centerY: '50%' })
|
|
|
+ .translate({ x: this.miniPlayerOrbTranslateX })
|
|
|
+ .onClick((): void => {
|
|
|
+ this.expandMiniPlayerFromOrb()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ PlayController() {
|
|
|
+ Row() {
|
|
|
+ this.playConLeft()
|
|
|
+ this.playConRigth()
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
.height(this.bottomBarHeight)
|
|
|
+ .scale({ x: 1, y: this.miniPlayerContentScaleY, centerX: '50%', centerY: '50%' })
|
|
|
+ .translate({ y: this.miniPlayerContentTranslateY })
|
|
|
.hitTestBehavior(HitTestMode.Transparent)
|
|
|
.zIndex(2)
|
|
|
- .onTouch((event: TouchEvent) => {
|
|
|
+ .onTouch((event: TouchEvent): void => {
|
|
|
if (event.type === TouchType.Down) {
|
|
|
this.pointLightOptions = {
|
|
|
color: this.themeColor,
|
|
|
@@ -945,59 +1277,169 @@ struct NewIndex {
|
|
|
|
|
|
}
|
|
|
@Builder
|
|
|
- playConLeft(isLeft: boolean = true) {
|
|
|
+ private HiCarPlayController() {
|
|
|
+ Stack({ alignContent: Alignment.Center }) {
|
|
|
+ this.hiCarLeadingCluster()
|
|
|
+ this.hiCarCenterInfo()
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height(this.bottomBarHeight)
|
|
|
+ .hitTestBehavior(HitTestMode.Transparent)
|
|
|
+ .zIndex(2)
|
|
|
+ .onTouch((event: TouchEvent): void => {
|
|
|
+ if (event.type === TouchType.Down) {
|
|
|
+ this.pointLightOptions = {
|
|
|
+ color: this.themeColor,
|
|
|
+ intensity: 1,
|
|
|
+ height: 60
|
|
|
+ }
|
|
|
+ } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
|
|
|
+ this.pointLightOptions = undefined
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .visualEffect(deviceInfo.sdkApiVersion >= 20
|
|
|
+ ? new hdsEffect.HdsEffectBuilder()
|
|
|
+ .pointLight({
|
|
|
+ options: this.pointLightOptions,
|
|
|
+ illuminatedType: hdsEffect.PointLightIlluminatedType.BORDER_CONTENT
|
|
|
+ })
|
|
|
+ .buildEffect()
|
|
|
+ : undefined)
|
|
|
+ .padding({
|
|
|
+ left: 16,
|
|
|
+ right: 16
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ private hiCarLeadingCluster() {
|
|
|
+ Row() {
|
|
|
+ this.hiCarCoverControl()
|
|
|
+ this.hiCarPlayConRigth()
|
|
|
+ Row()
|
|
|
+ .layoutWeight(1)
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .justifyContent(FlexAlign.Start)
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ playConLeft() {
|
|
|
Row() {
|
|
|
- Image( StrUtil.isNotEmpty(this.currentSong?.pixelMapPath)?
|
|
|
+ Stack({ alignContent: Alignment.Center }) {
|
|
|
+ Image( StrUtil.isNotEmpty(this.currentSong?.pixelMapPath)?
|
|
|
+ this.currentSong?.pixelMapPath:$r('app.media.alt'))
|
|
|
+ .width(48)
|
|
|
+ .height(48)
|
|
|
+ .objectFit(ImageFit.Contain)
|
|
|
+ .alt( $r('app.media.alt'))
|
|
|
+ .fillColor(this.themeColor)
|
|
|
+ .borderRadius(8)
|
|
|
+ .shadow({
|
|
|
+ radius: 15,
|
|
|
+ type: ShadowType.BLUR,
|
|
|
+ color: 'on_primary'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ .width(48)
|
|
|
+ .height(48)
|
|
|
+ .margin({ left: 5 })
|
|
|
+ .zIndex(3)
|
|
|
+ .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.9 })
|
|
|
+ .onClick((): void => {
|
|
|
+ this.collapseMiniPlayerToOrb()
|
|
|
+ })
|
|
|
+
|
|
|
+ Column() {
|
|
|
+ Text(this.currentSong?.name)
|
|
|
+ .fontSize(16)
|
|
|
+ .textOverflow({ overflow: TextOverflow.MARQUEE }) //超长滚动
|
|
|
+ .maxLines(1)
|
|
|
+ .fontColor(Color.White)
|
|
|
+ .fontWeight(FontWeight.Bolder);
|
|
|
+ Row() {
|
|
|
+ Text(this.currentSong?.artist)
|
|
|
+ .margin({ top: 2 })
|
|
|
+ .fontSize(13)
|
|
|
+ .textAlign(TextAlign.Start)
|
|
|
+ .maxLines(1)
|
|
|
+ .fontWeight(FontWeight.Bold)
|
|
|
+ .textOverflow({ overflow: TextOverflow.MARQUEE }) //超长滚动
|
|
|
+ .fontColor(Color.White)
|
|
|
+ }
|
|
|
+ .visibility(this.currentSong?.artist? Visibility.Visible:Visibility.None)
|
|
|
+ }
|
|
|
+ .padding({left:8})
|
|
|
+ .alignItems(HorizontalAlign.Start)
|
|
|
+ .margin({ right: 22 })
|
|
|
+ .onClick((): void => {
|
|
|
+ this.setShowPlayTrue()
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+ .padding({ right: 18 })
|
|
|
+ .layoutWeight(1)
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
+ .justifyContent(FlexAlign.Start)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ private hiCarCoverControl() {
|
|
|
+ Stack({ alignContent: Alignment.Center }) {
|
|
|
+ Image(StrUtil.isNotEmpty(this.currentSong?.pixelMapPath)?
|
|
|
this.currentSong?.pixelMapPath:$r('app.media.alt'))
|
|
|
+ .width(48)
|
|
|
.height(48)
|
|
|
.objectFit(ImageFit.Contain)
|
|
|
- .alt( $r('app.media.alt'))
|
|
|
+ .alt($r('app.media.alt'))
|
|
|
.fillColor(this.themeColor)
|
|
|
- .margin({left:5})
|
|
|
.borderRadius(8)
|
|
|
.shadow({
|
|
|
radius: 15,
|
|
|
type: ShadowType.BLUR,
|
|
|
color: 'on_primary'
|
|
|
})
|
|
|
- // .geometryTransition('cover', { follow: true }) // 绑定标识符
|
|
|
- if(!this.curDisplayIsHiCar){
|
|
|
- Column() {
|
|
|
- Text(this.currentSong?.name)
|
|
|
- .fontSize(16)
|
|
|
- .textOverflow({ overflow: TextOverflow.MARQUEE }) //超长滚动
|
|
|
- .maxLines(1)
|
|
|
- .fontColor(Color.White)
|
|
|
- .fontWeight(FontWeight.Bolder);
|
|
|
- Row() {
|
|
|
- Text(this.currentSong?.artist)
|
|
|
- .margin({ top: 2 })
|
|
|
- .fontSize(13)
|
|
|
- .textAlign(TextAlign.Start)
|
|
|
- .maxLines(1)
|
|
|
- .fontWeight(FontWeight.Bold)
|
|
|
- .textOverflow({ overflow: TextOverflow.MARQUEE }) //超长滚动
|
|
|
- .fontColor(Color.White)
|
|
|
- }
|
|
|
- .visibility(this.currentSong?.artist? Visibility.Visible:Visibility.None)
|
|
|
- }
|
|
|
- .padding({left:8})
|
|
|
- .alignItems(isLeft?HorizontalAlign.Start:HorizontalAlign.End)
|
|
|
- .margin({ right: isLeft?22:10 })
|
|
|
- }else{
|
|
|
- this.playConRigth()
|
|
|
- }
|
|
|
+ }
|
|
|
+ .width(48)
|
|
|
+ .height(48)
|
|
|
+ .margin({ left: 5 })
|
|
|
+ .zIndex(3)
|
|
|
+ .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.9 })
|
|
|
+ .onClick((): void => {
|
|
|
+ this.collapseMiniPlayerToOrb()
|
|
|
+ })
|
|
|
+ }
|
|
|
|
|
|
+ @Builder
|
|
|
+ private hiCarCenterInfo() {
|
|
|
+ Column() {
|
|
|
+ Text(this.currentSong?.name)
|
|
|
+ .fontSize(16)
|
|
|
+ .textOverflow({ overflow: TextOverflow.MARQUEE })
|
|
|
+ .maxLines(1)
|
|
|
+ .textAlign(TextAlign.Center)
|
|
|
+ .fontColor(Color.White)
|
|
|
+ .fontWeight(FontWeight.Bolder)
|
|
|
+ Row() {
|
|
|
+ Text(this.currentSong?.artist)
|
|
|
+ .margin({ top: 2 })
|
|
|
+ .fontSize(13)
|
|
|
+ .textAlign(TextAlign.Center)
|
|
|
+ .maxLines(1)
|
|
|
+ .fontWeight(FontWeight.Bold)
|
|
|
+ .textOverflow({ overflow: TextOverflow.MARQUEE })
|
|
|
+ .fontColor(Color.White)
|
|
|
+ }
|
|
|
+ .visibility(this.currentSong?.artist ? Visibility.Visible : Visibility.None)
|
|
|
}
|
|
|
- .padding({ right: 18 })
|
|
|
- .layoutWeight(1)
|
|
|
- .alignItems(VerticalAlign.Center)
|
|
|
- .justifyContent(FlexAlign.Start)
|
|
|
- .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
|
|
|
- .onClick(() => {
|
|
|
+ .width('42%')
|
|
|
+ .alignItems(HorizontalAlign.Center)
|
|
|
+ .onClick((): void => {
|
|
|
this.setShowPlayTrue()
|
|
|
})
|
|
|
-
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1080,6 +1522,9 @@ struct NewIndex {
|
|
|
.visibility(this.isShowPrecious ? Visibility.Visible : Visibility.None)
|
|
|
.displayPriority(2)
|
|
|
.onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
this.getUIContext().getHostContext()!.eventHub.emit('playPrevious');
|
|
|
})
|
|
|
// 播放进度条与播放键共用一个点光点击区域
|
|
|
@@ -1096,6 +1541,93 @@ struct NewIndex {
|
|
|
.height(46)
|
|
|
.displayPriority(3)
|
|
|
.onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.getUIContext().getHostContext()!.eventHub.emit('playOrPause');
|
|
|
+ })
|
|
|
+
|
|
|
+ PointLightContentButton({
|
|
|
+ pointColor: this.themeColor,
|
|
|
+ buttonRadius: 22,
|
|
|
+ pointLightHeight: 56,
|
|
|
+ pressScale: 0.88,
|
|
|
+ builder: () => {
|
|
|
+ this.buildPlayNextControlContent()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .width(44)
|
|
|
+ .height(44)
|
|
|
+ .displayPriority(2)
|
|
|
+ .onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.getUIContext().getHostContext()!.eventHub.emit('playNext');
|
|
|
+ })
|
|
|
+
|
|
|
+ PointLightContentButton({
|
|
|
+ pointColor: this.themeColor,
|
|
|
+ buttonRadius: 21,
|
|
|
+ pointLightHeight: 52,
|
|
|
+ pressScale: 0.88,
|
|
|
+ builder: () => {
|
|
|
+ this.buildPlayListControlContent()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .width(42)
|
|
|
+ .height(42)
|
|
|
+ .displayPriority(1)
|
|
|
+ .onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.getUIContext().getHostContext()!.eventHub.emit('openPlayList');
|
|
|
+ })
|
|
|
+ }
|
|
|
+ .margin({left:5})
|
|
|
+ .justifyContent(FlexAlign.End)
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ private hiCarPlayConRigth() {
|
|
|
+ Row() {
|
|
|
+ PointLightContentButton({
|
|
|
+ pointColor: this.themeColor,
|
|
|
+ buttonRadius: 22,
|
|
|
+ pointLightHeight: 56,
|
|
|
+ pressScale: 0.88,
|
|
|
+ builder: () => {
|
|
|
+ this.buildPlayPreviousControlContent()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .width(44)
|
|
|
+ .height(44)
|
|
|
+ .visibility(this.isShowPrecious ? Visibility.Visible : Visibility.None)
|
|
|
+ .displayPriority(2)
|
|
|
+ .onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.getUIContext().getHostContext()!.eventHub.emit('playPrevious');
|
|
|
+ })
|
|
|
+ PointLightContentButton({
|
|
|
+ pointColor: this.themeColor,
|
|
|
+ buttonRadius: 23,
|
|
|
+ pointLightHeight: 62,
|
|
|
+ pressScale: 0.9,
|
|
|
+ builder: () => {
|
|
|
+ this.buildPlayToggleControlContent()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .width(46)
|
|
|
+ .height(46)
|
|
|
+ .displayPriority(3)
|
|
|
+ .onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
this.getUIContext().getHostContext()!.eventHub.emit('playOrPause');
|
|
|
})
|
|
|
|
|
|
@@ -1112,6 +1644,9 @@ struct NewIndex {
|
|
|
.height(44)
|
|
|
.displayPriority(2)
|
|
|
.onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
this.getUIContext().getHostContext()!.eventHub.emit('playNext');
|
|
|
})
|
|
|
|
|
|
@@ -1128,11 +1663,14 @@ struct NewIndex {
|
|
|
.height(42)
|
|
|
.displayPriority(1)
|
|
|
.onClick(() => {
|
|
|
+ if (this.isMiniPlayerModeTransitioning) {
|
|
|
+ return
|
|
|
+ }
|
|
|
this.getUIContext().getHostContext()!.eventHub.emit('openPlayList');
|
|
|
})
|
|
|
}
|
|
|
- .margin({left:this.curDisplayIsHiCar?20:5})
|
|
|
- .justifyContent(this.curDisplayIsHiCar?FlexAlign.Start:FlexAlign.End)
|
|
|
+ .margin({ left: 16 })
|
|
|
+ .justifyContent(FlexAlign.Start)
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
}
|
|
|
|