Kaynağa Gözat

歌词增加 歌词发光开关
支持网盘歌曲播放页更换封面

onecold 5 ay önce
ebeveyn
işleme
4274d79a4f

+ 2 - 2
entry/src/main/ets/pages/WebDavMainPage.ets

@@ -2439,8 +2439,8 @@ export struct WebDavMainPage {
         this.SongPropertyRow('文件大小', this.getSongPropertyValue(this.songForPropertySheet?.size))
         this.SongPropertyRow('文件大小', this.getSongPropertyValue(this.songForPropertySheet?.size))
         this.SongPropertyRow('比特率', this.getSongPropertyValue(this.songForPropertySheet?.bit_rate))
         this.SongPropertyRow('比特率', this.getSongPropertyValue(this.songForPropertySheet?.bit_rate))
         this.SongPropertyRow('采样率', this.getSongPropertyValue(this.songForPropertySheet?.sampleRate))
         this.SongPropertyRow('采样率', this.getSongPropertyValue(this.songForPropertySheet?.sampleRate))
-        this.SongPropertyRow('声道数', this.getSongPropertyValue(this.songForPropertySheet?.channels))
-        this.SongPropertyRow('编码类型', this.getSongPropertyValue(this.songForPropertySheet?.mimeType))
+        this.SongPropertyRow('音乐封面', StrUtil.isNotEmpty(this.songForPropertySheet?.pixelMapPath) ? '有' : '无')
+        this.SongPropertyRow('内嵌歌词', StrUtil.isNotEmpty(this.songForPropertySheet?.lyricContent) ? '有' : '无')
         this.SongPropertyRow('创建时间', this.getSongPropertyValue(this.songForPropertySheet?.cTime))
         this.SongPropertyRow('创建时间', this.getSongPropertyValue(this.songForPropertySheet?.cTime))
         this.SongPropertyRow('来源类型', this.getSongTypeLabel(this.songForPropertySheet))
         this.SongPropertyRow('来源类型', this.getSongTypeLabel(this.songForPropertySheet))
         this.SongPropertyRow('文件路径', this.getSongPropertyValue(this.songForPropertySheet?.filePath))
         this.SongPropertyRow('文件路径', this.getSongPropertyValue(this.songForPropertySheet?.filePath))

+ 69 - 16
entry/src/main/ets/view/LocalMusic.ets

@@ -506,6 +506,7 @@ export struct LocalMusic {
   @State isSwipe: boolean = false //listItem的左滑开关
   @State isSwipe: boolean = false //listItem的左滑开关
   @State openSkipSongAnimate: boolean = true//切歌动画效果
   @State openSkipSongAnimate: boolean = true//切歌动画效果
   @State isPlayPageSwipeNext: boolean = true // 播放页上滑切歌
   @State isPlayPageSwipeNext: boolean = true // 播放页上滑切歌
+  @State isLightText: boolean = true //是否开启歌词发光
   @State customizeBgPath: string | undefined = '';
   @State customizeBgPath: string | undefined = '';
   @State isDarkMode: boolean = false
   @State isDarkMode: boolean = false
   @State lyricTextWeight: number = 400
   @State lyricTextWeight: number = 400
@@ -1386,7 +1387,9 @@ export struct LocalMusic {
     this.isCoverTopBig = PreferencesUtil.getBooleanSync(SettingPage.IS_COVER_TOP_BIG, false)
     this.isCoverTopBig = PreferencesUtil.getBooleanSync(SettingPage.IS_COVER_TOP_BIG, false)
     this.isShowSingleLineLyric = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_SLLYRIC, false)
     this.isShowSingleLineLyric = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_SLLYRIC, false)
     this.isEnableWordByWordLyric = PreferencesUtil.getBooleanSync(SettingPage.IS_ENABLE_WORD_BY_WORD_LYRIC, true)
     this.isEnableWordByWordLyric = PreferencesUtil.getBooleanSync(SettingPage.IS_ENABLE_WORD_BY_WORD_LYRIC, true)
+    this.isLightText = PreferencesUtil.getBooleanSync(SettingPage.IS_LIGHT_TEXT, true)
     this.syncWordByWordLyricMode()
     this.syncWordByWordLyricMode()
+    this.syncLyricLightTextMode()
     this.longPressSpeed = PreferencesUtil.getNumberSync(SettingPage.LONG_PRESS_SPEED, 3)
     this.longPressSpeed = PreferencesUtil.getNumberSync(SettingPage.LONG_PRESS_SPEED, 3)
     this.isPlayListBgGrass = PreferencesUtil.getBooleanSync(SettingPage.IS_PLAYLIST_BG_GRASS, true)
     this.isPlayListBgGrass = PreferencesUtil.getBooleanSync(SettingPage.IS_PLAYLIST_BG_GRASS, true)
     this.isShowHeader = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_HEADER, true)
     this.isShowHeader = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_HEADER, true)
@@ -3136,23 +3139,37 @@ export struct LocalMusic {
       ToastUtil.showToast('当前歌曲无效');
       ToastUtil.showToast('当前歌曲无效');
       return;
       return;
     }
     }
-    if (this.currentSong.type !== CommonConstants.TYPE_LOCAL) {
-      ToastUtil.showToast('仅支持本地歌曲更换封面');
-      return;
-    }
 
 
     const sandboxCoverUri = await this.pickCoverImageToSandbox();
     const sandboxCoverUri = await this.pickCoverImageToSandbox();
     if (StrUtil.isEmpty(sandboxCoverUri)) {
     if (StrUtil.isEmpty(sandboxCoverUri)) {
       return;
       return;
     }
     }
+    const coverUri = sandboxCoverUri as string;
 
 
     this.loadingDialogId = DialogHelper.showLoadingDialog();
     this.loadingDialogId = DialogHelper.showLoadingDialog();
     try {
     try {
+      if (isRemoteCloudType(this.currentSong.type)) {
+        this.cover = coverUri;
+        this.currentSong.pixelMapPath = coverUri;
+        this.syncRemoteManagerSong(this.currentSong);
+        await this.persistRemoteMetadataToDb(this.currentSong);
+        this.emitRemoteMetadataUpdated(this.currentSong);
+        this.currentSong = cloneVideoItem(this.currentSong);
+        AppStorage.setOrCreate('currentSong', this.currentSong);
+        ToastUtil.showToast('更换封面成功');
+        return;
+      }
+
+      if (this.currentSong.type !== CommonConstants.TYPE_LOCAL) {
+        ToastUtil.showToast('当前歌曲类型暂不支持更换封面');
+        return;
+      }
+
       const task = new taskpool.Task(
       const task = new taskpool.Task(
         replaceLocalMusicCoverTask,
         replaceLocalMusicCoverTask,
         this.context,
         this.context,
         this.currentSong.filePath,
         this.currentSong.filePath,
-        FileUtil.getFilePath(sandboxCoverUri!)
+        FileUtil.getFilePath(coverUri)
       );
       );
       const result = await taskpool.execute(task, taskpool.Priority.HIGH) as boolean;
       const result = await taskpool.execute(task, taskpool.Priority.HIGH) as boolean;
       if (!result) {
       if (!result) {
@@ -3160,8 +3177,8 @@ export struct LocalMusic {
         return;
         return;
       }
       }
 
 
-      this.cover = sandboxCoverUri;
-      this.currentSong.pixelMapPath = sandboxCoverUri;
+      this.cover = coverUri;
+      this.currentSong.pixelMapPath = coverUri;
       await this.doUpateEditedFields(this.currentSong);
       await this.doUpateEditedFields(this.currentSong);
       ToastUtil.showToast('更换封面成功');
       ToastUtil.showToast('更换封面成功');
     } catch (error) {
     } catch (error) {
@@ -10412,8 +10429,8 @@ export struct LocalMusic {
           duration: 666,
           duration: 666,
           curve: 'ease-in-out' // 可选动画曲线
           curve: 'ease-in-out' // 可选动画曲线
         })
         })
-        .transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 0.8, y: 0.8 }).animation({ duration: 600 }),
-          TransitionEffect.scale({ x: 0, y: 0 })))
+        // .transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 0.8, y: 0.8 }).animation({ duration: 600 }),
+        //   TransitionEffect.scale({ x: 0, y: 0 })))
         .clickEffect({ level: ClickEffectLevel.MIDDLE })
         .clickEffect({ level: ClickEffectLevel.MIDDLE })
         //拖动List关键代码开始
         //拖动List关键代码开始
         .scale({ x: this.scaleSelect(index), y: this.scaleSelect(index) })
         .scale({ x: this.scaleSelect(index), y: this.scaleSelect(index) })
@@ -11240,6 +11257,12 @@ export struct LocalMusic {
     this.lyricControllerSingle.setEnableWordByWordLyric(this.isEnableWordByWordLyric)
     this.lyricControllerSingle.setEnableWordByWordLyric(this.isEnableWordByWordLyric)
   }
   }
 
 
+  private syncLyricLightTextMode(): void {
+    this.lyricController.setLightText(this.isLightText)
+    this.lyricControllerXF.setLightText(this.isLightText)
+    this.lyricControllerSingle.setLightText(this.isLightText)
+  }
+
   /**
   /**
    * 初始化歌词加载与展示逻辑
    * 初始化歌词加载与展示逻辑
    * @param lyricPath 歌词文件路径(支持普通.lrc和加密.lrcc)
    * @param lyricPath 歌词文件路径(支持普通.lrc和加密.lrcc)
@@ -11265,6 +11288,7 @@ export struct LocalMusic {
     }
     }
 
 
     this.syncWordByWordLyricMode()
     this.syncWordByWordLyricMode()
+    this.syncLyricLightTextMode()
     this.initPipLyricSetting()
     this.initPipLyricSetting()
     this.lyricControllerSingle
     this.lyricControllerSingle
       .setTextSize(15)
       .setTextSize(15)
@@ -11859,14 +11883,14 @@ export struct LocalMusic {
             .fontWeight(FontWeight.Bolder)
             .fontWeight(FontWeight.Bolder)
             .fontColor(Color.White)
             .fontColor(Color.White)
             .textOverflow({ overflow: TextOverflow.Ellipsis })
             .textOverflow({ overflow: TextOverflow.Ellipsis })
-            .margin({ left: this.currentLyricAlignMode === 0 ? 8 : 0 })
+            .margin({ left:  10 })
           Row() {
           Row() {
             Text(this.currentSong?.artist !== undefined ? this.currentSong?.artist : '')
             Text(this.currentSong?.artist !== undefined ? this.currentSong?.artist : '')
               .fontSize(13)
               .fontSize(13)
               .fontWeight(FontWeight.Bolder)
               .fontWeight(FontWeight.Bolder)
               .padding({ top: 8 })
               .padding({ top: 8 })
               .fontColor(Color.White)
               .fontColor(Color.White)
-              .margin({ left: this.currentLyricAlignMode === 0 ? 8 : 0 })
+              .margin({ left: 10 })
             Blank()
             Blank()
 
 
           }
           }
@@ -11912,7 +11936,7 @@ export struct LocalMusic {
 
 
     }
     }
     .width(this.currentLyricAlignModePip === 1?'98%':'90%%')
     .width(this.currentLyricAlignModePip === 1?'98%':'90%%')
-    .padding({ left: 25, right: 25 })
+    .padding({ left: 28, right: 28 })
     .height(58)
     .height(58)
     .alignItems(VerticalAlign.Center)
     .alignItems(VerticalAlign.Center)
   }
   }
@@ -13106,6 +13130,36 @@ export struct LocalMusic {
           top: 10,
           top: 10,
           bottom: 10
           bottom: 10
         })
         })
+
+        Row() {
+          Text(`歌词发光:`)
+            .fontSize(14)
+            .fontColor(Color.White)
+
+          Column() {
+            Toggle({ type: ToggleType.Switch, isOn: this.isLightText })
+              .selectedColor(this.themeColor)
+              .switchPointColor(Color.White)
+              .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.5 })
+              .onChange((checked: boolean) => {
+                this.isLightText = checked;
+                PreferencesUtil.putSync(SettingPage.IS_LIGHT_TEXT, this.isLightText)
+                this.syncLyricLightTextMode()
+              })
+              .width(50)
+              .height(30)
+              .alignSelf(ItemAlign.Start)
+              .margin({ left: 12 })
+            Blank()
+          }
+          .width('76%')
+        }
+        .margin({
+          left: 20,
+          right: 15,
+          top: 10,
+          bottom: 10
+        })
       }
       }
       Row() {
       Row() {
         Text(`歌词居中:`)
         Text(`歌词居中:`)
@@ -13477,7 +13531,6 @@ export struct LocalMusic {
           .textAlign(TextAlign.End)
           .textAlign(TextAlign.End)
 
 
       }
       }
-      .width('76%')
       .margin({
       .margin({
         left: 20,
         left: 20,
         right: 45,
         right: 45,
@@ -13514,7 +13567,7 @@ export struct LocalMusic {
           .textAlign(TextAlign.End)
           .textAlign(TextAlign.End)
 
 
       }
       }
-      .width('76%')
+
       .margin({
       .margin({
         left: 20,
         left: 20,
         right: 45,
         right: 45,
@@ -13552,7 +13605,7 @@ export struct LocalMusic {
 
 
 
 
       }
       }
-      .width('76%')
+
       .margin({
       .margin({
         left: 20,
         left: 20,
         right: 45,
         right: 45,
@@ -13598,7 +13651,7 @@ export struct LocalMusic {
 
 
 
 
       }
       }
-      .width('76%')
+
       .margin({
       .margin({
         left: 20,
         left: 20,
         right: 45,
         right: 45,

+ 12 - 0
lib/src/main/ets/LyricController.ets

@@ -11,6 +11,7 @@ const DEFAULT_ANIM_DURATION = 300
 const DEFAULT_CACHE_SIZE = 4
 const DEFAULT_CACHE_SIZE = 4
 const DEFAULT_BLUR_DEGREE = 4
 const DEFAULT_BLUR_DEGREE = 4
 const DEFAULT_ENABLE_WORD_BY_WORD_LYRIC = true
 const DEFAULT_ENABLE_WORD_BY_WORD_LYRIC = true
+const DEFAULT_LIGHT_TEXT = true
 
 
 /**
 /**
  * The controller for LyricView.
  * The controller for LyricView.
@@ -34,6 +35,7 @@ export class LyricController {
     private textWeight: number = FontWeight.Medium
     private textWeight: number = FontWeight.Medium
     private transverterType: number = 0
     private transverterType: number = 0
     private enableWordByWordLyric: boolean = DEFAULT_ENABLE_WORD_BY_WORD_LYRIC
     private enableWordByWordLyric: boolean = DEFAULT_ENABLE_WORD_BY_WORD_LYRIC
+    private lightText: boolean = DEFAULT_LIGHT_TEXT
     /**
     /**
      *  Listener to observe the lyric data set changed. This is a inner function, do not call this.
      *  Listener to observe the lyric data set changed. This is a inner function, do not call this.
      */
      */
@@ -144,6 +146,16 @@ export class LyricController {
         return this.enableWordByWordLyric
         return this.enableWordByWordLyric
     }
     }
 
 
+    setLightText(lightText: boolean): LyricController {
+        this.lightText = lightText
+        this.onInvalidated(false)
+        return this
+    }
+
+    getLightText(): boolean {
+        return this.lightText
+    }
+
     setHightLightCenter(isHightLightCenter: boolean): LyricController {
     setHightLightCenter(isHightLightCenter: boolean): LyricController {
         this.isHightLightCenter = isHightLightCenter
         this.isHightLightCenter = isHightLightCenter
         this.onInvalidated(true)
         this.onInvalidated(true)

+ 26 - 0
lib/src/main/ets/view/LyricView2.ets

@@ -30,6 +30,7 @@ export struct LyricView2 {
      * If false, lines with word timing will fallback to normal line render.
      * If false, lines with word timing will fallback to normal line render.
      */
      */
     @State enableWordByWordLyric: boolean = true
     @State enableWordByWordLyric: boolean = true
+    @State isLightText: boolean = true
     /**
     /**
      * The color of seek button and duration text.
      * The color of seek button and duration text.
      */
      */
@@ -217,6 +218,7 @@ export struct LyricView2 {
         this.alignMode = this.controller.getAlignMode()
         this.alignMode = this.controller.getAlignMode()
         this.textWeight = this.controller.getTextWeight()
         this.textWeight = this.controller.getTextWeight()
         this.enableWordByWordLyric = this.controller.getEnableWordByWordLyric()
         this.enableWordByWordLyric = this.controller.getEnableWordByWordLyric()
+        this.isLightText = this.controller.getLightText()
     }
     }
 
 
     aboutToAppear() {
     aboutToAppear() {
@@ -358,6 +360,12 @@ export struct LyricView2 {
                     (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                     (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                     : Visibility.Visible)
                     : Visibility.Visible)
                 .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '80%')
                 .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '80%')
+                .textShadow(this.isLightText ? {
+                    radius: 20,
+                    color: Color.White,
+                    offsetX: 0,
+                    offsetY: 0
+                } : undefined)
                 .blendMode(
                 .blendMode(
                     index == this.currentIndex && this.enableWordByWordLyric&&
                     index == this.currentIndex && this.enableWordByWordLyric&&
             !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.DST_IN : undefined,
             !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.DST_IN : undefined,
@@ -378,6 +386,12 @@ export struct LyricView2 {
                     .visibility(this.isSingleLine?
                     .visibility(this.isSingleLine?
                         (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                         (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                         : Visibility.Visible)
                         : Visibility.Visible)
+                    .textShadow(this.isLightText ? {
+                        radius: 20,
+                        color: Color.White,
+                        offsetX: 0,
+                        offsetY: 0
+                    } : undefined)
                     .blendMode(
                     .blendMode(
                         index == this.currentIndex && this.enableWordByWordLyric&&
                         index == this.currentIndex && this.enableWordByWordLyric&&
                             !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.DST_IN : undefined,
                             !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.DST_IN : undefined,
@@ -541,6 +555,12 @@ export struct LyricView2 {
                             (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                             (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                             : Visibility.Visible)
                             : Visibility.Visible)
                         .padding(this.isSingleLine?0:{ top:5,bottom:5 })
                         .padding(this.isSingleLine?0:{ top:5,bottom:5 })
+                        .textShadow(this.isLightText?{
+                            radius: 25,
+                            color: Color.White,
+                            offsetX: 0,
+                            offsetY: 0
+                        }:undefined)
                         .shaderStyle(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) &&
                         .shaderStyle(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) &&
                             this.getWordPlaybackState(word) == 1 ?{
                             this.getWordPlaybackState(word) == 1 ?{
                             direction: GradientDirection.Right,
                             direction: GradientDirection.Right,
@@ -562,6 +582,12 @@ export struct LyricView2 {
                         .padding(this.isSingleLine?{ bottom:2 }:{ bottom:5 })
                         .padding(this.isSingleLine?{ bottom:2 }:{ bottom:5 })
                         .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
                         .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
                         .width('100%')
                         .width('100%')
+                        .textShadow(this.isLightText ? {
+                            radius: 25,
+                            color: Color.White,
+                            offsetX: 0,
+                            offsetY: 0
+                        } : undefined)
                         .visibility(this.isSingleLine?
                         .visibility(this.isSingleLine?
                             (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                             (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                             : Visibility.Visible)
                             : Visibility.Visible)