Browse Source

播放页增加音乐频谱的开关 和 音乐频谱的类型切换

onecold 6 months ago
parent
commit
f9107d37ce

+ 80 - 25
entry/src/main/ets/view/LocalMusic.ets

@@ -348,6 +348,8 @@ export struct LocalMusic {
   @State showSimple: boolean = true//开启沉浸模式
   @State isPaging: boolean = true;//是否分页加载机制
   @State isCoverRectangle: boolean = true;
+  @State isShowSpectrum: boolean = false;
+  @State spectrumModeIndex: number = 0; // 频谱特效类型索引
   @State showZMIndex: boolean = false //是否右侧显示字母索引
   private prevOffsetY: number = 0; // 记录上一次的Y轴偏移量
   @State autoHideTitle: boolean = true //滚动自动隐藏标题栏
@@ -1206,6 +1208,9 @@ export struct LocalMusic {
     context.getApplicationContext().setColorMode(colorMode)
   }
   initSetting() {
+    this.isShowSpectrum  = PreferencesUtil.getBooleanSync('isShowSpectrum', false)
+    this.spectrumModeIndex = PreferencesUtil.getNumberSync('spectrumModeIndex', 0)
+    AppStorage.setOrCreate<number>('spectrumMode', this.spectrumModeIndex)
     this.enablePointLight = PreferencesUtil.getBooleanSync('enablePointLight', true)
     AppStorage.setOrCreate('EnablePointLight', this.enablePointLight);
     this.showSimple = PreferencesUtil.getBooleanSync('showSimple', true)
@@ -10771,6 +10776,9 @@ export struct LocalMusic {
 
         if (this.isPhoneLan()) {
           Column() {
+            if (this.isShowSpectrum) {
+              this.InlineSpectrumView()
+            }
             this.playProgressView()
           }
           .margin({ bottom: 32, right: this.currentLyricAlignMode == 0 ? 0 : 30 })
@@ -10807,6 +10815,9 @@ export struct LocalMusic {
   @Builder
   BottomControl() {
     Column() {
+      if (this.isShowSpectrum) {
+        this.InlineSpectrumView()
+      }
       this.TopPlayProgressView()
       //播放 暂停,下一首,上一首
       this.playCenterView()
@@ -11401,16 +11412,9 @@ export struct LocalMusic {
       })
 
 
-      if (this.isPhonePortrait()  ) {
-        Stack(){
-          if (true) {
-            this.InlineSpectrumView()
-          }
-          if (this.isShowSingleLineLyric) {
-            this.SingleLyricView()
-          }
-        }
 
+      if (this.isPhonePortrait() &&this.isShowSingleLineLyric) {
+        this.SingleLyricView()
       }
       if (this.isPhoneLan()) {
         Column() {
@@ -12819,15 +12823,27 @@ export struct LocalMusic {
                 })
                   .id('AVCastPicker')
 
-              } else {
-                Image(more.image)
-                  .width(24)
-                  .height(24)
-                  .fillColor(Color.White)
-                  .margin({ left: 10, right: 10 })
-                  .onClick(() => {
-                    this.doMore(more.id)
-                  })
+              }else {
+                if(more.id >= 22){
+                  SymbolGlyph(more.image)
+                    .fontSize(24)
+                    .fontColor([Color.White])
+                    .alignSelf(ItemAlign.Center)
+                    .margin({ left: 10, right: 10 })
+                    .onClick(() => {
+                      this.doMore(more.id)
+                    })
+                }else{
+                  Image(more.image)
+                    .width(24)
+                    .height(24)
+                    .fillColor(Color.White)
+                    .margin({ left: 10, right: 10 })
+                    .onClick(() => {
+                      this.doMore(more.id)
+                    })
+                }
+
                 Text(more.id == 17 ? (this.isLandscape ? '竖屏模式' : '横屏模式') : more.title)
                   .fontSize(16)
 
@@ -12964,6 +12980,44 @@ export struct LocalMusic {
                   .width(48)
                   .height(24);
 
+                Toggle({ type: ToggleType.Switch, isOn: this.isShowSpectrum })
+                  .selectedColor(this.themeColor)
+                  .switchPointColor(Color.White)
+                  .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.5 })
+                  .margin({ right: 15 })
+                  .visibility(more.id == 25 ? Visibility.Visible : Visibility.None)
+                  .onChange((checked: boolean) => { // 选择开关状态变化时触发事件
+                    if (more.id == 25) {
+                      this.isShowSpectrum = checked;
+                      PreferencesUtil.put("isShowSpectrum", this.isShowSpectrum)
+                    }
+
+                  })
+                  .width(48)
+                  .height(24);
+
+                // 频谱特效类型选择器
+                Select([
+                  { value: '柱状' },
+                  { value: '波形' },
+                  { value: '圆形' },
+                  { value: '粒子' }
+                ])
+                  .font({ size: 14, weight: FontWeight.Medium })
+                  .fontColor(Color.White)
+                  .margin({ left: 25 })
+                  .visibility(more.id === 26 ? Visibility.Visible : Visibility.None)
+                  .selected(this.spectrumModeIndex)
+                  .value(['柱状', '波形', '圆形', '粒子'][this.spectrumModeIndex])
+                  .onSelect(async (index: number, _text?: string) => {
+                    this.spectrumModeIndex = index;
+                    PreferencesUtil.put('spectrumModeIndex', this.spectrumModeIndex);
+                    AppStorage.setOrCreate<number>('spectrumMode', this.spectrumModeIndex);
+                    const modeNames = ['柱状', '波形', '圆形', '粒子'];
+                    ToastUtil.showToast(`已切换到${modeNames[index]}频谱`);
+                  });
+
+
                 Toggle({ type: ToggleType.Switch, isOn: this.showSimple })
                   .selectedColor(this.themeColor)
                   .switchPointColor(Color.White)
@@ -13061,7 +13115,7 @@ export struct LocalMusic {
 
     { id: 2, image: $r('app.media.lyric'), title: '歌词' },
 
-    { id: 24, image: $r('app.media.equalizer'), title: '均衡器' },
+    { id: 24, image: $r('sys.symbol.slider_vertical_3'), title: '均衡器' },
 
     { id: 17, image: $r('app.media.full_4'), title: '横屏模式' },
 
@@ -13087,15 +13141,16 @@ export struct LocalMusic {
 
     { id: 9, image: $r('app.media.volume_white'), title: '调整音量' },
 
-
+    { id: 25, image: $r('sys.symbol.ranking'), title: '音乐频谱' },
+    { id: 26, image: $r('sys.symbol.eight_diagram'), title: '频谱类型' },
     // { id: 6, image: $r('app.media.memory'), title: '记忆播放' },
 
 
     { id: 13, image: $r('app.media.rectangle'), title: '封面方形' },
 
-    { id : 22, image: $r('app.media.skip'), title: '沉浸式' },
+    { id : 22, image: $r('sys.symbol.satellite_map'), title: '沉浸式' },
 
-    { id : 23, image: $r('app.media.more_do'), title: '点光源效果' },
+    { id : 23, image: $r('sys.symbol.lightbulb'), title: '点光源效果' },
 
     { id : 21, image: $r('app.media.kp_music'), title: '背景双边流光' },
 
@@ -15302,9 +15357,9 @@ export struct LocalMusic {
       isVisible: this.currentSwiperIndex === 0,
       isPlaying: this.CONTROL_PlayStatus === PlayStatus.PLAY
     })
-      .width(this.isLandscape ? '82%' : '90%')
-      .height(this.isCoverOpacity() ? 120 : 150)
-      .margin({ top: 3, bottom: 12 })
+      .width( '82%')
+      .height(this.isCoverOpacity() ? 80 : 100)
+      .margin({bottom: 3 })
       .clip(true)
   }
 

+ 11 - 6
entry/src/main/ets/view/spectrum/BarSpectrumRenderer.ets

@@ -26,10 +26,12 @@ export class BarSpectrumRenderer implements SpectrumRenderer {
     // 轻微拖影,接近参考图中的荧光残影(使用透明背景)
     ctx.clearRect(0, 0, width, height)
 
-    const gap: number = 2.2 // 恢复柱子之间的间隙
-    const barWidth: number = (width - gap * (bandCount + 1)) / bandCount
-    const usableHeight: number = height * 0.80
-    const segmentHeight: number = Math.max(3, height * 0.015) // 增加单段高度
+    const gap: number = 1.0 // 减小间隙,增加柱子列数
+    const barWidth: number = 5 // 固定柱子宽度
+    const totalSpectrumWidth: number = bandCount * barWidth + (bandCount - 1) * gap
+    const startX: number = (width - totalSpectrumWidth) / 2 // 居中起始位置
+    const usableHeight: number = height * 0.60 // 减小最大高度
+    const segmentHeight: number = Math.max(2, height * 0.012) // 减小单段高度
     const segmentGap: number = 0 // 去掉间隙,让方格紧密相连
     const segmentCount: number = Math.max(10, Math.floor(usableHeight / (segmentHeight + segmentGap)))
     const palette = buildSpectrumPalette(brandColor)
@@ -40,7 +42,7 @@ export class BarSpectrumRenderer implements SpectrumRenderer {
     for (let i = 0; i < bandCount; i++) {
       const level: number = Math.max(0, Math.min(1, bands[i]))
       const activeSegments: number = Math.floor(level * segmentCount)
-      const x: number = gap + i * (barWidth + gap)
+      const x: number = startX + i * (barWidth + gap)
       const hue: number = (palette.primaryHue + (i / bandCount) * hueSpan) % 360
 
       for (let seg = 0; seg < segmentCount; seg++) {
@@ -73,7 +75,10 @@ export class BarSpectrumRenderer implements SpectrumRenderer {
 
       const peakSeg: number = Math.floor(this.peaks[i] * segmentCount)
       const peakY: number = height - (peakSeg + 1) * (segmentHeight + segmentGap)
-      ctx.fillStyle = hslToHex(palette.accentHue, 0.95, 0.72)
+      // 使用当前柱子的颜色
+      const peakT: number = peakSeg / segmentCount
+      const peakLightness: number = 0.34 + peakT * 0.34
+      ctx.fillStyle = hslToHex(hue, 0.86, peakLightness)
       ctx.globalAlpha = 0.95
       ctx.fillRect(x, peakY, barWidth, segmentHeight + 1)
       ctx.globalAlpha = 1.0

+ 3 - 34
entry/src/main/ets/view/spectrum/SpectrumView.ets

@@ -9,7 +9,7 @@ import { normalizeHexColor } from './SpectrumRenderer'
 import Logger from '../../common/util/Logger'
 
 const TAG: string = 'heanup-SpectrumView'
-const BAND_COUNT: number = 32
+const BAND_COUNT: number = 53
 const FRAME_INTERVAL: number = 33 // ~30fps
 
 export enum SpectrumMode {
@@ -116,7 +116,7 @@ export struct SpectrumView {
   }
 
   build() {
-    Stack({ alignContent: Alignment.TopEnd }) {
+    Stack({ alignContent: Alignment.Center }) {
       Canvas(this.canvasContext)
         .width('100%')
         .height('100%')
@@ -130,38 +130,7 @@ export struct SpectrumView {
           this.canvasHeight = newVal.height as number
         })
 
-      // 特效切换按钮
-      Column() {
-        Text('🎵')
-          .fontSize(22)
-          .fontColor('#FFFFFF')
-          .opacity(0.7)
-          .onClick(() => {
-            this.showModePanel = !this.showModePanel
-          })
-          .padding(8)
-
-        if (this.showModePanel) {
-          Column() {
-            ForEach(MODE_NAMES, (name: string, index: number) => {
-              Text(name)
-                .fontSize(14)
-                .fontColor(index === this.currentMode ? $r('app.color.brand') : '#FFFFFF')
-                .fontWeight(index === this.currentMode ? FontWeight.Bold : FontWeight.Normal)
-                .opacity(index === this.currentMode ? 1.0 : 0.7)
-                .padding({ top: 8, bottom: 8, left: 16, right: 16 })
-                .onClick(() => {
-                  this.switchMode(index)
-                  this.showModePanel = false
-                })
-            })
-          }
-          // .backgroundColor('rgba(0,0,0,0.6)')
-          .borderRadius(12)
-          .padding(4)
-        }
-      }
-      .margin({ top: 16, right: 16 })
+
     }
     .width('100%')
     .height('100%')