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/member_status_info.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_evaluate_bean.dart'; class MemberPage extends BasePage { const MemberPage({super.key}); static void start() { Get.toNamed(RoutePath.member); } @override bool immersive() { return true; } @override bool statusBarDarkFont() { return false; } @override Widget buildBody(BuildContext context) { return Stack( children: [ SingleChildScrollView( controller: controller.scrollController, child: Stack( children: [ Assets.images.bgMemberHeader.image(width: double.infinity), SafeArea( child: Column( children: [ SizedBox(height: 62.w), 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(), 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(() { return SizedBox( height: 123.w, child: ListView.builder( padding: EdgeInsets.only(left: 12.w), physics: const BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics()), scrollDirection: Axis.horizontal, itemBuilder: (BuildContext ctx, int index) { return Obx(() { final item = controller.goodsList[index]; bool isSelected = controller.selectedGoods?.id == item.id; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => controller.onGoodsItemClick(item), child: Container( margin: EdgeInsets.only(right: 10.w), width: 138.w, height: 123.w, child: Stack( children: [ Container( width: double.infinity, height: double.infinity, decoration: BoxDecoration( color: isSelected ? '#6BC4BAFF'.color : ColorName.white20, borderRadius: BorderRadius.circular(18.w), border: Border.all( color: isSelected ? '#C4BAFF'.color : '#E8E8E8'.color, width: 3.w)), padding: EdgeInsets.only(left: 10.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Spacer(flex: 2), Text( item.name, style: TextStyle( fontSize: 14.sp, color: ColorName.black90, fontWeight: FontWeight.bold), ), SizedBox(height: 3.w), Text('¥${item.originalAmount.divideBy100()}', style: TextStyle( decoration: TextDecoration.lineThrough, fontSize: 10.sp, color: ColorName.black60)), Spacer(flex: 1), RichText( text: TextSpan( style: TextStyle( color: isSelected ? '#EA1231'.color : ColorName.black80, fontWeight: FontWeight.bold), children: [ TextSpan( text: '¥', style: TextStyle( fontSize: 20.sp, height: 1)), TextSpan( text: item.amount.divideBy100(), style: TextStyle( fontSize: 34.sp, height: 1, fontFamily: FontFamily.oppoSans)) ])), Padding( padding: EdgeInsets.only(left: 7.w), child: Text(item.description ?? '', style: TextStyle( fontSize: 12.sp, color: ColorName.black40)), ), Spacer( flex: 1, ) ], ), ), Visibility( visible: item.tag?.isNotEmpty == true, child: Positioned( top: 0, right: 0, child: Container( decoration: BoxDecoration( gradient: LinearGradient(colors: [ '#A26CFF'.color, '#FF7CD8'.color, '#898BFF'.color ]), borderRadius: BorderRadius.only( topRight: Radius.circular(11.w), bottomLeft: Radius.circular(11.w))), padding: EdgeInsets.symmetric( horizontal: 10.w, vertical: 4.w), child: Text(item.tag ?? '', style: TextStyle( fontSize: 12.sp, color: Colors.white)), ), )) ], )), ); }); }, itemCount: controller.goodsList.length), ); }); } Widget buildMemberBottomView() { return Obx(() { return Visibility( visible: controller.memberStatusInfo == null || controller.memberStatusInfo?.permanent == false, child: Align( alignment: Alignment.bottomCenter, child: Container( padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 13.w, bottom: 20.w), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), offset: Offset(0, -2), blurRadius: 4) ], borderRadius: BorderRadius.only( topLeft: Radius.circular(16.w), topRight: Radius.circular(16.w)), ), child: Obx(() { return Row( children: [ Text('¥', style: TextStyle( fontSize: 14.sp, color: '#EA1231'.color, fontWeight: FontWeight.bold)), Text( controller.selectedGoods?.amount.divideBy100() ?? '--', style: TextStyle( fontSize: 24.sp, color: '#EA1231'.color, fontWeight: FontWeight.bold), ), Text( ' / ${controller.selectedGoods?.name}', style: TextStyle(fontSize: 12.sp, color: '#000000'.color), ), Spacer(), Container( decoration: BoxDecoration( color: ColorName.colorPrimary, borderRadius: BorderRadius.circular(100.w)), width: 164.w, height: 44.w, child: Center( child: Text( controller.memberStatusInfo?.expired == false ? StringName.memberVipRenew : StringName.memberVipUnlock, style: TextStyle( fontSize: 15.sp, color: Colors.white, fontWeight: FontWeight.bold), ), ), ) ], ); }), ), ), ); }); } Widget buildUserInfoView() { return Row( children: [ SizedBox(width: 20.w), Assets.images.iconMemberAvatar.image(width: 40.w, height: 40.w), SizedBox(width: 10.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: 16.sp, color: Colors.white, fontWeight: FontWeight.bold)), ); }), buildMemberCardVipDesc() ], ), 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)); })), SizedBox(width: 18.w) ], ); } Widget buildMemberCardVipDesc() { return Obx(() { String desc = ''; if (!controller.isLogin) { desc = StringName.memberCardNoLoginDesc; } 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: 12.sp, color: Colors.white60)); }); } Widget buildHeadBar() { return Obx(() { return Container( color: ColorName.colorPrimary.withOpacity(controller.toolBarOpacity), child: SafeArea( child: SizedBox( width: double.infinity, height: 56.w, child: Stack(alignment: Alignment.center, children: [ Positioned( left: 12.w, child: GestureDetector( onTap: controller.back, child: Assets.images.iconWhiteBack .image(width: 24.w, height: 24.w), )), Container(child: buildVerticalSlideshowWidget()) ]), ), ), ); }); } Widget buildVerticalSlideshowWidget() { return Container( width: 220.w, height: 24.w, decoration: BoxDecoration( color: '#1F000000'.color, borderRadius: BorderRadius.circular(100.w), ), child: Center( child: AnimatedSwitcherWidget( controller: controller.switcherController)), ); } 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), ) ], ); } }