NewIndex.ets 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. import { AppUtil, DeviceUtil, DisplayUtil, LogUtil, PreferencesUtil, ToastUtil } from '@pura/harmony-utils';
  2. import TitleBar from '../view/TitleBar';
  3. import { curves, router } from '@kit.ArkUI';
  4. import mainViewModel, { MainViewModel } from '../viewmodel/MainViewModel';
  5. import ItemData from '../viewmodel/ItemData';
  6. import type { sysResource } from '../viewmodel/ItemData';
  7. import { CommonConstants } from '../common/constants/CommonConstants';
  8. import { VideoItem } from '../viewmodel/VideoItem';
  9. import ScreenUtil from '../common/util/ScreenUtil';
  10. import { Utility } from '../common/util/Utility';
  11. import { BusinessError, emitter } from '@kit.BasicServicesKit';
  12. import { common } from '@kit.AbilityKit';
  13. // import { AdSlot, AdSlotBuilder,
  14. // CSJAdCreator,
  15. // CSJAdSdk, CSJNativeExpressAd, NativeExpressAdListener } from '@csj/openadsdk';
  16. import { PrintBiddingTokenUtils } from '../common/util/PrintBiddintTokenUtils';
  17. import { ArrayList } from '@kit.ArkTS';
  18. import { CSJUtil } from '../common/util/CSJUtil';
  19. import { StreamContent } from '../view/StreamContent';
  20. import { AvSessionController } from '../controller/AvSessionController';
  21. import { BreakpointSystem, BreakpointTypeEnum } from '../common/util/BreakpointSystem';
  22. import dataStorage from '@ohos.data.storage';
  23. import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
  24. import { SettingPage } from './SettingPage';
  25. import { deviceInfo } from '@kit.BasicServicesKit';
  26. import { resourceManager } from '@kit.LocalizationKit';
  27. import { systemShare } from '@kit.ShareKit';
  28. import { uniformTypeDescriptor } from '@kit.ArkData';
  29. import { hilog } from '@kit.PerformanceAnalysisKit';
  30. import { DialogHelper } from '@pura/harmony-dialog';
  31. import UserUtil from '../common/util/UserUtil';
  32. import json from '@ohos.util.json';
  33. import { UserCenter } from './UserCenter';
  34. import { ScanFilePage } from './ScanFilePage';
  35. import { AboutPage } from './AboutPage';
  36. import { smartMobilityCommon } from '@kit.CarKit';
  37. import { UpdateLogManager } from '../common/util/UpdateLogManager';
  38. import OnlineUpdateLogDialog from '../dialog/OnlineUpdateLog';
  39. import OnlineUpdateLog from '../dialog/OnlineUpdateLog';
  40. import { LocalMusic } from '../view/LocalMusic';
  41. import { ChartsCount } from './ChartsCount';
  42. // import { FFmpeg, FFProgressMessageParser } from '@sj/ffmpeg';
  43. const TAG = 'NewIndex'; // 日志标签
  44. /**
  45. * 首页主组件,包含顶部标题栏、主内容区(本地音乐/网络内容)、侧边抽屉菜单等。
  46. * 支持多端适配、广告集成、导航、生命周期管理等功能。
  47. */
  48. @Preview
  49. @Entry
  50. @Component
  51. struct NewIndex {
  52. /** 列表滚动器,用于抽屉菜单列表滚动 */
  53. private scroller: Scroller = new Scroller();
  54. /** 应用包名 */
  55. @State bundleName: string = ''
  56. @State appName: string = ''
  57. /** 是否显示侧边抽屉菜单 */
  58. @Provide isShowDrawer: boolean = false;
  59. /** 抽屉菜单 X 轴偏移量,用于手势滑动动画 */
  60. @Provide offsetX: number = 0;
  61. /** 本地视频列表,页面参数传入 */
  62. @Provide videoLocalList: Array<VideoItem> = []
  63. /** Y 轴偏移量(预留) */
  64. @State offsetY: number = 0;
  65. /** 主内容类型(0:本地音乐,1:网络内容) */
  66. @Provide mType: number = 0
  67. /** 模式类型(如歌手、专辑等) */
  68. @Provide modeType: number = 0
  69. /** 是否为零状态(预留) */
  70. @Provide('isZero') isZero: boolean = false;
  71. /** 是否显示赞助入口 */
  72. @State isShowSponsorship: boolean = false
  73. /** 页面上下文 */
  74. context = getContext(this);
  75. /** 音乐是否为零状态(预留) */
  76. @Provide('isMusicZero') isMusicZero: boolean = false;
  77. @State isShowTitleBar: boolean = true //是否显示分类导航条
  78. /** 本地音乐列表,持久化存储 */
  79. @StorageLink('musicLocalList') musicLocalList: Array<VideoItem> = []
  80. @Provide isFavMusic: boolean = false
  81. @StorageProp('windowWidth') windowWidth: number = 0;
  82. @StorageProp('windowHeight') windowHeight: number = 0;
  83. @StorageProp('isHiCarStatus') isHiCarStatus: boolean = false;
  84. @StorageProp('curDisplayIsHiCar') curDisplayIsHiCar: boolean = false;
  85. /**
  86. * 是否显示更新日志开关
  87. */
  88. @State isShowUpdateDialog: boolean = false
  89. /** 标题栏配置模型 */
  90. @State titleBarModel: TitleBar.Model = new TitleBar.Model()
  91. .setTitleTextStyle(FontStyle.Normal)
  92. .setTitleBarStyle(TitleBar.BarStyle.TRANSPARENT)
  93. .setLeftIcon($r('app.media.menu'))
  94. .setLeftIconWidth(28)
  95. .setLeftIconHeight(28)
  96. .setTitleBarMinHeight(64)
  97. .setTitleName('首页')// .setRightIcon($r('app.media.add'))
  98. .setTitleFontSize(19)
  99. .setTitleFontColor(Color.White)
  100. .setTitleBarBackground($r('app.color.title_bar_bg'))
  101. .setLeftTitleBackground($r('app.color.title_bar_bg'))
  102. .setOnLeftClickListener(() => {
  103. // 打开菜单栏动画
  104. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  105. this.isShowDrawer = true
  106. this.offsetX = 0
  107. })
  108. })
  109. .setRightTitleBackground($r('app.color.title_bar_bg'))
  110. // .setOnRightClickListener(()=>{
  111. // // this.goSelectVideo()
  112. // this.showSheelDialog()
  113. // })
  114. /** 应用版本号 */
  115. @State versionName: string = ''
  116. /** 音频根目录路径 */
  117. @Provide rootPath: string = ''
  118. /** 当前路径 */
  119. @Provide currentPath: string = ''
  120. /** 是否为历史记录页面 */
  121. @Provide isHistory: boolean = false
  122. /** 是否可以返回上一级 */
  123. @Provide isCanBack: boolean = false
  124. @StorageProp('currentColorMode') currentMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
  125. @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
  126. /**
  127. * 一多界面适配断点系统
  128. */
  129. private breakpointSystem: BreakpointSystem = new BreakpointSystem();
  130. /** 当前断点类型(如大屏/小屏) */
  131. @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD;
  132. /** 记录上一次点击返回键的时间戳,用于双击退出 */
  133. private backTime: number = 0;
  134. /**
  135. * 返回键处理逻辑:
  136. * - 如果不是根目录或有历史记录,发送广播通知更新列表
  137. * - 如果是根目录,双击返回键退出应用,否则提示
  138. */
  139. onBackPress(): boolean | void {
  140. if (this.currentPath !== this.rootPath || this.isHistory || this.isFavMusic ||
  141. (this.modeType !== 0 && this.isCanBack)) {
  142. const eventData: emitter.EventData = {};
  143. emitter.emit({ eventId: 888 }, eventData); // 发送音频广播通知更新doSwipBack
  144. } else {
  145. if (this.isShowDrawer) {
  146. // 如果抽屉菜单打开,先关闭抽屉
  147. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  148. this.isShowDrawer = false
  149. })
  150. } else {
  151. return false
  152. }
  153. }
  154. return true;
  155. }
  156. /**
  157. * 刷新@State用户信息变量,确保UI同步
  158. */
  159. refreshUserInfoState() {
  160. this.isLogin = PreferencesUtil.getBooleanSync('isLogin', false);
  161. this.userId = PreferencesUtil.getNumberSync('userId', 0);
  162. this.userName = PreferencesUtil.getStringSync('userName', '未登录用户');
  163. this.userAvatarUrl = PreferencesUtil.getStringSync('userAvatarUrl', '');
  164. this.subscriptionName = PreferencesUtil.getStringSync('subscriptionName', '');
  165. this.subscriptionEndDate = PreferencesUtil.getStringSync('subscriptionEndDate', '');
  166. this.hasActiveSubscription = PreferencesUtil.getBooleanSync('hasActiveSubscription', false);
  167. }
  168. onPageShow() {
  169. }
  170. /**
  171. * 页面显示生命周期钩子
  172. * - 注册断点系统
  173. * - 获取页面参数
  174. * - 设置状态栏样式
  175. * - 初始化图片缓存
  176. * - 判断是否显示赞助入口
  177. */
  178. async aboutToAppear() {
  179. this.isShowTitleBar = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_TITLTBAR, true)
  180. Utility.enableFullScreen()
  181. this.topRectHeight = px2vp(AppUtil.getStatusBarHeight());
  182. Utility.getAppName(getContext(this)).then((appName: string) => {
  183. this.appName = appName
  184. })
  185. this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
  186. this.breakpointSystem.register();
  187. let params = router.getParams() as Record<string, Object>;
  188. this.videoLocalList = params.videoList as VideoItem[];
  189. // Utility.setStatusBarLight()
  190. ScreenUtil.setScreenSize();
  191. this.bundleName = AppUtil.getBundleName()
  192. this.versionName = AppUtil.getVersionName();
  193. // await ImageKnife.getInstance().initFileCache(this.context, 256, 256 * 1024 * 1024)
  194. this.isShowSponsorship = Utility.isOpenTime()
  195. let themeColor = PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
  196. hilog.info(0x0000, 'Heanup', '当前 NewIndex themeColor:' + themeColor);
  197. AppStorage.setOrCreate('themeColor', themeColor);
  198. this.themeColor = themeColor
  199. // ====== 本地会员同步提醒逻辑 ======
  200. // this.refreshUserInfoState();
  201. // if (this.isLogin) {
  202. // void this.fetchUserInfo();
  203. // }
  204. console.log('Heanup isLogin:' + this.isLogin)
  205. console.log('Heanup Utility.isNobleForOld():' + Utility.isNobleForOld())
  206. await UserUtil.fetchUserInfo();
  207. this.refreshUserInfoState();
  208. let changeUserState: emitter.InnerEvent = { eventId: 1001 }
  209. emitter.on(changeUserState, () => {
  210. this.refreshUserInfoState();
  211. });
  212. let eventSetting: emitter.InnerEvent = { eventId: 333 }
  213. // 监听广播事件(通用设置配置更新)
  214. emitter.on(eventSetting, (eventData: emitter.EventData) => {
  215. this.isShowTitleBar = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_TITLTBAR, true)
  216. });
  217. console.log('getHiCarStatus isHiCarStatus:' + this.isHiCarStatus)
  218. if(this.isHiCarStatus||this.isBigScreen()){
  219. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  220. this.isShowDrawer = true
  221. this.offsetX = 0
  222. })
  223. this.isShowTitleBar = false
  224. }
  225. // 检查并显示更新日志
  226. this.checkAndShowUpdateLog();
  227. }
  228. /**
  229. * 检查并显示更新日志
  230. */
  231. private async checkAndShowUpdateLog() {
  232. try {
  233. const shouldShow = await UpdateLogManager.checkAndShowUpdateLog();
  234. if (shouldShow) {
  235. this.isShowUpdateDialog = !this.isShowUpdateDialog
  236. UpdateLogManager.markCurrentVersionShown()
  237. }
  238. // this.isShowUpdateDialog = true;//调试期间显示更新日志,测试完成后请删除
  239. } catch (error) {
  240. console.error('NewIndex checkAndShowUpdateLog error:', error);
  241. }
  242. }
  243. /**
  244. * 页面消失生命周期钩子
  245. * 注销断点系统
  246. */
  247. aboutToDisappear() {
  248. console.info('NewIndex aboutToDisappear');
  249. this.breakpointSystem.unregister();
  250. emitter.off(888);
  251. emitter.off(1001);
  252. }
  253. build() {
  254. SideBarContainer(SideBarContainerType.AUTO) {
  255. Column() {
  256. this.getLeftView()
  257. }
  258. .backgroundColor(Color.Transparent)
  259. Column() {
  260. Stack() {
  261. // 本地音乐内容区
  262. LocalMusic()
  263. .visibility(this.mType === 0 ? Visibility.Visible : Visibility.None)
  264. // 网络内容区
  265. UserCenter()
  266. .visibility(this.mType === 1 ? Visibility.Visible : Visibility.None)
  267. ScanFilePage()
  268. .visibility(this.mType === 2 ? Visibility.Visible : Visibility.None)
  269. ChartsCount({
  270. isShowDrawer:this.isShowDrawer,
  271. offsetX:this.offsetX
  272. })
  273. .visibility(this.mType === 3 ? Visibility.Visible : Visibility.None)
  274. SettingPage()
  275. .visibility(this.mType === 4 ? Visibility.Visible : Visibility.None)
  276. AboutPage()
  277. .visibility(this.mType === 5 ? Visibility.Visible : Visibility.None)
  278. // 抽屉打开时的遮罩层,用于拦截点击事件 这个只能正常尺寸的手机竖屏的才能生效
  279. if (this.isShowDrawer&&this.isPhonePortrait()) {
  280. Column()
  281. .width('100%')
  282. .height('100%')
  283. .backgroundBlurStyle(BlurStyle.BACKGROUND_THIN)
  284. .transition(TransitionEffect.OPACITY.animation({
  285. curve: curves.springMotion(0, 1)
  286. }))
  287. .onClick(() => {
  288. // 点击遮罩层关闭抽屉
  289. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  290. this.isShowDrawer = false
  291. })
  292. })
  293. }
  294. }
  295. .bindSheet($$this.isShowUpdateDialog, this.updateSheet(), {
  296. height: '90%',
  297. dragBar: true,
  298. preferType: this.currentBreakpoint !== BreakpointTypeEnum.SM ? SheetType.CENTER : SheetType.BOTTOM,
  299. showClose: true,
  300. blurStyle: BlurStyle.Regular,
  301. title: { title: '更新日志' }
  302. })
  303. }
  304. .gesture(SwipeGesture({ direction: SwipeDirection.Horizontal }).onAction((event: GestureEvent) => {
  305. if (event) {//手势返回
  306. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  307. this.isShowDrawer = !this.isShowDrawer
  308. if(this.isShowDrawer)
  309. this.offsetX = 0
  310. })
  311. }
  312. }))
  313. }
  314. .showControlButton(false)
  315. .minContentWidth(0)
  316. .sideBarWidth(260)
  317. .autoHide(true)
  318. .showSideBar($$this.isShowDrawer)
  319. .onChange((value: boolean) => {
  320. this.isShowDrawer = value
  321. })
  322. }
  323. //是不是hicar的屏幕分辨率
  324. isHiCar() {
  325. return this.isHiCarStatus&&this.curDisplayIsHiCar;
  326. // const hiCarAspectRatios: HiCarAspectRatio[] = [
  327. // { ratio: 800 / 480, name: "800x480" },
  328. // { ratio: 762 / 752, name: "762x752" },
  329. // { ratio: 968 / 1280, name: "968x1280" },
  330. // { ratio: 1200 / 1200, name: "1200x1200" },
  331. // { ratio: 1280 / 720, name: "1280x720" },
  332. // { ratio: 1920 / 1080, name: "1920x1080" }
  333. // ];
  334. // const currentRatio: number = this.windowWidth / this.windowHeight;
  335. // const RATIO_TOLERANCE: number = 0.1; // 宽高比容差
  336. //
  337. // for (const hiCarRatio of hiCarAspectRatios) {
  338. // if (Math.abs(currentRatio - hiCarRatio.ratio) <= RATIO_TOLERANCE) {
  339. // LogUtil.info(`HiCar detected: ${hiCarRatio.name}, actual: ${this.windowWidth}x${this.windowHeight}`);
  340. // return true;
  341. // }
  342. // }
  343. return false;
  344. }
  345. //是不是正常的手机竖屏
  346. isPhonePortrait() {
  347. LogUtil.info('twocold this.currentHeightBreakpoint = '+this.currentHeightBreakpoint)
  348. LogUtil.info('twocold this.currentWidthBreakpoint = '+this.currentWidthBreakpoint)
  349. if(DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
  350. &&this.currentHeightBreakpoint == HeightBreakpoint.HEIGHT_LG
  351. &&this.currentWidthBreakpoint==WidthBreakpoint.WIDTH_SM){//如果是手机横屏,返回false
  352. return true
  353. }
  354. return false
  355. }
  356. /**
  357. * 判断是否横屏
  358. * @returns
  359. */
  360. isBigScreen() {
  361. if (this.currentWidthBreakpoint == WidthBreakpoint.WIDTH_LG) {
  362. return true
  363. }
  364. if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
  365. && this.currentWidthBreakpoint === WidthBreakpoint.WIDTH_SM
  366. && this.currentHeightBreakpoint == HeightBreakpoint.HEIGHT_LG) {
  367. return false
  368. } else {
  369. return true
  370. }
  371. return false
  372. }
  373. @Builder
  374. getLeftView() {
  375. Column() {
  376. Column() {
  377. this.getDrawerView()
  378. }
  379. .width('100%')
  380. .height('100%')
  381. .onClick((event: ClickEvent) => {
  382. // 点击抽屉内部不关闭,通过返回值阻止事件传播
  383. return true
  384. })
  385. }
  386. // .width(this.currentBreakpoint !== BreakpointTypeEnum.SM?'36%':'70%')
  387. .height('100%')
  388. .borderRadius({
  389. topLeft: 0,
  390. topRight: 20,
  391. bottomLeft: 0,
  392. bottomRight: 20
  393. })
  394. // .backgroundColor($r('app.color.silvery'))
  395. // .backgroundColor($r('app.color.index_background'))
  396. .backgroundColor($r('app.color.user_center_card_background'))
  397. .alignItems(HorizontalAlign.Start)
  398. .translate({ x: this.offsetX, y: 0, z: 0 })
  399. .transition({ type: TransitionType.Insert, translate: { x: -DisplayUtil.getWidth(), y: 0 } })
  400. .transition({ type: TransitionType.Delete, translate: { x: -DisplayUtil.getWidth(), y: 0 } })
  401. .gesture(
  402. PanGesture()
  403. .onActionUpdate((event: GestureEvent) => {
  404. // 手势滑动更新抽屉偏移
  405. if (event.offsetX < 0) {
  406. this.offsetX = event.offsetX;
  407. }
  408. })
  409. .onActionEnd(() => {
  410. // 手势结束判断是否关闭抽屉
  411. if (this.offsetX < -DisplayUtil.getWidth() / 15) {
  412. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  413. this.isShowDrawer = false
  414. })
  415. } else {
  416. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  417. this.isShowDrawer = true
  418. this.offsetX = 0
  419. })
  420. }
  421. })
  422. )
  423. }
  424. @State isLogin: boolean = false;
  425. @State userAvatar: Resource = $r('app.media.icon_person2');
  426. @State userAvatarUrl: string = '';
  427. @State isVip: boolean = false;
  428. @State isDarkMode: boolean = false
  429. @State userName: string = '未登录用户';
  430. @State userId: number = 0;
  431. @State hasActiveSubscription: boolean = false;
  432. @State subscriptionName: string = '';
  433. @State subscriptionEndDate: string = '';
  434. // 用户信息卡片
  435. @Builder
  436. buildUserInfoCard() {
  437. Column() {
  438. Row() {
  439. Stack({ alignContent: Alignment.BottomEnd }){
  440. Image(this.userAvatarUrl && this.userAvatarUrl.length > 0 ? this.userAvatarUrl : this.userAvatar)
  441. .width(55)
  442. .height(55)
  443. .margin({ left: 12 })
  444. .borderRadius('50%')
  445. .clip(true)
  446. // .fillColor(this.themeColor)
  447. // .backgroundColor(this.isDarkMode ? Color.Black : Color.White)
  448. Column() {
  449. Text('VIP')
  450. .fontSize(9)
  451. .padding(2)
  452. .textAlign(TextAlign.Center)
  453. .fontWeight(FontWeight.Bolder)
  454. .fontColor(Color.White)
  455. }
  456. .width(28)
  457. .height(16)
  458. .visibility(Utility.isNoble()?Visibility.Visible:Visibility.None)
  459. .borderRadius(15)
  460. .backgroundColor(this.themeColor)
  461. }
  462. Column() {
  463. Row() {
  464. Text(this.isLogin ? this.userName : '未登录用户')
  465. .fontSize(14)
  466. // .fontWeight(FontWeight.Bold)
  467. // .fontColor(this.isDarkMode ? Color.White : Color.Black)
  468. .textAlign(TextAlign.Start)
  469. .maxLines(1)
  470. .width(110)
  471. .margin({ right: 12 })
  472. }
  473. .justifyContent(FlexAlign.Start)
  474. .margin({ top: 2 })
  475. if (this.isLogin) {
  476. if (this.hasActiveSubscription) {
  477. // Text(this.subscriptionName)
  478. // .fontSize(13)
  479. // .fontColor(themeColorWithAlpha(this.themeColor, 0.8, false))
  480. // .textAlign(TextAlign.Start)
  481. // .padding({top:5})
  482. this.TimeTextBuilder()
  483. } else {
  484. Text('普通用户')
  485. .fontSize(13)
  486. .fontColor(this.isDarkMode ? Color.White : Color.Grey)
  487. .textAlign(TextAlign.Start)
  488. .padding({top:5})
  489. this.TimeTextBuilder()
  490. }
  491. } else {
  492. this.TimeTextBuilder()
  493. }
  494. }
  495. .alignItems(HorizontalAlign.Start)
  496. .width(80)
  497. .margin({ left: 10 })
  498. }
  499. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.7})
  500. .onClick(() => {
  501. // if (!this.isLogin) {
  502. this.mType = 1
  503. if (!this.isBigScreen()) {
  504. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  505. this.isShowDrawer = false
  506. })
  507. // }
  508. }
  509. })
  510. .width('100%')
  511. .padding(10)
  512. }
  513. .backgroundColor($r('app.color.user_center_card_background'))
  514. .borderRadius(24)
  515. .width('86%')
  516. .padding(8)
  517. .margin({ left: 10, right: 10, top: this.topRectHeight + 10,bottom:10 })
  518. .shadow({
  519. radius: 8,
  520. color: 0x11000000,
  521. offsetX: 0,
  522. offsetY: 2
  523. })
  524. }
  525. @Builder
  526. TimeTextBuilder() {
  527. Text(Utility.getTimePeriod())
  528. .fontSize(13)
  529. .margin({ top: 5 })
  530. .fontColor($r('app.color.text_color'))
  531. .align(Alignment.Start)
  532. }
  533. /**
  534. * 动态生成抽屉菜单内容
  535. * 根据 isShowSponsorship 展示不同菜单项
  536. */
  537. @Builder
  538. getDrawerView() {
  539. List({ space: 0, scroller: this.scroller }) {
  540. ListItemGroup({ header: this.buildUserInfoCard() }) {
  541. ForEach(this.isHiCar()||!this.isShowTitleBar?mainViewModel.getDrawerData():mainViewModel.getDrawerData2(), (item: ItemData, index: number) => {
  542. ListItem() {
  543. Button({ type: ButtonType.Capsule, stateEffect: true }) {
  544. Row() {
  545. // 菜单图标
  546. if (typeof item.img === 'object' && item.img !== null && (item.img as sysResource).type === 'symbol') {
  547. SymbolGlyph((item.img as sysResource).value as Resource)// .size({ width: 22, height: 22 })
  548. .fontSize(22)
  549. .fontColor([this.themeColor])
  550. .effectStrategy(SymbolEffectStrategy.HIERARCHICAL)
  551. .alignSelf(ItemAlign.Center)
  552. .margin({ left: 25 })
  553. } else {
  554. Image(item.img as Resource)
  555. .height(22)
  556. .alignSelf(ItemAlign.Center)
  557. .fillColor(this.themeColor)
  558. .margin({ left: 25 })
  559. }
  560. // 菜单标题
  561. Text(item.title)
  562. .margin({ left: 10, right: 20 })
  563. .fontSize(15)
  564. .fontColor(this.isTextSelected(index) ? this.themeColor : $r('app.color.index_tab_font_color'))
  565. .fontWeight(480)
  566. Blank()
  567. // 右侧箭头
  568. Image($r('app.media.arrow_right'))
  569. .width(22)
  570. .height(22)
  571. .margin({ left: 20, right: 0 })
  572. .align(Alignment.Center)
  573. }
  574. .width('100%')
  575. .height(55)
  576. }
  577. .backgroundColor(Color.Transparent)
  578. .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.6 })
  579. .onClick(async () => {
  580. // 根据 item.id 跳转或切换功能
  581. switch (item.id) {
  582. case MainViewModel.MENU_MUSIC:
  583. this.mType = 0
  584. this.modeType = 0
  585. this.doShowDrawer()
  586. break
  587. case MainViewModel.MENU_FILE_SCAN:
  588. this.mType = 2
  589. this.doShowDrawer()
  590. break
  591. case MainViewModel.MENU_CHARTS:
  592. this.mType = 3
  593. this.modeType = 0
  594. this.doShowDrawer()
  595. break
  596. case MainViewModel.MENU_MIEDIA_KU:
  597. this.modeType = 1
  598. this.mType = 0
  599. this.doShowDrawer()
  600. break
  601. case MainViewModel.MENU_MIEDIA_ARTIST:
  602. this.modeType = 2
  603. this.mType = 0
  604. this.doShowDrawer()
  605. break
  606. case MainViewModel.MENU_MIEDIA_ALBUM:
  607. this.modeType = 3
  608. this.mType = 0
  609. this.doShowDrawer()
  610. break
  611. case MainViewModel.MENU_SETTING:
  612. this.mType = 4
  613. this.doShowDrawer()
  614. break
  615. case MainViewModel.MENU_VIP:
  616. router.pushUrl({
  617. url: 'pages/VipPage'
  618. }, router.RouterMode.Single);
  619. break
  620. case MainViewModel.MENU_USER:
  621. this.mType = 1
  622. this.doShowDrawer()
  623. break
  624. case MainViewModel.MENU_NET_CONNECT:
  625. this.mType = 1
  626. this.doShowDrawer()
  627. break
  628. case MainViewModel.MENU_SIMI:
  629. router.pushUrl({
  630. url: 'pages/VerifyPage'
  631. });
  632. break
  633. case MainViewModel.MENU_DUTY:
  634. router.pushUrl({
  635. url: 'pages/WebIndex',
  636. params: { titleName: '用户协议', webUrl: CommonConstants.NEW_DUTY }
  637. });
  638. break
  639. case MainViewModel.MENU_HAOPING:
  640. Utility.gotoMarket(getContext(this) as common.UIAbilityContext, this.bundleName)
  641. break
  642. case MainViewModel.MENU_ABOUT:
  643. this.mType = 5
  644. this.doShowDrawer()
  645. break
  646. case MainViewModel.MENU_UPDATE:
  647. AlertDialog.show({
  648. title: '版本更新',
  649. message: '当前版本为最新版本:' + this.versionName,
  650. autoCancel: true,
  651. alignment: DialogAlignment.Center,
  652. offset: { dx: 0, dy: -20 }, //在Y轴方向上的编译量
  653. confirm: {
  654. value: '确定',
  655. fontColor: Color.White,
  656. backgroundColor: $r('app.color.title_bar_bg'),
  657. action: () => {
  658. }
  659. }
  660. })
  661. break
  662. case MainViewModel.MENU_YSZC:
  663. router.pushUrl({
  664. url: 'pages/WebIndex',
  665. params: { titleName: '隐私政策', webUrl: CommonConstants.NEW_YS_HW }
  666. });
  667. break
  668. case MainViewModel.MENU_SHARE:
  669. this.gotoShare()
  670. break
  671. }
  672. })
  673. }
  674. .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  675. .animation({ duration: 600, curve: Curve.Ease, delay: 60 * index }))
  676. .width('90%')
  677. .height(55)
  678. })
  679. }
  680. }
  681. .width('86%')
  682. .borderRadius(20)
  683. .margin({
  684. bottom: 20,
  685. left: 10,
  686. right: 10,
  687. top: 10
  688. })
  689. .alignListItem(ListItemAlign.Center)
  690. .layoutWeight(1)
  691. .backgroundColor($r('app.color.left_draw_bg'))
  692. .edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果
  693. }
  694. isTextSelected(index:number):boolean{
  695. if(this.isShowTitleBar&&!this.isHiCar()){
  696. return this.mType ==index
  697. }else{
  698. if(this.mType == 0){
  699. return this.modeType == index
  700. }
  701. return this.mType+3 == index
  702. }
  703. return false
  704. }
  705. doShowDrawer(){
  706. if (!this.isBigScreen()) {
  707. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  708. this.isShowDrawer = false
  709. })
  710. }
  711. }
  712. gotoShare() {
  713. let shareData: systemShare.SharedData = new systemShare.SharedData({
  714. utd: uniformTypeDescriptor.UniformDataType.TEXT,
  715. content: 'https://appgallery.huawei.com/app/detail?id=' + this.bundleName,
  716. title: this.appName, // 不传title字段时,显示content
  717. description: '精心雕琢的无损音乐播放器',
  718. // thumbnail: new Uint8Array() // 推荐传入适合的缩略图 不传则显示默认text图标
  719. });
  720. // 进行分享面板显示
  721. let controller: systemShare.ShareController = new systemShare.ShareController(shareData);
  722. let context = getContext(this) as common.UIAbilityContext;
  723. controller.show(context, {
  724. selectionMode: systemShare.SelectionMode.SINGLE,
  725. previewMode: systemShare.SharePreviewMode.DETAIL,
  726. }).then(() => {
  727. console.info('ShareController show success.');
  728. }).catch((error: BusinessError) => {
  729. console.error(`ShareController show error. code: ${error.code}, message: ${error.message}`);
  730. });
  731. }
  732. @Builder
  733. updateSheet() {
  734. Scroll() {
  735. Column() {
  736. OnlineUpdateLog()
  737. }
  738. }
  739. .width('100%')
  740. .height('100%')
  741. }
  742. // /**
  743. // * ================== 穿山甲广告相关 ==================
  744. // */
  745. // /** Banner广告对象 */
  746. // private declare bannerAd: CSJNativeExpressAd;
  747. // /** 广告加载状态 */
  748. // @State private status: string = "未加载"
  749. // /** 是否展示广告 */
  750. // @State private isShowAd: boolean = false
  751. // /** 广告位配置信息 */
  752. // private declare mAdSlot: AdSlot;
  753. // /** 服务端bidding广告内容(可选) */
  754. // private mBiddingAdm = ''
  755. // /** 广告加载监听器 */
  756. // private expressLoadAdListener: NativeExpressAdListener = {
  757. // /**
  758. // * 广告加载失败回调
  759. // */
  760. // onError: (code: number, message: string) => {
  761. // console.error("加载广告失败,code=" + code + ",message=" + message);
  762. // this.status = "加载广告失败,code=" + code + ",message=" + message;
  763. // },
  764. // /**
  765. // * 广告加载成功回调
  766. // * @param ads 返回的广告列表
  767. // */
  768. // onNativeExpressAdLoad: (ads: ArrayList<CSJNativeExpressAd>) => {
  769. // console.log("BannerExpressAdPage==onNativeExpressAdLoad......success");
  770. // if (ads && ads.length > 0) {
  771. // ads.forEach((ad: CSJNativeExpressAd, idx: number) => {
  772. // // 设置广告交互监听
  773. // ad.setExpressInteractionListener({
  774. // /** 广告点击回调 */
  775. // onAdClicked: (type: number) => {
  776. // console.log("BannerExpressAdPage==onAdClicked......");
  777. // },
  778. // /** 广告展示回调 */
  779. // onAdShow: (type: number) => {
  780. // console.log("BannerExpressAdPage==onAdShow......");
  781. // },
  782. // /** 模板渲染失败回调 */
  783. // onRenderFail: (code: number, msg: string) => {
  784. // console.log("BannerExpressAdPage==onRenderFail...code=" + code + ",msg=" + msg);
  785. // },
  786. // /** 模板渲染成功回调 */
  787. // onRenderSuccess: (width: number, height: number) => {
  788. // console.log("BannerExpressAdPage==onRenderSuccess......width=" + width + ",height=" + height);
  789. // this.bannerAd = ad;
  790. // this.status = "广告加载完成待展示";
  791. // this.showBannerAd()
  792. // }
  793. // })
  794. // // 设置广告轮播时间
  795. // ad.setSlideIntervalTime(30 * 1000);//设置轮播时间长
  796. // this.setDislikeCallback(ad); //设置dislike
  797. // ad.render(this.getUIContext()) // 开始渲染广告
  798. // this.status = "广告加载中...";
  799. // });
  800. // }
  801. // }
  802. // }
  803. //
  804. // /**
  805. // * 设置广告 dislike 回调
  806. // * @param ad 广告对象
  807. // */
  808. // private setDislikeCallback(ad: CSJNativeExpressAd) {
  809. // ad.setDislikeCallback({
  810. // /** dislike 弹窗显示 */
  811. // onShow: () => {
  812. // console.log("BannerExpressAdPage==dislike......show");
  813. // },
  814. // /** 选择 dislike 选项 */
  815. // onSelected: (position: number, value: string, enforceRemove: boolean) => {
  816. // this.isShowAd = false;
  817. // console.log("BannerExpressAdPage==dislike......onSelected:position=" + position + ",value:" + value + ",enforce=" + enforceRemove);
  818. // },
  819. // /** 点击取消 dislike */
  820. // onCancel: () => {
  821. // console.log("BannerExpressAdPage==dislike......onCancel");
  822. // }
  823. // })
  824. // }
  825. //
  826. // /**
  827. // * 加载Banner广告
  828. // * @param rit 广告位ID
  829. // */
  830. // loadBannerAd(rit: string) {
  831. // // 仅在满足条件时加载广告
  832. // if(!Utility.isNoble()){
  833. // return
  834. // }
  835. // if(!Utility.isPassInstallTime(2)){
  836. // return
  837. // }
  838. // this.isShowAd = false;
  839. // let adCreator:CSJAdCreator = CSJAdSdk.getAdCreator()
  840. // this.mAdSlot = new AdSlotBuilder()
  841. // .setCodeId(rit)
  842. // .setAcceptSize(CSJUtil.BANNER_WIGTH, CSJUtil.BANNER_HEIGHT)
  843. // .setAdCount(1)
  844. // .setBidAdm(this.mBiddingAdm)
  845. // .build()
  846. // PrintBiddingTokenUtils.printBiddingToken(this.mAdSlot, adCreator);
  847. // adCreator.loadBannerAd(this.mAdSlot, this.expressLoadAdListener)
  848. // this.status = "广告加载中..."
  849. // }
  850. @StorageProp('currentHeightBreakpoint') currentHeightBreakpoint: HeightBreakpoint | undefined =
  851. HeightBreakpoint.HEIGHT_LG;
  852. @StorageProp('currentWidthBreakpoint') currentWidthBreakpoint: WidthBreakpoint | undefined = WidthBreakpoint.WIDTH_SM;
  853. @StorageProp('topRectHeight') topRectHeight: number = px2vp(AppUtil.getStatusBarHeight());
  854. //是否是Pura X外屏,或者小屏幕
  855. isPuraWP() {
  856. return this.currentWidthBreakpoint === WidthBreakpoint.WIDTH_SM
  857. && this.currentHeightBreakpoint === HeightBreakpoint.HEIGHT_MD
  858. }
  859. //是否是Pura X外屏,或者小屏幕或者手机横屏
  860. isCoverOpacity() {
  861. if (this.isPuraWP()) {
  862. return true
  863. }
  864. if (this.isPhoneLan()) {
  865. return true
  866. }
  867. if (deviceInfo.marketName.includes('Pura X')
  868. && this.currentHeightBreakpoint === HeightBreakpoint.HEIGHT_SM) {
  869. return true
  870. }
  871. return false
  872. }
  873. //是不是手机横屏
  874. isPhoneLan() {
  875. if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
  876. && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
  877. if (DisplayUtil.getFoldStatus() === 0) {
  878. return true
  879. }
  880. }
  881. return false
  882. }
  883. isLoginChange() {
  884. this.refreshUserInfoState();
  885. }
  886. }
  887. // 1. 工具函数:将 #RRGGBB 字符串和透明度转为 'rgba(r,g,b,a)' 字符串,深色模式下可返回深色变体
  888. function themeColorWithAlpha(themeColor: string, alpha: number, isDarkMode: boolean = false): string {
  889. if (isDarkMode) {
  890. // 深色模式下返回更深的灰色或半透明黑色
  891. return `rgba(34,34,34,${alpha + 0.2 > 1 ? 1 : alpha + 0.2})`;
  892. }
  893. const color = themeColor.replace('#', '');
  894. const r = parseInt(color.substring(0, 2), 16);
  895. const g = parseInt(color.substring(2, 4), 16);
  896. const b = parseInt(color.substring(4, 6), 16);
  897. return `rgba(${r},${g},${b},${alpha})`;
  898. }
  899. // 定义接口
  900. interface HiCarAspectRatio {
  901. ratio: number;
  902. name: string;
  903. }