|
|
@@ -3,11 +3,12 @@ import { VideoItem } from '../viewmodel/VideoItem';
|
|
|
import PlaylistTable from '../common/util/PlaylistTable';
|
|
|
import MediaTable from '../common/util/MediaTable';
|
|
|
import { emitter } from '@kit.BasicServicesKit';
|
|
|
-import { ToastUtil, AppUtil, LogUtil } from '@pura/harmony-utils';
|
|
|
+import { ToastUtil, AppUtil, LogUtil, PreferencesUtil } from '@pura/harmony-utils';
|
|
|
import { showEditPlaylistDialog } from '../dialog/PlaylistDialog';
|
|
|
import { showAddSongsToPlaylistDialog } from '../dialog/AddSongsToPlaylistDialog';
|
|
|
import { router } from '@kit.ArkUI';
|
|
|
import { GlobalContext } from '../common/util/GlobalContext';
|
|
|
+import { CommonConstants } from '../common/constants/CommonConstants';
|
|
|
|
|
|
/**
|
|
|
* 简化的歌单播放事件数据
|
|
|
@@ -40,8 +41,12 @@ export struct PlaylistDetailPage {
|
|
|
private playlistTable: PlaylistTable = new PlaylistTable(getContext(this))
|
|
|
private mediaTable: MediaTable = new MediaTable(getContext(this))
|
|
|
private playlistId: string = ''
|
|
|
+ @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
|
|
|
|
|
|
aboutToAppear() {
|
|
|
+ let themeColor = PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
|
|
|
+ AppStorage.setOrCreate('themeColor', themeColor);
|
|
|
+ this.themeColor = themeColor
|
|
|
// 获取传入的歌单对象
|
|
|
const params = router.getParams() as Record<string, Object>
|
|
|
if (params && params['playlist']) {
|
|
|
@@ -155,14 +160,29 @@ export struct PlaylistDetailPage {
|
|
|
// 监听播放状态变化事件
|
|
|
const eventPlaybackStatus: emitter.InnerEvent = { eventId: 2003 }
|
|
|
emitter.on(eventPlaybackStatus, (eventData: emitter.EventData) => {
|
|
|
- LogUtil.info('heanup PlaylistDetailPage 收到播放状态变化事件')
|
|
|
+ LogUtil.info('heanup PlaylistDetailPage 收到播放状态变化事件:'+ JSON.stringify(eventData))
|
|
|
if (eventData.data) {
|
|
|
const data = eventData.data as Record<string, Object>
|
|
|
- this.isPlaying = data['isPlaying'] as boolean || false
|
|
|
- this.curIndex = data['curIndex'] as number || -1
|
|
|
+ const oldIsPlaying = this.isPlaying
|
|
|
+ const oldCurIndex = this.curIndex
|
|
|
+
|
|
|
+ // 添加调试日志
|
|
|
+
|
|
|
+ this.isPlaying = data['isPlaying'] as boolean
|
|
|
+ let newCurIndex = data['curIndex'] as number
|
|
|
+
|
|
|
+ LogUtil.info(`heanup 原始播放状态: isPlaying=${this.isPlaying}, curIndex=${newCurIndex}`)
|
|
|
+
|
|
|
+
|
|
|
+ this.curIndex = newCurIndex
|
|
|
|
|
|
- // 如果当前播放的是这个歌单的歌曲,高亮显示
|
|
|
- LogUtil.info(`heanup 播放状态更新: isPlaying=${this.isPlaying}, curIndex=${this.curIndex}`)
|
|
|
+ LogUtil.info(`heanup 播放状态更新: isPlaying=${oldIsPlaying}->${this.isPlaying}, curIndex=${oldCurIndex}->${this.curIndex}`)
|
|
|
+
|
|
|
+ // 检查当前播放的歌曲是否在当前歌单中
|
|
|
+ if (this.curIndex >= 0 && this.curIndex < this.songList.length) {
|
|
|
+ const currentSong = this.songList[this.curIndex]
|
|
|
+ LogUtil.info(`heanup 当前播放歌曲: ${currentSong.name}, 文件路径: ${currentSong.filePath}`)
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
} catch (error) {
|
|
|
@@ -412,15 +432,11 @@ export struct PlaylistDetailPage {
|
|
|
.fontWeight(FontWeight.Medium)
|
|
|
.layoutWeight(1)
|
|
|
.textAlign(TextAlign.Center)
|
|
|
-
|
|
|
- // 更多操作按钮
|
|
|
- Image($r('app.media.ic_more_vert_black_24dp'))
|
|
|
+
|
|
|
+ // 占位空间,保持标题居中
|
|
|
+ Blank()
|
|
|
.width(24)
|
|
|
- .height(24)
|
|
|
.margin({ right: 12 })
|
|
|
- .onClick(() => {
|
|
|
- this.showMoreMenu()
|
|
|
- })
|
|
|
}
|
|
|
.height(48)
|
|
|
.width('100%')
|
|
|
@@ -434,7 +450,7 @@ export struct PlaylistDetailPage {
|
|
|
LoadingProgress()
|
|
|
.width(40)
|
|
|
.height(40)
|
|
|
- .color($r('app.color.theme_color'))
|
|
|
+ .color(this.themeColor )
|
|
|
|
|
|
Text('加载中...')
|
|
|
.fontSize(14)
|
|
|
@@ -519,7 +535,7 @@ export struct PlaylistDetailPage {
|
|
|
.padding({ right: 24 })
|
|
|
|
|
|
// 操作按钮区域
|
|
|
- Row({ space: 16 }) {
|
|
|
+ Row({ space: 12 }) {
|
|
|
// 播放全部按钮 - 参考LocalMusic的按钮样式
|
|
|
Button() {
|
|
|
Row({ space: 8 }) {
|
|
|
@@ -535,9 +551,9 @@ export struct PlaylistDetailPage {
|
|
|
}
|
|
|
.justifyContent(FlexAlign.Center)
|
|
|
}
|
|
|
- .width(140)
|
|
|
+ .layoutWeight(1)
|
|
|
.height(44)
|
|
|
- .backgroundColor($r('app.color.theme_color'))
|
|
|
+ .backgroundColor(this.themeColor )
|
|
|
.borderRadius(22)
|
|
|
.shadow({
|
|
|
radius: 8,
|
|
|
@@ -550,7 +566,7 @@ export struct PlaylistDetailPage {
|
|
|
})
|
|
|
.stateStyles({
|
|
|
normal: {
|
|
|
- .backgroundColor($r('app.color.theme_color'))
|
|
|
+ .backgroundColor(this.themeColor )
|
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
|
pressed: {
|
|
|
@@ -568,22 +584,22 @@ export struct PlaylistDetailPage {
|
|
|
Row({ space: 6 }) {
|
|
|
Text('✏️')
|
|
|
.fontSize(16)
|
|
|
- .fontColor($r('app.color.theme_color'))
|
|
|
+ .fontColor(this.themeColor )
|
|
|
|
|
|
Text('编辑')
|
|
|
.fontSize(14)
|
|
|
- .fontColor($r('app.color.theme_color'))
|
|
|
+ .fontColor(this.themeColor )
|
|
|
.fontWeight(FontWeight.Medium)
|
|
|
}
|
|
|
.justifyContent(FlexAlign.Center)
|
|
|
}
|
|
|
- .width(100)
|
|
|
+ .layoutWeight(1)
|
|
|
.height(44)
|
|
|
.backgroundColor(Color.Transparent)
|
|
|
.borderRadius(22)
|
|
|
.border({
|
|
|
width: 1.5,
|
|
|
- color: $r('app.color.theme_color')
|
|
|
+ color: this.themeColor
|
|
|
})
|
|
|
.onClick(() => {
|
|
|
this.editPlaylist()
|
|
|
@@ -603,19 +619,26 @@ export struct PlaylistDetailPage {
|
|
|
curve: Curve.EaseInOut
|
|
|
})
|
|
|
|
|
|
- // 删除歌单按钮
|
|
|
+ // 删除按钮
|
|
|
Button() {
|
|
|
- Text('🗑️')
|
|
|
- .fontSize(16)
|
|
|
- .fontColor('#ff4757')
|
|
|
+ Row({ space: 6 }) {
|
|
|
+ Text('🗑️')
|
|
|
+ .fontSize(16)
|
|
|
+
|
|
|
+ Text('删除')
|
|
|
+ .fontSize(14)
|
|
|
+ .fontColor(Color.Red)
|
|
|
+ .fontWeight(FontWeight.Medium)
|
|
|
+ }
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
}
|
|
|
- .width(44)
|
|
|
+ .layoutWeight(1)
|
|
|
.height(44)
|
|
|
.backgroundColor(Color.Transparent)
|
|
|
.borderRadius(22)
|
|
|
.border({
|
|
|
width: 1.5,
|
|
|
- color: '#ff4757'
|
|
|
+ color: Color.Red
|
|
|
})
|
|
|
.onClick(() => {
|
|
|
this.deletePlaylist()
|
|
|
@@ -626,7 +649,7 @@ export struct PlaylistDetailPage {
|
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
|
pressed: {
|
|
|
- .backgroundColor('#ff475715')
|
|
|
+ .backgroundColor('#ff000015')
|
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
|
}
|
|
|
})
|
|
|
@@ -667,6 +690,43 @@ export struct PlaylistDetailPage {
|
|
|
.fontSize(14)
|
|
|
.fontColor($r('app.color.text_color'))
|
|
|
.opacity(0.6)
|
|
|
+
|
|
|
+ // 添加歌曲按钮
|
|
|
+ Button() {
|
|
|
+ Row({ space: 6 }) {
|
|
|
+ Text('+')
|
|
|
+ .fontSize(18)
|
|
|
+ .fontColor(Color.White)
|
|
|
+
|
|
|
+ Text('添加歌曲')
|
|
|
+ .fontSize(14)
|
|
|
+ .fontColor(Color.White)
|
|
|
+ .fontWeight(FontWeight.Medium)
|
|
|
+ }
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
+ .padding({ left: 16, right: 16, top: 8, bottom: 8 })
|
|
|
+ }
|
|
|
+ .height(36)
|
|
|
+ .backgroundColor(this.themeColor)
|
|
|
+ .borderRadius(18)
|
|
|
+ .margin({ left: 12 })
|
|
|
+ .onClick(() => {
|
|
|
+ this.addSongsToPlaylist()
|
|
|
+ })
|
|
|
+ .stateStyles({
|
|
|
+ normal: {
|
|
|
+ .backgroundColor(this.themeColor)
|
|
|
+ .scale({ x: 1, y: 1 })
|
|
|
+ },
|
|
|
+ pressed: {
|
|
|
+ .backgroundColor('#0a59f7cc')
|
|
|
+ .scale({ x: 0.96, y: 0.96 })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .animation({
|
|
|
+ duration: 150,
|
|
|
+ curve: Curve.EaseInOut
|
|
|
+ })
|
|
|
}
|
|
|
.width('100%')
|
|
|
.padding({ left: 24, right: 24, top: 16, bottom: 12 })
|
|
|
@@ -681,90 +741,74 @@ export struct PlaylistDetailPage {
|
|
|
ListItem() {
|
|
|
Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
Row() {
|
|
|
- // 音乐图标 - 圆形设计,参考LocalMusic
|
|
|
+ // 歌曲封面 - 改为圆形
|
|
|
Stack() {
|
|
|
- Image($r('app.media.music_red'))
|
|
|
- .width(40)
|
|
|
- .height(40)
|
|
|
- .fillColor(this.isPlaying && this.curIndex === index ? $r('app.color.theme_color') : $r('app.color.text_color'))
|
|
|
- .borderRadius('100%')
|
|
|
- .clip(true)
|
|
|
+ Image(song.pixelMapPath || $r('app.media.music_red'))
|
|
|
+ .width(48)
|
|
|
+ .height(48)
|
|
|
+ .borderRadius(24) // 改为圆形
|
|
|
+ .objectFit(ImageFit.Cover)
|
|
|
.interpolation(ImageInterpolation.High)
|
|
|
.autoResize(true)
|
|
|
- .margin({ left: 20 })
|
|
|
+ .margin({ left: 16 })
|
|
|
.onClick(() => {
|
|
|
this.playSong(song, index)
|
|
|
})
|
|
|
-
|
|
|
- // 播放中动画覆盖层
|
|
|
- if (this.isPlaying && this.curIndex === index) {
|
|
|
- Text('♪')
|
|
|
- .fontSize(16)
|
|
|
- .fontColor(Color.White)
|
|
|
- .position({ x: 0, y: 0 })
|
|
|
- .width(40)
|
|
|
- .height(40)
|
|
|
- .textAlign(TextAlign.Center)
|
|
|
- .animation({
|
|
|
- duration: 800,
|
|
|
- curve: Curve.EaseInOut,
|
|
|
- iterations: -1,
|
|
|
- playMode: PlayMode.Alternate
|
|
|
- })
|
|
|
- }
|
|
|
}
|
|
|
- .width(60)
|
|
|
+ .width(64)
|
|
|
|
|
|
// 歌曲信息 - 参考LocalMusic的布局
|
|
|
Column() {
|
|
|
- // 歌曲名称
|
|
|
- Text(song.name || song.fileName || '')
|
|
|
- .fontSize(16)
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? $r('app.color.theme_color') : $r('app.color.text_color'))
|
|
|
- .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Bold : FontWeight.Normal)
|
|
|
- .maxLines(1)
|
|
|
- .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
- .width('100%')
|
|
|
- .margin({ top: 8, left: 12 })
|
|
|
+ Row() {
|
|
|
+ // 歌曲名称
|
|
|
+ Text(song.name || song.fileName || '')
|
|
|
+ .fontSize(16)
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
+ .fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Bold : FontWeight.Normal)
|
|
|
+ .maxLines(1)
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
+ .layoutWeight(1)
|
|
|
+ .margin({ top: 8, left: 12 })
|
|
|
+
|
|
|
+ // 音质标签
|
|
|
+ if (song.md5Str) {
|
|
|
+ Text(song.md5Str?.includes('Lossless') ? '无损' : song.md5Str)
|
|
|
+ .fontSize(10)
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
+ .fontWeight(500)
|
|
|
+ .padding({ top: 2, right: 6, left: 6, bottom: 2 })
|
|
|
+ .borderRadius(4)
|
|
|
+ .margin({ top: 8, left: 8 })
|
|
|
+ .backgroundColor( '#FFC107')
|
|
|
+ .visibility(song.md5Str ? Visibility.Visible : Visibility.None)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
|
|
|
// 歌手和专辑信息 - 参考LocalMusic的第二行布局
|
|
|
Row() {
|
|
|
- if (song.artist) {
|
|
|
Text(song.artist)
|
|
|
.fontSize(13)
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? $r('app.color.theme_color') : $r('app.color.text_color'))
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ?this.themeColor : $r('app.color.text_color'))
|
|
|
.fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
.maxLines(1)
|
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
.layoutWeight(1)
|
|
|
.opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
- }
|
|
|
-
|
|
|
- if (song.artist && song.album) {
|
|
|
- Text('·')
|
|
|
- .fontSize(13)
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? $r('app.color.theme_color') : $r('app.color.text_color'))
|
|
|
- .opacity(this.isPlaying && this.curIndex === index ? 0.8 : 0.6)
|
|
|
- }
|
|
|
-
|
|
|
- if (song.album) {
|
|
|
Text(song.album)
|
|
|
.fontSize(13)
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? $r('app.color.theme_color') : $r('app.color.text_color'))
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
.fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
.maxLines(1)
|
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
.layoutWeight(1)
|
|
|
.opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.8)
|
|
|
- }
|
|
|
-
|
|
|
- Blank()
|
|
|
|
|
|
// 时长显示
|
|
|
if (song.duration && typeof song.duration === 'number' && song.duration > 0) {
|
|
|
Text(this.formatDuration(song.duration))
|
|
|
.fontSize(13)
|
|
|
- .fontColor(this.isPlaying && this.curIndex === index ? $r('app.color.theme_color') : $r('app.color.text_color'))
|
|
|
+ .fontColor(this.isPlaying && this.curIndex === index ? this.themeColor : $r('app.color.text_color'))
|
|
|
.fontWeight(this.isPlaying && this.curIndex === index ? FontWeight.Medium : FontWeight.Normal)
|
|
|
.opacity(this.isPlaying && this.curIndex === index ? 1.0 : 0.7)
|
|
|
.margin({ right: 20 })
|
|
|
@@ -778,6 +822,7 @@ export struct PlaylistDetailPage {
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
.justifyContent(FlexAlign.Center)
|
|
|
|
|
|
+
|
|
|
// 更多操作按钮
|
|
|
Text('⋯')
|
|
|
.fontSize(20)
|
|
|
@@ -817,7 +862,7 @@ export struct PlaylistDetailPage {
|
|
|
.backgroundColor(this.isPlaying && this.curIndex === index ? '#f0f8ff' : Color.Transparent)
|
|
|
.border({
|
|
|
width: { left: this.isPlaying && this.curIndex === index ? 3 : 0 },
|
|
|
- color: $r('app.color.theme_color')
|
|
|
+ color: this.themeColor
|
|
|
})
|
|
|
.opacity(this.pageOpacity)
|
|
|
.translate({ x: 0, y: this.showContent ? 0 : 20 })
|
|
|
@@ -873,7 +918,7 @@ export struct PlaylistDetailPage {
|
|
|
.width(64)
|
|
|
.height(64)
|
|
|
.opacity(0.6)
|
|
|
- .fillColor($r('app.color.theme_color'))
|
|
|
+ .fillColor(this.themeColor )
|
|
|
}
|
|
|
.margin({ bottom: 32 })
|
|
|
|
|
|
@@ -911,7 +956,7 @@ export struct PlaylistDetailPage {
|
|
|
}
|
|
|
.width(160)
|
|
|
.height(48)
|
|
|
- .backgroundColor($r('app.color.theme_color'))
|
|
|
+ .backgroundColor(this.themeColor )
|
|
|
.borderRadius(24)
|
|
|
.shadow({
|
|
|
radius: 12,
|
|
|
@@ -938,7 +983,7 @@ export struct PlaylistDetailPage {
|
|
|
})
|
|
|
.stateStyles({
|
|
|
normal: {
|
|
|
- .backgroundColor($r('app.color.theme_color'))
|
|
|
+ .backgroundColor(this.themeColor )
|
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
|
pressed: {
|
|
|
@@ -989,23 +1034,48 @@ export struct PlaylistDetailPage {
|
|
|
* 显示更多菜单
|
|
|
*/
|
|
|
showMoreMenu() {
|
|
|
+ // 简单直接的二选一,避免复杂的多级菜单
|
|
|
AlertDialog.show({
|
|
|
title: '歌单操作',
|
|
|
- message: '',
|
|
|
+ message: '🎵 添加歌曲:向歌单添加新音乐\n✏️ 编辑歌单:修改歌单信息\n\n点击"确定"添加歌曲,点击"取消"编辑歌单',
|
|
|
primaryButton: {
|
|
|
- value: '取消',
|
|
|
- action: () => {}
|
|
|
+ value: '取消 (编辑)',
|
|
|
+ action: () => {
|
|
|
+ this.editPlaylist()
|
|
|
+ }
|
|
|
},
|
|
|
secondaryButton: {
|
|
|
- value: '删除歌单',
|
|
|
- fontColor: Color.Red,
|
|
|
+ value: '确定 (添加)',
|
|
|
action: () => {
|
|
|
- this.deletePlaylist()
|
|
|
+ this.addSongsToPlaylist()
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 添加歌曲到歌单
|
|
|
+ */
|
|
|
+ addSongsToPlaylist() {
|
|
|
+ if (this.playlist) {
|
|
|
+ showAddSongsToPlaylistDialog(
|
|
|
+ this.playlist,
|
|
|
+ async (songs: VideoItem[]) => {
|
|
|
+ // 添加选中的歌曲到歌单
|
|
|
+ const success = await this.playlistTable.addSongsToPlaylist(this.playlistId, songs.map(song => song.filePath))
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ ToastUtil.showToast(`成功添加 ${songs.length} 首歌曲`)
|
|
|
+ // 重新加载歌单详情
|
|
|
+ this.loadPlaylistDetail()
|
|
|
+ } else {
|
|
|
+ ToastUtil.showToast('添加歌曲失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 显示歌曲菜单
|
|
|
*/
|