fix: preview store item effects
This commit is contained in:
parent
2684fd4673
commit
a800a0f941
@ -1,17 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:yumi/app_localizations.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_tts.dart';
|
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
||||||
import 'package:yumi/shared/tools/sc_loading_manager.dart';
|
|
||||||
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
||||||
import 'package:yumi/services/auth/user_profile_manager.dart';
|
|
||||||
import 'package:yumi/ui_kit/widgets/store/props_store_chatbox_detail_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/store/props_store_chatbox_detail_dialog.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
||||||
|
|
||||||
@ -20,8 +13,10 @@ import '../../../shared/data_sources/models/enum/sc_props_type.dart';
|
|||||||
|
|
||||||
///聊天气泡框
|
///聊天气泡框
|
||||||
class StoreChatboxPage extends SCPageList {
|
class StoreChatboxPage extends SCPageList {
|
||||||
|
const StoreChatboxPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_StoreChatboxPageState createState() => _StoreChatboxPageState();
|
SCPageListState createState() => _StoreChatboxPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StoreChatboxPageState
|
class _StoreChatboxPageState
|
||||||
@ -41,7 +36,7 @@ class _StoreChatboxPageState
|
|||||||
crossAxisCount: gridViewCount,
|
crossAxisCount: gridViewCount,
|
||||||
mainAxisSpacing: 12.w,
|
mainAxisSpacing: 12.w,
|
||||||
crossAxisSpacing: 12.w,
|
crossAxisSpacing: 12.w,
|
||||||
childAspectRatio: 0.78,
|
childAspectRatio: 0.88,
|
||||||
);
|
);
|
||||||
loadData(1);
|
loadData(1);
|
||||||
}
|
}
|
||||||
@ -59,100 +54,15 @@ class _StoreChatboxPageState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildItem(StoreListResBean res) {
|
Widget buildItem(StoreListResBean res) {
|
||||||
return GestureDetector(
|
return SCStoreGridItemCard(
|
||||||
child: Container(
|
res: res.res,
|
||||||
decoration: BoxDecoration(
|
selected: res.isSelecte,
|
||||||
color:
|
discount: disCount,
|
||||||
res.isSelecte
|
coverHeight: 45.w,
|
||||||
? const Color(0xff18F2B1).withValues(alpha: 0.1)
|
previewWidth: 88.w,
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
previewHeight: 58.w,
|
||||||
.getStoreItemBackgroundColor(),
|
onPreviewTap: () => _togglePreview(res),
|
||||||
border: Border.all(
|
onDetailsTap: () => _showDetail(res.res),
|
||||||
color:
|
|
||||||
res.isSelecte
|
|
||||||
? SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemSelectedBorderColor()
|
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemUnselectedBorderColor(),
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
netImage(
|
|
||||||
url: res.res.propsResources?.cover ?? "",
|
|
||||||
height: 45.w,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: Image.asset(
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemGoldIcon(),
|
|
||||||
width: 22.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: " "),
|
|
||||||
disCount < 1
|
|
||||||
? TextSpan(
|
|
||||||
text: "${res.res.propsPrices![0].amount}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: TextSpan(),
|
|
||||||
disCount < 1 ? TextSpan(text: " ") : TextSpan(),
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"${((res.res.propsPrices![0].amount ?? 0) * disCount).toInt()}/${res.res.propsPrices![0].days} ${SCAppLocalizations.of(context)!.day}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
strutStyle: StrutStyle(
|
|
||||||
height: 1.3, // 行高倍数
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
forceStrutHeight: true, // 强制应用行高
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
_selectItem(res);
|
|
||||||
_showDetail(res.res);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,39 +101,14 @@ class _StoreChatboxPageState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectItem(StoreListResBean res) {
|
void _togglePreview(StoreListResBean res) {
|
||||||
|
final shouldSelect = !res.isSelecte;
|
||||||
for (var value in items) {
|
for (var value in items) {
|
||||||
value.isSelecte = false;
|
value.isSelecte = false;
|
||||||
}
|
}
|
||||||
res.isSelecte = true;
|
res.isSelecte = shouldSelect;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _buy(StoreListResBean res) {
|
|
||||||
if (res.res.propsPrices!.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SCLoadingManager.show();
|
|
||||||
num days = res.res.propsPrices![0].days ?? 0;
|
|
||||||
SCStoreRepositoryImp()
|
|
||||||
.storePurchasing(
|
|
||||||
res.res.id ?? "",
|
|
||||||
SCPropsType.CHAT_BUBBLE.name,
|
|
||||||
SCCurrencyType.GOLD.name,
|
|
||||||
"$days",
|
|
||||||
)
|
|
||||||
.then((value) {
|
|
||||||
SCTts.show(SCAppLocalizations.of(context)!.purchaseIsSuccessful);
|
|
||||||
Provider.of<SocialChatUserProfileManager>(
|
|
||||||
context,
|
|
||||||
listen: false,
|
|
||||||
).updateBalance(value);
|
|
||||||
SCLoadingManager.hide();
|
|
||||||
})
|
|
||||||
.catchError((e) {
|
|
||||||
SCLoadingManager.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StoreListResBean {
|
class StoreListResBean {
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
||||||
import 'package:yumi/app_localizations.dart';
|
|
||||||
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
||||||
import 'package:yumi/shared/data_sources/models/enum/sc_currency_type.dart';
|
import 'package:yumi/shared/data_sources/models/enum/sc_currency_type.dart';
|
||||||
import 'package:yumi/shared/data_sources/models/enum/sc_props_type.dart';
|
import 'package:yumi/shared/data_sources/models/enum/sc_props_type.dart';
|
||||||
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
||||||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/store/props_store_data_card_detail_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/store/props_store_data_card_detail_dialog.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
||||||
@ -35,7 +32,7 @@ class StoreDataCardPageState
|
|||||||
crossAxisCount: gridViewCount,
|
crossAxisCount: gridViewCount,
|
||||||
mainAxisSpacing: 12.w,
|
mainAxisSpacing: 12.w,
|
||||||
crossAxisSpacing: 12.w,
|
crossAxisSpacing: 12.w,
|
||||||
childAspectRatio: 0.78,
|
childAspectRatio: 0.88,
|
||||||
);
|
);
|
||||||
loadData(1);
|
loadData(1);
|
||||||
}
|
}
|
||||||
@ -54,101 +51,20 @@ class StoreDataCardPageState
|
|||||||
@override
|
@override
|
||||||
Widget buildItem(StoreDataCardListResBean item) {
|
Widget buildItem(StoreDataCardListResBean item) {
|
||||||
final res = item;
|
final res = item;
|
||||||
final prices = res.res.propsPrices ?? const <PropsPrices>[];
|
return SCStoreGridItemCard(
|
||||||
final firstPrice = prices.isNotEmpty ? prices.first : null;
|
res: res.res,
|
||||||
return GestureDetector(
|
selected: res.isSelecte,
|
||||||
child: Container(
|
discount: disCount,
|
||||||
decoration: BoxDecoration(
|
previewKind: SCStoreItemPreviewKind.dataCard,
|
||||||
color:
|
coverWidth: 72.w,
|
||||||
res.isSelecte
|
coverHeight: 50.w,
|
||||||
? const Color(0xff18F2B1).withValues(alpha: 0.1)
|
previewWidth: 88.w,
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
previewHeight: 58.w,
|
||||||
.getStoreItemBackgroundColor(),
|
coverFit: BoxFit.cover,
|
||||||
border: Border.all(
|
previewFit: BoxFit.cover,
|
||||||
color:
|
coverBorderRadius: BorderRadius.circular(6.w),
|
||||||
res.isSelecte
|
onPreviewTap: () => _togglePreview(res),
|
||||||
? SCGlobalConfig.businessLogicStrategy
|
onDetailsTap: () => _showDetail(res.res),
|
||||||
.getStoreItemSelectedBorderColor()
|
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemUnselectedBorderColor(),
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(6.w),
|
|
||||||
child: netImage(
|
|
||||||
url: res.res.propsResources?.cover ?? "",
|
|
||||||
width: 72.w,
|
|
||||||
height: 50.w,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 12.w),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: Image.asset(
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemGoldIcon(),
|
|
||||||
width: 22.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const TextSpan(text: " "),
|
|
||||||
if (disCount < 1)
|
|
||||||
TextSpan(
|
|
||||||
text: "${firstPrice?.amount ?? 0}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (disCount < 1) const TextSpan(text: " "),
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"${((firstPrice?.amount ?? 0) * disCount).toInt()}/${firstPrice?.days ?? 0} ${SCAppLocalizations.of(context)!.day}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
strutStyle: const StrutStyle(
|
|
||||||
height: 1.3,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
forceStrutHeight: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
_selectItem(res);
|
|
||||||
_showDetail(res.res);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,11 +100,12 @@ class StoreDataCardPageState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectItem(StoreDataCardListResBean res) {
|
void _togglePreview(StoreDataCardListResBean res) {
|
||||||
|
final shouldSelect = !res.isSelecte;
|
||||||
for (final value in items) {
|
for (final value in items) {
|
||||||
value.isSelecte = false;
|
value.isSelecte = false;
|
||||||
}
|
}
|
||||||
res.isSelecte = true;
|
res.isSelecte = shouldSelect;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:yumi/app_localizations.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_tts.dart';
|
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
||||||
import 'package:yumi/shared/tools/sc_loading_manager.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
||||||
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
||||||
import 'package:yumi/services/auth/user_profile_manager.dart';
|
|
||||||
import 'package:yumi/ui_kit/widgets/store/props_store_headdress_detail_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/store/props_store_headdress_detail_dialog.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
||||||
|
|
||||||
@ -19,8 +12,10 @@ import '../../../shared/data_sources/models/enum/sc_props_type.dart';
|
|||||||
|
|
||||||
///头饰
|
///头饰
|
||||||
class StoreHeaddressPage extends SCPageList {
|
class StoreHeaddressPage extends SCPageList {
|
||||||
|
const StoreHeaddressPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_StoreHeaddressPageState createState() => _StoreHeaddressPageState();
|
SCPageListState createState() => _StoreHeaddressPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StoreHeaddressPageState
|
class _StoreHeaddressPageState
|
||||||
@ -40,7 +35,7 @@ class _StoreHeaddressPageState
|
|||||||
crossAxisCount: gridViewCount,
|
crossAxisCount: gridViewCount,
|
||||||
mainAxisSpacing: 12.w,
|
mainAxisSpacing: 12.w,
|
||||||
crossAxisSpacing: 12.w,
|
crossAxisSpacing: 12.w,
|
||||||
childAspectRatio: 0.78,
|
childAspectRatio: 0.88,
|
||||||
);
|
);
|
||||||
loadData(1);
|
loadData(1);
|
||||||
}
|
}
|
||||||
@ -58,100 +53,13 @@ class _StoreHeaddressPageState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildItem(StoreListResBean res) {
|
Widget buildItem(StoreListResBean res) {
|
||||||
return GestureDetector(
|
return SCStoreGridItemCard(
|
||||||
child: Container(
|
res: res.res,
|
||||||
decoration: BoxDecoration(
|
selected: res.isSelecte,
|
||||||
color:
|
discount: disCount,
|
||||||
res.isSelecte
|
previewKind: SCStoreItemPreviewKind.avatarFrame,
|
||||||
? const Color(0xff18F2B1).withValues(alpha: 0.1)
|
onPreviewTap: () => _togglePreview(res),
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
onDetailsTap: () => _showDetail(res.res),
|
||||||
.getStoreItemBackgroundColor(),
|
|
||||||
border: Border.all(
|
|
||||||
color:
|
|
||||||
res.isSelecte
|
|
||||||
? SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemSelectedBorderColor()
|
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemUnselectedBorderColor(),
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
netImage(
|
|
||||||
url: res.res.propsResources?.cover ?? "",
|
|
||||||
width: 55.w,
|
|
||||||
height: 55.w,
|
|
||||||
),
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: Image.asset(
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemGoldIcon(),
|
|
||||||
width: 22.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: " "),
|
|
||||||
disCount < 1
|
|
||||||
? TextSpan(
|
|
||||||
text: "${res.res.propsPrices![0].amount}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: TextSpan(),
|
|
||||||
disCount < 1 ? TextSpan(text: " ") : TextSpan(),
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"${((res.res.propsPrices![0].amount ?? 0) * disCount).toInt()}/${res.res.propsPrices![0].days} ${SCAppLocalizations.of(context)!.day}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
strutStyle: StrutStyle(
|
|
||||||
height: 1.3, // 行高倍数
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
forceStrutHeight: true, // 强制应用行高
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
_selectItem(res);
|
|
||||||
_showDetail(res.res);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,39 +98,14 @@ class _StoreHeaddressPageState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectItem(StoreListResBean res) {
|
void _togglePreview(StoreListResBean res) {
|
||||||
|
final shouldSelect = !res.isSelecte;
|
||||||
for (var value in items) {
|
for (var value in items) {
|
||||||
value.isSelecte = false;
|
value.isSelecte = false;
|
||||||
}
|
}
|
||||||
res.isSelecte = true;
|
res.isSelecte = shouldSelect;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _buy(StoreListResBean res) {
|
|
||||||
if (res.res.propsPrices!.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SCLoadingManager.show();
|
|
||||||
num days = res.res.propsPrices![0].days ?? 0;
|
|
||||||
SCStoreRepositoryImp()
|
|
||||||
.storePurchasing(
|
|
||||||
res.res.id ?? "",
|
|
||||||
SCPropsType.AVATAR_FRAME.name,
|
|
||||||
SCCurrencyType.GOLD.name,
|
|
||||||
"$days",
|
|
||||||
)
|
|
||||||
.then((value) {
|
|
||||||
SCTts.show(SCAppLocalizations.of(context)!.purchaseIsSuccessful);
|
|
||||||
Provider.of<SocialChatUserProfileManager>(
|
|
||||||
context,
|
|
||||||
listen: false,
|
|
||||||
).updateBalance(value);
|
|
||||||
SCLoadingManager.hide();
|
|
||||||
})
|
|
||||||
.catchError((e) {
|
|
||||||
SCLoadingManager.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StoreListResBean {
|
class StoreListResBean {
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:yumi/app_localizations.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
||||||
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/store/props_store_mountains_detail_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/store/props_store_mountains_detail_dialog.dart';
|
||||||
@ -16,10 +13,10 @@ import '../../../shared/data_sources/models/enum/sc_props_type.dart';
|
|||||||
|
|
||||||
///坐骑
|
///坐骑
|
||||||
class StoreMountainsPage extends SCPageList {
|
class StoreMountainsPage extends SCPageList {
|
||||||
StoreMountainsPage();
|
const StoreMountainsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_StoreMountainsPageState createState() => _StoreMountainsPageState();
|
SCPageListState createState() => _StoreMountainsPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StoreMountainsPageState
|
class _StoreMountainsPageState
|
||||||
@ -39,16 +36,11 @@ class _StoreMountainsPageState
|
|||||||
crossAxisCount: gridViewCount,
|
crossAxisCount: gridViewCount,
|
||||||
mainAxisSpacing: 12.w,
|
mainAxisSpacing: 12.w,
|
||||||
crossAxisSpacing: 12.w,
|
crossAxisSpacing: 12.w,
|
||||||
childAspectRatio: 0.78,
|
childAspectRatio: 0.88,
|
||||||
);
|
);
|
||||||
loadData(1);
|
loadData(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -62,100 +54,12 @@ class _StoreMountainsPageState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildItem(StoreListResBean res) {
|
Widget buildItem(StoreListResBean res) {
|
||||||
return GestureDetector(
|
return SCStoreGridItemCard(
|
||||||
child: Container(
|
res: res.res,
|
||||||
decoration: BoxDecoration(
|
selected: res.isSelecte,
|
||||||
color:
|
discount: disCount,
|
||||||
res.isSelecte
|
onPreviewTap: () => _togglePreview(res),
|
||||||
? const Color(0xff18F2B1).withValues(alpha: 0.1)
|
onDetailsTap: () => _showDetail(res.res),
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemBackgroundColor(),
|
|
||||||
border: Border.all(
|
|
||||||
color:
|
|
||||||
res.isSelecte
|
|
||||||
? SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemSelectedBorderColor()
|
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemUnselectedBorderColor(),
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
netImage(
|
|
||||||
url: res.res.propsResources?.cover ?? "",
|
|
||||||
width: 55.w,
|
|
||||||
height: 55.w,
|
|
||||||
),
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: Image.asset(
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemGoldIcon(),
|
|
||||||
width: 22.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: " "),
|
|
||||||
disCount < 1
|
|
||||||
? TextSpan(
|
|
||||||
text: "${res.res.propsPrices![0].amount}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: TextSpan(),
|
|
||||||
disCount < 1 ? TextSpan(text: " ") : TextSpan(),
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"${((res.res.propsPrices![0].amount ?? 0) * disCount).toInt()}/${res.res.propsPrices![0].days} ${SCAppLocalizations.of(context)!.day}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
strutStyle: StrutStyle(
|
|
||||||
height: 1.3, // 行高倍数
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
forceStrutHeight: true, // 强制应用行高
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
_selectItem(res);
|
|
||||||
_showDetail(res.res);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,11 +98,12 @@ class _StoreMountainsPageState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectItem(StoreListResBean res) {
|
void _togglePreview(StoreListResBean res) {
|
||||||
|
final shouldSelect = !res.isSelecte;
|
||||||
for (var value in items) {
|
for (var value in items) {
|
||||||
value.isSelecte = false;
|
value.isSelecte = false;
|
||||||
}
|
}
|
||||||
res.isSelecte = true;
|
res.isSelecte = shouldSelect;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'package:yumi/app_localizations.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
|
||||||
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
import 'package:yumi/ui_kit/components/sc_page_list.dart';
|
||||||
import 'package:yumi/ui_kit/components/sc_tts.dart';
|
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
||||||
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_store_repository_imp.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
||||||
import 'package:yumi/services/auth/user_profile_manager.dart';
|
|
||||||
import 'package:yumi/ui_kit/widgets/store/props_store_theme_detail_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/store/props_store_theme_detail_dialog.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
import 'package:yumi/ui_kit/widgets/store/store_bag_page_helpers.dart';
|
||||||
import 'package:yumi/modules/store/headdress/store_headdress_page.dart';
|
import 'package:yumi/modules/store/headdress/store_headdress_page.dart';
|
||||||
@ -20,10 +14,10 @@ import '../../../shared/data_sources/models/enum/sc_props_type.dart';
|
|||||||
|
|
||||||
///房间主题
|
///房间主题
|
||||||
class StoreThemePage extends SCPageList {
|
class StoreThemePage extends SCPageList {
|
||||||
StoreThemePage();
|
const StoreThemePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_StoreThemePagePageState createState() => _StoreThemePagePageState();
|
SCPageListState createState() => _StoreThemePagePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StoreThemePagePageState
|
class _StoreThemePagePageState
|
||||||
@ -43,7 +37,7 @@ class _StoreThemePagePageState
|
|||||||
crossAxisCount: gridViewCount,
|
crossAxisCount: gridViewCount,
|
||||||
mainAxisSpacing: 12.w,
|
mainAxisSpacing: 12.w,
|
||||||
crossAxisSpacing: 12.w,
|
crossAxisSpacing: 12.w,
|
||||||
childAspectRatio: 0.78,
|
childAspectRatio: 0.88,
|
||||||
);
|
);
|
||||||
loadData(1);
|
loadData(1);
|
||||||
}
|
}
|
||||||
@ -61,101 +55,13 @@ class _StoreThemePagePageState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildItem(StoreListResBean res) {
|
Widget buildItem(StoreListResBean res) {
|
||||||
return GestureDetector(
|
return SCStoreGridItemCard(
|
||||||
child: Container(
|
res: res.res,
|
||||||
decoration: BoxDecoration(
|
selected: res.isSelecte,
|
||||||
color:
|
discount: disCount,
|
||||||
res.isSelecte
|
coverBorderRadius: BorderRadius.all(Radius.circular(8.w)),
|
||||||
? const Color(0xff18F2B1).withValues(alpha: 0.1)
|
onPreviewTap: () => _togglePreview(res),
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
onDetailsTap: () => _showDetail(res.res),
|
||||||
.getStoreItemBackgroundColor(),
|
|
||||||
border: Border.all(
|
|
||||||
color:
|
|
||||||
res.isSelecte
|
|
||||||
? SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemSelectedBorderColor()
|
|
||||||
: SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemUnselectedBorderColor(),
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
netImage(
|
|
||||||
url: res.res.propsResources?.cover ?? "",
|
|
||||||
width: 55.w,
|
|
||||||
height: 55.w,
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
||||||
),
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: Image.asset(
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemGoldIcon(),
|
|
||||||
width: 22.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: " "),
|
|
||||||
disCount < 1
|
|
||||||
? TextSpan(
|
|
||||||
text: "${res.res.propsPrices![0].amount}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: TextSpan(),
|
|
||||||
disCount < 1 ? TextSpan(text: " ") : TextSpan(),
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"${((res.res.propsPrices![0].amount ?? 0) * disCount).toInt()}/${res.res.propsPrices![0].days} ${SCAppLocalizations.of(context)!.day}",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
color:
|
|
||||||
SCGlobalConfig.businessLogicStrategy
|
|
||||||
.getStoreItemPriceTextColor(),
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
strutStyle: StrutStyle(
|
|
||||||
height: 1.3, // 行高倍数
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
forceStrutHeight: true, // 强制应用行高
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
_selectItem(res);
|
|
||||||
_showDetail(res.res);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,34 +100,12 @@ class _StoreThemePagePageState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectItem(StoreListResBean res) {
|
void _togglePreview(StoreListResBean res) {
|
||||||
|
final shouldSelect = !res.isSelecte;
|
||||||
for (var value in items) {
|
for (var value in items) {
|
||||||
value.isSelecte = false;
|
value.isSelecte = false;
|
||||||
}
|
}
|
||||||
res.isSelecte = true;
|
res.isSelecte = shouldSelect;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _buy(StoreListResBean res) {
|
|
||||||
num days = 0;
|
|
||||||
if (res.res.propsPrices!.length > 1) {
|
|
||||||
days = res.res.propsPrices![1].days ?? 0;
|
|
||||||
} else {
|
|
||||||
days = res.res.propsPrices![0].days ?? 0;
|
|
||||||
}
|
|
||||||
SCStoreRepositoryImp()
|
|
||||||
.storePurchasing(
|
|
||||||
res.res.id ?? "",
|
|
||||||
SCPropsType.THEME.name,
|
|
||||||
SCCurrencyType.GOLD.name,
|
|
||||||
"$days",
|
|
||||||
)
|
|
||||||
.then((value) {
|
|
||||||
SCTts.show(SCAppLocalizations.of(context)!.purchaseIsSuccessful);
|
|
||||||
Provider.of<SocialChatUserProfileManager>(
|
|
||||||
context,
|
|
||||||
listen: false,
|
|
||||||
).updateBalance(value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:yumi/app/constants/sc_global_config.dart';
|
||||||
|
import 'package:yumi/app_localizations.dart';
|
||||||
|
import 'package:yumi/shared/business_logic/models/res/store_list_res.dart';
|
||||||
|
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
|
||||||
|
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
||||||
import 'package:yumi/ui_kit/components/text/sc_text.dart';
|
import 'package:yumi/ui_kit/components/text/sc_text.dart';
|
||||||
|
import 'package:yumi/ui_kit/widgets/props/sc_data_card_resource_view.dart';
|
||||||
|
|
||||||
const Duration _kStoreBagSkeletonAnimationDuration = Duration(
|
const Duration _kStoreBagSkeletonAnimationDuration = Duration(
|
||||||
milliseconds: 1450,
|
milliseconds: 1450,
|
||||||
@ -11,6 +17,8 @@ const Color _kStoreBagSkeletonBoneBase = Color(0xFF2B5C53);
|
|||||||
const Color _kStoreBagSkeletonBoneHighlight = Color(0xFF5F8177);
|
const Color _kStoreBagSkeletonBoneHighlight = Color(0xFF5F8177);
|
||||||
const Color _kStoreBagSkeletonBorder = Color(0x66D8B57B);
|
const Color _kStoreBagSkeletonBorder = Color(0x66D8B57B);
|
||||||
|
|
||||||
|
enum SCStoreItemPreviewKind { resource, avatarFrame, dataCard }
|
||||||
|
|
||||||
Widget buildStoreBagItemTitle(
|
Widget buildStoreBagItemTitle(
|
||||||
String content, {
|
String content, {
|
||||||
required double fontSize,
|
required double fontSize,
|
||||||
@ -86,7 +94,7 @@ class SCStoreGridSkeleton extends StatelessWidget {
|
|||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
mainAxisSpacing: 12.w,
|
mainAxisSpacing: 12.w,
|
||||||
crossAxisSpacing: 12.w,
|
crossAxisSpacing: 12.w,
|
||||||
childAspectRatio: 0.78,
|
childAspectRatio: 0.88,
|
||||||
),
|
),
|
||||||
itemCount: itemCount,
|
itemCount: itemCount,
|
||||||
itemBuilder: (context, index) => _buildStoreCardSkeleton(progress),
|
itemBuilder: (context, index) => _buildStoreCardSkeleton(progress),
|
||||||
@ -95,6 +103,228 @@ class SCStoreGridSkeleton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SCStoreGridItemCard extends StatelessWidget {
|
||||||
|
const SCStoreGridItemCard({
|
||||||
|
super.key,
|
||||||
|
required this.res,
|
||||||
|
required this.selected,
|
||||||
|
required this.discount,
|
||||||
|
required this.onPreviewTap,
|
||||||
|
required this.onDetailsTap,
|
||||||
|
this.previewKind = SCStoreItemPreviewKind.resource,
|
||||||
|
this.coverWidth,
|
||||||
|
this.coverHeight,
|
||||||
|
this.previewWidth,
|
||||||
|
this.previewHeight,
|
||||||
|
this.coverFit = BoxFit.contain,
|
||||||
|
this.previewFit = BoxFit.contain,
|
||||||
|
this.coverBorderRadius,
|
||||||
|
});
|
||||||
|
|
||||||
|
final StoreListRes res;
|
||||||
|
final bool selected;
|
||||||
|
final double discount;
|
||||||
|
final VoidCallback onPreviewTap;
|
||||||
|
final VoidCallback onDetailsTap;
|
||||||
|
final SCStoreItemPreviewKind previewKind;
|
||||||
|
final double? coverWidth;
|
||||||
|
final double? coverHeight;
|
||||||
|
final double? previewWidth;
|
||||||
|
final double? previewHeight;
|
||||||
|
final BoxFit coverFit;
|
||||||
|
final BoxFit previewFit;
|
||||||
|
final BorderRadius? coverBorderRadius;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final firstPrice =
|
||||||
|
(res.propsPrices?.isNotEmpty ?? false) ? res.propsPrices!.first : null;
|
||||||
|
final amount = ((firstPrice?.amount ?? 0) * discount).toInt();
|
||||||
|
final tagText = _buildDurationTag(context, firstPrice?.days);
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onDetailsTap,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
selected
|
||||||
|
? const Color(0xff18F2B1).withValues(alpha: 0.1)
|
||||||
|
: SCGlobalConfig.businessLogicStrategy
|
||||||
|
.getStoreItemBackgroundColor(),
|
||||||
|
border: Border.all(
|
||||||
|
color:
|
||||||
|
selected
|
||||||
|
? SCGlobalConfig.businessLogicStrategy
|
||||||
|
.getStoreItemSelectedBorderColor()
|
||||||
|
: SCGlobalConfig.businessLogicStrategy
|
||||||
|
.getStoreItemUnselectedBorderColor(),
|
||||||
|
width: 1.w,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
PositionedDirectional(
|
||||||
|
top: 6.w,
|
||||||
|
start: 6.w,
|
||||||
|
child: _buildDurationBadge(tagText),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(6.w, 16.w, 6.w, 8.w),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildPreviewTapArea(),
|
||||||
|
SizedBox(height: 8.w),
|
||||||
|
_buildPriceRow(amount, firstPrice),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPreviewTapArea() {
|
||||||
|
return GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: onPreviewTap,
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height:
|
||||||
|
previewHeight ??
|
||||||
|
coverHeight ??
|
||||||
|
(previewKind == SCStoreItemPreviewKind.avatarFrame ? 64.w : 62.w),
|
||||||
|
child: Center(child: selected ? _buildPreview() : _buildCover()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCover() {
|
||||||
|
Widget child = netImage(
|
||||||
|
url: res.propsResources?.cover ?? "",
|
||||||
|
width: coverWidth ?? 58.w,
|
||||||
|
height: coverHeight ?? 58.w,
|
||||||
|
fit: coverFit,
|
||||||
|
);
|
||||||
|
if (coverBorderRadius != null) {
|
||||||
|
child = ClipRRect(borderRadius: coverBorderRadius!, child: child);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPreview() {
|
||||||
|
switch (previewKind) {
|
||||||
|
case SCStoreItemPreviewKind.avatarFrame:
|
||||||
|
return head(
|
||||||
|
url: AccountStorage().getCurrentUser()?.userProfile?.userAvatar ?? "",
|
||||||
|
width: previewWidth ?? 64.w,
|
||||||
|
height: previewHeight ?? 64.w,
|
||||||
|
headdress: res.propsResources?.sourceUrl,
|
||||||
|
headdressCover: res.propsResources?.cover,
|
||||||
|
);
|
||||||
|
case SCStoreItemPreviewKind.dataCard:
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(6.w),
|
||||||
|
child: SizedBox(
|
||||||
|
width: previewWidth ?? 88.w,
|
||||||
|
height: previewHeight ?? 58.w,
|
||||||
|
child: SCDataCardResourceView(
|
||||||
|
resource: res.propsResources,
|
||||||
|
fit: previewFit,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case SCStoreItemPreviewKind.resource:
|
||||||
|
return SizedBox(
|
||||||
|
width: previewWidth ?? 72.w,
|
||||||
|
height: previewHeight ?? 62.w,
|
||||||
|
child: SCDataCardResourceView(
|
||||||
|
resource: res.propsResources,
|
||||||
|
fit: previewFit,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPriceRow(int amount, PropsPrices? firstPrice) {
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 22.w,
|
||||||
|
child: FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
SCGlobalConfig.businessLogicStrategy.getStoreItemGoldIcon(),
|
||||||
|
width: 18.w,
|
||||||
|
height: 18.w,
|
||||||
|
),
|
||||||
|
SizedBox(width: 4.w),
|
||||||
|
if (discount < 1) ...[
|
||||||
|
text(
|
||||||
|
"${firstPrice?.amount ?? 0}",
|
||||||
|
fontSize: 12.sp,
|
||||||
|
textColor:
|
||||||
|
SCGlobalConfig.businessLogicStrategy
|
||||||
|
.getStoreItemPriceTextColor(),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
SizedBox(width: 4.w),
|
||||||
|
],
|
||||||
|
text(
|
||||||
|
"$amount",
|
||||||
|
fontSize: 13.sp,
|
||||||
|
textColor:
|
||||||
|
SCGlobalConfig.businessLogicStrategy
|
||||||
|
.getStoreItemPriceTextColor(),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDurationBadge(String tagText) {
|
||||||
|
if (tagText.isEmpty) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: 58.w),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xff18F2B1).withValues(alpha: 0.16),
|
||||||
|
borderRadius: BorderRadius.circular(4.w),
|
||||||
|
border: Border.all(
|
||||||
|
color: const Color(0xff18F2B1).withValues(alpha: 0.28),
|
||||||
|
width: 0.5.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: text(
|
||||||
|
tagText,
|
||||||
|
fontSize: 9.sp,
|
||||||
|
textColor:
|
||||||
|
SCGlobalConfig.businessLogicStrategy.getStoreItemPriceTextColor(),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _buildDurationTag(BuildContext context, num? days) {
|
||||||
|
if (days == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
final normalizedDays = days % 1 == 0 ? days.toInt().toString() : "$days";
|
||||||
|
return "$normalizedDays ${SCAppLocalizations.of(context)!.day}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SCBagGridSkeleton extends StatelessWidget {
|
class SCBagGridSkeleton extends StatelessWidget {
|
||||||
const SCBagGridSkeleton({
|
const SCBagGridSkeleton({
|
||||||
super.key,
|
super.key,
|
||||||
@ -130,9 +360,18 @@ Widget _buildStoreCardSkeleton(double progress) {
|
|||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: _buildStoreBagShellDecoration(radius: 8.w),
|
decoration: _buildStoreBagShellDecoration(radius: 8.w),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.w),
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 8.w),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: _buildStoreBagSkeletonBone(
|
||||||
|
progress,
|
||||||
|
width: 42.w,
|
||||||
|
height: 14.w,
|
||||||
|
borderRadius: BorderRadius.circular(4.w),
|
||||||
|
),
|
||||||
|
),
|
||||||
SizedBox(height: 2.w),
|
SizedBox(height: 2.w),
|
||||||
_buildStoreBagSkeletonBone(
|
_buildStoreBagSkeletonBone(
|
||||||
progress,
|
progress,
|
||||||
@ -140,14 +379,7 @@ Widget _buildStoreCardSkeleton(double progress) {
|
|||||||
height: 55.w,
|
height: 55.w,
|
||||||
borderRadius: BorderRadius.circular(12.w),
|
borderRadius: BorderRadius.circular(12.w),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10.w),
|
SizedBox(height: 8.w),
|
||||||
_buildStoreBagSkeletonBone(
|
|
||||||
progress,
|
|
||||||
width: double.infinity,
|
|
||||||
height: 12.w,
|
|
||||||
borderRadius: BorderRadius.circular(999.w),
|
|
||||||
),
|
|
||||||
SizedBox(height: 10.w),
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -166,13 +398,6 @@ Widget _buildStoreCardSkeleton(double progress) {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 6.w),
|
|
||||||
_buildStoreBagSkeletonBone(
|
|
||||||
progress,
|
|
||||||
width: 48.w,
|
|
||||||
height: 11.w,
|
|
||||||
borderRadius: BorderRadius.circular(999.w),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user