member_page.dart 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. import 'dart:io';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/gestures.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/src/widgets/framework.dart';
  7. import 'package:flutter_screenutil/flutter_screenutil.dart';
  8. import 'package:get/get.dart';
  9. import 'package:get/get_core/src/get_main.dart';
  10. import 'package:location/base/base_page.dart';
  11. import 'package:location/module/member/member_controller.dart';
  12. import 'package:location/resource/assets.gen.dart';
  13. import 'package:location/resource/colors.gen.dart';
  14. import 'package:location/utils/common_expand.dart';
  15. import 'package:location/utils/project_expand.dart';
  16. import 'package:location/widget/auto_scroll_list_view.dart';
  17. import '../../data/bean/member_status_info.dart';
  18. import '../../data/bean/pay_item_bean.dart';
  19. import '../../data/consts/payment_type.dart';
  20. import '../../resource/fonts.gen.dart';
  21. import '../../resource/string.gen.dart';
  22. import '../../router/app_pages.dart';
  23. import '../../utils/date_util.dart';
  24. import '../../widget/animated_switcher_widget.dart';
  25. import 'member_discount_countdown_widget.dart';
  26. import 'member_evaluate_bean.dart';
  27. import 'member_header_cycle_widget.dart';
  28. ///进入会员类型
  29. enum MemberPageType {
  30. ///通用进入
  31. universalAccessEnter,
  32. ///倒计时试用完会员进入
  33. afeterTrialMemberEnter,
  34. ///加好友进入
  35. addFriendToEnter,
  36. }
  37. class MemberPage extends BasePage<MemberController> {
  38. MemberPage({super.key,this.pageType});
  39. late MemberPageType? pageType = MemberPageType.universalAccessEnter;
  40. static void start({MemberPageType? enterTyp = MemberPageType.universalAccessEnter}) {
  41. Get.toNamed(RoutePath.member,arguments: enterTyp);
  42. }
  43. @override
  44. bool immersive() {
  45. return true;
  46. }
  47. @override
  48. bool statusBarDarkFont() {
  49. return false;
  50. }
  51. @override
  52. Widget buildBody(BuildContext context) {
  53. return PopScope(
  54. canPop: false,
  55. onPopInvokedWithResult: (bool didPop, dynamic result) async {
  56. controller.onPopBack();
  57. },
  58. child: Stack(
  59. children: [
  60. SingleChildScrollView(
  61. physics: const ClampingScrollPhysics(),
  62. controller: controller.scrollController,
  63. child: Stack(
  64. children: [
  65. MemberHeaderCycleWidget(),
  66. Column(
  67. children: [
  68. SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top),
  69. Container(
  70. decoration: BoxDecoration(
  71. color: ColorName.white,
  72. borderRadius: BorderRadius.only(
  73. topLeft: Radius.circular(20.w),
  74. topRight: Radius.circular(20.w)),
  75. ),
  76. child: Stack(
  77. children: [
  78. Container(
  79. decoration: BoxDecoration(
  80. borderRadius: BorderRadius.only(
  81. topLeft: Radius.circular(20.w),
  82. topRight: Radius.circular(20.w)),
  83. image: DecorationImage(
  84. image: Assets.images.iconMemberVipMiddleBg.provider(),
  85. )
  86. ),
  87. width: double.infinity,
  88. height: 174,
  89. ),
  90. Container(
  91. width: double.infinity,
  92. decoration: BoxDecoration(
  93. borderRadius: BorderRadius.only(
  94. topLeft: Radius.circular(20.w),
  95. topRight: Radius.circular(20.w)),
  96. image: DecorationImage(image: Assets.images.iconMemberVipMiddleBg.provider())
  97. ),
  98. child: Column(
  99. crossAxisAlignment: CrossAxisAlignment.start,
  100. children: [
  101. SizedBox(height: 15.w),
  102. buildUserInfoView(),
  103. SizedBox(height: 26.w),
  104. SizedBox(height: 23.w),
  105. buildGoodsList(),
  106. SizedBox(height: 12.w),
  107. buildPrivacyPolicyView(),
  108. buildPayWayView(),
  109. SizedBox(height: 30.w),
  110. Padding(
  111. padding: EdgeInsets.only(left: 12.w),
  112. child: Text(StringName.memberEquityIntroduction,
  113. style: TextStyle(
  114. fontSize: 16.sp,
  115. color: ColorName.black90,
  116. fontWeight: FontWeight.bold)),
  117. ),
  118. SizedBox(height: 19.w),
  119. buildFunctionList(),
  120. SizedBox(height: 40.w),
  121. Padding(
  122. padding: EdgeInsets.only(left: 12.w),
  123. child: Text(StringName.memberUserEvaluate,
  124. style: TextStyle(
  125. fontSize: 16.sp,
  126. color: ColorName.black90,
  127. fontWeight: FontWeight.bold)),
  128. ),
  129. SizedBox(height: 8.w),
  130. buildUserEvaluateList(),
  131. SizedBox(height: 20.w),
  132. Container(
  133. padding: EdgeInsets.all(12.w),
  134. decoration: BoxDecoration(
  135. color: '#F7F7F7'.color,
  136. borderRadius: BorderRadius.circular(6.w)),
  137. margin: EdgeInsets.symmetric(horizontal: 12.w),
  138. child: Text(StringName.memberTips,
  139. style: TextStyle(
  140. fontSize: 12.sp, color: '#A7A7A7'.color)),
  141. ),
  142. SizedBox(height: 100.w)
  143. ],
  144. ),
  145. ),
  146. ],
  147. ),
  148. )
  149. ],
  150. ),
  151. ],
  152. )
  153. /*Stack(
  154. children: [
  155. Assets.images.bgMemberHeader.image(width: double.infinity),
  156. SafeArea(
  157. child: Column(
  158. children: [
  159. SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top),
  160. buildUserInfoView(),
  161. SizedBox(height: 26.w),
  162. Container(
  163. width: double.infinity,
  164. decoration: BoxDecoration(
  165. borderRadius: BorderRadius.only(
  166. topLeft: Radius.circular(14.w),
  167. topRight: Radius.circular(14.w)),
  168. gradient: LinearGradient(
  169. begin: Alignment.topCenter,
  170. end: Alignment.bottomCenter,
  171. stops: [0.0, 0.1],
  172. colors: ['#EFE9FF'.color, Colors.white])),
  173. child: Column(
  174. crossAxisAlignment: CrossAxisAlignment.start,
  175. children: [
  176. SizedBox(height: 23.w),
  177. buildGoodsList(),
  178. SizedBox(height: 12.w),
  179. buildPrivacyPolicyView(),
  180. buildPayWayView(),
  181. SizedBox(height: 30.w),
  182. Padding(
  183. padding: EdgeInsets.only(left: 12.w),
  184. child: Text(StringName.memberEquityIntroduction,
  185. style: TextStyle(
  186. fontSize: 16.sp,
  187. color: ColorName.black90,
  188. fontWeight: FontWeight.bold)),
  189. ),
  190. SizedBox(height: 19.w),
  191. buildFunctionList(),
  192. SizedBox(height: 40.w),
  193. Padding(
  194. padding: EdgeInsets.only(left: 12.w),
  195. child: Text(StringName.memberUserEvaluate,
  196. style: TextStyle(
  197. fontSize: 16.sp,
  198. color: ColorName.black90,
  199. fontWeight: FontWeight.bold)),
  200. ),
  201. SizedBox(height: 8.w),
  202. buildUserEvaluateList(),
  203. SizedBox(height: 20.w),
  204. Container(
  205. padding: EdgeInsets.all(12.w),
  206. decoration: BoxDecoration(
  207. color: '#F7F7F7'.color,
  208. borderRadius: BorderRadius.circular(6.w)),
  209. margin: EdgeInsets.symmetric(horizontal: 12.w),
  210. child: Text(StringName.memberTips,
  211. style: TextStyle(
  212. fontSize: 12.sp, color: '#A7A7A7'.color)),
  213. ),
  214. SizedBox(height: 100.w)
  215. ],
  216. ),
  217. )
  218. ],
  219. ),
  220. )
  221. ],
  222. ),*/
  223. ),
  224. buildHeadBar(),
  225. buildMemberBottomView()
  226. ],
  227. ),
  228. );
  229. }
  230. Widget buildGoodsList() {
  231. return Obx(() {
  232. return SizedBox(
  233. height: 123.w,
  234. child: ListView.builder(
  235. padding: EdgeInsets.only(left: 12.w),
  236. physics: const BouncingScrollPhysics(
  237. parent: AlwaysScrollableScrollPhysics()),
  238. scrollDirection: Axis.horizontal,
  239. itemBuilder: (BuildContext ctx, int index) {
  240. return Obx(() {
  241. final item = controller.goodsList[index];
  242. bool isSelected = controller.selectedGoods?.id == item.id;
  243. return GestureDetector(
  244. behavior: HitTestBehavior.translucent,
  245. onTap: () => controller.onGoodsItemClick(item),
  246. child: Container(
  247. margin: EdgeInsets.only(right: 10.w),
  248. width: 138.w,
  249. height: 123.w,
  250. child: Stack(
  251. children: [
  252. Container(
  253. width: double.infinity,
  254. height: double.infinity,
  255. decoration: BoxDecoration(
  256. color: isSelected
  257. ? '#6BC4BAFF'.color
  258. : ColorName.white20,
  259. borderRadius: BorderRadius.circular(18.w),
  260. border: Border.all(
  261. color: isSelected
  262. ? '#C4BAFF'.color
  263. : '#E8E8E8'.color,
  264. width: 3.w)),
  265. padding: EdgeInsets.only(left: 10.w),
  266. child: Column(
  267. crossAxisAlignment: CrossAxisAlignment.start,
  268. children: [
  269. Spacer(flex: 2),
  270. Text(
  271. item.name,
  272. style: TextStyle(
  273. fontSize: 14.sp,
  274. color: ColorName.black90,
  275. fontWeight: FontWeight.bold),
  276. ),
  277. SizedBox(height: 3.w),
  278. Text('¥${item.originalAmount.divideBy100()}',
  279. style: TextStyle(
  280. decoration: TextDecoration.lineThrough,
  281. fontSize: 10.sp,
  282. color: ColorName.black60)),
  283. Spacer(flex: 1),
  284. RichText(
  285. text: TextSpan(
  286. style: TextStyle(
  287. color: isSelected
  288. ? '#EA1231'.color
  289. : ColorName.black80,
  290. fontWeight: FontWeight.bold),
  291. children: [
  292. TextSpan(
  293. text: '¥',
  294. style: TextStyle(
  295. fontSize: 20.sp, height: 1)),
  296. TextSpan(
  297. text: item.amount.divideBy100(),
  298. style: TextStyle(
  299. fontSize: 34.sp,
  300. height: 1,
  301. fontFamily: FontFamily.oppoSans))
  302. ])),
  303. Padding(
  304. padding: EdgeInsets.only(left: 7.w),
  305. child: Text(item.description ?? '',
  306. style: TextStyle(
  307. fontSize: 12.sp,
  308. color: ColorName.black40)),
  309. ),
  310. Spacer(
  311. flex: 1,
  312. )
  313. ],
  314. ),
  315. ),
  316. Visibility(
  317. visible: item.tag?.isNotEmpty == true,
  318. child: Positioned(
  319. top: 0,
  320. right: 0,
  321. child: Container(
  322. decoration: BoxDecoration(
  323. gradient: LinearGradient(colors: [
  324. '#A26CFF'.color,
  325. '#FF7CD8'.color,
  326. '#898BFF'.color
  327. ]),
  328. borderRadius: BorderRadius.only(
  329. topRight: Radius.circular(11.w),
  330. bottomLeft: Radius.circular(11.w))),
  331. padding: EdgeInsets.symmetric(
  332. horizontal: 10.w, vertical: 4.w),
  333. child: Text(item.tag ?? '',
  334. style: TextStyle(
  335. fontSize: 12.sp,
  336. color: Colors.white)),
  337. ),
  338. ))
  339. ],
  340. )),
  341. );
  342. });
  343. },
  344. itemCount: controller.goodsList.length),
  345. );
  346. });
  347. }
  348. Widget buildMemberBottomView() {
  349. return Obx(() {
  350. return Visibility(
  351. visible: controller.memberStatusInfo == null ||
  352. controller.memberStatusInfo?.permanent == false,
  353. child: Align(
  354. alignment: Alignment.bottomCenter,
  355. child: Container(//top: 98.w,
  356. alignment: Alignment.bottomCenter,
  357. height: 190.w + MediaQuery.of(Get.context!).padding.bottom,
  358. padding: EdgeInsets.only(
  359. left: 12.w, right: 12.w, bottom: 17.w + MediaQuery.of(Get.context!).padding.bottom),
  360. decoration: BoxDecoration(
  361. gradient: LinearGradient(
  362. begin: Alignment.bottomCenter, // 0deg 相当于从底部开始
  363. end: Alignment.topCenter,
  364. colors: [
  365. Colors.white, // #FFF
  366. "#00FFFFFF".color,
  367. ],
  368. stops: [0.4368, 1.0], // 对应 43.68% 和 100%
  369. ),
  370. ),
  371. child: Obx(() {
  372. return Column(
  373. mainAxisAlignment: MainAxisAlignment.end,
  374. children: [
  375. Container(
  376. width: double.infinity, // 设置容器宽度
  377. height: 50.w, // 设置容器高度
  378. padding: EdgeInsets.only(left: 20.w),
  379. decoration: BoxDecoration(
  380. image: DecorationImage(
  381. image: Assets.images.iconMemberSettlementBg.provider(),
  382. fit: BoxFit.fill,
  383. ),
  384. ),
  385. // 实现内阴影效果
  386. child: Row(
  387. children: [
  388. Transform.translate(
  389. offset: Offset(0, 3), // 向下偏移4像素
  390. child: Text('¥',
  391. style: TextStyle(
  392. fontSize: 14.sp,
  393. color: '#FFF8EF'.color,
  394. fontWeight: FontWeight.bold)),
  395. ),
  396. SizedBox(width: 3.w,),
  397. Text(
  398. controller.selectedGoods?.amount.divideBy100() ?? '--',
  399. style: TextStyle(
  400. fontSize: 24.sp,
  401. color: '#FFF8EF'.color,
  402. fontWeight: FontWeight.bold),
  403. ),
  404. SizedBox(width: 3.w,),
  405. Text("/",
  406. style: TextStyle(
  407. fontSize: 12.sp,
  408. fontWeight: FontWeight.w400,
  409. color: "#FFF8EF".color),),
  410. Text('原价${controller.selectedGoods?.originalAmount.divideBy100()}',
  411. style: TextStyle(
  412. decoration: TextDecoration.lineThrough,
  413. decorationColor: Colors.white,
  414. decorationThickness: 1.0,
  415. fontSize: 12.sp,
  416. fontWeight: FontWeight.w400,
  417. color: "#FFF8EF".color)),
  418. Spacer(),
  419. GestureDetector(
  420. onTap: controller.onBuyClick,
  421. child: Container(
  422. decoration: BoxDecoration(
  423. image: DecorationImage(
  424. image: Assets.images.iconMemberSettlementConfirm.provider(),
  425. fit: BoxFit.fill,
  426. )
  427. ),
  428. // width: 164.w,
  429. // height: 44.w,
  430. padding: EdgeInsets.only(left: 64.w,right: 29.w),
  431. child: Center(
  432. child: Text(
  433. controller.memberStatusInfo?.expired == false
  434. ? StringName.memberVipRenew
  435. : StringName.memberVipUnlock,
  436. style: TextStyle(
  437. fontSize: 18.sp,
  438. color: "#9B3800".color,
  439. fontWeight: FontWeight.bold),
  440. ),
  441. ),
  442. ),
  443. )
  444. ],
  445. ),
  446. ),
  447. SizedBox(height: 8.w,),
  448. buildPrivacyPolicyView(),
  449. ],
  450. );
  451. }),
  452. ),
  453. ),
  454. );
  455. });
  456. }
  457. Widget buildUserInfoView() {
  458. return Row(
  459. children: [
  460. SizedBox(width: 18.w),
  461. controller.isLogin ? ClipOval(
  462. child: Container(
  463. width: 32.w,
  464. height: 32.w,
  465. child: CachedNetworkImage(
  466. imageUrl: controller.memberStatusInfo?.avatar ?? "",
  467. fit: BoxFit.cover,
  468. ),
  469. ),
  470. ) : Assets.images.iconMemberAvatar.image(width: 32.w, height: 32.w),
  471. SizedBox(width: 7.w),
  472. Column(
  473. crossAxisAlignment: CrossAxisAlignment.start,
  474. children: [
  475. Obx(() {
  476. return GestureDetector(
  477. onTap: controller.onLoginClick,
  478. child: Text(
  479. controller.phone?.isNotEmpty == true
  480. ? controller.getUserName(controller.phone!)
  481. : StringName.mineAccountGoLogin,
  482. style: TextStyle(
  483. fontSize: 13.sp,
  484. color: "#333333".color,
  485. fontWeight: FontWeight.bold)),
  486. );
  487. }),
  488. Container(
  489. height: 13.w,
  490. child: Row(
  491. // 主轴默认左对齐,通过Spacer推挤右侧内容
  492. children: [
  493. // 左侧内容:会员等级描述 + VIP卡片描述
  494. Visibility(
  495. visible: MemberStatusInfo.getLevelDesc(controller.memberStatusInfo).isNotEmpty,
  496. child: Text(
  497. MemberStatusInfo.getLevelDesc(controller.memberStatusInfo),
  498. style: TextStyle(
  499. fontSize: 11.sp,
  500. fontWeight: FontWeight.w700,
  501. color: '#9144F8'.color
  502. )
  503. ),
  504. ),
  505. buildMemberCardVipDesc(),
  506. Container(
  507. child: MemberDiscountCountdownWidget(
  508. onExpired: () {
  509. print("sssfsdfs");
  510. controller.isShowCount.value = false;
  511. },
  512. ),
  513. )
  514. ],
  515. ),
  516. )
  517. ],
  518. ),
  519. SizedBox(width: 20.w)
  520. ],
  521. );
  522. }
  523. // Spacer(),
  524. // Container(
  525. // decoration: BoxDecoration(
  526. // color: '#272F51'.color,
  527. // border: Border.all(color: '#99CAB0F0'.color, width: 1.w),
  528. // borderRadius: BorderRadius.circular(100.w),
  529. // ),
  530. // padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 6.w),
  531. // child: Obx(() {
  532. // return Text(
  533. // MemberStatusInfo.getLevelDesc(controller.memberStatusInfo),
  534. // style: TextStyle(fontSize: 12.sp, color: '#D2CCFF'.color));
  535. // })),
  536. Widget buildMemberCardVipDesc() {
  537. return Obx(() {
  538. String desc = '';
  539. if (!controller.isLogin) {
  540. //desc = StringName.memberCardNoLoginDesc;
  541. desc =
  542. '${DateUtil.fromMillisecondsSinceEpoch('yyyy-MM-dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
  543. } else if (controller.memberStatusInfo == null ||
  544. controller.memberStatusInfo?.expired == true) {
  545. desc = StringName.memberCardNoVipDesc;
  546. } else if (controller.memberStatusInfo?.expired == false &&
  547. controller.memberStatusInfo?.permanent == true) {
  548. desc = StringName.memberCardPermanentVipDesc;
  549. } else {
  550. desc =
  551. '${DateUtil.fromMillisecondsSinceEpoch('yyyy-MM-dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
  552. }
  553. return Text(desc,
  554. style: TextStyle(fontSize: 11.sp, color: ColorName.black50,fontWeight: FontWeight.w400));
  555. });
  556. }
  557. Widget buildHeadBar() {
  558. return Obx(() {
  559. return Stack(
  560. children: [
  561. IgnorePointer(
  562. child: Container(
  563. color: ColorName.colorPrimary.withOpacity(controller.toolBarOpacity),
  564. child: SafeArea(
  565. child: SizedBox(
  566. width: double.infinity,
  567. height: 56.w,
  568. ),
  569. ),
  570. ),
  571. ),
  572. SafeArea(
  573. child: SizedBox(
  574. width: double.infinity,
  575. height: 56.w,
  576. child: Stack(alignment: Alignment.center, children: [
  577. Positioned(
  578. left: 15.w,
  579. child: GestureDetector(
  580. onTap: () => controller.onPopBack(),
  581. child: Assets.images.iconMemberVipBack
  582. .image(width: 26.w, height: 26..w),
  583. )),
  584. Container(
  585. padding: EdgeInsets.only(left: 51.w,right: 12.w),
  586. child: buildVerticalSlideshowWidget())
  587. ]),
  588. ),
  589. ),
  590. ],
  591. );
  592. });
  593. }
  594. Widget buildVerticalSlideshowWidget() {
  595. return Row(
  596. children: [
  597. Visibility(visible: !Platform.isIOS, child: Spacer()),
  598. Container(
  599. width: 192.w,
  600. height: 26.w,
  601. decoration: BoxDecoration(
  602. color: ColorName.black40,
  603. borderRadius: BorderRadius.circular(87.w),
  604. ),
  605. child: Center(
  606. child: AnimatedSwitcherWidget(
  607. controller: controller.switcherController)),
  608. ),
  609. Spacer(),
  610. Visibility(
  611. visible: Platform.isIOS && controller.accountRepository.isLogin.value,
  612. child: GestureDetector(
  613. onTap: controller.clickRecoverSubscribe,
  614. child: Container(
  615. height: 26.w,
  616. decoration: BoxDecoration(
  617. color: ColorName.black40,
  618. borderRadius: BorderRadius.circular(26.w / 2.0),
  619. ),
  620. padding: EdgeInsets.symmetric(horizontal: 10.w),
  621. child: Row(
  622. children: [
  623. Assets.images.iconAppleRecoverSubscribe.image(width: 14.w,height: 14.w),
  624. Text(StringName.appleRecoverSubscribeTxt,
  625. style: TextStyle(
  626. fontSize: 11.sp,
  627. color: ColorName.white,
  628. fontWeight: FontWeight.w500)),
  629. ],
  630. ),
  631. ),
  632. )
  633. )
  634. ],
  635. );
  636. }
  637. Widget buildPrivacyPolicyView() {
  638. return Padding(
  639. padding: EdgeInsets.only(left: 12.w),
  640. child: RichText(
  641. text: TextSpan(
  642. style: TextStyle(fontSize: 12.sp, color: ColorName.black40),
  643. children: [
  644. TextSpan(text: '购买前请先阅读'),
  645. TextSpan(
  646. recognizer: TapGestureRecognizer()
  647. ..onTap = () {
  648. controller.onPrivacyPolicyClick();
  649. },
  650. text: '隐私政策',
  651. style: TextStyle(
  652. color: ColorName.black60,
  653. decoration: TextDecoration.underline)),
  654. TextSpan(text: '&'),
  655. TextSpan(
  656. recognizer: TapGestureRecognizer()
  657. ..onTap = () {
  658. controller.onTermOfServiceClick();
  659. },
  660. text: '服务条款',
  661. style: TextStyle(
  662. color: ColorName.black60,
  663. decoration: TextDecoration.underline)),
  664. ])),
  665. );
  666. }
  667. Widget buildFunctionList() {
  668. return SizedBox(
  669. height: 80.w,
  670. child: AutoScrollListView(
  671. padding: EdgeInsets.only(left: 12.w),
  672. itemBuilder: (ctx, index) {
  673. final item = controller.funList[index];
  674. return Padding(
  675. padding: EdgeInsets.only(right: 20.w),
  676. child: Column(
  677. children: [
  678. Image.asset(item.iconPath, width: 36.w, height: 36.w),
  679. Spacer(flex: 3),
  680. Text(item.funName,
  681. style: TextStyle(
  682. fontSize: 12.8.sp,
  683. color: ColorName.black90,
  684. fontWeight: FontWeight.bold)),
  685. Spacer(flex: 2),
  686. Text(item.funDesc,
  687. style: TextStyle(
  688. fontSize: 10.6.sp,
  689. color: ColorName.black50,
  690. )),
  691. ],
  692. ),
  693. );
  694. },
  695. itemCount: controller.funList.length));
  696. }
  697. Widget buildUserEvaluateList() {
  698. return Column(
  699. children: [
  700. for (int index = 0; index < controller.evaluateList.length; index++)
  701. buildUserEvaluateItem(controller.evaluateList[index],
  702. index == controller.evaluateList.length - 1)
  703. ],
  704. );
  705. }
  706. Widget buildUserEvaluateItem(MemberEvaluateBean item, bool isLast) {
  707. return Column(
  708. crossAxisAlignment: CrossAxisAlignment.start,
  709. children: [
  710. SizedBox(height: 20.w),
  711. Row(
  712. children: [
  713. SizedBox(width: 12.w),
  714. Image.asset(item.avatarPath, width: 24.w, height: 24.w),
  715. SizedBox(width: 8.w),
  716. Text(
  717. item.userName,
  718. style: TextStyle(fontSize: 14.sp, color: Colors.black),
  719. )
  720. ],
  721. ),
  722. SizedBox(height: 1.w),
  723. Padding(
  724. padding: EdgeInsets.only(left: 44.w, right: 12.w),
  725. child: Text(
  726. item.userEvaluate,
  727. style: TextStyle(fontSize: 14.sp, color: '#BF000000'.color),
  728. )),
  729. SizedBox(height: 20.w),
  730. Visibility(
  731. child: Container(
  732. margin: EdgeInsets.only(left: 26.w),
  733. width: 288.w,
  734. color: '#21000000'.color,
  735. height: 1.w),
  736. )
  737. ],
  738. );
  739. }
  740. Widget buildPayWayView() {
  741. return Obx(() {
  742. return Visibility(
  743. visible: Platform.isIOS ? false : controller.payItemList.isNotEmpty,
  744. child: Container(
  745. margin: EdgeInsets.only(top: 7.w),
  746. child: Column(
  747. children: [
  748. for (PayItemBean item in controller.payItemList)
  749. buildPayWayItem(item)
  750. ],
  751. ),
  752. ),
  753. );
  754. });
  755. }
  756. Widget buildPayWayItem(PayItemBean item) {
  757. return GestureDetector(
  758. behavior: HitTestBehavior.translucent,
  759. onTap: () => controller.onPayWayItemClick(item),
  760. child: Obx(() {
  761. bool isSelected = controller.selectedPayWay?.id == item.id;
  762. return Container(
  763. padding: EdgeInsets.symmetric(vertical: 10.w),
  764. child: Row(
  765. children: [
  766. SizedBox(width: 12.w),
  767. Image.asset(
  768. getPaymentIconPath(
  769. payMethod: item.payMethod, payPlatform: item.payPlatform),
  770. width: 24.w,
  771. height: 24.w),
  772. SizedBox(width: 6.w),
  773. Text(item.title,
  774. style: TextStyle(fontSize: 14.sp, color: ColorName.black90)),
  775. Spacer(),
  776. Image.asset(
  777. isSelected
  778. ? Assets.images.iconCbSelected.path
  779. : Assets.images.iconCbUnSelect.path,
  780. width: 20.w,
  781. height: 20.w),
  782. SizedBox(width: 20.w),
  783. ],
  784. ),
  785. );
  786. }),
  787. );
  788. }
  789. }