From 44c789e2f131542066555f147afa04a03975af8c Mon Sep 17 00:00:00 2001 From: fuenmao <980740792@qq.com> Date: Fri, 6 Dec 2024 10:19:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E9=A2=84=E8=A7=88=E6=82=AC?= =?UTF-8?q?=E6=B5=AE=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wgshare/lib/pages/loginPage/login_view.dart | 3 - .../lib/pages/metting/meeting_main_logic.dart | 11 +- .../lib/pages/metting/meeting_main_state.dart | 3 + .../lib/pages/metting/meeting_main_view.dart | 1241 +++++++++-------- .../video/meeting_main_video_view.dart | 10 +- wgshare/pubspec.lock | 8 + wgshare/pubspec.yaml | 3 + 7 files changed, 717 insertions(+), 562 deletions(-) diff --git a/wgshare/lib/pages/loginPage/login_view.dart b/wgshare/lib/pages/loginPage/login_view.dart index c974653..a6516db 100644 --- a/wgshare/lib/pages/loginPage/login_view.dart +++ b/wgshare/lib/pages/loginPage/login_view.dart @@ -2,11 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:wgshare/main.dart'; -import 'package:wgshare/utils/my_text.dart'; import 'package:wgshare/utils/utils.dart'; -import '../../routes/app_routes.dart'; import '../../utils/color_util.dart'; import 'login_logic.dart'; diff --git a/wgshare/lib/pages/metting/meeting_main_logic.dart b/wgshare/lib/pages/metting/meeting_main_logic.dart index 4036919..62ea0e9 100644 --- a/wgshare/lib/pages/metting/meeting_main_logic.dart +++ b/wgshare/lib/pages/metting/meeting_main_logic.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:agora_rtc_engine/agora_rtc_engine.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:signalr_core/signalr_core.dart'; @@ -33,6 +34,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ @override void onClose() { super.onClose(); + state.floating.value?.close(); state.memberNameSearchController.dispose(); state.sendMsgController.dispose(); stopTime(); @@ -311,7 +313,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ doHttpSetMicr(); }); - /// 单独用户开闭麦回调 + /// 用户单独开闭麦回调 state.hubConnection.value?.on("OperMicr", (e){ // var jsonStr = const Utf8Decoder().convert(json.encode(e?[0]).runes.toList()); var jsonStr = json.encode(e?[0]); @@ -406,7 +408,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ }); /// ------------------------------------------------------------------------------摄像头或者屏幕相关回调 - /// 单独用户开闭摄像头回调 + /// 用户单独开闭摄像头回调 state.hubConnection.value?.on("OperCamera", (e){ // var jsonStr = const Utf8Decoder().convert(json.encode(e?[0]).runes.toList()); var jsonStr = json.encode(e?[0]); @@ -425,7 +427,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ muteLocalVideoStream(false); // 开始本地预览 startPreview(); - + // 打开本地预览悬浮窗 + state.floating.value?.open(state.context.value!); changePageState(1); } }else{ @@ -442,6 +445,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ muteLocalVideoStream(true); // 停止本地预览 stopPreview(); + // 关闭本地预览悬浮窗 + state.floating.value?.close(); } } }); diff --git a/wgshare/lib/pages/metting/meeting_main_state.dart b/wgshare/lib/pages/metting/meeting_main_state.dart index ab45e62..f7209fe 100644 --- a/wgshare/lib/pages/metting/meeting_main_state.dart +++ b/wgshare/lib/pages/metting/meeting_main_state.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter_floating/floating/floating.dart'; import 'package:get/get.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:signalr_core/signalr_core.dart'; @@ -18,6 +19,8 @@ class MeetingMainState { late TextEditingController memberNameSearchController = TextEditingController(); late TextEditingController sendMsgController = TextEditingController(); + late Rx floating = Rx(null); + late Rx context = Rx(null); /// 是否显示会议信息浮层 late RxBool isShowMeetingInfoFloatingLayer = false.obs; diff --git a/wgshare/lib/pages/metting/meeting_main_view.dart b/wgshare/lib/pages/metting/meeting_main_view.dart index a4defd4..e3b66ae 100644 --- a/wgshare/lib/pages/metting/meeting_main_view.dart +++ b/wgshare/lib/pages/metting/meeting_main_view.dart @@ -1,5 +1,10 @@ +import 'dart:ui'; + +import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_floating/floating/assist/floating_slide_type.dart'; +import 'package:flutter_floating/floating/floating.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:liquid_progress_indicator_v2/liquid_progress_indicator.dart'; @@ -15,13 +20,35 @@ import 'meeting_main_logic.dart'; import 'meeting_main_state.dart'; import 'voice/meeting_main_voice_view.dart'; -class MeetingMainPage extends StatelessWidget { - MeetingMainPage({Key? key}) : super(key: key); +class MeetingMainPage extends StatefulWidget { + const MeetingMainPage({super.key}); + + @override + State createState() => MeetingMainPageState(); +} + +class MeetingMainPageState extends State { final MeetingMainLogic logic = Get.put(MeetingMainLogic()); final MeetingMainState state = Get.find().state; + @override + void initState() { + super.initState(); + state.floating.value = Floating( + previewFloatingWidget(), + slideType: FloatingSlideType.onRightAndTop, + moveOpacity: 1, + isShowLog: false, + isSnapToEdge: false, + isPosCache: false, + top: MediaQueryData.fromView(window).padding.top + 100 + 58, + right: 13); + } + + @override Widget build(BuildContext context) { + state.context.value = context; return Scaffold( appBar: AppBar( surfaceTintColor: ColorUtil.Color_41_41_41, @@ -37,391 +64,423 @@ class MeetingMainPage extends StatelessWidget { backgroundColor: ColorUtil.Color_41_41_41, ), body: Obx(() => Stack( - children: [ - Column( children: [ - /// 顶部布局 - Container( - width: double.infinity, - height: 100.h, - alignment: Alignment.center, - color: ColorUtil.Color_41_41_41, - padding: const EdgeInsets.only(left: 16, right: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 92.w, - child: Row( - children: [ - Image.asset( - 'assets/images/meeting_main_narrow.png', - width: 20.w, - height: 20.h, - ), - SizedBox(width: 16.w), - GestureDetector( - child: Image.asset( - state.communicationMode.value == 1 ? 'assets/images/meeting_main_receiver.png' : 'assets/images/meeting_main_speaker.png', - width: 20.w, - height: 20.h, - ), - onTap: (){ - if(state.communicationMode.value == 1 || state.communicationMode.value == 3){ - logic.changeMeetingAudioState(true); - } - }, - ), - Visibility( - visible: state.isOpenCamera.value, - child: GestureDetector( - child: Row( - children: [ - SizedBox(width: 16.w), - Image.asset( - 'assets/images/meeting_main_rotate_camera.png', - width: 20.w, - height: 20.h, - ) - ], - ), - onTap: (){ - logic.switchCamera(); - }, - ), - ) - ], - ), - ), - GestureDetector( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( + Column( + children: [ + /// 顶部布局 + Container( + width: double.infinity, + height: 100.h, + alignment: Alignment.center, + color: ColorUtil.Color_41_41_41, + padding: const EdgeInsets.only(left: 16, right: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 92.w, + child: Row( children: [ - Text( - state.meetingRoomInfo.value?.roomName ?? '', - style: TextStyle( - color: Colors.white, - fontSize: 14.sp, - fontWeight: FontWeight.w500), + GestureDetector( + child: Image.asset( + 'assets/images/meeting_main_narrow.png', + width: 20.w, + height: 20.h, + ), + onTap: (){ + if(state.floating.value?.isShowing == true){ + state.floating.value?.close(); + }else{ + state.floating.value?.open(context); + } + }, ), - SizedBox(width: 4.w), - Image.asset( - 'assets/images/meeting_main_down.png', - width: 16.w, - height: 16.h, + SizedBox(width: 16.w), + GestureDetector( + child: Image.asset( + state.communicationMode.value == 1 + ? 'assets/images/meeting_main_receiver.png' + : 'assets/images/meeting_main_speaker.png', + width: 20.w, + height: 20.h, + ), + onTap: () { + if (state.communicationMode.value == 1 || + state.communicationMode.value == 3) { + logic.changeMeetingAudioState(true); + } + }, + ), + Visibility( + visible: state.isOpenCamera.value, + child: GestureDetector( + child: Row( + children: [ + SizedBox(width: 16.w), + Image.asset( + 'assets/images/meeting_main_rotate_camera.png', + width: 20.w, + height: 20.h, + ) + ], + ), + onTap: () { + logic.switchCamera(); + }, + ), ) ], ), - SizedBox(height: 4.h), - Text( - state.duration.value, - style: TextStyle( - color: Colors.white, - fontSize: 12.sp, - ), - ) - ], - ), - onTap: (){ - logic.changeMeetingInfoState(true); - }, + ), + GestureDetector( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + Text( + state.meetingRoomInfo.value?.roomName ?? + '', + style: TextStyle( + color: Colors.white, + fontSize: 14.sp, + fontWeight: FontWeight.w500), + ), + SizedBox(width: 4.w), + Image.asset( + 'assets/images/meeting_main_down.png', + width: 16.w, + height: 16.h, + ) + ], + ), + SizedBox(height: 4.h), + Text( + state.duration.value, + style: TextStyle( + color: Colors.white, + fontSize: 12.sp, + ), + ) + ], + ), + onTap: () { + logic.changeMeetingInfoState(true); + }, + ), + Container( + width: 92.w, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + /// 结束发言 + Visibility( + visible: state.isSpeak.value, + child: GestureDetector( + child: Image.asset( + 'assets/images/meeting_main_hang_up.png', + width: 22.w, + height: 22.h, + ), + onTap: () { + logic.doHttpCancelSpeak(); + }, + ), + ), + SizedBox(width: 16.w), + + /// 退出会议 + GestureDetector( + child: Image.asset( + 'assets/images/meeting_leave.png', + width: 20.w, + height: 20.h, + ), + onTap: () { + Get.bottomSheet( + isScrollControlled: true, + leaveBottomSheet(context)); + }, + ) + ], + ), + ) + ], ), - Container( - width: 92.w, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - /// 结束发言 - Visibility( - visible: state.isSpeak.value, - child: GestureDetector( - child: Image.asset( - 'assets/images/meeting_main_hang_up.png', + ), + + /// 中间布局 + Expanded( + child: Stack( + alignment: Alignment.bottomLeft, + children: [ + // 语音 + Visibility( + visible: state.pageState.value == 0, + child: MeetingMainVoiceComponent( + users: state.cacheUsers.value)), + + // 视频 + Visibility( + visible: state.pageState.value == 1, + child: null != state.rctEngine.value + ? MeetingMainVideoComponent( + rtcEngine: state.rctEngine.value!, + channelId: state.roomNumber.value, + isOpenCamera: state.isOpenCamera.value, + remoteUid: state.remoteUid.value, + users: state.cacheUsers.value + .where((user) => + user.enableCamera == true) + .toList(), + onHangUpTap: () { + logic.hangUpVideo(); + }, + ) + : Container()), + + // 共享屏幕 + Visibility( + visible: state.pageState.value == 2, + child: null != state.rctEngine.value + ? MeetingMainShareComponent( + rtcEngine: state.rctEngine.value!, + channelId: state.roomNumber.value, + remoteUid: state.remoteUid.value, + ) + : Container()), + + GestureDetector( + child: Container( + width: 180.w, + height: 40.h, + margin: + const EdgeInsets.only(left: 20, bottom: 40), + padding: const EdgeInsets.only(left: 20), + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(56), + topRight: Radius.circular(50), + bottomRight: Radius.circular(50)), + color: ColorUtil.Color_35_35_35_07, + border: Border.all( + width: 1.w, + color: ColorUtil.Color_99_111_158), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Image.asset( + 'assets/images/meeting_main_chat.png', + width: 18.w, + height: 18.h, + ), + SizedBox(width: 6.w), + Text( + '说点什么...', + style: TextStyle( + fontSize: 14.sp, + color: ColorUtil.Color_156_156_156), + ) + ], + ), + ), + onTap: () { + Get.bottomSheet( + isScrollControlled: true, + chatBottomSheet(context)); + Future.delayed(const Duration(milliseconds: 100), + () { + state.chatController.jumpTo(state + .chatController.position.maxScrollExtent); + }); + }, + ) + ], + ), + ), + + /// 底部布局 + Container( + width: double.infinity, + height: 84.h, + color: ColorUtil.Color_35_35_35, + padding: const EdgeInsets.only(left: 26, right: 26), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + /// 音频 + GestureDetector( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + state.isSpeak.value == false + ? Image.asset( + state.isSpeak.value == false + ? 'assets/images/meeting_main_sqfy.png' + : state.isOpenMicrophone.value == + true + ? 'assets/images/meeting_main_microphone_default.png' + : 'assets/images/meeting_main_sqfy.png', + width: 20.w, + height: 20.h, + ) + : state.isOpenMicrophone.value == true + ? Container( + width: 20.w, + height: 20.h, + child: LiquidCustomProgressIndicator( + value: state + .microphoneVolume.value, + valueColor: + const AlwaysStoppedAnimation( + ColorUtil + .Color_2_177_136), + backgroundColor: + ColorUtil.Color_255_255_255, + direction: Axis.vertical, + shapePath: ViewSvgPath + .getMicrpphonePath()), + ) + : Image.asset( + 'assets/images/meeting_main_sqfy.png', + width: 20.w, + height: 20.h, + ), + SizedBox(height: 4.h), + Text( + state.isSpeak.value == false + ? '申请发言' + : state.isOpenMicrophone.value == true + ? "手动静音" + : "解除静音", + style: TextStyle( + fontSize: 12.sp, + color: ColorUtil.Color_202_202_202), + ) + ], + ), + onTap: () { + if (state.isSpeak.value == false) { + Get.bottomSheet( + isScrollControlled: true, + applySpeakPermissionBottomSheet(context)); + } else { + if (state.isOpenMicrophone.value == false) { + logic.setMicrophoneOpen(true); + } else { + logic.setMicrophoneOpen(false); + } + } + }, + ), + + /// 视频 + GestureDetector( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + state.isSpeak.value == true + ? state.isOpenCamera.value == true + ? 'assets/images/meeting_main_camera_open.png' + : 'assets/images/meeting_main_camera_default.png' + : 'assets/images/meeting_main_sp.png', width: 22.w, height: 22.h, ), - onTap: () { - logic.doHttpCancelSpeak(); - }, - ), + SizedBox(height: 4.h), + Text( + state.isOpenCamera.value == true + ? "关闭视频" + : "开启视频", + style: TextStyle( + fontSize: 12.sp, + color: ColorUtil.Color_202_202_202), + ) + ], ), - SizedBox(width: 16.w), - /// 退出会议 - GestureDetector( - child: Image.asset( - 'assets/images/meeting_leave.png', - width: 20.w, - height: 20.h, - ), - onTap: () { - Get.bottomSheet( - isScrollControlled: true, - leaveBottomSheet(context) - ); - }, - ) - ], - ), - ) - ], - ), - ), + onTap: () { + if (state.isSpeak.value == true) { + if (state.isOpenCamera.value == true) { + logic.setCameraOpen(false); + } else { + logic.setCameraOpen(true); + } + } + }, + ), - /// 中间布局 - Expanded( - child: Stack( - alignment: Alignment.bottomLeft, - children: [ - - // 语音 - Visibility( - visible: state.pageState.value == 0, - child: MeetingMainVoiceComponent(users: state.cacheUsers.value) - ), - - // 视频 - Visibility( - visible: state.pageState.value == 1, - child: null != state.rctEngine.value - ? MeetingMainVideoComponent( - rtcEngine: state.rctEngine.value!, - channelId: state.roomNumber.value, - isOpenCamera: state.isOpenCamera.value, - remoteUid: state.remoteUid.value, - users: state.cacheUsers.value.where((user) => user.enableCamera == true).toList(), - onHangUpTap: (){ - logic.hangUpVideo(); - }, - ) - : Container() - ), - - // 共享屏幕 - Visibility( - visible: state.pageState.value == 2, - child: null != state.rctEngine.value - ? MeetingMainShareComponent( - rtcEngine: state.rctEngine.value!, - channelId: state.roomNumber.value, - remoteUid: state.remoteUid.value, - ) - : Container() - ), - - GestureDetector( - child: Container( - width: 180.w, - height: 40.h, - margin: const EdgeInsets.only(left: 20, bottom: 40), - padding: const EdgeInsets.only(left: 20), - decoration: BoxDecoration( - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(56), - topRight: Radius.circular(50), - bottomRight: Radius.circular(50)), - color: ColorUtil.Color_35_35_35_07, - border: Border.all( - width: 1.w, - color: ColorUtil.Color_99_111_158 + /// 共享 + GestureDetector( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + state.isSpeak.value == true + ? state.isOpenShare.value == true + ? 'assets/images/meeting_main_share_open.png' + : 'assets/images/meeting_main_share_default.png' + : 'assets/images/meeting_main_share_close.png', + width: 22.w, + height: 22.h, + ), + SizedBox(height: 4.h), + Text( + '共享屏幕', + style: TextStyle( + fontSize: 12.sp, + color: ColorUtil.Color_202_202_202), + ) + ], ), + onTap: () { + if (state.isSpeak.value == true) { + if (state.isOpenShare.value == true) { + logic.setScreenShareOpen(false); + } else { + logic.setScreenShareOpen(true); + } + } + }, ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image.asset( - 'assets/images/meeting_main_chat.png', - width: 18.w, - height: 18.h, - ), - SizedBox(width: 6.w), - Text( - '说点什么...', - style: TextStyle( - fontSize: 14.sp, - color: ColorUtil.Color_156_156_156), - ) - ], - ), - ), - onTap: () { - Get.bottomSheet( - isScrollControlled: true, - chatBottomSheet(context) - ); - Future.delayed(const Duration(milliseconds: 100), () { - state.chatController.jumpTo(state.chatController.position.maxScrollExtent); - }); - }, - ) - ], - ), - ), - /// 底部布局 - Container( - width: double.infinity, - height: 84.h, - color: ColorUtil.Color_35_35_35, - padding: const EdgeInsets.only(left: 26, right: 26), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - /// 音频 - GestureDetector( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - state.isSpeak.value == false - ? Image.asset( - state.isSpeak.value == false - ? 'assets/images/meeting_main_sqfy.png' - : state.isOpenMicrophone.value == true - ? 'assets/images/meeting_main_microphone_default.png' - : 'assets/images/meeting_main_sqfy.png', - width: 20.w, - height: 20.h, - ) - : state.isOpenMicrophone.value == true - ? Container( - width: 20.w, - height: 20.h, - child: LiquidCustomProgressIndicator( - value: state.microphoneVolume.value, - valueColor: const AlwaysStoppedAnimation(ColorUtil.Color_2_177_136), - backgroundColor: ColorUtil.Color_255_255_255, - direction: Axis.vertical, - shapePath: ViewSvgPath.getMicrpphonePath() - ), - ) - : Image.asset( - 'assets/images/meeting_main_sqfy.png', - width: 20.w, - height: 20.h, - ) , - SizedBox(height: 4.h), - Text( - state.isSpeak.value == false ? '申请发言' : state.isOpenMicrophone.value == true ? "手动静音" : "解除静音", - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil.Color_202_202_202), - ) - ], - ), - onTap: () { - if(state.isSpeak.value == false){ - Get.bottomSheet( + /// 成员 + GestureDetector( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/meeting_main_member_default.png', + width: 22.w, + height: 22.h, + ), + SizedBox(height: 4.h), + Text( + ' 成员 ', + style: TextStyle( + fontSize: 12.sp, + color: ColorUtil.Color_202_202_202), + ) + ], + ), + onTap: () { + Get.bottomSheet( isScrollControlled: true, - applySpeakPermissionBottomSheet( - context) - ); - }else{ - if(state.isOpenMicrophone.value == false){ - logic.setMicrophoneOpen(true); - }else{ - logic.setMicrophoneOpen(false); - } - } - }, + queryMemberFloatingLayer(context), + ); + }, + ), + ], ), - - /// 视频 - GestureDetector( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - state.isSpeak.value == true ? state.isOpenCamera.value == true ? 'assets/images/meeting_main_camera_open.png' : 'assets/images/meeting_main_camera_default.png' : 'assets/images/meeting_main_sp.png', - width: 22.w, - height: 22.h, - ), - SizedBox(height: 4.h), - Text( - state.isOpenCamera.value == true ? "关闭视频" : "开启视频", - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil.Color_202_202_202), - ) - ], - ), - onTap: (){ - if(state.isSpeak.value == true){ - if(state.isOpenCamera.value == true){ - logic.setCameraOpen(false); - }else{ - logic.setCameraOpen(true); - } - } - }, - ), - - /// 共享 - GestureDetector( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - state.isSpeak.value == true ? state.isOpenShare.value == true ? 'assets/images/meeting_main_share_open.png' : 'assets/images/meeting_main_share_default.png' : 'assets/images/meeting_main_share_close.png', - width: 22.w, - height: 22.h, - ), - SizedBox(height: 4.h), - Text( - '共享屏幕', - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil.Color_202_202_202), - ) - ], - ), - onTap: (){ - if(state.isSpeak.value == true){ - if(state.isOpenShare.value == true){ - logic.setScreenShareOpen(false); - }else{ - logic.setScreenShareOpen(true); - } - } - }, - ), - - /// 成员 - GestureDetector( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/meeting_main_member_default.png', - width: 22.w, - height: 22.h, - ), - SizedBox(height: 4.h), - Text( - ' 成员 ', - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil.Color_202_202_202), - ) - ], - ), - onTap: () { - Get.bottomSheet( - isScrollControlled: true, - queryMemberFloatingLayer(context), - ); - }, - ), - ], - ), - ) + ) + ], + ), + meetingInfoFloatingLayer(), + meetingAudioFloatingLayer(), ], - ), - meetingInfoFloatingLayer(), - meetingAudioFloatingLayer(), - ], - ))); + ))); } /// 退出会议底部弹窗 @@ -448,7 +507,7 @@ class MeetingMainPage extends StatelessWidget { ), ), ), - onTap: (){ + onTap: () { Get.back(); Get.back(); }, @@ -470,7 +529,7 @@ class MeetingMainPage extends StatelessWidget { ), ), ), - onTap: (){ + onTap: () { Get.back(); }, ) @@ -617,7 +676,7 @@ class MeetingMainPage extends StatelessWidget { SizedBox(height: 10.h), GestureDetector( child: Container( - padding: const EdgeInsets.only(top:10, bottom: 10), + padding: const EdgeInsets.only(top: 10, bottom: 10), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -637,7 +696,7 @@ class MeetingMainPage extends StatelessWidget { ], ), ), - onTap: (){ + onTap: () { logic.changeMeetingInfoState(false); }, ) @@ -646,8 +705,8 @@ class MeetingMainPage extends StatelessWidget { ), Expanded( child: Container( - color: ColorUtil.Color_57_57_57_08, - )) + color: ColorUtil.Color_57_57_57_08, + )) ], ), ); @@ -661,15 +720,15 @@ class MeetingMainPage extends StatelessWidget { children: [ Expanded( child: Container( - color: ColorUtil.Color_57_57_57_08, - )), + color: ColorUtil.Color_57_57_57_08, + )), Container( color: ColorUtil.Color_57_57_57_08, child: Container( width: double.infinity, padding: const EdgeInsets.only(top: 16, bottom: 16), margin: const EdgeInsets.only(left: 40, right: 40), - decoration: BoxDecoration( + decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(6)), border: Border.all(color: ColorUtil.Color_0_0_0_0), color: ColorUtil.Color_35_35_35, @@ -681,8 +740,8 @@ class MeetingMainPage extends StatelessWidget { ), Expanded( child: Container( - color: ColorUtil.Color_57_57_57_08, - )) + color: ColorUtil.Color_57_57_57_08, + )) ], ), ); @@ -691,50 +750,52 @@ class MeetingMainPage extends StatelessWidget { /// 音频列表 List audioList() { List audioList = []; - audioList.add( - GestureDetector( - child: Column(children: [ + audioList.add(GestureDetector( + child: Column(children: [ + Text( + '听筒', + style: TextStyle( + fontSize: 14.sp, + fontWeight: state.communicationMode.value == 1 + ? FontWeight.w500 + : FontWeight.w400, + color: state.communicationMode.value == 1 + ? ColorUtil.Color_85_117_242 + : ColorUtil.Color_134_134_134), + ), + Container( + width: double.infinity, + height: 1.h, + color: ColorUtil.Color_49_47_47, + margin: const EdgeInsets.only(top: 14, bottom: 14), + ) + ]), + onTap: () { + logic.setEnableSpeakerphone(1); + logic.changeMeetingAudioState(false); + }, + )); + audioList.add(GestureDetector( + child: Column( + children: [ Text( - '听筒', + '扬声器', style: TextStyle( fontSize: 14.sp, - fontWeight: state.communicationMode.value == 1 ? FontWeight.w500 : FontWeight.w400, - color: state.communicationMode.value == 1 ? ColorUtil.Color_85_117_242 : ColorUtil.Color_134_134_134 - ), + fontWeight: state.communicationMode.value == 3 + ? FontWeight.w500 + : FontWeight.w400, + color: state.communicationMode.value == 3 + ? ColorUtil.Color_85_117_242 + : ColorUtil.Color_134_134_134), ), - Container( - width: double.infinity, - height: 1.h, - color: ColorUtil.Color_49_47_47, - margin: const EdgeInsets.only(top: 14, bottom: 14), - ) - ]), - onTap: (){ - logic.setEnableSpeakerphone(1); - logic.changeMeetingAudioState(false); - }, - ) - ); - audioList.add( - GestureDetector( - child: Column( - children: [ - Text( - '扬声器', - style: TextStyle( - fontSize: 14.sp, - fontWeight: state.communicationMode.value == 3 ? FontWeight.w500 : FontWeight.w400, - color: state.communicationMode.value == 3 ? ColorUtil.Color_85_117_242 : ColorUtil.Color_134_134_134 - ), - ), - ], - ), - onTap: (){ - logic.setEnableSpeakerphone(3); - logic.changeMeetingAudioState(false); - }, - ) - ); + ], + ), + onTap: () { + logic.setEnableSpeakerphone(3); + logic.changeMeetingAudioState(false); + }, + )); return audioList; } @@ -769,7 +830,7 @@ class MeetingMainPage extends StatelessWidget { width: 12.w, height: 12.h, ), - onTap: (){ + onTap: () { Get.back(); }, ) @@ -813,7 +874,7 @@ class MeetingMainPage extends StatelessWidget { ), ), ), - onTap: (){ + onTap: () { Get.back(); }, ), @@ -836,7 +897,7 @@ class MeetingMainPage extends StatelessWidget { ), ), ), - onTap: (){ + onTap: () { logic.doHttpApplySpeak(); Get.back(); }, @@ -881,7 +942,7 @@ class MeetingMainPage extends StatelessWidget { width: 12.w, height: 12.h, ), - onTap: (){ + onTap: () { Get.back(); }, ) @@ -900,8 +961,7 @@ class MeetingMainPage extends StatelessWidget { padding: const EdgeInsets.only(left: 12, right: 12), decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(12)), - border: Border.all( - width: 1.w, color: ColorUtil.Color_70_71_73), + border: Border.all(width: 1.w, color: ColorUtil.Color_70_71_73), ), child: Row( children: [ @@ -915,18 +975,16 @@ class MeetingMainPage extends StatelessWidget { child: TextField( controller: state.memberNameSearchController, style: TextStyle( - fontSize: 14.sp, - color: ColorUtil.Color_235_235_235 - ), - textInputAction: TextInputAction.search, + fontSize: 14.sp, color: ColorUtil.Color_235_235_235), + textInputAction: TextInputAction.search, decoration: InputDecoration( contentPadding: const EdgeInsets.all(0), - border: const OutlineInputBorder(borderSide: BorderSide.none), + border: const OutlineInputBorder( + borderSide: BorderSide.none), hintText: '输入用户名', hintStyle: TextStyle( - color: ColorUtil.Color_70_71_73, - fontSize: 14.sp)), - onSubmitted: (value){ + color: ColorUtil.Color_70_71_73, fontSize: 14.sp)), + onSubmitted: (value) { logic.searchMember(value); }, ), @@ -936,7 +994,7 @@ class MeetingMainPage extends StatelessWidget { ), Container( margin: - const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 16), + const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 16), child: Text( '会议中(${state.users.value.length})', style: TextStyle( @@ -945,11 +1003,10 @@ class MeetingMainPage extends StatelessWidget { color: ColorUtil.Color_85_117_242), ), ), - Expanded( child: ScrollConfiguration( behavior: CusBehavior(), - child: GetBuilder(builder: (controll){ + child: GetBuilder(builder: (controll) { return ListView.builder( itemBuilder: (context, index) { return Container( @@ -958,29 +1015,41 @@ class MeetingMainPage extends StatelessWidget { child: Column( children: [ Container( - padding: const EdgeInsets.only(left: 16, right: 16), + padding: + const EdgeInsets.only(left: 16, right: 16), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(100), - color: ColorUtil.Color_85_117_242 - ), + borderRadius: + BorderRadius.circular(100), + color: ColorUtil.Color_85_117_242), margin: const EdgeInsets.only(right: 8), width: 36.w, height: 36.h, alignment: Alignment.center, child: Text( - state.users.value[index].userName.length > 3 - ? state.users.value[index].userName.substring(state.users.value[index].userName.length - 2,state.users.value[index].userName.length) - : state.users.value[index].userName, + state.users.value[index].userName + .length > + 3 + ? state + .users.value[index].userName + .substring( + state.users.value[index] + .userName.length - + 2, + state.users.value[index] + .userName.length) + : state + .users.value[index].userName, style: TextStyle( fontSize: 12.sp, - color: ColorUtil.Color_244_244_244 - ), + color: + ColorUtil.Color_244_244_244), ), ), Text( @@ -992,7 +1061,14 @@ class MeetingMainPage extends StatelessWidget { ), SizedBox(width: 8.w), Visibility( - visible: state.users.value[index].roleId == "1" || state.users.value[index].roleId == "3" ? true : false, + visible: + state.users.value[index].roleId == + "1" || + state.users.value[index] + .roleId == + "3" + ? true + : false, child: Text( '主持人', style: TextStyle( @@ -1002,7 +1078,14 @@ class MeetingMainPage extends StatelessWidget { ), ), Visibility( - visible: state.users.value[index].roleId == "2" && state.users.value[index].isRoomManager == true ? true : false, + visible: + state.users.value[index].roleId == + "2" && + state.users.value[index] + .isRoomManager == + true + ? true + : false, child: Text( '发言人', style: TextStyle( @@ -1025,7 +1108,10 @@ class MeetingMainPage extends StatelessWidget { Container( margin: const EdgeInsets.only(left: 12), child: Image.asset( - state.users.value[index].enableMicr == true ? 'assets/images/meeting_main_microphone_default.png' : 'assets/images/meeting_main_microphone_close.png', + state.users.value[index].enableMicr == + true + ? 'assets/images/meeting_main_microphone_default.png' + : 'assets/images/meeting_main_microphone_close.png', width: 17.w, height: 17.h, ), @@ -1033,7 +1119,11 @@ class MeetingMainPage extends StatelessWidget { Container( margin: const EdgeInsets.only(left: 12), child: Image.asset( - state.users.value[index].enableCamera == true ? 'assets/images/meeting_main_camera_default.png' : 'assets/images/meeting_main_camera_close.png', + state.users.value[index] + .enableCamera == + true + ? 'assets/images/meeting_main_camera_default.png' + : 'assets/images/meeting_main_camera_close.png', width: 17.w, height: 17.h, ), @@ -1046,7 +1136,8 @@ class MeetingMainPage extends StatelessWidget { Container( width: double.infinity, height: 0.5.h, - margin: const EdgeInsets.only(top: 12, bottom: 12), + margin: + const EdgeInsets.only(top: 12, bottom: 12), color: ColorUtil.Color_49_47_47, ) ], @@ -1055,8 +1146,7 @@ class MeetingMainPage extends StatelessWidget { }, itemCount: state.users.value.length, ); - }) - ), + })), ) ], ), @@ -1068,7 +1158,8 @@ class MeetingMainPage extends StatelessWidget { return Container( height: 500.h, color: ColorUtil.Color_35_35_35, - padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + padding: + EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -1095,7 +1186,7 @@ class MeetingMainPage extends StatelessWidget { width: 12.w, height: 12.h, ), - onTap: (){ + onTap: () { Get.back(); }, ) @@ -1110,16 +1201,17 @@ class MeetingMainPage extends StatelessWidget { Expanded( child: ScrollConfiguration( behavior: CusBehavior(), - child: GetBuilder(builder: (controll){ + child: GetBuilder(builder: (controll) { return ListView.builder( controller: state.chatController, itemBuilder: (context, index) { - return state.meetingRoomMsgs.value[index].source == 0 ? chartItemToOthers(index) : chartItemToOwn(index); + return state.meetingRoomMsgs.value[index].source == 0 + ? chartItemToOthers(index) + : chartItemToOwn(index); }, itemCount: state.meetingRoomMsgs.value.length, ); - }) - ), + })), ), Container( width: double.infinity, @@ -1135,22 +1227,19 @@ class MeetingMainPage extends StatelessWidget { child: TextField( controller: state.sendMsgController, style: TextStyle( - fontSize: 14.sp, - color: ColorUtil.Color_235_235_235 - ), + fontSize: 14.sp, color: ColorUtil.Color_235_235_235), decoration: InputDecoration( contentPadding: const EdgeInsets.all(0), - border: const OutlineInputBorder(borderSide: BorderSide.none), + border: + const OutlineInputBorder(borderSide: BorderSide.none), hintText: '请输入内容...', hintStyle: TextStyle( - color: ColorUtil.Color_235_235_235, - fontSize: 14.sp) - ), - onSubmitted: (value){ - if(value.isNotEmpty){ + color: ColorUtil.Color_235_235_235, fontSize: 14.sp)), + onSubmitted: (value) { + if (value.isNotEmpty) { logic.sendMsg(value); state.sendMsgController.text = ""; - }else{ + } else { ToastUtils.showError("请输入内容"); } }, @@ -1163,7 +1252,7 @@ class MeetingMainPage extends StatelessWidget { } /// 聊天浮层-其他人消息 - Widget chartItemToOthers(int index){ + Widget chartItemToOthers(int index) { return Container( width: double.infinity, padding: const EdgeInsets.only(left: 16, right: 16), @@ -1174,64 +1263,59 @@ class MeetingMainPage extends StatelessWidget { children: [ Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(99), - color: ColorUtil.Color_85_117_242 - ), + borderRadius: BorderRadius.circular(99), + color: ColorUtil.Color_85_117_242), width: 50.w, height: 50.h, alignment: Alignment.center, child: Text( state.meetingRoomMsgs.value[index].userName.length > 3 - ? state.meetingRoomMsgs.value[index].userName.substring(state.meetingRoomMsgs.value[index].userName.length - 2,state.meetingRoomMsgs.value[index].userName.length) + ? state.meetingRoomMsgs.value[index].userName.substring( + state.meetingRoomMsgs.value[index].userName.length - 2, + state.meetingRoomMsgs.value[index].userName.length) : state.meetingRoomMsgs.value[index].userName, style: TextStyle( - fontSize: 14.sp, - color: ColorUtil.Color_244_244_244 - ), + fontSize: 14.sp, color: ColorUtil.Color_244_244_244), ), ), Expanded( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: const EdgeInsets.only(left: 6), - child: Text( - state.meetingRoomMsgs.value[index].userName, - style: TextStyle( - fontSize: 10.sp, - color: ColorUtil.Color_202_202_202), - ), - ), - Container( - margin: const EdgeInsets.only( - left: 6, top: 6, right: 16), - padding: const EdgeInsets.only( - left: 18, right: 18, top: 10, bottom: 10), - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(99), - topRight: Radius.circular(99), - bottomRight: Radius.circular(99)), - color: ColorUtil.Color_53_53_53, - ), - child: Text( - state.meetingRoomMsgs.value[index].message, - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil.Color_235_235_235), - ), - ) - ], + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: const EdgeInsets.only(left: 6), + child: Text( + state.meetingRoomMsgs.value[index].userName, + style: TextStyle( + fontSize: 10.sp, color: ColorUtil.Color_202_202_202), + ), + ), + Container( + margin: const EdgeInsets.only(left: 6, top: 6, right: 16), + padding: const EdgeInsets.only( + left: 18, right: 18, top: 10, bottom: 10), + decoration: const BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(99), + topRight: Radius.circular(99), + bottomRight: Radius.circular(99)), + color: ColorUtil.Color_53_53_53, + ), + child: Text( + state.meetingRoomMsgs.value[index].message, + style: TextStyle( + fontSize: 12.sp, color: ColorUtil.Color_235_235_235), + ), ) - ) + ], + )) ], ), ); } /// 聊天浮层-自己消息 - Widget chartItemToOwn(int index){ + Widget chartItemToOwn(int index) { return Container( width: double.infinity, padding: const EdgeInsets.only(left: 16, right: 16), @@ -1242,60 +1326,115 @@ class MeetingMainPage extends StatelessWidget { children: [ Expanded( child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Container( - margin: const EdgeInsets.only(right: 6), - child: Text( - state.meetingRoomMsgs.value[index].userName, - style: TextStyle( - fontSize: 10.sp, - color: ColorUtil.Color_202_202_202), - ), - ), - Container( - margin: const EdgeInsets.only( - left: 16, top: 6, right: 6), - padding: const EdgeInsets.only( - left: 18, right: 18, top: 10, bottom: 10), - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(99), - bottomLeft: Radius.circular(99), - bottomRight: Radius.circular(99) - ), - color: ColorUtil.Color_85_117_242, - ), - child: Text( - state.meetingRoomMsgs.value[index].message, - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil.Color_235_235_235), - ), - ) - ], + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Container( + margin: const EdgeInsets.only(right: 6), + child: Text( + state.meetingRoomMsgs.value[index].userName, + style: TextStyle( + fontSize: 10.sp, color: ColorUtil.Color_202_202_202), + ), + ), + Container( + margin: const EdgeInsets.only(left: 16, top: 6, right: 6), + padding: const EdgeInsets.only( + left: 18, right: 18, top: 10, bottom: 10), + decoration: const BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(99), + bottomLeft: Radius.circular(99), + bottomRight: Radius.circular(99)), + color: ColorUtil.Color_85_117_242, + ), + child: Text( + state.meetingRoomMsgs.value[index].message, + style: TextStyle( + fontSize: 12.sp, color: ColorUtil.Color_235_235_235), + ), ) - ), + ], + )), Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(99), - color: ColorUtil.Color_85_117_242 - ), + borderRadius: BorderRadius.circular(99), + color: ColorUtil.Color_85_117_242), width: 50.w, height: 50.h, alignment: Alignment.center, child: Text( state.meetingRoomMsgs.value[index].userName.length > 3 - ? state.meetingRoomMsgs.value[index].userName.substring(state.meetingRoomMsgs.value[index].userName.length - 2,state.meetingRoomMsgs.value[index].userName.length) + ? state.meetingRoomMsgs.value[index].userName.substring( + state.meetingRoomMsgs.value[index].userName.length - 2, + state.meetingRoomMsgs.value[index].userName.length) : state.meetingRoomMsgs.value[index].userName, style: TextStyle( - fontSize: 14.sp, - color: ColorUtil.Color_244_244_244 - ), + fontSize: 14.sp, color: ColorUtil.Color_244_244_244), ), ) ], ), ); } + + /// 自己视频预览悬浮窗 + Widget previewFloatingWidget(){ + return Stack( + children: [ + SizedBox( + width: 120, + height: 150, + child: Obx(() => Center( + child: state.isOpenCamera.value == true + ? AgoraVideoView( + controller: VideoViewController( + rtcEngine: state.rctEngine.value!, + canvas: const VideoCanvas(uid: 0), + ), + ) + : const CircularProgressIndicator(), + )), + ), + Positioned( + left: 4, + bottom: 4, + child: Row( + children: [ + Image.asset( + 'assets/images/meeting_main_own.png', + width: 20.w, + height: 15.h, + ), + Container( + height: 15, + margin: const EdgeInsets.only(left: 4), + padding: + const EdgeInsets.only(left: 4, right: 4), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(2), + color: ColorUtil.Color_0_0_0_96), + child: Row( + children: [ + /*Image.asset( + 'assets/images/meeting_main_microphone_open.png', + width: 13.w, + height: 14.h, + ), + SizedBox(width: 4.w),*/ + Text( + UserStore + .to.userInfoEntity.value!.userName, + style: TextStyle( + fontSize: 10.sp, + color: ColorUtil.Color_185_184_184), + ) + ], + ), + ) + ], + ), + ) + ], + ); + } } diff --git a/wgshare/lib/pages/metting/video/meeting_main_video_view.dart b/wgshare/lib/pages/metting/video/meeting_main_video_view.dart index e47ceb4..7b60b95 100644 --- a/wgshare/lib/pages/metting/video/meeting_main_video_view.dart +++ b/wgshare/lib/pages/metting/video/meeting_main_video_view.dart @@ -12,7 +12,7 @@ import 'meeting_main_video_logic.dart'; import 'meeting_main_video_state.dart'; class MeetingMainVideoComponent extends StatefulWidget { - MeetingMainVideoComponent({super.key, + const MeetingMainVideoComponent({super.key, required this.rtcEngine, required this.channelId, required this.isOpenCamera, @@ -115,7 +115,7 @@ class _MeetingMainVideoComponentState extends State w ), /// 右上角小窗 - Visibility( + /*Visibility( visible: widget.isOpenCamera, child: Positioned( top: 58, @@ -156,12 +156,12 @@ class _MeetingMainVideoComponentState extends State w color: ColorUtil.Color_0_0_0_96), child: Row( children: [ - /*Image.asset( + *//*Image.asset( 'assets/images/meeting_main_microphone_open.png', width: 13.w, height: 14.h, ), - SizedBox(width: 4.w),*/ + SizedBox(width: 4.w),*//* Text( UserStore .to.userInfoEntity.value!.userName, @@ -178,7 +178,7 @@ class _MeetingMainVideoComponentState extends State w ], ), ), - ) + )*/ ], ), Container( diff --git a/wgshare/pubspec.lock b/wgshare/pubspec.lock index dce5d0c..f824fbb 100644 --- a/wgshare/pubspec.lock +++ b/wgshare/pubspec.lock @@ -315,6 +315,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.0.5" + flutter_floating: + dependency: "direct main" + description: + name: flutter_floating + sha256: "0ff6a47c29a213c426005d248c6afe93fa76e308abbbbd6c8a35689daf11a997" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.8" flutter_hooks: dependency: "direct main" description: diff --git a/wgshare/pubspec.yaml b/wgshare/pubspec.yaml index 6145843..0409e45 100644 --- a/wgshare/pubspec.yaml +++ b/wgshare/pubspec.yaml @@ -79,6 +79,9 @@ dependencies: # 水波效果的进度器 liquid_progress_indicator_v2: ^0.5.0 + # 悬浮拖动组件 + flutter_floating: ^1.0.7 + dev_dependencies: flutter_test: sdk: flutter