Sfoglia il codice sorgente

Merge remote-tracking branch 'origin/master' into feature/桌面卡片

chendeben 1 anno fa
parent
commit
a97eeb2ba2

+ 2 - 2
AppScope/app.json5

@@ -2,8 +2,8 @@
   "app": {
     "bundleName": "com.xgplayer.ttmusic.hm",
     "vendor": "example",
-    "versionCode": 20250730,
-    "versionName": "1.4.9",
+    "versionCode": 20250806,
+    "versionName": "1.5.0",
     "icon": "$media:app_icon",
     "label": "$string:app_name",
     "multiAppMode": {

+ 1 - 1
entry/src/main/ets/common/constants/PlayConstants.ets

@@ -97,7 +97,7 @@ export class PlayConstants {
   static readonly PROGRESS_PROGRESS_VAL: number = 0;
   static readonly PROGRESS_INTERVAL: number = -1;
   static readonly PROGRESS_STEP: number = 1;
-  static readonly PROGRESS_TRACK_THICKNESS: number = 3;
+  static readonly PROGRESS_TRACK_THICKNESS: number = 5;
   static readonly PROGRESS_SLIDER_WIDTH: string = '68.9%';
   static readonly PROGRESS_MARGIN_LEFT: string = '2.2%';
   static readonly PROGRESS_SEEK_TIME: number = 0;

+ 10 - 0
entry/src/main/ets/common/util/MediaTable.ets

@@ -238,6 +238,8 @@ export default class MediaTable {
       obj.year  = resultSet.getString(resultSet.getColumnIndex('year'));
       obj.nb_streams  = resultSet.getDouble(resultSet.getColumnIndex('nb_streams'));
       obj.nb_programs  = resultSet.getDouble(resultSet.getColumnIndex('nb_programs'));
+      obj.genre  = resultSet.getString(resultSet.getColumnIndex('genre'));
+      obj.track  = resultSet.getString(resultSet.getColumnIndex('track'));
 
       const valueBucket: relationalStore.ValuesBucket = obj
       // Step 4: 执行更新
@@ -562,6 +564,8 @@ export default class MediaTable {
     item.year = safeGet('year');
     item.nb_streams = safeGetNumber('nb_streams');
     item.nb_programs = safeGetNumber('nb_programs');
+    item.genre = safeGet('genre');
+    item.track = safeGet('track');
 
     return item;
   }
@@ -650,6 +654,12 @@ function generateBucket(item: VideoItem): relationalStore.ValuesBucket {
   if(item.nb_programs){
     obj.nb_programs = item.nb_programs;
   }
+  if(item.genre){
+    obj.genre = item.genre;
+  }
+  if(item.track){
+    obj.track = item.track;
+  }
 
   return obj;
 }

+ 6 - 1
entry/src/main/ets/common/util/RdbUtils.ets

@@ -67,13 +67,15 @@ export default class RdbUtils {
       '        year TEXT,\n' +
       '        nb_streams INTEGER DEFAULT 0,\n' +
       '        nb_programs INTEGER DEFAULT 0,\n' +
+      '        genre TEXT,\n' +
+      '        track TEXT,\n' +
 
       '        mimeType TEXT' +
       ')',
     columns: ['id', 'name', 'filePath','mtype', 'videoSize', 'cTime','size', 'artist', 'album',
       'fileName','parentPath','isFav','pixelMapPath','pixelMapToString',
       'duration',   'sampleRate','playCount',  'lastPlayedStr', 'trackCount',
-      'lyricContent','md5Str','extra_json','pyStr','bit_rate','probe_score','year','nb_streams','nb_programs','mimeType']
+      'lyricContent','md5Str','extra_json','pyStr','bit_rate','probe_score','year','nb_streams','nb_programs','genre','track','mimeType']
   };
 
   constructor(tableName: string, sqlCreateTable: string, columns: Array<string>) {
@@ -153,6 +155,9 @@ export default class RdbUtils {
             'year': 'TEXT',
             'nb_streams': 'INTEGER DEFAULT 0',
             'nb_programs': 'INTEGER DEFAULT 0',
+            'genre': 'TEXT',
+            'track': 'TEXT',
+
           };
           
           // 逐个添加列,不依赖于检查结果

+ 170 - 113
entry/src/main/ets/common/util/Utility.ets

@@ -25,13 +25,22 @@ import { VipData } from '../../viewmodel/VipData';
 import { LocalMusic } from '../../view/LocalMusic';
 import { VipPage } from '../../pages/VipPage';
 import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
+
 interface FFMpegTags {
   album?: string;
+  ALBUM?: string;
   artist?: string;
+  ARTIST?: string;
+  TITLE?: string;
   title?: string;
   track?: string;
+  TRACK?: string;
   TYER?: string;
+  year?: string;
+  genre?:string;
+  GENRE?:string;
   date?: string;
+  DATE?: string;
   LYRICS?: string;
   lyrics?: string;       // 小写变体
   USLT?: string;         // ID3v2同步歌词
@@ -520,67 +529,9 @@ export class Utility {
 
     return format;
   }
-  //获取从文件管理器获得的视频资源的属性值
-  static async uriGetAssetsFromFile(context:Context,uri:string,type:number,isLoadPixelMap?:boolean): Promise<VideoItem> {
-    let item:VideoItem = new VideoItem('',uri,uri,type,0,'')
-    try {
-      console.info('asset file.uri: ', uri);
-
-
-      let file = fs.openSync(uri, fs.OpenMode.READ_ONLY | fs.OpenMode.CREATE)
-      console.info("file.fd " + file.fd);
-      let fdfd = 'fd://' + file.fd
-      //3、通过fs.stat方法获取stat对象
-      console.info('asset file.name: ', file.name);
-      console.info('asset file.uri: ', uri);
-      console.info('asset file.fd: ', file.fd);
-      console.info('asset file.path: ', file.path);
-      item = new VideoItem(file.name,uri,uri,type,0,'')
-      await fs.stat(file.fd).then(async (stat: fs.Stat) => {
-        console.info("get file info succeed, the size of file is " + stat.size);
-        let videoSize =  stat.size
-        // let videoTime = stat.ctime
-
-        let fileSize = Utility.formatFSize(videoSize)
-        let cTime = Utility.getFormatDateStr(stat.mtime,'yyyy-MM-dd HH:mm')
-
-        // console.info('asset stat.ino: ', stat.ino);
-        // console.info('asset stat.mode: ', stat.mode);
-        // console.info('asset stat.uid: ', stat.uid);
-        // console.info('asset stat.ino: ', stat.gid);
-        // console.info('asset stat.size: ', stat.size);
-        console.info('asset stat.ctime: ', stat.ctime);
-        // console.info('asset stat.mtime: ', stat.mtime);
-        // console.info('asset stat.duration: ', duration);
-
-
-        let pixelMap:image.PixelMap|undefined = undefined
-        if(isLoadPixelMap){
-          //获取缩略图
-          if(Utility.isVideoByExtension(uri)){
-            pixelMap = await Utility.getFetchFrameByTime(uri)
-          }else{
-            pixelMap = await Utility.getFetchMetadataFromFdSrcByPromise(uri)
-          }
-        }
-
-        item = new VideoItem( file.name,uri ,uri,type,videoSize,cTime,pixelMap,fileSize,
-          await ImageUtil.pixelMapToBase64Str(pixelMap))
-
 
 
 
-      })
-    } catch (error) {
-      console.error('uriGetAssetsFromFile failed with err: ' + JSON.stringify(error));
-    }
-
-    return item
-
-
-  }
-
-
   static async getFilePixelMapBig(uri:string){
     let pixelMap:image.PixelMap|undefined = undefined
     if(Utility.isMusicByExtension(uri)){
@@ -668,6 +619,8 @@ export class Utility {
 
   //获取音乐资源的属性值,
   static async uriGetMusicAssetsFromFile(context:Context,uri:string,type:number,isLoadPixelMap?:boolean): Promise<VideoItem> {
+    return Utility.readMetaInfoFFmpeg(context,uri,type)
+
     //华为官方不支持的格式 不支持内嵌歌词Dsf,aif,aiff,wav  不支持内嵌封面dsf,aif,aiff
     if(StrUtil.isNotEmpty(uri)){
       if(uri.toLowerCase().endsWith('.dsf')
@@ -881,9 +834,26 @@ export class Utility {
             let addTime = Utility.getFormatDateStr(new Date(),'yyyy-MM-dd HH:mm');
             // Extract artist and title from tags
             const tags = format.tags  || {};
-            const artist = tags.artist  || '';
-            const title = tags.title  || '';
-            const album = tags.album  || '';
+            let artist = tags.artist ||tags.ARTIST || '';
+            let title = tags.title ||tags.TITLE || '';
+            const album = tags.album ||tags.ALBUM|| '';
+
+
+            if(StrUtil.isEmpty(title)){
+              //自动解析像这样的获取不到元数据的 周杰伦-七里香.mp3文件
+              console.log(`onecold musicName为空:${file.name}`);
+              const musicData = parseMusicFileName(file.name);
+              if (musicData.isValid)  {
+                // console.log(`onecold 艺术家:${musicData.artist}`);   // 输出:周杰伦
+                // console.log(`onecold 歌曲名:${musicData.title}`);   // 输出:七里香
+                title = musicData.title
+                if(artist==''||artist==undefined)
+                  artist = musicData.artist
+              } else {
+                title = file.name
+                // console.log("onecold 文件名格式不符合要求");
+              }
+            }
 
             let name: string = title;
             if (!name) {
@@ -902,7 +872,6 @@ export class Utility {
             // Set additional properties from format metadata
             videoItem.artist  = artist;
             videoItem.album  = album;
-            videoItem.mimeType = format.format_name
             videoItem.sampleRate = sampleRate
             videoItem.pyStr = pinyin4js.getShortPinyin(name)
             videoItem.fileName  = FileUtil.getFileName(inputPath);
@@ -913,36 +882,39 @@ export class Utility {
             videoItem.probe_score  = format.probe_score;
             videoItem.nb_streams  = format.nb_streams;
             videoItem.nb_programs  = format.nb_programs;
-            videoItem.year  = tags.TYER || tags.date  || 'unknown'; // try different tag names for year
+            videoItem.year  = tags.TYER || tags.date ||tags.DATE|| Utility.resourceToString(context, $r('app.string.unknown')); // try different tag names for year
             videoItem.lyricContent  = tags.LYRICS || tags.lyrics  ||  tags.USLT || tags.UNSYNCEDLYRICS || '';
-
+            videoItem.genre  = tags.genre||tags.GENRE|| Utility.resourceToString(context, $r('app.string.unknown'));
+            videoItem.track  = tags.track||tags.TRACK|| Utility.resourceToString(context, $r('app.string.unknown'));
+            videoItem.mimeType = format.format_name
             // 检查是否有封面图片流
             const hasCover = metadata.streams.some(stream  =>
             stream.disposition?.attached_pic  === 1
             );
             console.info('readMetaInfoFFmpeg asset hasCover: ', hasCover);
+            let md5Name = await MD5.digestSync(inputPath)
+            let imagePath = `${context.filesDir}${FileUtil.separator}${md5Name}.jpg`;
+            console.info('readMetaInfoFFmpeg asset imagePath: ', imagePath);
             // 如果有封面图片,则提取
-            if (hasCover) {
-
-              try {
-                let md5Name = await MD5.digestSync(inputPath)
-                // const imageName = `${md5Name}.jpg`;
-                const imagePath = `${context.filesDir}${FileUtil.separator}${md5Name}`;
-                console.info('readMetaInfoFFmpeg asset imagePath: ', imagePath);
-                // 提取封面图片
-                // await extractCoverImage(inputPath, imagePath);
-                await FFmpegCover(inputPath, imagePath);
-
-                // 检查图片是否生成成功
-                if (fs.accessSync(imagePath))  {
+            try {
+              if (hasCover) {
+                  //提取封面
+                  await getFFmpegCover(inputPath, imagePath);
+                  imagePath = fileUri.getUriFromPath(imagePath)
                   videoItem.pixelMapPath  = imagePath;
-
-                }
-              } catch (error) {
-                console.warn(' 提取封面图片失败:', error.message);
+              }else if(Utility.isVideoByExtension(inputPath)){
+                //提取封面
+                await getVideoFFmpegCover(inputPath, imagePath);
+                videoItem.mimeType = getFileFormatByPath(inputPath)
+                imagePath = fileUri.getUriFromPath(imagePath)
+                videoItem.pixelMapPath  = imagePath;
               }
+            } catch (error) {
+              console.warn(' 提取封面图片失败:', error.message);
+            }
+            if(sampleRate&&format.bit_rate){
+              videoItem.md5Str = determineAudioQuality( videoItem.mimeType,Number(format.bit_rate),Number(sampleRate))
             }
-
             console.info('Successfully  parsed metadata:', videoItem);
             resolve(videoItem);
           })
@@ -1600,43 +1572,14 @@ function getFileNameWithoutExtension(filePath: string): string {
   return lastDotIndex > 0 ? fileName.substring(0,  lastDotIndex) : fileName;
 }
 
-/**
- * 从音乐文件中提取封面
- * @param inputPath 音乐文件路径
- * @returns Promise<void>
- */
-async function extractCoverImage(inputPath: string, outputPath: string): Promise<void> {
-  const commands = [
-    'ffmpeg',
-    '-i', inputPath,
-    '-an',              // 禁用音频
-    '-vcodec', 'copy',  // 直接复制视频流
-    '-f', 'image2',     // 强制输出为图片
-    '-y',               // 覆盖输出文件
-    outputPath
-  ];
-
-  return new Promise((resolve, reject) => {
-    FFmpeg.execute(commands,  {
-      logCallback: (logLevel: number, logMessage: string) => {
-        console.log(`[${logLevel}]${logMessage}`);
-      },
-      outputCallback: (message: string) => {
-        console.log(`FFmpeg  output: ${message}`);
-      },
-    }).then(() => resolve())
-      .catch((error: BusinessError) => reject(error));
-  });
-}
-
 
 /**
  * 从音乐文件中提取封面
  * @param inputPath 音乐文件路径
  * @returns Promise<void>
  */
-async function FFmpegCover(inputPath: string, outputPath: string) {
-  let commands = ["ffmpeg", "-i", inputPath, "-map", "0:v", "-c:v", "copy", outputPath];
+async function getFFmpegCover(inputPath: string, outputPath: string) {
+  let commands = ["ffmpeg", "-y","-i", inputPath, "-map", "0:v", "-c:v", "copy", outputPath];
   FFmpeg.execute(commands, {
     logCallback: (logLevel: number, logMessage: string) => {
       console.info(`[FFmpeg LOG] [${logLevel}]${logMessage}`)
@@ -1652,6 +1595,35 @@ async function FFmpegCover(inputPath: string, outputPath: string) {
       console.error(`FFmpeg execution failed with error: ${error.message}`);
     });
 }
+/**
+ * 从视频文件中提取封面 提前视频第5帧的封面
+ * @param inputPath 文件路径
+ * @returns Promise<void>
+ */
+async function getVideoFFmpegCover(inputPath: string, outputPath: string,duration?:string) {
+  let durationText = "00:00:05"
+  if(duration&&Number(duration) >300000){//如果时间超过5分钟,截10s的缩略图
+    durationText = "00:00:10"
+  }
+  if(duration&&Number(duration) <5000){//如果时间小5s,截0s的缩略图
+    durationText = "00:00:01"
+  }
+  let commands = ["ffmpeg", "-y","-i", inputPath, "-ss", "00:00:03", "-t", "1","-r",'1','-q:v','2','-f','image2', outputPath];
+  FFmpeg.execute(commands, {
+    logCallback: (logLevel: number, logMessage: string) => {
+      console.info(`[FFmpegX LOG] [${logLevel}]${logMessage}`)
+    },
+    progressCallback: (message: string) => {
+      console.info(`[FFmpegX progress]${JSON.stringify(FFProgressMessageParser.parse(message))}`)
+    },
+  })
+    .then(() => {
+
+    })
+    .catch((error: Error) => {
+      console.error(`FFmpegX execution failed with error: ${error.message}`);
+    });
+}
 
 /**
  * 从音乐文件中提取歌词内容
@@ -1776,4 +1748,89 @@ function formatBitrateToKbps(bitRate: string, decimalPlaces: number = 0): string
 
   // 3. 格式化输出
   return `${kbps.toFixed(decimalPlaces)}  kbps`;
+}
+
+
+// 定义音质等级
+enum AudioQuality {
+  LQ = "LQ",             // 低音质
+  SQ = "SQ",             // 标准音质
+  HQ = "HQ",             // 高音质
+  LOSSLESS = "Lossless", // 无损
+  HIRES = "Hi-Res"       // 高解析度
+}
+
+// 明确定义支持的音频格式类型
+interface SupportedFormats {
+  LOSSY: Set<string>;
+  LOSSLESS: Set<string>;
+}
+
+// 声明并初始化支持的音频格式(符合类型定义)
+const SUPPORTED_FORMATS: SupportedFormats = {
+  LOSSY: new Set(['mp3', 'aac', 'ogg', 'opus', 'wma']),
+  LOSSLESS: new Set(['flac', 'alac', 'ape', 'wav', 'aiff', 'dsf','aif'])
+};
+
+/**
+ * 根据音频参数判断音质等级
+ * @param format 编码格式(字符串,不区分大小写,如"MP3"或"flac")
+ * @param bitrate 比特率(单位:bps,如320kbps需传入320000)
+ * @param sampleRate 采样率(单位:Hz,如44.1kHz需传入44100)
+ * @param bitDepth 位深(单位:bit,默认16bit,Hi-Res需≥24bit)
+ * @returns AudioQuality 音质等级
+ */
+function determineAudioQuality(
+  format: string,
+  bitrate: number,
+  sampleRate: number
+): AudioQuality {
+  // 统一转为小写便于比较
+  const normalizedFormat = format.toLowerCase();
+
+  // --------------- 第一步:判断是否无损/Hi-Res ---------------
+  const isLossless = SUPPORTED_FORMATS.LOSSLESS.has(normalizedFormat);
+  if (isLossless) {
+    // Hi-Res标准:采样率≥96kHz且位深≥24bit
+    if (sampleRate >= 96000 ) {
+      return AudioQuality.HIRES;
+    }
+    // CD级无损标准:采样率≥44.1kHz且位深≥16bit
+    if (sampleRate >= 44100) {
+      return AudioQuality.LOSSLESS;
+    }
+  }
+
+  // --------------- 第二步:有损音质判断 ---------------
+  // 高音质标准:比特率≥256kbps且采样率≥44.1kHz
+  if (bitrate >= 256000 && sampleRate >= 44100) {
+    return AudioQuality.HQ;
+  }
+  // 标准音质:比特率≥128kbps且采样率≥22.05kHz
+  else if (bitrate >= 128000 && sampleRate >= 22050) {
+    return AudioQuality.SQ;
+  }
+  // 其余情况为低音质
+  else {
+    return AudioQuality.LQ;
+  }
+}
+
+function getFileFormatByPath(filePath: string): string {
+  // 检查文件路径是否有效
+  if (!filePath || filePath.length  === 0) {
+    console.error(' 文件路径不能为空');
+    return '';
+  }
+
+  // 获取最后一个点号的位置
+  const lastDotIndex = filePath.lastIndexOf('.');
+
+  // 如果没有点号或者点号在最后一位,返回空字符串
+  if (lastDotIndex === -1 || lastDotIndex === filePath.length  - 1) {
+    return '';
+  }
+
+  // 返回点号后的部分(转换为小写)
+  return filePath.substring(lastDotIndex  + 1).toLowerCase();
 }

+ 10 - 16
entry/src/main/ets/controller/AvSessionController.ets

@@ -132,21 +132,15 @@ export class AvSessionController {
       hilog.error(0x0000, TAG, 'SetAVMetadata Error, curSource is null');
       return;
     }
-    BackgroundTaskManager.startContinuousTask(this.context);
-    let pixelMapPath:string|undefined = curSource.pixelMapPath
+    try {
+      BackgroundTaskManager.startContinuousTask(this.context);
+      let pixelMapPath:string|undefined = curSource.pixelMapPath
 
-    Utility.getFetchMetadataFromFdSrcByPromise(curSource.filePath).then(async (value: PixelMap | undefined) => {
       let imagePixMap: PixelMap|string ;
-      if (value == undefined) {
-
-        if(pixelMapPath){
-          imagePixMap = pixelMapPath
-        }else{
-          imagePixMap = await ImageUtil.getPixelMapFromMedia($r('app.media.ic_avatar7'));
-        }
-
-      } else {
-        imagePixMap = value;
+      if(pixelMapPath){
+        imagePixMap = await ImageUtil.imagePathToPixelMap(pixelMapPath)
+      }else{
+        imagePixMap = await ImageUtil.getPixelMapFromMedia($r('app.media.ic_avatar2'));
       }
       let lyric = ''
       if(lyricContent)
@@ -171,9 +165,9 @@ export class AvSessionController {
           hilog.error(0x0000, TAG, `SetAVMetadata BusinessError: code: ${err.code}, message: ${err.message}`);
         });
       }
-    }).catch((err: BusinessError) => {
-      hilog.error(0x0000, TAG, `Failed to fetch metadata: code: ${err.code}, message: ${err.message}`);
-    });
+    } catch (error) {
+      console.warn(' setAVMetadataMusic:', error.message);
+    }
 
   }
 

+ 153 - 0
entry/src/main/ets/controller/KnockController.ets

@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// [Start knock_controller_create]
+import { harmonyShare, systemShare } from '@kit.ShareKit';
+import { fileUri } from '@kit.CoreFileKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { uniformTypeDescriptor } from '@kit.ArkData';
+import { common } from '@kit.AbilityKit';
+// [StartExclude knock_controller_create]
+// import { VIDEO_SOURCES, VideoData } from '../model/VideoData';
+import { window } from '@kit.ArkUI';
+import { VideoItem } from '../viewmodel/VideoItem';
+import Logger from '../common/util/Logger';
+import { LogUtil } from '@pura/harmony-utils';
+
+const TAG = 'KnockController';
+// [EndExclude knock_controller_create]
+export class KnockController {
+  private static controller: KnockController;
+  private context: common.UIAbilityContext | undefined = undefined;
+  // Knock listening status
+  private isKnockListening: boolean = false;
+  private  currentSong: VideoItem | undefined = undefined;
+
+  public static getInstance(context: common.UIAbilityContext): KnockController {
+    if (!KnockController.controller) {
+      KnockController.controller = new KnockController(context);
+    }
+    return KnockController.controller;
+  }
+
+  constructor(context: common.UIAbilityContext) {
+    this.context = context;
+  }
+
+  // [Start share_linking]
+  /**
+   * knock listening callback
+   * @param target After the Huawei Share event is triggered,
+   * you can call back the parameters and share them across devices.
+   */
+  public immersiveCallback(target: harmonyShare.SharableTarget) {
+    // [StartExclude knock_controller_create]
+    // share app linking
+    LogUtil.info('onecold KnockController  碰一碰 ');
+    try {
+       this.currentSong = AppStorage.get('currentSong');
+
+       if(this.currentSong){
+         let mediaData: VideoItem = this.currentSong;
+         let artist = ''
+         if(mediaData.artist){
+           artist = mediaData.artist
+         }
+         // Video thumbnail image sandbox path
+         let coverUri: string = fileUri.getUriFromPath(mediaData.pixelMapPath);
+         console.info('onecold KnockController  碰一碰 coverUri '+coverUri);
+         console.info('onecold KnockController  碰一碰 mediaData.filePath '+fileUri.getUriFromPath(mediaData.filePath));
+         // Get video thumbnail URI path
+         let shareData: systemShare.SharedData = new systemShare.SharedData({
+           utd: uniformTypeDescriptor.UniformDataType.MEDIA,
+           uri: fileUri.getUriFromPath(mediaData.filePath),
+           thumbnailUri: coverUri,
+           title: mediaData.name,
+           description: artist
+         });
+         // Initiate a share
+         target.share(shareData).then(() => {
+           Logger.info(TAG, 'Share link success');
+         }).catch((error: BusinessError) => {
+           Logger.error(TAG, `Share link  error. code: ${error.code}, message: ${error.message}`);
+         });
+       }
+
+
+    } catch (err) {
+      Logger.error(TAG, `Share link exception. code: ${err.code}, message: ${err.message}`);
+    }
+    // [EndExclude knock_controller_create]
+  }
+  // [End share_linking]
+
+  /**
+   *  Add knock listening
+   */
+  public immersiveListening() {
+    if (canIUse('SystemCapability.Collaboration.HarmonyShare') && !this.isKnockListening) {
+      harmonyShare.on('knockShare', (target: harmonyShare.SharableTarget) => {
+        this.immersiveCallback(target);
+      });
+      this.isKnockListening = true;
+    }
+  }
+
+  /**
+   *  remove knock listening
+   */
+  public immersiveDisableListening() {
+    if (canIUse('SystemCapability.Collaboration.HarmonyShare') && this.isKnockListening) {
+      harmonyShare.off('knockShare');
+      this.isKnockListening = false;
+    }
+  }
+
+  /**
+   *  Add knock listening in 2in1 device type.
+   */
+  public immersiveListeningPC() {
+    if (canIUse('SystemCapability.Collaboration.HarmonyShare') && !this.isKnockListening) {
+      window.getLastWindow(this.context).then((data) => {
+        let mainWindowID: number = data.getWindowProperties().id;
+        // harmonyShare.on('knockShare', { windowId:mainWindowID }, (target: harmonyShare.SharableTarget) => {
+        //   this.immersiveCallback(target);
+        // });
+
+        harmonyShare.on('knockShare', (target: harmonyShare.SharableTarget) => {
+          this.immersiveCallback(target);
+        });
+      })
+
+      this.isKnockListening = true;
+    }
+  }
+
+  /**
+   *  Remove knock listening in 2in1 device type.
+   */
+  public immersiveDisableListeningPC() {
+    if (canIUse('SystemCapability.Collaboration.HarmonyShare') && this.isKnockListening) {
+      window.getLastWindow(this.context).then((data) => {
+        let mainWindowID: number = data.getWindowProperties().id;
+        // harmonyShare.off('knockShare', { windowId:mainWindowID });
+        harmonyShare.off('knockShare');
+      })
+
+      this.isKnockListening = false;
+    }
+  }
+}
+// [End knock_controller_create]

+ 20 - 10
entry/src/main/ets/entryability/EntryAbility.ets

@@ -25,6 +25,7 @@ import statusBarManager from '@hms.pcService.statusBarManager';
 import StatusBarViewExtensionAbility from '@hms.pcService.StatusBarViewExtensionAbility';
 import { SpiderMan } from '@simplepeng/spider-man';
 import { smartMobilityCommon } from '@kit.CarKit';
+import { url } from '@kit.ArkTS';
 
 /**
  * 主Ability类,继承自UIAbility
@@ -37,6 +38,7 @@ export default class EntryAbility extends UIAbility {
     // UI上下文对象,用于获取窗口信息
     private uiContext?: UIContext;
     private awareness: smartMobilityCommon.SmartMobilityAwareness = smartMobilityCommon.getSmartMobilityAwareness();
+
     /**
      * 窗口尺寸变化回调函数
      * @param windowSize 新的窗口尺寸对象
@@ -54,13 +56,17 @@ export default class EntryAbility extends UIAbility {
         let heightBp: HeightBreakpoint = this.uiContext!.getWindowHeightBreakpoint();
         AppStorage.setOrCreate('currentHeightBreakpoint', heightBp);
         // 记录尺寸变化日志
-        LogUtil.info('pura onWindowSizeChange currentHeightBreakpoint= '+heightBp);
-        LogUtil.info( 'pura onWindowSizeChange currentWidthBreakpoint= '+widthBp);
+        // LogUtil.info('pura onWindowSizeChange currentHeightBreakpoint= '+heightBp);
+        // LogUtil.info( 'pura onWindowSizeChange currentWidthBreakpoint= '+widthBp);
         AppStorage.setOrCreate('windowWidth', windowSize.width);
         AppStorage.setOrCreate('windowHeight', windowSize.height);
-
-        LogUtil.info('hicar onWindowSizeChange width= '+windowSize.width);
-        LogUtil.info( 'hicar onWindowSizeChange height= '+windowSize.height);
+        if(windowSize.width > windowSize.height){
+            AppStorage.setOrCreate('isLandscape', true);
+        }else{
+            AppStorage.setOrCreate('isLandscape', false);
+        }
+        // LogUtil.info('hicar onWindowSizeChange width= '+windowSize.width);
+        // LogUtil.info( 'hicar onWindowSizeChange height= '+windowSize.height);
 
     };
 
@@ -80,11 +86,10 @@ export default class EntryAbility extends UIAbility {
     async onCreate(want:Want, launchParam:AbilityConstant.LaunchParam) {
         AppStorage.setOrCreate('context', this.context);
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
-
         setTimeout(async ()=>{
             this.loadDoWant(want)
             await this.handleParam(want)
-        },1000)
+        },2000)
 
         this.handleWeChatCallIfNeed(want)
 
@@ -107,7 +112,7 @@ export default class EntryAbility extends UIAbility {
 
     //处理其他app点击其他应用打开播放器播放视频或者音频
     loadDoWant(want: Want){
-
+        // console.info('onecold KnockController  碰一碰 want ='+JSON.stringify(want));
         let uri = want.uri;
         if (uri == null || uri == undefined|| StrUtil.isEmpty(uri)) {
             console.info('uri is invalid');
@@ -226,8 +231,13 @@ export default class EntryAbility extends UIAbility {
 
                 AppStorage.setOrCreate('windowWidth', data.getWindowProperties().windowRect.width);
                 AppStorage.setOrCreate('windowHeight', data.getWindowProperties().windowRect.height);
-                LogUtil.info('hicar getMainWindow width= '+data.getWindowProperties().windowRect.width);
-                LogUtil.info( 'hicar getMainWindow height= '+data.getWindowProperties().windowRect.height);
+                if(data.getWindowProperties().windowRect.width > data.getWindowProperties().windowRect.height){
+                    AppStorage.setOrCreate('isLandscape', true);
+                }else{
+                    AppStorage.setOrCreate('isLandscape', false);
+                }
+                // LogUtil.info('hicar getMainWindow width= '+data.getWindowProperties().windowRect.width);
+                // LogUtil.info( 'hicar getMainWindow height= '+data.getWindowProperties().windowRect.height);
             }).catch((err: BusinessError) => {
                 console.error(`Failed to obtain the main window. Cause code: ${err.code}, message: ${err.message}`);
             });

+ 40 - 23
entry/src/main/ets/pages/AboutPage.ets

@@ -117,8 +117,8 @@ export struct AboutPage{
           // 左右按钮
           Row() {
             Image($r('app.media.menu'))
-              .width(24)
-              .height(24)
+              .width(26)
+              .height(26)
               .margin({ left: 12, right: 8 })
               .onClick(() => {
                 animateTo({ duration: 555 }, () => {
@@ -143,46 +143,64 @@ export struct AboutPage{
         Column(){
 
           Image($r('app.media.icon'))
-            .width(150)
-            .height(150)
+            .width(120)
+            .height(120)
             .borderRadius('100%')
             .clip(true)
-            .margin({top:55})
           Text(this.appName+'V:'+this.verName)
             .fontColor(this.isDarkMode ? Color.White : Color.Black)
             .fontWeight(480)
             .fontSize(17)
-            .margin({top:20,bottom:20})
+            .margin({top:20,bottom:10})
 
           Text(CommonConstants.ICP_NO)
             .fontColor(this.isDarkMode ? Color.White : Color.Black)
             .fontWeight(480)
             .decoration({ type: TextDecorationType.Underline, color: this.isDarkMode ? Color.White : Color.Black })
-            .fontSize(18)
-            .margin({top:20,bottom:20})
+            .fontSize(17)
+            .margin({top:10,bottom:10})
             .onClick(()=>{
-              // let want = {
-              //   action: "ohos.want.action.viewData",
-              //   uri: CommonConstants.ICP_URL
-              // };
-
                 let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
                 context.openLink(CommonConstants.ICP_URL, {})
             })
 
-          Button('加入Q群:685109858', { type: ButtonType.Capsule, stateEffect: false })
+          Button('用户协议', { type: ButtonType.Capsule, stateEffect: false })
+            .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?'25%':'60%')
+            .height(55)
+            .margin({top:10,bottom:10})
+            .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
+            .stateEffect(true)
+            .backgroundColor(this.themeColor)
+            .onClick(()=>{
+              router.pushUrl({
+                url: 'pages/WebIndex',
+                params: { titleName: '用户协议', webUrl: CommonConstants.NEW_DUTY }
+              });
+            })
+          Button('隐私政策', { type: ButtonType.Capsule, stateEffect: false })
             .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?'25%':'60%')
             .height(55)
-            .margin({top:50,bottom:20})
-              // .visibility(Visibility.None)
+            .margin({top:10,bottom:10})
+            .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
             .stateEffect(true)
             .backgroundColor(this.themeColor)
-            .stateStyles({
-              pressed: { opacity: 0.6 }
+            .onClick(()=>{
+              router.pushUrl({
+                url: 'pages/WebIndex',
+                params: { titleName: '隐私政策', webUrl: CommonConstants.NEW_YS_HW }
+              });
             })
+
+          Button('粉丝QQ群', { type: ButtonType.Capsule, stateEffect: false })
+            .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?'25%':'60%')
+            .height(55)
+            .margin({top:10,bottom:20})
+            .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
+            .stateEffect(true)
+            .backgroundColor(this.themeColor)
             .onClick(()=>{
-              // ToastUtil.showToast('复制群号成功!')
-              // Utility.copyText('685109858')
+              ToastUtil.showToast('复制群号成功!')
+              Utility.copyText('685109858')
               const qqUrl = `mqqapi://card/show_pslcard?src_type=internal&version=1&uin=${CommonConstants.QQ_GROUP}&card_type=group&source=external`;
               let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
               context.openLink(qqUrl, {})
@@ -193,10 +211,8 @@ export struct AboutPage{
             .height(55)
             .stateEffect(true)
             .margin({bottom:20})
+            .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
             .backgroundColor(this.themeColor)
-            .stateStyles({
-              pressed: { opacity: 0.6 }
-            })
             .onClick(()=>{
               AlertDialog.show({
                 title:'发送邮件',
@@ -216,6 +232,7 @@ export struct AboutPage{
               })
             })
         }
+        .justifyContent(FlexAlign.Start)
         .width('100%')
 
       }

+ 27 - 24
entry/src/main/ets/pages/ScanFilePage.ets

@@ -66,10 +66,7 @@ export struct ScanFilePage{
 
   }
   onPageShow() {
-    this.initLottie(this.path,true)
-    setTimeout(()=>{
-      lottie.pause()
-    },88)
+
 
   }
   // 组件生命周期
@@ -88,6 +85,10 @@ export struct ScanFilePage{
 
     this.lockPath =  this.rootPath +'/'+ LocalMusic.STR_LOCK_VIDEO
     LogUtil.info('onecold 文件扫描 aboutToAppear')
+    this.initLottie(this.path,true)
+    setTimeout(()=>{
+      lottie.pause()
+    },88)
 
   }
   onColorModeChange() {
@@ -224,12 +225,26 @@ export struct ScanFilePage{
 
           Text(this.strText)
             .height(50)
-            .margin({ right: 20 })
             .fontSize(16)
             .fontColor($r('app.color.text_color'))
             .fontWeight(480)
             .visibility(this.textVisi)
 
+          Button($r('app.string.start_scan'), { type: ButtonType.Capsule, stateEffect: false })
+
+            .width(180)
+            .height(55)
+            .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
+            .margin({ top: 10, bottom: 10 })
+            .backgroundColor(this.themeColor)
+            .enabled(this.isStart ?false:true)
+            .onClick(() => {
+              this.doOptimize(false)
+
+            })
+            .alignSelf(ItemAlign.Center)
+            .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
+              .animation({ duration: 380, curve: Curve.Ease,delay:30 }))
 
           Column() {
             Row() {
@@ -303,26 +318,14 @@ export struct ScanFilePage{
           .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
             .animation({ duration: 380, curve: Curve.Ease,delay:60 }))
 
-          Column() {
-            Button($r('app.string.start_scan'), { type: ButtonType.Capsule, stateEffect: false })
-
-              .width(180)
-              .height(55)
-              .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
-              .margin({ top: 20, bottom: 10 })
-              .backgroundColor(this.themeColor)
-              .enabled(this.isStart ?false:true)
-              .onClick(() => {
-                this.doOptimize(false)
+          Row() {
 
-              })
-              .alignSelf(ItemAlign.Center)
 
             Button($r('app.string.onekey_cover'), { type: ButtonType.Capsule, stateEffect: false })
-              .width(180)
+              .width(150)
               .height(55)
               .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
-              .margin({ top: 10, bottom: 10 })
+              .margin({ top: 10, bottom: 10,right:10 })
               .backgroundColor(this.themeColor)
               .enabled(this.isStartCover ?false:true)
               .onClick(() => {
@@ -336,10 +339,10 @@ export struct ScanFilePage{
               .alignSelf(ItemAlign.Center)
 
             Button($r('app.string.sync_data'), { type: ButtonType.Capsule, stateEffect: false })
-              .width(180)
+              .width(150)
               .height(55)
               .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
-              .margin({ top: 10, bottom: 20 })
+              .margin({ left:10,top: 10, bottom: 10 })
               .backgroundColor(this.themeColor)
               .enabled(this.isStartSync ?false:true)
               .onClick(() => {
@@ -411,7 +414,7 @@ export struct ScanFilePage{
           .backgroundColor($r('app.color.title_bar_bg'))//.linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
           .height(50)
           .layoutWeight(1)
-          .stateEffect(true)
+          .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
           .margin({ right: 6 })
           .onClick(() => {
             DialogHelper.closeDialog('tips'); //关闭弹框
@@ -421,7 +424,7 @@ export struct ScanFilePage{
           .layoutWeight(1)
           .height(50)
           .backgroundColor($r('app.color.title_bar_bg'))
-          .stateEffect(true)
+          .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
           .margin({ left: 6 })
           .onClick(() => {
             DialogHelper.closeDialog('tips'); //关闭弹框

+ 30 - 2
entry/src/main/ets/pages/SettingPage.ets

@@ -56,6 +56,7 @@ export struct SettingPage {
   public static IS_PLAYLIST_BG_GRASS: string = 'isPlayListBgGrass';
   static readonly IS_SWIPE: string = 'isSwipe'
   static readonly IS_AUTO_HIDE_PROGRESS: string = 'IS_AUTO_HIDE_PROGRESS';
+  public static OPEN_SKIPSONG_ANIMATE: string = 'openSkipSongAnimate';
 
   public static THEME_COLOR_LIST: Array<ThemeColorItem> = [
     { name: '玫瑰粉', color: '#FF4081', isVip: false },
@@ -114,6 +115,7 @@ export struct SettingPage {
   @State isSwipe: boolean = false //listItem的左滑开关
   @State isPlayListBgGrass: boolean = true//是否播放列表玻璃透明效果
   @State is_auto_hide_progress: boolean = false
+  @State openSkipSongAnimate: boolean = true//切歌动画效果
 
 
   @State customizeBgPath: string | undefined = '';
@@ -235,6 +237,7 @@ export struct SettingPage {
     this.isPlayListBgGrass = PreferencesUtil.getBooleanSync(SettingPage.IS_PLAYLIST_BG_GRASS, true)
     this.isSwipe = PreferencesUtil.getBooleanSync(SettingPage.IS_SWIPE, true)
     this.is_auto_hide_progress = PreferencesUtil.getBooleanSync(SettingPage.IS_AUTO_HIDE_PROGRESS, false)
+    this.openSkipSongAnimate = PreferencesUtil.getBooleanSync(SettingPage.OPEN_SKIPSONG_ANIMATE, true)
     // 只用 themeMode 控制主题
     this.themeMode = PreferencesUtil.getNumberSync(SettingPage.THEME_MODE, 0)
     this.applyThemeMode(this.themeMode)
@@ -535,8 +538,8 @@ export struct SettingPage {
         // 左侧返回按钮
         Row() {
           Image($r('app.media.menu'))
-            .width(29)
-            .height(29)
+            .width(26)
+            .height(26)
             .margin({ left: 12, right: 8 })
             .onClick(() => {
               animateTo({ duration: 555 }, () => {
@@ -842,6 +845,31 @@ export struct SettingPage {
                 curve: 'ease-in-out' // 可选动画曲线
               })
 
+            Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
+
+            // 切歌动画效果
+            Row() {
+              Text('切歌动画效果')
+                .margin({ left: 18 })
+                .fontSize(15)
+                .fontColor(Color.Gray)
+                .fontWeight(480)
+                .layoutWeight(1)
+              Toggle({ type: ToggleType.Switch, isOn: this.openSkipSongAnimate })
+                .selectedColor(this.themeColor)
+                .switchPointColor(Color.White)
+                .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
+                .margin({ right: 18 })
+                .onChange((checked: boolean) => {
+                  this.openSkipSongAnimate = checked;
+                  PreferencesUtil.put(SettingPage.OPEN_SKIPSONG_ANIMATE, this.openSkipSongAnimate)
+                  this.sendChangeEvent()
+                })
+                .width(50)
+                .height(30);
+            }
+            .height(55)
+            .clickEffect({ level: ClickEffectLevel.HEAVY })
 
             Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
 

+ 5 - 1
entry/src/main/ets/pages/SplashIndex.ets

@@ -384,10 +384,14 @@ struct  SplashIndex{
                 params:{ titleName:'ICP备案',webUrl:CommonConstants.ICP_URL}
               });
             })
-          Text(this.appName)
+          Text('无损音乐播放器')
             .fontColor(Color.Grey)
             .fontSize(18)
             .margin({top:20})
+          // Text(this.appName)
+          //   .fontColor(Color.Grey)
+          //   .fontSize(18)
+          //   .margin({top:20})
           Text(CommonConstants.ICP_NO)
             .fontColor(Color.Grey)
             .fontSize(9)

+ 2 - 2
entry/src/main/ets/pages/UserCenter.ets

@@ -412,8 +412,8 @@ export struct UserCenter {
           // 左右按钮
           Row() {
             Image($r('app.media.menu'))
-              .width(32)
-              .height(32)
+              .width(26)
+              .height(26)
               .margin({ left: 12, right: 8 })
               .onClick(() => {
                 animateTo({ duration: 555 }, () => {

+ 307 - 160
entry/src/main/ets/view/LocalMusic.ets

@@ -76,6 +76,7 @@ import app from '@system.app';
 import { TextNodeController } from './PipLyricTextBuilder';
 import { IndexerView } from './IndexerView';
 import { KeyCode } from '@kit.InputKit';
+import { KnockController } from '../controller/KnockController';
 // import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
 const TAG = 'LocalMusic';
 
@@ -137,6 +138,8 @@ const ITEM_HEIGHT_BIG: number = 78; // 列表项大高度
 @Preview
 @Component
 export struct LocalMusic {
+  @State opacityValueImage: number = 1;
+  @State tipPopup:boolean = false
   @Consume mType: number;
   @StorageProp('themeColor') themeColor: string =
     PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
@@ -192,6 +195,7 @@ export struct LocalMusic {
   @State isMemoryLastPlay: boolean = false //是否启用应用退出记忆最后一首的播放进度
   @State isCoverTopBig: boolean = false //顶部大封面部分手机显示会和播放控制页重叠
   @State isSwipe: boolean = false //listItem的左滑开关
+  @State openSkipSongAnimate: boolean = true//切歌动画效果
   @State customizeBgPath: string | undefined = '';
   @State isDarkMode: boolean = false
   @State lyricTextWeight: number = 400
@@ -206,6 +210,7 @@ export struct LocalMusic {
   @StorageProp('windowWidth') windowWidth: number = 0;
   @StorageProp('windowHeight') windowHeight: number = 0;
   @StorageProp('isHiCarStatus') isHiCarStatus: boolean = false;
+  private UNKONWN:string = '';
   private listArea: Area = {
     width: 0,
     height: 0,
@@ -286,6 +291,7 @@ export struct LocalMusic {
   @Consume isFavMusic: boolean
   @State isClickedPLayAll: boolean = false;
   private scrollerForlist: ListScroller = new ListScroller();
+  private knockController: KnockController | undefined = undefined;
   imagesF: ImageFrameInfo[] = [
     { src: $r("app.media.app_loading0") },
     { src: $r("app.media.app_loading1") },
@@ -359,13 +365,13 @@ export struct LocalMusic {
   @State appName: string = ''
   @State isHasDir: boolean = false
   @State packName: string = ''
-  context = getContext(this);
+  context =  this.getUIContext().getHostContext() as common.UIAbilityContext
   @State titleBarModel: TitleBar.Model = new TitleBar.Model()
     .setTitleTextStyle(FontStyle.Normal)
     .setTitleBarStyle(TitleBar.BarStyle.TRANSPARENT)
     .setLeftIcon($r('app.media.menu'))
-    .setLeftIconWidth(25)
-    .setLeftIconHeight(25)
+    .setLeftIconWidth(26)
+    .setLeftIconHeight(26)
     .setTitleName('首页')
     .setTitleFontSize(18)
     .setTitleFontColor(Color.White)
@@ -376,9 +382,9 @@ export struct LocalMusic {
     .setOnRightClickListener(() => {
       this.showSheelDialog()
     })
-    .setOnTitleClickListener(() => {
-      this.showPupDialog()
-    })
+    // .setOnTitleClickListener(() => {
+    //   this.showPupDialog()
+    // })
     .setOnLeftClickListener(() => {
       this.doSwipBack()
     })
@@ -447,7 +453,12 @@ export struct LocalMusic {
 
   // 组件生命周期
   aboutToAppear() {
+    if(PreferencesUtil.getBooleanSync('isFirstTiped',true)){
+      this.tipPopup = !this.tipPopup
+      PreferencesUtil.putSync('isFirstTiped',false)
+    }
     this.initSetting()
+    this.UNKONWN = Utility.resourceToString(this.context, $r('app.string.unknown'));
     this.topRectHeight = px2vp(AppUtil.getStatusBarHeight());
     Utility.getAppName(getContext(this)).then((appName: string) => {
       this.appName = appName
@@ -535,7 +546,7 @@ export struct LocalMusic {
     this.themeColor = themeColor;
     this.doChangeSetting()
     this.windowClass.on('windowSizeChange', (size) => {
-      // LogUtil.info('onecold  windowSizeChange')
+      LogUtil.info('onecold  windowSizeChange')
       this.doChangeBarHeight()
       let viewWidth = px2vp(size.width);
       let viewHeight = px2vp(size.height);
@@ -560,6 +571,7 @@ export struct LocalMusic {
 
   startAutoHide() {
     if(PreferencesUtil.getBooleanSync(SettingPage.IS_AUTO_HIDE_PROGRESS,false)){
+      console.info('onecold  startAutoHide')
       this.is_auto_hide_progress = false
       setTimeout(() => {
         this.is_auto_hide_progress = true
@@ -609,6 +621,7 @@ export struct LocalMusic {
     this.isShowHeader = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_HEADER, true)
     this.volume = PreferencesUtil.getNumberSync('DefalutVolume', this.volume)
     this.isSwipe = PreferencesUtil.getBooleanSync(SettingPage.IS_SWIPE, true)
+    this.openSkipSongAnimate = PreferencesUtil.getBooleanSync(SettingPage.OPEN_SKIPSONG_ANIMATE, true)
     //如果是hicar连接状态,这些都是false
     if(this.isHiCarStatus){
       this.isShowTitleBar = false//不显示导航栏
@@ -662,6 +675,7 @@ export struct LocalMusic {
   }
 
   onPageShow() {
+    this.knockController?.immersiveListening();
     app.setImageCacheCount(100);
     // 设置解码前图片数据内存缓存上限为100MB (100MB=100*1024*1024B=104857600B)
     app.setImageRawDataCacheSize(104857600);
@@ -739,8 +753,21 @@ export struct LocalMusic {
 
     }
 
+    // let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
+    //碰一碰分享的监听
+    this.knockController = KnockController.getInstance(this.context);
+    this.knockController?.immersiveListening();
+
   }
 
+
+
+  onPageHide(): void {
+    this.knockController?.immersiveDisableListening();
+  }
+
+
+
   @State isFirstStartPlay: boolean = false
 
   //获取download_path
@@ -789,8 +816,7 @@ export struct LocalMusic {
         this.videoUrl = this.currentSong.filePath
         this.name = this.currentSong.name
         this.cover = this.currentSong.pixelMapPath
-
-
+        AppStorage.setOrCreate('currentSong',this.currentSong) ;
       } else {
         this.name = '空空如也'
       }
@@ -828,6 +854,8 @@ export struct LocalMusic {
   // 组件消失生命周期
   aboutToDisappear() {
     console.info('LifeCycleComponent aboutToDisappear');
+    this.knockController?.immersiveDisableListening();
+    this.curIndex = 0
     emitter.off(2);
     emitter.off(101);
     emitter.off(888);
@@ -915,7 +943,7 @@ export struct LocalMusic {
         // Utility.doSortListAscending(directories)
 
       } else {
-        if (this.currentPath === this.lockPath) {
+        if (this.currentPath === this.lockPath&&Utility.isMeidaByExtension(path)) {
           let item: VideoItem =
             await Utility.uriGetMusicAssetsFromFile(this.context, path, CommonConstants.TYPE_LOCAL, false);
           if (!path.endsWith('.lrc') && Utility.isMeidaByExtension(path) && !path.endsWith('.srt')) {
@@ -991,6 +1019,7 @@ export struct LocalMusic {
         }
         let item2 = new VideoItem(Utility.getMediaNameByUri(destPath), destPath, destPath, 0, 0, '')
         this.doPlay(item2)
+        this.isShowPlay = true
       }
 
 
@@ -1054,41 +1083,7 @@ export struct LocalMusic {
 
   }
 
-  //获取视频缩略图头像
-  async updatePixelMaps(curPath: string) {
-    console.info('updatePixelMaps: ', curPath);
-    const updatedList = [...this.videoLocalList]; // 创建一个新的列表
 
-    for (const videoItem of updatedList) {
-      if (videoItem.type === CommonConstants.TYPE_LOCAL) {
-        let pixelMap: image.PixelMap | undefined = undefined;
-        const uri = videoItem.filePath;
-
-        // 获取缩略图
-        // if (Utility.isVideoByExtension(uri)) {
-        //   pixelMap = await Utility.getFetchFrameByTime(uri);
-        // } else {
-        //   pixelMap = await Utility.getFetchMetadataFromFdSrcByPromise(uri);
-        // }
-        let name = await MD5.digestSync(uri)
-        let imagePath = this.context.filesDir + FileUtil.separator + name
-        console.info('onecold release success. name= ' + name);
-        imagePath = fileUri.getUriFromPath(imagePath)
-        videoItem.pixelMapPath = imagePath
-        // videoItem.pixelMap = pixelMap;
-        // videoItem.pixelMapToString = pixelMap ? await ImageUtil.pixelMapToBase64StrBig(pixelMap) : undefined;
-      }
-
-    }
-    // console.info('updatePixelMaps完毕: ', updatedList.length);
-    this.updateListData(updatedList)
-    // this.videoLocalList = updatedList; // 重新赋值以触发更新
-    // 缓存结果
-    this.addCache(curPath, updatedList);
-    await this.saveCacheToStorage(); // 保存缓存至本地存储
-
-
-  }
 
   //排序模式和多选模式
   showPupDialog() {
@@ -1238,6 +1233,7 @@ export struct LocalMusic {
       transition: AnimationHelper.transitionInDown(555),
       onAction: (index) => {
         this.doSortType(index)
+        PreferencesUtil.put(SettingPage.SORT_TYPE, index)
         this.updateListData(this.videoLocalList, true)
       }
     })
@@ -1966,11 +1962,6 @@ export struct LocalMusic {
               controller: this.xcomponentController
 
             })
-              .onLoad((event?: object) => {
-                if (!!event) {
-                  this.initDelayPlay(event);
-                }
-              })
               .onLoad((event?: object) => {
                 if (!!event) {
                   this.initDelayPlay(event);
@@ -2184,7 +2175,6 @@ export struct LocalMusic {
       .backdropBlur(this.blurValue)
       .backgroundBrightness({ rate: this.isCustomizeBg ? 0.1 : 0, lightUpDegree: this.bgBrightness })
       .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
-
     }
 
   }
@@ -2598,6 +2588,19 @@ export struct LocalMusic {
                 })
               )
             Row() {
+              Column(){
+                Text(item.md5Str?.includes('Lossless')?
+                   Utility.resourceToString(this.context,$r('app.string.lossless')):item.md5Str)//音质
+                  .fontSize(this.twoFingerType == 1 ? 8 : this.twoFingerType == 2 ? 9 : 11)
+                  .padding({ top: 3,right:6,left:6,bottom:3 })
+                  .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
+                  $r('app.color.text_color'))
+                  .fontWeight(500)
+                  .borderRadius(12)
+                  .margin({ left: this.twoFingerType == 3 ? 6 : 8 })
+                  .backgroundColor('#FFC107')
+              }
+              .padding({ top: 8 })
               Text(StrUtil.isEmpty(item.artist) ? item.cTime : item.artist + '  ' + item?.album)
                 .fontSize(this.twoFingerType == 1 ? 11 : this.twoFingerType == 2 ? 12 : 14)
                 .padding({ top: 8 })
@@ -2759,7 +2762,6 @@ export struct LocalMusic {
 
   @State currentTitleName: string = '' //点击歌单,艺术家,专辑进去后的标题
   @State currentTitleCover: string | ResourceStr = '' //点击歌单,艺术家,专辑进去后的封面
-  @State currentYear:string = ''
   isShowCoverHeader() {
     if (!this.isShowHeader) {
       return false
@@ -2830,7 +2832,7 @@ export struct LocalMusic {
 
           }
           .alignItems(HorizontalAlign.Start)
-          .margin({ left: 30, top: 10, bottom: 15 })
+          .margin({ left: 30, top: 3, bottom: 15 })
 
           Column() {
             Column() {
@@ -2842,32 +2844,53 @@ export struct LocalMusic {
                 .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
               if (this.modeType == 3 && ArrayUtil.isNotEmpty(this.videoLocalList)) {
                 Text(`艺术家:${this.videoLocalList[0].artist}`)
-                  .fontSize(16)
+                  .fontSize(14)
                   .padding({ top: 8 })
                   .maxLines(1)
                   .fontWeight(FontWeight.Bold)
                   .fontColor($r('app.color.text_color'))
                   .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
+                if(this.videoLocalList[0].genre){
+                  Text(`风格:${this.videoLocalList[0].genre}`)
+                    .fontSize(14)
+                    .padding({ top: 8 })
+                    .maxLines(1)
+                    .visibility(StrUtil.isEmpty(this.videoLocalList[0].genre)||
+                    this.videoLocalList[0].genre.includes(this.UNKONWN)
+                      ?Visibility.None:Visibility.Visible)
+                    .fontWeight(FontWeight.Bold)
+                    .fontColor($r('app.color.text_color'))
+                    .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
+                }
+                if(this.videoLocalList[0].year){
+                  Text(`发行时间:${this.videoLocalList[0].year}`)
+                    .fontSize(14)
+                    .padding({ top: 8 })
+                    .maxLines(1)
+                    .visibility(StrUtil.isEmpty(this.videoLocalList[0].year)||
+                       this.videoLocalList[0].year.includes(this.UNKONWN)
+                      ?Visibility.None:Visibility.Visible)
+                    .fontWeight(FontWeight.Bold)
+                    .fontColor($r('app.color.text_color'))
+                    .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
+                }
+
 
-                Text(this.currentYear)
-                  .fontSize(16)
-                  .padding({ top: 8 })
-                  .maxLines(1)
-                  .fontWeight(FontWeight.Bold)
-                  .fontColor($r('app.color.text_color'))
-                  .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
               }
-              Row() {
-                Text(`共${this.videoLocalList.length}首歌`)
-                  .fontSize(13)
-                  .fontWeight(FontWeight.Bold)
-                  .padding({ top: 8 })
-                  .fontColor($r('app.color.text_color'))
-                  .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
-                Blank()
+              if(this.modeType != 3){
+                Row() {
+                  Text(`共${this.videoLocalList.length}首歌`)
+                    .fontSize(13)
+                    .fontWeight(FontWeight.Bold)
+                    .padding({ top: 8 })
+                    .fontColor($r('app.color.text_color'))
+                    .margin({ left: this.currentLyricAlignMode === 0 ? 18 : 0 })
+                  Blank()
 
+                }
               }
 
+
             }
             .height('100%')
             .width('100%')
@@ -3122,8 +3145,11 @@ export struct LocalMusic {
             if (this.isFavMusic) {
               this.getFavList(true)
             } else {
-              this.deleteCache(this.currentPath)
-              this.getSortedFiles(this.currentPath)
+              if(this.modeType == 0){
+                this.asyncCurrentPathData()
+              }else if(this.modeType ==1){
+                workerInstance.postMessage({ code: 2, data: this.context });
+              }
             }
           })
 
@@ -3177,6 +3203,17 @@ export struct LocalMusic {
           })
           .fillColor(this.themeColor)
           .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.6 })
+          .bindPopup($$this.tipPopup, {
+            builder: this.popupBuilder,
+            placement: Placement.Bottom,
+            maskColor: 0x33000000,
+            enableArrow: true,
+            onStateChange: (e) => {
+              if (!e.isVisible) {
+                this.tipPopup = false;
+              }
+            }
+          })
           .onClick(() => {
             this.isGridMusic = !this.isGridMusic
           })
@@ -3195,6 +3232,21 @@ export struct LocalMusic {
 
   }
 
+  // 第二步:popup构造器定义弹框内容
+  @Builder popupBuilder() {
+    Column({ space: 2 }) {
+      Text('友情提示:双指缩放可以放大缩小列表')
+        .fontSize(12)
+        .fontWeight(FontWeight.Regular)
+        .fontColor($r('app.color.text_color'))
+    }
+    .justifyContent(FlexAlign.SpaceAround)
+    .width(220)
+    .height(55)
+    .padding(15)
+  }
+
+
   //搜索功能的实现
   @State searchText: string = ''; // 用户输入内容
   @State filteredList: Array<VideoItem> = []; // 过滤后的结果
@@ -3446,8 +3498,8 @@ export struct LocalMusic {
       .animation({ duration: 500, curve: Curve.Ease }))
     // .margin({ bottom: this.isCoverOpacity() ? 80 : 175 })
     .margin({
-      bottom: this.isCoverOpacity() ? (this.isShowCoverHeader() ? 45 : 80)
-        : (this.isShowCoverHeader() ? 95 : 178)
+      bottom: this.isCoverOpacity() ? (this.isShowCoverHeader() ? this.topBarHeight+30 : this.topBarHeight+90)
+        : (this.isShowCoverHeader() ? this.topBarHeight+45 : this.topBarHeight+128)
     })
     .layoutWeight(1)
     .scrollBar(BarState.Off)
@@ -3551,7 +3603,7 @@ export struct LocalMusic {
         this.isGridMusic = false
       }
     }
-
+    PreferencesUtil.put(SettingPage.TWO_FINGER_TYPE, this.twoFingerType)
     this.pinchValue = 1;
     this.scaleValue = 1;
   }
@@ -3611,17 +3663,36 @@ export struct LocalMusic {
                 .fontSize(this.twoFingerType == 1 ? 10 : this.twoFingerType == 2 ? 12 : 14)
                 .visibility(this.modeType === 3 && !this.isCanBack ? Visibility.Visible : Visibility.None)
                 .fontColor($r('app.color.text_color'))
-              Text(StrUtil.isEmpty(item.artist) ? 'Unknown' : item.artist)
-                .fontSize(11)
-                .fontSize(this.twoFingerType == 1 ? 10 : this.twoFingerType == 2 ? 12 : 14)
-                .maxLines(1)
-                .margin({ top: 2 })
-                .visibility(item.type == CommonConstants.TYPE_IS_ARTIST
-                  || item.type == CommonConstants.TYPE_IS_ALBUM
-                  || item.type == CommonConstants.TYPE_IS_DIR ? Visibility.None : Visibility.Visible)
-                .fontWeight(FontWeight.Medium)
-                .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
-                $r('app.color.text_color'))
+              Row(){
+                Column(){
+                  Text(item.md5Str?.includes('Lossless')?
+                  Utility.resourceToString(this.context,$r('app.string.lossless')):item.md5Str)//音质
+                    .fontSize(this.twoFingerType == 1 ? 8 : this.twoFingerType == 2 ? 9 : 11)
+                    .padding({ top: 3,right:6,left:6,bottom:3 })
+                    .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
+                    $r('app.color.text_color'))
+                    .fontWeight(500)
+                    .borderRadius(12)
+                    .margin({ left: this.twoFingerType == 3 ? 6 : 8 })
+                    .backgroundColor('#FFC107')
+                }
+                .margin({ top: 2 ,right:6})
+                .visibility((this.modeType == 3 && !this.isCanBack)||(this.modeType == 2 && !this.isCanBack)
+                     ||(this.modeType == 0&&item.type==CommonConstants.TYPE_IS_DIR)? Visibility.None : Visibility.Visible)
+                Text(StrUtil.isEmpty(item.artist) ? item.duration: item.artist)
+                  .fontSize(11)
+                  .fontSize(this.twoFingerType == 1 ? 10 : this.twoFingerType == 2 ? 12 : 14)
+                  .maxLines(1)
+                  .textOverflow({ overflow: TextOverflow.MARQUEE })//超长滚动
+                  .margin({ top: 2 ,right:18})
+                  .visibility(item.type == CommonConstants.TYPE_IS_ARTIST
+                    || item.type == CommonConstants.TYPE_IS_ALBUM
+                    || item.type == CommonConstants.TYPE_IS_DIR ? Visibility.None : Visibility.Visible)
+                  .fontWeight(FontWeight.Medium)
+                  .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
+                  $r('app.color.text_color'))
+              }
+
 
             }
             .alignItems(HorizontalAlign.Center) // 关键:使内容水平居中
@@ -3885,6 +3956,7 @@ export struct LocalMusic {
 
       }
     }
+    PreferencesUtil.put(SettingPage.TWO_FINGER_TYPE, this.twoFingerType)
     this.pinchValue = 1;
     this.scaleValue = 1;
   }
@@ -4062,8 +4134,8 @@ export struct LocalMusic {
       }))
     // .divider({ strokeWidth: 1, color: this.isDarkMode? '#333333':'#ffe9f0f0' })
     .margin({
-      bottom: this.isCoverOpacity() ? (this.isShowCoverHeader() ? 25 : 80)
-        : (this.isShowCoverHeader() ? 85 : this.isHiCarSmall()?140:175)
+      bottom: this.isCoverOpacity() ? (this.isShowCoverHeader() ? this.topBarHeight+25 : this.topBarHeight+80)
+        : (this.isShowCoverHeader() ? this.topBarHeight+35 : this.isHiCarSmall()?this.topBarHeight+90:this.topBarHeight+125)
     })
     .cachedCount(6)
     .borderRadius(20)
@@ -4343,6 +4415,11 @@ export struct LocalMusic {
           this.titleBarModel.setLeftIconMain($r('app.media.left_back_white'))
         }
 
+        //进入歌单的时候的滚动位置在顶部
+        if (this.isGridMusic) {
+          this.scroller.scrollToIndex(0)
+        }
+
         break;
       case CommonConstants.TYPE_IS_ALBUM:
         // 进入专辑前安全保存当前滚动偏移量,支持列表和网格
@@ -4370,7 +4447,6 @@ export struct LocalMusic {
           this.isCanBack = true
           this.titleBarModel.setTitleName(item.name)
           this.currentTitleName = '专辑:' + item.name
-          this.currentYear = '发行时间:' + item.year
           if (item.pixelMapPath) {
             this.currentTitleCover = item.pixelMapPath
           }
@@ -4378,6 +4454,10 @@ export struct LocalMusic {
           this.titleBarModel.setLeftIconMain($r('app.media.left_back_white'))
           this.mScrollMap.set(item.name, this.selectedIndex)
         }
+        //进入歌单的时候的滚动位置在顶部
+        if (this.isGridMusic) {
+          this.scroller.scrollToIndex(0)
+        }
 
         break;
       case CommonConstants.TYPE_IS_CSJAD:
@@ -4397,11 +4477,12 @@ export struct LocalMusic {
           let globalVideoList = Utility.getGlobalList(this.videoLocalList, CommonConstants.TYPE_LOCAL) as VideoItem[];
           this.curIndex = Utility.getCurIndexFromGlobalList(globalVideoList, item.filePath)
           this.songList = globalVideoList
+
           this.sonDataSource.pushArrayData(this.songList)
           this.currentSong = globalVideoList[this.curIndex]
         }
 
-
+        AppStorage.setOrCreate('currentSong',this.currentSong) ;
         this.videoUrl = this.currentSong.filePath
         this.name = this.currentSong.name
         this.cover = this.currentSong.pixelMapPath
@@ -4490,7 +4571,7 @@ export struct LocalMusic {
             })
               .color(this.themeColor)// 进度条前景色为灰色
               .backgroundColor($r('app.color.index_background'))
-              .height(36)
+              .height(40)
               .aspectRatio(CommonConstants.ASPECT_RATIO)
             Image(this.CONTROL_PlayStatus === PlayStatus.PLAY ? $r('app.media.hm_pause') : $r('app.media.hm_play2'))
               .height(38)
@@ -5053,6 +5134,21 @@ export struct LocalMusic {
         .margin({ top: 10, bottom: 10 })
         .justifyContent(FlexAlign.Start)
 
+        Row() {
+          Text('风格:')
+            .fontSize(14)
+            .fontColor(Color.White)
+            .margin({ left: 22 })
+          Text(currentItem.genre)
+            .fontSize(14)
+            .margin({ left: 10 })
+            .fontColor(Color.White)
+            .layoutWeight(1)
+        }
+        .width('100%')
+        .margin({ top: 10, bottom: 10 })
+        .justifyContent(FlexAlign.Start)
+
         Row() {
           Text('发行时间:')
             .fontSize(14)
@@ -5084,11 +5180,11 @@ export struct LocalMusic {
         .justifyContent(FlexAlign.Start)
 
         Row() {
-          Text('音轨:')
+          Text('音轨:')
             .fontSize(14)
             .fontColor(Color.White)
             .margin({ left: 22 })
-          Text(StrUtil.isEmpty(currentItem.trackCount)?'1':currentItem.trackCount)
+          Text(currentItem.track)
             .fontSize(14)
             .margin({ left: 10 })
             .fontColor(Color.White)
@@ -5098,6 +5194,7 @@ export struct LocalMusic {
         .margin({ top: 10, bottom: 10 })
         .justifyContent(FlexAlign.Start)
 
+
         Row() {
           Text('格式:')
             .fontSize(14)
@@ -5128,6 +5225,8 @@ export struct LocalMusic {
         .margin({ top: 10, bottom: 10 })
         .justifyContent(FlexAlign.Start)
 
+
+
         Row() {
           Text('流数量:')
             .fontSize(14)
@@ -5454,6 +5553,7 @@ export struct LocalMusic {
       .width(40)
       .height(40)
       .type(ButtonType.Circle)
+      .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
       .backgroundColor(this.themeColor)
       .margin(5)
       .onClick(() => {
@@ -5467,6 +5567,7 @@ export struct LocalMusic {
       }
       .width(40)
       .height(40)
+      .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
       .type(ButtonType.Circle)
       .backgroundColor(this.themeColor)
       .margin(5)
@@ -5482,6 +5583,7 @@ export struct LocalMusic {
       }
       .width(40)
       .height(40)
+      .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
       .type(ButtonType.Circle)
       .backgroundColor(this.themeColor)
       .margin(5)
@@ -5660,12 +5762,25 @@ export struct LocalMusic {
               .maxLines(1)
               .margin({ left: this.twoFingerType == 3 ? 18 : 10 })
             Row() {
+              Column(){
+                Text(item.md5Str?.includes('Lossless')?
+                Utility.resourceToString(this.context,$r('app.string.lossless')):item.md5Str)//音质
+                  .fontSize(this.twoFingerType == 1 ? 8 : this.twoFingerType == 2 ? 9 : 11)
+                  .padding({ top: 3,right:6,left:6,bottom:3 })
+                  .fontColor(this.currentSong?.filePath === item.filePath ? this.themeColor :
+                  $r('app.color.text_color'))
+                  .fontWeight(500)
+                  .borderRadius(12)
+                  .margin({ left: this.twoFingerType == 3 ? 12 : 10 })
+                  .backgroundColor('#FFC107')
+              }
+              .padding({ top: 8 })
               Text(StrUtil.isEmpty(item.artist) ? item.cTime : item.artist + '  ' + item?.album)
                 .fontSize(this.twoFingerType == 1 ? 11 : this.twoFingerType == 2 ? 12 : 14)
                 .padding({ top: 8 })
                 .fontColor(this.curIndex === index ? this.themeColor :
                   this.isFrontWhite ? $r('app.color.playlistText_color') : $r('app.color.text_color'))
-                .margin({ left: this.twoFingerType == 3 ? 18 : 10 })
+                .margin({ left: this.twoFingerType == 3 ? 5 : 3 })
               Blank()
               Text(item.size)
                 .fontSize(this.twoFingerType == 1 ? 11 : this.twoFingerType == 2 ? 12 : 14)
@@ -5818,25 +5933,19 @@ export struct LocalMusic {
     // LogUtil.info('twocold this.currentWidthBreakpoint = '+this.currentWidthBreakpoint)
     LogUtil.info('hicar isPhoneLan width= ' + this.windowWidth);
     LogUtil.info('hicar isPhoneLan height= ' + this.windowHeight);
-    LogUtil.info(`twocold  hicarWindow size: ${this.windowWidth}x${this.windowHeight}, isHiCar: ${this.isHiCar()}`);
+    LogUtil.info(`twocold  hicarWindow size: ${this.windowWidth}x${this.windowHeight}, this.isHiCarStatus: ${this.isHiCarStatus}`);
     LogUtil.info(`twocold  hicar Window size: ${this.windowWidth}x${this.windowHeight}, isHiCarSmall: ${this.isHiCarSmall()}`);
-    if (this.isHiCar()) {
+    if (this.isHiCarStatus) {
       return false
     }
 
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentHeightBreakpoint == HeightBreakpoint.HEIGHT_SM
-      && this.currentWidthBreakpoint == WidthBreakpoint.WIDTH_MD) { //如果是手机横屏,返回true
+      && this.currentWidthBreakpoint == WidthBreakpoint.WIDTH_MD&&this.isLandscape) { //如果是手机横屏,返回true
 
       return true
     }
 
-    if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
-      && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0) {
-        return true
-      }
-    }
 
     return false
   }
@@ -5893,29 +6002,31 @@ export struct LocalMusic {
 
   isHiCar() {
 
-    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 / 720, name: "1920x720" },
-      { ratio: 1920 / 1080, name: "1920x1080" }
-    ];
-    const currentRatio: number = this.windowWidth / this.windowHeight;
-    const RATIO_TOLERANCE: number = 0.18; // 宽高比容差
-    LogUtil.info('twocold currentRatio = ' + currentRatio)
-
-    for (const hiCarRatio of hiCarAspectRatios) {
-      LogUtil.info('twocold hiCarRatio= ' + hiCarRatio.ratio)
-      LogUtil.info('twocold Math.abs(currentRatio - hiCarRatio.ratio)= ' + Math.abs(currentRatio - hiCarRatio.ratio))
-      if (Math.abs(currentRatio - hiCarRatio.ratio) <= RATIO_TOLERANCE) {
-        // LogUtil.info(`HiCar detected: ${hiCarRatio.name}, actual: ${this.windowWidth}x${this.windowHeight}`);
-        return true&&this.isHiCarStatus;
-      }
-    }
-
-    return false;
+    return this.isHiCarStatus;
+
+    // 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 / 720, name: "1920x720" },
+    //   { ratio: 1920 / 1080, name: "1920x1080" }
+    // ];
+    // const currentRatio: number = this.windowWidth / this.windowHeight;
+    // const RATIO_TOLERANCE: number = 0.18; // 宽高比容差
+    // LogUtil.info('twocold currentRatio = ' + currentRatio)
+    //
+    // for (const hiCarRatio of hiCarAspectRatios) {
+    //   LogUtil.info('twocold hiCarRatio= ' + hiCarRatio.ratio)
+    //   LogUtil.info('twocold Math.abs(currentRatio - hiCarRatio.ratio)= ' + Math.abs(currentRatio - hiCarRatio.ratio))
+    //   if (Math.abs(currentRatio - hiCarRatio.ratio) <= RATIO_TOLERANCE) {
+    //     // LogUtil.info(`HiCar detected: ${hiCarRatio.name}, actual: ${this.windowWidth}x${this.windowHeight}`);
+    //     return true&&this.isHiCarStatus;
+    //   }
+    // }
+    //
+    // return false;
   }
 
 
@@ -6098,7 +6209,11 @@ export struct LocalMusic {
     .backgroundBrightness({ rate: this.isPuraWP() ? 0.1 : 0, lightUpDegree: -0.1 })
     .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
     .onClick(() => {
-      this.startAutoHide()
+      // this.startAutoHide()
+      this.is_auto_hide_progress = false
+      setTimeout(() => {
+        this.is_auto_hide_progress = true
+      }, 6000)
     })
   }
 
@@ -6143,7 +6258,7 @@ export struct LocalMusic {
   private positionX: number = PlayConstants.POSITION_X;
   private positionY: number = PlayConstants.POSITION_Y;
   private windowClass: window.Window = globalThis.windowClass
-  @State volume: number = 0.5;
+  @State volume: number = 0.3;
   @State volumeShow: boolean = PlayConstants.VOLUME_SHOW;
   @State bright: number = PlayConstants.BRIGHT;
   @State brightShow: boolean = PlayConstants.BRIGHT_SHOW;
@@ -6235,7 +6350,7 @@ export struct LocalMusic {
       .setEmptyHint("")
       .setAnimationDuration(1000)
     this.currentLyricAlignMode = PreferencesUtil.getNumberSync('LyricAlignMode', 1)
-    this.blurDegree = PreferencesUtil.getNumberSync('setBlurDegree', 0)
+    this.blurDegree = PreferencesUtil.getNumberSync('setBlurDegree', 3)
     this.setBlurDegree(this.blurDegree, false)
     this.setLyricAlignMode(this.currentLyricAlignMode, false)
     this.setLyricTextSize(PreferencesUtil.getNumberSync('LyricTextSize', 18), false)
@@ -6468,7 +6583,7 @@ export struct LocalMusic {
       .setEmptyHint("")
       .setAnimationDuration(1000)
     this.currentLyricAlignModePip = PreferencesUtil.getNumberSync('LyricAlignModePip', 0)
-    this.blurDegreePip = PreferencesUtil.getNumberSync('setBlurDegreePip', 2)
+    this.blurDegreePip = PreferencesUtil.getNumberSync('setBlurDegreePip', 3)
     this.setBlurDegree(this.blurDegreePip, true)
     this.setLyricAlignMode(this.currentLyricAlignModePip, true)
     this.setLyricTextSize(PreferencesUtil.getNumberSync('LyricTextSizePip', 18), true)
@@ -6578,8 +6693,9 @@ export struct LocalMusic {
       return;
     }
     let bg = Utility.getMusisBg()
-
     this.imageLabel = bg
+
+
     ColorConversion.setSysBarLightBackground(true);
     this.context.resourceManager.getMediaContent(bg)
       .then((value: Uint8Array) => {
@@ -7050,13 +7166,13 @@ export struct LocalMusic {
         style: SliderStyle.OutSet
       })
         .width('600px')
-        .blockColor(Color.White)
-        .trackColor($r('app.color.track_color'))
+        .blockColor('rgba(255,255,255,1)')
+        .trackColor('rgba(255,255,255,0.3)')
         .selectedColor(Color.White)
         .trackThickness(PlayConstants.PROGRESS_TRACK_THICKNESS)
         .layoutWeight(1)
         .margin({ left: PlayConstants.PROGRESS_MARGIN_LEFT })
-        .showSteps(true)
+        .showSteps(false)
         .showTips(true)
         .enabled(this.slideEnable)
         .onChange((value: number, mode: SliderChangeMode) => {
@@ -7148,7 +7264,8 @@ export struct LocalMusic {
   @State is_auto_hide_progress: boolean = false //手机横屏自动隐藏播放进退条,点击屏幕可以显示,倒计时4秒后又自动隐藏
   @State isCoverRectangle: boolean = false
   @State isCoverTop: boolean = true
-
+  // 添加控制缩放的状态变量
+  @State scaleValueImage: number = 1
   @Builder
   CoverInfo() {
     Column() {
@@ -7166,8 +7283,8 @@ export struct LocalMusic {
       Stack() {
         // 唱片旋转效果
         Image($r('app.media.ic_music_disc'))
-          .width(250)
-          .height(250)
+          .width(245)
+          .height(245)
           .margin({ right: 20, left: 20 })
           .aspectRatio(1)
           .opacity(this.isCoverOpacity() || this.isCoverRectangle ? 0 : 1)
@@ -7191,19 +7308,17 @@ export struct LocalMusic {
 
         Column() {
           if (this.isCoverTop && !this.isCoverOpacity() && this.isCoverRectangle) {
-            Image(StrUtil.isEmpty(this.cover) ? this.imageLabel :
-            this.cover)// .height(this.isCoverOpacity() ? 250 : this.isCoverRectangle ? 320 : 162)
+            Image(StrUtil.isEmpty(this.cover) ? this.imageLabel : this.cover)// .height(this.isCoverOpacity() ? 250 : this.isCoverRectangle ? 320 : 162)
               .width(this.isBigScreen() ? '72%' : this.isCoverTopBig ? '100%' : '86%')
               .objectFit(this.isCoverRectangle ? ImageFit.Contain : ImageFit.Auto)
               .alt(this.imageLabel)
               .margin({ right: 8, left: 8, top: 8 })
               .aspectRatio(1)
+              .opacity(this.opacityValueImage)
+              .scale({ x: this.scaleValueImage, y: this.scaleValueImage }) // 添加缩放效果
+              .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.8 })
               .visibility(this.isPuraWP() ? Visibility.None : Visibility.Visible)
               .borderRadius(this.isCoverRectangle ? 20 : '100%')
-              .clickEffect({ level: ClickEffectLevel.MIDDLE })
-              .transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 1.2, y: 1.2 })
-                .animation({ duration: 500 }),
-                TransitionEffect.scale({ x: 0, y: 0 })))
               .align(Alignment.Center)//
               .clip(true)
               .rotate({
@@ -7224,12 +7339,11 @@ export struct LocalMusic {
               .alt(this.imageLabel)
               .margin({ right: 20, left: 20 })
               .aspectRatio(1)
+              .opacity(this.opacityValueImage)
+              .scale({ x: this.scaleValueImage, y: this.scaleValueImage }) // 添加缩放效果
               .visibility(this.isPuraWP() ? Visibility.None : Visibility.Visible)
               .borderRadius(this.isCoverRectangle ? 20 : '100%')
-              .clickEffect({ level: ClickEffectLevel.MIDDLE })
-              .transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 1.2, y: 1.2 })
-                .animation({ duration: 500 }),
-                TransitionEffect.scale({ x: 0, y: 0 })))
+              .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.8 })
               .align(Alignment.Center)//
               .clip(true)
               .rotate({
@@ -7334,11 +7448,13 @@ export struct LocalMusic {
         .textOverflow({ overflow: TextOverflow.MARQUEE })//超长滚动
         .fontColor(Color.White)
         .textAlign(TextAlign.Center)
+        .visibility(StrUtil.isEmpty(this.artist)?Visibility.None:Visibility.Visible)
         .width('99%')
         .maxLines(1)
     }
     .margin({ top: this.isCoverOpacity() ? 20 : isHidden ? 40 : 20 })
     .zIndex(1)
+    .scale({ x: this.scaleValueImage, y: this.scaleValueImage }) // 添加缩放效果
     .visibility(this.isCoverOpacity() || isHidden ? Visibility.None : Visibility.Visible)
   }
 
@@ -7908,8 +8024,8 @@ export struct LocalMusic {
           .fontColor(Color.White)
         Slider({
           value: isPip ? this.currentLyricLineSpacePip : this.currentLyricLineSpace,
-          min: 2,
-          max: 120,
+          min: 0,
+          max: 100,
           step: 1,
           style: SliderStyle.OutSet
         })
@@ -7978,7 +8094,7 @@ export struct LocalMusic {
           Slider({
             value: isPip ? this.blurDegreePip : this.blurDegree,
             min: 0,
-            max: 10,
+            max: 5,
             step: 0.1,
             style: SliderStyle.OutSet
           })
@@ -9505,7 +9621,8 @@ export struct LocalMusic {
           } else {
             this.getImageColor();
           }
-
+          //保存碰一碰分享的当前的歌曲
+          AppStorage.setOrCreate('currentSong',this.currentSong) ;
 
           let lyricPath = this.videoUrl.substring(0, this.videoUrl.lastIndexOf('.')) + '.lrc'
 
@@ -10313,11 +10430,44 @@ export struct LocalMusic {
       this.stop();
       this.currentSong = this.songList[this.curIndex]
       this.videoUrl = this.songList[this.curIndex].filePath;
-      this.cover = this.songList[this.curIndex].pixelMapPath
       this.artist = this.songList[this.curIndex].artist
       this.name = this.songList[this.curIndex].name
-      this.startPlayOrResumePlay()
+      //this.cover = this.songList[this.curIndex].pixelMapPath
+      this.changeImageAnimation()
+
+    }
 
+  }
+
+  changeImageAnimation() {
+    if(this.openSkipSongAnimate){
+      // 第一步:淡出动画
+      this.getUIContext()?.animateTo({
+        duration: 500,
+        curve: Curve.EaseOut,
+      }, () => {
+        this.opacityValueImage = 0.1;
+        if(this.isCoverRectangle){
+          this.scaleValueImage = 0.88
+        }
+
+      });
+
+      // 第二步:切换图片后淡入
+      setTimeout(() => {
+        this.cover = this.songList[this.curIndex].pixelMapPath
+        this.getUIContext()?.animateTo({
+          duration: 500,
+          curve: Curve.EaseIn,
+        }, () => {
+          this.opacityValueImage = 1;
+          this.scaleValueImage = 1 // 图标恢复到原始大小
+          this.startPlayOrResumePlay()
+        });
+      }, 500);
+    }else{
+      this.cover = this.songList[this.curIndex].pixelMapPath
+      this.startPlayOrResumePlay()
     }
 
   }
@@ -10369,9 +10519,9 @@ export struct LocalMusic {
       this.currentSong = this.songList[this.curIndex];
       this.videoUrl = this.songList[this.curIndex].filePath;
       this.name = this.songList[this.curIndex].name;
-      this.cover = this.songList[this.curIndex].pixelMapPath
       this.artist = this.songList[this.curIndex].artist
-      this.startPlayOrResumePlay();
+      // this.cover = this.songList[this.curIndex].pixelMapPath
+      this.changeImageAnimation()
     }
   }
 
@@ -10386,14 +10536,14 @@ export struct LocalMusic {
       this.currentSong = this.songList[this.curIndex]
       this.videoUrl = this.songList[index].filePath;
       this.name = this.songList[index].name
-      this.cover = this.songList[this.curIndex].pixelMapPath
       this.artist = this.songList[this.curIndex].artist
       this.curIndex = index;
-      this.startPlayOrResumePlay()
+      this.changeImageAnimation()
     }
 
   }
 
+
   //上一个
   private playPrevious() {
     if (!this.debounce()) {
@@ -10414,9 +10564,8 @@ export struct LocalMusic {
     this.currentSong = this.songList[this.curIndex]
     this.videoUrl = this.songList[this.curIndex].filePath;
     this.name = this.songList[this.curIndex].name
-    this.cover = this.songList[this.curIndex].pixelMapPath
     this.artist = this.songList[this.curIndex].artist
-    this.startPlayOrResumePlay()
+    this.changeImageAnimation()
   }
 
   //随机播放模式下点击上一首: 上一首应该应该播放历史记录的第二首
@@ -10444,11 +10593,9 @@ export struct LocalMusic {
       this.stop();
       this.currentSong = this.songList[this.curIndex];
       this.videoUrl = this.songList[this.curIndex].filePath;
-      this.cover = this.songList[this.curIndex].pixelMapPath
       this.artist = this.songList[this.curIndex].artist
       this.name = this.songList[this.curIndex].name;
-
-      this.startPlayOrResumePlay();
+      this.changeImageAnimation()
     }
   }
 

+ 4 - 4
entry/src/main/ets/viewmodel/MainViewModel.ets

@@ -56,8 +56,8 @@ export  class  MainViewModel{
       new ItemData($r('app.string.setting'),  { type: 'symbol', value: $r('sys.symbol.gearshape') },MainViewModel.MENU_SETTING,false),
       new ItemData($r('app.string.about_me'), { type: 'symbol', value: $r('sys.symbol.info_shield') },MainViewModel.MENU_ABOUT,false),
       new ItemData($r('app.string.haoping'), { type: 'symbol', value: $r('sys.symbol.flower') },MainViewModel.MENU_HAOPING,false),
-      new ItemData($r('app.string.persion_duty'),{ type: 'symbol', value: $r('sys.symbol.doc_plaintext') },MainViewModel.MENU_DUTY,false),
-      new ItemData($r('app.string.yszc'), { type: 'symbol', value: $r('sys.symbol.lock') },MainViewModel.MENU_YSZC,false),
+      // new ItemData($r('app.string.persion_duty'),{ type: 'symbol', value: $r('sys.symbol.doc_plaintext') },MainViewModel.MENU_DUTY,false),
+      // new ItemData($r('app.string.yszc'), { type: 'symbol', value: $r('sys.symbol.lock') },MainViewModel.MENU_YSZC,false),
       new ItemData($r('app.string.share_tt'),  { type: 'symbol', value: $r('sys.symbol.share') },MainViewModel.MENU_SHARE,false),
       // new ItemData($r('app.string.nor_setting'), $r('app.media.hm_gps'),MainViewModel.MENU_SETTING,false),
     ];
@@ -73,8 +73,8 @@ export  class  MainViewModel{
       new ItemData($r('app.string.about_me'), { type: 'symbol', value: $r('sys.symbol.info_shield') },MainViewModel.MENU_ABOUT,false),
       // new ItemData($r('app.string.vip'), { type: 'symbol', value: $r('sys.symbol.vip_hand') }, MainViewModel.MENU_VIP, false),
       new ItemData($r('app.string.haoping'), { type: 'symbol', value: $r('sys.symbol.flower') },MainViewModel.MENU_HAOPING,false),
-      new ItemData($r('app.string.persion_duty'),{ type: 'symbol', value: $r('sys.symbol.doc_plaintext') },MainViewModel.MENU_DUTY,false),
-      new ItemData($r('app.string.yszc'), { type: 'symbol', value: $r('sys.symbol.lock') },MainViewModel.MENU_YSZC,false),
+      // new ItemData($r('app.string.persion_duty'),{ type: 'symbol', value: $r('sys.symbol.doc_plaintext') },MainViewModel.MENU_DUTY,false),
+      // new ItemData($r('app.string.yszc'), { type: 'symbol', value: $r('sys.symbol.lock') },MainViewModel.MENU_YSZC,false),
       new ItemData($r('app.string.share_tt'),  { type: 'symbol', value: $r('sys.symbol.share') },MainViewModel.MENU_SHARE,false),
     ];
     return drawerGridData;

+ 3 - 0
entry/src/main/ets/viewmodel/VideoItem.ets

@@ -54,6 +54,9 @@ export class VideoItem  {
   nb_streams?:number//流数量
   nb_programs?:number//节目数量
 
+  genre?:string//风格
+  track?:string//音轨号
+
   constructor(name: string, id: string, filePath: string, type:number,videoSize:number,cTime: string,pixelMap?: image.PixelMap,
     size?: string,pixelMapPath?: string,artist?: string,album?: string,fileName?: string, lastPlayed?:Date) {
     this.name = name;

+ 6 - 3
entry/src/main/module.json5

@@ -49,7 +49,7 @@
           {
             "actions": [
               "action.system.home",
-              "ohos.want.action.viewData",
+              "ohos.want.action.viewData",//碰一碰分享增加
               "ohos.want.action.sendData"
             ],
             "uris": [
@@ -76,10 +76,13 @@
                 "type": "video/*",
                 "linkFeature": "FileOpen",
                 "maxFileSupported": 1
-              }
+              },
+
             ],
+//            "domainVerify": true,//碰一碰分享增加
             "entities": [
-              "entity.system.home"
+              "entity.system.home",
+//              "entity.system.browsable"//碰一碰分享增加
             ],
 
           }

+ 8 - 0
entry/src/main/resources/base/element/string.json

@@ -459,6 +459,14 @@
     {
       "name": "sync_dataing",
       "value": "正在校正数据"
+    },
+    {
+      "name": "unknown",
+      "value": "unknown"
+    },
+    {
+      "name": "lossless",
+      "value": "Lossless"
     }
   ]
 }

+ 8 - 3
entry/src/main/resources/zh_CN/element/string.json

@@ -56,7 +56,7 @@
     },
     {
       "name": "Honey_the_video_is_playing_errant_The_system_is_wandering",
-      "value": "亲,视频播放异常"
+      "value": "亲,播放异常"
     },
     {
       "name": "ijkplayer_Audio_player",
@@ -200,9 +200,14 @@
       "name": "current_play_list",
       "value": "播放列表"
     },
+
+    {
+      "name": "unknown",
+      "value": "未知"
+    },
     {
-      "name": "reason_copymusic",
-      "value": ""
+      "name": "lossless",
+      "value": "无损"
     }
   ]
 }

+ 2 - 1
lib/src/main/ets/view/LyricView2.ets

@@ -173,7 +173,8 @@ export struct LyricView2 {
 
     private calculateOpacityFactor(index: number, currentIndex: number): number {
         const distance = Math.abs(index - currentIndex);
-        return Math.max(0.26, 1 - distance * 0.11); // 透明度随着距离增加而减小
+        let maxOp =  Math.max(0.3,1-this.blurDegree*0.2)
+        return Math.max(maxOp, 1 - distance * 0.08); // 透明度随着距离增加而减小
     }