rewards_home_page.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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. cornerRadius:6,
  334. ),
  335. Column(
  336. crossAxisAlignment: CrossAxisAlignment.start,
  337. children: [
  338. Text(
  339. maxLines: 2, // 设置最大行数为2
  340. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  341. item?['name'] ?? '',
  342. style: const TextStyle(
  343. fontSize: 15.0,
  344. color: Colors.black,
  345. fontWeight: FontWeight.w500),
  346. ).marginOnly(bottom: 5),
  347. Row(
  348. children: [
  349. Text(
  350. '$point',
  351. style: const TextStyle(
  352. fontSize: 18.0,
  353. color: Colors.black,
  354. fontWeight: FontWeight.w500),
  355. ),
  356. Text(
  357. '$originalPoint',
  358. style: TextStyle(
  359. decoration: TextDecoration.lineThrough,
  360. decorationColor: ColorUtils.string2Color('#808DAF'),
  361. decorationStyle: TextDecorationStyle.solid,
  362. fontSize: 13.0,
  363. color: ColorUtils.string2Color('#808DAF'),
  364. fontWeight: FontWeight.w400),
  365. ).marginOnly(left: 5, right: 5),
  366. const Text(
  367. 'Points',
  368. style: TextStyle(
  369. fontSize: 13.0,
  370. color: Colors.black,
  371. fontWeight: FontWeight.w400),
  372. ),
  373. ],
  374. )
  375. ],
  376. ).paddingOnly(top: 12, left: 12, right: 12)
  377. ],
  378. ).onTap(() {
  379. RewardsDetailPage.startInstance(id: id);
  380. });
  381. }
  382. Widget _buildFood(BuildContext context, WidgetRef ref, _vm, list) {
  383. return list['rewards'].length > 0
  384. ? Container(
  385. child: Column(
  386. children: [
  387. Row(
  388. crossAxisAlignment: CrossAxisAlignment.center,
  389. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  390. children: [
  391. Text(
  392. list?['name'] ?? '',
  393. style: TextStyle(
  394. fontSize: 17.0,
  395. color: ColorUtils.string2Color('#000001'),
  396. fontWeight: FontWeight.w500), // 设置字体大小
  397. ),
  398. Text(
  399. 'See All',
  400. style: TextStyle(
  401. fontSize: 17.0,
  402. color: ColorUtils.string2Color('#4161D0'),
  403. fontWeight: FontWeight.w500), // 设置字体大小
  404. ).onTap(() {
  405. RewardsListPage.startInstance();
  406. }),
  407. ],
  408. ).marginOnly(bottom: 15),
  409. Row(
  410. crossAxisAlignment: CrossAxisAlignment.center,
  411. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  412. children: List.generate(list['rewards'].length, (index) {
  413. double hg = 70;
  414. return Container(
  415. width: MediaQuery.of(context).size.width / 2 - 25,
  416. height: 185,
  417. decoration: const BoxDecoration(
  418. color: Colors.white,
  419. borderRadius:
  420. BorderRadius.all(Radius.circular(6.0)),
  421. boxShadow: [
  422. BoxShadow(
  423. color: Color.fromRGBO(184, 191, 217, 0.3),
  424. blurRadius: 6)
  425. ],
  426. ),
  427. child: _buildItem(
  428. context, ref, _vm, hg, list['rewards'][index]));
  429. }))
  430. ],
  431. ),
  432. ).paddingOnly(left: 15, right: 15, top: 10)
  433. : Container();
  434. }
  435. Widget _buildBest(BuildContext context, WidgetRef ref, _vm, list) {
  436. return list['rewards'].length > 0
  437. ? Container(
  438. child: Column(
  439. children: [
  440. Row(
  441. crossAxisAlignment: CrossAxisAlignment.center,
  442. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  443. children: [
  444. Text(
  445. 'Best Offers in Singapore',
  446. style: TextStyle(
  447. fontSize: 17.0,
  448. color: ColorUtils.string2Color('#000001'),
  449. fontWeight: FontWeight.w500), // 设置字体大小
  450. ),
  451. Text(
  452. 'See All',
  453. style: TextStyle(
  454. fontSize: 17.0,
  455. color: ColorUtils.string2Color('#4161D0'),
  456. fontWeight: FontWeight.w500), // 设置字体大小
  457. ),
  458. ],
  459. ).marginOnly(bottom: 15),
  460. Column(
  461. crossAxisAlignment: CrossAxisAlignment.center,
  462. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  463. children: List.generate(list['rewards'].length, (index) {
  464. double hg = 140;
  465. return Container(
  466. // width: MediaQuery.of(context).size.width / 2 - 25,
  467. height: 220,
  468. decoration: const BoxDecoration(
  469. color: Colors.white,
  470. borderRadius:
  471. BorderRadius.all(Radius.circular(6.0)),
  472. boxShadow: [
  473. BoxShadow(
  474. color: Color.fromRGBO(184, 191, 217, 0.3),
  475. blurRadius: 6)
  476. ],
  477. ),
  478. child: _buildItem(context, ref, _vm, hg,
  479. list['rewards'][index]))
  480. .marginOnly(bottom: 13);
  481. }))
  482. ],
  483. ),
  484. ).paddingOnly(left: 15, right: 15, top: 10)
  485. : Container();
  486. }
  487. @override
  488. Widget build(BuildContext context, WidgetRef ref) {
  489. final _vm = ref.read(rewardsHomeVmProvider.notifier);
  490. final state = ref.watch(rewardsHomeVmProvider);
  491. useEffect(() {
  492. // 组件挂载时执行 - 执行接口请求
  493. Future.microtask(() => _vm.initPageData());
  494. return () {
  495. // 组件卸载时执行s
  496. Log.d("property_news_page 组件卸载时执行");
  497. };
  498. }, []);
  499. return Scaffold(
  500. // appBar: AppBar(title: Text("奖励")),
  501. body: Column(children: [
  502. Expanded(
  503. child: LoadStateLayout(
  504. state: state.loadingState,
  505. errorMessage: state.errorMessage,
  506. errorRetry: () {
  507. _vm.retryRequest();
  508. },
  509. successWidget: SingleChildScrollView(
  510. scrollDirection: Axis.vertical,
  511. physics: const BouncingScrollPhysics(),
  512. clipBehavior: Clip.none,
  513. child: state.list.length > 0
  514. ? Column(
  515. children: [
  516. _buildTop(context, ref, _vm).paddingOnly(
  517. top: MediaQuery.of(context).padding.top),
  518. Container(
  519. transform: Matrix4.translationValues(0.0, -25.0, 0.0),
  520. child: _buildSearch(context, ref, _vm), // 使用负数margin
  521. ).paddingOnly(left: 15, right: 15),
  522. _buildSwiper(context, ref, _vm),
  523. _buildRecommend(context, ref, _vm, state.list![0])
  524. .marginOnly(bottom: 15),
  525. // _buildHottest(context, ref, _vm).marginOnly(bottom: 15),
  526. _buildFood(context, ref, _vm, state.list![2])
  527. .marginOnly(bottom: 15),
  528. _buildBest(context, ref, _vm, state.list![1])
  529. .marginOnly(bottom: 15),
  530. ],
  531. )
  532. : const Column()),
  533. )),
  534. ]).backgroundColor(ColorUtils.string2Color('#F2F3F6')),
  535. );
  536. }
  537. }