فهرست منبع

feat(dialog): 支持批量添加歌曲到歌单功能

chendeben 9 ماه پیش
والد
کامیت
49c50e6768
2فایلهای تغییر یافته به همراه125 افزوده شده و 45 حذف شده
  1. 91 38
      entry/src/main/ets/dialog/AddToPlaylistDialog.ets
  2. 34 7
      entry/src/main/ets/view/LocalMusic.ets

+ 91 - 38
entry/src/main/ets/dialog/AddToPlaylistDialog.ets

@@ -25,7 +25,7 @@ function themeColorWithAlpha(themeColor: string, alpha: number, isDarkMode: bool
 struct AddToPlaylistDialogContent {
   @State playlists: Playlist[] = []
   @State selectedPlaylistId: string = ''
-  private currentSong?: VideoItem
+  private currentSongs: VideoItem[] = []
   @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
   @State isDarkMode: boolean = false
   @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
@@ -45,40 +45,93 @@ struct AddToPlaylistDialogContent {
     this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
   }
 
+  private getFirstSong(): VideoItem | undefined {
+    return this.currentSongs.length > 0 ? this.currentSongs[0] : undefined
+  }
+
+  private getSelectedSongCount(): number {
+    return this.currentSongs.length
+  }
+
+  private getPreviewNames(): string {
+    const count = this.currentSongs.length
+    if (count === 0) {
+      return ''
+    }
+    return this.currentSongs.slice(0, Math.min(2, count))
+      .map(item => item.name || '未知歌曲')
+      .join('、')
+  }
+
+  @Builder
+  private renderSingleSong(song: VideoItem) {
+    Row({ space: 12 }) {
+      Image(song.pixelMapPath || $r('app.media.icon'))
+        .width(48)
+        .height(48)
+        .borderRadius(8)
+        .objectFit(ImageFit.Cover)
+
+      Column({ space: 4 }) {
+        Text(song.name || '未知歌曲')
+          .fontSize(14)
+          .fontColor(this.isDarkMode ? '#FFFFFF' : $r('app.color.text_color'))
+          .maxLines(1)
+          .textOverflow({ overflow: TextOverflow.Ellipsis })
+
+        Text(song.artist || '未知艺术家')
+          .fontSize(12)
+          .fontColor(this.isDarkMode ? '#8E8E93' : '#999999')
+          .maxLines(1)
+          .textOverflow({ overflow: TextOverflow.Ellipsis })
+      }
+      .alignItems(HorizontalAlign.Start)
+      .layoutWeight(1)
+    }
+    .width('100%')
+    .padding(12)
+    .backgroundColor(this.isDarkMode ? '#2C2C2E' : $r('app.color.input_background'))
+    .borderRadius(8)
+  }
+
+  @Builder
+  private renderMultiSongs(firstSong: VideoItem, songCount: number, previewNames: string) {
+    Row({ space: 12 }) {
+      Image(firstSong.pixelMapPath || $r('app.media.icon'))
+        .width(48)
+        .height(48)
+        .borderRadius(8)
+        .objectFit(ImageFit.Cover)
+
+      Column({ space: 4 }) {
+        Text(`已选择 ${songCount} 首歌曲`)
+          .fontSize(14)
+          .fontColor(this.isDarkMode ? '#FFFFFF' : $r('app.color.text_color'))
+          .maxLines(1)
+          .textOverflow({ overflow: TextOverflow.Ellipsis })
+
+        Text(previewNames)
+          .fontSize(12)
+          .fontColor(this.isDarkMode ? '#8E8E93' : '#999999')
+          .maxLines(1)
+          .textOverflow({ overflow: TextOverflow.Ellipsis })
+      }
+      .alignItems(HorizontalAlign.Start)
+      .layoutWeight(1)
+    }
+    .width('100%')
+    .padding(12)
+    .backgroundColor(this.isDarkMode ? '#2C2C2E' : $r('app.color.input_background'))
+    .borderRadius(8)
+  }
+
   build() {
     Column({ space: 16 }) {
-
       // 歌曲信息
-      if (this.currentSong) {
-        Row({ space: 12 }) {
-          // 封面
-          Image(this.currentSong.pixelMapPath || $r('app.media.icon'))
-            .width(48)
-            .height(48)
-            .borderRadius(8)
-            .objectFit(ImageFit.Cover)
-
-          // 歌曲名和艺术家
-          Column({ space: 4 }) {
-            Text(this.currentSong.name || '未知歌曲')
-              .fontSize(14)
-              .fontColor(this.isDarkMode ? '#FFFFFF' : $r('app.color.text_color'))
-              .maxLines(1)
-              .textOverflow({ overflow: TextOverflow.Ellipsis })
-
-            Text(this.currentSong.artist || '未知艺术家')
-              .fontSize(12)
-              .fontColor(this.isDarkMode ? '#8E8E93' : '#999999')
-              .maxLines(1)
-              .textOverflow({ overflow: TextOverflow.Ellipsis })
-          }
-          .alignItems(HorizontalAlign.Start)
-          .layoutWeight(1)
-        }
-        .width('100%')
-        .padding(12)
-        .backgroundColor(this.isDarkMode ? '#2C2C2E' : $r('app.color.input_background'))
-        .borderRadius(8)
+      if (this.currentSongs.length === 1 && this.getFirstSong()) {
+        this.renderSingleSong(this.getFirstSong()!)
+      } else if (this.currentSongs.length > 1 && this.getFirstSong()) {
+        this.renderMultiSongs(this.getFirstSong()!, this.getSelectedSongCount(), this.getPreviewNames())
       }
 
       // 创建新歌单按钮
@@ -248,14 +301,14 @@ export struct AddToPlaylistDialogManager {
    */
   @Builder
   buildAddToPlaylistDialog(
-    song: VideoItem,
+    songs: VideoItem[],
     playlists: Playlist[],
     onConfirm: (playlistId: string) => void,
     onCancel?: () => void,
     onCreateNew?: () => void
   ) {
     AddToPlaylistDialogContent({
-      currentSong: song,
+      currentSongs: songs,
       playlists: playlists,
       onConfirm: onConfirm,
       onCancel: onCancel,
@@ -267,7 +320,7 @@ export struct AddToPlaylistDialogManager {
    * 显示添加到歌单对话框
    */
   showAddToPlaylistDialog(
-    song: VideoItem,
+    songs: VideoItem[],
     playlists: Playlist[],
     onConfirm: (playlistId: string) => void,
     onCancel?: () => void,
@@ -278,7 +331,7 @@ export struct AddToPlaylistDialogManager {
       title: '添加到歌单',
       autoCancel: true,
       contentBuilder: () => {
-        this.buildAddToPlaylistDialog(song, playlists, onConfirm, onCancel, onCreateNew)
+        this.buildAddToPlaylistDialog(songs, playlists, onConfirm, onCancel, onCreateNew)
       },
       buttons: []
     })
@@ -295,11 +348,11 @@ const dialogManager = new AddToPlaylistDialogManager()
  * 显示添加到歌单对话框
  */
 export function showAddToPlaylistDialog(
-  song: VideoItem,
+  songs: VideoItem[],
   playlists: Playlist[],
   onConfirm: (playlistId: string) => void,
   onCancel?: () => void,
   onCreateNew?: () => void
 ) {
-  dialogManager.showAddToPlaylistDialog(song, playlists, onConfirm, onCancel, onCreateNew)
+  dialogManager.showAddToPlaylistDialog(songs, playlists, onConfirm, onCancel, onCreateNew)
 }

+ 34 - 7
entry/src/main/ets/view/LocalMusic.ets

@@ -2603,6 +2603,18 @@ export struct LocalMusic {
                 }
               })
 
+            Button('歌单', { type: ButtonType.Circle, stateEffect: true })
+              .width(50)
+              .height(50)
+              .fontSize(13)
+              .margin({ top: 10, bottom: 10, right: 6 })
+              .backgroundColor(this.themeColor)
+              .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.5 })
+              .onClick(async () => {
+                this.longItemFilePath = ''
+                await this.openAddToPlaylistDialog(this.selectedFiles)
+              })
+
 
             // Button('乱码修复', { type: ButtonType.Capsule, stateEffect: true })
             //   .width(90)
@@ -3553,22 +3565,37 @@ export struct LocalMusic {
   /**
    * 显示添加到歌单对话框
    */
-  async showAddToPlaylistDialog(item: VideoItem) {
+  async openAddToPlaylistDialog(items: VideoItem | VideoItem[]) {
+    const songs = Array.isArray(items) ? items : [items]
+    const musicItems = songs.filter(song => song.type !== CommonConstants.TYPE_IS_DIR)
+    if (musicItems.length === 0) {
+      ToastUtil.showToast('请选择要添加的歌曲')
+      return
+    }
+
     // 加载最新的歌单列表
     await this.loadAllPlaylists()
 
     showAddToPlaylistDialog(
-      item,
+      musicItems,
       this.allPlaylists,
       async (playlistId: string) => {
         // 添加歌曲到歌单
-        const success = await this.playlistTable?.addSongToPlaylist(playlistId, item.filePath)
+        const success = await this.playlistTable?.addSongsToPlaylist(playlistId,
+          musicItems.map(song => song.filePath))
         if (success) {
-          ToastUtil.showToast('已添加到歌单')
+          const count = musicItems.length
+          ToastUtil.showToast(count > 1 ? `已添加 ${count} 首歌曲` : '已添加到歌单')
           // 重新加载歌单列表
           await this.loadAllPlaylists()
         } else {
-          ToastUtil.showToast('歌曲已在该歌单中')
+          ToastUtil.showToast(musicItems.length > 1 ? '选中的歌曲已在该歌单中' : '歌曲已在该歌单中')
+        }
+        this.longItemFilePath = ''
+        if (this.isMultiSelect) {
+          this.isMultiSelect = false
+          this.isAllSelected = false
+          this.selectedFiles = []
         }
       },
       () => {
@@ -3583,7 +3610,7 @@ export struct LocalMusic {
               ToastUtil.showToast('歌单创建成功')
               // 重新加载歌单列表并打开添加对话框
               await this.loadAllPlaylists()
-              await this.showAddToPlaylistDialog(item)
+              await this.openAddToPlaylistDialog(musicItems)
             } else {
               ToastUtil.showToast('歌单创建失败')
             }
@@ -5087,7 +5114,7 @@ export struct LocalMusic {
               .visibility(item.type === CommonConstants.TYPE_IS_DIR ? Visibility.None : Visibility.Visible)
               .onClick(async () => {
                 this.longItemFilePath = ''
-                await this.showAddToPlaylistDialog(item)
+                await this.openAddToPlaylistDialog(item)
               })
 
             MenuItem({