diff --git a/assets/ic_apple.png b/assets/ic_apple.png new file mode 100644 index 0000000..9604d3a Binary files /dev/null and b/assets/ic_apple.png differ diff --git a/assets/ic_fb.png b/assets/ic_fb.png new file mode 100644 index 0000000..f073917 Binary files /dev/null and b/assets/ic_fb.png differ diff --git a/assets/login_bg.png b/assets/login_bg.png new file mode 100644 index 0000000..6405e31 Binary files /dev/null and b/assets/login_bg.png differ diff --git a/assets/login_sheet_bg.png b/assets/login_sheet_bg.png new file mode 100644 index 0000000..64e6078 Binary files /dev/null and b/assets/login_sheet_bg.png differ diff --git a/assets/month_text_bg.png b/assets/month_text_bg.png new file mode 100644 index 0000000..5f41f5c Binary files /dev/null and b/assets/month_text_bg.png differ diff --git a/assets/quarter_text_bg.png b/assets/quarter_text_bg.png new file mode 100644 index 0000000..84a955f Binary files /dev/null and b/assets/quarter_text_bg.png differ diff --git a/assets/year_text_bg.png b/assets/year_text_bg.png new file mode 100644 index 0000000..e7cd4a7 Binary files /dev/null and b/assets/year_text_bg.png differ diff --git a/lib/kt_model/kt_goods_bean.dart b/lib/kt_model/kt_goods_bean.dart index 0ea8e2b..ee69223 100644 --- a/lib/kt_model/kt_goods_bean.dart +++ b/lib/kt_model/kt_goods_bean.dart @@ -81,6 +81,9 @@ class KtGoodsBean { int? payTemplateId, String? deletedAt, int? payProductId, + int? isFirstBuy, + int? isDiscount, + int? discountType, ExtInfo? extInfo, String? factor, String? shortType, @@ -125,6 +128,9 @@ class KtGoodsBean { _payTemplateId = payTemplateId; _deletedAt = deletedAt; _payProductId = payProductId; + _discountType = discountType; + _isDiscount = isDiscount; + _isFirstBuy = isFirstBuy; _extInfo = extInfo; _factor = factor; _shortType = shortType; @@ -171,6 +177,9 @@ class KtGoodsBean { _payTemplateId = json['pay_template_id']; _deletedAt = json['deleted_at']; _payProductId = json['pay_product_id']; + _discountType = json['discount_type']; + _isDiscount = json['is_discount']; + _isFirstBuy = json['is_first_buy']; _extInfo = json['ext_info'] != null ? ExtInfo.fromJson(json['ext_info']) : null; _factor = json['factor']; _shortType = json['short_type']; @@ -216,6 +225,9 @@ class KtGoodsBean { int? _payTemplateId; String? _deletedAt; int? _payProductId; + int? _discountType; + int? _isDiscount; + int? _isFirstBuy; ExtInfo? _extInfo; String? _factor; String? _shortType; @@ -261,6 +273,9 @@ class KtGoodsBean { int? payTemplateId, String? deletedAt, int? payProductId, + int? discountType, + int? isDiscount, + int? isFirstBuy, ExtInfo? extInfo, String? factor, String? shortType, @@ -305,6 +320,9 @@ class KtGoodsBean { payTemplateId: payTemplateId ?? _payTemplateId, deletedAt: deletedAt ?? _deletedAt, payProductId: payProductId ?? _payProductId, + discountType: discountType ?? _discountType, + isDiscount: isDiscount ?? _isDiscount, + isFirstBuy: isFirstBuy ?? _isFirstBuy, extInfo: extInfo ?? _extInfo, factor: factor ?? _factor, shortType: shortType ?? _shortType, @@ -383,6 +401,12 @@ class KtGoodsBean { int? get payProductId => _payProductId; + int? get discountType => _discountType; + + int? get isDiscount => _isDiscount; + + int? get isFirstBuy => _isFirstBuy; + ExtInfo? get extInfo => _extInfo; String? get factor => _factor; @@ -470,6 +494,12 @@ class KtGoodsBean { set payProductId(int? value) => _payProductId = value; + set discountType(int? value) => _discountType = value; + + set isDiscount(int? value) => _isDiscount = value; + + set isFirstBuy(int? value) => _isFirstBuy = value; + set extInfo(ExtInfo? value) => _extInfo = value; set factor(String? value) => _factor = value; @@ -525,6 +555,9 @@ class KtGoodsBean { map['pay_template_id'] = _payTemplateId; map['deleted_at'] = _deletedAt; map['pay_product_id'] = _payProductId; + map['discount_type'] = _discountType; + map['is_discount'] = _isDiscount; + map['is_first_buy'] = _isFirstBuy; if (_extInfo != null) { map['ext_info'] = _extInfo?.toJson(); } @@ -705,5 +738,4 @@ class BackhaulPercentConf { map['backhaul_percent'] = _backhaulPercent; return map; } -} - +} \ No newline at end of file diff --git a/lib/kt_model/kt_login_bean.dart b/lib/kt_model/kt_login_bean.dart new file mode 100644 index 0000000..5f18f6c --- /dev/null +++ b/lib/kt_model/kt_login_bean.dart @@ -0,0 +1,32 @@ +import 'dart:convert'; + +/// customer_id : "" +/// token : "" + +KtLoginBean ktLoginBeanFromJson(String str) => KtLoginBean.fromJson(json.decode(str)); +String ktLoginBeanToJson(KtLoginBean data) => json.encode(data.toJson()); + +class KtLoginBean { + KtLoginBean({String? customerId, String? token}) { + _customerId = customerId; + _token = token; + } + + KtLoginBean.fromJson(dynamic json) { + _customerId = json['customer_id']; + _token = json['token']; + } + String? _customerId; + String? _token; + KtLoginBean copyWith({String? customerId, String? token}) => + KtLoginBean(customerId: customerId ?? _customerId, token: token ?? _token); + String? get customerId => _customerId; + String? get token => _token; + + Map toJson() { + final map = {}; + map['customer_id'] = _customerId; + map['token'] = _token; + return map; + } +} diff --git a/lib/kt_pages/kt_mine/kt_store/logic.dart b/lib/kt_pages/kt_mine/kt_store/logic.dart index c23e39a..9128441 100644 --- a/lib/kt_pages/kt_mine/kt_store/logic.dart +++ b/lib/kt_pages/kt_mine/kt_store/logic.dart @@ -69,7 +69,7 @@ class KtStoreLogic extends GetxController { if (res.success) { state.storeBean = KtStoreBean.fromJson(res.data); update(); - initStore(); + // initStore(); } } catch (e) { EasyLoading.dismiss(); diff --git a/lib/kt_pages/kt_mine/logic.dart b/lib/kt_pages/kt_mine/logic.dart index c43ca84..6682756 100644 --- a/lib/kt_pages/kt_mine/logic.dart +++ b/lib/kt_pages/kt_mine/logic.dart @@ -1,13 +1,25 @@ -import 'package:flustars/flustars.dart'; +import 'dart:io'; + +import 'package:flustars/flustars.dart' hide ScreenUtil; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; import 'package:flutter_kinetra/dio_cilent/kt_apis.dart'; import 'package:flutter_kinetra/kt_pages/kt_mine/state.dart'; +import 'package:flutter_kinetra/kt_utils/kt_string_extend.dart'; import 'package:flutter_kinetra/kt_utils/kt_utils.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import '../../dio_cilent/kt_request.dart'; +import '../../kt_model/kt_login_bean.dart'; import '../../kt_model/kt_user_info.dart'; import '../../kt_utils/kt_keys.dart'; +import '../../kt_utils/kt_toast_utils.dart'; +import '../../kt_widgets/kt_dialog.dart'; +import '../kt_routes.dart'; +import '../kt_webview_page.dart'; class KtMineLogic extends GetxController { final state = KtMineState(); @@ -39,4 +51,237 @@ class KtMineLogic extends GetxController { refreshController.refreshCompleted(); } } + + showLoginDialog() { + Get.bottomSheet( + isScrollControlled: true, + Container( + height: 510.w, + width: ScreenUtil().screenWidth, + padding: EdgeInsets.fromLTRB(0.w, 68.w, 0.w, 20.w), + decoration: BoxDecoration( + // borderRadius: BorderRadius.vertical(top: Radius.circular(12.w)), + image: DecorationImage( + image: AssetImage('login_sheet_bg.png'.ktIcon), + fit: BoxFit.fill, + ), + ), + child: Column( + children: [ + Image.asset('login_bg.png'.ktIcon, width: 322.w), + SizedBox(height: 14.w), + Text( + 'Welcome to LimeTale', + style: TextStyle( + fontSize: 20.sp, + color: Color(0xFF1C1C1C), + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ), + ), + const Spacer(), + GestureDetector( + onTap: loginWithFacebook, + child: Container( + width: ScreenUtil().screenWidth - 30.w, + padding: EdgeInsets.fromLTRB(35.w, 13.w, 30.w, 13.w), + decoration: BoxDecoration( + border: Border.all(width: 1.w, color: Color(0xFF1E1E20)), + borderRadius: BorderRadius.circular(100), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.asset('ic_fb.png'.ktIcon, width: 20.w), + Text( + 'Login with Facebook', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF1C1C1C), + ), + ), + Image.asset('ic_right_arrow.png'.ktIcon, width: 14.w), + ], + ), + ), + ), + if (Platform.isIOS) + GestureDetector( + child: Container( + width: ScreenUtil().screenWidth - 30.w, + margin: EdgeInsets.only(top: 20.w), + padding: EdgeInsets.fromLTRB(35.w, 13.w, 30.w, 13.w), + decoration: BoxDecoration( + color: Color(0xFF1C1C1C), + borderRadius: BorderRadius.circular(100), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.asset('ic_apple.png'.ktIcon, width: 20.w), + Text( + 'Login with Facebook', + style: TextStyle(fontSize: 14.sp, color: Colors.white), + ), + Image.asset('ic_right_white.png'.ktIcon, width: 14.w), + ], + ), + ), + ), + const Spacer(), + Column( + children: [ + Text( + 'By logging in you agree to:', + style: TextStyle(fontSize: 12.sp, color: Color(0xFF777777)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () => Get.to( + () => KtWebViewPage( + url: KtApis.WEB_SITE_POLICY, + title: "User Agreement", + ), + ), + child: Text( + 'User Agreement', + style: TextStyle( + fontSize: 12.sp, + decoration: TextDecoration.underline, // 添加下划线 + color: Color(0xFF777777), + ), + ), + ), + Text( + ' & ', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF777777), + ), + ), + GestureDetector( + onTap: () => Get.to( + () => KtWebViewPage( + url: KtApis.WEB_SITE_PRIVATE, + title: "Privacy Policy", + ), + ), + child: Text( + 'Privacy Policy', + style: TextStyle( + fontSize: 12.sp, + decoration: TextDecoration.underline, // 添加下划线 + color: Color(0xFF777777), + ), + ), + ), + ], + ), + ], + ), + ], + ), + ), + ); + } + + loginWithFacebook() async { + final LoginResult result = await FacebookAuth.instance.login( + permissions: ['email', 'public_profile'], + loginBehavior: LoginBehavior.nativeWithFallback, + ); + if (result.status == LoginStatus.success) { + try { + EasyLoading.show(status: '', dismissOnTap: true); + final userData = await FacebookAuth.instance.getUserData(); + final String facebookAvatar = + userData['picture']?['data']?['url'] ?? ""; + final String facebookId = userData['id'] ?? ""; + final String facebookEmail = userData['email'] ?? ""; + final String facebookName = userData['name'] ?? ""; + loginRequest( + facebookAvatar, + facebookEmail, + facebookName, + 'facebook', + facebookId, + ); + } catch (e) { + EasyLoading.dismiss(); + } + } else { + KtToastUtils.showError('Login failed'); + debugPrint('---facebook failed-:${result.status} ${result.message}'); + } + } + + loginRequest(String avatar, email, familyName, platform, thirdId) async { + Map params = { + "avator": avatar, + "email": email, + "family_name": familyName, + "platform": platform, + "third_id": thirdId, + }; + + ApiResponse res = await KtHttpClient().request(KtApis.login, data: params); + EasyLoading.dismiss(); + if (res.success) { + debugPrint('----old token"${SpUtil.getString(KtKeys.token)}'); + String? token = SpUtil.getString(KtKeys.token); + await KtHttpClient().request( + KtApis.leaveApp, + data: {'PostAuthorization': token ?? ''}, + ); + + await KtHttpClient().request( + KtApis.onLine, + data: {'PostAuthorization': token ?? ''}, + ); + KtLoginBean data = KtLoginBean.fromJson(res.data); + + SpUtil.putString(KtKeys.token, data.token ?? ''); + KtHttpClient().setAuthToken(data.token ?? ''); + debugPrint('----new token"${SpUtil.getString(KtKeys.token)}'); + await KtHttpClient().request( + KtApis.enterTheApp, + data: {'is_open_notice': 0}, + ); + getUserInfo(); + + // Get.offAllNamed(KtRoutes.home); + } else { + KtToastUtils.showError('Login Failed'); + } + } + + checkSignOut() { + Get.dialog( + KtDialog( + topIcon: 'dialog_logout.png', + title: 'Log out?', + subTitle: 'Sign in again to access favorites', + leftBtnText: 'Log Out', + leftBtnFunc: signOut, + rightBtnText: 'Stay', + ), + ); + } + + signOut() async { + String? token = SpUtil.getString(KtKeys.token); + await KtHttpClient().request( + KtApis.leaveApp, + data: {'PostAuthorization': token ?? ''}, + ); + ApiResponse res = await KtHttpClient().request(KtApis.signOut); + if (res.success) { + KtToastUtils.showSuccess(placeholder: 'Logout Success'); + + // await UserUtil().register(toHome: false); + getUserInfo(); + } + } } diff --git a/lib/kt_pages/kt_mine/view.dart b/lib/kt_pages/kt_mine/view.dart index 59d735f..330ca3d 100644 --- a/lib/kt_pages/kt_mine/view.dart +++ b/lib/kt_pages/kt_mine/view.dart @@ -198,6 +198,38 @@ class _KtMinePageState extends State { ), ], ), + const Spacer(), + GestureDetector( + onTap: () { + logic.isLogin + ? logic.checkSignOut() + : logic.showLoginDialog(); + }, + child: Container( + width: 78.w, + alignment: Alignment.center, + padding: EdgeInsets.symmetric( + vertical: 11.w, + ), + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(100), + border: Border.all( + width: 1.w, + color: Color(0xFFC0C0C0), + ), + ), + child: Text( + logic.isLogin + ? 'Log out' + : 'Log in', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFFC0C0C0), + ), + ), + ), + ), ], ), ), diff --git a/lib/kt_utils/kt_utils.dart b/lib/kt_utils/kt_utils.dart index aa1c4ff..01c550d 100644 --- a/lib/kt_utils/kt_utils.dart +++ b/lib/kt_utils/kt_utils.dart @@ -1,3 +1,11 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:in_app_purchase/in_app_purchase.dart'; +import 'package:in_app_purchase_android/billing_client_wrappers.dart'; +import 'package:in_app_purchase_android/in_app_purchase_android.dart'; +import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; + class KtUtils { static String getTimeZoneOffset(DateTime dateTime) { Duration offset = dateTime.timeZoneOffset; @@ -18,4 +26,60 @@ class KtUtils { static bool isNotEmpty(dynamic value) { return !isEmpty(value); } + + + static String getDiscountPrice(ProductDetails? product, {bool showDiscount = false}) { + String price = product?.price ?? ''; + if (product == null) return price; + if (Platform.isIOS) { + if (product is AppStoreProductDetails) { + debugPrint("skProduct优惠价格: ${product.skProduct.price}"); + for (final discount in product.skProduct.discounts) { + debugPrint("优惠ID: ${discount.identifier}"); + debugPrint("优惠价格: ${discount.price}"); + debugPrint("priceLocale: ${discount.priceLocale.currencySymbol}-${discount.priceLocale.currencyCode}"); + debugPrint("优惠周期: ${discount.subscriptionPeriod.numberOfUnits}"); + debugPrint("支付模式: ${discount.paymentMode}"); // freeTrial, payAsYouGo, payUpFront + if (isNotEmpty(discount.price)) price = discount.priceLocale.currencySymbol + discount.price; + break; + } + } + } else if (Platform.isAndroid) { + if (product is GooglePlayProductDetails) { + for (SubscriptionOfferDetailsWrapper? offer in product.productDetails.subscriptionOfferDetails ?? []) { + debugPrint('Base plan ID: ${offer?.basePlanId}'); + debugPrint('Offer ID: ${offer?.offerId}'); + if (offer?.pricingPhases.isEmpty ?? true) continue; + for (PricingPhaseWrapper phase in offer!.pricingPhases) { + debugPrint('价格: ${phase.formattedPrice}'); + debugPrint('周期: ${phase.billingPeriod}'); + debugPrint('周期内收费次数: ${phase.recurrenceMode}'); + if (isNotEmpty(phase.formattedPrice)) { + price = phase.formattedPrice; + if (showDiscount) return price; + } + } + } + } + } + return price; + } + + static Map filterVipType(String? type) { + if (isEmpty(type)) { + return {}; + } + List> vipTypes = [ + {'type': 'week', 'name': 'Weekly', 'shortName': 'week'}, + {'type': 'month', 'name': 'Monthly', 'shortName': 'month'}, + {'type': 'three_months', 'name': 'Quarterly', 'shortName': 'quarter'}, + {'type': 'yearly', 'name': 'Yearly', 'shortName': 'year'}, + {'type': 'year', 'name': 'Yearly', 'shortName': 'year'}, + ]; + final filterType = vipTypes.where((item) => item['type'] == type).cast?>().firstOrNull; + if (filterType != null) { + return filterType; + } + return {}; + } } diff --git a/lib/kt_widgets/kt_dialog.dart b/lib/kt_widgets/kt_dialog.dart index 435d5b1..8640150 100644 --- a/lib/kt_widgets/kt_dialog.dart +++ b/lib/kt_widgets/kt_dialog.dart @@ -66,7 +66,7 @@ class KtDialog extends StatelessWidget { style: TextStyle( fontSize: 15.sp, color: Color(0xFF1C1C1C), - fontWeight: FontWeight.w500, + fontWeight: FontWeight.w400, ), ), ), diff --git a/lib/kt_widgets/kt_store_widget.dart b/lib/kt_widgets/kt_store_widget.dart index fcab6b9..3b7e704 100644 --- a/lib/kt_widgets/kt_store_widget.dart +++ b/lib/kt_widgets/kt_store_widget.dart @@ -1,6 +1,9 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_kinetra/kt_model/kt_goods_bean.dart'; import 'package:flutter_kinetra/kt_utils/kt_string_extend.dart'; +import 'package:flutter_kinetra/kt_utils/kt_utils.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../kt_model/kt_store_bean.dart'; @@ -35,13 +38,16 @@ class _KtStoreWidgetState extends State { } Widget descView() { - return Text(''' + return Text( + ''' 1. Coins are virtual items and cannot be refunded. Use it for this product. \n 2. Gold coins will never expire, the reward coins will expire 24 hours a day.\n 3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used. \n 4. The purchase has not been credited, click to refresh. \n 5. For other questions, contact us via Profile>Help &feedback.\n - ''', style: TextStyle(fontSize: 12.sp, color: Color(0xFF848484),height: 0.95)); + ''', + style: TextStyle(fontSize: 12.sp, color: Color(0xFF848484), height: 0.95), + ); } List initWidget() { @@ -51,11 +57,10 @@ class _KtStoreWidgetState extends State { // int coinsIndex = widget.store.sort?.indexOf('list_coins') ?? 0; // int vipIndex = widget.store.sort?.indexOf('list_sub_vip') ?? 0; // if (coinsIndex < vipIndex) { - // widgets.addAll([coinList(), SizedBox(height: 15.w), vipList()]); + widgets.addAll([coinList(), SizedBox(height: 15.w), vipList()]); // } else { // widgets.addAll([vipList(), SizedBox(height: 15.w), coinList()]); // } - widgets.addAll([coinList()]); widgets.addAll([ if (widget.store.payMode == 0 && widget.store.showType == 0) @@ -75,7 +80,7 @@ class _KtStoreWidgetState extends State { Widget coinList() { if (widget.store.listCoins?.isEmpty ?? true) return Container(); - return Column( + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (!widget.onlyCoins) @@ -85,7 +90,9 @@ class _KtStoreWidgetState extends State { 'Go Coins', style: TextStyle( fontSize: 14.sp, - color:widget.isStoreDialog? Color(0xFF1E1E20):Colors.white, + color: widget.isStoreDialog + ? Color(0xFF1E1E20) + : Colors.white, fontWeight: FontWeight.w600, ), ), @@ -93,7 +100,9 @@ class _KtStoreWidgetState extends State { ' | Limited-time coin packs', style: TextStyle( fontSize: 14.sp, - color:widget.isStoreDialog? Color(0xFF1E1E20):Colors.white, + color: widget.isStoreDialog + ? Color(0xFF1E1E20) + : Colors.white, fontWeight: FontWeight.w200, ), ), @@ -129,10 +138,7 @@ class _KtStoreWidgetState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Image.asset( - 'ic_coin.png'.ktIcon, - width: 22.4.w, - ), + Image.asset('ic_coin.png'.ktIcon, width: 22.4.w), Text( '${item.coins ?? 0}', style: TextStyle( @@ -179,10 +185,7 @@ class _KtStoreWidgetState extends State { Positioned( top: 4.w, left: 4.w, - child: Image.asset( - 'ic_fire.png'.ktIcon, - width: 16.w, - ), + child: Image.asset('ic_fire.png'.ktIcon, width: 16.w), ), if ((item.sendCoins ?? 0) > 0) Positioned( @@ -361,4 +364,186 @@ class _KtStoreWidgetState extends State { ], ); } + + Widget vipList() { + if (widget.store.listSubVip?.isEmpty ?? true) return Container(); + if (widget.store.payMode == 1) return Container(); + final colors = { + "month": Color(0xFF00679A), + "week": Color(0xFF3D6D00), + "quarter": Color(0xFF5C5FB5), + "year": Color(0xFFAE6F00), + }; + final textColors = { + "month": Color(0xFFBDEBFF), + "week": Color(0xFFE7FCCA), + "quarter": Color(0xFFDBDDFF), + "year": Color(0xFFFFF2DA), + }; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Go VIP Premium | Auto renew, cancel anytime ', + style: TextStyle( + fontSize: 14.sp, + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 10.w), + ListView.separated( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (_, index) { + KtGoodsBean item = widget.store.listSubVip![index]; + return GestureDetector( + onTap: () { + selVip = item.id ?? -1; + setState(() {}); + widget.onItemTap?.call(item); // 回调 + }, + child: Container( + width: ScreenUtil().screenWidth - 30.w, + padding: EdgeInsets.fromLTRB(12.w, 19.w, 12.w, 5.w), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('vip_${item.vipTypeKey}_bg.png'.ktIcon), + fit: BoxFit.fill, + ), + border: selVip == item.id + ? Border.all(color: Colors.red, width: 1.5.w) + : null, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${item.shortType ?? ''} VIP', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF2A0428), + fontWeight: FontWeight.w500, + ), + ), + item.discountType != 0 + ? RichText( + text: TextSpan( + children: [ + TextSpan( + text: Platform.isAndroid + ? item.productDetails?.price + : KtUtils.getDiscountPrice( + item.productDetails, + ), + style: TextStyle( + fontSize: 26.sp, + color: Color(0xFF2A0428), + fontStyle: FontStyle.italic, + ), + ), + TextSpan( + text: Platform.isIOS + ? item.productDetails?.price + : KtUtils.getDiscountPrice( + item.productDetails, + ), + style: TextStyle( + fontSize: 16.sp, + color: Color(0xFFC2C2C2), + decoration: + TextDecoration.lineThrough, // 中间横线 + ), + ), + ], + ), + ) + : RichText( + text: TextSpan( + children: [ + // TextSpan( + // text: item.productDetails?.currencySymbol ?? '', + // style: TextStyle(fontSize: 16.sp, color: ColorResource.mainBlack), + // ), + TextSpan( + text: Platform.isIOS + ? item.productDetails?.price + : KtUtils.getDiscountPrice( + item.productDetails, + ), + style: TextStyle( + fontSize: 26.sp, + color: Color(0xFF2A0428), + fontStyle: FontStyle.italic, + ), + ), + TextSpan( + text: + '/${KtUtils.filterVipType(item.vipType ?? '')['shortName']}', + style: TextStyle( + fontSize: 16.sp, + color: Colors.black, + ), + ), + ], + ), + ), + SizedBox(height: 4.w), + + SizedBox(height: 2.w), + Row( + children: [ + Text( + 'Unlimited access to all series', + // item.description ?? '', + style: TextStyle( + fontSize: 10.sp, + color: Color(0xFF99889B), + ), + ), + const Spacer(), + if ((item.sendCoins ?? 0) > 0) + Stack( + alignment: Alignment.topCenter, + children: [ + Container( + padding: EdgeInsets.only(top: 8.w), + child: Image.asset( + '${KtUtils.filterVipType(item.vipType ?? '')['shortName']}_text_bg.png'.ktIcon, + height: 10.w, + ), + ), + Row( + children: [ + Text( + '+Extra ${item.sendCoins}', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF1E1E20), + fontWeight: FontWeight.w500, + ), + ), + SizedBox(width: 2.w), + Image.asset( + 'ic_coin.png'.ktIcon, + width: 15.w, + ), + ], + ), + ], + ), + ], + ), + ], + ), + ), + ); + }, + separatorBuilder: (_, __) => SizedBox(height: 10.w), + itemCount: widget.store.listSubVip?.length ?? 0, + ), + ], + ); + } }