NewIndex.ets 34 KB

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