From 77d32e2f48104c071aabc74ee0ca27d79fce42b8 Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Wed, 3 Dec 2025 23:07:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(live):=20=E6=B7=BB=E5=8A=A0=E7=9B=B4?= =?UTF-8?q?=E6=92=AD=E9=97=B4=E8=AE=BE=E7=BD=AE=E5=8A=9F=E8=83=BD=E4=B8=8E?= =?UTF-8?q?=E9=80=80=E5=87=BA=E6=88=BF=E9=97=B4=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增直播设置按钮,仅主持人可见 - 实现解除连麦与结束直播功能 - 添加相关资源图片引用 - 优化页面返回与 overlay 控制逻辑 - 修复用户头像显示样式问题 - 调整顶部用户信息布局结构 --- assets/images/exit_room.png | Bin 0 -> 702 bytes assets/images/mic_off.png | Bin 0 -> 642 bytes lib/generated/assets.dart | 2 + lib/pages/discover/live_room_page.dart | 2 +- lib/widget/live/live_room_user_header.dart | 186 +++++++++++++++++---- 5 files changed, 154 insertions(+), 36 deletions(-) create mode 100644 assets/images/exit_room.png create mode 100644 assets/images/mic_off.png diff --git a/assets/images/exit_room.png b/assets/images/exit_room.png new file mode 100644 index 0000000000000000000000000000000000000000..4f817f9e015c93aaa0fc4d9e9492b66a4fe6307c GIT binary patch literal 702 zcmV;v0zv(WP)Px#1am@3R0s$N2z&@+hyVZrXh}ptR7i=nRy}sAKotJ&yjN)F5?lgVK@jNEfOU3| zlNCr-kmC+a8*N^%h8^e*;u7qj3HKEP!^|)d#N=x@=MHnfx&Id!fIJRYMG|m657Hs` z#r1@dPsH~CK#Zq6j{ILItuPsQubVWV2WgQ6TqNP4kFp{O4}IM3B+cW!L51@rLI6N1GV8x7QTgF|tU;Q`k>6O?fCG@gLvmymvo1nK{Ju|_#jHha=~bk89IkA_(Rz0`-fXiz zgo=2x%|`1z0d&;mdNK;2j-#x-8l&~@?iw;1%=BzYrnQ@O_fFL@;pG-Wpo+0{b)8%j zB7Rk*R`Q(s#;^}DK&M8+ULHrjuv3}|Z$Ck(^hq~2r6fwfRi{5?rP3!8QMFBCdJx3) zaD&cCzw9C0?afZ6zu)I{*nqoI^-?@h(6Zc4x^9T4c|Qc9njIv-t&-6 z;1X2;fe&`gPXzb zQdT|3gA9wkfS&<6xi%2z-aFpx9vNM8l|9WPt&N`v%kNemr=>cyr07CrEghNZ`BI&C klIrAu9Kx<~*hQq{KfjkFWP*>;C;$Ke07*qoM6N<$g84K>D*ylh literal 0 HcmV?d00001 diff --git a/assets/images/mic_off.png b/assets/images/mic_off.png new file mode 100644 index 0000000000000000000000000000000000000000..351a4117293e361954a2888ce798a71d3774848d GIT binary patch literal 642 zcmV-|0)737P)Px#1am@3R0s$N2z&@+hyVZrEJ;K`R9Ja89H(&*Kg1`hV6BH)U`=c^Z9NUqT^tUfD?d&44uT*0C*7Ffr#3fct@G@YGr`RfDccQ@Np_5 zt^}a`Ix9eDouoj{DcA@g3z`c2n+2o)S^W2zICTIrInZ}T|B#J-6MzV!HTs8B)NTT> z1R|Qd9$*bb1mG6~EQQz&1G2T8OIv)IeMfzzT6y01L$C020tyAtHdI*ha;w z6gvmN%zU;$qyWU;i%pm9Huej;DN@Y<19+03CnEZzhVP>9qGAXaf<{k03N`}(Tv|O~ zXnX*mMMk$7`!4$Z510PY8vuZz!#XKjlY^LuhhCshj3xI#&0m@5H@pOcf|R0f%+N4%;tOF<6> zqxq`=jPvy#$zBt#0w9a`3g9>gFu8&8xDNc@q$JQgfKM6o@(J2uxSxjNb^y>3k^Mmo zd%&v623-xHd^(lpUis_PyXyC^f}8e$g7uP}R?VM%|0&(_xfGtH~0};`4JSbyLWWLAnAH|olKLGdu@RRU=sX8GMgucM6kt?l}>nDOd#y!Cz crLwH`AAtJjk`J*)Qvd(}07*qoM6N<$f?rn^%K!iX literal 0 HcmV?d00001 diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index f505ebe..b9f8919 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -102,6 +102,7 @@ class Assets { static const String imagesEmoji = 'assets/images/emoji.png'; static const String imagesEmojiTab = 'assets/images/emoji_tab.png'; static const String imagesEmptyIcon = 'assets/images/empty_icon.png'; + static const String imagesExitRoom = 'assets/images/exit_room.png'; static const String imagesFemale = 'assets/images/female.png'; static const String imagesFemaleEmpty = 'assets/images/female_empty.png'; static const String imagesFireIcon = 'assets/images/fire_icon.png'; @@ -137,6 +138,7 @@ class Assets { static const String imagesMessagePre = 'assets/images/message_pre.png'; static const String imagesMicClose = 'assets/images/mic_close.png'; static const String imagesMicLine = 'assets/images/mic_line.png'; + static const String imagesMicOff = 'assets/images/mic_off.png'; static const String imagesMicOpen = 'assets/images/mic_open.png'; static const String imagesMineNol = 'assets/images/mine_nol.png'; static const String imagesMinePre = 'assets/images/mine_pre.png'; diff --git a/lib/pages/discover/live_room_page.dart b/lib/pages/discover/live_room_page.dart index 9c4cc4c..36d5b00 100644 --- a/lib/pages/discover/live_room_page.dart +++ b/lib/pages/discover/live_room_page.dart @@ -107,7 +107,7 @@ class _LiveRoomPageState extends State { Widget build(BuildContext context) { return PopScope( onPopInvokedWithResult: (bool didPop, Object? result) async { - _overlayController.toggle(); + _overlayController.hide(); Get.back(); }, child: Scaffold( diff --git a/lib/widget/live/live_room_user_header.dart b/lib/widget/live/live_room_user_header.dart index baae02c..99d2947 100644 --- a/lib/widget/live/live_room_user_header.dart +++ b/lib/widget/live/live_room_user_header.dart @@ -1,6 +1,11 @@ +import 'package:dating_touchme_app/controller/discover/room_controller.dart'; +import 'package:dating_touchme_app/controller/overlay_controller.dart'; import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/widget/live/disconnect_mic_dialog.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'; /// 直播间顶部用户信息与操作区域 class LiveRoomUserHeader extends StatelessWidget { @@ -25,6 +30,11 @@ class LiveRoomUserHeader extends StatelessWidget { @override Widget build(BuildContext context) { + // 获取 RoomController 判断当前用户角色 + final roomController = Get.find(); + final overlayController = Get.find(); + final isHost = roomController.currentRole == CurrentRole.broadcaster; + return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -40,20 +50,20 @@ class LiveRoomUserHeader extends StatelessWidget { 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, - ); - }, - ), - ), + 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, + ); + }, + ), + ), SizedBox(width: 7.w), Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -61,37 +71,143 @@ class LiveRoomUserHeader extends StatelessWidget { children: [ Text( userName, - style: TextStyle( - fontSize: 13.w, - color: Colors.white, - ), + style: TextStyle(fontSize: 13.w, color: Colors.white), ), ], ), ], ), ), - 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, + Row( + children: [ + // 只有主持人才显示直播设置按钮 + if (isHost) + GestureDetector( + onTap: () { + SmartDialog.showAttach( + targetContext: context, + builder: (context) { + return Container( + width: 100.w, + margin: EdgeInsets.only(left: 160.w), + decoration: BoxDecoration( + color: Colors.black.withAlpha(80), + borderRadius: BorderRadius.all(Radius.circular(10.w)), + ), + child: Column( + children: [ + SizedBox(height: 15.w), + GestureDetector( + onTap: () { + // 关闭设置弹窗 + SmartDialog.dismiss(); + // 弹出解除连麦对话框 + SmartDialog.show(builder: (context){ + return DisconnectMicDialog(); + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset(Assets.imagesMicOff, width: 15.w), + SizedBox(width: 5.w), + Text( + '解除连麦', + style: TextStyle( + color: Colors.white, + fontSize: 13.sp, + ), + ), + ], + ), + ), + SizedBox(height: 15.w), + GestureDetector( + onTap: () async { + // 关闭弹窗 + SmartDialog.dismiss(); + // 隐藏 overlay + overlayController.hide(); + // 返回上一页 + Get.back(); + // 调用结束直播方法 + await roomController.leaveChannel(); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + 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), + ), ), ), - ), + ], ), ], ); } } -