feat:会员和个人中心
BIN
assets/ic_apple.png
Normal file
|
After Width: | Height: | Size: 868 B |
BIN
assets/ic_fb.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/login_bg.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
assets/login_sheet_bg.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
assets/month_text_bg.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/quarter_text_bg.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/year_text_bg.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
32
lib/kt_model/kt_login_bean.dart
Normal file
@ -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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
map['customer_id'] = _customerId;
|
||||
map['token'] = _token;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@ -69,7 +69,7 @@ class KtStoreLogic extends GetxController {
|
||||
if (res.success) {
|
||||
state.storeBean = KtStoreBean.fromJson(res.data);
|
||||
update();
|
||||
initStore();
|
||||
// initStore();
|
||||
}
|
||||
} catch (e) {
|
||||
EasyLoading.dismiss();
|
||||
|
||||
@ -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<String, dynamic> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,6 +198,38 @@ class _KtMinePageState extends State<KtMinePage> {
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -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<String, dynamic> filterVipType(String? type) {
|
||||
if (isEmpty(type)) {
|
||||
return {};
|
||||
}
|
||||
List<Map<String, dynamic>> 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<Map<String, dynamic>?>().firstOrNull;
|
||||
if (filterType != null) {
|
||||
return filterType;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ class KtDialog extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 15.sp,
|
||||
color: Color(0xFF1C1C1C),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@ -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<KtStoreWidget> {
|
||||
}
|
||||
|
||||
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 <Restore> 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<Widget> initWidget() {
|
||||
@ -51,11 +57,10 @@ class _KtStoreWidgetState extends State<KtStoreWidget> {
|
||||
// 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<KtStoreWidget> {
|
||||
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<KtStoreWidget> {
|
||||
'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<KtStoreWidget> {
|
||||
' | 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<KtStoreWidget> {
|
||||
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<KtStoreWidget> {
|
||||
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<KtStoreWidget> {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||