Kaynağa Gözat

实现cue分轨文件的解析和cue分轨列表的对话框展示

onecold 10 ay önce
ebeveyn
işleme
21511ac8d2

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

@@ -86,7 +86,7 @@ export class CommonConstants {
     '.3gv','.m4v','.avi','.rmvb','.flv','.3g2','.rmvb','.mpg','.webm','.ogv','.f4v','.swf'
     ,'.srt','.vtt','.dsf','.vob','.3gp','.mpeg','.ts','.ogg','.opus','.wv','.aiff','.amr','.aif','.dff'
     ,'.aif','.au','.eac3','.mlp','.tak','.thd','.tta','.wv','.ac3','.amr','.mka','.mpc','.ra','.dts'
-  , '.asf','.m2ts','.m4b','.mts','.rm','.wtv','.av3a','.dsd']
+  , '.asf','.m2ts','.m4b','.mts','.rm','.wtv','.av3a','.dsd','.cue']
 
   static readonly REAL_MUSIC_FORMAT = ['.mp3','.mp3','.wma','.mp2','.mov','.flac',
     '.midi','.ra','.aac','.ape','.cda','.lrc','.alac','.m4a','.ogg','.opus','.wv','.aiff','.amr','.aif','.dff'

+ 2 - 1
entry/src/main/ets/common/util/CommUtils.ets

@@ -101,4 +101,5 @@ export function  completionNum(num: number): string | number {
   } else {
     return num;
   }
-}
+}
+

+ 212 - 0
entry/src/main/ets/common/util/CueUtils.ets

@@ -0,0 +1,212 @@
+import { fileIo } from '@kit.CoreFileKit';
+import { util } from '@kit.ArkTS';
+import { UniversalDetector } from '@ohos/juniversalchardet';
+
+
+// 类型定义
+export interface CueTrack {
+  trackNumber: number;
+  title: string;
+  performer: string;
+  startTime: string;
+  startOffset: number;
+  endTime: string | null;  // 明确区分null和undefined
+  endOffset: number | null;
+  duration: number | null;
+}
+
+export interface CueInfo {
+  title: string;
+  performer: string;
+  genre?: string;
+  date?: string;
+  filePath: string;
+  tracks: CueTrack[];
+  totalDuration?: number;
+}
+
+// 主解析函数(同步totalDuration参数)
+export async function parseCueFile(cuePath: string, totalDuration?: number): Promise<CueInfo> {
+  const file = fileIo.openSync(cuePath,  fileIo.OpenMode.READ_ONLY);
+  try {
+    // 读取文件内容
+    const stat = await fileIo.stat(file.fd);
+    const arrayBuffer = new ArrayBuffer(stat.size);
+    const readLen = await fileIo.read(file.fd,  arrayBuffer);
+    if (readLen <= 0) throw new Error("CUE文件内容为空");
+    let detectedEncoding = detect(arrayBuffer)
+    // 解码文本
+    const textDecoder = new util.TextDecoder(detectedEncoding || 'utf-8');
+    const content = textDecoder.decode(new  Uint8Array(arrayBuffer, 0, readLen));
+    console.log('onecold  CUE文件内容=', content);
+    // 解析基础信息
+    const result = parseCueContent(content);
+    console.log('onecold  cue result =', JSON.stringify(result));
+    // 计算时间信息
+    return calculateTrackTimes(result, totalDuration);
+  } finally {
+    fileIo.closeSync(file);
+  }
+}
+
+// 核心解析逻辑
+function parseCueContent(content: string): CueInfo {
+  const result: CueInfo = {
+    title: '',
+    performer: '',
+    filePath: '',
+    tracks: []
+  };
+
+  const lines = content.split(/\r?\n/);  // 兼容不同换行符
+  let currentTrack: Partial<CueTrack> | null = null;
+  lines.forEach(line => {
+    const trimmed = line.trim();
+    if (!trimmed) return;
+
+    // 元数据解析 - 改进正则表达式或split方式处理
+    if (/^REM\s+GENRE\s+/i.test(trimmed)) {
+      result.genre = extractQuotedValue(trimmed.substring(trimmed.indexOf('GENRE') + 5).trim());
+    } else if (/^REM\s+DATE\s+/i.test(trimmed)) {
+      result.date = trimmed.substring(trimmed.indexOf('DATE') + 4).trim();
+    } else if (/^TITLE\s+/i.test(trimmed)) {
+      const val = extractQuotedValue(trimmed.substring(trimmed.indexOf('TITLE') + 5).trim());
+      currentTrack ? (currentTrack.title = val) : (result.title = val);
+    } else if (/^PERFORMER\s+/i.test(trimmed)) {
+      const val = extractQuotedValue(trimmed.substring(trimmed.indexOf('PERFORMER') + 9).trim());
+      currentTrack ? (currentTrack.performer = val) : (result.performer = val);
+    } else if (/^FILE\s+/i.test(trimmed)) {
+      const match = trimmed.match(/FILE\s+"(.+?)"/i);
+      if (match) result.filePath = match[1];
+    }
+    // 音轨处理
+    else if (/^TRACK\s+\d+/i.test(trimmed)) {
+      if (currentTrack) finalizeTrack(currentTrack, result);
+      currentTrack = {
+        trackNumber: parseInt(trimmed.split(/\s+/)[1]),
+        endTime: null,
+        endOffset: null,
+        duration: null
+      };
+    }
+    // 时间索引
+    else if (/^INDEX\s+01/i.test(trimmed)) {
+      const timeStr = trimmed.substring(trimmed.indexOf('01') + 3).trim();
+      if (currentTrack) {
+        currentTrack.startTime = timeStr;
+        currentTrack.startOffset = timeToMilliseconds(timeStr);
+      }
+    }
+  });
+
+  if (currentTrack) finalizeTrack(currentTrack, result);
+  return result;
+}
+
+// 时间计算(带totalDuration处理)
+function calculateTrackTimes(cueInfo: CueInfo, totalDuration?: number): CueInfo {
+  const tracks = cueInfo.tracks;  // ✅ 标准属性访问
+  if (totalDuration) cueInfo.totalDuration  = totalDuration;
+
+  tracks.forEach((track,  index) => {
+    // 普通音轨
+    if (index < tracks.length  - 1) {
+      const nextTrack = tracks[index + 1];
+      track.endTime  = nextTrack.startTime;
+      track.endOffset  = nextTrack.startOffset;
+      track.duration  = nextTrack.startOffset  - track.startOffset;
+    }
+    // 最后一首(有总时长时计算)
+    else if (totalDuration && totalDuration > track.startOffset)  {
+      track.endOffset  = totalDuration;
+      track.endTime  = millisecondsToTime(totalDuration);
+      track.duration  = totalDuration - track.startOffset;
+    }
+  });
+
+  return cueInfo;
+}
+
+// 工具函数
+function extractQuotedValue(str: string): string {
+  return str.replace(/^"(.*)"$/,  '$1').replace(/\\"/g, '"').trim();
+}
+
+function timeToMilliseconds(timeStr: string): number {
+  const parts = timeStr.split(':');
+  const minutes = parseInt(parts[0]) || 0;
+  const seconds = parseInt(parts[1]) || 0;
+  const frames = parseInt(parts[2]) || 0;
+  return (minutes * 60 + seconds) * 1000 + Math.floor(frames  * (1000 / 75));
+}
+
+export function millisecondsToTime(ms: number): string {
+  const totalSeconds = Math.floor(ms / 1000);
+  const hours = Math.floor(totalSeconds / 3600);
+  const minutes = Math.floor((totalSeconds % 3600) / 60);
+  const seconds = totalSeconds % 60;
+
+  const timeParts = [
+    minutes.toString().padStart(2, '0'),
+    seconds.toString().padStart(2, '0')
+  ];
+
+  // 只有当小时大于0时才显示小时部分
+  if (hours > 0) {
+    timeParts.unshift(hours.toString().padStart(2, '0'));
+  }
+
+  return timeParts.join(':');
+}
+function finalizeTrack(track: Partial<CueTrack>, result: CueInfo) {
+  if (track.trackNumber  && track.title  && track.startTime)  {
+    result.tracks.push({
+      trackNumber: track.trackNumber,
+      title: track.title,
+      performer: track.performer  || result.performer,
+      startTime: track.startTime,
+      startOffset: track.startOffset  || 0,
+      endTime: track.endTime  ?? null,
+      endOffset: track.endOffset  ?? null,
+      duration: track.duration  ?? null
+    });
+  }
+}
+
+// 使用示例
+// async function demo() {
+//   const cuePath = '田震 - 永远执着.cue';
+//   const totalDuration = 62 * 60 * 1000 + 53 * 1000 + 360; // 示例总时长62:53.36
+//
+//   try {
+//     const cueInfo = await parseCueFile(cuePath, totalDuration);
+//     console.log(' 专辑标题:', cueInfo.title);
+//
+//     cueInfo.tracks.forEach(track  => {
+//       console.log(
+//         `#${track.trackNumber}  ${track.title}\n`  +
+//           `开始: ${track.startTime}  | 结束: ${track.endTime  || '未知'}\n` +
+//           `时长: ${track.duration  ? (track.duration  / 1000).toFixed(2) + '秒' : '需补充总时长'}\n`
+//       );
+//     });
+//   } catch (err) {
+//     console.error(' 解析失败:', err);
+//   }
+// }
+
+
+
+function detect(data: ArrayBuffer): string {
+  //创建检测对象
+  let detector: UniversalDetector = new UniversalDetector();
+  // 传入检测数据并实时判断编码格式
+  detector.handleData(data, 0, data.byteLength);
+  // 标记检测数据 读取结束
+  detector.dataEnd();
+  // 获取检测结果
+  let detected: string = detector.getDetectedCharset();
+  // 释放资源
+  detector.reset();
+
+  return detected;
+}

+ 3 - 0
entry/src/main/ets/common/util/Utility.ets

@@ -649,6 +649,9 @@ export class Utility {
 
   //获取音乐资源的属性值,
   static async uriGetMusicAssetsFromFile(context:Context,uri:string,type:number,autoParseMusicName?:boolean): Promise<VideoItem> {
+    if(StrUtil.isNotEmpty(uri)&&uri.toLowerCase().endsWith('.cue')){
+      return  new VideoItem(FileUtil.getFileName(uri),uri,uri,type,0,'')
+    }
     return Utility.readMetaInfoFFmpeg(context,uri,type,autoParseMusicName)
 
     //华为官方不支持的格式 不支持内嵌歌词Dsf,aif,aiff,wav  不支持内嵌封面dsf,aif,aiff

+ 103 - 0
entry/src/main/ets/view/CueComptent.ets

@@ -0,0 +1,103 @@
+import { common } from '@kit.AbilityKit';
+import { CommonConstants } from '../common/constants/CommonConstants';
+import { VideoItem } from '../viewmodel/VideoItem';
+import { ArrayUtil, FileUtil, LogUtil, PreferencesUtil, StrUtil, ToastUtil } from '@pura/harmony-utils';
+import MediaTable from '../common/util/MediaTable';
+import { taskpool } from '@kit.ArkTS';
+import { CueTrack, millisecondsToTime } from '../common/util/CueUtils';
+
+// 批量删除
+@Component
+export struct CueComptent {
+  @Prop title: string = ''
+  @Prop isLongNameRoLL: boolean = true
+
+  onDeleteResult = (_result: boolean) => {
+  }
+  onCancel = () => {
+  }
+  @Prop cueTracks: CueTrack[]
+  @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
+  context = this.getUIContext().getHostContext() as common.UIAbilityContext
+
+
+  async aboutToAppear() {
+
+
+  }
+
+  build() {
+    Column() {
+      Text(this.title).fontSize(16).margin({ top: 20, bottom: 10 })
+
+      this.getListView()
+
+      Flex({ justifyContent: FlexAlign.SpaceAround }) {
+        Button($r('app.string.back'))
+          .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
+          .padding(15)
+          .width(120)
+          .onClick(() => {
+            this.onCancel()
+          })
+          .backgroundColor($r('app.color.silvery'))
+          .backgroundBlurStyle(BlurStyle.COMPONENT_THICK)
+          .fontColor(Color.Black)
+      }.margin({ bottom: 10 })
+    }
+    .backgroundColor($r('app.color.start_window_background'))
+    .backgroundBlurStyle(BlurStyle.Regular)
+  }
+
+  @Builder
+  getListView() {
+    List() {
+      ForEach(this.cueTracks, (item: CueTrack, index: number) => {
+        ListItem() {
+          Button({ type: ButtonType.Normal, stateEffect: true }) {
+            Row() {
+              Row(){
+                SymbolGlyph($r('sys.symbol.media_center'))
+                  .fontColor([this.themeColor])
+                  .fontSize(25)
+                  .effectStrategy(1)
+                Text(item.title || 'Unknown Title')
+                  .fontSize(14)
+                  .padding({ left: 6 })
+                  .fontColor($r('app.color.text_color'))
+                  .maxLines(1)
+                  .textOverflow({ overflow: this.isLongNameRoLL?TextOverflow.MARQUEE:TextOverflow.Ellipsis })//超长滚动
+              }
+              .layoutWeight(1)
+              .margin({ left: 10 })
+
+              Blank()
+              Text(millisecondsToTime(item.duration||0))
+                .fontSize(14)
+                .margin({ right: 10 })
+                .fontColor(Color.Gray)
+            }
+          }
+          .backgroundColor(Color.Transparent)
+          .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.8 })
+          .transition(TransitionEffect.move(TransitionEdge.BOTTOM).animation({ duration: 600, curve: Curve.Ease, delay: 60*index }))
+          .width('100%')
+          .height(50)
+          .padding({ left: 15, right: 15 })
+        }
+      }) // 使用唯一标识符作为key
+    }
+    .layoutWeight(1)
+    .borderRadius(20)
+    .scrollBar(BarState.Off)
+    .divider({
+      strokeWidth: 0.2,
+      color: Color.Gray,
+      startMargin: 25,
+      endMargin: 25
+    })
+  }
+
+
+}
+

+ 55 - 2
entry/src/main/ets/view/LocalMusic.ets

@@ -83,7 +83,8 @@ import { KnockController } from '../controller/KnockController';
 import { DeleteComptent } from '../view/DeleteComptent'
 import { ABLoopComptent } from '../view/ABLoopComptent';
 import { FixMessyView } from '../view/FixMessyView';
-
+import { parseCueFile,CueTrack,CueInfo } from '../common/util/CueUtils';
+import { CueComptent } from '../view/CueComptent';
 const TAG = 'LocalMusic';
 
 const DEFAULT_INDEX =
@@ -4909,7 +4910,7 @@ export struct LocalMusic {
     }
   }
 
-  private doPlay(item: VideoItem, index?: number, isFromSonPlayList?: boolean,isOpen?:boolean) {
+  private async doPlay(item: VideoItem, index?: number, isFromSonPlayList?: boolean,isOpen?:boolean) {
 
     switch (item.type) {
       case CommonConstants.TYPE_IS_DIR:
@@ -5109,6 +5110,16 @@ export struct LocalMusic {
         if (this.CONTROL_PlayStatus !== PlayStatus.INIT) {
           this.stop();
         }
+        if(item&&item.filePath.toLowerCase().endsWith('.cue')){
+         const cueinfo:CueInfo = await parseCueFile(item.filePath,Number(item.duration))
+          const cueTracks:CueTrack[] = cueinfo.tracks
+          console.log('onecold  cue cueTracks =', JSON.stringify(cueTracks));
+          if(ArrayUtil.isNotEmpty(cueTracks)){
+            this.showCueDialog(cueTracks,cueinfo)
+          }
+          // this.showCueSheet = !this.showCueSheet
+          return
+        }
 
         if (isOpen) {
           this.currentSong = item
@@ -5147,6 +5158,48 @@ export struct LocalMusic {
 
   }
 
+  private cueComponentId: number = 0
+  //显示cue分轨列表对话框
+  showCueDialog(cueTracks:CueTrack[],cueinfo:CueInfo){
+    this.getUIContext().getPromptAction().openCustomDialog({
+      builder: () => {
+        this.cueComptentBuilder(cueTracks,cueinfo)
+      },
+      isModal:true,
+      showInSubWindow:false,
+      maskColor: Color.Transparent,
+      dialogTransition: // 设置弹窗内容显示的过渡效果
+      TransitionEffect.translate({ x: 0, y: 390, z: 0 })
+        .animation({ duration: 600, curve: Curve.Smooth }),
+
+      maskTransition: // 设置蒙层显示的过渡效果
+      TransitionEffect.opacity(0.5)
+        .animation({ duration: 600, curve: Curve.Smooth })
+    }).then((dialogId: number) => {
+      this.cueComponentId = dialogId
+    })
+      .catch((error: BusinessError) => {
+        console.error(`openCustomDialog error code is ${error.code}, message is ${error.message}`)
+      })
+
+  }
+
+  @Builder
+  cueComptentBuilder(cueTracks:CueTrack[]=[],cueinfo:CueInfo){
+    CueComptent({
+      title:cueinfo.title,
+      cueTracks:cueTracks,
+      isLongNameRoLL:this.isLongNameRoLL,
+      onCancel:()=>{
+        this.getUIContext().getPromptAction().closeCustomDialog(this.cueComponentId)
+      },
+      onDeleteResult:(result: boolean)=>{
+
+
+      }
+    })
+  }
+
 
   @Builder
   PlayController() {

+ 0 - 668
entry/src/main/ets/view/ToolView.ets

@@ -1,668 +0,0 @@
-import TitleBar from './TitleBar'
-
-import mainViewModel, { MainViewModel } from '../viewmodel/MainViewModel';
-import ItemData from '../viewmodel/ItemData';
-import { promptAction, router, Scale } from '@kit.ArkUI';
-import { CommonConstants } from '../common/constants/CommonConstants';
-import { wifiManager } from '@kit.ConnectivityKit';
-import { AppUtil,
-  LogUtil,
-  NetworkUtil,
-  PermissionUtil, PickerUtil,
-  PreferencesUtil,
-  RandomUtil,
-  ScanUtil,
-  StrUtil,
-  ToastUtil } from '@pura/harmony-utils';
-
-import wifi from '@ohos.wifiManager'
-import Logger from '../common/util/Logger';
-import { common, Permissions, Want } from '@kit.AbilityKit';
-import { ErrorEvent } from '@kit.ArkTS';
-import { BusinessError } from '@kit.BasicServicesKit';
-import { picker } from '@kit.CoreFileKit';
-import { photoAccessHelper } from '@kit.MediaLibraryKit';
-import { PullToRefresh } from '@ohos/pulltorefresh';
-import { Utility } from '../common/util/Utility';
-import { AnimationHelper, DialogAction,DialogHelper } from '@pura/harmony-dialog';
-import { DialogUtil } from '@pura/harmony-utils';
-import { DrawerOptions } from '../dialog/DrawerOptions';
-import WifiType from '../viewmodel/WiFiType';
-
-
-const TAG = 'ToolView'
-
-interface GeneratedObjectLiteralInterface_1 {
-  bundleName: string;
-  abilityName: string;
-  action: string;
-}
-
-@Preview
-@Component
-export  struct  ToolView{
-
-  @State isListening: boolean = true; // 控制组件状态 true:开启水波纹 false:停止水波纹
-
-
-  private linkedInfo: wifi.WifiLinkedInfo = null!
-  @State isLinked: boolean = false
-  @StorageLink('wifiList')  wifiList: Array<wifi.WifiScanInfo> = []
-  @State uriStr: string = ''
-  @State scanResult: string = ''
-  private scroller: Scroller = new Scroller();
-  @State currentName: string = ''
-  @State ssid: string = ''
-
-
-  @State state:AnimationStatus = AnimationStatus.Initial
-  @State textWifi:string ='未连接'
-  @State count:number =0
-
-  //连接、通讯历史记录
-  @State msgHistory: string = ''
-
-
-
-
-
-  @State titleBarModel: TitleBar.Model = new TitleBar.Model()
-    .setLeftIcon(null)
-    .setTitleTextStyle(FontStyle.Normal)
-    .setTitleName("工具")
-    .setTitleFontColor(Color.White)
-    .setTitleBarBackground($r('app.color.title_bar_bg'))
-    .setTitleBarBottomLineColor($r('app.color.title_bar_bg'))
-
-  @State bundleName:string =''
-  // 组件生命周期
-  async aboutToAppear() {
-    this.initDialogConfig()
-    this.bundleName = await  AppUtil.getBundleName()
-    this.scan()
-    // 启动监听
-    this.addListener()
-
-    console.info('LifeCycleComponent aboutToAppear');
-  }
-
-  initDialogConfig() {
-    DialogHelper.setDefaultConfig((config) => {
-      config.alignment = DialogAlignment.Center; //弹窗的对齐方式。
-      config.offset = { dx: 0, dy: 0 }; //弹窗相对alignment所在位置的偏移量。默认值:{ dx: 0, dy: 0 }
-      config.maskColor = 0x33000000; //自定义蒙层颜色。默认值 0x33000000
-      config.backgroundColor = $r('app.color.pri_bg'); //弹窗背板颜色。默认值:Color.White
-      config.backgroundBlurStyle = BlurStyle.NONE; //弹窗背板模糊材质。默认值:BlurStyle.COMPONENT_ULTRA_THICK
-      config.cornerRadius = 20; //设置背板的圆角半径。可分别设置4个圆角的半径。
-    })
-  }
-
-  // 组件消失生命周期
-  aboutToDisappear() {
-    console.info('LifeCycleComponent aboutToDisappear');
-  }
-
-  // 扫描wifi
-  async scan() {
-
-
-  }
-  //当前连接wifi的info和名称
-  async getLinkedInfo() {
-
-
-  }
-
-  // 监听wifi的变化
-  addListener() {
-
-  }
-  //跳转到市场界面进行好评
-  gotoHao(){
-    const want: Want = {
-      uri: `store://appgallery.huawei.com/app/detail?id=${this.bundleName}`
-    };
-    const context = getContext(this) as common.UIAbilityContext;
-    context.startAbility(want).then(()=>{
-      //拉起成功
-    }).catch(()=>{
-      // 拉起失败
-    });
-  }
-
-
-
-  //好评的自定义内容
-  @Builder
-  customHaoPingBuilder(content: string) {
-    Column() {
-      Text(content)
-        .fontColor(Color.White)
-        .fontSize(16)
-      .alignSelf(ItemAlign.Start)
-      .fontColor(Color.White)
-      .margin({bottom:15})
-      .fontSize(16)
-
-      Row(){
-        Button('取消')
-          .fontColor(Color.White)
-          .linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
-          .height(50)
-          .layoutWeight(1)
-          .stateEffect(true)
-          .margin({right:6})
-          .onClick(()=>{
-            DialogHelper.closeDialog('haoping'); //关闭弹框
-          })
-        Button('好评')
-          .fontColor(Color.White)
-          .linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
-          .layoutWeight(1)
-          .height(50)
-          .stateEffect(true)
-          .margin({left:6})
-          .onClick(()=>{
-            DialogHelper.closeDialog('haoping'); //关闭弹框
-            this.gotoHao()
-            PreferencesUtil.putSync("is_haoping", true);
-          })
-      }
-
-    }
-    .width("100%")
-    .padding(10)
-  }
-
-  showHaopingDialog(){
-
-
-    DialogHelper.showCustomContentDialog({
-      dialogId:'haoping',
-      title: "该功能免费",
-      autoCancel: false, //点击遮障层时,不关闭弹窗
-      backCancel: true, //点击返回键,不关闭弹窗
-      contentBuilder: () => {
-        this.customHaoPingBuilder("如果您觉得好用可以给个好评吗?谢谢!\n给个好评吧,非常感谢您的支持!")
-      },
-      buttons: [],
-
-
-    })
-
-
-  }
-  //自定义文本和图片
-  @Builder
-  customSeeBuilder(content: string) {
-    Column() {
-      Text(content)
-        .fontColor(Color.White)
-        .fontSize(16)
-      // Text(){
-      //   Span('点我查看华为截屏教程')
-      //     .fontColor($r('app.color.white'))
-      //     .decoration({ type: TextDecorationType.Underline, color:$r('app.color.white') })
-      //     .onClick(()=>{
-      //       DialogHelper.closeDialog('dig'); //关闭弹框
-      //       router.pushUrl({url:'pages/WebIndex',
-      //         params:{ titleName:'截图教程',webUrl:$rawfile('jieping.html')}
-      //       },router.RouterMode.Single);
-      //
-      //
-      //     })
-      // }
-      // .alignSelf(ItemAlign.Start)
-      // .fontColor(Color.White)
-      // .visibility(Visibility.None)
-      // .margin({bottom:15})
-      // .fontSize(16)
-
-      Row(){
-        Button('1、截图')
-          .fontColor(Color.White)
-          .linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
-          .height(50)
-          .layoutWeight(1)
-          .stateEffect(true)
-          .margin({right:6})
-          .onClick(()=>{
-            this.goSystemWifiSetting()
-          })
-        Button('2、选图')
-          .fontColor(Color.White)
-          .linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
-          .layoutWeight(1)
-          .height(50)
-          .stateEffect(true)
-          .margin({left:6})
-          .onClick(()=>{
-            DialogHelper.closeDialog('dig'); //关闭弹框
-            this.goSelectPhoto()
-          })
-      }
-
-    }
-    .width("100%")
-    .padding(10)
-  }
-  async showSeePwdDialog(){
-    if(Utility.isFreeTime()){
-      let isHao:boolean = PreferencesUtil.getBooleanSync('is_haoping');
-      if(!isHao){
-        this.showHaopingDialog()
-        return
-      }
-    }
-
-
-
-    DialogHelper.showCustomContentDialog({
-      dialogId:'dig',
-      title: "提示:请按如下教程",
-      contentBuilder: () => {
-        this.customSeeBuilder("第一步:请点击【1、截图】按钮,去系统的WIFI设置界面点到wifi分享二维码界面,然后截图。\n\n第二步:点击【2、选图】按钮,选择该截图的图片进行wifi密码解析。\n")
-      },
-      buttons: [],
-
-
-    })
-
-
-
-  }
-
-
-
-  showFileDialog() {
-    let ps: Permissions = 'ohos.permission.READ_MEDIA';
-    // let ps: Permissions[] = ['ohos.permission.READ_MEDIA'];
-    PermissionUtil.checkPermissions(ps).then((result) => {
-      if (result) {
-        //有文件权限,直接调用第一步和第二部对话框
-        this.showSeePwdDialog()
-      } else {
-        Logger.info(TAG, 'not file permissions state:')
-        //没有文件权限
-       // this.showRuqFile();
-      }
-    })
-
-  }
-
-  // async showRuqFile(){
-  //
-  //
-  //   DialogUtil.showPrimaryDialog({
-  //     backgroundColor:$r('app.color.btn_green'),
-  //     title: "申请文件权限",
-  //     message: '此功能需要读取相册截图的WiFi的二维码图片,从而解析出当前wifi连接的密码。所以需要向您申请文件存储权限,如果紧急将无法使用该功能。\n',
-  //     borderStyle:BorderStyle.Dashed,
-  //     primaryButton: {
-  //       backgroundColor:$r('app.color.btn_green'),
-  //       value: "取消申请",
-  //       action: () => {
-  //
-  //       }
-  //     },
-  //     secondaryButton: {
-  //       backgroundColor:$r('app.color.btn_red'),
-  //       value: "现在申请",
-  //       action: () => {
-  //         let ps: Permissions[] = ['ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA'];
-  //         PermissionUtil.requestPermissions(ps).then((result) => {
-  //           if (result) {
-  //             this.showSeePwdDialog()
-  //           } else {
-  //             ToastUtil.showLong("请在设置中打开权限")
-  //             // AppUtil.toAppSetting()
-  //           }
-  //         })
-  //       }
-  //     },
-  //     onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
-  //       LogUtil.error("showPrimaryDialog-onWillDismiss: " + JSON.stringify(dismissDialogAction))
-  //       if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
-  //         dismissDialogAction.dismiss()
-  //       }
-  //       if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
-  //         dismissDialogAction.dismiss()
-  //       }
-  //     }
-  //   })
-  // }
-
-
-
-
-  //拉起相册的选择刚刚截图的二维码图片进行扫描解析密码
-  goSelectPhoto(){
-
-     let options = new photoAccessHelper.PhotoSelectOptions();
-     options.maxSelectNumber = 1;
-     options.MIMEType =photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
-
-
-
-      //调用系统的相册
-      // PickerUtil.selectPhoto(options).then((uris) => {
-      //   this.uriStr = uris[0];
-      //
-      //   Logger.info(TAG, 'select photo uri:' + uris[0])
-      //   //获得二维码图片uri用scan进行扫描
-      //   ScanUtil.onDetectBarCode(uris[0]).then((scanResult)=>{
-      //
-      //     this.showPwdResultDialog(scanResult[0].originalValue);
-      //     Logger.info(TAG, 'scan select photo result:' + scanResult[0].originalValue)
-      //     // Logger.info(TAG, 'scan select photo result:' +JSON.stringify(scanResult, null, 2))
-      //   }).catch((err: BusinessError) => {
-      //     this.uriStr = `扫描二维码异常:\n${JSON.stringify(err)}`
-      //   })
-      //
-      // }).catch((err: BusinessError) => {
-      //   this.uriStr = `调用相册,异常:\n${JSON.stringify(err)}`
-      // })
-
-
-
-  }
-
-  //自定义文本和图片
-  @Builder
-  customShowPwdBuilder(result: string) {
-    Column() {
-      Text('WiFi名称:'+getWiFiName(result)+'\n\nWiFi密码:'+getWiFiPWD(result)+'\n\n加密类型:WPA/WPA2\n')
-        .fontColor(Color.White)
-        .fontSize(16)
-      Row(){
-        Button('复制密码')
-          .fontColor(Color.White)
-          .linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
-          .height(50)
-          .layoutWeight(1)
-          .stateEffect(true)
-          .onClick(()=>{
-            Utility.copyText(getWiFiPWD(result))
-            ToastUtil.showToast('复制成功')
-            DialogHelper.closeDialog('pwd')
-          })
-
-      }
-
-    }
-    .width("100%")
-    .padding(10)
-  }
-
-  //解析二维码的密码的对话框
-  showPwdResultDialog(result:string){
-
-    DialogHelper.showCustomContentDialog({
-      dialogId:'pwd',
-      title: "WiFi详情",
-      contentBuilder: () => {
-        this.customShowPwdBuilder(result)
-      },
-      buttons: [],
-
-    })
-
-
-
-  }
-
-  //跳转到系统wifi界面
-  goSystemWifiSetting(){
-
-    let context = getContext(this) as common.UIAbilityContext;
-
-    let want: Want = {
-      bundleName: 'com.huawei.hmos.settings',
-      abilityName: 'com.huawei.hmos.settings.MainAbility',
-      uri: 'wifi_entry'};
-    context.startAbility(want)
-      .then(() => {
-        // ...
-      })
-      .catch((err:Error) => {
-        console.error(`Failed to startAbility. Code: ${err.name}, message: ${err.message}`);
-      });
-
-  }
-
-
-
-
-
-
-
-
-  build() {
-    Scroll(){
-    Column() {
-      TitleBar({ model: $titleBarModel })
-      Column() {
-
-        Shape() {
-          Ellipse()
-            .height(200)
-            .width('100%')
-            .fill(Color.White)
-            .backgroundColor($r('app.color.title_bar_bg'))
-        }
-
-      }
-
-      .width('100%')
-      .height(100)
-      .alignItems(HorizontalAlign.Start)
-      .borderRadius({ bottomLeft: 20, bottomRight: 20 })
-
-      Stack() {
-
-
-        Column() {
-          Grid() {
-            ForEach(mainViewModel.getWiFiGridData(), (item: ItemData) => {
-              GridItem() {
-
-                Column() {
-
-                  Image(item.img)
-                    .width(38)
-                    .height(38)
-                    .margin({top:22})
-                    .alignSelf(ItemAlign.Center)
-                    .visibility(item.isHide ? Visibility.None : Visibility.Visible)
-
-                  Text(item.title)
-                    .fontSize(12)
-                    .fontWeight(300)
-                    .fontColor(Color.Grey)
-                    .margin({ top: 8 })
-                    .visibility(item.isHide ? Visibility.None : Visibility.Visible)
-
-
-                }
-                // .backgroundImage($r('app.media.circle'))
-                .backgroundImagePosition(Alignment.Top)
-                .backgroundImageSize({width:100,height:100})
-                .height('100%')
-                .width('100%')
-                .onClick(() => {
-                  switch (item.id) {
-                    case MainViewModel.SAFE_TEST:
-                      router.pushUrl({url:'pages/SafeTestIndex'
-
-                      });
-                      break
-                    case MainViewModel.SEE_PWD:
-                      // this.showFileDialog()
-                      this.showSeePwdDialog() //鸿蒙系统不需要申请文件权限
-                      break
-                    case MainViewModel.SPEED_TEST:
-                      // router.pushUrl({url:'pages/WebPage',
-                      //   params:{ titleName:'网络测速',webUrl:CommonConstants.IS_YUN_CESU2}
-                      // });
-                      router.pushUrl({
-                        url: 'pages/SpeedIndex'
-                      });
-                      break
-                    case MainViewModel.JIAO_CHENG:
-                      router.pushUrl({
-                        url: 'pages/MacPage'
-                      });
-                      break
-                    case MainViewModel.CAMERA_TEST:
-                      router.pushUrl({
-                        url: 'pages/AddSpeedPage'
-                      });
-                      break
-                    case MainViewModel.POWER_TEST:
-                      //跳转到系统的省电模式
-
-                      router.pushUrl({
-                        url: 'pages/CoolingPage'
-                      });
-                      break
-
-                  }
-                })
-
-              }
-
-            })
-          }
-          .columnsTemplate('1fr 1fr 1fr')
-          .rowsTemplate('1fr 1fr')
-          .height(230)
-          .borderRadius(24)
-          .margin({top:50})
-
-        }
-      }
-
-
-      // Column() {
-      //   Line().width('100%').height(0.5).backgroundColor($r('app.color.index_tab_unselected_font_color'))
-      //   Text(this.textWifi)
-      //     .fontSize(13)
-      //     .fontColor($r('app.color.title_bar_bg'))
-      //     .alignSelf(ItemAlign.Start)
-      //     .margin({ left: 15 })
-      //     .height(38)
-      //     .backgroundColor(Color.White)
-      //   Line().width('100%').height(1).backgroundColor($r('app.color.title_bar_bg'))
-      //
-      // }
-      // .layoutWeight(1)
-
-    }
-    .width('100%')
-    .height('100%')
-    .backgroundColor(Color.White)
-  }
-  .height(1024)
-  }
-
-
-
-
-  /**
-   * 查看密码的dialgo定布局提示弹窗
-   */
-  @Builder
-  builderCustomDialogTipView() {
-    Column() {
-      Column({ space: '10vp' }) {
-        Text('提示:请按如下教程')
-          .fontSize('15fp')
-          .fontColor(Color.Black)
-          .textAlign(TextAlign.Start)
-          .fontWeight(500)
-
-        Text('第一步:点击第一步按钮,去系统的WIFI设置界面点到wifi分享二维码界面,然后截图。\n\n第二步:点击第二步按钮,选择该截图的图片进行wifi密码解析。\n')
-          .fontSize('15fp')
-          .fontColor(Color.Grey)
-          .textAlign(TextAlign.Start)
-          .fontWeight(FontWeight.Regular)
-          .margin({left:8,right:8})
-          .padding(5)
-
-        Row() {
-          Button('第一步', { type: ButtonType.Normal, stateEffect: true })
-            .fontColor(Color.White)
-            .fontSize('13fp')
-            .width('50%')
-            .backgroundColor('#55ceac')
-            .onClick(() => {
-              this.goSystemWifiSetting()
-            })
-            .borderRadius({
-              bottomLeft: '5vp',
-            })
-          Button('第二步', { type: ButtonType.Normal, stateEffect: true })
-            .fontColor(Color.White)
-            .fontSize('13fp')
-            .width('50%')
-            .backgroundColor('#ff6b47')
-            .onClick(() => {
-              this.goSelectPhoto()
-            })
-            .borderRadius({
-              bottomRight: '5vp'
-            })
-        }
-        .justifyContent(FlexAlign.SpaceBetween)
-        .width("100%")
-        .borderRadius({
-          bottomLeft: '5vp',
-          bottomRight: '5vp'
-        })
-      }
-      .alignItems(HorizontalAlign.Center)
-      .width('100%')
-      .backgroundColor(Color.White)
-      .borderRadius('5vp')
-      .margin({
-        top: '15vp'
-      })
-    }
-    .width('100%')
-    .borderRadius('5vp')
-    .backgroundColor(Color.White)
-  }
-
-
-
-
-
-
-}
-
-
-//根据 WIFI:T:WPA;S:Tenda_xiaoke;P:20161221;; 解析出wifi的名称
-function getWiFiName(res: string): string {
-  let str =''
-  if(StrUtil.isNotEmpty(res)){
-    if(res.indexOf('S:')!=-1){
-      str = res.substring(res.indexOf('S:')+2,res.indexOf(';P:'))
-    }
-  }
-  return str
-
-}
-
-//根据 WIFI:T:WPA;S:Tenda_xiaoke;P:20161221;; 解析出wifi的密码
-function getWiFiPWD(res: string): string {
-  let str =''
-  if(StrUtil.isNotEmpty(res)){
-    if(res.indexOf('P:')!=-1){
-      str = res.substring(res.indexOf('P:')+2,res.indexOf(';;'))
-    }
-  }
-  return str
-
-}
-
-

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

@@ -478,6 +478,10 @@
     {
       "name": "music_charts",
       "value": "歌曲统计"
+    },
+    {
+      "name": "back",
+      "value": "返回"
     }
   ]
 }