Explorar el Código

feat(ui): 实现深色模式下的主题颜色适配

chendeben hace 9 meses
padre
commit
011a984af4

+ 22 - 2
entry/src/main/ets/dialog/PlaylistDialog.ets

@@ -4,7 +4,20 @@ import { ToastUtil } from '@pura/harmony-utils';
 import { CommonConstants } from '../common/constants/CommonConstants';
 import { ImagePickerUtil } from '../common/util/ImagePickerUtil';
 import Logger from '../common/util/Logger';
-import { Context } from '@kit.AbilityKit';
+import { ConfigurationConstant, Context } 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})`;
+}
 
 /**
  * 歌单对话框内容组件
@@ -17,6 +30,13 @@ struct PlaylistDialogContent {
   @State isEditMode: boolean = false
   @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
   @State originalPlaylist: Playlist | null = null
+  @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
+  }
 
   // 回调函数
   onConfirm?: (name: string, description: string, coverPath?: string) => void
@@ -175,7 +195,7 @@ struct PlaylistDialogContent {
         Button(this.isEditMode ? '保存' : '创建',{ type: ButtonType.Capsule, stateEffect: true })
           .width('45%')
           .height(40)
-          .backgroundColor(this.themeColor)
+          .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
           .borderRadius(8)
           .fontSize(14)
           .fontColor(Color.White)

+ 57 - 55
entry/src/main/ets/pages/PlaylistDetailPage.ets

@@ -13,6 +13,20 @@ import { EventConstants } from '../common/constants/EventConstants';
 import { common } from '@kit.AbilityKit';
 import { ImagePickerUtil } from '../common/util/ImagePickerUtil';
 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 playlistId: string = ''
   @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
@@ -448,9 +469,9 @@ export struct PlaylistDetailPage {
       Column() {
         Blank()
           .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])
-        
+
         // 标题栏
         Row() {
           Image($r('app.media.back'))
@@ -489,7 +510,7 @@ export struct PlaylistDetailPage {
         .height(48)
         .width('100%')
         .alignItems(VerticalAlign.Center)
-        .backgroundColor($r('app.color.title_bar_bg'))
+        .backgroundColor(this.isDarkMode ? $r('app.color.title_bar_bg') : this.themeColor)
       }
 
       if (this.isLoading) {
@@ -600,11 +621,11 @@ export struct PlaylistDetailPage {
             }
             .layoutWeight(1)
             .height(44)
-            .backgroundColor(this.themeColor )
+            .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
             .borderRadius(22)
             .shadow({
               radius: 8,
-              color: '#0a59f740',
+              color: themeColorWithAlpha(this.themeColor, 0.25, this.isDarkMode),
               offsetX: 0,
               offsetY: 4
             })
@@ -613,11 +634,11 @@ export struct PlaylistDetailPage {
             })
             .stateStyles({
               normal: {
-                .backgroundColor(this.themeColor )
+                .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
                 .scale({ x: 1, y: 1 })
               },
               pressed: {
-                .backgroundColor('#0a59f7cc')
+                .backgroundColor(themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode))
                 .scale({ x: 0.96, y: 0.96 })
               }
             })
@@ -631,11 +652,11 @@ export struct PlaylistDetailPage {
               Row({ space: 6 }) {
                 Text('✏️')
                   .fontSize(16)
-                  .fontColor(this.themeColor )
+                  .fontColor(this.isDarkMode ? Color.White : this.themeColor)
 
                 Text('编辑')
                   .fontSize(14)
-                  .fontColor(this.themeColor )
+                  .fontColor(this.isDarkMode ? Color.White : this.themeColor)
                   .fontWeight(FontWeight.Medium)
               }
               .justifyContent(FlexAlign.Center)
@@ -646,7 +667,7 @@ export struct PlaylistDetailPage {
             .borderRadius(22)
             .border({
               width: 1.5,
-              color: this.themeColor
+              color: this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.6, this.isDarkMode) : this.themeColor
             })
             .onClick(() => {
               this.editPlaylist()
@@ -657,7 +678,7 @@ export struct PlaylistDetailPage {
                 .scale({ x: 1, y: 1 })
               },
               pressed: {
-                .backgroundColor('#0a59f715')
+                .backgroundColor(themeColorWithAlpha(this.themeColor, 0.08, this.isDarkMode))
                 .scale({ x: 0.96, y: 0.96 })
               }
             })
@@ -757,7 +778,7 @@ export struct PlaylistDetailPage {
               .padding({ left: 16, right: 16, top: 8, bottom: 8 })
             }
             .height(36)
-            .backgroundColor(this.themeColor)
+            .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
             .borderRadius(18)
             .margin({ left: 12 })
             .onClick(() => {
@@ -765,11 +786,11 @@ export struct PlaylistDetailPage {
             })
             .stateStyles({
               normal: {
-                .backgroundColor(this.themeColor)
+                .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
                 .scale({ x: 1, y: 1 })
               },
               pressed: {
-                .backgroundColor('#0a59f7cc')
+                .backgroundColor(themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode))
                 .scale({ x: 0.96, y: 0.96 })
               }
             })
@@ -801,6 +822,7 @@ export struct PlaylistDetailPage {
                         .interpolation(ImageInterpolation.High)
                         .autoResize(true)
                         .margin({ left: 20 })
+                        .fillColor(song.pixelMapPath ? undefined : (this.isDarkMode ? Color.White : this.themeColor))
                         .onClick(() => {
                           this.playSong(song, index)
                         })
@@ -869,7 +891,8 @@ export struct PlaylistDetailPage {
                         // 上移按钮
                         Text('▲')
                           .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(() => {
                             if (index > 0) {
                               this.moveSong(index, index - 1)
@@ -880,7 +903,8 @@ export struct PlaylistDetailPage {
                         // 下移按钮
                         Text('▼')
                           .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(() => {
                             if (index < this.songList.length - 1) {
                               this.moveSong(index, index + 1)
@@ -920,14 +944,14 @@ export struct PlaylistDetailPage {
                     .backgroundColor(Color.Transparent)
                   },
                   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({
                   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)
                 .translate({ x: 0, y: this.showContent ? 0 : 20 })
@@ -1055,7 +1079,7 @@ export struct PlaylistDetailPage {
             // 空状态容器
             Column() {
               // 空状态图标容器
-              emptyView(this.themeColor)
+              emptyView(this.themeColor, this.isDarkMode)
 
               // 添加歌曲按钮
               Button() {
@@ -1074,11 +1098,11 @@ export struct PlaylistDetailPage {
               }
               .width(160)
               .height(48)
-              .backgroundColor(this.themeColor )
+              .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
               .borderRadius(24)
               .shadow({
                 radius: 12,
-                color: '#0a59f74d',
+                color: themeColorWithAlpha(this.themeColor, 0.3, this.isDarkMode),
                 offsetX: 0,
                 offsetY: 6
               })
@@ -1088,7 +1112,7 @@ export struct PlaylistDetailPage {
                   async (songs: VideoItem[]) => {
                     // 添加选中的歌曲到歌单
                     const success = await this.playlistTable.addSongsToPlaylist(this.playlistId, songs.map(song => song.filePath))
-                    
+
                     if (success) {
                       ToastUtil.showToast(`成功添加 ${songs.length} 首歌曲`)
                       // 重新加载歌单详情
@@ -1101,11 +1125,11 @@ export struct PlaylistDetailPage {
               })
               .stateStyles({
                 normal: {
-                  .backgroundColor(this.themeColor )
+                  .backgroundColor(this.isDarkMode ? themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode) : this.themeColor)
                   .scale({ x: 1, y: 1 })
                 },
                 pressed: {
-                  .backgroundColor('#0a59f7cc')
+                  .backgroundColor(themeColorWithAlpha(this.themeColor, 0.8, this.isDarkMode))
                   .scale({ x: 0.96, y: 0.96 })
                 }
               })
@@ -1363,63 +1387,41 @@ export async function convertPlaylistSongsToVideoItems(context: Context,playlist
         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)
+        LogUtil.warn(`heanup 数据库中未找到歌曲,已被删除,不添加到歌单: ${playlistSong.songFilePath}`)
+        // 不再添加不存在的歌曲到列表中,只记录日志
       }
     } catch (error) {
       LogUtil.error('heanup 转换歌曲失败: ' + error)
     }
   }
 
-  LogUtil.info(`heanup 转换完成,共 ${videoItems.length} 首歌曲`)
+  LogUtil.info(`heanup 转换完成,共 ${videoItems.length} 首歌曲(原始 ${playlistSongs.length} 首)`)
   return videoItems
 }
 
 
 @Builder
-export function emptyView(themeColor: ResourceColor) {
-
+export function emptyView(themeColor: string, isDarkMode: boolean = false) {
   Column(){
     Stack() {
       // 背景圆圈
       Circle({ width: 160, height: 160 })
-        .fill('#0a59f715')
+        .fill(themeColorWithAlpha(themeColor, 0.08, isDarkMode))
         .border({
           width: 2,
-          color: '#0a59f71a'
+          color: themeColorWithAlpha(themeColor, 0.1, isDarkMode)
         })
 
       // 中间圆圈
       Circle({ width: 120, height: 120 })
-        .fill('#0a59f722')
+        .fill(themeColorWithAlpha(themeColor, 0.13, isDarkMode))
 
       // 音符图标
       Image($r('app.media.music_red'))
         .width(64)
         .height(64)
         .opacity(0.6)
-        .fillColor(themeColor )
+        .fillColor(themeColor)
     }
     .margin({ bottom: 32 })