rewards_home_page.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. import 'package:cpt_rewards/modules/rewards_address/rewards_address_page.dart';
  2. import 'package:cpt_rewards/modules/rewards_code/rewards_code_page.dart';
  3. import 'package:cpt_rewards/modules/rewards_detail/rewards_detail_page.dart';
  4. import 'package:cpt_rewards/modules/rewards_list/rewards_list_page.dart';
  5. import 'package:cpt_rewards/modules/rewards_my/rewards_my_page.dart';
  6. import 'package:cpt_rewards/modules/rewards_search/rewards_search_page.dart';
  7. import 'package:cs_resources/generated/assets.dart';
  8. import 'package:cs_resources/generated/l10n.dart';
  9. import 'package:cs_resources/theme/app_colors_theme.dart';
  10. import 'package:cs_resources/theme/theme_config.dart';
  11. import 'package:domain/entity/rewards_category_entity.dart';
  12. import 'package:domain/entity/rewards_home_entity.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:auto_route/auto_route.dart';
  15. import 'package:flutter/services.dart';
  16. import 'package:flutter_hooks/flutter_hooks.dart';
  17. import 'package:hooks_riverpod/hooks_riverpod.dart';
  18. import 'package:plugin_platform/engine/image/image_nine_grid.dart';
  19. import 'package:router/ext/auto_router_extensions.dart';
  20. import 'package:shared/utils/color_utils.dart';
  21. import 'package:shared/utils/log_utils.dart';
  22. import 'package:widgets/ext/ex_widget.dart';
  23. import 'package:widgets/load_state_layout.dart';
  24. import 'package:widgets/my_appbar.dart';
  25. import 'package:widgets/my_load_image.dart';
  26. import 'package:widgets/utils/dark_theme_util.dart';
  27. import '../../../router/page/rewards_page_router.dart';
  28. import './rewards_home_vm.dart';
  29. @RoutePage()
  30. class RewardsHomePage extends HookConsumerWidget {
  31. final int? points;
  32. const RewardsHomePage({Key? key, @PathParam('points') required this.points}) : super(key: key);
  33. //启动当前页面
  34. static void startInstance({
  35. BuildContext? context,
  36. int? points,
  37. }) {
  38. if (context != null) {
  39. context.router.push(RewardsHomePageRoute(points: points));
  40. } else {
  41. appRouter.push(RewardsHomePageRoute(points: points));
  42. }
  43. }
  44. Widget _buildTop(BuildContext context, WidgetRef ref, _vm) {
  45. int? point = points ?? 0;
  46. // String available = '$point'
  47. return Container(
  48. decoration: BoxDecoration(
  49. border: Border(
  50. bottom: BorderSide(
  51. color: context.appColors.btnBgDefault, // 设置bottom边框的颜色
  52. width: 45.0, // 设置bottom边框的宽度
  53. )),
  54. borderRadius: const BorderRadius.only(
  55. topLeft: Radius.circular(0.0),
  56. topRight: Radius.circular(0.0),
  57. bottomLeft: Radius.circular(30.0),
  58. bottomRight: Radius.circular(30.0),
  59. ), // 圆角
  60. ),
  61. child: Column(
  62. crossAxisAlignment: CrossAxisAlignment.start,
  63. children: [
  64. Row(
  65. crossAxisAlignment: CrossAxisAlignment.center,
  66. mainAxisAlignment: MainAxisAlignment.center,
  67. children: [
  68. Text(
  69. '$point ${S.current.available_points}',
  70. style: const TextStyle(fontSize: 18.0, color: Colors.white, fontWeight: FontWeight.w500), // 设置字体大小
  71. ).paddingOnly(left: 10, top: 0, bottom: 13),
  72. ],
  73. ),
  74. Row(
  75. crossAxisAlignment: CrossAxisAlignment.center,
  76. mainAxisAlignment: MainAxisAlignment.center,
  77. children: [
  78. Container(
  79. decoration: BoxDecoration(
  80. border: Border.all(color: Colors.white, width: 1), // 边框
  81. borderRadius: BorderRadius.circular(8), // 圆角
  82. ),
  83. child: Text(
  84. S.current.my_rewards,
  85. style: const TextStyle(fontSize: 15.0, color: Colors.white, fontWeight: FontWeight.w400), // 设置字体大小
  86. ).paddingOnly(left: 10, top: 7, bottom: 7, right: 10).onTap(() {
  87. RewardsMyPage.startInstance();
  88. }),
  89. ),
  90. // Row(
  91. // crossAxisAlignment: CrossAxisAlignment.center,
  92. // mainAxisAlignment: MainAxisAlignment.center,
  93. // children: [
  94. // const MyAssetImage(
  95. // Assets.rewardsRewardsY,
  96. // width: 26,
  97. // height: 26,
  98. // ),
  99. // Text(
  100. // 'Bronze',
  101. // style: TextStyle(
  102. // fontSize: 17.0,
  103. // color: ColorUtils.string2Color('#FFCC00'),
  104. // fontWeight: FontWeight.w500), // 设置字体大小
  105. // ).marginOnly(
  106. // left: 9,
  107. // right: 7,
  108. // ),
  109. // const MyAssetImage(
  110. // Assets.rewardsRewardsRight,
  111. // width: 7,
  112. // height: 12,
  113. // ),
  114. // ],
  115. // )
  116. ],
  117. ).paddingOnly(left: 10)
  118. ],
  119. )
  120. .paddingOnly(top: 8, left: 5, right: 15, bottom: 8)
  121. .border(bottom: 0, color: context.appColors.btnBgDefault)
  122. .backgroundColor(context.appColors.btnBgDefault),
  123. );
  124. }
  125. Widget _buildSearch(BuildContext context, WidgetRef ref, _vm) {
  126. // List itemsList = _vm.state.list.toList();
  127. return Container(
  128. width: MediaQuery.of(context).size.width - 30,
  129. height: 50,
  130. decoration: BoxDecoration(
  131. color: context.appColors.whiteSecondBG,
  132. borderRadius: BorderRadius.circular(10),
  133. ),
  134. child: Row(
  135. crossAxisAlignment: CrossAxisAlignment.center,
  136. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  137. children: [
  138. Text(
  139. S.current.search,
  140. style: TextStyle(fontSize: 15.0, color: ColorUtils.string2Color('#C7CDE3'), fontWeight: FontWeight.w500), // 设置字体大小
  141. ),
  142. const MyAssetImage(
  143. Assets.rewardsRewardsIndexSearch,
  144. width: 21,
  145. height: 21,
  146. ),
  147. ],
  148. ).paddingOnly(left: 15, right: 15),
  149. ).onTap(() {
  150. RewardsSearchPage.startInstance();
  151. });
  152. }
  153. Widget _buildSwiper(BuildContext context, WidgetRef ref, _vm) {
  154. // List itemsList = _vm.state.lists.toList();
  155. final state = ref.watch(rewardsHomeVmProvider);
  156. List<Map<String, dynamic>>? itemsList = state.categoryList;
  157. return Container(
  158. transform: Matrix4.translationValues(0.0, -10.0, 0.0),
  159. // color: Colors.white,
  160. height: 110,
  161. decoration: BoxDecoration(
  162. color: context.appColors.whiteBG,
  163. borderRadius: const BorderRadius.only(
  164. topLeft: Radius.circular(10.0),
  165. topRight: Radius.circular(0.0),
  166. bottomLeft: Radius.circular(10.0),
  167. bottomRight: Radius.circular(0.0),
  168. ),
  169. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  170. ),
  171. child: ClipRect(
  172. child: SingleChildScrollView(
  173. scrollDirection: Axis.horizontal,
  174. physics: const BouncingScrollPhysics(),
  175. clipBehavior: Clip.none,
  176. child: Row(
  177. crossAxisAlignment: CrossAxisAlignment.center,
  178. mainAxisAlignment: MainAxisAlignment.center,
  179. children: List.generate(itemsList!.length, (index) {
  180. final item = itemsList[index];
  181. return Column(
  182. crossAxisAlignment: CrossAxisAlignment.center,
  183. mainAxisAlignment: MainAxisAlignment.center,
  184. children: [
  185. MyLoadImage(
  186. item['icon'] ?? '',
  187. width: 70,
  188. height: 70,
  189. ),
  190. Text(
  191. item['name']!,
  192. style: TextStyle(fontSize: 14.0, color: context.appColors.textBlack, fontWeight: FontWeight.w600), // 设置字体大小
  193. ),
  194. ],
  195. ).marginOnly(right: 5).onTap(() {
  196. RewardsListPage.startInstance();
  197. });
  198. }),
  199. ).marginOnly(left: 15, right: 15),
  200. )),
  201. ).paddingOnly(left: 15);
  202. }
  203. Widget _buildRecommend(BuildContext context, WidgetRef ref, _vm, list) {
  204. return Container(
  205. child: Column(
  206. children: [
  207. Row(
  208. crossAxisAlignment: CrossAxisAlignment.center,
  209. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  210. children: [
  211. Text(
  212. list?['name'] ?? '',
  213. style: TextStyle(fontSize: 17.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500), // 设置字体大小
  214. ),
  215. Text(
  216. S.current.see_all,
  217. style: TextStyle(fontSize: 17.0, color: context.appColors.textPrimary, fontWeight: FontWeight.w500), // 设置字体大小
  218. ).onTap(() {
  219. RewardsListPage.startInstance();
  220. }),
  221. ],
  222. ).marginOnly(bottom: 15),
  223. list['rewards'].length > 0
  224. ? Row(
  225. crossAxisAlignment: CrossAxisAlignment.center,
  226. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  227. children: List.generate(list['rewards'].length, (index) {
  228. double hg = 70;
  229. return Container(
  230. width: MediaQuery.of(context).size.width / 2 - 25,
  231. height: 155,
  232. decoration: BoxDecoration(
  233. color: context.appColors.whiteBG,
  234. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  235. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  236. ),
  237. child: ClipRRect(
  238. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  239. child: _buildItem(context, ref, _vm, hg, list['rewards'][index])));
  240. })):
  241. const MyAssetImage(
  242. Assets.baseServicePageNoData,
  243. width: 185,
  244. height: 173,
  245. ),
  246. ],
  247. ),
  248. ).paddingOnly(left: 15, right: 15, top: 10);
  249. }
  250. Widget _buildHottest(BuildContext context, WidgetRef ref, _vm) {
  251. return Container(
  252. child: Column(
  253. children: [
  254. Row(
  255. crossAxisAlignment: CrossAxisAlignment.center,
  256. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  257. children: [
  258. Text(
  259. S.current.hottest,
  260. style: TextStyle(fontSize: 17.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500), // 设置字体大小
  261. ),
  262. Text(
  263. S.current.see_all,
  264. style: TextStyle(fontSize: 17.0, color: context.appColors.textPrimary, fontWeight: FontWeight.w500), // 设置字体大小
  265. ).onTap(() {
  266. RewardsListPage.startInstance();
  267. }),
  268. ],
  269. ).marginOnly(bottom: 15),
  270. Row(
  271. crossAxisAlignment: CrossAxisAlignment.center,
  272. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  273. children: List.generate(2, (index) {
  274. double hg = 70;
  275. return Container(
  276. width: MediaQuery.of(context).size.width / 2 - 25,
  277. height: 185,
  278. decoration: BoxDecoration(
  279. color: context.appColors.whiteBG,
  280. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  281. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  282. ),
  283. child: _buildItem(context, ref, _vm, hg, {}));
  284. }))
  285. ],
  286. ),
  287. ).paddingOnly(left: 15, right: 15, top: 10);
  288. }
  289. Widget _buildItem(BuildContext context, WidgetRef ref, _vm, height, item) {
  290. double hg = height;
  291. num point = item['point'] ?? 0;
  292. num originalPoint = item['original_point'] ?? 0;
  293. int id = item['id'];
  294. return Column(
  295. children: [
  296. MyLoadImage(
  297. item?['resources']?[0] ?? '',
  298. width: MediaQuery.of(context).size.width,
  299. height: hg,
  300. // cornerRadius:6,
  301. ),
  302. Column(
  303. crossAxisAlignment: CrossAxisAlignment.start,
  304. children: [
  305. Text(
  306. maxLines: 1, // 设置最大行数为2
  307. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  308. item?['name'] ?? '',
  309. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  310. ).marginOnly(bottom: 5),
  311. Row(
  312. children: [
  313. Text(
  314. '$point',
  315. style: TextStyle(fontSize: 18.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  316. ),
  317. Text(
  318. '$originalPoint',
  319. style: TextStyle(
  320. decoration: TextDecoration.lineThrough,
  321. decorationColor: ColorUtils.string2Color('#808DAF'),
  322. decorationStyle: TextDecorationStyle.solid,
  323. fontSize: 13.0,
  324. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#808DAF'),darkColor: Colors.white),
  325. fontWeight: FontWeight.w400),
  326. ).marginOnly(left: 5, right: 5),
  327. Text(
  328. S.current.points,
  329. style: TextStyle(fontSize: 13.0, color: context.appColors.textBlack, fontWeight: FontWeight.w400),
  330. ),
  331. ],
  332. )
  333. ],
  334. ).paddingOnly(top: 12, left: 12, right: 12)
  335. ],
  336. ).onTap(() {
  337. RewardsDetailPage.startInstance(id: id);
  338. });
  339. }
  340. Widget _buildFood(BuildContext context, WidgetRef ref, _vm, list) {
  341. return Container(
  342. child: Column(
  343. children: [
  344. Row(
  345. crossAxisAlignment: CrossAxisAlignment.center,
  346. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  347. children: [
  348. Text(
  349. list?['name'] ?? '',
  350. style: TextStyle(fontSize: 17.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500), // 设置字体大小
  351. ),
  352. Text(
  353. S.current.see_all,
  354. style: TextStyle(fontSize: 17.0, color: context.appColors.textPrimary, fontWeight: FontWeight.w500), // 设置字体大小
  355. ).onTap(() {
  356. RewardsListPage.startInstance();
  357. }),
  358. ],
  359. ).marginOnly(bottom: 15),
  360. list['rewards'].length > 0
  361. ? Row(
  362. crossAxisAlignment: CrossAxisAlignment.center,
  363. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  364. children: List.generate(list['rewards'].length, (index) {
  365. double hg = 70;
  366. return Container(
  367. width: MediaQuery.of(context).size.width / 2 - 25,
  368. height: 155,
  369. decoration: BoxDecoration(
  370. color: context.appColors.whiteBG,
  371. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  372. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  373. ),
  374. child: ClipRRect(
  375. borderRadius: const BorderRadius.all(Radius.circular(6.0)), child: _buildItem(context, ref, _vm, hg, list['rewards'][index])));
  376. })):
  377. const MyAssetImage(
  378. Assets.baseServicePageNoData,
  379. width: 185,
  380. height: 173,
  381. ),
  382. ],
  383. ),
  384. ).paddingOnly(left: 15, right: 15, top: 10);
  385. }
  386. Widget _buildBest(BuildContext context, WidgetRef ref, _vm, list) {
  387. return Container(
  388. child: Column(
  389. children: [
  390. Row(
  391. crossAxisAlignment: CrossAxisAlignment.center,
  392. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  393. children: [
  394. Text(
  395. S.current.best_offers_in_singapore,
  396. style: TextStyle(fontSize: 17.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500), // 设置字体大小
  397. ),
  398. Text(
  399. S.current.see_all,
  400. style: TextStyle(fontSize: 17.0, color: context.appColors.textPrimary, fontWeight: FontWeight.w500), // 设置字体大小
  401. ),
  402. ],
  403. ).marginOnly(bottom: 15),
  404. list['rewards'].length > 0
  405. ? Column(
  406. crossAxisAlignment: CrossAxisAlignment.center,
  407. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  408. children: List.generate(list['rewards'].length, (index) {
  409. double hg = 140;
  410. return Container(
  411. // width: MediaQuery.of(context).size.width / 2 - 25,
  412. height: 220,
  413. decoration: BoxDecoration(
  414. color:context.appColors.whiteBG,
  415. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  416. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  417. ),
  418. child: ClipRRect(
  419. borderRadius: const BorderRadius.all(Radius.circular(6.0)), child: _buildItem(context, ref, _vm, hg, list['rewards'][index])))
  420. .marginOnly(bottom: 13);
  421. })):
  422. const MyAssetImage(
  423. Assets.baseServicePageNoData,
  424. width: 185,
  425. height: 173,
  426. ),
  427. ],
  428. ),
  429. ).paddingOnly(left: 15, right: 15, top: 10);
  430. }
  431. @override
  432. Widget build(BuildContext context, WidgetRef ref) {
  433. final _vm = ref.read(rewardsHomeVmProvider.notifier);
  434. final state = ref.watch(rewardsHomeVmProvider);
  435. useEffect(() {
  436. // 组件挂载时执行 - 执行接口请求
  437. Future.microtask(() => _vm.initPageData());
  438. return () {
  439. // 组件卸载时执行s
  440. Log.d("property_news_page 组件卸载时执行");
  441. };
  442. }, []);
  443. return Scaffold(
  444. appBar: MyAppBar.appBar(
  445. context,
  446. "",
  447. backIconPath: Assets.rewardsRewardsBack,
  448. backIconWidth: 32.0,
  449. backIconHeight: 32.0,
  450. titleColor: Colors.white,
  451. titleDarkColor: Colors.white,
  452. showBackButton: true,
  453. backgroundColor: context.appColors.btnBgDefault,
  454. systemUiOverlayStyle: MediaQuery.of(context).platformBrightness == Brightness.dark
  455. ? ThemeConfig.systemUiOverlayStyleDarkTheme
  456. : ThemeConfig.systemUiOverlayStyleLightThemeWhite,
  457. ),
  458. body: Column(children: [
  459. Expanded(
  460. child: LoadStateLayout(
  461. state: state.loadingState,
  462. errorMessage: state.errorMessage,
  463. errorRetry: () {
  464. _vm.retryRequest();
  465. },
  466. successWidget: SingleChildScrollView(
  467. scrollDirection: Axis.vertical,
  468. physics: const BouncingScrollPhysics(),
  469. clipBehavior: Clip.none,
  470. child: state.list.length > 0
  471. ? Column(
  472. children: [
  473. Stack(clipBehavior: Clip.none, children: <Widget>[
  474. _buildTop(context, ref, _vm),
  475. // GestureDetector(
  476. // onTap: () {
  477. // print('第二个元素被点击'); // 这个会被触发。
  478. // },
  479. // child:Container(
  480. // transform:Matrix4.translationValues(0.0,210.0,0.0),child: _buildSearch(context,ref,_vm)//使用负数
  481. // ).paddingOnly(left:15,right:15))
  482. // Container(
  483. // // transform: Matrix4.translationValues(0.0, -25.0, 0.0),
  484. // child: _buildSearch(context, ref, _vm), // 使用负数margin
  485. // ).paddingOnly(left: 15, right: 15),
  486. Positioned(
  487. // 通过 Positioned 来确保它在红色容器的上方。
  488. left: 0, // 根据需要调整位置。
  489. bottom: -12, // 根据需要调整位置。
  490. child: GestureDetector(
  491. onTap: () {
  492. RewardsSearchPage.startInstance();
  493. },
  494. child: _buildSearch(context, ref, _vm),
  495. ).paddingOnly(left: 15, right: 15),
  496. ),
  497. ]).paddingOnly(bottom: 42),
  498. _buildSwiper(context, ref, _vm),
  499. _buildRecommend(context, ref, _vm, state.list![0]).marginOnly(bottom: 15),
  500. // _buildHottest(context, ref, _vm).marginOnly(bottom: 15),
  501. _buildFood(context, ref, _vm, state.list![2]).marginOnly(bottom: 15),
  502. _buildBest(context, ref, _vm, state.list![1]).marginOnly(bottom: 15),
  503. ],
  504. )
  505. : const Column()),
  506. )),
  507. ]).backgroundColor(context.appColors.backgroundDark),
  508. );
  509. }
  510. }