|
|
@@ -1,22 +1,31 @@
|
|
|
-import 'package:flutter/src/widgets/framework.dart';
|
|
|
+import 'package:flutter/material.dart';
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
import 'package:keyboard/base/base_view.dart';
|
|
|
import 'package:keyboard/module/store/discount/discount_controller.dart';
|
|
|
-import 'package:get/get.dart';
|
|
|
-import 'package:flutter/material.dart';
|
|
|
+import 'package:keyboard/resource/string.gen.dart';
|
|
|
+
|
|
|
+import '../../../data/consts/payment_type.dart';
|
|
|
+import '../../../resource/assets.gen.dart';
|
|
|
+import '../../../utils/styles.dart';
|
|
|
+import '../../../widget/vertical_dots.dart';
|
|
|
|
|
|
class DiscountView extends BaseView<DiscountController> {
|
|
|
const DiscountView({super.key});
|
|
|
|
|
|
@override
|
|
|
+ Color backgroundColor() {
|
|
|
+ return Colors.transparent;
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
Widget buildBody(BuildContext context) {
|
|
|
return Container(
|
|
|
+ clipBehavior: Clip.hardEdge,
|
|
|
+ padding: EdgeInsets.only(bottom: 20.h),
|
|
|
+ width: 360.w,
|
|
|
decoration: ShapeDecoration(
|
|
|
- gradient: LinearGradient(
|
|
|
- begin: Alignment(0.50, 0.00),
|
|
|
- end: Alignment(0.50, 1.00),
|
|
|
- colors: [const Color(0xFF9EED00), const Color(0xFF48D900)],
|
|
|
- ),
|
|
|
+ color: Color(0xFFF7FDAD),
|
|
|
shape: RoundedRectangleBorder(
|
|
|
borderRadius: BorderRadius.only(
|
|
|
topLeft: Radius.circular(28.r),
|
|
|
@@ -25,9 +34,523 @@ class DiscountView extends BaseView<DiscountController> {
|
|
|
),
|
|
|
),
|
|
|
child: Column(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.start,
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
+ children: [
|
|
|
+ buildTitleCard(),
|
|
|
+ SizedBox(height: 20.h),
|
|
|
+ buildBottomCard(),
|
|
|
+ Transform.translate(
|
|
|
+ offset: Offset(0, -30.h),
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.clickPayNow();
|
|
|
+ },
|
|
|
+ child: Assets.images.gifDiscountUnlockButton.image(width: 244.h),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ //标题和多重权益
|
|
|
+ Widget buildTitleCard() {
|
|
|
+ return Container(
|
|
|
+ width: 360.w,
|
|
|
+ height: 290.h,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ image: DecorationImage(
|
|
|
+ image: Assets.images.bgDiscountTitle.provider(),
|
|
|
+ fit: BoxFit.fill,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Stack(
|
|
|
+ children: [
|
|
|
+ Positioned(
|
|
|
+ top: 16.h,
|
|
|
+ left: 16.w,
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: () => controller.clickBack(),
|
|
|
+ child: Assets.images.iconDiscountClose.image(
|
|
|
+ width: 32.w,
|
|
|
+ height: 32.w,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Positioned(
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ bottom: 0,
|
|
|
+ child: Column(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.end,
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
+ children: [
|
|
|
+ Transform.translate(
|
|
|
+ offset: Offset(0, -3),
|
|
|
+ child: ClipPath(
|
|
|
+ clipper: BottomCurveClipper(),
|
|
|
+ child: Container(
|
|
|
+ width: 328.w,
|
|
|
+ height: 150.h,
|
|
|
+ padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
|
|
+ decoration: ShapeDecoration(
|
|
|
+ gradient: LinearGradient(
|
|
|
+ begin: Alignment(0.50, 0.56),
|
|
|
+ end: Alignment(0.50, 1.00),
|
|
|
+ colors: [Colors.white, const Color(0xFFDFFFD7)],
|
|
|
+ ),
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ borderRadius: BorderRadius.circular(25),
|
|
|
+ ),
|
|
|
+ shadows: [
|
|
|
+ BoxShadow(
|
|
|
+ color: Color(0xFFC6FF32),
|
|
|
+ blurRadius: 4.r,
|
|
|
+ offset: Offset(0, 0),
|
|
|
+ spreadRadius: 0,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
+ children: [
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ Assets.images.iconDiscountBoxTitle.image(
|
|
|
+ width: 73.w,
|
|
|
+ height: 22.h,
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ StringName.discountDialogDesc,
|
|
|
+ style: TextStyle(
|
|
|
+ color: const Color(0xFF6EC1A8),
|
|
|
+ fontSize: 10.sp,
|
|
|
+ fontWeight: FontWeight.w400,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
|
+ children: [
|
|
|
+ _buildBox(
|
|
|
+ colors: [
|
|
|
+ const Color(0xFFBDE7FF),
|
|
|
+ const Color(0xFFF3FBFF),
|
|
|
+ ],
|
|
|
+ image: Assets.images.iconDiscountChat,
|
|
|
+ text: StringName.discountDialogChat,
|
|
|
+ ),
|
|
|
+ _buildBox(
|
|
|
+ colors: [
|
|
|
+ const Color(0xFFFFD5DC),
|
|
|
+ const Color(0xFFFFFAFB),
|
|
|
+ ],
|
|
|
+ image: Assets.images.iconDiscountTutorial,
|
|
|
+ text: StringName.discountDialogTutorial,
|
|
|
+ ),
|
|
|
+ _buildBox(
|
|
|
+ colors: [
|
|
|
+ const Color(0xFFFFECBC),
|
|
|
+ const Color(0xFFFFFDDE),
|
|
|
+ ],
|
|
|
+ image: Assets.images.iconDiscountCharacter,
|
|
|
+ text: StringName.discountDialogCharacter,
|
|
|
+ ),
|
|
|
+ _buildBox(
|
|
|
+ colors: [
|
|
|
+ const Color(0xFFD2DBFF),
|
|
|
+ const Color(0xFFF1F4FF),
|
|
|
+ ],
|
|
|
+ image: Assets.images.iconDiscountSocial,
|
|
|
+ text: StringName.discountDialogSocial,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildBottomCard() {
|
|
|
+ return Container(
|
|
|
+ width: 330.w,
|
|
|
+ decoration: ShapeDecoration(
|
|
|
+ gradient: LinearGradient(
|
|
|
+ begin: Alignment(0.00, 0.50),
|
|
|
+ end: Alignment(1.00, 0.50),
|
|
|
+ colors: [const Color(0xFFB2FB52), const Color(0xFF9CFD27)],
|
|
|
+ ),
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ side: BorderSide(width: 1.w, color: Colors.white),
|
|
|
+ borderRadius: BorderRadius.circular(20.r),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Stack(
|
|
|
+ children: [
|
|
|
+ Positioned(
|
|
|
+ child: IgnorePointer(
|
|
|
+ child: Opacity(
|
|
|
+ opacity: 0.4,
|
|
|
+ child: Assets.images.bgDiscountContent.image(),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+
|
|
|
+ Positioned(
|
|
|
+ child: Column(
|
|
|
+ children: [
|
|
|
+ _buildDescTime(),
|
|
|
+ Container(
|
|
|
+ width: 330.w,
|
|
|
+ decoration: ShapeDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ borderRadius: BorderRadius.circular(20.r),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: SingleChildScrollView(
|
|
|
+ child: Column(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
+ children: [
|
|
|
+ SizedBox(height: 12.h),
|
|
|
+ buildGoodsItem(
|
|
|
+ tagTop: true,
|
|
|
+ tagTopDesc: "秒杀价",
|
|
|
+ title: "测试",
|
|
|
+ tagRight: true,
|
|
|
+ tagRightDesc: "买断价",
|
|
|
+ selected: false,
|
|
|
+ onTap: () {},
|
|
|
+ ),
|
|
|
+ SizedBox(height: 12.h),
|
|
|
+ buildGoodsItem(
|
|
|
+ tagTop: true,
|
|
|
+ tagTopDesc: "秒杀价",
|
|
|
+ title: "测试",
|
|
|
+ tagRight: true,
|
|
|
+ tagRightDesc: "买断价",
|
|
|
+ selected: true,
|
|
|
+ onTap: () {},
|
|
|
+ ),
|
|
|
+ SizedBox(height: 12.h),
|
|
|
+ _buildPayWayCard(),
|
|
|
+
|
|
|
+ Container(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
|
+ alignment: Alignment.centerLeft,
|
|
|
+ child: Text(
|
|
|
+ '*首周18.8元,后续38元/周,可随时取消',
|
|
|
+ style: TextStyle(
|
|
|
+ color: const Color(0x99673300),
|
|
|
+ fontSize: 10.sp,
|
|
|
+ fontWeight: FontWeight.w400,
|
|
|
+ height: 2,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ SizedBox(height: 54.h),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildGoodsItem({
|
|
|
+ required bool tagTop,
|
|
|
+ required String? tagTopDesc,
|
|
|
+ required bool tagRight,
|
|
|
+ required String? tagRightDesc,
|
|
|
+ required String title,
|
|
|
+
|
|
|
+ required bool selected,
|
|
|
+ required VoidCallback onTap,
|
|
|
+ }) {
|
|
|
+ return GestureDetector(
|
|
|
+ onTap: onTap,
|
|
|
+ child: Stack(
|
|
|
+ clipBehavior: Clip.none,
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
|
+ height: 72.h,
|
|
|
+ width: 298.w,
|
|
|
+ decoration: ShapeDecoration(
|
|
|
+ color: selected ? Color(0xFFFFF9BB) : Color(0xFFFFFDE2),
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ side: BorderSide(
|
|
|
+ width: 2.w,
|
|
|
+ color: selected ? Color(0xFFFF7F14) : Color(0xFFFFFAC1),
|
|
|
+ ),
|
|
|
+ borderRadius: BorderRadius.circular(16.r),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ title,
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 22,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ color: Color(0xFF663300),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ SizedBox(width: 8),
|
|
|
+ if (tagRight == tagRight) // 只有“买断价”才显示这个标签
|
|
|
+ Container(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Color(0xFFFFD5A0),
|
|
|
+ borderRadius: BorderRadius.circular(6.r),
|
|
|
+ ),
|
|
|
+ child: Text(
|
|
|
+ tagRightDesc ?? '',
|
|
|
+ style: TextStyle(fontSize: 12, color: Color(0xFFBB5A00)),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Spacer(),
|
|
|
+ Container(
|
|
|
+ width: 20.w,
|
|
|
+ height: 20.w,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ shape: BoxShape.circle,
|
|
|
+ border: Border.all(
|
|
|
+ color: selected ? Color(0xFFFF7F14) : Color(0xFFFEE86B),
|
|
|
+ width: 2.w,
|
|
|
+ ),
|
|
|
+ color: selected ? Color(0xFFFF8400) : Colors.white,
|
|
|
+ ),
|
|
|
+ child:
|
|
|
+ selected
|
|
|
+ ? Icon(Icons.check, color: Colors.white, size: 16)
|
|
|
+ : null,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ if (tagTop == true) // 只对“秒杀价”显示上面的标签
|
|
|
+ Positioned(
|
|
|
+ top: -6.h,
|
|
|
+
|
|
|
+ child: Container(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 2.h),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ image: DecorationImage(
|
|
|
+ image: Assets.images.bgDiscountTagTop.provider(),
|
|
|
+ fit: BoxFit.fill,
|
|
|
+ ),
|
|
|
+ borderRadius: BorderRadius.circular(4.r),
|
|
|
+ ),
|
|
|
+ child: Text(
|
|
|
+ tagTopDesc ?? '',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 12.sp,
|
|
|
+ color: Colors.white,
|
|
|
+ fontWeight: FontWeight.w600,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 倒计时
|
|
|
+ _buildDescTime() {
|
|
|
+ return Container(
|
|
|
+ padding: EdgeInsets.only(
|
|
|
+ left: 16.w,
|
|
|
+ right: 16.w,
|
|
|
+ top: 12.h,
|
|
|
+ bottom: 12.h,
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ Assets.images.iconDiscountSubhead.image(width: 90.w, height: 20.h),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ _buildTimeBox("00"),
|
|
|
+ VerticalDots(
|
|
|
+ height: 8.h,
|
|
|
+ dotSize: 2.w,
|
|
|
+ color: const Color(0xFF2F640B),
|
|
|
+ horizontalPadding: 5.w,
|
|
|
+ ),
|
|
|
+ _buildTimeBox("00"),
|
|
|
+ VerticalDots(
|
|
|
+ height: 8.h,
|
|
|
+ dotSize: 2.w,
|
|
|
+ color: const Color(0xFF2F640B),
|
|
|
+ horizontalPadding: 5.w,
|
|
|
+ ),
|
|
|
+ _buildTimeBox("00"),
|
|
|
+ SizedBox(width: 6.w),
|
|
|
+ Text(
|
|
|
+ StringName.discountDialogEndDesc,
|
|
|
+ style: TextStyle(
|
|
|
+ color: const Color(0xFF2F640B),
|
|
|
+ fontSize: 10.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildTimeBox(String value) {
|
|
|
+ return Container(
|
|
|
+ width: 18.w,
|
|
|
+ height: 15.h,
|
|
|
+ decoration: ShapeDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.r)),
|
|
|
+ ),
|
|
|
+ child: Center(
|
|
|
+ child: Text(
|
|
|
+ value,
|
|
|
+ style: TextStyle(
|
|
|
+ color: const Color(0xFF2F640B),
|
|
|
+ fontSize: 10.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 功能模块
|
|
|
+ Widget _buildBox({
|
|
|
+ required List<Color> colors,
|
|
|
+ required AssetGenImage image,
|
|
|
+ required String text,
|
|
|
+ }) {
|
|
|
+ return Container(
|
|
|
+ width: 70.w,
|
|
|
+ height: 76.w,
|
|
|
+ decoration: ShapeDecoration(
|
|
|
+ gradient: LinearGradient(
|
|
|
+ begin: Alignment(0.50, 0.00),
|
|
|
+ end: Alignment(0.50, 1.00),
|
|
|
+ colors: colors,
|
|
|
+ ),
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ side: BorderSide(width: 1, color: Colors.white),
|
|
|
+ borderRadius: BorderRadius.circular(10.r),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Column(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
+ children: [
|
|
|
+ image.image(width: 28.w, height: 28.w),
|
|
|
+ SizedBox(height: 4.h),
|
|
|
+ Text(
|
|
|
+ text,
|
|
|
+ style: TextStyle(
|
|
|
+ color: const Color(0xFF4A4B28),
|
|
|
+ fontSize: 13.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
+ Widget _buildPayWayCard() {
|
|
|
+ return GestureDetector(
|
|
|
+ onTap: () => controller.clickPayWaySwitch(),
|
|
|
+ child: Container(
|
|
|
+ height: 36.h,
|
|
|
+ margin: EdgeInsets.symmetric(horizontal: 17.w),
|
|
|
+ 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,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// 底部曲线剪裁
|
|
|
+class BottomCurveClipper extends CustomClipper<Path> {
|
|
|
+ @override
|
|
|
+ Path getClip(Size size) {
|
|
|
+ Path path = Path();
|
|
|
+ path.lineTo(0, size.height - 20);
|
|
|
+ path.quadraticBezierTo(
|
|
|
+ size.width / 2,
|
|
|
+ size.height,
|
|
|
+ size.width,
|
|
|
+ size.height - 20,
|
|
|
+ );
|
|
|
+ path.lineTo(size.width, 0);
|
|
|
+ path.close();
|
|
|
+ return path;
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ bool shouldReclip(CustomClipper<Path> oldClipper) => false;
|
|
|
+}
|