rewards_home_page.dart 21 KB

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