import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:keyboard/base/base_page.dart'; import 'package:keyboard/module/store/new_discount/new_discount_controller.dart'; import 'package:flutter/material.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:get/get.dart'; import '../../../data/bean/character_info.dart'; import '../../../data/consts/payment_type.dart'; import '../../../data/consts/web_url.dart'; import '../../../resource/assets.gen.dart'; import '../../../resource/colors.gen.dart'; import '../../../resource/string.gen.dart'; import '../../../router/app_pages.dart'; import '../../../utils/styles.dart'; import '../../../widget/auto_scroll_list_view.dart'; import '../../../widget/click_text_span.dart'; class NewDiscountPage extends BasePage { const NewDiscountPage({super.key}); /// 跳转 static void start() { Get.toNamed(RoutePath.newDiscount); } @override bool immersive() { return true; } @override backgroundColor() => Colors.white; @override Widget buildBody(BuildContext context) { return Stack( children: [ Positioned(top: 0.w, child: _buildBanner()), Positioned( top: 408.w, child: Container( decoration: BoxDecoration( color: ColorName.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r), ), ), width: 360.w, height: 392.w, child: SingleChildScrollView( child: Column( children: [ SizedBox(height: 16.w), _buildGoodsCard(), SizedBox(height: 12.w), _buildPayWayCard(), SizedBox(height: 8.w), _buildSelectedDesc(), SizedBox(height: 30.w), _buildMemberCard(), SizedBox(height: 200.w), ], ), ), ), ), Positioned(top: 0, left: 0, right: 0, child: _buildTitle()), Positioned(bottom: 0, left: 0, right: 0, child: _buildBuyButtonCard()), ], ); } _buildTitle() { return SafeArea( child: Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(top: 16.h, left: 16.w, right: 16.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: controller.clickBack, child: Assets.images.iconStoreBack.image( width: 32.w, height: 32.w, ), ), ], ), ), ); } Widget _buildBanner() { return SizedBox( width: 360.w, child: Stack( children: [ CarouselSlider( carouselController: controller.carouselSliderController, options: CarouselOptions( height: 438.w, viewportFraction: 1, initialPage: 0, enableInfiniteScroll: true, reverse: false, autoPlay: true, autoPlayInterval: const Duration(seconds: 3), autoPlayAnimationDuration: const Duration(milliseconds: 500), autoPlayCurve: Curves.fastOutSlowIn, scrollDirection: Axis.horizontal, onPageChanged: (index, reason) { controller.onBannerChanged(index, reason); }, ), items: controller.bannerList.map((item) { return item.image(width: 360.w, fit: BoxFit.contain); }).toList(), ), Positioned( bottom: 149.16.w, left: 31.w, child: Assets.images.iconNewDiscountCharacterTitle.image( width: 296.w, height: 39.w, ), ), Positioned( bottom: 211.13.w, left: 42.w, right: 0, child: _buildIndicator(), ), Positioned( bottom: 0, left: 0, right: 0, child: _buildAutoCharacterList(), ), ], ), ); } /// 指示器 _buildIndicator() { return Row( children: controller.bannerList.asMap().entries.map((entry) { return Obx(() { final isSelectedBanner = controller.currentBannerIndex == entry.key; return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ GestureDetector( onTap: () => controller.carouselSliderController.animateToPage( entry.key, ), child: AnimatedContainer( duration: const Duration(milliseconds: 300), margin: EdgeInsets.only(right: 5.w), height: 5.w, width: isSelectedBanner ? 10.w : 5.w, decoration: BoxDecoration( color: isSelectedBanner ? const Color(0xff483459) : const Color(0xffAFB4BF), borderRadius: BorderRadius.circular(5.r), ), ), ), ], ); }); }).toList(), ); } Widget _buildAutoCharacterList() { return Obx(() { if (controller.charactersList.isEmpty) { return Container(); } return SizedBox( height: 130.w, child: AutoScrollListView( itemCount: (controller.charactersList.length / 2).ceil(), scrollDirection: Axis.horizontal, itemBuilder: (context, columnIndex) { int rowCount = 2; int startIndex = columnIndex * rowCount; final List columnItems = controller.charactersList .skip(startIndex) .take(rowCount) .toList(); return Column( children: columnItems.map((item) { final emoji = item.emoji ?? ""; final name = item.name ?? ""; return Padding( padding: EdgeInsets.symmetric( vertical: 4.w, horizontal: 4.w, ), child: Container( padding: EdgeInsets.symmetric( horizontal: 12.w, vertical: 6.w, ), decoration: ShapeDecoration( color: Colors.white, shape: RoundedRectangleBorder( side: BorderSide( width: 1.w, color: const Color(0xFFF4F1FF), ), borderRadius: BorderRadius.circular(31.r), ), ), child: Text( "$emoji$name", style: TextStyle( color: Colors.black.withAlpha(204), fontSize: 13.sp, fontWeight: FontWeight.w400, ), ), ), ); }).toList(), ); }, ), ); }); } Widget _buildBuyButtonCard() { return Container( width: 360.w, padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 11.h), decoration: ShapeDecoration( color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r), ), ), shadows: [ BoxShadow( color: Color(0x99FFE498), blurRadius: 20, offset: Offset(0, 0), spreadRadius: 0, ), ], ), child: Column( children: [ GestureDetector( onTap: controller.clickPayNow, child: Container( width: 328.w, height: 56.w, decoration: ShapeDecoration( shape: RoundedRectangleBorder( side: BorderSide(width: 2.w, color: const Color(0xFFFFF6C9)), borderRadius: BorderRadius.circular(30.55), ), ), child: Container( width: 328, height: 54, decoration: ShapeDecoration( gradient: LinearGradient( begin: Alignment(0.60, -0.39), end: Alignment(0.60, 0.95), colors: [ const Color(0xFFF95FAC), const Color(0xFFFD4D99), const Color(0xFFFF3E75), const Color(0xFFFF0F53), ], ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.55), ), ), child: Center( child: Text( StringName.newDiscountUnlockNow, style: Styles.getTextStyleWhiteW500(17.sp), ), ), ), ), ), SizedBox(height: 11.h), _buildPrivacyTextSpan(), ], ), ); } Widget _buildGoodsCard() { return Container( margin: EdgeInsets.symmetric(horizontal: 16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Obx(() { final goodsList = controller.filteredGoodsList; return Column( children: List.generate(goodsList.length, (index) { final item = goodsList[index]; final isSelected = controller.selectedGoodsInfoItem?.id == item.id; return Column( children: [ GestureDetector( onTap: () => controller.onGoodsItemClick(item), child: _buildGoodsItem(item, isSelected), ), if (index != goodsList.length - 1) SizedBox(height: 10.w), ], ); }), ); }), ], ), ); } Widget _buildPayWayCard() { return GestureDetector( onTap: () => controller.clickPayWaySwitch(), child: Container( margin: EdgeInsets.symmetric(horizontal: 16.w), height: 36.h, padding: EdgeInsets.symmetric(horizontal: 10.w), decoration: ShapeDecoration( shape: RoundedRectangleBorder( side: BorderSide(width: 1, color: const Color(0xFFECEBE0)), borderRadius: BorderRadius.circular(10.r), ), ), child: Row( children: [ Text( StringName.storePayWay, style: Styles.getTextStyleBlack204W400(14.sp), ), const Spacer(), Obx(() { if (controller.selectedPayWay == null) { return SizedBox.shrink(); } return Row( children: [ Image.asset( getPaymentIconPath( payMethod: controller.selectedPayWay!.payMethod, payPlatform: controller.selectedPayWay!.payPlatform, ), width: 20.w, height: 20.w, ), SizedBox(width: 4.w), Text( controller.selectedPayWay?.title ?? '', style: Styles.getTextStyleBlack204W400(14.sp), ), SizedBox(width: 6.w), Assets.images.iconStoreSwitchPay.image( width: 20.w, height: 20.w, fit: BoxFit.fill, ), ], ); }), ], ), ), ); } Widget _buildGoodsItem(item, bool isSelected) { return Container( height: 70.w, width: 328.w, padding: EdgeInsets.symmetric(horizontal: 16.w), decoration: isSelected ? BoxDecoration( borderRadius: BorderRadius.circular(16.w), image: DecorationImage( image: Assets.images.bgNewDiscountItemSelect.provider(), fit: BoxFit.fill, ), ) : BoxDecoration( borderRadius: BorderRadius.circular(16.w), image: DecorationImage( image: Assets.images.bgNewDiscountItemUnselect.provider(), fit: BoxFit.fill, ), ), child: Row( children: [ Text( "¥", style: TextStyle( color: isSelected ? const Color(0xFFFF684E) : Colors.black.withAlpha(204), fontSize: 16.sp, fontWeight: FontWeight.w700, ), ), Text( '${item.amountText}', textAlign: TextAlign.center, style: TextStyle( color: isSelected ? const Color(0xFFFF684E) : Colors.black.withAlpha(204), fontSize: 29.sp, fontWeight: FontWeight.w700, ), ), SizedBox(width: 9.w), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ Text( item.name, style: TextStyle( color: Colors.black.withAlpha(204), fontSize: 14.sp, fontWeight: FontWeight.w500, ), ), SizedBox(width: 4.5.w), if (item.mostDesc?.isNotEmpty == true) Container( padding: EdgeInsets.symmetric( horizontal: 4.w, vertical: 2.w, ), margin: EdgeInsets.only(bottom: 4.w), decoration: ShapeDecoration( gradient: LinearGradient( begin: Alignment(0.00, 0.50), end: Alignment(1.00, 0.50), colors: [ const Color(0xFFFF684E), const Color(0xFFFF4F9A), ], ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(10.50), topRight: Radius.circular(10.50), bottomRight: Radius.circular(10.50), ), ), ), child: Text( item.mostDesc!, style: TextStyle( color: Colors.white, fontSize: 12.sp, fontWeight: FontWeight.w500, ), ), ), ], ), Text( item.priceDesc, style: TextStyle( color: Colors.black.withAlpha(153), fontSize: 12.sp, fontWeight: FontWeight.w400, ), ), ], ), Spacer(), isSelected ? Assets.images.iconCustomCharacterAddDialogSelect.image( width: 20.w, height: 20.w, fit: BoxFit.contain, ) : Container( width: 20.w, height: 20.w, decoration: ShapeDecoration( color: Colors.white, shape: OvalBorder( side: BorderSide( width: 2.w, color: const Color(0xFFE6E6E6), ), ), ), ), ], ), ); } _buildSelectedDesc() { return Obx(() { return Container( margin: EdgeInsets.symmetric(horizontal: 16.w), child: Row( children: [ Text( controller.selectedGoodsInfoItem?.selectDesc ?? "", style: TextStyle( color: Colors.black.withAlpha(102), fontSize: 12.sp, fontWeight: FontWeight.w400, ), ), ], ), ); }); } Widget _buildMemberCard() { return Container( margin: EdgeInsets.symmetric(horizontal: 16.w), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Assets.images.iconNewDiscountMembershipCardTitle.image( width: 79.w, height: 24.w, ), SizedBox(height: 6.w), Text( StringName.newDiscountMemberCardDesc, style: TextStyle( color: Colors.black.withValues(alpha: 87), fontSize: 11.sp, fontWeight: FontWeight.w400, ), ), SizedBox(height: 8.w), _buildMemberCardItem(), ], ), ); } // 卡片权益 _buildMemberCardItem() { return SizedBox( height: 80.w, child: AutoScrollListView( scrollDirection: Axis.horizontal, itemBuilder: (context, index) { final item = controller.memberCardList[index]; return Container( margin: EdgeInsets.only(right: 8.w), width: 140.w, height: 65.w, decoration: ShapeDecoration( gradient: item.gradient, shape: RoundedRectangleBorder( side: BorderSide(width: 1.w, color: Colors.black.withAlpha(8)), borderRadius: BorderRadius.circular(20.r), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ item.imageUrl.image(width: 28.w, height: 27.62.w), SizedBox(width: 8.w), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( item.title, style: TextStyle( color: Colors.black.withAlpha(204), fontSize: 12.sp, fontWeight: FontWeight.w700, ), ), SizedBox(height: 6.w), Text( item.desc, style: TextStyle( color: Colors.black.withAlpha(128), fontSize: 10.sp, fontWeight: FontWeight.w400, ), ), ], ), ], ), ); }, itemCount: controller.memberCardList.length, ), ); } Widget _buildPrivacyTextSpan() { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { controller.isAgree.value = !controller.isAgree.value; }, child: controller.isAgree.value ? Assets.images.iconStoreAgreePrivacy.image( width: 16.w, height: 16.w, ) : SizedBox( child: Container( padding: EdgeInsets.all(1.w), width: 16.w, height: 16.w, child: Container( decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: Colors.black.withAlpha(153), width: 1.w, ), ), ), ), ), ); }), Text.rich( TextSpan( children: [ TextSpan( text: StringName.textSpanIHaveReadAndAgree, style: TextStyle( color: Colors.black.withAlpha(153), fontSize: 10.sp, fontWeight: FontWeight.w400, ), ), ClickTextSpan( text: StringName.textSpanPrivacyPolicy, url: WebUrl.privacyPolicy, ), TextSpan( text: StringName.textSpanAnd, style: TextStyle( color: Colors.black.withAlpha(153), fontSize: 10.sp, fontWeight: FontWeight.w400, ), ), ClickTextSpan( text: StringName.textSpanServiceTerms, url: WebUrl.serviceAgreement, ), ], ), ), ], ); } }