王子贤 4 months ago
parent
commit
4de6be7bef
12 changed files with 680 additions and 133 deletions
  1. 2
      lib/components/page_appbar.dart
  2. 9
      lib/controller/mine/league_controller.dart
  3. 84
      lib/controller/setting/spread_controller.dart
  4. 7
      lib/model/mine/rose_data.dart
  5. 2
      lib/network/api_urls.dart
  6. 3
      lib/network/user_api.dart
  7. 38
      lib/network/user_api.g.dart
  8. 26
      lib/pages/discover/live_room_page.dart
  9. 2
      lib/pages/setting/match_league_page.dart
  10. 197
      lib/pages/setting/match_spread_page.dart
  11. 354
      lib/widget/live/live_gift_popup.dart
  12. 89
      lib/widget/live/live_room_gift_item.dart

2
lib/components/page_appbar.dart

@ -21,7 +21,7 @@ class PageAppbar extends StatelessWidget implements PreferredSizeWidget {
title: Text( title: Text(
title, title,
style: TextStyle( style: TextStyle(
fontSize: 16,
fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: const Color.fromRGBO(51, 51, 51, 1) color: const Color.fromRGBO(51, 51, 51, 1)
), ),

9
lib/controller/mine/league_controller.dart

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import '../../network/user_api.dart'; import '../../network/user_api.dart';
import '../../pages/setting/match_spread_page.dart';
import '../global.dart'; import '../global.dart';
class LeagueController extends GetxController { class LeagueController extends GetxController {
@ -74,12 +75,13 @@ class LeagueController extends GetxController {
}); });
} }
Future<void> changePhone() async {
Future<void> submitInfo() async {
if(isSendingCode.value){ if(isSendingCode.value){
return; return;
} }
if (phoneNumber.value.isEmpty) { if (phoneNumber.value.isEmpty) {
SmartDialog.showToast('请输入手机号'); SmartDialog.showToast('请输入手机号');
Get.off(() => MatchSpreadPage());
return; return;
} }
if (verificationCode.value.isEmpty) { if (verificationCode.value.isEmpty) {
@ -94,9 +96,8 @@ class LeagueController extends GetxController {
final response = await _userApi.updatePhone(param); final response = await _userApi.updatePhone(param);
// //
if (response.data.isSuccess) { if (response.data.isSuccess) {
GlobalData().userData!.phone = phoneNumber.value;
SmartDialog.showToast('更换成功');
Get.back(result: 1);
SmartDialog.showToast('提交成功');
Get.off(() => MatchSpreadPage());
} else { } else {
SmartDialog.showToast(response.data.message); SmartDialog.showToast(response.data.message);
} }

84
lib/controller/setting/spread_controller.dart

@ -0,0 +1,84 @@
import 'package:dating_touchme_app/model/mine/rose_data.dart';
import 'package:dating_touchme_app/network/user_api.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
class SpreadController extends GetxController {
// UserApi实例
late UserApi _userApi;
final roseList = <RoseData>[].obs;
final roseNum = 0.obs;
final payChecked = true.obs;
final activePay = 0.obs;
final Fluwx fluwx = Fluwx();
changePayActive(int index){
activePay.value = index;
}
List<Map> list2 = [
{'title': '邀请注册', 'unit': '10%', 'desc': '分佣', 'enable': 1, 'value': 111, 'icon': 'icon-right1'},
{'title': '发布悬赏', 'unit': '10%', 'desc': '分佣', 'enable': 1, 'value': 112, 'icon': 'icon-right2'},
{'title': '匹配悬赏', 'unit': '10%', 'desc': '分佣', 'enable': 0, 'value': 113, 'icon': 'icon-right41'},
{'title': '推荐红娘', 'unit': '10%', 'desc': '分佣', 'enable': 1, 'value': 114, 'icon': 'icon-right3'},
{'title': '免费升级', 'desc': '门店合伙人', 'enable': 0, 'value': 0, 'icon': 'icon-right51'},
{'title': '资源共享', 'desc': '所有资料', 'enable': 1, 'value': 0, 'icon': 'icon-right6'},
{'title': '业绩奖励', 'unit': '5%', 'desc': '奖励', 'enable': 1, 'value': 0, 'icon': 'icon-right71'},
{'title': '次年续签', 'unit': '90%', 'desc': '减免', 'enable': 1, 'value': 0, 'icon': 'icon-right8'}
].obs;
@override
void onInit() {
super.onInit();
_userApi = Get.find<UserApi>();
getRoseList();
}
getRoseList() async {
try{
final response = await _userApi.getMatchmakerFee();
if (response.data.isSuccess && response.data.data != null) {
final data = response.data.data!.records;
roseList.addAll(data.toList());
}
print('rose>>>${roseList.length}');
} catch (e) {
print('玫瑰列表获取失败: $e');
rethrow;
}
}
submitOrder() async {
try {
final response = await _userApi.submitOrder({
"productSpecId": roseList[activePay.value].productSpecId
});
if (response.data.isSuccess && response.data.data != null) {
final data = response.data.data;
fluwx.open(target: MiniProgram(
username: 'gh_9ea8d46add6f',
path:"pages/index/index?amount=${roseList[activePay.value].unitSellingPrice}&paymentOrderId=${data!.paymentOrderId}&url=match-fee"
));
SmartDialog.showToast('开始支付');
} else {
//
throw Exception(response.data.message ?? '获取数据失败');
}
} catch (e) {
print('玫瑰列表获取失败: $e');
SmartDialog.showToast('下单失败');
rethrow;
}
}
}

7
lib/model/mine/rose_data.dart

@ -9,6 +9,7 @@ class RoseData {
num? unitOriginalPrice; num? unitOriginalPrice;
num? unitSellingPrice; num? unitSellingPrice;
String? purchaseTimeValue; String? purchaseTimeValue;
String? validityPeriodDays;
RoseData( RoseData(
{this.productId, {this.productId,
@ -20,7 +21,9 @@ class RoseData {
this.detailDesc, this.detailDesc,
this.unitOriginalPrice, this.unitOriginalPrice,
this.unitSellingPrice, this.unitSellingPrice,
this.purchaseTimeValue});
this.purchaseTimeValue,
this.validityPeriodDays
});
RoseData.fromJson(Map<String, dynamic> json) { RoseData.fromJson(Map<String, dynamic> json) {
productId = json['productId']; productId = json['productId'];
@ -33,6 +36,7 @@ class RoseData {
unitOriginalPrice = json['unitOriginalPrice']; unitOriginalPrice = json['unitOriginalPrice'];
unitSellingPrice = json['unitSellingPrice']; unitSellingPrice = json['unitSellingPrice'];
purchaseTimeValue = json['purchaseTimeValue']; purchaseTimeValue = json['purchaseTimeValue'];
validityPeriodDays = json['validityPeriodDays'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -47,6 +51,7 @@ class RoseData {
data['unitOriginalPrice'] = this.unitOriginalPrice; data['unitOriginalPrice'] = this.unitOriginalPrice;
data['unitSellingPrice'] = this.unitSellingPrice; data['unitSellingPrice'] = this.unitSellingPrice;
data['purchaseTimeValue'] = this.purchaseTimeValue; data['purchaseTimeValue'] = this.purchaseTimeValue;
data['validityPeriodDays'] = this.validityPeriodDays;
return data; return data;
} }
} }

2
lib/network/api_urls.dart

@ -86,4 +86,6 @@ class ApiUrls {
'dating-agency-service/user/page/dongwo/marriage-information'; 'dating-agency-service/user/page/dongwo/marriage-information';
// API端点 // API端点
static const String listMatchmakerProduct =
'dating-agency-mall/user/page/product/by/matchmaker';
} }

3
lib/network/user_api.dart

@ -185,4 +185,7 @@ abstract class UserApi {
@Query('miId') required String miId, @Query('miId') required String miId,
} }
); );
@GET(ApiUrls.listMatchmakerProduct)
Future<HttpResponse<BaseResponse<PaginatedResponse<RoseData>>>> getMatchmakerFee();
} }

38
lib/network/user_api.g.dart

@ -1129,6 +1129,44 @@ class _UserApi implements UserApi {
return httpResponse; return httpResponse;
} }
@override
Future<HttpResponse<BaseResponse<PaginatedResponse<RoseData>>>>
getMatchmakerFee() async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options =
_setStreamType<HttpResponse<BaseResponse<PaginatedResponse<RoseData>>>>(
Options(method: 'GET', headers: _headers, extra: _extra)
.compose(
_dio.options,
'dating-agency-mall/user/page/product/by/matchmaker',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl),
),
);
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late BaseResponse<PaginatedResponse<RoseData>> _value;
try {
_value = BaseResponse<PaginatedResponse<RoseData>>.fromJson(
_result.data!,
(json) => PaginatedResponse<RoseData>.fromJson(
json as Map<String, dynamic>,
(json) => RoseData.fromJson(json as Map<String, dynamic>),
),
);
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
final httpResponse = HttpResponse(_value, _result);
return httpResponse;
}
RequestOptions _setStreamType<T>(RequestOptions requestOptions) { RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
if (T != dynamic && if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes || !(requestOptions.responseType == ResponseType.bytes ||

26
lib/pages/discover/live_room_page.dart

@ -30,14 +30,6 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
final activeGift = ValueNotifier<int?>(null); final activeGift = ValueNotifier<int?>(null);
List<Map> giftList = [
{"icon": Assets.imagesGift1, "title": "爱心礼物", "price": 30},
{"icon": Assets.imagesGift2, "title": "小小小星星", "price": 30},
{"icon": Assets.imagesGift3, "title": "助威", "price": 30},
{"icon": Assets.imagesGift4, "title": "点赞", "price": 30},
{"icon": Assets.imagesGift5, "title": "崇拜衣柜", "price": 30},
];
final giftNum = ValueNotifier<int>(1); final giftNum = ValueNotifier<int>(1);
final activePay = ValueNotifier<int?>(null); final activePay = ValueNotifier<int?>(null);
@ -99,12 +91,18 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
SmartDialog.show( SmartDialog.show(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
maskColor: TDTheme.of(context).fontGyColor2, maskColor: TDTheme.of(context).fontGyColor2,
builder: (_) => LiveGiftPopup(
activeGift: activeGift,
giftNum: giftNum,
giftList: giftList,
changeActive: changeActive,
),
builder: (_) => Obx(() {
// 使 API giftProducts使
final giftProducts = _roomController.giftProducts;
final giftList = giftProducts.toList();
return LiveGiftPopup(
activeGift: activeGift,
giftNum: giftNum,
giftList: giftList,
changeActive: changeActive,
);
}),
); );
} }

2
lib/pages/setting/match_league_page.dart

@ -107,7 +107,7 @@ class MatchLeaguePage extends StatelessWidget {
backgroundColor: Color(0xC37562F9), backgroundColor: Color(0xC37562F9),
), ),
onTap: (){ onTap: (){
// controller.startAuthing();
controller.submitInfo();
}, },
), ),
], ],

197
lib/pages/setting/match_spread_page.dart

@ -0,0 +1,197 @@
import 'package:dating_touchme_app/components/page_appbar.dart';
import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:dating_touchme_app/model/mine/rose_data.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import '../../controller/setting/spread_controller.dart';
class MatchSpreadPage extends StatelessWidget {
const MatchSpreadPage({super.key});
@override
Widget build(BuildContext context) {
return GetX<SpreadController>(
init: SpreadController(),
builder: (controller){
return Scaffold(
appBar: PageAppbar(title: "入驻加盟"),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.w, horizontal: 12.w),
child: Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
...controller.roseList.asMap().entries.map((entry){
return PayItem(item: entry.value, active: controller.activePay.value, index: entry.key, changeActive: controller.changePayActive);
}),
],
),
),
SizedBox(height: 32.w),
Row(
children: [
Text('红娘权益', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
],
),
SizedBox(height: 24.w,),
Wrap(
spacing: 10.w,
runSpacing: 18.w,
children: [
...controller.list2.map((e){
return SizedBox(
width: 80.w,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(TDIcons.help_circle, color: Colors.orange, size: 36),
SizedBox(height: 8.w,),
Text(e['title'], style: TextStyle(fontSize: 14, color: Color(0xFF999999))),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if(e['unit'] != null)Text(e['unit'], style: TextStyle(fontSize: 14)),
Text(e['desc'], style: TextStyle(fontSize: 14, color: Color(0xFF999999))),
],
)
],
),
);
}),
],
),
],
),
),
),
bottomNavigationBar: SafeArea(
child: Container(
height: 60,
padding: EdgeInsets.symmetric(vertical: 5.w, horizontal: 16.w),
child: TDButton(
text: '立即加入',
width: MediaQuery.of(context).size.width - 40,
size: TDButtonSize.large,
type: TDButtonType.fill,
shape: TDButtonShape.round,
style: TDButtonStyle(
textColor: Colors.white,
backgroundColor: Color(0xFFEE811B),
),
activeStyle: TDButtonStyle(
textColor: Colors.white,
backgroundColor: Color(0xC3EE811B),
),
onTap: (){
controller.submitOrder();
},
),
)
),
);
},
);
}
}
class PayItem extends StatefulWidget {
final RoseData item;
final int active;
final int index;
final void Function(int) changeActive;
const PayItem({super.key, required this.item, required this.active, required this.index, required this.changeActive, });
@override
State<PayItem> createState() => _PayItemState();
}
class _PayItemState extends State<PayItem> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
width: 124.w,
height: 160.h,
margin: const EdgeInsets.only(right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: widget.active == widget.index ? const Color.fromRGBO(239, 19, 46, .05) : Colors.white,
border: widget.active == widget.index ? Border.all(width: 1, color: const Color(0xFFEE811B)) : Border.all(width: 1, color: const Color(0xFFEEEEEE))
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 32),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
padding: EdgeInsets.only(bottom: 5),
child: Text(
"¥",
style: TextStyle(
fontSize: 16.w,
color: Color(0xFFEE811B),
fontWeight: FontWeight.bold
),
),
),
const SizedBox(width: 2),
Text(
"${widget.item.unitSellingPrice}",
style: TextStyle(
fontSize: 26.w,
color: Color(0xFFEE811B),
fontWeight: FontWeight.bold
),
),
],
),
TDText("${widget.item.unitOriginalPrice}", isTextThrough: true, style: TextStyle(color: Color(0xFFCCCCCC)),),
const SizedBox(height: 18),
Text(
"有效期:${widget.item.validityPeriodDays}",
style: TextStyle(
fontSize: 14.w,
color: Color(0xFF333333),
fontWeight: FontWeight.bold
),
),
],
),
),
Positioned(
left: 0,
top: 0,
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.w, horizontal: 6.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(6.w),
bottomRight: Radius.circular(6.w),
),
color: widget.active == widget.index ? const Color(0xFFEE811B) : Color(0xFFCCCCCC)
),
child: Center(
child: Text(widget.item.productTitle!.replaceAll('加盟费', ''), style: TextStyle(fontSize: 12, color: Colors.white)),
),
),
)
],
).onTap((){
widget.changeActive(widget.index);
});
}
}

354
lib/widget/live/live_gift_popup.dart

@ -1,11 +1,16 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:dating_touchme_app/controller/discover/room_controller.dart';
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/generated/assets.dart'; import 'package:dating_touchme_app/generated/assets.dart';
import 'package:dating_touchme_app/model/rtc/rtc_channel_detail.dart';
import 'package:dating_touchme_app/widget/live/live_room_gift_item.dart'; import 'package:dating_touchme_app/widget/live/live_room_gift_item.dart';
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_swiper_null_safety/flutter_swiper_null_safety.dart'; import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart';
class LiveGiftPopup extends StatelessWidget {
class LiveGiftPopup extends StatefulWidget {
const LiveGiftPopup({ const LiveGiftPopup({
super.key, super.key,
required this.activeGift, required this.activeGift,
@ -16,9 +21,44 @@ class LiveGiftPopup extends StatelessWidget {
final ValueNotifier<int?> activeGift; final ValueNotifier<int?> activeGift;
final ValueNotifier<int> giftNum; final ValueNotifier<int> giftNum;
final List<Map> giftList;
final List<dynamic> giftList; // List<Map> List<GiftProductModel>
final void Function(int) changeActive; final void Function(int) changeActive;
@override
State<LiveGiftPopup> createState() => _LiveGiftPopupState();
}
class _LiveGiftPopupState extends State<LiveGiftPopup> {
// ID集合
final Set<String> _selectedUserIds = <String>{};
//
void _toggleUserSelection(String userId) {
setState(() {
if (_selectedUserIds.contains(userId)) {
_selectedUserIds.remove(userId);
} else {
_selectedUserIds.add(userId);
}
});
}
// /
void _toggleSelectAll(List<RtcSeatUserInfo> users) {
setState(() {
if (_selectedUserIds.length == users.length) {
//
_selectedUserIds.clear();
} else {
//
_selectedUserIds.clear();
for (var user in users) {
_selectedUserIds.add(user.userId);
}
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return Material(
@ -32,7 +72,9 @@ class LiveGiftPopup extends StatelessWidget {
Expanded( Expanded(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)),
borderRadius: BorderRadius.vertical(
top: Radius.circular(9.w),
),
color: const Color.fromRGBO(22, 19, 28, 1), color: const Color.fromRGBO(22, 19, 28, 1),
), ),
child: Column( child: Column(
@ -51,88 +93,166 @@ class LiveGiftPopup extends StatelessWidget {
} }
Widget _buildHeader() { Widget _buildHeader() {
return Container(
height: 53.w,
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: Row(
children: [
Row(
children: [
Text(
"送给: ",
style: TextStyle(fontSize: 13.w, color: Colors.white),
),
SizedBox(width: 6.w),
...List.generate(3, (index) {
return Padding(
padding: EdgeInsets.only(right: 10.w),
child: Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(index == 0 ? 68.w : 34.w),
),
child: Container(
width: 34.w,
height: 34.w,
decoration: BoxDecoration(
return Obx(() {
// RoomController
final roomController = Get.isRegistered<RoomController>()
? Get.find<RoomController>()
: null;
// rtcChannelDetail
final rtcChannelDetail = roomController?.rtcChannelDetail.value;
// ID
final currentUserId = GlobalData().userId ?? GlobalData().userData?.id;
// anchorInfo, maleInfo, femaleInfo
final List<RtcSeatUserInfo> userList = [];
if (rtcChannelDetail?.anchorInfo != null) {
userList.add(rtcChannelDetail!.anchorInfo!);
}
if (rtcChannelDetail?.maleInfo != null) {
userList.add(rtcChannelDetail!.maleInfo!);
}
if (rtcChannelDetail?.femaleInfo != null) {
userList.add(rtcChannelDetail!.femaleInfo!);
}
//
final filteredUserList = userList.where((user) {
// userId miId
return user.userId != currentUserId && user.miId != currentUserId;
}).toList();
// 3
final displayUsers = filteredUserList.take(3).toList();
return Container(
height: 53.w,
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: Row(
children: [
Row(
children: [
Text(
"送给: ",
style: TextStyle(fontSize: 13.w, color: Colors.white),
),
SizedBox(width: 6.w),
...displayUsers.asMap().entries.map((entry) {
final index = entry.key;
final user = entry.value;
final isSelected = _selectedUserIds.contains(user.userId);
return GestureDetector(
onTap: () => _toggleUserSelection(user.userId),
child: Padding(
padding: EdgeInsets.only(right: 10.w),
child: Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(index == 0 ? 68.w : 34.w), Radius.circular(index == 0 ? 68.w : 34.w),
), ),
border: Border.all(
width: index == 0 ? 2 : 1,
color: const Color.fromRGBO(117, 98, 249, 1),
child: Container(
width: 34.w,
height: 34.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(index == 0 ? 68.w : 34.w),
),
border: Border.all(
width: index == 0 ? 2 : 1,
color: const Color.fromRGBO(117, 98, 249, 1),
),
),
child: user.profilePhoto.isNotEmpty
? CachedNetworkImage(
imageUrl: user.profilePhoto,
width: 34.w,
height: 34.w,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
width: 34.w,
height: 34.w,
color: Colors.grey[300],
child: Center(
child: SizedBox(
width: 16.w,
height: 16.w,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.grey[600],
),
),
),
),
errorWidget: (context, url, error) =>
Image.asset(
Assets.imagesUserAvatar,
width: 32.w,
height: 32.w,
),
)
: Image.asset(
Assets.imagesUserAvatar,
width: 32.w,
height: 32.w,
),
), ),
), ),
child: Image.asset(
Assets.imagesUserAvatar,
width: 32.w,
height: 32.w,
),
),
),
Positioned(
bottom: 0,
right: 2.w,
child: Container(
width: 12.w,
height: 12.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12.w)),
color: const Color.fromRGBO(117, 98, 249, 1),
),
child: Center(
child: Image.asset(
Assets.imagesCheck,
width: 6.w,
height: 4.w,
if (isSelected)
Positioned(
bottom: 0,
right: 2.w,
child: Container(
width: 12.w,
height: 12.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(12.w),
),
color: const Color.fromRGBO(117, 98, 249, 1),
),
child: Center(
child: Image.asset(
Assets.imagesCheck,
width: 6.w,
height: 4.w,
),
),
),
), ),
),
),
],
), ),
],
),
);
}),
],
),
Container(
width: 63.w,
height: 30.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.w)),
color: const Color.fromRGBO(117, 98, 249, 1),
),
);
}),
],
), ),
child: Center(
child: Text(
"全选",
style: TextStyle(fontSize: 13.w, color: Colors.white),
//
if (displayUsers.isNotEmpty)
GestureDetector(
onTap: () => _toggleSelectAll(displayUsers),
child: Container(
width: 63.w,
height: 30.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.w)),
color: const Color.fromRGBO(117, 98, 249, 1),
),
child: Center(
child: Text(
_selectedUserIds.length == displayUsers.length
? "取消全选"
: "全选",
style: TextStyle(fontSize: 13.w, color: Colors.white),
),
),
),
), ),
),
),
],
),
);
],
),
);
});
} }
Widget _buildTab() { Widget _buildTab() {
@ -163,34 +283,61 @@ class LiveGiftPopup extends StatelessWidget {
} }
Widget _buildGiftSwiper() { Widget _buildGiftSwiper() {
if (widget.giftList.isEmpty) {
return Expanded(
child: Center(
child: Text(
'暂无礼物',
style: TextStyle(fontSize: 14.w, color: Colors.white70),
),
),
);
}
// 824
final itemsPerPage = 8;
final totalPages = (widget.giftList.length / itemsPerPage).ceil();
return Expanded( return Expanded(
child: ValueListenableBuilder<int?>( child: ValueListenableBuilder<int?>(
valueListenable: activeGift,
valueListenable: widget.activeGift,
builder: (context, active, _) { builder: (context, active, _) {
return Swiper( return Swiper(
autoplay: false, autoplay: false,
itemCount: 6,
loop: true,
pagination: const SwiperPagination(
alignment: Alignment.bottomCenter,
builder: TDSwiperDotsPagination(
color: Color.fromRGBO(144, 144, 144, 1),
activeColor: Color.fromRGBO(77, 77, 77, 1),
),
),
itemBuilder: (context, index) {
itemCount: totalPages,
loop: false,
pagination: totalPages > 1
? const SwiperPagination(
alignment: Alignment.bottomCenter,
builder: TDSwiperDotsPagination(
color: Color.fromRGBO(144, 144, 144, 1),
activeColor: Color.fromRGBO(77, 77, 77, 1),
),
)
: null,
itemBuilder: (context, pageIndex) {
final startIndex = pageIndex * itemsPerPage;
final endIndex = (startIndex + itemsPerPage).clamp(
0,
widget.giftList.length,
);
final pageItems = widget.giftList.sublist(startIndex, endIndex);
return Align( return Align(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: Wrap( child: Wrap(
spacing: 7.w,
runSpacing: 7.w,
children: [ children: [
...giftList.asMap().entries.map(
(entry) => LiveRoomGiftItem(
...pageItems.asMap().entries.map((entry) {
final globalIndex = startIndex + entry.key;
return LiveRoomGiftItem(
item: entry.value, item: entry.value,
active: active ?? 0, active: active ?? 0,
index: entry.key,
changeActive: changeActive,
),
),
index: globalIndex,
changeActive: widget.changeActive,
);
}),
], ],
), ),
); );
@ -209,26 +356,18 @@ class LiveGiftPopup extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
Image.asset(
Assets.imagesRoseGift,
width: 21.w,
height: 21.w,
),
Image.asset(Assets.imagesRoseGift, width: 21.w, height: 21.w),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Text( Text(
"9", "9",
style: TextStyle(fontSize: 13.w, color: Colors.white), style: TextStyle(fontSize: 13.w, color: Colors.white),
), ),
SizedBox(width: 12.w), SizedBox(width: 12.w),
Image.asset(
Assets.imagesRoseGift,
width: 68.w,
height: 33.w,
),
Image.asset(Assets.imagesRoseGift, width: 68.w, height: 33.w),
], ],
), ),
ValueListenableBuilder<int>( ValueListenableBuilder<int>(
valueListenable: giftNum,
valueListenable: widget.giftNum,
builder: (context, num, _) { builder: (context, num, _) {
return Row( return Row(
children: [ children: [
@ -236,8 +375,8 @@ class LiveGiftPopup extends StatelessWidget {
label: "-", label: "-",
enabled: num > 1, enabled: num > 1,
onTap: () { onTap: () {
if (giftNum.value <= 1) return;
giftNum.value -= 1;
if (widget.giftNum.value <= 1) return;
widget.giftNum.value -= 1;
}, },
), ),
SizedBox( SizedBox(
@ -253,7 +392,7 @@ class LiveGiftPopup extends StatelessWidget {
label: "+", label: "+",
enabled: true, enabled: true,
onTap: () { onTap: () {
giftNum.value += 1;
widget.giftNum.value += 1;
}, },
), ),
SizedBox(width: 9.w), SizedBox(width: 9.w),
@ -323,4 +462,3 @@ class LiveGiftPopup extends StatelessWidget {
); );
} }
} }

89
lib/widget/live/live_room_gift_item.dart

@ -1,8 +1,10 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:dating_touchme_app/model/live/gift_product_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
class LiveRoomGiftItem extends StatefulWidget { class LiveRoomGiftItem extends StatefulWidget {
final Map item;
final dynamic item; // Map GiftProductModel
final int active; final int active;
final int index; final int index;
final void Function(int) changeActive; final void Function(int) changeActive;
@ -19,6 +21,83 @@ class LiveRoomGiftItem extends StatefulWidget {
} }
class _LiveRoomGiftItemState extends State<LiveRoomGiftItem> { class _LiveRoomGiftItemState extends State<LiveRoomGiftItem> {
// GiftProductModel
bool get _isGiftProductModel => widget.item is GiftProductModel;
//
Widget _buildImage() {
if (_isGiftProductModel) {
final gift = widget.item as GiftProductModel;
if (gift.mainPic.isNotEmpty) {
return CachedNetworkImage(
imageUrl: gift.mainPic,
width: 41.w,
height: 41.w,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
width: 41.w,
height: 41.w,
color: Colors.grey[300],
child: Center(
child: SizedBox(
width: 20.w,
height: 20.w,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.grey[600],
),
),
),
),
errorWidget: (context, url, error) => Container(
width: 41.w,
height: 41.w,
color: Colors.grey[300],
child: Icon(Icons.error_outline, size: 20.w, color: Colors.grey),
),
);
} else {
return Container(
width: 41.w,
height: 41.w,
color: Colors.grey[300],
);
}
} else {
final map = widget.item as Map;
final icon = map["icon"] as String?;
if (icon != null && icon.isNotEmpty) {
return Image.asset(icon, width: 41.w, height: 41.w);
} else {
return Container(
width: 41.w,
height: 41.w,
color: Colors.grey[300],
);
}
}
}
//
String _getTitle() {
if (_isGiftProductModel) {
return (widget.item as GiftProductModel).productTitle;
} else {
return (widget.item as Map)["title"]?.toString() ?? '';
}
}
//
String _getPrice() {
if (_isGiftProductModel) {
final price = (widget.item as GiftProductModel).unitSellingPrice;
return "${price.toInt()}";
} else {
final price = (widget.item as Map)["price"];
return "${price ?? 0}";
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return InkWell(
@ -49,15 +128,17 @@ class _LiveRoomGiftItemState extends State<LiveRoomGiftItem> {
), ),
child: Column( child: Column(
children: [ children: [
Image.asset(widget.item["icon"], width: 41.w, height: 41.w),
_buildImage(),
SizedBox(height: 7.w), SizedBox(height: 7.w),
Text( Text(
widget.item["title"],
_getTitle(),
style: TextStyle(fontSize: 11.w, color: Colors.white), style: TextStyle(fontSize: 11.w, color: Colors.white),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 1.w), SizedBox(height: 1.w),
Text( Text(
"${widget.item["price"]}",
_getPrice(),
style: TextStyle( style: TextStyle(
fontSize: 7.w, fontSize: 7.w,
color: const Color.fromRGBO(144, 144, 144, 1), color: const Color.fromRGBO(144, 144, 144, 1),

Loading…
Cancel
Save