import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:get/get_core/src/get_main.dart'; import 'package:location/base/base_page.dart'; import 'package:location/module/member/member_controller.dart'; import 'package:location/resource/assets.gen.dart'; import 'package:location/resource/colors.gen.dart'; import 'package:location/utils/common_expand.dart'; import 'package:location/utils/project_expand.dart'; import 'package:location/widget/auto_scroll_list_view.dart'; import '../../data/bean/goods_bean.dart'; import '../../data/bean/member_status_info.dart'; import '../../data/bean/pay_item_bean.dart'; import '../../data/consts/payment_type.dart'; import '../../resource/fonts.gen.dart'; import '../../resource/string.gen.dart'; import '../../router/app_pages.dart'; import '../../utils/date_util.dart'; import '../../widget/animated_switcher_widget.dart'; import 'member_discount_countdown_widget.dart'; import 'member_evaluate_bean.dart'; import 'member_header_cycle_widget.dart'; ///进入会员类型 enum MemberPageType { ///通用进入 universalAccessEnter, ///倒计时试用完会员进入 afeterTrialMemberEnter, ///加好友进入 addFriendToEnter, } class MemberPage extends BasePage { MemberPage({super.key,this.pageType}); late MemberPageType? pageType = MemberPageType.universalAccessEnter; static void start({MemberPageType? enterTyp = MemberPageType.universalAccessEnter}) { Get.toNamed(RoutePath.member,arguments: enterTyp); } @override bool immersive() { return true; } @override bool statusBarDarkFont() { return false; } @override Widget buildBody(BuildContext context) { return PopScope( canPop: false, onPopInvokedWithResult: (bool didPop, dynamic result) async { controller.onPopBack(); }, child: Stack( children: [ SingleChildScrollView( physics: const ClampingScrollPhysics(), controller: controller.scrollController, child: Stack( children: [ MemberHeaderCycleWidget(), Column( children: [ SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top), Container( decoration: BoxDecoration( color: ColorName.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.w), topRight: Radius.circular(20.w)), ), child: Stack( children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(20.w), topRight: Radius.circular(20.w)), image: DecorationImage( image: Assets.images.iconMemberVipMiddleBg.provider(), ) ), width: double.infinity, height: 174, ), Container( //width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(20.w), topRight: Radius.circular(20.w)), image: DecorationImage(image: Assets.images.iconMemberVipMiddleBg.provider()) ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 15.w), buildUserInfoView(), SizedBox(height: 23.w), buildGoodsList(), SizedBox(height: 12.w), buildPrivacyPolicyView(), buildPayWayView(), SizedBox(height: 30.w), Padding( padding: EdgeInsets.only(left: 12.w), child: Text(StringName.memberEquityIntroduction, style: TextStyle( fontSize: 16.sp, color: ColorName.black90, fontWeight: FontWeight.bold)), ), SizedBox(height: 19.w), buildFunctionList(), SizedBox(height: 40.w), Padding( padding: EdgeInsets.only(left: 12.w), child: Text(StringName.memberUserEvaluate, style: TextStyle( fontSize: 16.sp, color: ColorName.black90, fontWeight: FontWeight.bold)), ), SizedBox(height: 8.w), buildUserEvaluateList(), SizedBox(height: 20.w), Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: '#F7F7F7'.color, borderRadius: BorderRadius.circular(6.w)), margin: EdgeInsets.symmetric(horizontal: 12.w), child: Text(StringName.memberTips, style: TextStyle( fontSize: 12.sp, color: '#A7A7A7'.color)), ), SizedBox(height: 100.w) ], ), ), ], ), ) ], ), ], ) /*Stack( children: [ Assets.images.bgMemberHeader.image(width: double.infinity), SafeArea( child: Column( children: [ SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top), buildUserInfoView(), SizedBox(height: 26.w), Container( width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(14.w), topRight: Radius.circular(14.w)), gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, stops: [0.0, 0.1], colors: ['#EFE9FF'.color, Colors.white])), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 23.w), buildGoodsList(), SizedBox(height: 12.w), buildPrivacyPolicyView(), buildPayWayView(), SizedBox(height: 30.w), Padding( padding: EdgeInsets.only(left: 12.w), child: Text(StringName.memberEquityIntroduction, style: TextStyle( fontSize: 16.sp, color: ColorName.black90, fontWeight: FontWeight.bold)), ), SizedBox(height: 19.w), buildFunctionList(), SizedBox(height: 40.w), Padding( padding: EdgeInsets.only(left: 12.w), child: Text(StringName.memberUserEvaluate, style: TextStyle( fontSize: 16.sp, color: ColorName.black90, fontWeight: FontWeight.bold)), ), SizedBox(height: 8.w), buildUserEvaluateList(), SizedBox(height: 20.w), Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: '#F7F7F7'.color, borderRadius: BorderRadius.circular(6.w)), margin: EdgeInsets.symmetric(horizontal: 12.w), child: Text(StringName.memberTips, style: TextStyle( fontSize: 12.sp, color: '#A7A7A7'.color)), ), SizedBox(height: 100.w) ], ), ) ], ), ) ], ),*/ ), buildHeadBar(), buildMemberBottomView() ], ), ); } Widget buildGoodsList() { return Obx(() { if (controller.goodsList.isEmpty) { return Container(); } if (controller.goodsList.length == 1) { return Container( padding: EdgeInsets.symmetric(horizontal: 14.w), //height: 165.w, child: Column( children: [ _createSpecialProduct(controller.goodsList.first) ], ), ); } else if (controller.goodsList.length == 2) { return Container( padding: EdgeInsets.symmetric(horizontal: 14.w), //height: 165.w, child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: _ordinaryProductWidget(controller.goodsList.first)), SizedBox(width: 8,), Expanded(child: _ordinaryProductWidget(controller.goodsList[1])) ], ) ], ), ); } return Container( padding: EdgeInsets.symmetric(horizontal: 14.w), //height: 165.w, child: Column( children: [ _createSpecialProduct(controller.goodsList.first), SizedBox(height: 7.w,), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: _ordinaryProductWidget(controller.goodsList[1])), SizedBox(width: 8,), Expanded(child: _ordinaryProductWidget(controller.goodsList[2])) ], ) ], ), ); }); } //特惠产品 Widget _createSpecialProduct(GoodsBean goodsInfo) { bool isSelected = controller.selectedGoods?.id == goodsInfo.id; return GestureDetector( onTap: () { controller.onGoodsItemClick(goodsInfo); }, child: Container( height: 96.w, padding: EdgeInsets.only(left: 17.w), decoration: BoxDecoration( image: DecorationImage( image: isSelected ? Assets.images.iconMemberSpecialProductsSelect.provider() : Assets.images.iconMemberSpecialProductsNormal.provider(), fit: BoxFit.cover ), ), child: Column( children: [ SizedBox(height: 29.w,), Row( children: [ Column( children: [ RichText( text: TextSpan( style: TextStyle( color: isSelected ? '#FF5656'.color : "#323133".color, fontWeight: FontWeight.bold), children: [ TextSpan( text: '¥', style: TextStyle( fontSize: 16.sp, height: 1)), TextSpan( text: goodsInfo.amount.divideBy100(), style: TextStyle( fontSize: 28.sp, height: 1, //fontFamily: FontFamily.oppoSans ) ) ] ) ), Text('¥${goodsInfo.originalAmount.divideBy100()}', style: TextStyle( decoration: TextDecoration.lineThrough, decorationColor: ColorName.black40, decorationThickness: 1.0, fontSize: 12.sp, color: ColorName.black40)) ], ), SizedBox(width: 22.24.w,), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( goodsInfo.name, style: TextStyle( fontSize: 17.sp, color: "#333333".color, fontWeight: FontWeight.bold), ), SizedBox( height: 3.w, ), Text( goodsInfo.description ?? "", style: TextStyle( fontSize: 11.sp , color: "#9191BA".color, fontWeight: FontWeight.bold), ), ], ), ], ), ], ), ), ); } ///普通产品 Widget _ordinaryProductWidget(GoodsBean goodsInfo) { bool isSelected = controller.selectedGoods?.id == goodsInfo.id; return GestureDetector( onTap: () { controller.onGoodsItemClick(goodsInfo); }, child: Container( height: 62.w, padding: EdgeInsets.only(left: 16.w,right: 12.w), decoration: BoxDecoration( image: DecorationImage( image: isSelected ? Assets.images.iconMemberOrdinaryProductSelect.provider() : Assets.images.iconMemberOrdinaryProductNormal.provider(), fit: BoxFit.cover ), ), child: Column( children: [ SizedBox(height: 15.w,), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( goodsInfo.name, style: TextStyle( fontSize: 12.sp, color: "#333333".color, fontWeight: FontWeight.bold), ), //SizedBox(height: 6.w,), Text( goodsInfo.description ?? "", style: TextStyle( fontSize: 10.sp , color: ColorName.black40, fontWeight: FontWeight.bold), ), ], ), //SizedBox(width: 22.24.w,), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ RichText( text: TextSpan( style: TextStyle( color: isSelected ? '#FF5656'.color : "#323133".color, fontWeight: FontWeight.bold), children: [ TextSpan( text: '¥', style: TextStyle( color: isSelected? "#FF5656".color : ColorName.black80, fontSize: 11.sp, height: 1)), TextSpan( text: goodsInfo.amount.divideBy100(), style: TextStyle( fontSize: 20.sp, height: 1,)) ] ) ), Text('¥${goodsInfo.originalAmount.divideBy100()}', style: TextStyle( decoration: TextDecoration.lineThrough, decorationColor: ColorName.black30, decorationThickness: 1.0, fontSize: 10.sp, color: ColorName.black30)) ], ), ], ), ], ), ), ); } Widget buildMemberBottomView() { return Obx(() { return Visibility( visible: controller.memberStatusInfo == null || controller.memberStatusInfo?.permanent == false, child: Align( alignment: Alignment.bottomCenter, child: Container(//top: 98.w, alignment: Alignment.bottomCenter, height: 190.w + MediaQuery.of(Get.context!).padding.bottom, padding: EdgeInsets.only( left: 12.w, right: 12.w, bottom: 17.w + MediaQuery.of(Get.context!).padding.bottom), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, // 0deg 相当于从底部开始 end: Alignment.topCenter, colors: [ Colors.white, // #FFF "#00FFFFFF".color, ], stops: [0.4368, 1.0], // 对应 43.68% 和 100% ), ), child: Obx(() { return Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Container( width: double.infinity, // 设置容器宽度 height: 50.w, // 设置容器高度 padding: EdgeInsets.only(left: 20.w), decoration: BoxDecoration( image: DecorationImage( image: Assets.images.iconMemberSettlementBg.provider(), fit: BoxFit.fill, ), ), // 实现内阴影效果 child: Row( children: [ Transform.translate( offset: Offset(0, 3), // 向下偏移4像素 child: Text('¥', style: TextStyle( fontSize: 14.sp, color: '#FFF8EF'.color, fontWeight: FontWeight.bold)), ), SizedBox(width: 3.w,), Text( controller.selectedGoods?.amount.divideBy100() ?? '--', style: TextStyle( fontSize: 24.sp, color: '#FFF8EF'.color, fontWeight: FontWeight.bold), ), SizedBox(width: 3.w,), Text("/", style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w400, color: "#FFF8EF".color),), Text('原价${controller.selectedGoods?.originalAmount.divideBy100()}', style: TextStyle( decoration: TextDecoration.lineThrough, decorationColor: Colors.white, decorationThickness: 1.0, fontSize: 12.sp, fontWeight: FontWeight.w400, color: "#FFF8EF".color)), Spacer(), GestureDetector( onTap: controller.onBuyClick, child: Container( decoration: BoxDecoration( image: DecorationImage( image: Assets.images.iconMemberSettlementConfirm.provider(), fit: BoxFit.fill, ) ), // width: 164.w, // height: 44.w, padding: EdgeInsets.only(left: 64.w,right: 29.w), child: Center( child: Text( controller.memberStatusInfo?.expired == false ? StringName.memberVipRenew : StringName.memberVipUnlock, style: TextStyle( fontSize: 18.sp, color: "#9B3800".color, fontWeight: FontWeight.bold), ), ), ), ) ], ), ), SizedBox(height: 8.w,), buildPrivacyPolicyView(), ], ); }), ), ), ); }); } Widget buildUserInfoView() { return Row( children: [ SizedBox(width: 18.w), controller.isLogin ? ClipOval( child: Container( width: 32.w, height: 32.w, child: CachedNetworkImage( imageUrl: controller.memberStatusInfo?.avatar ?? "", fit: BoxFit.cover, ), ), ) : Assets.images.iconMemberAvatar.image(width: 32.w, height: 32.w), SizedBox(width: 7.w), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Obx(() { return GestureDetector( onTap: controller.onLoginClick, child: Text( controller.phone?.isNotEmpty == true ? controller.getUserName(controller.phone!) : StringName.mineAccountGoLogin, style: TextStyle( fontSize: 13.sp, color: "#333333".color, fontWeight: FontWeight.bold)), ); }), Container( height: 16.w, width: MediaQuery.of(Get.context!).size.width - 77.w, child: Row( // 主轴默认左对齐,通过Spacer推挤右侧内容 children: [ // 左侧内容:会员等级描述 + VIP卡片描述 Visibility( visible: MemberStatusInfo.getLevelDesc(controller.memberStatusInfo).isNotEmpty, child: Text( MemberStatusInfo.getLevelDesc(controller.memberStatusInfo), style: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.w700, color: '#9144F8'.color ) ), ), buildMemberCardVipDesc(), Spacer(), Container( child: MemberDiscountCountdownWidget( onExpired: () { print("sssfsdfs"); controller.isShowCount.value = false; }, ), ) ], ), ) ], ), SizedBox(width: 20.w) ], ); } // Spacer(), // Container( // decoration: BoxDecoration( // color: '#272F51'.color, // border: Border.all(color: '#99CAB0F0'.color, width: 1.w), // borderRadius: BorderRadius.circular(100.w), // ), // padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 6.w), // child: Obx(() { // return Text( // MemberStatusInfo.getLevelDesc(controller.memberStatusInfo), // style: TextStyle(fontSize: 12.sp, color: '#D2CCFF'.color)); // })), Widget buildMemberCardVipDesc() { return Obx(() { String desc = ''; if (!controller.isLogin) { //desc = StringName.memberCardNoLoginDesc; desc = '${DateUtil.fromMillisecondsSinceEpoch('yyyy-MM-dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}'; } else if (controller.memberStatusInfo == null || controller.memberStatusInfo?.expired == true) { desc = StringName.memberCardNoVipDesc; } else if (controller.memberStatusInfo?.expired == false && controller.memberStatusInfo?.permanent == true) { desc = StringName.memberCardPermanentVipDesc; } else { desc = '${DateUtil.fromMillisecondsSinceEpoch('yyyy-MM-dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}'; } return Text(desc, style: TextStyle(fontSize: 11.sp, color: ColorName.black50,fontWeight: FontWeight.w400)); }); } Widget buildHeadBar() { return Obx(() { return Stack( children: [ IgnorePointer( child: Container( color: ColorName.colorPrimary.withOpacity(controller.toolBarOpacity), child: SafeArea( child: SizedBox( width: double.infinity, height: 56.w, ), ), ), ), SafeArea( child: SizedBox( width: double.infinity, height: 56.w, child: Stack(alignment: Alignment.center, children: [ Positioned( left: 15.w, child: GestureDetector( onTap: () => controller.onPopBack(), child: Assets.images.iconMemberVipBack .image(width: 26.w, height: 26..w), )), Container( padding: EdgeInsets.only(left: 51.w,right: 12.w), child: buildVerticalSlideshowWidget()) ]), ), ), ], ); }); } Widget buildVerticalSlideshowWidget() { return Row( children: [ Visibility(visible: !Platform.isIOS, child: Spacer()), Container( width: 192.w, height: 26.w, decoration: BoxDecoration( color: ColorName.black40, borderRadius: BorderRadius.circular(87.w), ), child: Center( child: AnimatedSwitcherWidget( controller: controller.switcherController)), ), Spacer(), Visibility( visible: Platform.isIOS && controller.accountRepository.isLogin.value, child: GestureDetector( onTap: controller.clickRecoverSubscribe, child: Container( height: 26.w, decoration: BoxDecoration( color: ColorName.black40, borderRadius: BorderRadius.circular(26.w / 2.0), ), padding: EdgeInsets.symmetric(horizontal: 10.w), child: Row( children: [ Assets.images.iconAppleRecoverSubscribe.image(width: 14.w,height: 14.w), Text(StringName.appleRecoverSubscribeTxt, style: TextStyle( fontSize: 11.sp, color: ColorName.white, fontWeight: FontWeight.w500)), ], ), ), ) ) ], ); } Widget buildPrivacyPolicyView() { return Padding( padding: EdgeInsets.only(left: 12.w), child: RichText( text: TextSpan( style: TextStyle(fontSize: 12.sp, color: ColorName.black40), children: [ TextSpan(text: '购买前请先阅读'), TextSpan( recognizer: TapGestureRecognizer() ..onTap = () { controller.onPrivacyPolicyClick(); }, text: '隐私政策', style: TextStyle( color: ColorName.black60, decoration: TextDecoration.underline)), TextSpan(text: '&'), TextSpan( recognizer: TapGestureRecognizer() ..onTap = () { controller.onTermOfServiceClick(); }, text: '服务条款', style: TextStyle( color: ColorName.black60, decoration: TextDecoration.underline)), ])), ); } Widget buildFunctionList() { return SizedBox( height: 80.w, child: AutoScrollListView( padding: EdgeInsets.only(left: 12.w), itemBuilder: (ctx, index) { final item = controller.funList[index]; return Padding( padding: EdgeInsets.only(right: 20.w), child: Column( children: [ Image.asset(item.iconPath, width: 36.w, height: 36.w), Spacer(flex: 3), Text(item.funName, style: TextStyle( fontSize: 12.8.sp, color: ColorName.black90, fontWeight: FontWeight.bold)), Spacer(flex: 2), Text(item.funDesc, style: TextStyle( fontSize: 10.6.sp, color: ColorName.black50, )), ], ), ); }, itemCount: controller.funList.length)); } Widget buildUserEvaluateList() { return Column( children: [ for (int index = 0; index < controller.evaluateList.length; index++) buildUserEvaluateItem(controller.evaluateList[index], index == controller.evaluateList.length - 1) ], ); } Widget buildUserEvaluateItem(MemberEvaluateBean item, bool isLast) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 20.w), Row( children: [ SizedBox(width: 12.w), Image.asset(item.avatarPath, width: 24.w, height: 24.w), SizedBox(width: 8.w), Text( item.userName, style: TextStyle(fontSize: 14.sp, color: Colors.black), ) ], ), SizedBox(height: 1.w), Padding( padding: EdgeInsets.only(left: 44.w, right: 12.w), child: Text( item.userEvaluate, style: TextStyle(fontSize: 14.sp, color: '#BF000000'.color), )), SizedBox(height: 20.w), Visibility( child: Container( margin: EdgeInsets.only(left: 26.w), width: 288.w, color: '#21000000'.color, height: 1.w), ) ], ); } Widget buildPayWayView() { return Obx(() { return Visibility( visible: Platform.isIOS ? false : controller.payItemList.isNotEmpty, child: Container( margin: EdgeInsets.only(top: 7.w), child: Column( children: [ for (PayItemBean item in controller.payItemList) buildPayWayItem(item) ], ), ), ); }); } Widget buildPayWayItem(PayItemBean item) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => controller.onPayWayItemClick(item), child: Obx(() { bool isSelected = controller.selectedPayWay?.id == item.id; return Container( padding: EdgeInsets.symmetric(vertical: 10.w), child: Row( children: [ SizedBox(width: 12.w), Image.asset( getPaymentIconPath( payMethod: item.payMethod, payPlatform: item.payPlatform), width: 24.w, height: 24.w), SizedBox(width: 6.w), Text(item.title, style: TextStyle(fontSize: 14.sp, color: ColorName.black90)), Spacer(), Image.asset( isSelected ? Assets.images.iconCbSelected.path : Assets.images.iconCbUnSelect.path, width: 20.w, height: 20.w), SizedBox(width: 20.w), ], ), ); }), ); } }