| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- import TitleBar from '../view/TitleBar'
- import { router, window } from '@kit.ArkUI'
- import { AppUtil, DeviceUtil, DisplayUtil, FileUtil, LogUtil, PreferencesUtil, ToastUtil } from '@pura/harmony-utils'
- import lottie from '@ohos/lottie'
- import { AnimationItem } from '@ohos/lottie'
- import { JSON, MessageEvents, taskpool, worker } from '@kit.ArkTS'
- import { fileUri, picker } from '@kit.CoreFileKit'
- import { Utility } from '../common/util/Utility'
- import MediaTable from '../common/util/MediaTable'
- import { VideoItem } from '../viewmodel/VideoItem'
- import Logger from '../common/util/Logger'
- import { CommonConstants, STR_LOCK_VIDEO } from '../common/constants/CommonConstants'
- import { EventConstants } from '../common/constants/EventConstants'
- import { BusinessError, emitter } from '@kit.BasicServicesKit'
- import { BreakpointTypeEnum } from '../common/util/BreakpointSystem'
- import { resourceManager } from '@kit.LocalizationKit'
- import { common, ConfigurationConstant } from '@kit.AbilityKit'
- import { DialogHelper } from '@pura/harmony-dialog'
- @Preview
- // @Entry
- @Component
- export struct ScanFilePage{
- // 新增状态变量
- @State currentInsertCount: number = 0 // 当前已扫描并插入的歌曲数量
- @State currentFilePath: string = '' // 当前正在处理的文件路径
- context = this.getUIContext().getHostContext() as common.UIAbilityContext
- // @StorageProp('mediaKuList') mediaKuList: Array<VideoItem> = []; //媒体库文件
- @State rootPath:string = '' //音频根目录
- @State lockPath:string = ''
- @Consume isShowDrawer: boolean;
- @Consume offsetX: number;
- @State textVisi:Visibility=Visibility.Hidden
- @State isStart:boolean = false
- @State isStartCover:boolean = false
- @State isStartSync:boolean = false
- @State appName:string = ''
- @State packName: string = ''
- @Consume mType: number;
- //lottie动画构建渲染上下文
- private mainRenderingSettings: RenderingContextSettings = new RenderingContextSettings(true)
- private path:string = "common/lottie/leida.json"
- private successpath:string = "common/lottie/success2.json"
- private mainCanvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.mainRenderingSettings)
- private animateItem: AnimationItem | null = null;
- /** 当前断点类型(如大屏/小屏) */
- @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD;
- @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
- @State isDarkMode: boolean = false
- @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
- ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
- private windowClass: window.Window = globalThis.windowClass
- @StorageProp('topRectHeight') topRectHeight: number = px2vp(AppUtil.getStatusBarHeight());
- initLottie(lpath:string,isLoop:boolean){
- lottie.destroy(); //加载动画前先销毁之前加载的动画
- this.animateItem = lottie.loadAnimation({
- container: this.mainCanvasRenderingContext, // 渲染上下文
- renderer: 'canvas', // 渲染方式
- loop: isLoop, // 是否循环播放,默认true
- autoplay: true, // 是否自动播放,默认true
- name: '2024', // 动画名称
- contentMode: 'Contain', // 填充的模式
- frameRate: 30, //设置animator的刷帧率为30
- imagePath: 'lottie/images/', // 加载读取指定路径下的图片资源
- path: lpath, // json路径
- // initialSegment: [0,70]
- })
- lottie.setSpeed(0.7)
- }
- onPageShow() {
- }
- // 组件生命周期
- async aboutToAppear() {
- this.packName = AppUtil.getBundleName()
- this.topRectHeight = px2vp(AppUtil.getStatusBarHeight());
- Utility.getAppName(getContext(this)).then((appName:string)=>{
- this.appName = appName
- })
- let themeColor = PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
- AppStorage.setOrCreate('themeColor', themeColor);
- this.themeColor = themeColor;
- this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
- const documentViewPicker = new picker.DocumentViewPicker()
- let documentSaveResult = await documentViewPicker.save({ pickerMode: picker.DocumentPickerMode.DOWNLOAD })
- this.rootPath = new fileUri.FileUri(documentSaveResult[0]).path
- this.lockPath = this.rootPath +'/'+ STR_LOCK_VIDEO
- LogUtil.info('onecold 文件扫描 aboutToAppear')
- this.initLottie(this.path,true)
- setTimeout(()=>{
- lottie.pause()
- },88)
- }
- onColorModeChange() {
- this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
- }
- endScan(isOnekey:boolean){
- const eventData: emitter.EventData = {};
- emitter.emit({ eventId: EventConstants.EVENT_SCAN_UPDATE }, eventData); // 发送视频打开广播事件
- this.watchStatus(false)
- this.currentFilePath = '扫描文件入库成功!'
- if(isOnekey){
- this.isStartCover = false
- }else{
- if(this.isStartSync){
- this.isStartSync = false
- }else{
- this.isStart = false
- }
- }
- //结束动画
- lottie.pause()
- lottie.stop()
- this.initLottie(this.successpath,false)
- lottie.play()
- }
- //扫描过程中屏幕要保存常亮
- watchStatus(isKeep:boolean) {
- this.windowClass.setWindowKeepScreenOn(isKeep);
- }
- // 组件生命周期
- aboutToDisappear() {
- lottie.destroy();
- }
- initState(isOnekey:boolean){
- this.textVisi = Visibility.Visible
- this.initLottie(this.path,true)
- if(isOnekey){
- this.isStartCover = true
- }else{
- this.isStart = true
- }
- lottie.play()
- }
- doOptimize(isOnekey:boolean){
- this.watchStatus(true)
- this.initState(isOnekey)
- const task = new taskpool.Task(scanDirectoryTask, this.context, this.rootPath,
- this.lockPath,PreferencesUtil.getStringSync('COVER_API',''),
- PreferencesUtil.getBooleanSync('autoParseMusicName', true));
- task.onReceiveData((path: string, count: number) => {
- this.currentFilePath = path
- this.currentInsertCount = count
- })
- taskpool.execute(task, taskpool.Priority.HIGH).then(()=>{
- this.endScan(isOnekey)
- taskpool.terminateTask(task);
- }).catch((e:object)=>{
- console.info("onecold task1 catch e: " + JSON.stringify(e));
- })
- }
- // 更新进度回调函数
- private updateProgress = (path: string, count: number) => {
- this.currentFilePath = path
- this.currentInsertCount = count
- }
- build() {
- Column() {
- // 顶部安全区和自定义标题栏
- Column() {
- // 顶部安全区
- Blank()
- .height(this.topRectHeight)
- .backgroundColor(this.isDarkMode?$r('app.color.title_bar_bg'):this.themeColor)
- .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
- // 自定义标题栏(Stack实现绝对居中)
- Stack() {
- // 居中标题
- Text('文件扫描')
- .fontSize(18)
- .fontColor(Color.White)
- .align(Alignment.Center)
- // 左右按钮
- Row() {
- Image($r('app.media.menu'))
- .width(28)
- .height(28)
- .margin({ left: 12, right: 8 })
- .onClick(() => {
- animateTo({ duration: 555 }, () => {
- // 动画闭包内控制Image组件的出现和消失
- this.isShowDrawer = !this.isShowDrawer
- this.offsetX = 0
- })
- })
- Blank().flexGrow(1)
- Blank().width(32)
- }
- .height(48)
- .width('100%')
- .alignItems(VerticalAlign.Center)
- }
- .height(48)
- .width('100%')
- .backgroundColor(this.isDarkMode?$r('app.color.title_bar_bg'):this.themeColor)
- }
- Scroll(){
- Column() {
- Stack(){
- Image($r('app.media.file_search'))
- .width(48)
- .height(48)
- .fillColor(this.themeColor)
- .alignSelf(ItemAlign.Center)
- //lottie动画
- Canvas(this.mainCanvasRenderingContext)
- .width(160)
- .height(160)
- .onReady(()=>{
- //抗锯齿的设置
- this.mainCanvasRenderingContext.imageSmoothingEnabled = true;
- this.mainCanvasRenderingContext.imageSmoothingQuality = 'medium'
- })
- }
- .margin({top:10})
- .transition(TransitionEffect.move(TransitionEdge.END)
- .animation({ duration: 380, curve: Curve.Ease,delay:300 }))
- Text(`${this.currentInsertCount}首歌`)
- .height(38)
- .fontSize(16)
- .fontColor($r('app.color.text_color'))
- .fontWeight(480)
- .visibility(this.textVisi)
- .animation({
- duration: 666,
- curve: 'ease-in-out' // 可选动画曲线
- })
- Text(this.currentFilePath)
- .height(38)
- .fontSize(!this.isStart?15:12)
- .maxLines(3)
- .margin({bottom:6})
- .width('86%')
- .textAlign(this.isStart?TextAlign.Start:TextAlign.Center)
- .fontColor($r('app.color.text_color'))
- .fontWeight(480)
- .visibility(this.textVisi)
- .animation({
- duration: 666,
- curve: 'ease-in-out' // 可选动画曲线
- })
- Button({ type: ButtonType.Capsule, stateEffect: true }) {
- Row(){
- SymbolGlyph($r('sys.symbol.magnifyingglass'))
- .fontSize(22)
- .fontColor([Color.White])
- Text($r('app.string.start_scan'))
- .margin({ left: 8 })
- .fontSize(18)
- .fontColor(Color.White)
- .fontWeight(480)
- .textAlign(TextAlign.Center)
- }
- .justifyContent(FlexAlign.Center)
- }
- .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.END)
- .animation({ duration: 380, curve: Curve.Ease,delay:300 }))
- Column() {
- Row() {
- Image($r('app.media.selected'))
- .width(16)
- .height(16)
- .fillColor(this.themeColor)
- .margin({ left:10})
- .alignSelf(ItemAlign.Center)
- Text(Utility.resourceToString(getContext(this),$r('app.string.file_scan_tip_one'))
- +`${this.appName} `+
- Utility.resourceToString(getContext(this),$r('app.string.file_scan_tip_one_1')))
- .margin({ left: 10, right: 20 })
- .fontSize(15)
- .fontColor(Color.Gray)
- .fontWeight(480)
- .layoutWeight(1)
- }
- // .width('100%')
- .margin({ left:25,right: 25 ,top:20 })
- Row() {
- Image($r('app.media.selected'))
- .width(16)
- .height(16)
- .fillColor(this.themeColor)
- .margin({ left:10})
- .alignSelf(ItemAlign.Center)
- Text($r('app.string.file_scan_tip_two'))
- .margin({ left: 10, right: 20 })
- .fontSize(15)
- .fontColor(Color.Gray)
- .fontWeight(480)
- .layoutWeight(1)
- }
- // .width('100%')
- .margin({ left:25,right: 25 ,top:20,bottom:20 })
- Row() {
- Image($r('app.media.selected'))
- .width(16)
- .height(16)
- .fillColor(this.themeColor)
- .margin({ left:10})
- .alignSelf(ItemAlign.Center)
- Text(Utility.resourceToString(getContext(this),$r('app.string.pcfile_scan_tip_one'))
- +`${this.packName} `+
- Utility.resourceToString(getContext(this),$r('app.string.pcfile_scan_tip_one_1')))
- .margin({ left: 10, right: 20 })
- .fontSize(15)
- .fontColor(Color.Gray)
- .fontWeight(480)
- .layoutWeight(1)
- }
- .margin({ left:25,right: 25 ,bottom:20 })
- }
- .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?450:350)
- .margin({ left:25,right: 25,top:20,bottom:20 })
- .borderRadius(20)
- .border({
- color: Color.Gray,
- width: 1.8
- })
- .justifyContent(FlexAlign.Center)
- .transition(TransitionEffect.move(TransitionEdge.END)
- .animation({ duration: 380, curve: Curve.Ease,delay:300 }))
- Row() {
- Button({ type: ButtonType.Capsule, stateEffect: true }) {
- Row(){
- SymbolGlyph($r('sys.symbol.picture'))
- .fontSize(19)
- .fontColor([Color.White])
- Text($r('app.string.onekey_cover'))
- .margin({ left: 4 })
- .fontSize(15)
- .fontColor(Color.White)
- .fontWeight(480)
- .textAlign(TextAlign.Center)
- }
- .justifyContent(FlexAlign.Center)
- }
- .width(150)
- .height(55)
- .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
- .margin({ top: 10, bottom: 10,right:10 })
- .backgroundColor(this.themeColor)
- .enabled(this.isStartCover ?false:true)
- .onClick(() => {
- if(PreferencesUtil.getStringSync('COVER_API','')===''){
- this.showTipsDialog()
- return
- }
- this.doOptimize(true)
- })
- .alignSelf(ItemAlign.Center)
- }
- .transition(TransitionEffect.move(TransitionEdge.END)
- .animation({ duration: 380, curve: Curve.Ease,delay:300 }))
- .visibility(Visibility.None)
- }
- .height('100%')
- .width('100%')
- .align(Alignment.Top)
- }
- .height(1000)
- }
- }
- showTipsDialog() {
- DialogHelper.showCustomContentDialog({
- dialogId: 'tips',
- title: "友情提示",
- autoCancel: false, //点击遮障层时,不关闭弹窗
- backCancel: true, //点击返回键,不关闭弹窗
- contentBuilder: () => {
- this.customTipsBuilder("请到设置界面配置封面服务器地址!")
- },
- buttons: [],
- })
- }
- @Builder
- customTipsBuilder(content: string) {
- Column() {
- Text(content)
- .fontColor(Color.Gray)
- .fontSize(16)
- .alignSelf(ItemAlign.Start)
- .margin({ bottom: 15 })
- .fontSize(16)
- Row() {
- Button('取消')
- .fontColor(Color.White)
- .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)
- .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
- .margin({ right: 6 })
- .onClick(() => {
- DialogHelper.closeDialog('tips'); //关闭弹框
- })
- Button('跳转')
- .fontColor(Color.White)//.linearGradient( { direction: GradientDirection.Right, colors:[['#ff37a0fc',0.0],['#67e667',0.5],['#f5856e',1.0]]})
- .layoutWeight(1)
- .height(50)
- .backgroundColor($r('app.color.title_bar_bg'))
- .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
- .margin({ left: 6 })
- .onClick(() => {
- DialogHelper.closeDialog('tips'); //关闭弹框
- this.mType = 3
- // router.pushUrl({
- // url: 'pages/SettingPage'
- // }, router.RouterMode.Single);
- })
- }
- }
- .width("100%")
- .padding(10)
- }
- }
- //扫描数据库校正对比数据是否真实存在,不存在在删除数据
- @Concurrent
- async function syncDataTask(context: Context, mediaKuList: Array<string>) {
- const table: MediaTable = new MediaTable(context);
- for (const item of mediaKuList) {
- const filePath = item;
- // 检查 filePath 是否存在
- const exists:boolean = await FileUtil.accessSync(filePath);
- // 如果 filePath 不存在,则删除数据库中的数据
- if (!exists) {
- table.getRdbStore(context, async (err:Error) => {
- if (err) {
- return;
- }
- Logger.info('xiaozheng 校正数据开始 this.exists = ' + exists+' filepath = ' +filePath)
- await table.deleteDataFilePath(filePath, (result:boolean) => {
- if(result){
- Logger.info(`xiaozheng Deleted item success with filePath: ${filePath}`);
- }
- });
- })
- }
- }
- }
- //扫描文件入库
- @Concurrent
- async function scanDirectoryTask(context: Context, dirPath: string,
- lockPath: string,cover_api:string,autoParseMusicName:boolean) {
- const stack: string[] = [dirPath];
- const table: MediaTable = new MediaTable(context);
- let insertCount = 0
- while (stack.length > 0) {
- const currentPath = stack.pop()!;
- const files = FileUtil.listFileSync(currentPath);
- await Promise.all(files.map(async (file) => {
- const fPath = `${currentPath}/${file}`;
- // console.info('onecold scanDirectoryTask fPath = ' + fPath)
- if (fPath === lockPath) return;
- if (FileUtil.isDirectory(fPath)) {
- stack.push(fPath); // 使用栈结构代替递归
- } else {
- if (fPath.endsWith('.lrc') || fPath.endsWith('.srt')) return;
- // console.info('onecold scanDirectoryTask fPath2 = ' + fPath)
- if (Utility.isMeidaByExtension(fPath)) {
- const mediaItem = await Utility.uriGetMusicAssetsFromFile(
- context, fPath, CommonConstants.TYPE_LOCAL, autoParseMusicName
- );
- insertCount++
- try {
- // console.info('onecold scanDirectoryTask fPath = ' + fPath)
- // console.info('onecold scanDirectoryTask insertCount = ' + insertCount)
- taskpool.Task.sendData(fPath,insertCount);
- } catch (error) {
- let err = error as BusinessError;
- console.warn( `onecold sendData failed, code=${err.code}, message=${err.message}`);
- }
- table.insert(mediaItem, (id: number) => {
- },cover_api);
- }
- }
- }));
- }
- }
|