|
@@ -13,6 +13,20 @@ import { EventConstants } from '../common/constants/EventConstants';
|
|
|
import { common } from '@kit.AbilityKit';
|
|
import { common } from '@kit.AbilityKit';
|
|
|
import { ImagePickerUtil } from '../common/util/ImagePickerUtil';
|
|
import { ImagePickerUtil } from '../common/util/ImagePickerUtil';
|
|
|
import { LazyDataSource } from '../common/util/LazyDataSource';
|
|
import { LazyDataSource } from '../common/util/LazyDataSource';
|
|
|
|
|
+import { ConfigurationConstant } from '@kit.AbilityKit';
|
|
|
|
|
+
|
|
|
|
|
+// 工具函数:将 #RRGGBB 字符串和透明度转为 'rgba(r,g,b,a)' 字符串,深色模式下可返回深色变体
|
|
|
|
|
+function themeColorWithAlpha(themeColor: string, alpha: number, isDarkMode: boolean = false): string {
|
|
|
|
|
+ if (isDarkMode) {
|
|
|
|
|
+ // 深色模式下返回更深的灰色或半透明黑色
|
|
|
|
|
+ return `rgba(34,34,34,${alpha + 0.2 > 1 ? 1 : alpha + 0.2})`;
|
|
|
|
|
+ }
|
|
|
|
|
+ const color = themeColor.replace('#', '');
|
|
|
|
|
+ const r = parseInt(color.substring(0, 2), 16);
|
|
|
|
|
+ const g = parseInt(color.substring(2, 4), 16);
|
|
|
|
|
+ const b = parseInt(color.substring(4, 6), 16);
|
|
|
|
|
+ return `rgba(${r},${g},${b},${alpha})`;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 歌单播放事件数据
|
|
* 歌单播放事件数据
|
|
@@ -49,6 +63,13 @@ export struct PlaylistDetailPage {
|
|
|
private mediaTable: MediaTable = new MediaTable(getContext(this))
|
|
private mediaTable: MediaTable = new MediaTable(getContext(this))
|
|
|
private playlistId: string = ''
|
|
private playlistId: string = ''
|
|
|
@StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
|
|
@StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
|
|
|
|
|
+ @State isDarkMode: boolean = false
|
|
|
|
|
+ @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
|
|
|
|
|
+ ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
|
|
|
|
|
+
|
|
|
|
|
+ onColorModeChange() {
|
|
|
|
|
+ this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
//长按拖动
|
|
//长按拖动
|
|
|
@State dragItem: number = -1
|
|
@State dragItem: number = -1
|
|
@@ -448,9 +469,9 @@ export struct PlaylistDetailPage {
|
|
|
Column() {
|
|
Column() {
|
|
|
Blank()
|
|
Blank()
|
|
|
.height(this.topRectHeight+5)
|
|
.height(this.topRectHeight+5)
|
|
|
- .backgroundColor($r('app.color.title_bar_bg'))
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? $r('app.color.title_bar_bg') : this.themeColor)
|
|
|
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
|
|
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 标题栏
|
|
// 标题栏
|
|
|
Row() {
|
|
Row() {
|
|
|
Image($r('app.media.back'))
|
|
Image($r('app.media.back'))
|
|
@@ -489,7 +510,7 @@ export struct PlaylistDetailPage {
|
|
|
.height(48)
|
|
.height(48)
|
|
|
.width('100%')
|
|
.width('100%')
|
|
|
.alignItems(VerticalAlign.Center)
|
|
.alignItems(VerticalAlign.Center)
|
|
|
- .backgroundColor($r('app.color.title_bar_bg'))
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? $r('app.color.title_bar_bg') : this.themeColor)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (this.isLoading) {
|
|
if (this.isLoading) {
|
|
@@ -600,11 +621,11 @@ export struct PlaylistDetailPage {
|
|
|
}
|
|
}
|
|
|
.layoutWeight(1)
|
|
.layoutWeight(1)
|
|
|
.height(44)
|
|
.height(44)
|
|
|
- .backgroundColor(this.themeColor )
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
|
|
|
.borderRadius(22)
|
|
.borderRadius(22)
|
|
|
.shadow({
|
|
.shadow({
|
|
|
radius: 8,
|
|
radius: 8,
|
|
|
- color: '#0a59f740',
|
|
|
|
|
|
|
+ color: themeColorWithAlpha(this.themeColor, 0.25, this.isDarkMode),
|
|
|
offsetX: 0,
|
|
offsetX: 0,
|
|
|
offsetY: 4
|
|
offsetY: 4
|
|
|
})
|
|
})
|
|
@@ -613,11 +634,11 @@ export struct PlaylistDetailPage {
|
|
|
})
|
|
})
|
|
|
.stateStyles({
|
|
.stateStyles({
|
|
|
normal: {
|
|
normal: {
|
|
|
- .backgroundColor(this.themeColor )
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
|
|
|
.scale({ x: 1, y: 1 })
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
},
|
|
|
pressed: {
|
|
pressed: {
|
|
|
- .backgroundColor('#0a59f7cc')
|
|
|
|
|
|
|
+ .backgroundColor(themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode))
|
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -631,11 +652,11 @@ export struct PlaylistDetailPage {
|
|
|
Row({ space: 6 }) {
|
|
Row({ space: 6 }) {
|
|
|
Text('✏️')
|
|
Text('✏️')
|
|
|
.fontSize(16)
|
|
.fontSize(16)
|
|
|
- .fontColor(this.themeColor )
|
|
|
|
|
|
|
+ .fontColor(this.isDarkMode ? Color.White : this.themeColor)
|
|
|
|
|
|
|
|
Text('编辑')
|
|
Text('编辑')
|
|
|
.fontSize(14)
|
|
.fontSize(14)
|
|
|
- .fontColor(this.themeColor )
|
|
|
|
|
|
|
+ .fontColor(this.isDarkMode ? Color.White : this.themeColor)
|
|
|
.fontWeight(FontWeight.Medium)
|
|
.fontWeight(FontWeight.Medium)
|
|
|
}
|
|
}
|
|
|
.justifyContent(FlexAlign.Center)
|
|
.justifyContent(FlexAlign.Center)
|
|
@@ -646,7 +667,7 @@ export struct PlaylistDetailPage {
|
|
|
.borderRadius(22)
|
|
.borderRadius(22)
|
|
|
.border({
|
|
.border({
|
|
|
width: 1.5,
|
|
width: 1.5,
|
|
|
- color: this.themeColor
|
|
|
|
|
|
|
+ color: this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.6, this.isDarkMode) : this.themeColor
|
|
|
})
|
|
})
|
|
|
.onClick(() => {
|
|
.onClick(() => {
|
|
|
this.editPlaylist()
|
|
this.editPlaylist()
|
|
@@ -657,7 +678,7 @@ export struct PlaylistDetailPage {
|
|
|
.scale({ x: 1, y: 1 })
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
},
|
|
|
pressed: {
|
|
pressed: {
|
|
|
- .backgroundColor('#0a59f715')
|
|
|
|
|
|
|
+ .backgroundColor(themeColorWithAlpha(this.themeColor, 0.08, this.isDarkMode))
|
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -757,7 +778,7 @@ export struct PlaylistDetailPage {
|
|
|
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
|
|
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
|
|
|
}
|
|
}
|
|
|
.height(36)
|
|
.height(36)
|
|
|
- .backgroundColor(this.themeColor)
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
|
|
|
.borderRadius(18)
|
|
.borderRadius(18)
|
|
|
.margin({ left: 12 })
|
|
.margin({ left: 12 })
|
|
|
.onClick(() => {
|
|
.onClick(() => {
|
|
@@ -765,11 +786,11 @@ export struct PlaylistDetailPage {
|
|
|
})
|
|
})
|
|
|
.stateStyles({
|
|
.stateStyles({
|
|
|
normal: {
|
|
normal: {
|
|
|
- .backgroundColor(this.themeColor)
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
|
|
|
.scale({ x: 1, y: 1 })
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
},
|
|
|
pressed: {
|
|
pressed: {
|
|
|
- .backgroundColor('#0a59f7cc')
|
|
|
|
|
|
|
+ .backgroundColor(themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode))
|
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -801,6 +822,7 @@ export struct PlaylistDetailPage {
|
|
|
.interpolation(ImageInterpolation.High)
|
|
.interpolation(ImageInterpolation.High)
|
|
|
.autoResize(true)
|
|
.autoResize(true)
|
|
|
.margin({ left: 20 })
|
|
.margin({ left: 20 })
|
|
|
|
|
+ .fillColor(song.pixelMapPath ? undefined : (this.isDarkMode ? Color.White : this.themeColor))
|
|
|
.onClick(() => {
|
|
.onClick(() => {
|
|
|
this.playSong(song, index)
|
|
this.playSong(song, index)
|
|
|
})
|
|
})
|
|
@@ -869,7 +891,8 @@ export struct PlaylistDetailPage {
|
|
|
// 上移按钮
|
|
// 上移按钮
|
|
|
Text('▲')
|
|
Text('▲')
|
|
|
.fontSize(16)
|
|
.fontSize(16)
|
|
|
- .fontColor(index === 0 ? '#cccccc' : this.themeColor)
|
|
|
|
|
|
|
+ .fontColor(index === 0 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
+ (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
.onClick(() => {
|
|
.onClick(() => {
|
|
|
if (index > 0) {
|
|
if (index > 0) {
|
|
|
this.moveSong(index, index - 1)
|
|
this.moveSong(index, index - 1)
|
|
@@ -880,7 +903,8 @@ export struct PlaylistDetailPage {
|
|
|
// 下移按钮
|
|
// 下移按钮
|
|
|
Text('▼')
|
|
Text('▼')
|
|
|
.fontSize(16)
|
|
.fontSize(16)
|
|
|
- .fontColor(index === this.songList.length - 1 ? '#cccccc' : this.themeColor)
|
|
|
|
|
|
|
+ .fontColor(index === this.songList.length - 1 ? (this.isDarkMode ? '#666666' : '#cccccc') :
|
|
|
|
|
+ (this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.9, false) : this.themeColor))
|
|
|
.onClick(() => {
|
|
.onClick(() => {
|
|
|
if (index < this.songList.length - 1) {
|
|
if (index < this.songList.length - 1) {
|
|
|
this.moveSong(index, index + 1)
|
|
this.moveSong(index, index + 1)
|
|
@@ -920,14 +944,14 @@ export struct PlaylistDetailPage {
|
|
|
.backgroundColor(Color.Transparent)
|
|
.backgroundColor(Color.Transparent)
|
|
|
},
|
|
},
|
|
|
pressed: {
|
|
pressed: {
|
|
|
- .backgroundColor(this.isSortMode ? Color.Transparent : '#f1f3f5')
|
|
|
|
|
|
|
+ .backgroundColor(this.isSortMode ? Color.Transparent : themeColorWithAlpha(this.themeColor, 0.05, this.isDarkMode))
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
// 当前播放歌曲的背景高亮
|
|
// 当前播放歌曲的背景高亮
|
|
|
- .backgroundColor(this.isPlaying && this.curIndex === index ? '#f0f8ff' : Color.Transparent)
|
|
|
|
|
|
|
+ .backgroundColor(this.isPlaying && this.curIndex === index ? themeColorWithAlpha(this.themeColor, 0.08, this.isDarkMode) : Color.Transparent)
|
|
|
.border({
|
|
.border({
|
|
|
width: { left: this.isPlaying && this.curIndex === index ? 3 : 0 },
|
|
width: { left: this.isPlaying && this.curIndex === index ? 3 : 0 },
|
|
|
- color: this.themeColor
|
|
|
|
|
|
|
+ color: this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor
|
|
|
})
|
|
})
|
|
|
.opacity(this.pageOpacity)
|
|
.opacity(this.pageOpacity)
|
|
|
.translate({ x: 0, y: this.showContent ? 0 : 20 })
|
|
.translate({ x: 0, y: this.showContent ? 0 : 20 })
|
|
@@ -1055,7 +1079,7 @@ export struct PlaylistDetailPage {
|
|
|
// 空状态容器
|
|
// 空状态容器
|
|
|
Column() {
|
|
Column() {
|
|
|
// 空状态图标容器
|
|
// 空状态图标容器
|
|
|
- emptyView(this.themeColor)
|
|
|
|
|
|
|
+ emptyView(this.themeColor, this.isDarkMode)
|
|
|
|
|
|
|
|
// 添加歌曲按钮
|
|
// 添加歌曲按钮
|
|
|
Button() {
|
|
Button() {
|
|
@@ -1074,11 +1098,11 @@ export struct PlaylistDetailPage {
|
|
|
}
|
|
}
|
|
|
.width(160)
|
|
.width(160)
|
|
|
.height(48)
|
|
.height(48)
|
|
|
- .backgroundColor(this.themeColor )
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
|
|
|
.borderRadius(24)
|
|
.borderRadius(24)
|
|
|
.shadow({
|
|
.shadow({
|
|
|
radius: 12,
|
|
radius: 12,
|
|
|
- color: '#0a59f74d',
|
|
|
|
|
|
|
+ color: themeColorWithAlpha(this.themeColor, 0.3, this.isDarkMode),
|
|
|
offsetX: 0,
|
|
offsetX: 0,
|
|
|
offsetY: 6
|
|
offsetY: 6
|
|
|
})
|
|
})
|
|
@@ -1088,7 +1112,7 @@ export struct PlaylistDetailPage {
|
|
|
async (songs: VideoItem[]) => {
|
|
async (songs: VideoItem[]) => {
|
|
|
// 添加选中的歌曲到歌单
|
|
// 添加选中的歌曲到歌单
|
|
|
const success = await this.playlistTable.addSongsToPlaylist(this.playlistId, songs.map(song => song.filePath))
|
|
const success = await this.playlistTable.addSongsToPlaylist(this.playlistId, songs.map(song => song.filePath))
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (success) {
|
|
if (success) {
|
|
|
ToastUtil.showToast(`成功添加 ${songs.length} 首歌曲`)
|
|
ToastUtil.showToast(`成功添加 ${songs.length} 首歌曲`)
|
|
|
// 重新加载歌单详情
|
|
// 重新加载歌单详情
|
|
@@ -1101,11 +1125,11 @@ export struct PlaylistDetailPage {
|
|
|
})
|
|
})
|
|
|
.stateStyles({
|
|
.stateStyles({
|
|
|
normal: {
|
|
normal: {
|
|
|
- .backgroundColor(this.themeColor )
|
|
|
|
|
|
|
+ .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
|
|
|
.scale({ x: 1, y: 1 })
|
|
.scale({ x: 1, y: 1 })
|
|
|
},
|
|
},
|
|
|
pressed: {
|
|
pressed: {
|
|
|
- .backgroundColor('#0a59f7cc')
|
|
|
|
|
|
|
+ .backgroundColor(themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode))
|
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
.scale({ x: 0.96, y: 0.96 })
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -1363,63 +1387,41 @@ export async function convertPlaylistSongsToVideoItems(context: Context,playlist
|
|
|
LogUtil.info(`heanup 找到歌曲: ${videoItem.name}`)
|
|
LogUtil.info(`heanup 找到歌曲: ${videoItem.name}`)
|
|
|
videoItems.push(videoItem)
|
|
videoItems.push(videoItem)
|
|
|
} else {
|
|
} 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)
|
|
|
|
|
|
|
+ LogUtil.warn(`heanup 数据库中未找到歌曲,已被删除,不添加到歌单: ${playlistSong.songFilePath}`)
|
|
|
|
|
+ // 不再添加不存在的歌曲到列表中,只记录日志
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
LogUtil.error('heanup 转换歌曲失败: ' + error)
|
|
LogUtil.error('heanup 转换歌曲失败: ' + error)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- LogUtil.info(`heanup 转换完成,共 ${videoItems.length} 首歌曲`)
|
|
|
|
|
|
|
+ LogUtil.info(`heanup 转换完成,共 ${videoItems.length} 首歌曲(原始 ${playlistSongs.length} 首)`)
|
|
|
return videoItems
|
|
return videoItems
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
@Builder
|
|
@Builder
|
|
|
-export function emptyView(themeColor: ResourceColor) {
|
|
|
|
|
-
|
|
|
|
|
|
|
+export function emptyView(themeColor: string, isDarkMode: boolean = false) {
|
|
|
Column(){
|
|
Column(){
|
|
|
Stack() {
|
|
Stack() {
|
|
|
// 背景圆圈
|
|
// 背景圆圈
|
|
|
Circle({ width: 160, height: 160 })
|
|
Circle({ width: 160, height: 160 })
|
|
|
- .fill('#0a59f715')
|
|
|
|
|
|
|
+ .fill(themeColorWithAlpha(themeColor, 0.08, isDarkMode))
|
|
|
.border({
|
|
.border({
|
|
|
width: 2,
|
|
width: 2,
|
|
|
- color: '#0a59f71a'
|
|
|
|
|
|
|
+ color: themeColorWithAlpha(themeColor, 0.1, isDarkMode)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 中间圆圈
|
|
// 中间圆圈
|
|
|
Circle({ width: 120, height: 120 })
|
|
Circle({ width: 120, height: 120 })
|
|
|
- .fill('#0a59f722')
|
|
|
|
|
|
|
+ .fill(themeColorWithAlpha(themeColor, 0.13, isDarkMode))
|
|
|
|
|
|
|
|
// 音符图标
|
|
// 音符图标
|
|
|
Image($r('app.media.music_red'))
|
|
Image($r('app.media.music_red'))
|
|
|
.width(64)
|
|
.width(64)
|
|
|
.height(64)
|
|
.height(64)
|
|
|
.opacity(0.6)
|
|
.opacity(0.6)
|
|
|
- .fillColor(themeColor )
|
|
|
|
|
|
|
+ .fillColor(themeColor)
|
|
|
}
|
|
}
|
|
|
.margin({ bottom: 32 })
|
|
.margin({ bottom: 32 })
|
|
|
|
|
|