rewards_home_page.dart 24 KB

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