You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

518 lines
24 KiB

import 'package:dating_touchme_app/controller/discover/room_controller.dart';
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/controller/overlay_controller.dart';
import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:dating_touchme_app/model/live/live_chat_message.dart';
import 'package:dating_touchme_app/model/rtc/rtc_channel_detail.dart';
import 'package:dating_touchme_app/network/user_api.dart';
import 'package:dating_touchme_app/pages/discover/live_end_page.dart';
import 'package:dating_touchme_app/pages/discover/settlement_page.dart';
import 'package:dating_touchme_app/widget/live/disconnect_mic_dialog.dart';
import 'package:dating_touchme_app/widget/live/kick_list.dart';
import 'package:dating_touchme_app/widget/live/live_gift_popup.dart';
import 'package:dating_touchme_app/widget/live/live_room_user_profile_dialog.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
/// 直播间顶部用户信息与操作区域
class LiveRoomUserHeader extends StatelessWidget {
const LiveRoomUserHeader({
super.key,
required this.userName,
required this.popularityText,
this.avatarAsset = Assets.imagesUserAvatar,
this.fireIconAsset = Assets.imagesFireIcon,
this.closeIconAsset = Assets.imagesCloseArrow,
this.onFollowTap,
this.onCloseTap,
});
final String userName;
final String popularityText;
final String avatarAsset;
final String fireIconAsset;
final String closeIconAsset;
final VoidCallback? onFollowTap;
final VoidCallback? onCloseTap;
void _showGiftPopupForUser(RtcSeatUserInfo? userInfo, int type) async {
// 获取 RoomController 判断当前用户角色
final _roomController = Get.find<RoomController>();
if (userInfo == null) {
return;
}
// 获取目标用户ID(优先使用userId,如果没有则使用miId)
final targetUserId = userInfo.uid;
if (targetUserId == null) {
SmartDialog.showToast('用户ID不存在');
return;
}
// 刷新玫瑰数量
await _roomController.getVirtualAccount();
// 创建必要的 ValueNotifier
final activeGift = ValueNotifier<int?>(null);
final giftNum = ValueNotifier<int>(1);
_roomController.setDialogDismiss(true);
SmartDialog.show(
alignment: Alignment.bottomCenter,
maskColor: Colors.black.withOpacity(0.5),
onDismiss: (){
_roomController.setDialogDismiss(false);
},
builder: (context) {
return Obx(() {
// 获取礼物列表
final giftProducts = _roomController.giftProducts;
final giftList = giftProducts.toList();
return LiveGiftPopup(
activeGift: activeGift,
giftNum: giftNum,
giftList: giftList,
changeActive: (index) {
activeGift.value = index;
},
type: type,
showHeader: false, // 不显示头部
targetUserId: targetUserId, // 设置目标用户ID
);
});
},
);
}
@override
Widget build(BuildContext context) {
// 获取 RoomController 判断当前用户角色
final roomController = Get.find<RoomController>();
final overlayController = Get.find<OverlayController>();
final isHost = roomController.currentRole == CurrentRole.broadcaster;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 40.w,
padding: EdgeInsets.symmetric(horizontal: 3.w),
margin: EdgeInsets.only(left: 10.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(40.w)),
color: const Color.fromRGBO(0, 0, 0, .25),
),
child: Row(
children: [
// 支持网络图片和本地资源
ClipOval(
child: Image.network(
avatarAsset,
width: 34.w,
height: 34.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 34.w,
height: 34.w,
);
},
),
).onTap(() async {
// 检查是否是当前用户自己的消息
final currentUserId = GlobalData().userId ?? GlobalData().userData?.id;
if (currentUserId != null && currentUserId == roomController.rtcChannelDetail
.value?.anchorInfo?.userId) {
// 是自己的头像,不显示弹框
return;
}
try {
final _userApi = Get.find<UserApi>();
final response = await _userApi.getDongwoMarriageInformationDetail(miId: roomController.rtcChannelDetail
.value?.anchorInfo?.miId ?? "");
if (response.data.isSuccess && response.data.data != null) {
// 不是自己的消息,显示用户资料对话框
showUserProfileDialog(
context,
LiveChatMessage(
userId: roomController.rtcChannelDetail
.value?.anchorInfo?.userId ?? "",
uid: roomController.rtcChannelDetail
.value?.anchorInfo?.uid,
userName: roomController.rtcChannelDetail
.value?.anchorInfo?.nickName ?? "",
avatar: roomController.rtcChannelDetail
.value?.anchorInfo?.profilePhoto,
miId: roomController.rtcChannelDetail
.value?.anchorInfo?.miId,
content: "",
timestamp: 0
),
(int type) =>
_showGiftPopupForUser(roomController.rtcChannelDetail
.value?.anchorInfo, type),
response.data.data!
);
} else {
// 响应失败,设置错误信息
final errorMsg = response.data.message ?? '获取数据失败';
SmartDialog.showToast(errorMsg);
}
} catch(e, stackTrace){
print('获取用户信息失败: $e');
print('堆栈跟踪: $stackTrace');
SmartDialog.showToast('获取用户信息失败,请稍后重试');
// 不再 rethrow,避免导致闪退
}
}),
SizedBox(width: 7.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
userName,
style: TextStyle(fontSize: 13.w, color: Colors.white),
),
],
),
],
),
),
Row(
children: [
// 只有主持人才显示直播设置按钮
if (false && isHost)
GestureDetector(
onTap: () {
roomController.setDialogDismiss(true);
SmartDialog.showAttach(
targetContext: context,
onDismiss: (){
roomController.setDialogDismiss(false);
},
builder: (context) {
// 判断是否有嘉宾在连麦
final hasGuests =
roomController.rtcChannelDetail.value?.maleInfo !=
null ||
roomController.rtcChannelDetail.value?.femaleInfo !=
null;
return Container(
width: 110.w,
margin: EdgeInsets.only(left: 160.w),
padding: EdgeInsets.symmetric(horizontal: 10.w),
decoration: BoxDecoration(
color: Colors.black.withAlpha(80),
borderRadius: BorderRadius.all(Radius.circular(10.w)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 15.w),
// 只有当有嘉宾在连麦时才显示"解除连麦"选项
GestureDetector(
onTap: () async {
roomController.audienceList.clear();
await roomController.getAudienceList(null);
// 隐藏键盘
FocusScope.of(context).unfocus();
// 隐藏 overlay
SmartDialog.dismiss();
roomController.setDialogDismiss(true);
SmartDialog.show(
alignment: Alignment.bottomCenter,
maskColor: TDTheme.of(context).fontGyColor2,
onDismiss: (){
roomController.setDialogDismiss(false);
},
builder: (_) {
return KickList();
},
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
Assets.imagesGetOutIcon,
width: 15.w,
),
SizedBox(width: 5.w),
Text(
'踢出直播间',
style: TextStyle(
color: Colors.white,
fontSize: 13.sp,
),
),
],
),
),
SizedBox(height: 15.w),
if (hasGuests)
GestureDetector(
onTap: () {
// 关闭设置弹窗
SmartDialog.dismiss();
// 弹出解除连麦对话框
roomController.setDialogDismiss(true);
SmartDialog.show(
onDismiss: (){
roomController.setDialogDismiss(false);
},
builder: (context) {
return DisconnectMicDialog();
},
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
Assets.imagesMicOff,
width: 15.w,
),
SizedBox(width: 5.w),
Text(
'解除连麦',
style: TextStyle(
color: Colors.white,
fontSize: 13.sp,
),
),
],
),
),
if (hasGuests) SizedBox(height: 15.w),
GestureDetector(
onTap: () async {
await roomController.getDurationMins();
// 隐藏 overlay
SmartDialog.dismiss();
SmartDialog.show(
onDismiss: (){
roomController.setDialogDismiss(false);
},
builder: (context) {
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(16.w)),
child: Material(
color: Colors.white,
child: Container(
width: 311.w,
height: 189.w,
padding: EdgeInsets.symmetric(
vertical: 20.w,
horizontal: 27.w
),
child: Column(
children: [
Text(
"您当前正在视频相亲中\n"
"确定要退出吗?",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18.w
),
),
Container(
margin: EdgeInsets.only(top: 9.w, bottom: 18.w),
height: 23.w,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft, // 90deg = 从左到右
end: Alignment.centerRight,
colors: [
Color.fromRGBO(117, 98, 249, 0),
Color.fromRGBO(117, 98, 249, 0.2),
Color.fromRGBO(117, 98, 249, 0.2),
Color.fromRGBO(117, 98, 249, 0.2),
Color.fromRGBO(117, 98, 249, 0),
],
stops: [
0.0,
0.2931,
0.5389,
0.7708,
1.0,
],
),
),
child: Center(
child: Text(
"本场有效露脸开播时长${roomController.durationMins.value}分钟",
style: TextStyle(
fontSize: 12.w,
color: const Color.fromRGBO(117, 98, 249, 1)
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 128.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12.w)),
color: const Color.fromRGBO(237, 237, 237, 1)
),
child: Center(
child: Text(
"取消",
style: TextStyle(
fontSize: 15.w,
fontWeight: FontWeight.w400
),
),
),
).onTap(() {
SmartDialog.dismiss();
}),
Container(
width: 128.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12.w)),
color: const Color.fromRGBO(117, 98, 249, 1)
),
child: Center(
child: Text(
"确认",
style: TextStyle(
color: Colors.white,
fontSize: 15.w,
fontWeight: FontWeight.w400
),
),
),
).onTap(() async {
// 退出房间时清空RTM消息
await roomController.leaveChannel();
await roomController.getLiveData();
await roomController.getLiveIncome();
SmartDialog.dismiss();
if (Get.isRegistered<RoomController>()) {
final roomController = Get.find<RoomController>();
roomController.chatMessages.clear();
}
// 如果还没有执行 pop,手动调用 Get.back()
Get.off(() => SettlementPage());
// 等待页面关闭后再显示小窗口,确保小窗口能正确显示
Future.delayed(const Duration(milliseconds: 200), () {
overlayController.hide();
});
}),
],
)
],
),
),
),
);
},
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
Assets.imagesExitRoom,
width: 15.w,
),
SizedBox(width: 5.w),
Text(
'结束直播',
style: TextStyle(
color: Colors.white,
fontSize: 13.sp,
),
),
],
),
),
SizedBox(height: 15.w),
],
),
);
},
);
},
child: Container(
height: 30.w,
padding: EdgeInsets.symmetric(horizontal: 5.w),
margin: EdgeInsets.only(right: 15.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.w)),
color: const Color.fromRGBO(0, 0, 0, .3),
border: Border.all(
color: const Color.fromRGBO(255, 255, 255, .3),
width: 1.w,
),
),
child: Row(
children: [
Icon(
Icons.settings_rounded,
color: Colors.white,
size: 18.w,
),
Text(
'直播设置',
style: TextStyle(color: Colors.white, fontSize: 13.sp),
),
Icon(
Icons.keyboard_arrow_down_sharp,
color: Colors.white,
size: 18.w,
),
],
),
),
),
GestureDetector(
onTap: onCloseTap,
child: Container(
width: 30.w,
height: 30.w,
margin: EdgeInsets.only(right: 15.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.w)),
color: const Color.fromRGBO(0, 0, 0, .3),
),
child: Center(
child: Image.asset(closeIconAsset, width: 14.w, height: 14.w),
),
),
),
],
),
],
);
}
}