Просмотр исходного кода

修复名称排序问题
删除单个文件 ,可以选择删除源文件 删除歌词 删除封面

onecold 11 месяцев назад
Родитель
Сommit
7578852e46

+ 2 - 2
AppScope/app.json5

@@ -2,8 +2,8 @@
   "app": {
     "bundleName": "com.xgplayer.ttmusic.hm",
     "vendor": "example",
-    "versionCode": 20250903,
-    "versionName": "1.5.5",
+    "versionCode": 20250906,
+    "versionName": "1.5.6",
     "icon": "$media:app_icon",
     "label": "$string:app_name",
     "multiAppMode": {

+ 24 - 21
entry/src/main/ets/common/util/Utility.ets

@@ -1362,7 +1362,8 @@ export class Utility {
     let options: Intl.CollatorOptions = {
       localeMatcher: "lookup",
       usage: "sort",
-      sensitivity: "case" // 区分大小写
+      sensitivity: "accent", // 对中文更友好
+      numeric:true
     };
 
     const collator = new Intl.Collator("zh-CN", options);
@@ -1372,16 +1373,16 @@ export class Utility {
       if (typeOrder !== 0) {
         return typeOrder;
       }
-
-      const partsA = extractParts(a.name);
-      const partsB = extractParts(b.name);
-
-      const nonNumericComparison = collator.compare(partsA.nonNumeric, partsB.nonNumeric);
-      if (nonNumericComparison !== 0) {
-        return nonNumericComparison;
-      }
-
-      return partsA.numeric - partsB.numeric;
+      return collator.compare(a.name, b.name)
+      // const partsA = extractParts(a.name);
+      // const partsB = extractParts(b.name);
+      //
+      // const nonNumericComparison = collator.compare(partsA.nonNumeric, partsB.nonNumeric);
+      // if (nonNumericComparison !== 0) {
+      //   return nonNumericComparison;
+      // }
+      //
+      // return partsA.numeric - partsB.numeric;
     });
   }
   //按名称降序
@@ -1389,7 +1390,8 @@ export class Utility {
     const options: Intl.CollatorOptions = {
       localeMatcher: "lookup",
       usage: "sort",
-      sensitivity: "case" // 区分大小写
+      sensitivity: "accent", // 对中文更友好
+      numeric:true
     };
 
     const collator = new Intl.Collator("zh-CN", options);
@@ -1399,15 +1401,16 @@ export class Utility {
       if (typeOrder !== 0) {
         return typeOrder;
       }
-      const partsA = extractParts(a.name);
-      const partsB = extractParts(b.name);
-
-      const nonNumericComparison = collator.compare(partsB.nonNumeric, partsA.nonNumeric);
-      if (nonNumericComparison !== 0) {
-        return nonNumericComparison;
-      }
-
-      return partsB.numeric - partsA.numeric;
+      return collator.compare(b.name, a.name)
+      // const partsA = extractParts(a.name);
+      // const partsB = extractParts(b.name);
+      //
+      // const nonNumericComparison = collator.compare(partsB.nonNumeric, partsA.nonNumeric);
+      // if (nonNumericComparison !== 0) {
+      //   return nonNumericComparison;
+      // }
+
+      // return partsB.numeric - partsA.numeric;
     });
   }
 

+ 191 - 25
entry/src/main/ets/view/LocalMusic.ets

@@ -1682,7 +1682,156 @@ export struct LocalMusic {
     }
   }
 
-  showWarnIsDeleteFile(item: VideoItem, index: string, filePath: string) {
+  private deleteDialogComponentId: number = 0
+  @State isDeleteYuan:boolean = true
+  @State isDeletePicture:boolean = true
+  @State isDeleteLrc:boolean = true
+  @Builder
+  customDeleteDialogComponent(item: VideoItem, index: string, filePath: string) {
+    Column() {
+      Text('温馨提醒').fontSize(20).margin({ top: 10, bottom: 10 })
+      Text('是否删除该文件?').fontSize(16).margin({ top: 10, bottom: 10 })
+      Column(){
+        // 删除源文件选项
+        Button({ type: ButtonType.Capsule, stateEffect: true }) {
+          Row() {
+            SymbolGlyph($r('sys.symbol.doc_text'))
+              .fontSize(20)
+              .fontColor([this.themeColor])
+              .alignSelf(ItemAlign.Center)
+              .margin({ left: 15 })
+            Text("删除源文件")
+              .fontSize(16)
+              .layoutWeight(1)
+              .margin({ left: 10 })
+            Toggle({ type: ToggleType.Checkbox, isOn: this.isDeleteYuan })
+              .onChange((isOn: boolean) => {
+                this.isDeleteYuan = isOn;
+                PreferencesUtil.put('isDeleteYuan', this.isDeleteYuan)
+              })
+              .margin({ right: 28 })
+              .selectedColor(this.themeColor)
+
+          }
+        }
+        .backgroundColor(Color.Transparent)
+        .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.6 })
+        .onClick(() => {
+            this.isDeleteYuan = !this.isDeleteYuan
+        })
+        .width('100%')
+        .padding(10)
+        .margin({ left: 18 })
+
+        // 删除封面选项
+        Button({ type: ButtonType.Capsule, stateEffect: true }) {
+          Row() {
+            SymbolGlyph($r('sys.symbol.picture'))
+              .fontSize(20)
+              .fontColor([this.themeColor])
+              .alignSelf(ItemAlign.Center)
+              .margin({ left: 15 })
+            Text("删除封面文件")
+              .fontSize(16)
+              .layoutWeight(1)
+              .margin({ left: 10 })
+            Toggle({ type: ToggleType.Checkbox, isOn: this.isDeletePicture })
+              .onChange((isOn: boolean) => {
+                this.isDeletePicture = isOn;
+                PreferencesUtil.put('isDeletePicture', this.isDeletePicture)
+              })
+              .margin({ right: 28 })
+              .selectedColor(this.themeColor)
+          }
+        }
+        .backgroundColor(Color.Transparent)
+        .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.6 })
+        .onClick(() => {
+          this.isDeletePicture = !this.isDeletePicture
+        })
+        .width('100%')
+        .padding(10)
+        .margin({ left: 18 })
+
+
+        // 删除歌词选项
+        Button({ type: ButtonType.Capsule, stateEffect: true }) {
+          Row() {
+            SymbolGlyph($r('sys.symbol.input_mode'))
+              .fontSize(20)
+              .fontColor([this.themeColor])
+              .alignSelf(ItemAlign.Center)
+              .margin({ left: 15 })
+
+            Text("删除歌词文件")
+              .fontSize(16)
+              .layoutWeight(1)
+              .margin({ left: 10 })
+            Toggle({ type: ToggleType.Checkbox, isOn: this.isDeleteLrc })
+              .onChange((isOn: boolean) => {
+                this.isDeleteLrc = isOn;
+                PreferencesUtil.put('isDeleteLrc', this.isDeleteLrc)
+              })
+              .margin({ right: 28 })
+              .selectedColor(this.themeColor)
+          }
+        }
+        .backgroundColor(Color.Transparent)
+        .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.6 })
+        .onClick(() => {
+          this.isDeleteLrc = !this.isDeleteLrc
+        })
+        .width('100%')
+        .padding(10)
+        .margin({ left: 18 ,bottom:10})
+
+      }
+      .visibility(item.type === CommonConstants.TYPE_IS_DIR?Visibility.None:Visibility.Visible)
+      Flex({ justifyContent: FlexAlign.SpaceAround }) {
+        Button($r('app.string.cancel'))
+          .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.8 })
+          .padding(15)
+          .width(120)
+          .onClick(() => {
+            this.getUIContext().getPromptAction().closeCustomDialog(this.deleteDialogComponentId)
+          }).backgroundColor(0xffffff).fontColor(Color.Black)
+        Button($r('app.string.sure'))
+          .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.8 })
+          .padding(15)
+          .width(120)
+          .onClick(() => {
+            this.doDelete(item, index + '', filePath)
+            this.getUIContext().getPromptAction().closeCustomDialog(this.deleteDialogComponentId)
+
+          }).backgroundColor(0xffffff).fontColor(Color.Red)
+      }.margin({ bottom: 10 })
+    }
+  }
+  showWarnIsDeleteFile(item: VideoItem, index: string, filePath: string){
+    this.getUIContext().getPromptAction().openCustomDialog({
+      builder: () => {
+        this.customDeleteDialogComponent(item,index,filePath)
+      },
+      isModal:true,
+      showInSubWindow:false,
+      maskColor: Color.Transparent,
+      dialogTransition: // 设置弹窗内容显示的过渡效果
+      TransitionEffect.translate({ x: 0, y: 290, z: 0 })
+        .animation({ duration: 600, curve: Curve.Smooth }),
+
+      maskTransition: // 设置蒙层显示的过渡效果
+      TransitionEffect.opacity(0)
+        .animation({ duration: 600, curve: Curve.Smooth })
+      }).then((dialogId: number) => {
+        this.deleteDialogComponentId = dialogId
+      })
+        .catch((error: BusinessError) => {
+          console.error(`openCustomDialog error code is ${error.code}, message is ${error.message}`)
+        })
+
+  }
+
+  showWarnIsDeleteFile2(item: VideoItem, index: string, filePath: string) {
     //操作确认类弹出框
     DialogHelper.showAlertDialog({
       maskColor: Color.Transparent,
@@ -1701,7 +1850,7 @@ export struct LocalMusic {
   }
 
   //删除单个索引index的视频
-  doDelete(item: VideoItem, index: string, filePath: string) {
+  async doDelete(item: VideoItem, index: string, filePath: string) {
     if (ArrayUtil.isNotEmpty(this.videoLocalList)) {
 
       Logger.info(TAG, 'delete filePath = ' + filePath);
@@ -1719,17 +1868,28 @@ export struct LocalMusic {
 
 
       } else {
-        this.table.deleteData(item, () => {
-          FileUtil.unlink(filePath)
-            .catch((error: BusinessError) => {
-              console.error(error.message);
-              // 可以根据 error.code 判断是否为"文件不存在",如需特殊处理
-            })
-            .finally(() => {
-              this.videoLocalList.splice(Number(index), 1)
-              this.deleteCache(this.currentPath)
-              this.getSortedFiles(this.currentPath, true)
-            });
+        this.table.deleteData(item,async () => {
+          if(this.isDeleteYuan){
+           await FileUtil.unlink(filePath)
+
+          }
+          if (this.isDeletePicture && item.pixelMapPath &&
+            item.pixelMapPath !== $r('app.media.music_red').toString() &&
+          FileUtil.accessSync(item.pixelMapPath)) {
+            await FileUtil.unlink(item.pixelMapPath);
+            Logger.info(TAG, `onecold 封面文件已删除: ${item.pixelMapPath}`);
+          }
+          if(this.isDeleteLrc) {
+            const lyricPath = item.filePath?.replace(/\.[^/.]+$/, ".lrc");
+            if (lyricPath && FileUtil.accessSync(lyricPath)) {
+              await FileUtil.unlink(lyricPath);
+              Logger.info(TAG, `onecold 歌词文件已删除: ${lyricPath}`);
+            }
+          }
+          this.videoLocalList.splice(Number(index), 1)
+          this.deleteCache(this.currentPath)
+          this.getSortedFiles(this.currentPath, true)
+
         });
 
       }
@@ -2684,20 +2844,22 @@ export struct LocalMusic {
               .padding({ top: 8 })
               Text(StrUtil.isEmpty(item.artist) ? item.cTime : item.artist + '  ' + item?.album)
                 .fontSize(this.twoFingerType == 1 ? 11 : this.twoFingerType == 2 ? 12 : 14)
-                .padding({ top: 8 })
+                .padding({ top: 8 ,right:25})
+                .maxLines(1)
                 .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
                 $r('app.color.text_color'))
                 .margin({ left: this.twoFingerType == 3 ? 6 : 8 })
-                .padding({right:25})
               Blank()
               Text(item.size)
                 .fontSize(this.twoFingerType == 1 ? 11 : this.twoFingerType == 2 ? 12 : 14)
                 .padding({ top: 8 })
+                .maxLines(1)
                 .visibility(StrUtil.isEmpty(item.artist) ? Visibility.Visible : Visibility.None)
                 .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
                 $r('app.color.text_color'))
                 .margin({ left: 10 })
             }
+            .visibility(this.twoFingerType==1?Visibility.None:Visibility.Visible)
             .gesture(LongPressGesture()
               .onAction(async () => {
                 //如果是专辑和艺术家的首页,不能长按
@@ -2921,9 +3083,10 @@ export struct LocalMusic {
               Text(this.currentTitleName)
                 .fontSize(16)
                 .maxLines(1)
+                .textOverflow({ overflow: TextOverflow.MARQUEE })//超长滚动
                 .fontWeight(FontWeight.Bold)
                 .fontColor($r('app.color.text_color'))
-                .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
+                .margin({ left: this.currentLyricAlignMode === 0 ? 13 : 0 })
               if (this.modeType == 3 && ArrayUtil.isNotEmpty(this.videoLocalList)) {
                 Text(`艺术家:${this.videoLocalList[0].artist}`)
                   .fontSize(14)
@@ -2931,7 +3094,7 @@ export struct LocalMusic {
                   .maxLines(1)
                   .fontWeight(FontWeight.Bold)
                   .fontColor($r('app.color.text_color'))
-                  .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
+                  .margin({ left: this.currentLyricAlignMode === 0 ? 13 : 0 })
                 if(this.videoLocalList[0].genre){
                   Text(`风格:${this.videoLocalList[0].genre}`)
                     .fontSize(14)
@@ -3137,14 +3300,17 @@ export struct LocalMusic {
               duration: 666,
               curve: 'ease-in-out' // 可选动画曲线
             })
-          Text(`(${Utility.getGlobalList(this.videoLocalList, CommonConstants.TYPE_LOCAL).length}首)`)
-            .fontColor($r('app.color.text_color'))
-            .fontSize(14)
-            .opacity(this.opacityItem)
-            .animation({
-              duration: 666,
-              curve: 'ease-in-out' // 可选动画曲线
-            })
+          if(Utility.getGlobalList(this.videoLocalList, CommonConstants.TYPE_LOCAL).length>0){
+            Text(`(${Utility.getGlobalList(this.videoLocalList, CommonConstants.TYPE_LOCAL).length}首)`)
+              .fontColor($r('app.color.text_color'))
+              .fontSize(14)
+              .opacity(this.opacityItem)
+              .animation({
+                duration: 666,
+                curve: 'ease-in-out' // 可选动画曲线
+              })
+          }
+
         }
         .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
         .visibility(this.isSearchMode ? Visibility.None : Visibility.Visible)

+ 5 - 2
entry/src/main/resources/base/element/string.json

@@ -138,7 +138,7 @@
     },
     {
       "name": "cancel",
-      "value": "To cancel"
+      "value": "取消"
     },
     {
       "name": "link_check_success",
@@ -204,7 +204,10 @@
       "name": "speed_test",
       "value": "网络测速"
     },
-
+    {
+      "name": "sure",
+      "value": "确定"
+    },
     {
       "name": "jiaocheng",
       "value": "自助教程"