import { AppUtil, DeviceUtil,DisplayUtil, PreferencesUtil, ToastUtil } from '@pura/harmony-utils'; import TitleBar from '../view/TitleBar'; import { router } from '@kit.ArkUI'; import mainViewModel, { MainViewModel } from '../viewmodel/MainViewModel'; import ItemData from '../viewmodel/ItemData'; import type { sysResource } from '../viewmodel/ItemData'; import { CommonConstants } from '../common/constants/CommonConstants'; import { VideoItem } from '../viewmodel/VideoItem'; import ScreenUtil from '../common/util/ScreenUtil'; import { Utility } from '../common/util/Utility'; import { BusinessError, emitter } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit'; import { AdSlot, AdSlotBuilder, CSJAdCreator, CSJAdSdk, CSJNativeExpressAd, NativeExpressAdListener } from '@csj/openadsdk'; import { PrintBiddingTokenUtils } from '../common/util/PrintBiddintTokenUtils'; import { ArrayList } from '@kit.ArkTS'; import { CSJUtil } from '../common/util/CSJUtil'; import { LocalMusic } from '../view/LocalMusic'; import { StreamContent } from '../view/StreamContent'; import { AvSessionController } from '../controller/AvSessionController'; import { ImageKnife } from '@ohos/imageknife'; import { BreakpointSystem, BreakpointTypeEnum } from '../common/util/BreakpointSystem'; import dataStorage from '@ohos.data.storage'; import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant'; import { SettingPage } from './SettingPage'; import { deviceInfo } from '@kit.BasicServicesKit'; import { resourceManager } from '@kit.LocalizationKit'; import { systemShare } from '@kit.ShareKit'; import { uniformTypeDescriptor } from '@kit.ArkData'; import { IBestIcon } from "@ibestservices/ibest-ui"; const TAG = 'NewIndex'; // 日志标签 /** * 首页主组件,包含顶部标题栏、主内容区(本地音乐/网络内容)、侧边抽屉菜单等。 * 支持多端适配、广告集成、导航、生命周期管理等功能。 */ @Preview @Entry @Component struct NewIndex{ /** 列表滚动器,用于抽屉菜单列表滚动 */ private scroller: Scroller = new Scroller(); /** 应用包名 */ @State bundleName:string = '' @State appName:string = '' /** 是否显示侧边抽屉菜单 */ @Provide isShowDrawer:boolean = false; /** 抽屉菜单 X 轴偏移量,用于手势滑动动画 */ @Provide offsetX: number = 0; /** 本地视频列表,页面参数传入 */ @Provide videoLocalList: Array = [] /** Y 轴偏移量(预留) */ @State offsetY: number = 0; /** 主内容类型(0:本地音乐,1:网络内容) */ @State mType:number = 0 /** 模式类型(如歌手、专辑等) */ @Provide modeType:number = 0 /** 是否为零状态(预留) */ @Provide('isZero') isZero:boolean = false; /** 是否显示赞助入口 */ @State isShowSponsorship:boolean = false /** 页面上下文 */ context = getContext(this); /** 音乐是否为零状态(预留) */ @Provide('isMusicZero') isMusicZero:boolean = false; /** 本地音乐列表,持久化存储 */ @StorageLink('musicLocalList') musicLocalList: Array = [] @Provide isFavMusic:boolean = false /** 标题栏配置模型 */ @State titleBarModel: TitleBar.Model = new TitleBar.Model() .setTitleTextStyle(FontStyle.Normal) .setTitleBarStyle(TitleBar.BarStyle.TRANSPARENT) .setLeftIcon($r('app.media.menu')) .setLeftIconWidth(28) .setLeftIconHeight(28) .setTitleBarMinHeight(64) .setTitleName('首页') // .setRightIcon($r('app.media.add')) .setTitleFontSize(19) .setTitleFontColor(Color.White) .setTitleBarBackground($r('app.color.title_bar_bg')) .setLeftTitleBackground($r('app.color.title_bar_bg')) .setOnLeftClickListener(() => { // 打开菜单栏动画 animateTo({ duration: 555 }, () => { this.isShowDrawer = true this.offsetX = 0 }) }) .setRightTitleBackground($r('app.color.title_bar_bg')) // .setOnRightClickListener(()=>{ // // this.goSelectVideo() // this.showSheelDialog() // }) /** 应用版本号 */ @State versionName:string ='' /** 音频根目录路径 */ @Provide rootPath:string = '' /** 当前路径 */ @Provide currentPath:string = '' /** 是否为历史记录页面 */ @Provide isHistory:boolean = false /** 是否可以返回上一级 */ @Provide isCanBack:boolean= false @StorageProp('currentColorMode') currentMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT; /** * 一多界面适配断点系统 */ private breakpointSystem: BreakpointSystem = new BreakpointSystem(); /** 当前断点类型(如大屏/小屏) */ @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD; /** 记录上一次点击返回键的时间戳,用于双击退出 */ private backTime:number=0; /** * 返回键处理逻辑: * - 如果不是根目录或有历史记录,发送广播通知更新列表 * - 如果是根目录,双击返回键退出应用,否则提示 */ onBackPress(): boolean | void { if(this.currentPath !== this.rootPath||this.isHistory||this.isFavMusic||(this.modeType!==0&&this.isCanBack)){ const eventData: emitter.EventData = {}; emitter.emit({ eventId: 888 }, eventData); // 发送音频广播通知更新doSwipBack }else{ let nowtime = Date.now(); if(nowtime - this.backTime < 1000){ const mContext = getContext(this) as common.UIAbilityContext mContext.terminateSelf(); // 关闭应用 AvSessionController.getInstance(true).unregisterSessionListener() }else { if(this.isShowDrawer){ // 如果抽屉菜单打开,先关闭抽屉 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) }else{ this.backTime=nowtime; ToastUtil.showToast("再按一次将退出当前应用") } } } return true; } /** * 页面显示生命周期钩子 * - 注册断点系统 * - 获取页面参数 * - 设置状态栏样式 * - 初始化图片缓存 * - 判断是否显示赞助入口 */ async aboutToAppear() { Utility.enableFullScreen() Utility.getAppName(getContext(this)).then((appName:string)=>{ this.appName = appName }) this.breakpointSystem.register(); let params = router.getParams() as Record; this.videoLocalList = params.videoList as VideoItem[]; Utility.setStatusBarLight() ScreenUtil.setScreenSize(); this.bundleName = AppUtil.getBundleName() this.versionName = AppUtil.getVersionName(); await ImageKnife.getInstance().initFileCache(this.context, 256, 256 * 1024 * 1024) this.isShowSponsorship = Utility.isOpenTime() } /** * 页面消失生命周期钩子 * 注销断点系统 */ aboutToDisappear() { console.info('NewIndex aboutToDisappear'); this.breakpointSystem.unregister(); } /** * 构建主页面结构,包括顶部横线、主内容区和抽屉菜单 */ build() { Stack({ alignContent: Alignment.TopStart }) { // 顶部横线 Column(){ Line() .width('100%') .height(1) } .backgroundColor($r('app.color.title_bar_bg')) .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP]) // 主内容区 Column() { Stack(){ // 本地音乐内容区 LocalMusic() .visibility(this.mType===0?Visibility.Visible:Visibility.None) // 网络内容区 StreamContent() .visibility(this.mType===1?Visibility.Visible:Visibility.None) } } .width('100%') .height('100%') .justifyContent(FlexAlign.Start) .backgroundColor($r('app.color.bottom_control_background')) // 侧边抽屉菜单 if(this.isShowDrawer){ Column() { Column() { // 抽屉顶部背景图 Image($r('app.media.bg_music')) .width('100%') .visibility(this.isCoverOpacity()?Visibility.None:Visibility.Visible) .height(180) Blank() .backgroundColor($r('app.color.title_bar_bg')) .visibility(this.isCoverOpacity()?Visibility.Visible:Visibility.None) .width('100%') .height(55) // 动态生成抽屉菜单内容 this.getDrawerView() } .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?'40%':'75%') .height('100%') .backgroundColor($r('app.color.silvery')) .onClick((event:ClickEvent)=>{ // 阻止事件冒泡 }) } .width('100%') .height('100%') .backgroundColor($r('app.color.ban_touming')) .alignItems(HorizontalAlign.Start) .onClick((event:ClickEvent)=>{ // 点击抽屉外部关闭抽屉 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) }) .translate({ x: this.offsetX, y: 0, z: 0 }) .transition({ type: TransitionType.Insert, translate: { x: -DisplayUtil.getWidth(), y: 0 } }) .transition({ type: TransitionType.Delete, translate: { x: -DisplayUtil.getWidth(), y: 0 } }) .gesture( PanGesture() .onActionUpdate((event:GestureEvent)=>{ // 手势滑动更新抽屉偏移 if(event.offsetX<0){ this.offsetX = event.offsetX; } }) .onActionEnd(() => { // 手势结束判断是否关闭抽屉 if(this.offsetX<-DisplayUtil.getWidth()/9){ animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) }else{ animateTo({ duration: 555 }, () => { this.isShowDrawer = true this.offsetX = 0 }) } }) ) } } } /** * 动态生成抽屉菜单内容 * 根据 isShowSponsorship 展示不同菜单项 */ @Builder getDrawerView(){ List({space: 0, scroller: this.scroller}){ ForEach(this.isShowSponsorship?mainViewModel.getDrawerData2():mainViewModel.getDrawerData(),(item: ItemData)=>{ ListItem(){ Row() { // 菜单图标 if (typeof item.img === 'object' && item.img !== null && (item.img as sysResource).type === 'symbol') { SymbolGlyph((item.img as sysResource).value as Resource) .size({ width: 22, height: 22 }) .fontColor([$r("app.color.img_color")]) .alignSelf(ItemAlign.Center) .margin({ left: 2 }) }else if (typeof item.img === 'object' && item.img !== null && (item.img as sysResource).type === 'ibest') { IBestIcon({ name: (item.img as sysResource).value as string, iconSize:22, color: $r("app.color.img_color"), }).margin({ left: 2 }) .alignSelf(ItemAlign.Center) }else { Image(item.img as Resource) .height(22) .alignSelf(ItemAlign.Center) .fillColor($r('app.color.img_color')) .margin({ left: 2 }) } // 菜单标题 Text(item.title) .margin({ left: 10, right: 20 }) .fontSize(15) .fontColor($r('app.color.index_tab_font_color')) .fontWeight(480) Blank() // 右侧箭头 Image($r('app.media.arrow_right')) .width(22) .height(22) .margin({ left: 20, right: 0 }) .align(Alignment.Center) } .width('100%') .height(55) .useEffect(true) .onClick(async () => { // 根据 item.id 跳转或切换功能 switch (item.id) { case MainViewModel.MENU_MUSIC: this.mType = 0 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) break case MainViewModel.MENU_FILE_SCAN: router.pushUrl({ url: 'pages/ScanFilePage' }); break case MainViewModel.MENU_HOME: this.mType = 0 this.modeType = 0 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) break case MainViewModel.MENU_MIEDIA_KU: this.modeType = 1 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) break case MainViewModel.MENU_MIEDIA_ARTIST: this.modeType = 2 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) break case MainViewModel.MENU_MIEDIA_ALBUM: this.modeType = 3 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) break case MainViewModel.MENU_SETTING: router.pushUrl({ url: 'pages/SettingPage' }, router.RouterMode.Single); break case MainViewModel.MENU_VIP: router.pushUrl({ url: 'pages/VipPage' }, router.RouterMode.Single); break case MainViewModel.MENU_USER: router.pushUrl({ url: 'pages/UserCenter' }, router.RouterMode.Single); break case MainViewModel.MENU_NET_CONNECT: this.mType = 1 animateTo({ duration: 555 }, () => { this.isShowDrawer = false }) break case MainViewModel.MENU_SIMI: router.pushUrl({ url: 'pages/VerifyPage' }); break case MainViewModel.MENU_LIKE: router.pushUrl({ url: 'pages/LikeVideoPage' }); break case MainViewModel.MENU_DUTY: router.pushUrl({ url: 'pages/WebIndex', params: { titleName: '用户协议', webUrl: CommonConstants.NEW_DUTY } }); break case MainViewModel.MENU_HAOPING: Utility.gotoMarket(getContext(this) as common.UIAbilityContext,this.bundleName) break case MainViewModel.MENU_TEST_SPEED: router.pushUrl({ url: 'pages/SpeedIndex' }); break case MainViewModel.MENU_OPTIMIZE: router.pushUrl({ url: 'pages/AddSpeedPage' }); break case MainViewModel.MENU_ABOUT: router.pushUrl({ url: 'pages/AboutPage' }, router.RouterMode.Single); break case MainViewModel.MENU_UPDATE: AlertDialog.show({title:'版本更新',message:'当前版本为最新版本:'+this.versionName, autoCancel:true, alignment:DialogAlignment.Center, offset:{dx:0,dy:-20},//在Y轴方向上的编译量 confirm:{ value:'确定',fontColor:Color.White,backgroundColor:$r('app.color.title_bar_bg'), action:()=>{ } } }) break case MainViewModel.MENU_YSZC: router.pushUrl({ url: 'pages/WebIndex', params: { titleName: '隐私政策', webUrl: CommonConstants.NEW_YS_HW } }); break case MainViewModel.MENU_SHARE: this.gotoShare() break } }) } .width('90%') .height(55) }) } .width('100%') .alignListItem(ListItemAlign.Center) .backgroundColor($r('app.color.silvery')) .layoutWeight(1) // .divider({ strokeWidth: 1, color: this.isDarkMode? '333333':'#ffe9f0f0' }) .edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果 } gotoShare(){ let shareData: systemShare.SharedData = new systemShare.SharedData({ utd: uniformTypeDescriptor.UniformDataType.TEXT, content: 'https://appgallery.huawei.com/app/detail?id='+this.bundleName, title: this.appName, // 不传title字段时,显示content description: '精心雕琢的无损音乐播放器', // thumbnail: new Uint8Array() // 推荐传入适合的缩略图 不传则显示默认text图标 }); // 进行分享面板显示 let controller: systemShare.ShareController = new systemShare.ShareController(shareData); let context = getContext(this) as common.UIAbilityContext; controller.show(context, { selectionMode: systemShare.SelectionMode.SINGLE, previewMode: systemShare.SharePreviewMode.DETAIL, }).then(() => { console.info('ShareController show success.'); }).catch((error: BusinessError) => { console.error(`ShareController show error. code: ${error.code}, message: ${error.message}`); }); } /** * ================== 穿山甲广告相关 ================== */ /** Banner广告对象 */ private declare bannerAd: CSJNativeExpressAd; /** 广告加载状态 */ @State private status: string = "未加载" /** 是否展示广告 */ @State private isShowAd: boolean = false /** 广告位配置信息 */ private declare mAdSlot: AdSlot; /** 服务端bidding广告内容(可选) */ private mBiddingAdm = '' /** 广告加载监听器 */ private expressLoadAdListener: NativeExpressAdListener = { /** * 广告加载失败回调 */ onError: (code: number, message: string) => { console.error("加载广告失败,code=" + code + ",message=" + message); this.status = "加载广告失败,code=" + code + ",message=" + message; }, /** * 广告加载成功回调 * @param ads 返回的广告列表 */ onNativeExpressAdLoad: (ads: ArrayList) => { console.log("BannerExpressAdPage==onNativeExpressAdLoad......success"); if (ads && ads.length > 0) { ads.forEach((ad: CSJNativeExpressAd, idx: number) => { // 设置广告交互监听 ad.setExpressInteractionListener({ /** 广告点击回调 */ onAdClicked: (type: number) => { console.log("BannerExpressAdPage==onAdClicked......"); }, /** 广告展示回调 */ onAdShow: (type: number) => { console.log("BannerExpressAdPage==onAdShow......"); }, /** 模板渲染失败回调 */ onRenderFail: (code: number, msg: string) => { console.log("BannerExpressAdPage==onRenderFail...code=" + code + ",msg=" + msg); }, /** 模板渲染成功回调 */ onRenderSuccess: (width: number, height: number) => { console.log("BannerExpressAdPage==onRenderSuccess......width=" + width + ",height=" + height); this.bannerAd = ad; this.status = "广告加载完成待展示"; this.showBannerAd() } }) // 设置广告轮播时间 ad.setSlideIntervalTime(30 * 1000);//设置轮播时间长 this.setDislikeCallback(ad); //设置dislike ad.render(this.getUIContext()) // 开始渲染广告 this.status = "广告加载中..."; }); } } } /** * 设置广告 dislike 回调 * @param ad 广告对象 */ private setDislikeCallback(ad: CSJNativeExpressAd) { ad.setDislikeCallback({ /** dislike 弹窗显示 */ onShow: () => { console.log("BannerExpressAdPage==dislike......show"); }, /** 选择 dislike 选项 */ onSelected: (position: number, value: string, enforceRemove: boolean) => { this.isShowAd = false; console.log("BannerExpressAdPage==dislike......onSelected:position=" + position + ",value:" + value + ",enforce=" + enforceRemove); }, /** 点击取消 dislike */ onCancel: () => { console.log("BannerExpressAdPage==dislike......onCancel"); } }) } /** * 加载Banner广告 * @param rit 广告位ID */ loadBannerAd(rit: string) { // 仅在满足条件时加载广告 if(!Utility.isNoble()){ return } if(!Utility.isPassInstallTime(2)){ return } this.isShowAd = false; let adCreator:CSJAdCreator = CSJAdSdk.getAdCreator() this.mAdSlot = new AdSlotBuilder() .setCodeId(rit) .setAcceptSize(CSJUtil.BANNER_WIGTH, CSJUtil.BANNER_HEIGHT) .setAdCount(1) .setBidAdm(this.mBiddingAdm) .build() PrintBiddingTokenUtils.printBiddingToken(this.mAdSlot, adCreator); adCreator.loadBannerAd(this.mAdSlot, this.expressLoadAdListener) this.status = "广告加载中..." } @StorageProp('currentHeightBreakpoint') currentHeightBreakpoint: HeightBreakpoint | undefined = HeightBreakpoint.HEIGHT_LG; @StorageProp('currentWidthBreakpoint') currentWidthBreakpoint: WidthBreakpoint | undefined = WidthBreakpoint.WIDTH_SM; //是否是Pura X外屏,或者小屏幕 isPuraWP() { return this.currentWidthBreakpoint === WidthBreakpoint.WIDTH_SM && this.currentHeightBreakpoint === HeightBreakpoint.HEIGHT_MD } //是否是Pura X外屏,或者小屏幕或者手机横屏 isCoverOpacity() { if (this.isPuraWP()) { return true } if (this.isPhoneLan()) { return true } if (deviceInfo.marketName.includes('Pura X') && this.currentHeightBreakpoint === HeightBreakpoint.HEIGHT_SM) { return true } return false } //是不是手机横屏 isPhoneLan() { if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE && this.currentBreakpoint !== BreakpointTypeEnum.SM) { if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) { return true } } return false } /** * 展示Banner广告 */ showBannerAd() { if (!this.bannerAd) { return } this.isShowAd = true this.status = "已展示" } /** * ================== 穿山甲广告相关结束 ================== */ // geIDD() { // // 获取应用签名等信息示例代码 // let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | // bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO; // try { // bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => { // hilog.info(0x0000, 'testTag11', 'getBundleInfoForSelf successfully. Data: %{public}s', JSON.stringify(data)); // }).catch((err: BusinessError) => { // hilog.error(0x0000, 'testTag11', 'getBundleInfoForSelf failed. Cause: %{public}s', err.message); // }); // } catch (err) { // let message = (err as BusinessError).message; // hilog.error(0x0000, 'testTag33', 'getBundleInfoForSelf failed: %{public}s', message); // } // } }