rewards_detail_page.dart 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. import 'package:cpt_rewards/modules/rewards_confirm/rewards_confirm_page.dart';
  2. import 'package:cs_resources/generated/l10n.dart';
  3. import 'package:cs_resources/theme/app_colors_theme.dart';
  4. import 'package:domain/entity/rewards_detail_entity.dart';
  5. import 'package:flutter/cupertino.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:auto_route/auto_route.dart';
  8. import 'package:flutter_hooks/flutter_hooks.dart';
  9. import 'package:hooks_riverpod/hooks_riverpod.dart';
  10. import 'package:router/ext/auto_router_extensions.dart';
  11. import 'package:shared/utils/log_utils.dart';
  12. import 'package:shared/utils/color_utils.dart';
  13. import 'package:widgets/ext/ex_widget.dart';
  14. import 'package:widgets/load_state_layout.dart';
  15. import 'package:widgets/my_appbar.dart';
  16. import 'package:widgets/my_load_image.dart';
  17. import 'package:widgets/my_text_view.dart';
  18. import 'package:widgets/shatter/picker_container.dart';
  19. import 'package:widgets/utils/dark_theme_util.dart';
  20. import 'package:widgets/widget_export.dart';
  21. import 'package:cs_resources/generated/assets.dart';
  22. import '../../../router/page/rewards_page_router.dart';
  23. import './rewards_detail_vm.dart';
  24. @RoutePage()
  25. class RewardsDetailPage extends HookConsumerWidget {
  26. final int? id;
  27. const RewardsDetailPage({Key? key, @PathParam('id') required this.id}) : super(key: key);
  28. //启动当前页面
  29. static void startInstance({
  30. BuildContext? context,
  31. int? id,
  32. }) {
  33. if (context != null) {
  34. context.router.push(RewardsDetailPageRoute(id: id));
  35. } else {
  36. appRouter.push(RewardsDetailPageRoute(id: id));
  37. }
  38. }
  39. // listitem
  40. Widget _buildSaleItem(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  41. String title = detailInfo!.title ?? "";
  42. String createdAt = detailInfo.createdAt ?? "";
  43. List? resources = detailInfo!.resources ?? [];
  44. int point = detailInfo.point ?? 0;
  45. int originalPoint = detailInfo.originalPoint ?? 0;
  46. String description = detailInfo.description ?? "";
  47. bool reservation = detailInfo!.reservation;
  48. String redeemedStart = detailInfo.redeemedStart ?? "";
  49. String redeemedEnd = detailInfo.redeemedEnd ?? "";
  50. String redeemedDate = '$redeemedStart-$redeemedEnd';
  51. return Column(
  52. children: [
  53. Container(
  54. decoration: BoxDecoration(
  55. color: context.appColors.whiteBG,
  56. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  57. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  58. ),
  59. width: MediaQuery.of(context).size.width - 30,
  60. // height: 420,
  61. // margin: const EdgeInsets.only(left: 15, right: 15, top: 12.5),
  62. child: Column(
  63. children: [
  64. resources!.length > 0
  65. ? MyLoadImage(
  66. resources[0] ?? '',
  67. width: MediaQuery.of(context).size.width,
  68. height: 150,
  69. )
  70. : Container(),
  71. Column(
  72. crossAxisAlignment: CrossAxisAlignment.start,
  73. mainAxisAlignment: MainAxisAlignment.start,
  74. children: [
  75. Text(
  76. maxLines: 1, // 设置最大行数为2
  77. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  78. title,
  79. style: TextStyle(fontSize: 16.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  80. ),
  81. Text(
  82. maxLines: 1, // 设置最大行数为2
  83. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  84. '${S.current.published_date}: $createdAt',
  85. style: TextStyle(
  86. fontSize: 13.0,
  87. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#808DAF'), darkColor: Colors.white),
  88. fontWeight: FontWeight.w400),
  89. ).marginOnly(bottom: 5),
  90. Row(
  91. children: [
  92. Text(
  93. '$point',
  94. style: TextStyle(fontSize: 19.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  95. ),
  96. Text(
  97. '$originalPoint',
  98. style: TextStyle(
  99. decoration: TextDecoration.lineThrough,
  100. decorationColor: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#808DAF'), darkColor: Colors.white),
  101. decorationStyle: TextDecorationStyle.solid,
  102. fontSize: 12.0,
  103. color: ColorUtils.string2Color('#808DAF'),
  104. fontWeight: FontWeight.w400),
  105. ).marginOnly(left: 5, right: 5),
  106. Text(
  107. S.current.points,
  108. style: TextStyle(fontSize: 13.0, color: context.appColors.textBlack, fontWeight: FontWeight.w400),
  109. ),
  110. ],
  111. ),
  112. Text(
  113. description,
  114. style: TextStyle(
  115. fontSize: 13.0,
  116. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#808DAF'), darkColor: Colors.white),
  117. fontWeight: FontWeight.w400),
  118. ).marginOnly(bottom: 10, top: 10),
  119. Container(
  120. height: 28,
  121. decoration: BoxDecoration(
  122. color: ColorUtils.string2Color('#F2F3F6'),
  123. borderRadius:
  124. const BorderRadius.all(Radius.circular(6.0)),
  125. ),
  126. child: Row(
  127. mainAxisSize: MainAxisSize.min,
  128. mainAxisAlignment: MainAxisAlignment.start,
  129. crossAxisAlignment: CrossAxisAlignment.center,
  130. children: [
  131. const MyAssetImage(
  132. Assets.rewardsRewardsDetailDay,
  133. width: 25,
  134. height: 25,
  135. ).marginOnly(right: 5),
  136. Text(
  137. maxLines: 1, // 设置最大行数为2
  138. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  139. redeemedDate,
  140. style: TextStyle(
  141. fontSize: 12.0,
  142. color: ColorUtils.string2Color('#808DAF'),
  143. fontWeight: FontWeight.w400),
  144. )
  145. ],
  146. ).paddingOnly(left: 7, right: 12)),
  147. Container(
  148. height: 28,
  149. decoration: BoxDecoration(
  150. color: ColorUtils.string2Color('#F2F3F6'),
  151. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  152. ),
  153. child: Row(
  154. mainAxisSize: MainAxisSize.min,
  155. mainAxisAlignment: MainAxisAlignment.start,
  156. crossAxisAlignment: CrossAxisAlignment.center,
  157. children: [
  158. const MyAssetImage(
  159. Assets.rewardsRewardsDetailRequired,
  160. width: 25,
  161. height: 25,
  162. ).marginOnly(right: 5),
  163. Text(
  164. maxLines: 1, // 设置最大行数为2
  165. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  166. reservation ? S.current.reservation_required : S.current.no_reservation_required,
  167. style: TextStyle(
  168. fontSize: 14.0,
  169. color: ColorUtils.string2Color('#808DAF'),
  170. fontWeight: FontWeight.w400),
  171. )
  172. ],
  173. ).paddingOnly(left: 7, right: 12))
  174. .marginOnly(top: 8, bottom: 25)
  175. ],
  176. ).paddingOnly(left: 15, right: 15, top: 10),
  177. ],
  178. )),
  179. ],
  180. ).marginOnly(left: 15, bottom: 15, right: 15);
  181. }
  182. Widget _buildDeal(BuildContext context, WidgetRef ref, _vm) {
  183. return Column(
  184. children: [
  185. Container(
  186. decoration: const BoxDecoration(
  187. color: Colors.white,
  188. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  189. boxShadow: [BoxShadow(color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)],
  190. ),
  191. width: MediaQuery.of(context).size.width - 30,
  192. child: Column(
  193. crossAxisAlignment: CrossAxisAlignment.start,
  194. children: [
  195. Row(
  196. mainAxisSize: MainAxisSize.min,
  197. mainAxisAlignment: MainAxisAlignment.start,
  198. crossAxisAlignment: CrossAxisAlignment.center,
  199. children: [
  200. const MyAssetImage(
  201. Assets.rewardsRewardsDetailDeal,
  202. width: 25,
  203. height: 25,
  204. ).marginOnly(right: 10),
  205. Text(
  206. S.current.redeem_deal_at,
  207. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  208. )
  209. ],
  210. ),
  211. Container(
  212. height: 77,
  213. decoration: BoxDecoration(
  214. color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#F2F3F6'),darkColor: Colors.white),
  215. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  216. ),
  217. child: Row(
  218. mainAxisSize: MainAxisSize.max,
  219. mainAxisAlignment: MainAxisAlignment.start,
  220. crossAxisAlignment: CrossAxisAlignment.center,
  221. children: [
  222. const MyAssetImage(
  223. Assets.rewardsRewardsIndex1,
  224. width: 60,
  225. height: 60,
  226. ).marginOnly(right: 15),
  227. Column(
  228. crossAxisAlignment: CrossAxisAlignment.start,
  229. children: [
  230. Text(
  231. maxLines: 1, // 设置最大行数为2
  232. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  233. 'Delibowl Group',
  234. style: TextStyle(fontSize: 15.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w500),
  235. ).marginOnly(bottom: 8),
  236. Text(
  237. maxLines: 1, // 设置最大行数为2
  238. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  239. '#01-136, SingPost Center, 408600',
  240. style: TextStyle(fontSize: 14.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  241. )
  242. ],
  243. ).paddingOnly(
  244. top: 5,
  245. )
  246. ],
  247. ).paddingOnly(left: 12, right: 12, bottom: 9, top: 9))
  248. .marginOnly(top: 12, bottom: 12),
  249. Row(
  250. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  251. crossAxisAlignment: CrossAxisAlignment.center,
  252. children: [
  253. Text(
  254. 'Also redeemable in 1 more location',
  255. style: TextStyle(fontSize: 15.0, color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  256. ),
  257. const MyAssetImage(
  258. Assets.rewardsRewardsRight,
  259. width: 12,
  260. height: 16,
  261. ),
  262. ],
  263. ),
  264. ],
  265. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  266. ),
  267. ],
  268. ).marginOnly(left: 15, bottom: 15, right: 15);
  269. }
  270. Widget _buildPackage(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  271. String package = detailInfo.package ?? "";
  272. return Column(
  273. children: [
  274. Container(
  275. decoration: BoxDecoration(
  276. color:context.appColors.whiteBG ,
  277. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  278. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow )],
  279. ),
  280. width: MediaQuery.of(context).size.width - 30,
  281. child: Column(
  282. crossAxisAlignment: CrossAxisAlignment.start,
  283. children: [
  284. Row(
  285. mainAxisSize: MainAxisSize.min,
  286. mainAxisAlignment: MainAxisAlignment.start,
  287. crossAxisAlignment: CrossAxisAlignment.center,
  288. children: [
  289. const MyAssetImage(
  290. Assets.rewardsRewardsDetailPackage,
  291. width: 25,
  292. height: 25,
  293. ).marginOnly(right: 10),
  294. Text(
  295. 'What’s In The Package',
  296. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  297. )
  298. ],
  299. ).marginOnly(bottom: 10),
  300. Column(
  301. crossAxisAlignment: CrossAxisAlignment.start,
  302. children: [
  303. Text(
  304. package,
  305. style: TextStyle(fontSize: 15.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  306. ),
  307. ],
  308. ),
  309. ],
  310. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  311. ),
  312. ],
  313. ).marginOnly(left: 15, bottom: 15, right: 15);
  314. }
  315. Widget _buildNotice(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  316. String notice = detailInfo.notice ?? "";
  317. return Column(
  318. children: [
  319. Container(
  320. decoration: BoxDecoration(
  321. color:context.appColors.whiteBG ,
  322. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  323. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow )],
  324. ),
  325. width: MediaQuery.of(context).size.width - 30,
  326. child: Column(
  327. crossAxisAlignment: CrossAxisAlignment.start,
  328. children: [
  329. Row(
  330. mainAxisSize: MainAxisSize.min,
  331. mainAxisAlignment: MainAxisAlignment.start,
  332. crossAxisAlignment: CrossAxisAlignment.center,
  333. children: [
  334. const MyAssetImage(
  335. Assets.rewardsRewardsDetailNotice,
  336. width: 25,
  337. height: 25,
  338. ).marginOnly(right: 10),
  339. Text(
  340. S.current.redemption_notice,
  341. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  342. )
  343. ],
  344. ).marginOnly(bottom: 10),
  345. Column(
  346. crossAxisAlignment: CrossAxisAlignment.start,
  347. children: [
  348. Text(
  349. notice,
  350. style: TextStyle(fontSize: 15.0, color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  351. ),
  352. ],
  353. ),
  354. ],
  355. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  356. ),
  357. ],
  358. ).marginOnly(left: 15, bottom: 15, right: 15);
  359. }
  360. Widget _buildInstructions(BuildContext context, WidgetRef ref, _vm) {
  361. return Column(
  362. children: [
  363. Container(
  364. decoration: BoxDecoration(
  365. color: context.appColors.whiteBG ,
  366. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  367. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  368. ),
  369. width: MediaQuery.of(context).size.width - 30,
  370. child: Column(
  371. crossAxisAlignment: CrossAxisAlignment.start,
  372. children: [
  373. Row(
  374. mainAxisSize: MainAxisSize.min,
  375. mainAxisAlignment: MainAxisAlignment.start,
  376. crossAxisAlignment: CrossAxisAlignment.center,
  377. children: [
  378. const MyAssetImage(
  379. Assets.rewardsRewardsDetailInstructions,
  380. width: 25,
  381. height: 25,
  382. ).marginOnly(right: 10),
  383. Text(
  384. S.current.redemption_instructions,
  385. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  386. )
  387. ],
  388. ).marginOnly(bottom: 10),
  389. Column(
  390. crossAxisAlignment: CrossAxisAlignment.start,
  391. children: [
  392. Text(
  393. S.current.redemption_reservation_txt,
  394. style: TextStyle(fontSize: 15.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  395. ),
  396. ],
  397. ),
  398. ],
  399. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  400. ),
  401. ],
  402. ).marginOnly(left: 15, bottom: 15, right: 15);
  403. }
  404. Widget _buildRedeemable(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  405. List? redeemable = detailInfo!.redeemable ?? [];
  406. return Column(
  407. children: [
  408. Container(
  409. decoration: BoxDecoration(
  410. color: context.appColors.whiteBG ,
  411. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  412. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow )],
  413. ),
  414. width: MediaQuery.of(context).size.width - 30,
  415. child: Column(
  416. crossAxisAlignment: CrossAxisAlignment.start,
  417. children: [
  418. Row(
  419. mainAxisSize: MainAxisSize.min,
  420. mainAxisAlignment: MainAxisAlignment.start,
  421. crossAxisAlignment: CrossAxisAlignment.center,
  422. children: [
  423. const MyAssetImage(
  424. Assets.rewardsRewardsDetailNotice,
  425. width: 25,
  426. height: 25,
  427. ).marginOnly(right: 10),
  428. Text(
  429. S.current.redeemable_on,
  430. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  431. )
  432. ],
  433. ).marginOnly(bottom: 10),
  434. Column(
  435. crossAxisAlignment: CrossAxisAlignment.start,
  436. children: List.generate(
  437. redeemable!.length,
  438. (index) {
  439. final item = redeemable[index];
  440. return Text(
  441. '${item.day}: ${item.time}',
  442. style: TextStyle(fontSize: 15.0, color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  443. );
  444. },
  445. ),
  446. ),
  447. ],
  448. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  449. ),
  450. ],
  451. ).marginOnly(left: 15, bottom: 15, right: 15);
  452. }
  453. @override
  454. Widget build(BuildContext context, WidgetRef ref) {
  455. final _vm = ref.read(rewardsDetailVmProvider.notifier);
  456. final state = ref.watch(rewardsDetailVmProvider);
  457. RewardsDetailEntity? detailInfo = state.detailInfo;
  458. useEffect(() {
  459. // 组件挂载时执行 - 执行接口请求
  460. Future.microtask(() => _vm.initPageData(id: id));
  461. return () {
  462. // 组件卸载时执行
  463. Log.d("property_news_page 组件卸载时执行");
  464. };
  465. }, []);
  466. return Scaffold(
  467. appBar: MyAppBar.appBar(
  468. context,
  469. S.current.detail,
  470. backgroundColor: context.appColors.whiteBG,
  471. ),
  472. body: LoadStateLayout(
  473. state: state.loadingState,
  474. errorMessage: state.errorMessage,
  475. errorRetry: () {
  476. _vm.retryRequest(id: id);
  477. },
  478. successWidget: Column(
  479. children: [
  480. Expanded(
  481. child: SingleChildScrollView(
  482. scrollDirection: Axis.vertical,
  483. physics: const BouncingScrollPhysics(),
  484. clipBehavior: Clip.none,
  485. child: Column(
  486. children: [
  487. Container(
  488. color: context.appColors.backgroundDark,
  489. padding: const EdgeInsets.only(top: 15),
  490. child: Column(
  491. children: [
  492. _buildSaleItem(context, ref, _vm, detailInfo),
  493. // _buildDeal(context, ref, _vm),
  494. _buildPackage(context, ref, _vm, detailInfo),
  495. _buildNotice(context, ref, _vm, detailInfo),
  496. // _buildInstructions(context, ref, _vm),
  497. _buildRedeemable(context, ref, _vm, detailInfo),
  498. ],
  499. )),
  500. ],
  501. ))),
  502. Container(
  503. height: 50,
  504. color: context.appColors.btnBgDefault,
  505. child: Flex(
  506. direction: Axis.horizontal,
  507. children: [
  508. Expanded(
  509. flex: 1,
  510. child: Container(
  511. color: context.appColors.btnBgDefault,
  512. height: 100,
  513. child: Row(
  514. mainAxisAlignment: MainAxisAlignment.center,
  515. crossAxisAlignment: CrossAxisAlignment.center,
  516. children: [
  517. MyTextView(
  518. S.current.redeem,
  519. fontSize: 16,
  520. textColor: Colors.white,
  521. isFontMedium: true,
  522. ),
  523. ],
  524. ),
  525. ).onTap(() {
  526. RewardsConfirmPage.startInstance(id: detailInfo?.id);
  527. }),
  528. ),
  529. ],
  530. ),
  531. )
  532. ],
  533. )),
  534. );
  535. }
  536. }