Kaynağa Gözat

优化歌词

onecold 5 ay önce
ebeveyn
işleme
29b2d92d9a

+ 11 - 12
entry/src/main/ets/pages/WallpaperPreviewPage.ets

@@ -80,17 +80,16 @@ export struct WallpaperPreviewPage {
               Image(this.imageUri)
                 .width('100%')
                 .height('60%')
+                .borderRadius(20)
                 .objectFit(ImageFit.Contain)
                 .shadow({
-                  radius: 55,
+                  radius: 200,
                   type: ShadowType.BLUR,
                   color: 'on_primary'
                 })
             }
             .width('100%')
-            .aspectRatio(this.wallpaperRatio)
-            .borderRadius(28)
-            .clip(true)
+
           } else {
             Text('未获取到图片')
               .fontSize(16)
@@ -106,14 +105,14 @@ export struct WallpaperPreviewPage {
       .height('100%')
 
       Row() {
-        SaveButton()
-          .onClick((event: ClickEvent, result: SaveButtonOnClickResult) => {
-            if (result === SaveButtonOnClickResult.SUCCESS) {
-              void this.saveWallpaper();
-              return;
-            }
-            promptAction.showToast({ message: '相册授权失败,请重试' });
-          })
+        // SaveButton()
+        //   .onClick((event: ClickEvent, result: SaveButtonOnClickResult) => {
+        //     if (result === SaveButtonOnClickResult.SUCCESS) {
+        //       void this.saveWallpaper();
+        //       return;
+        //     }
+        //     promptAction.showToast({ message: '相册授权失败,请重试' });
+        //   })
       }
       .width('100%')
       .justifyContent(FlexAlign.Center)

+ 47 - 14
entry/src/main/ets/view/LocalMusic.ets

@@ -10823,7 +10823,7 @@ export struct LocalMusic {
   }
 
 
-  isHiCar() {
+  isHiCar(): boolean {
 
     return this.curDisplayIsHiCar;
 
@@ -10955,16 +10955,12 @@ export struct LocalMusic {
           }
           .onChange((index: number) => {
             this.currentSwiperIndex = index
-
+            if (index === 1) {
+              this.syncLyricPositionNow()
+            }
           })
           .indicator(false)
-          .displayCount(new BreakpointType({
-            sm: 1,
-            md: 2,
-            lg: 2,
-            xl: 2,
-            xxl: 2
-          }).getValue(this.currentBreakpoint))
+          .displayCount(this.getPlayerSwiperDisplayCount())
           .clip(false)
           .loop(false)
           .autoPlay(false)
@@ -12654,7 +12650,7 @@ export struct LocalMusic {
     Menu(){
       MenuItem({
         symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.picture_2')),
-        content: '设为壁纸'
+        content: '查看封面'
       })
         .onClick(async() => {
           if (StrUtil.isEmpty(cover)) {
@@ -12713,7 +12709,7 @@ export struct LocalMusic {
           isSysBol:true,
           pointColor:Color.White,
           imageResource:this.showSimple?
-            $r('sys.symbol.sun_max'):$r('sys.symbol.sun_max_fill'),
+            $r('sys.symbol.sun_max'):$r('sys.symbol.moon'),
           isPx: false,
           builderHeight: 26,
           builderWidth: 26,
@@ -15134,17 +15130,54 @@ export struct LocalMusic {
     }
   }
 
+  private getPlayerSwiperDisplayCount(): number {
+    return new BreakpointType<number>({
+      sm: 1,
+      md: 2,
+      lg: 2,
+      xl: 2,
+      xxl: 2
+    }).getValue(this.currentBreakpoint) ?? 1
+  }
+
+  private shouldUpdateMainLyricPanel(): boolean {
+    return this.getPlayerSwiperDisplayCount() > 1 || this.currentSwiperIndex === 1
+  }
+
+  private getActivePlaybackPositionMs(): number {
+    if (this.castControllerWrapper && this.isCastPlaying) {
+      return this.currentTime2 * 1000
+    }
+    return this.mIjkMediaPlayer.getCurrentPosition()
+  }
+
+  private syncLyricPositionNow(): void {
+    const position = this.getActivePlaybackPositionMs()
+    if (position < 0) {
+      return
+    }
+    this.updateLyricPosition(position + this.timeOffset * 1000)
+  }
+
   private updateLyricPosition(lyricPosition: number): void {
+    const shouldUpdateMainLyric = this.shouldUpdateMainLyricPanel()
+    const shouldUpdatePipLyric = this.showPipLyric
+    const shouldUpdateSingleLineLyric = this.isShowSingleLineLyric
+    if (!shouldUpdateMainLyric && !shouldUpdatePipLyric && !shouldUpdateSingleLineLyric) {
+      return
+    }
     if (!Number.isNaN(this.lastLyricRenderPosition) &&
       Math.abs(lyricPosition - this.lastLyricRenderPosition) < this.lyricUpdateMinDeltaMs) {
       return;
     }
     this.lastLyricRenderPosition = lyricPosition;
-    this.lyricController.updatePosition(lyricPosition);
-    if(this.showPipLyric){
+    if (shouldUpdateMainLyric) {
+      this.lyricController.updatePosition(lyricPosition);
+    }
+    if (shouldUpdatePipLyric) {
       this.lyricControllerXF.updatePosition(lyricPosition);
     }
-    if(this.isShowSingleLineLyric){
+    if (shouldUpdateSingleLineLyric) {
       this.lyricControllerSingle.updatePosition(lyricPosition);
     }
   }

+ 84 - 15
lib/src/main/ets/view/LyricView2.ets

@@ -1,4 +1,4 @@
-import { duration2text, printW } from '../extensions/Extension';
+import { duration2text } from '../extensions/Extension';
 import { LyricController } from '../LyricController';
 import { Lyric } from '../bean/Lyric';
 import { ListAdapter } from '../extensions/ListAdapter';
@@ -78,6 +78,13 @@ export struct LyricView2 {
     private readonly positionUpdateThrottleMs: number = 33
     private readonly minPositionDeltaMs: number = 8
     private readonly karaokeTransitionWidth: number = 0.12
+    @State highlightFontProgress: number = 1
+    @State highlightFontActiveIndex: number = -1
+    private highlightFontToken: number = 0
+    private highlightFontStartTimeout = -1
+    private readonly highlightFontStartDelayMs: number = 100
+    private readonly highlightFontDurationMs: number = 180
+    private readonly areaReloadThresholdPx: number = 1
 
     private onDataChangedListener = (lyric: Lyric | null) => {
         clearTimeout(this.loadTimeout)
@@ -112,6 +119,10 @@ export struct LyricView2 {
 
     private loadData(lyric: Lyric | null) {
         this.currentLyric = lyric;
+        clearTimeout(this.highlightFontStartTimeout)
+        this.highlightFontToken += 1
+        this.highlightFontActiveIndex = -1
+        this.highlightFontProgress = 1
         if (this.w > 0 && this.h > 0) {
             if (this.currentLyric) {
                 this.listAdapter.clear(false);
@@ -332,8 +343,7 @@ export struct LyricView2 {
     NormalLyricLine(item: LyricLine, index: number) {
         Column(){
             Text(item.text)
-                .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?
-                    this.textHighlightSize : this.textSize)
+                .fontSize(this.getAnimatedLyricFontSize(index))
                 .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
                 .fontColor(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor)
                 .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
@@ -351,8 +361,7 @@ export struct LyricView2 {
             if (item.translation)  {
 
                 Text(item.translation)
-                    .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?
-                        this.textHighlightSize : this.textSize)
+                    .fontSize(this.getAnimatedLyricFontSize(index))
                     .fontColor(this.currentMediaPosition >= item.beginTime ?
                         index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor : this.textColor)
                     .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
@@ -506,11 +515,10 @@ export struct LyricView2 {
     @Builder
     WordByWordLyric(item: LyricLine, index: number) {
         Column() {
-            Row({ space: 0 }) {
+            Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap, justifyContent: this.alignMode === 'center' ? FlexAlign.Center : FlexAlign.Start }) {
                 ForEach(item.words, (word: LyricWord, wordIndex: number) => {
                     Text(word.word)
-                        .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?
-                            this.textHighlightSize : this.textSize)
+                        .fontSize(this.getAnimatedLyricFontSize(index))
                         .fontColor(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) &&
                             this.getWordPlaybackState(word) == 2 ? this.textHighlightColor : this.textColor)
                         .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?
@@ -527,20 +535,20 @@ export struct LyricView2 {
                         }:undefined)
                 })
             }
-            .justifyContent(this.alignMode === 'center' ? FlexAlign.Center : FlexAlign.Start)
             .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '85%')
 
             // 中文翻译(整行显示)
             if (item.translation)  {
                 Row({ space: 0 }) {
                     Text(item.translation)
-                        .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?
-                            this.textHighlightSize : this.textSize)
+                        .fontSize(this.getAnimatedLyricFontSize(index))
                         .fontColor(this.currentMediaPosition >= item.beginTime ?
                             index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor : this.textColor)
                         .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText)? FontWeight.Bold : this.textWeight)
                         .padding({ bottom:5 })
                         .padding(this.isSingleLine?{ bottom:2 }:{ bottom:5 })
+                        .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
+                        .width('100%')
                         .visibility(this.isSingleLine?
                             (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                             : Visibility.Visible)
@@ -680,11 +688,22 @@ export struct LyricView2 {
         .width('100%')
         .height('100%')
         .onAreaChange((_, newSize) => {
-            printW('onSizeChanged: ' + JSON.stringify(newSize))
-            this.h = newSize.height as number
-            this.w = newSize.width as number
+            const nextHeight = Number(newSize.height) || 0
+            const nextWidth = Number(newSize.width) || 0
+            const isFirstMeasure = this.h <= 0 || this.w <= 0
+            const isSizeChanged = Math.abs(nextHeight - this.h) >= this.areaReloadThresholdPx ||
+                Math.abs(nextWidth - this.w) >= this.areaReloadThresholdPx
+            if (!isFirstMeasure && !isSizeChanged) {
+                return
+            }
+            this.h = nextHeight
+            this.w = nextWidth
             if (this.currentLyric) {
-                this.loadData(this.currentLyric)
+                if (this.listAdapter.isEmpty()) {
+                    this.loadData(this.currentLyric)
+                } else {
+                    this.scrollToIndexImmediately(this.currentIndex)
+                }
             }
         })
     }
@@ -692,6 +711,7 @@ export struct LyricView2 {
     aboutToDisappear() {
         clearTimeout(this.loadTimeout)
         clearTimeout(this.seekUiHideTimeout)
+        clearTimeout(this.highlightFontStartTimeout)
     }
 
     private getIndex(position: number): number {
@@ -736,10 +756,12 @@ export struct LyricView2 {
             return
         }
         const safeIndex = Math.max(0, Math.min(count - 1, index))
+        const previousIndex = this.currentIndex
         this.currentIndex = safeIndex
         if (this.isUserTouching) {
             return
         }
+        this.playHighlightFontAnimation(previousIndex, safeIndex)
         if(this.isHightLightCenter){
             this.scroller.scrollToIndex(safeIndex, true, ScrollAlign.CENTER)
         }else{
@@ -751,6 +773,53 @@ export struct LyricView2 {
 
     }
 
+    private shouldApplyHighlightFontAnimation(index: number): boolean {
+        return index === this.currentIndex
+            && index === this.highlightFontActiveIndex
+            && !(this.currentLyric && this.currentLyric.isPlainText)
+            && !this.isUserTouching
+    }
+
+    private getAnimatedLyricFontSize(index: number): number {
+        if (!(index === this.currentIndex) || (this.currentLyric && this.currentLyric.isPlainText)) {
+            return this.textSize
+        }
+        if (!this.shouldApplyHighlightFontAnimation(index)) {
+            return this.textHighlightSize
+        }
+        const progress = Math.max(0, Math.min(1, this.highlightFontProgress))
+        return this.textSize + (this.textHighlightSize - this.textSize) * progress
+    }
+
+    private playHighlightFontAnimation(previousIndex: number, nextIndex: number): void {
+        if (previousIndex === nextIndex) {
+            return
+        }
+        if (this.currentLyric && this.currentLyric.isPlainText) {
+            return
+        }
+        clearTimeout(this.highlightFontStartTimeout)
+        this.highlightFontToken += 1
+        const token = this.highlightFontToken
+        this.highlightFontActiveIndex = nextIndex
+        this.highlightFontProgress = 0
+        this.highlightFontStartTimeout = setTimeout(() => {
+            if (token !== this.highlightFontToken) {
+                return
+            }
+            animateTo({
+                duration: this.highlightFontDurationMs,
+                curve: Curve.EaseOut
+            }, () => {
+                if (token !== this.highlightFontToken) {
+                    return
+                }
+                this.highlightFontProgress = 1
+                this.highlightFontActiveIndex = -1
+            })
+        }, this.highlightFontStartDelayMs)
+    }
+
 
     private onPositionChanged(mediaPosition: number) {
         if (this.isLyricEmpty) {