فهرست منبع

多选删除的进度条展示

onecold 9 ماه پیش
والد
کامیت
76c4751492
1فایلهای تغییر یافته به همراه338 افزوده شده و 130 حذف شده
  1. 338 130
      entry/src/main/ets/view/DeleteComptent.ets

+ 338 - 130
entry/src/main/ets/view/DeleteComptent.ets

@@ -16,6 +16,9 @@ export struct DeleteComptent {
   @State isDeletePicture: boolean = true
   @State isDeleteLrc: boolean = true
   @State packName: string = ''
+  @State isDeleting: boolean = false // 删除状态
+  @State deleteProgress: number = 0 // 删除进度 (0-100)
+  @State currentDeleteFile: string = '' // 当前删除的文件名
   onDeleteResult = (_result: boolean) => {
   }
   onCancel = () => {
@@ -35,151 +38,244 @@ export struct DeleteComptent {
 
   build() {
     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)
+      if (this.isDeleting) {
+        // 删除进度界面
+        Column() {
+          Text('正在删除文件').fontSize(18).fontColor(Color.Red).margin({ top: 20, bottom: 15 })
+
+          // 当前文件名显示
+          if (this.currentDeleteFile) {
+            Text(`正在删除: ${this.currentDeleteFile}`)
+              .fontSize(14)
+              .fontColor($r('app.color.text_color'))
+              .maxLines(2)
+              .textOverflow({ overflow: TextOverflow.Ellipsis })
+              .width('90%')
+              .textAlign(TextAlign.Center)
+              .margin({ bottom: 15 })
+          }
 
+          // 进度条
+          Column() {
+            Row() {
+              Text(`${Math.round(this.deleteProgress)}%`)
+                .fontSize(12)
+                .fontColor($r('app.color.text_color'))
+              Blank()
+              Text(`${Math.round(this.deleteProgress * this.selectedFiles.length / 100)}/${this.selectedFiles.length}`)
+                .fontSize(12)
+                .fontColor($r('app.color.text_color'))
+            }
+            .width('90%')
+            .margin({ bottom: 8 })
+
+            Progress({
+              value: this.deleteProgress,
+              total: 100,
+              type: ProgressType.Linear
+            })
+              .width('90%')
+              .height(8)
+              .color(this.themeColor)
+              .backgroundColor('#E0E0E0')
+              .borderRadius(4)
           }
+          .width('100%')
+          .alignItems(HorizontalAlign.Center)
+          .margin({ bottom: 20 })
+
+          // 取消按钮
+          Button('取消删除')
+            .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
+            .padding(15)
+            .width(120)
+            .onClick(() => {
+              this.onCancel()
+            })
+            .backgroundColor($r('app.color.silvery'))
+            .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
+            .fontColor(Color.Black)
         }
-        .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($r('app.color.start_window_background'))
+        .backgroundBlurStyle(BlurStyle.Regular)
+        .padding(20)
+      } else {
+        // 原始删除确认界面
+        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 })
+
           }
-        }
-        .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)
+          .visibility(this.selectedFiles.length==1&&this.selectedFiles[0].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.onCancel()
               })
-              .margin({ right: 28 })
-              .selectedColor(this.themeColor)
-          }
+              .backgroundColor($r('app.color.silvery'))
+              .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
+              .fontColor(Color.Black)
+            Button($r('app.string.sure'))
+              .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
+              .padding(15)
+              .width(120)
+              .onClick(() => {
+                this.doDeleteTask()
+              })
+              .backgroundColor($r('app.color.silvery'))
+              .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
+              .fontColor(Color.Red)
+          }.margin({ bottom: 10 })
         }
-        .backgroundColor(Color.Transparent)
-        .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
-        .onClick(() => {
-          this.isDeleteLrc = !this.isDeleteLrc
-        })
-        .width('100%')
-        .padding(10)
-        .margin({ left: 18, bottom: 10 })
-
+        .backgroundColor($r('app.color.start_window_background'))
+        .backgroundBlurStyle(BlurStyle.Regular)
       }
-      .visibility(this.selectedFiles.length==1&&this.selectedFiles[0].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.onCancel()
-          })
-          .backgroundColor($r('app.color.silvery'))
-          .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
-          .fontColor(Color.Black)
-        Button($r('app.string.sure'))
-          .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
-          .padding(15)
-          .width(120)
-          .onClick(() => {
-            this.doDeleteTask()
-          })
-          .backgroundColor($r('app.color.silvery'))
-          .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
-          .fontColor(Color.Red)
-      }.margin({ bottom: 10 })
     }
-    .backgroundColor($r('app.color.start_window_background'))
-    .backgroundBlurStyle(BlurStyle.Regular)
   }
 
 
   doDeleteTask(){
+    // 设置删除状态
+    this.isDeleting = true;
+    this.deleteProgress = 0;
+    this.currentDeleteFile = '';
+
+    const totalFiles = this.selectedFiles.length;
+    let currentFileIndex = 0;
+
+    // 创建进度监控定时器
+    let progressTimer: number = setInterval(() => {
+      // 基于时间模拟进度
+      if (currentFileIndex < totalFiles) {
+        this.deleteProgress = (currentFileIndex / totalFiles) * 95; // 最高到95%
+        this.currentDeleteFile = this.selectedFiles[currentFileIndex]?.name || '';
+        currentFileIndex++;
+      }
+
+      if (this.deleteProgress >= 95) {
+        clearInterval(progressTimer);
+      }
+    }, 300); // 每300ms更新一次,模拟删除进度
+
     const task = new taskpool.Task(
-      deleteMultipleFiles,
+      deleteMultipleFilesWithProgress,
       JSON.stringify(this.selectedFiles),
       this.isDeleteYuan,this.isDeletePicture,this.isDeleteLrc,this.context,this.packName
     );
     taskpool.execute(task, taskpool.Priority.HIGH).then((result) => {
-      if(result){
-        setTimeout(() => {
-          this.onDeleteResult(true)
-        },500)
+      clearInterval(progressTimer);
+      this.deleteProgress = 100;
+      this.currentDeleteFile = '删除完成';
 
-      }else {
-        this.onDeleteResult(false)
-      }
-    }).catch((error: Error) => {
-      console.error('Subtitle sync failed:', error);
+      setTimeout(() => {
+        if(result){
+          this.onDeleteResult(true)
+        }else {
+          this.onDeleteResult(false)
+        }
+      },500)
+    }).catch((error:Error) => {
+      clearInterval(progressTimer);
+      console.error('heanup DeleteComptent: delete failed:', (error as Error).message);
+      this.isDeleting = false;
     });
   }
 
@@ -187,7 +283,119 @@ export struct DeleteComptent {
 }
 
 
-//多选删除文件
+//多选删除文件(带进度显示的新版本)
+@Concurrent
+async function deleteMultipleFilesWithProgress(
+  selectedFilesStr:string,
+  isDeleteYuan:boolean,
+  isDeletePicture:boolean,
+  isDeleteLrc:boolean,
+  context:Context,
+  packName:string
+) {
+
+  const selectedFiles: VideoItem[] = JSON.parse(selectedFilesStr)
+  if (ArrayUtil.isNotEmpty(selectedFiles)) {
+    const table: MediaTable = new MediaTable(context)
+    const playlistTable: PlaylistTable = new PlaylistTable(context)
+
+    // 初始化数据库
+    await new Promise<void>((resolve, reject) => {
+      table.getRdbStore(context,  (err:Error) => {
+        err ? reject(err) : resolve();
+      });
+    });
+
+    let hasPlaylistChanges = false; // 标记是否有歌单变化
+    const totalFiles = selectedFiles.length;
+
+    for (let i = 0; i < selectedFiles.length; i++) {
+      const item = selectedFiles[i];
+      console.info('heanup DeleteComptent: deleting file ' + (i + 1) + '/' + totalFiles + ': ' + item.name);
+
+      if (item.type === CommonConstants.TYPE_IS_DIR) {
+        // 删除目录
+        await new Promise<void>((resolve) => {
+          table.deleteDataForParentPath(item.filePath, async () => {
+            try {
+              await FileUtil.rmdir(item.filePath);
+              console.info('heanup DeleteComptent: directory deleted: ' + item.filePath);
+            } catch (error) {
+              console.error('heanup DeleteComptent: directory delete error: ' + (error as Error).message);
+            }
+            resolve();
+          });
+        });
+      } else {
+        // 删除文件
+        await new Promise<void>((resolve) => {
+          table.deleteData(item, async () => {
+            try {
+              // 删除源文件
+              if(isDeleteYuan && item.filePath.toLowerCase().includes(packName)){
+                await FileUtil.unlink(item.filePath);
+                console.info('heanup DeleteComptent: source file deleted: ' + item.filePath);
+              }
+
+              // 删除封面文件
+              if (isDeletePicture && item.pixelMapPath) {
+                const picPath = FileUtil.getFilePath(item.pixelMapPath);
+                if (FileUtil.accessSync(picPath)) {
+                  await FileUtil.unlink(picPath);
+                  console.info('heanup DeleteComptent: cover file deleted: ' + picPath);
+                }
+              }
+
+              // 删除歌词文件
+              if(isDeleteLrc) {
+                const lyricPath = item.filePath?.replace(/\.[^/.]+$/, ".lrc");
+                if (lyricPath && item.filePath.toLowerCase().includes(packName) && FileUtil.accessSync(lyricPath)) {
+                  await FileUtil.unlink(lyricPath);
+                  console.info('heanup DeleteComptent: lyric file deleted: ' + lyricPath);
+                }
+              }
+            } catch (error) {
+              console.error('heanup DeleteComptent: file delete error: ' + (error as Error).message);
+            }
+            resolve();
+          });
+        });
+
+        // 从歌单中移除歌曲
+        LogUtil.info('heanup DeleteComptent', `准备从歌单中移除歌曲: ${item.name}, filePath: ${item.filePath}`);
+        if (item.filePath) {
+          try {
+            const affectedPlaylists = await playlistTable.removeSongFromAllPlaylists(item.filePath);
+            LogUtil.info('heanup DeleteComptent', `removeSongFromAllPlaylists 返回了 ${affectedPlaylists.length} 个受影响的歌单`);
+            if (affectedPlaylists.length > 0) {
+              hasPlaylistChanges = true;
+              LogUtil.info('heanup DeleteComptent', `歌曲已从 ${affectedPlaylists.length} 个歌单中移除: ${item.name}`);
+            } else {
+              LogUtil.info('heanup DeleteComptent', `歌曲不在任何歌单中: ${item.name}`);
+            }
+          } catch (error) {
+            LogUtil.error('heanup DeleteComptent', `从歌单移除歌曲失败: ${(error as Error).message}`);
+          }
+        } else {
+          LogUtil.warn('heanup DeleteComptent', `歌曲 ${item.name} 的 filePath 为空`);
+        }
+      }
+
+      // 短暂延迟,让用户能看到进度变化
+      await new Promise<void>(resolve => setTimeout(resolve, 200));
+    }
+
+    // 如果有歌单变化,发送刷新事件
+    if (hasPlaylistChanges) {
+      const eventRefresh: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYLIST_REFRESH };
+      emitter.emit(eventRefresh, {});
+      LogUtil.info('heanup DeleteComptent', '已发送歌单刷新事件,更新歌单数量');
+    }
+  }
+  return true
+}
+
+// 保留原始删除函数作为备用
 @Concurrent
 async function deleteMultipleFiles(
   selectedFilesStr:string,
@@ -218,8 +426,8 @@ async function deleteMultipleFiles(
         table.deleteDataForParentPath(item.filePath, () => {
           FileUtil.rmdir(item.filePath).then(() => {
             return true
-          }).catch((error: Error) => {
-            console.error(error.message);
+          }).catch((error:Error) => {
+            console.error((error as Error).message);
             return false
           });
         });