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

针对歌单进行界面优化

onecold 10 месяцев назад
Родитель
Сommit
24277691bc

+ 87 - 32
entry/src/main/ets/pages/NewIndex.ets

@@ -1,6 +1,6 @@
 import { AppUtil, DeviceUtil, DisplayUtil, LogUtil, PreferencesUtil, ToastUtil } from '@pura/harmony-utils';
 import { AppUtil, DeviceUtil, DisplayUtil, LogUtil, PreferencesUtil, ToastUtil } from '@pura/harmony-utils';
 import TitleBar from '../view/TitleBar';
 import TitleBar from '../view/TitleBar';
-import { curves, LengthMetrics, router, SegmentButton, SegmentButtonOptions } from '@kit.ArkUI';
+import { curves, LengthMetrics, router, SegmentButton, SegmentButtonOptions, SymbolGlyphModifier } from '@kit.ArkUI';
 import mainViewModel, { MainViewModel } from '../viewmodel/MainViewModel';
 import mainViewModel, { MainViewModel } from '../viewmodel/MainViewModel';
 import ItemData from '../viewmodel/ItemData';
 import ItemData from '../viewmodel/ItemData';
 import type { sysResource } from '../viewmodel/ItemData';
 import type { sysResource } from '../viewmodel/ItemData';
@@ -43,6 +43,7 @@ import { ChartsCount } from './ChartsCount';
 import { image } from '@kit.ImageKit';
 import { image } from '@kit.ImageKit';
 import { Playlist } from '../viewmodel/Playlist';
 import { Playlist } from '../viewmodel/Playlist';
 import PlaylistTable from '../common/util/PlaylistTable';
 import PlaylistTable from '../common/util/PlaylistTable';
+import { convertPlaylistSongsToVideoItems } from './PlaylistDetailPage';
 
 
 // import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
 // import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
 
 
@@ -56,6 +57,11 @@ const TAG = 'NewIndex'; // 日志标签
 @Entry
 @Entry
 @Component
 @Component
 struct NewIndex {
 struct NewIndex {
+  /** 页面上下文 */
+  context = this.getUIContext().getHostContext() as common.UIAbilityContext
+  @Provide currentSongList: Array<VideoItem> = []//当前歌单
+  @Provide currentSongListName:string = '' //当前歌单名称
+  @Provide  currentSongListID:string='' //当前歌单ID
   @State isDarkMode: boolean = false
   @State isDarkMode: boolean = false
   /** 列表滚动器,用于抽屉菜单列表滚动 */
   /** 列表滚动器,用于抽屉菜单列表滚动 */
   private scroller: Scroller = new Scroller();
   private scroller: Scroller = new Scroller();
@@ -78,8 +84,6 @@ struct NewIndex {
   @Provide('isZero') isZero: boolean = false;
   @Provide('isZero') isZero: boolean = false;
   /** 是否显示赞助入口 */
   /** 是否显示赞助入口 */
   @State isShowSponsorship: boolean = false
   @State isShowSponsorship: boolean = false
-  /** 页面上下文 */
-  context = this.getUIContext().getHostContext() as common.UIAbilityContext
   /** 音乐是否为零状态(预留) */
   /** 音乐是否为零状态(预留) */
   @Provide('isMusicZero') isMusicZero: boolean = false;
   @Provide('isMusicZero') isMusicZero: boolean = false;
   @State isShowTitleBar: boolean = true //是否显示分类导航条
   @State isShowTitleBar: boolean = true //是否显示分类导航条
@@ -405,23 +409,6 @@ struct NewIndex {
   isHiCar() {
   isHiCar() {
 
 
     return this.isHiCarStatus&&this.curDisplayIsHiCar;
     return this.isHiCarStatus&&this.curDisplayIsHiCar;
-    // const hiCarAspectRatios: HiCarAspectRatio[] = [
-    //   { ratio: 800 / 480, name: "800x480" },
-    //   { ratio: 762 / 752, name: "762x752" },
-    //   { ratio: 968 / 1280, name: "968x1280" },
-    //   { ratio: 1200 / 1200, name: "1200x1200" },
-    //   { ratio: 1280 / 720, name: "1280x720" },
-    //   { ratio: 1920 / 1080, name: "1920x1080" }
-    // ];
-    // const currentRatio: number = this.windowWidth / this.windowHeight;
-    // const RATIO_TOLERANCE: number = 0.1; // 宽高比容差
-    //
-    // for (const hiCarRatio of hiCarAspectRatios) {
-    //   if (Math.abs(currentRatio - hiCarRatio.ratio) <= RATIO_TOLERANCE) {
-    //     LogUtil.info(`HiCar detected: ${hiCarRatio.name}, actual: ${this.windowWidth}x${this.windowHeight}`);
-    //     return true;
-    //   }
-    // }
 
 
     return false;
     return false;
   }
   }
@@ -1094,16 +1081,91 @@ struct NewIndex {
         }
         }
         .backgroundColor(Color.Transparent)
         .backgroundColor(Color.Transparent)
         .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
         .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
-        .onClick(() => {
-          this.openPlaylist(playlist)
+        .onClick(async () => {
+          if (!this.playlistTable) {
+            ToastUtil.showToast('歌单功能初始化中,请稍后再试')
+            return
+          }
+          // 加载歌单歌曲
+          const playlistSongs = await this.playlistTable.queryPlaylistSongs(playlist.id)
+          this.currentSongList = await convertPlaylistSongsToVideoItems(this.context,playlistSongs)
+          this.currentSongListName= playlist.name
+          this.currentSongListID = playlist.id
+          this.modeType = 4//切换到歌单模式
+          this.doShowDrawer()
         })
         })
-        .gesture(LongPressGesture().onAction(() => {
-          this.showPlaylistMenu(playlist)
-        }))
+        .bindContextMenu(this.MenuBuilder(playlist), ResponseType.LongPress,
+          {
+            preview: MenuPreviewMode.IMAGE,
+            previewAnimationOptions: { scale: [0.8, 1.0] },
+          })
+        .bindContextMenu(this.MenuBuilder(playlist), ResponseType.RightClick,
+          {
+            preview: MenuPreviewMode.IMAGE,
+            previewAnimationOptions: { scale: [0.8, 1.0] },
+          })
       }
       }
     })
     })
   }
   }
 
 
+  @Builder
+  MenuBuilder(playlist: Playlist) {
+    Menu(){
+      MenuItem({
+        symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.square_and_pencil')),
+        content: '编辑歌单'
+      })
+        .onClick(async() => {
+          this.openPlaylist(playlist)
+
+        })
+
+      MenuItem({
+        symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.trash')),
+        content: '删除歌单'
+      })
+        .onClick(async() => {
+          this.deletePlaylist(playlist)
+
+        })
+    }
+
+  }
+
+  /**
+   * 删除歌单
+   */
+  async deletePlaylist(playlist: Playlist) {
+    if (playlist&&this.playlistTable) {
+      // 显示确认对话框
+      AlertDialog.show({
+        title: '删除歌单',
+        message: `确定要删除歌单"${playlist.name}"吗?此操作不可撤销。`,
+        primaryButton: {
+          value: '取消',
+          action: () => {}
+        },
+        secondaryButton: {
+          value: '删除',
+          fontColor: Color.Red,
+          action: async () => {
+            if (this.playlistTable) {
+              const success = await this.playlistTable.deletePlaylist(playlist.id)
+              if (success) {
+                ToastUtil.showToast('歌单删除成功')
+                // 发送刷新事件
+                emitter.emit({ eventId: EventConstants.EVENT_PLAYLIST_REFRESH }, {})
+              } else {
+                ToastUtil.showToast('歌单删除失败')
+              }
+            }
+
+          }
+        }
+      })
+    }
+  }
+
   /**
   /**
    * 显示创建歌单对话框
    * 显示创建歌单对话框
    */
    */
@@ -1157,13 +1219,6 @@ struct NewIndex {
     }
     }
   }
   }
 
 
-  /**
-   * 显示歌单菜单
-   */
-  showPlaylistMenu(playlist: Playlist) {
-    // TODO: 显示歌单操作菜单(重命名、删除等)
-    console.info('显示歌单菜单:', playlist.name)
-  }
 
 
   /**
   /**
    * 初始化歌单数据库
    * 初始化歌单数据库

+ 62 - 51
entry/src/main/ets/pages/PlaylistDetailPage.ets

@@ -10,6 +10,7 @@ import { router } from '@kit.ArkUI';
 import { GlobalContext } from '../common/util/GlobalContext';
 import { GlobalContext } from '../common/util/GlobalContext';
 import { CommonConstants } from '../common/constants/CommonConstants';
 import { CommonConstants } from '../common/constants/CommonConstants';
 import { EventConstants } from '../common/constants/EventConstants';
 import { EventConstants } from '../common/constants/EventConstants';
+import { common } from '@kit.AbilityKit';
 
 
 /**
 /**
  * 歌单播放事件数据
  * 歌单播放事件数据
@@ -29,6 +30,7 @@ interface PlaylistEventData {
 @Entry
 @Entry
 @Component
 @Component
 export struct PlaylistDetailPage {
 export struct PlaylistDetailPage {
+  context = this.getUIContext().getHostContext() as common.UIAbilityContext
   @State playlist: Playlist | null = null
   @State playlist: Playlist | null = null
   @State songList: VideoItem[] = []
   @State songList: VideoItem[] = []
   @State isLoading: boolean = true
   @State isLoading: boolean = true
@@ -83,7 +85,7 @@ export struct PlaylistDetailPage {
       const playlistSongs = await this.playlistTable.queryPlaylistSongs(this.playlistId)
       const playlistSongs = await this.playlistTable.queryPlaylistSongs(this.playlistId)
 
 
       // 将 PlaylistSong 转换为 VideoItem
       // 将 PlaylistSong 转换为 VideoItem
-      this.songList = await this.convertPlaylistSongsToVideoItems(playlistSongs)
+      this.songList = await convertPlaylistSongsToVideoItems(this.context,playlistSongs)
 
 
       // 歌单加载完成后,加载当前播放状态
       // 歌单加载完成后,加载当前播放状态
       this.loadCurrentPlaybackStatus()
       this.loadCurrentPlaybackStatus()
@@ -239,57 +241,7 @@ export struct PlaylistDetailPage {
     }
     }
   }
   }
 
 
-  /**
-   * 将 PlaylistSong 转换为 VideoItem
-   */
-  async convertPlaylistSongsToVideoItems(playlistSongs: PlaylistSong[]): Promise<VideoItem[]> {
-    const videoItems: VideoItem[] = []
-
-    LogUtil.info(`heanup 开始转换歌曲,共 ${playlistSongs.length} 首`)
-
-    for (const playlistSong of playlistSongs) {
-      try {
-        LogUtil.info(`heanup 查询歌曲: ${playlistSong.songFilePath}`)
-
-        // 从数据库查询完整的歌曲信息
-        const videoItem = await this.mediaTable.queryVideoByFilePath(playlistSong.songFilePath)
-
-        if (videoItem) {
-          LogUtil.info(`heanup 找到歌曲: ${videoItem.name}`)
-          videoItems.push(videoItem)
-        } else {
-          LogUtil.warn(`heanup 数据库中未找到歌曲: ${playlistSong.songFilePath}`)
-
-          // 如果数据库中没有,创建一个基本的 VideoItem
-          const fileName = playlistSong.songFilePath.split('/').pop() || ''
-          const name = fileName.replace(/\.[^/.]+$/, "") // 移除文件扩展名
-
-          const basicVideoItem = new VideoItem(
-            name, // name
-            Date.now().toString() + Math.random(), // id
-            playlistSong.songFilePath, // filePath
-            0, // type (音乐类型)
-            0, // videoSize
-            playlistSong.addTime, // cTime
-            undefined, // pixelMap
-            undefined, // size
-            undefined, // pixelMapPath
-            undefined, // artist
-            undefined, // album
-            fileName, // fileName
-            undefined // lastPlayed
-          )
-
-          videoItems.push(basicVideoItem)
-        }
-      } catch (error) {
-        LogUtil.error('heanup 转换歌曲失败: ' + error)
-      }
-    }
 
 
-    LogUtil.info(`heanup 转换完成,共 ${videoItems.length} 首歌曲`)
-    return videoItems
-  }
 
 
   /**
   /**
    * 播放歌单
    * 播放歌单
@@ -1102,6 +1054,7 @@ export struct PlaylistDetailPage {
             .transition(TransitionEffect.scale({ x: 0.95, y: 0.95 }).animation({ duration: 800, curve: Curve.EaseOut, delay: 200 }))
             .transition(TransitionEffect.scale({ x: 0.95, y: 0.95 }).animation({ duration: 800, curve: Curve.EaseOut, delay: 200 }))
           }
           }
           .layoutWeight(1)
           .layoutWeight(1)
+          .margin({ left: 16, right: 16 })
           .justifyContent(FlexAlign.Center)
           .justifyContent(FlexAlign.Center)
           .padding({ top: 20, bottom: 20 })
           .padding({ top: 20, bottom: 20 })
         }
         }
@@ -1247,3 +1200,61 @@ export struct PlaylistDetailPage {
     }
     }
   }
   }
 }
 }
+
+/**
+ * 将 PlaylistSong 转换为 VideoItem
+ */
+export async function convertPlaylistSongsToVideoItems(context: Context,playlistSongs: PlaylistSong[]): Promise<VideoItem[]> {
+  const videoItems: VideoItem[] = []
+
+  LogUtil.info(`heanup 开始转换歌曲,共 ${playlistSongs.length} 首`)
+
+  const mediaTable: MediaTable = new MediaTable(context)
+  await new Promise<void>((resolve, reject) => {
+    mediaTable.getRdbStore(context,  (err:Error) => {
+      err ? reject(err) : resolve();
+    });
+  });
+  for (const playlistSong of playlistSongs) {
+    try {
+      LogUtil.info(`heanup 查询歌曲: ${playlistSong.songFilePath}`)
+
+      // 从数据库查询完整的歌曲信息
+      const videoItem = await mediaTable.queryVideoByFilePath(playlistSong.songFilePath)
+
+      if (videoItem) {
+        LogUtil.info(`heanup 找到歌曲: ${videoItem.name}`)
+        videoItems.push(videoItem)
+      } else {
+        LogUtil.warn(`heanup 数据库中未找到歌曲: ${playlistSong.songFilePath}`)
+
+        // 如果数据库中没有,创建一个基本的 VideoItem
+        const fileName = playlistSong.songFilePath.split('/').pop() || ''
+        const name = fileName.replace(/\.[^/.]+$/, "") // 移除文件扩展名
+
+        const basicVideoItem = new VideoItem(
+          name, // name
+          Date.now().toString() + Math.random(), // id
+          playlistSong.songFilePath, // filePath
+          0, // type (音乐类型)
+          0, // videoSize
+          playlistSong.addTime, // cTime
+          undefined, // pixelMap
+          undefined, // size
+          undefined, // pixelMapPath
+          undefined, // artist
+          undefined, // album
+          fileName, // fileName
+          undefined // lastPlayed
+        )
+
+        videoItems.push(basicVideoItem)
+      }
+    } catch (error) {
+      LogUtil.error('heanup 转换歌曲失败: ' + error)
+    }
+  }
+
+  LogUtil.info(`heanup 转换完成,共 ${videoItems.length} 首歌曲`)
+  return videoItems
+}

+ 30 - 4
entry/src/main/ets/view/LocalMusic.ets

@@ -162,6 +162,9 @@ const ITEM_HEIGHT_BIG: number = 78; // 列表项大高度
 @Preview
 @Preview
 @Component
 @Component
 export struct LocalMusic {
 export struct LocalMusic {
+  @Consume currentSongList: Array<VideoItem>//当前歌单
+  @Consume currentSongListName:string //当前歌单名称
+  @Consume @Watch('onIDChange') currentSongListID:string //当前歌单ID
   @State mediaKuCount: number = 0;
   @State mediaKuCount: number = 0;
   @State albumCount: number = 0;
   @State albumCount: number = 0;
   @State artistCount: number = 0;
   @State artistCount: number = 0;
@@ -292,6 +295,17 @@ export struct LocalMusic {
     }
     }
   }
   }
 
 
+  //歌单id发生变化的时候回调
+  onIDChange(){
+    if(this.modeType==4){
+      this.titleBarModel.setLeftIconMainNoAnimate($r('app.media.menu'))
+      this.updateListData(this.currentSongList, true)
+      this.titleBarModel.setTitleName(this.currentSongListName)
+      this.isShowTitleBar = false
+    }
+
+  }
+
   onModeChange() {
   onModeChange() {
     this.isFavMusic = false
     this.isFavMusic = false
     if (this.modeType === 2 || this.modeType === 3) {
     if (this.modeType === 2 || this.modeType === 3) {
@@ -320,6 +334,12 @@ export struct LocalMusic {
         this.updateListData(this.albumList)
         this.updateListData(this.albumList)
         this.titleBarModel.setTitleName(Utility.resourceToString(this.context, $r('app.string.album')))
         this.titleBarModel.setTitleName(Utility.resourceToString(this.context, $r('app.string.album')))
         break
         break
+      case 4://歌单
+        this.titleBarModel.setLeftIconMainNoAnimate($r('app.media.menu'))
+        this.updateListData(this.currentSongList, true)
+        this.titleBarModel.setTitleName(this.currentSongListName)
+        this.isShowTitleBar = false
+        break
     }
     }
   }
   }
 
 
@@ -917,8 +937,12 @@ export struct LocalMusic {
           } else {
           } else {
             PreferencesUtil.putSync('artistList',  JSON.stringify(this.artistList));
             PreferencesUtil.putSync('artistList',  JSON.stringify(this.artistList));
           }
           }
-          const mapArray = Array.from(this.artistMap.entries());
-          PreferencesUtil.putSync('artistMap',  JSON.stringify(mapArray));
+          // 处理并缓存前60条艺术家数据
+          const sortedEntries = Array.from(this.artistMap.entries())
+            .sort((a, b) => b[1].length - a[1].length)
+            .slice(0, 60);
+
+          PreferencesUtil.putSync('artistMap',  JSON.stringify(sortedEntries));
           break;
           break;
 
 
         case 104: //收到查询专辑列表
         case 104: //收到查询专辑列表
@@ -940,7 +964,9 @@ export struct LocalMusic {
           } else {
           } else {
             PreferencesUtil.putSync('albumList',  JSON.stringify(this.albumList));
             PreferencesUtil.putSync('albumList',  JSON.stringify(this.albumList));
           }
           }
-          const mapArrayAlbum = Array.from(this.albumMap.entries());
+          const mapArrayAlbum = Array.from(this.albumMap.entries())
+            .sort((a, b) => b[1].length - a[1].length)
+            .slice(0, 60);
           PreferencesUtil.putSync('albumMap',  JSON.stringify(mapArrayAlbum));
           PreferencesUtil.putSync('albumMap',  JSON.stringify(mapArrayAlbum));
           break;
           break;
 
 
@@ -1361,7 +1387,7 @@ export struct LocalMusic {
           this.titleBarModel.setTitleName(Utility.resourceToString(this.context, $r('app.string.album')))
           this.titleBarModel.setTitleName(Utility.resourceToString(this.context, $r('app.string.album')))
           break
           break
         case 4: //同步数据
         case 4: //同步数据
-          this.asyncCurrentPathData()
+          // this.asyncCurrentPathData()
           break
           break
       }
       }