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.
782 lines
31 KiB
782 lines
31 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/mine/rose_controller.dart';
|
|
import 'package:dating_touchme_app/controller/overlay_controller.dart';
|
|
import 'package:dating_touchme_app/extension/ex_fuction.dart';
|
|
import 'package:dating_touchme_app/extension/ex_widget.dart';
|
|
import 'package:dating_touchme_app/generated/assets.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:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_room_user_header.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_room_anchor_showcase.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_room_active_speaker.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_room_notice_chat_panel.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_room_action_bar.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_gift_popup.dart';
|
|
import 'package:dating_touchme_app/widget/live/live_recharge_popup.dart';
|
|
import 'package:dating_touchme_app/widget/live/svga_player_widget.dart';
|
|
|
|
class LiveRoomPage extends StatefulWidget {
|
|
final int id;
|
|
const LiveRoomPage({super.key, required this.id});
|
|
|
|
@override
|
|
State<LiveRoomPage> createState() => _LiveRoomPageState();
|
|
}
|
|
|
|
class _LiveRoomPageState extends State<LiveRoomPage> {
|
|
late final RoomController _roomController;
|
|
late final OverlayController _overlayController;
|
|
String message = '';
|
|
final TextEditingController _messageController = TextEditingController();
|
|
final TextEditingController _inputDialogController = TextEditingController();
|
|
final FocusNode _inputDialogFocusNode = FocusNode();
|
|
bool _showInputDialog = false;
|
|
bool _isOpeningDialog = false; // 标记是否正在打开对话框
|
|
|
|
final activeGift = ValueNotifier<int?>(null);
|
|
|
|
final giftNum = ValueNotifier<int>(1);
|
|
|
|
changeActive(int index) {
|
|
activeGift.value = index;
|
|
setState(() {});
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_roomController = Get.isRegistered<RoomController>()
|
|
? Get.find<RoomController>()
|
|
: Get.put(RoomController());
|
|
_overlayController = Get.find<OverlayController>();
|
|
// 进入直播间时,确保隐藏小窗口(延迟到 build 完成后执行,避免在 build 过程中触发 setState)
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (_overlayController.showOverlay.value) {
|
|
_overlayController.hide();
|
|
}
|
|
});
|
|
// 监听输入对话框的焦点变化,当键盘收起时隐藏对话框
|
|
_inputDialogFocusNode.addListener(_onInputDialogFocusChanged);
|
|
// 启用屏幕常亮
|
|
WakelockPlus.enable();
|
|
// 如果当前用户是男性,请求连麦卡片信息
|
|
_loadLinkMicCard();
|
|
// 请求玫瑰数量
|
|
_loadRoseCount();
|
|
}
|
|
|
|
/// 加载连麦卡片信息(仅男性用户)
|
|
Future<void> _loadLinkMicCard() async {
|
|
final userData = GlobalData().userData;
|
|
if (userData?.genderCode == 0) {
|
|
// 男性用户才请求
|
|
await _roomController.getUserPropLinkMicCard();
|
|
}
|
|
}
|
|
|
|
/// 加载玫瑰数量
|
|
Future<void> _loadRoseCount() async {
|
|
await _roomController.getVirtualAccount();
|
|
}
|
|
|
|
/// 输入对话框焦点变化回调
|
|
void _onInputDialogFocusChanged() {
|
|
if (!mounted) return;
|
|
// 如果焦点丢失且对话框仍显示,检查键盘状态
|
|
if (!_inputDialogFocusNode.hasFocus && _showInputDialog) {
|
|
// 使用 addPostFrameCallback 确保在下一帧检查,此时键盘状态已更新
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (!mounted) return;
|
|
// 如果键盘已收起,隐藏对话框
|
|
final keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
|
|
if (keyboardHeight == 0) {
|
|
_hideInputDialog();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
// 移除焦点监听器
|
|
_inputDialogFocusNode.removeListener(_onInputDialogFocusChanged);
|
|
// 禁用屏幕常亮
|
|
WakelockPlus.disable();
|
|
_messageController.dispose();
|
|
_inputDialogController.dispose();
|
|
_inputDialogFocusNode.dispose();
|
|
SmartDialog.dismiss();
|
|
// 退出房间时清空RTM消息
|
|
if (Get.isRegistered<RoomController>()) {
|
|
final roomController = Get.find<RoomController>();
|
|
roomController.chatMessages.clear();
|
|
}
|
|
super.dispose();
|
|
}
|
|
|
|
/// 显示输入对话框
|
|
void _openInputDialog() {
|
|
_isOpeningDialog = true;
|
|
setState(() {
|
|
_showInputDialog = true;
|
|
});
|
|
// 延迟获取焦点,确保对话框已显示
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (mounted && _showInputDialog) {
|
|
_inputDialogFocusNode.requestFocus();
|
|
// 键盘弹起后,重置标志
|
|
Future.delayed(const Duration(milliseconds: 500), () {
|
|
if (mounted) {
|
|
_isOpeningDialog = false;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/// 隐藏输入对话框
|
|
void _hideInputDialog() {
|
|
_isOpeningDialog = false;
|
|
setState(() {
|
|
_showInputDialog = false;
|
|
});
|
|
_inputDialogFocusNode.unfocus();
|
|
_inputDialogController.clear();
|
|
}
|
|
|
|
/// 发送输入对话框中的消息
|
|
void _sendInputDialogMessage() {
|
|
final content = _inputDialogController.text.trim();
|
|
if (content.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
// 更新主 controller
|
|
_messageController.text = content;
|
|
message = content;
|
|
|
|
// 发送消息
|
|
_sendMessage();
|
|
|
|
// 关闭对话框
|
|
_hideInputDialog();
|
|
}
|
|
|
|
/// 发送消息
|
|
Future<void> _sendMessage() async {
|
|
final content = _messageController.text.trim();
|
|
if (content.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
// 发送消息
|
|
await _roomController.sendChatMessage(content);
|
|
|
|
// 清空输入框
|
|
_messageController.clear();
|
|
message = '';
|
|
}
|
|
|
|
void _showGiftPopup() async {
|
|
if(_roomController.isDialogShowing.value){
|
|
return;
|
|
}
|
|
// 隐藏键盘
|
|
FocusScope.of(context).unfocus();
|
|
// 刷新玫瑰数量
|
|
await _roomController.getVirtualAccount();
|
|
_roomController.setDialogDismiss(true);
|
|
SmartDialog.show(
|
|
backType: SmartBackType.block,
|
|
alignment: Alignment.bottomCenter,
|
|
maskColor: TDTheme.of(context).fontGyColor2,
|
|
onDismiss: () {
|
|
_roomController.setDialogDismiss(false);
|
|
},
|
|
builder: (_) => Obx(() {
|
|
// 优先使用 API 返回的 giftProducts,如果为空则使用后备列表
|
|
final giftProducts = _roomController.giftProducts;
|
|
final giftList = giftProducts.toList();
|
|
|
|
return LiveGiftPopup(
|
|
activeGift: activeGift,
|
|
giftNum: giftNum,
|
|
giftList: giftList,
|
|
changeActive: changeActive,
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
void _showRechargePopup() async {
|
|
// 隐藏键盘
|
|
FocusScope.of(context).unfocus();
|
|
_roomController.setDialogDismiss(true);
|
|
final roseController = Get.isRegistered<RoseController>()
|
|
? Get.find<RoseController>()
|
|
: Get.put(RoseController());
|
|
|
|
await roseController.getRoseNum();
|
|
SmartDialog.show(
|
|
alignment: Alignment.bottomCenter,
|
|
maskColor: TDTheme.of(context).fontGyColor2,
|
|
onDismiss: (){
|
|
_roomController.setDialogDismiss(false);
|
|
},
|
|
|
|
builder: (_) => const LiveRechargePopup(),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
|
|
final isHost = _roomController.currentRole == CurrentRole.broadcaster;
|
|
|
|
// 判断是否有嘉宾在连麦
|
|
final hasGuests =
|
|
_roomController.rtcChannelDetail.value?.maleInfo !=
|
|
null ||
|
|
_roomController.rtcChannelDetail.value?.femaleInfo !=
|
|
null;
|
|
|
|
// 在 build 方法开始时立即隐藏小窗口(使用 addPostFrameCallback 避免在 build 过程中触发 setState)
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (_overlayController.showOverlay.value) {
|
|
_overlayController.hide();
|
|
}
|
|
// 检查键盘状态,如果键盘收起但对话框仍显示,且不是正在打开对话框,则隐藏对话框
|
|
if (MediaQuery.of(context).viewInsets.bottom == 0 &&
|
|
_showInputDialog &&
|
|
!_isOpeningDialog) {
|
|
// 延迟一点时间再检查,避免在键盘弹起过程中误判
|
|
Future.delayed(const Duration(milliseconds: 300), () {
|
|
if (mounted &&
|
|
MediaQuery.of(context).viewInsets.bottom == 0 &&
|
|
_showInputDialog &&
|
|
!_isOpeningDialog) {
|
|
_hideInputDialog();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
return Obx(() {
|
|
return PopScope(
|
|
canPop: !_roomController.isDialogShowing.value,
|
|
onPopInvokedWithResult: (bool didPop, Object? result) {
|
|
// SmartDialog.dismiss();
|
|
// print('256>22>>' + didPop.toString());
|
|
// if (didPop) return;
|
|
|
|
// 如果有对话框显示,关闭对话框
|
|
if (_roomController.isDialogShowing.value) {
|
|
SmartDialog.dismiss();
|
|
return; // 阻止页面返回
|
|
}
|
|
// 退出房间时清空RTM消息
|
|
if (Get.isRegistered<RoomController>()) {
|
|
final roomController = Get.find<RoomController>();
|
|
roomController.chatMessages.clear();
|
|
}
|
|
// 如果还没有执行 pop,手动调用 Get.back()
|
|
if (!didPop) {
|
|
Get.back();
|
|
}
|
|
// 等待页面关闭后再显示小窗口,确保小窗口能正确显示
|
|
Future.delayed(const Duration(milliseconds: 200), () {
|
|
_overlayController.show();
|
|
});
|
|
},
|
|
child: Scaffold(
|
|
resizeToAvoidBottomInset: false,
|
|
body: Stack(
|
|
children: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [
|
|
Color.fromRGBO(248, 242, 255, 1),
|
|
Color.fromRGBO(247, 247, 247, 1),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Container(
|
|
decoration: const BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.bottomCenter,
|
|
end: Alignment.topCenter,
|
|
colors: [
|
|
Color.fromRGBO(19, 16, 47, 1),
|
|
Color.fromRGBO(19, 16, 47, 1),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Container(
|
|
padding: EdgeInsets.only(
|
|
top: MediaQuery.of(context).padding.top,
|
|
),
|
|
child: Column(
|
|
children: [
|
|
SizedBox(height: 10.w),
|
|
Obx(() {
|
|
final detail = _roomController.rtcChannelDetail.value;
|
|
final anchorInfo = detail?.anchorInfo;
|
|
|
|
final userName = anchorInfo?.nickName ?? '用户';
|
|
final avatarAsset =
|
|
anchorInfo?.profilePhoto ?? Assets.imagesUserAvatar;
|
|
const popularityText = '0'; // TODO: 使用真实数据
|
|
|
|
return LiveRoomUserHeader(
|
|
userName: userName,
|
|
popularityText: popularityText,
|
|
avatarAsset: avatarAsset,
|
|
onCloseTap: () {
|
|
SmartDialog.dismiss();
|
|
// 退出房间时清空RTM消息
|
|
if (Get.isRegistered<RoomController>()) {
|
|
final roomController = Get.find<RoomController>();
|
|
roomController.chatMessages.clear();
|
|
}
|
|
Get.back();
|
|
// 等待页面关闭后再显示小窗口,确保小窗口能正确显示
|
|
Future.delayed(const Duration(milliseconds: 200), () {
|
|
_overlayController.show();
|
|
});
|
|
},
|
|
);
|
|
}),
|
|
SizedBox(height: 7.w),
|
|
LiveRoomAnchorShowcase(),
|
|
// SizedBox(height: 5.w),
|
|
// const LiveRoomActiveSpeaker(),
|
|
SizedBox(height: 9.w),
|
|
Expanded(child: const LiveRoomNoticeChatPanel()),
|
|
// 根据键盘状态显示/隐藏 LiveRoomActionBar
|
|
if (MediaQuery.of(context).viewInsets.bottom == 0)
|
|
SafeArea(
|
|
top: false,
|
|
child: Padding(
|
|
padding: EdgeInsets.only(
|
|
bottom: 10.w,
|
|
left: 0,
|
|
right: 0,
|
|
),
|
|
child: LiveRoomActionBar(
|
|
messageController: _messageController,
|
|
onMessageChanged: (value) {
|
|
message = value;
|
|
},
|
|
onSendTap: _sendMessage,
|
|
onGiftTap: _showGiftPopup.throttle(),
|
|
onChargeTap: _showRechargePopup,
|
|
onInputTap: _openInputDialog,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (isHost) Positioned(
|
|
right: 15.w,
|
|
top: 95.w,
|
|
child: Column(
|
|
children: [
|
|
if (hasGuests) Container(
|
|
width: 44.w,
|
|
height: 44.w,
|
|
margin: EdgeInsets.only(bottom: 5.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(6.w)),
|
|
color: const Color.fromRGBO(0, 0, 0, .3)
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Image.asset(
|
|
Assets.imagesMicManage,
|
|
width: 17.w,
|
|
height: 18.w,
|
|
),
|
|
Text(
|
|
"连麦管理",
|
|
style: TextStyle(
|
|
fontSize: 9.w,
|
|
color: Colors.white
|
|
),
|
|
)
|
|
],
|
|
),
|
|
).onTap(() {
|
|
// 关闭设置弹窗
|
|
SmartDialog.dismiss();
|
|
// 弹出解除连麦对话框
|
|
_roomController.setDialogDismiss(true);
|
|
SmartDialog.show(
|
|
onDismiss: (){
|
|
_roomController.setDialogDismiss(false);
|
|
},
|
|
builder: (context) {
|
|
return DisconnectMicDialog();
|
|
},
|
|
);
|
|
}),
|
|
Container(
|
|
width: 44.w,
|
|
height: 44.w,
|
|
margin: EdgeInsets.only(bottom: 5.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(6.w)),
|
|
color: const Color.fromRGBO(0, 0, 0, .3)
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Image.asset(
|
|
Assets.imagesKickUser,
|
|
width: 19.w,
|
|
height: 18.w,
|
|
),
|
|
Text(
|
|
"踢出房间",
|
|
style: TextStyle(
|
|
fontSize: 9.w,
|
|
color: Colors.white
|
|
),
|
|
)
|
|
],
|
|
),
|
|
).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();
|
|
},
|
|
);
|
|
}),
|
|
Container(
|
|
width: 44.w,
|
|
height: 44.w,
|
|
margin: EdgeInsets.only(bottom: 5.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(6.w)),
|
|
color: const Color.fromRGBO(0, 0, 0, .3)
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Image.asset(
|
|
Assets.imagesCloseLive,
|
|
width: 15.w,
|
|
height: 16.w,
|
|
),
|
|
Text(
|
|
"结束直播",
|
|
style: TextStyle(
|
|
fontSize: 9.w,
|
|
color: Colors.white
|
|
),
|
|
)
|
|
],
|
|
),
|
|
).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();
|
|
});
|
|
|
|
}),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}),
|
|
],
|
|
),
|
|
),
|
|
// SVGA 动画播放组件
|
|
const SvgaPlayerWidget(),
|
|
// 输入对话框
|
|
if (_showInputDialog) ...[
|
|
// 遮罩层,点击时隐藏对话框和键盘(放在对话框下方,对话框会在上面拦截点击)
|
|
Positioned.fill(
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () {
|
|
// 隐藏键盘
|
|
FocusScope.of(context).unfocus();
|
|
// 隐藏对话框
|
|
_hideInputDialog();
|
|
},
|
|
child: Container(color: Colors.transparent),
|
|
),
|
|
),
|
|
// 输入对话框(放在遮罩层上面,会自动拦截点击事件)
|
|
AnimatedPositioned(
|
|
duration: const Duration(milliseconds: 200),
|
|
curve: Curves.easeOut,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: MediaQuery.of(context).viewInsets.bottom,
|
|
child: _InputDialogWidget(
|
|
controller: _inputDialogController,
|
|
focusNode: _inputDialogFocusNode,
|
|
onSend: _sendInputDialogMessage,
|
|
onClose: _hideInputDialog,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
class _InputDialogWidget extends StatelessWidget {
|
|
const _InputDialogWidget({
|
|
required this.controller,
|
|
required this.focusNode,
|
|
required this.onSend,
|
|
required this.onClose,
|
|
});
|
|
|
|
final TextEditingController controller;
|
|
final FocusNode focusNode;
|
|
final VoidCallback onSend;
|
|
final VoidCallback onClose;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(20.w),
|
|
topRight: Radius.circular(20.w),
|
|
),
|
|
),
|
|
child: SafeArea(
|
|
top: false,
|
|
child: Padding(
|
|
padding: EdgeInsets.all(16.w),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Container(
|
|
height: 38.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(38.w)),
|
|
color: const Color.fromRGBO(245, 245, 245, 1),
|
|
),
|
|
alignment: Alignment.centerLeft,
|
|
child: TextField(
|
|
controller: controller,
|
|
focusNode: focusNode,
|
|
keyboardType: TextInputType.text,
|
|
textAlignVertical: TextAlignVertical.center,
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(14),
|
|
height: 1.2,
|
|
color: Colors.black,
|
|
),
|
|
decoration: InputDecoration(
|
|
contentPadding: EdgeInsets.symmetric(
|
|
vertical: 0,
|
|
horizontal: 15.w,
|
|
),
|
|
hintText: "说点什么",
|
|
hintStyle: TextStyle(
|
|
color: const Color.fromRGBO(144, 144, 144, 1),
|
|
height: 1.2,
|
|
fontSize: ScreenUtil().setWidth(14),
|
|
),
|
|
border: InputBorder.none,
|
|
isDense: true,
|
|
),
|
|
onSubmitted: (_) {
|
|
onSend();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 12.w),
|
|
GestureDetector(
|
|
onTap: onSend,
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: 24.w,
|
|
vertical: 10.h,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: const Color.fromRGBO(117, 98, 249, 1),
|
|
borderRadius: BorderRadius.circular(19.w),
|
|
),
|
|
child: Text(
|
|
"发送",
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(14),
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|