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 { MessageEvents, taskpool, worker } from '@kit.ArkTS' import { fileUri, picker } from '@kit.CoreFileKit' import { LocalMusic } from '../view/LocalMusic' 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 } from '../common/constants/CommonConstants' import { emitter } from '@kit.BasicServicesKit' import { BreakpointTypeEnum } from '../common/util/BreakpointSystem' import { resourceManager } from '@kit.LocalizationKit' import { ConfigurationConstant } from '@kit.AbilityKit' import { DialogHelper } from '@pura/harmony-dialog' @Preview @Entry @Component export struct ScanFilePage{ @State rootPath:string = '' //音频根目录 @State lockPath:string = '' @State strText:string = '' @State isStart:boolean = false @State isStartCover:boolean = false @State appName:string = '' //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 = '#FF4081'; @State isDarkMode: boolean = false @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT; private windowClass: window.Window = globalThis.windowClass 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() { this.initLottie(this.path,true) setTimeout(()=>{ lottie.pause() },88) } // 组件生命周期 async aboutToAppear() { Utility.getAppName(getContext(this)).then((appName:string)=>{ this.appName = appName }) let themeColor = PreferencesUtil.getStringSync('THEME_COLOR', '#FF4081'); 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 +'/'+ LocalMusic.STR_LOCK_VIDEO LogUtil.info('onecold 文件扫描 aboutToAppear') } onColorModeChange() { this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK } endScan(isOnekey:boolean){ const eventData: emitter.EventData = {}; emitter.emit({ eventId: 101 }, eventData); // 发送视频打开广播事件 this.watchStatus(false) ToastUtil.showToast('扫描文件入库成功!') if(isOnekey){ this.isStartCover = false }else{ this.isStart = false } this.strText = '' //结束动画 lottie.pause() lottie.stop() this.initLottie(this.successpath,false) lottie.play() } //扫描过程中屏幕要保存常亮 watchStatus(isKeep:boolean) { this.windowClass.setWindowKeepScreenOn(isKeep); } // 组件生命周期 aboutToDisappear() { lottie.destroy(); } // @State titleBarModel: TitleBar.Model = new TitleBar.Model() // .setTitleTextStyle(FontStyle.Normal) // .setTitleBarStyle(TitleBar.BarStyle.TRANSPARENT) // .setLeftIcon($r('app.media.left_back_white')) // .setTitleName("文件扫描") // .setTitleFontColor(Color.White) // .setTitleBarBackground(this.themeColor) // .setLeftTitleBackground(this.themeColor) // .setTitleBarBottomLineColor(this.themeColor) // .setOnLeftClickListener(() => { // router.back() // // }) initState(isOnekey:boolean){ this.initLottie(this.path,true) if(isOnekey){ this.isStartCover = true }else{ this.isStart = true } this.strText = Utility.resourceToString(getContext(this),$r('app.string.scaning')) lottie.play() } doOptimize(isOnekey:boolean){ this.watchStatus(true) this.initState(isOnekey) const task = new taskpool.Task(scanDirectoryTask, getContext(this), this.rootPath, this.lockPath,PreferencesUtil.getStringSync('COVER_API','')); taskpool.execute(task, taskpool.Priority.HIGH).then(()=>{ this.endScan(isOnekey) }).catch((e:object)=>{ console.info("task1 catch e: " + e); }) } //是不是手机横屏 isPhoneLan() { if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE && this.currentBreakpoint !== BreakpointTypeEnum.SM) { if (DisplayUtil.getFoldStatus() === 0 ) { return true } } return false } build() { Column() { // 顶部安全区和自定义标题栏 Column() { // 顶部安全区 Blank() .height(this.isPhoneLan() ? 0 : px2vp(AppUtil.getStatusBarHeight())) .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.left_back_white')) .width(28) .height(28) .margin({ left: 12, right: 8 }) .onClick(() => { router.back(); }) 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) } // Column(){ // Line().width('100%').height('100%') // } // .height(this.isPhoneLan()?0:px2vp(AppUtil.getStatusBarHeight())) // .backgroundColor(this.themeColor) // .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP]) // TitleBar({ model: $titleBarModel }) 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' }) } // Text(this.strText) // .margin({ right: 20,top:20,bottom:20 }) // .fontSize(16) // .fontColor(Color.Black) // .fontWeight(480) 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 }) } .backgroundColor($r('app.color.index_background')) .margin({ left:25,right: 25,top:20,bottom:20 }) .borderRadius(20) Column() { Button(this.isStart?'正在扫描':$r('app.string.start_scan'), { type: ButtonType.Capsule, stateEffect: false }) .width('60%') .height(55) .margin({ top: 20, bottom: 10 }) .linearGradient({ direction: GradientDirection.Right, colors: [['#ff37a0fc', 0.0], ['#67e667', 0.5], ['#f5856e', 1.0]] }) .enabled(this.isStart ?false:true) .onClick(() => { this.doOptimize(false) }) .alignSelf(ItemAlign.Center) Button(this.isStartCover?'正在扫描':$r('app.string.onekey_cover'), { type: ButtonType.Capsule, stateEffect: false }) .width('60%') .height(55) .margin({ top: 10, bottom: 20 }) .linearGradient({ direction: GradientDirection.Right, colors: [['#ff37a0fc', 0.0], ['#67e667', 0.5], ['#f5856e', 1.0]] }) .enabled(this.isStartCover ?false:true) .onClick(() => { if(PreferencesUtil.getStringSync('COVER_API','')===''){ this.showTipsDialog() return } this.doOptimize(true) }) .alignSelf(ItemAlign.Center) } } .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) .stateEffect(true) .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')) .stateEffect(true) .margin({ left: 6 }) .onClick(() => { DialogHelper.closeDialog('tips'); //关闭弹框 router.pushUrl({ url: 'pages/SettingPage' }, router.RouterMode.Single); }) } } .width("100%") .padding(10) } } @Concurrent async function scanDirectoryTask(context: Context, dirPath: string, lockPath: string,cover_api:string) { const stack: string[] = [dirPath]; const table: MediaTable = new MediaTable(context); while (stack.length > 0) { const currentPath = stack.pop()!; const files = FileUtil.listFileSync(currentPath); await Promise.all(files.map(async (file) => { const fPath = `${currentPath}/${file}`; if (fPath === lockPath) return; if (FileUtil.isDirectory(fPath)) { stack.push(fPath); // 使用栈结构代替递归 } else { if (fPath.endsWith('.lrc') || fPath.endsWith('.srt')) return; if (Utility.isMeidaByExtension(fPath)) { const mediaItem = await Utility.uriGetMusicAssetsFromFile( context, fPath, CommonConstants.TYPE_LOCAL, true ); table.insert(mediaItem, (id: number) => { },cover_api); } } })); } }