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 { 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 { hilog } from '@kit.PerformanceAnalysisKit'; import { DialogHelper } from '@pura/harmony-dialog'; import UserUtil from '../common/util/UserUtil'; import json from '@ohos.util.json'; 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; @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR; /** * 一多界面适配断点系统 */ 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() this.topRectHeight = px2vp(AppUtil.getStatusBarHeight()); 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() let themeColor = PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR); hilog.info(0x0000, 'Heanup', '当前 NewIndex themeColor:'+themeColor); AppStorage.setOrCreate('themeColor', themeColor); this.themeColor=themeColor // ====== 本地会员同步提醒逻辑 ====== let isLogin = PreferencesUtil.getBooleanSync('isLogin', false); console.log('Heanup isLogin:'+isLogin) console.log('Heanup Utility.isNobleForOld():'+Utility.isNobleForOld()) if (!isLogin && Utility.isNobleForOld()) { setTimeout(() => { DialogHelper.showCustomContentDialog({ dialogId: 'syncNobleDialog', title: '会员同步提示', contentBuilder: () => { this.syncNobleDialogContentBuilder(); }, buttons: [ { value: '暂不登录' }, { value: '去登录', action: () => { router.pushUrl({ url: 'pages/UserCenter', params: { fromSyncNoble: true } }); } } ] }); }, 500); } // ====== 本地会员同步提醒逻辑 END ====== await UserUtil.fetchUserInfo(); } /** * 页面消失生命周期钩子 * 注销断点系统 */ aboutToDisappear() { console.info('NewIndex aboutToDisappear'); this.breakpointSystem.unregister(); emitter.off(888); } /** * 构建主页面结构,包括顶部横线、主内容区和抽屉菜单 */ 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) .borderRadius({ topLeft: 0, topRight : 20, bottomLeft: 0, bottomRight: 0 }) // 动态生成抽屉菜单内容 this.getDrawerView() } .width('100%') .height('100%') .onClick((event:ClickEvent)=>{ // 阻止事件冒泡 }) } .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?'36%':'70%') .height('100%') .borderRadius({ topLeft: 0, topRight : 20, bottomLeft: 0, bottomRight: 20 }) .backgroundColor($r('app.color.silvery')) .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,index:number)=>{ ListItem(){ Button({ type: ButtonType.Capsule, stateEffect: true }) { 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 }) .fontSize(22) .fontColor([this.themeColor]) .alignSelf(ItemAlign.Center) .margin({ left: 2 }) }else { Image(item.img as Resource) .height(22) .alignSelf(ItemAlign.Center) .fillColor(this.themeColor) .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) } .backgroundColor(Color.Transparent) .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 } }) } .clickEffect({level:ClickEffectLevel.HEAVY}) .transition(TransitionEffect.move(TransitionEdge.BOTTOM).animation({ duration: 600, curve: Curve.Ease, delay: 60*index })) .width('90%') .height(55) }) } .width('100%') .alignListItem(ListItemAlign.Center) .layoutWeight(1) .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; @StorageProp('topRectHeight') topRectHeight: number = px2vp(AppUtil.getStatusBarHeight()); //是否是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 ) { 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); // } // } /*** 本地会员同步弹窗内容Builder */ @Builder syncNobleDialogContentBuilder(): void { Text('检测到您是本地会员,为保障权益请登录账号,会员权益将自动同步到您的账号。') .fontSize(16) .fontColor('#222') .width('100%') .textAlign(TextAlign.Start) .padding(16) } }