rewards_detail_page.dart 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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. MyAssetImage(
  132. Assets.rewardsRewardsDetailDay,
  133. width: 25,
  134. height: 25,
  135. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  136. ).marginOnly(right: 5),
  137. Text(
  138. maxLines: 1, // 设置最大行数为2
  139. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  140. redeemedDate,
  141. style: TextStyle(
  142. fontSize: 12.0,
  143. color: ColorUtils.string2Color('#808DAF'),
  144. fontWeight: FontWeight.w400),
  145. )
  146. ],
  147. ).paddingOnly(left: 7, right: 12)),
  148. Container(
  149. height: 28,
  150. decoration: BoxDecoration(
  151. color: ColorUtils.string2Color('#F2F3F6'),
  152. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  153. ),
  154. child: Row(
  155. mainAxisSize: MainAxisSize.min,
  156. mainAxisAlignment: MainAxisAlignment.start,
  157. crossAxisAlignment: CrossAxisAlignment.center,
  158. children: [
  159. MyAssetImage(
  160. Assets.rewardsRewardsDetailRequired,
  161. width: 25,
  162. height: 25,
  163. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  164. ).marginOnly(right: 5),
  165. Text(
  166. maxLines: 1, // 设置最大行数为2
  167. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  168. reservation ? S.current.reservation_required : S.current.no_reservation_required,
  169. style: TextStyle(
  170. fontSize: 14.0,
  171. color: ColorUtils.string2Color('#808DAF'),
  172. fontWeight: FontWeight.w400),
  173. )
  174. ],
  175. ).paddingOnly(left: 7, right: 12))
  176. .marginOnly(top: 8, bottom: 25)
  177. ],
  178. ).paddingOnly(left: 15, right: 15, top: 10),
  179. ],
  180. )),
  181. ],
  182. ).marginOnly(left: 15, bottom: 15, right: 15);
  183. }
  184. Widget _buildDeal(BuildContext context, WidgetRef ref, _vm) {
  185. return Column(
  186. children: [
  187. Container(
  188. decoration: const BoxDecoration(
  189. color: Colors.white,
  190. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  191. boxShadow: [BoxShadow(color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)],
  192. ),
  193. width: MediaQuery.of(context).size.width - 30,
  194. child: Column(
  195. crossAxisAlignment: CrossAxisAlignment.start,
  196. children: [
  197. Row(
  198. mainAxisSize: MainAxisSize.min,
  199. mainAxisAlignment: MainAxisAlignment.start,
  200. crossAxisAlignment: CrossAxisAlignment.center,
  201. children: [
  202. MyAssetImage(
  203. Assets.rewardsRewardsDetailDeal,
  204. width: 25,
  205. height: 25,
  206. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  207. ).marginOnly(right: 10),
  208. Text(
  209. S.current.redeem_deal_at,
  210. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  211. )
  212. ],
  213. ),
  214. Container(
  215. height: 77,
  216. decoration: BoxDecoration(
  217. color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#F2F3F6'),darkColor: Colors.white),
  218. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  219. ),
  220. child: Row(
  221. mainAxisSize: MainAxisSize.max,
  222. mainAxisAlignment: MainAxisAlignment.start,
  223. crossAxisAlignment: CrossAxisAlignment.center,
  224. children: [
  225. MyAssetImage(
  226. Assets.rewardsRewardsIndex1,
  227. width: 60,
  228. height: 60,
  229. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  230. ).marginOnly(right: 15),
  231. Column(
  232. crossAxisAlignment: CrossAxisAlignment.start,
  233. children: [
  234. Text(
  235. maxLines: 1, // 设置最大行数为2
  236. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  237. 'Delibowl Group',
  238. style: TextStyle(fontSize: 15.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w500),
  239. ).marginOnly(bottom: 8),
  240. Text(
  241. maxLines: 1, // 设置最大行数为2
  242. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  243. '#01-136, SingPost Center, 408600',
  244. style: TextStyle(fontSize: 14.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  245. )
  246. ],
  247. ).paddingOnly(
  248. top: 5,
  249. )
  250. ],
  251. ).paddingOnly(left: 12, right: 12, bottom: 9, top: 9))
  252. .marginOnly(top: 12, bottom: 12),
  253. Row(
  254. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  255. crossAxisAlignment: CrossAxisAlignment.center,
  256. children: [
  257. Text(
  258. 'Also redeemable in 1 more location',
  259. style: TextStyle(fontSize: 15.0, color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  260. ),
  261. MyAssetImage(
  262. Assets.rewardsRewardsRight,
  263. width: 12,
  264. height: 16,
  265. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  266. ),
  267. ],
  268. ),
  269. ],
  270. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  271. ),
  272. ],
  273. ).marginOnly(left: 15, bottom: 15, right: 15);
  274. }
  275. Widget _buildPackage(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  276. String package = detailInfo.package ?? "";
  277. return Column(
  278. children: [
  279. Container(
  280. decoration: BoxDecoration(
  281. color:context.appColors.whiteBG ,
  282. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  283. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow )],
  284. ),
  285. width: MediaQuery.of(context).size.width - 30,
  286. child: Column(
  287. crossAxisAlignment: CrossAxisAlignment.start,
  288. children: [
  289. Row(
  290. mainAxisSize: MainAxisSize.min,
  291. mainAxisAlignment: MainAxisAlignment.start,
  292. crossAxisAlignment: CrossAxisAlignment.center,
  293. children: [
  294. MyAssetImage(
  295. Assets.rewardsRewardsDetailPackage,
  296. width: 25,
  297. height: 25,
  298. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  299. ).marginOnly(right: 10),
  300. Text(
  301. 'What’s In The Package',
  302. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  303. )
  304. ],
  305. ).marginOnly(bottom: 10),
  306. Column(
  307. crossAxisAlignment: CrossAxisAlignment.start,
  308. children: [
  309. Text(
  310. package,
  311. style: TextStyle(fontSize: 15.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  312. ),
  313. ],
  314. ),
  315. ],
  316. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  317. ),
  318. ],
  319. ).marginOnly(left: 15, bottom: 15, right: 15);
  320. }
  321. Widget _buildNotice(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  322. String notice = detailInfo.notice ?? "";
  323. return Column(
  324. children: [
  325. Container(
  326. decoration: BoxDecoration(
  327. color:context.appColors.whiteBG ,
  328. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  329. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow )],
  330. ),
  331. width: MediaQuery.of(context).size.width - 30,
  332. child: Column(
  333. crossAxisAlignment: CrossAxisAlignment.start,
  334. children: [
  335. Row(
  336. mainAxisSize: MainAxisSize.min,
  337. mainAxisAlignment: MainAxisAlignment.start,
  338. crossAxisAlignment: CrossAxisAlignment.center,
  339. children: [
  340. MyAssetImage(
  341. Assets.rewardsRewardsDetailNotice,
  342. width: 25,
  343. height: 25,
  344. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  345. ).marginOnly(right: 10),
  346. Text(
  347. S.current.redemption_notice,
  348. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  349. )
  350. ],
  351. ).marginOnly(bottom: 10),
  352. Column(
  353. crossAxisAlignment: CrossAxisAlignment.start,
  354. children: [
  355. Text(
  356. notice,
  357. style: TextStyle(fontSize: 15.0, color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  358. ),
  359. ],
  360. ),
  361. ],
  362. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  363. ),
  364. ],
  365. ).marginOnly(left: 15, bottom: 15, right: 15);
  366. }
  367. Widget _buildInstructions(BuildContext context, WidgetRef ref, _vm) {
  368. return Column(
  369. children: [
  370. Container(
  371. decoration: BoxDecoration(
  372. color: context.appColors.whiteBG ,
  373. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  374. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  375. ),
  376. width: MediaQuery.of(context).size.width - 30,
  377. child: Column(
  378. crossAxisAlignment: CrossAxisAlignment.start,
  379. children: [
  380. Row(
  381. mainAxisSize: MainAxisSize.min,
  382. mainAxisAlignment: MainAxisAlignment.start,
  383. crossAxisAlignment: CrossAxisAlignment.center,
  384. children: [
  385. MyAssetImage(
  386. Assets.rewardsRewardsDetailInstructions,
  387. width: 25,
  388. height: 25,
  389. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  390. ).marginOnly(right: 10),
  391. Text(
  392. S.current.redemption_instructions,
  393. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  394. )
  395. ],
  396. ).marginOnly(bottom: 10),
  397. Column(
  398. crossAxisAlignment: CrossAxisAlignment.start,
  399. children: [
  400. Text(
  401. S.current.redemption_reservation_txt,
  402. style: TextStyle(fontSize: 15.0, color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  403. ),
  404. ],
  405. ),
  406. ],
  407. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  408. ),
  409. ],
  410. ).marginOnly(left: 15, bottom: 15, right: 15);
  411. }
  412. Widget _buildRedeemable(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  413. List? redeemable = detailInfo!.redeemable ?? [];
  414. return Column(
  415. children: [
  416. Container(
  417. decoration: BoxDecoration(
  418. color: context.appColors.whiteBG ,
  419. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  420. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow )],
  421. ),
  422. width: MediaQuery.of(context).size.width - 30,
  423. child: Column(
  424. crossAxisAlignment: CrossAxisAlignment.start,
  425. children: [
  426. Row(
  427. mainAxisSize: MainAxisSize.min,
  428. mainAxisAlignment: MainAxisAlignment.start,
  429. crossAxisAlignment: CrossAxisAlignment.center,
  430. children: [
  431. MyAssetImage(
  432. Assets.rewardsRewardsDetailNotice,
  433. width: 25,
  434. height: 25,
  435. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  436. ).marginOnly(right: 10),
  437. Text(
  438. S.current.redeemable_on,
  439. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack , fontWeight: FontWeight.w500),
  440. )
  441. ],
  442. ).marginOnly(bottom: 10),
  443. Column(
  444. crossAxisAlignment: CrossAxisAlignment.start,
  445. children: List.generate(
  446. redeemable!.length,
  447. (index) {
  448. final item = redeemable[index];
  449. return Text(
  450. '${item.day}: ${item.time}',
  451. style: TextStyle(fontSize: 15.0, color:DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#54638C'),darkColor: Colors.white), fontWeight: FontWeight.w400),
  452. );
  453. },
  454. ),
  455. ),
  456. ],
  457. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  458. ),
  459. ],
  460. ).marginOnly(left: 15, bottom: 15, right: 15);
  461. }
  462. @override
  463. Widget build(BuildContext context, WidgetRef ref) {
  464. final _vm = ref.read(rewardsDetailVmProvider.notifier);
  465. final state = ref.watch(rewardsDetailVmProvider);
  466. RewardsDetailEntity? detailInfo = state.detailInfo;
  467. useEffect(() {
  468. // 组件挂载时执行 - 执行接口请求
  469. Future.microtask(() => _vm.initPageData(id: id));
  470. return () {
  471. // 组件卸载时执行
  472. Log.d("property_news_page 组件卸载时执行");
  473. };
  474. }, []);
  475. return Scaffold(
  476. appBar: MyAppBar.appBar(
  477. context,
  478. S.current.detail,
  479. backgroundColor: context.appColors.whiteBG,
  480. ),
  481. body: LoadStateLayout(
  482. state: state.loadingState,
  483. errorMessage: state.errorMessage,
  484. errorRetry: () {
  485. _vm.retryRequest(id: id);
  486. },
  487. successWidget: Column(
  488. children: [
  489. Expanded(
  490. child: SingleChildScrollView(
  491. scrollDirection: Axis.vertical,
  492. physics: const BouncingScrollPhysics(),
  493. clipBehavior: Clip.none,
  494. child: Column(
  495. children: [
  496. Container(
  497. color: context.appColors.backgroundDark,
  498. padding: const EdgeInsets.only(top: 15),
  499. child: Column(
  500. children: [
  501. _buildSaleItem(context, ref, _vm, detailInfo),
  502. // _buildDeal(context, ref, _vm),
  503. _buildPackage(context, ref, _vm, detailInfo),
  504. _buildNotice(context, ref, _vm, detailInfo),
  505. // _buildInstructions(context, ref, _vm),
  506. _buildRedeemable(context, ref, _vm, detailInfo),
  507. ],
  508. )),
  509. ],
  510. ))),
  511. Container(
  512. height: 50,
  513. color: context.appColors.btnBgDefault,
  514. child: Flex(
  515. direction: Axis.horizontal,
  516. children: [
  517. Expanded(
  518. flex: 1,
  519. child: Container(
  520. color: context.appColors.btnBgDefault,
  521. height: 100,
  522. child: Row(
  523. mainAxisAlignment: MainAxisAlignment.center,
  524. crossAxisAlignment: CrossAxisAlignment.center,
  525. children: [
  526. MyTextView(
  527. S.current.redeem,
  528. fontSize: 16,
  529. textColor: Colors.white,
  530. isFontMedium: true,
  531. ),
  532. ],
  533. ),
  534. ).onTap(() {
  535. RewardsConfirmPage.startInstance(id: detailInfo?.id);
  536. }),
  537. ),
  538. ],
  539. ),
  540. )
  541. ],
  542. )),
  543. );
  544. }
  545. }