1.增加socket和声网SDK断线重连相关提示弹窗

2.拦截会议室返回按钮,只能右上角弹窗点击“仅自己离开”退出会议
This commit is contained in:
fuenmao 2024-12-26 11:35:57 +08:00
parent 3b2e981d6b
commit fc9f72b88e
12 changed files with 540 additions and 245 deletions

View File

@ -1,9 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:date_format/date_format.dart'; import 'package:date_format/date_format.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:signalr_core/signalr_core.dart'; import 'package:signalr_core/signalr_core.dart';
import 'package:wgshare/common/store/user_store.dart'; import 'package:wgshare/common/store/user_store.dart';
@ -14,6 +16,7 @@ import '../../common/models/common/base_structure_result.dart';
import '../../common/models/meeting_room_info.dart'; import '../../common/models/meeting_room_info.dart';
import '../../common/models/meeting_room_msg.dart'; import '../../common/models/meeting_room_msg.dart';
import '../../common/models/meeting_room_user.dart'; import '../../common/models/meeting_room_user.dart';
import '../../utils/agora/AgoraUtil.dart';
import '../../utils/permission/PermissionService.dart'; import '../../utils/permission/PermissionService.dart';
import '../../utils/toast_utils.dart'; import '../../utils/toast_utils.dart';
import 'meeting_main_state.dart'; import 'meeting_main_state.dart';
@ -59,9 +62,11 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
/// ///
/// 1. /// 1.
/// 2. /// 2.
Future<void> mergeFetch() async { Future<void> mergeFetch(bool isAgain) async {
try { try {
ToastUtils.showLoading(); if(isAgain == false){
ToastUtils.showLoading();
}
var results = await Future.wait([ var results = await Future.wait([
getClient().getMeetingRoomInfo(state.roomNumber.value), getClient().getMeetingRoomInfo(state.roomNumber.value),
@ -238,12 +243,14 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
} }
} }
} else { } else {
if(state.remoteUid.value == UserStore.to.userInfoEntity.value!.screenShareId){ if (state.remoteUid.value ==
UserStore.to.userInfoEntity.value!.screenShareId) {
// //
}else{ } else {
// //
for (var i = 0; i < state.cacheUsers.value.length; i++) { for (var i = 0; i < state.cacheUsers.value.length; i++) {
if (state.remoteUid.value == state.cacheUsers.value[i].screenShareId) { if (state.remoteUid.value ==
state.cacheUsers.value[i].screenShareId) {
state.cacheUsers.value[i].enableShare = true; state.cacheUsers.value[i].enableShare = true;
} }
} }
@ -311,14 +318,51 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
accessTokenFactory: () async => accessTokenFactory: () async =>
await Future.value(UserStore.to.token), await Future.value(UserStore.to.token),
logging: (level, message) => logging: (level, message) =>
debugPrint("wgs输出===SignalR Socket-$message"), debugPrint("wgs输出===SignalR Socket-日志:$message"),
)) ))
// 线410 4 10 10 // 线52 4 4 5 10
.withAutomaticReconnect([10000, 4000, 10000, 10000]).build(); .withAutomaticReconnect([2000, 4000, 4000, 5000, 10000]).build();
await state.hubConnection.value?.start(); await state.hubConnection.value?.start();
joinMeetingToSocket(); //
state.hubConnection.value?.onreconnecting((error) {
debugPrint("wgs输出===SignalR Socket-重连$error");
if(EasyLoading.isShow == false) {
ToastUtils.showLoadingToMask("网络故障,正在重连...", EasyLoadingMaskType.black);
}
});
// 5
state.hubConnection.value?.onreconnected((connectionId) {
debugPrint("wgs输出===SignalR Socket-重连成功$connectionId");
joinMeetingToSocket(true);
ToastUtils.dismiss();
if(EasyLoading.isShow == false) {
ToastUtils.showSuccessToMask("重连成功!", EasyLoadingMaskType.black);
}
});
// 5
state.hubConnection.value?.onclose((error){
debugPrint("wgs输出===SignalR Socket-重连失败$error");
ToastUtils.dismiss();
if(state.isNormaExit.value == false && state.isShowOkAlertDialog.value == false){
showOkAlertDialog(
context: Get.context!,
title: "提示",
message: "网络错误,请重新加入会议室",
okLabel: "确定",
barrierDismissible: false,
).then((OkCancelResult value){
Get.back();
Get.back();
});
}
});
joinMeetingToSocket(false);
/// ------------------------------------------------------------------------------ /// ------------------------------------------------------------------------------
/// ///
@ -339,9 +383,9 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
if (UserStore.to.userInfoEntity.value!.uid == meetingRoomUser.uid) { if (UserStore.to.userInfoEntity.value!.uid == meetingRoomUser.uid) {
state.isSpeak.value = true; state.isSpeak.value = true;
state.defaulOpenState.value = 1; state.defaulOpenState.value = 1;
if(state.defaulOpenState.value == 1){ if (state.defaulOpenState.value == 1) {
state.isOpenMicrophone.value = true; state.isOpenMicrophone.value = true;
}else if(state.defaulOpenState.value == 2){ } else if (state.defaulOpenState.value == 2) {
doHttpSetCamer(true); doHttpSetCamer(true);
} }
// SDK角色为主播 // SDK角色为主播
@ -359,7 +403,6 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
} }
} }
if (UserStore.to.userInfoEntity.value!.uid == meetingRoomUser.uid) { if (UserStore.to.userInfoEntity.value!.uid == meetingRoomUser.uid) {
state.isSpeak.value = false; state.isSpeak.value = false;
state.defaulOpenState.value = 0; state.defaulOpenState.value = 0;
state.isOpenMicrophone.value = false; state.isOpenMicrophone.value = false;
@ -375,7 +418,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
// //
state.floating.value?.close(); state.floating.value?.close();
// //
if(state.remoteUid.value == "0"){ if (state.remoteUid.value == "0") {
state.remoteUid.value = ""; state.remoteUid.value = "";
changePageState(0); changePageState(0);
} }
@ -493,7 +536,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
var jsonStr = json.encode(e); var jsonStr = json.encode(e);
List list = json.decode(jsonStr); List list = json.decode(jsonStr);
DateTime dateTime = DateTime.now(); DateTime dateTime = DateTime.now();
MeetingRoomMsg meetingRoomMsg = MeetingRoomMsg(list[0], list[1], list[2], 0, formatDate(dateTime, [HH, ':', nn, ':', ss])); MeetingRoomMsg meetingRoomMsg = MeetingRoomMsg(list[0], list[1], list[2],
0, formatDate(dateTime, [HH, ':', nn, ':', ss]));
state.meetingRoomMsgs.value.add(meetingRoomMsg); state.meetingRoomMsgs.value.add(meetingRoomMsg);
update(); update();
Future.delayed(const Duration(milliseconds: 100), () { Future.delayed(const Duration(milliseconds: 100), () {
@ -576,10 +620,10 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
} }
/// ///
Future<void> joinMeetingToSocket() async { Future<void> joinMeetingToSocket(bool isAgain) async {
await state.hubConnection.value?.invoke("joinChannel", await state.hubConnection.value?.invoke("joinChannel",
args: [state.roomNumber.value, false, false, false]); args: [state.roomNumber.value, false, false, false]);
mergeFetch(); mergeFetch(isAgain);
} }
/// ///
@ -596,7 +640,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
UserStore.to.userInfoEntity.value!.uid, UserStore.to.userInfoEntity.value!.uid,
UserStore.to.userInfoEntity.value!.userName, UserStore.to.userInfoEntity.value!.userName,
msg, msg,
1, formatDate(dateTime, [HH, ':', nn, ':', ss])); 1,
formatDate(dateTime, [HH, ':', nn, ':', ss]));
state.meetingRoomMsgs.value.add(meetingRoomMsg); state.meetingRoomMsgs.value.add(meetingRoomMsg);
update(); update();
Future.delayed(const Duration(milliseconds: 100), () { Future.delayed(const Duration(milliseconds: 100), () {
@ -632,138 +677,178 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
await state.rctEngine.value?.enableAudioVolumeIndication( await state.rctEngine.value?.enableAudioVolumeIndication(
interval: 200, smooth: 3, reportVad: true); interval: 200, smooth: 3, reportVad: true);
// //
await state.rctEngine.value?.setDualStreamMode(mode: SimulcastStreamMode.enableSimulcastStream); await state.rctEngine.value
?.setDualStreamMode(mode: SimulcastStreamMode.enableSimulcastStream);
joinMeetingToRtc(); joinMeetingToRtc();
// //
state.rctEngine.value?.registerEventHandler( state.rctEngine.value?.registerEventHandler(
RtcEngineEventHandler( RtcEngineEventHandler(
// //
onJoinChannelSuccess: (RtcConnection connection, int elapsed) { onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
debugPrint("wgs输出===RTC-自己加入会议室ID${connection.localUid}"); debugPrint("wgs输出===RTC-自己加入会议室ID${connection.localUid}");
}, },
// //
onLeaveChannel: (RtcConnection connection, RtcStats stats) { onLeaveChannel: (RtcConnection connection, RtcStats stats) {
debugPrint("wgs输出===RTC-自己离开会议室ID${connection.localUid}"); debugPrint("wgs输出===RTC-自己离开会议室ID${connection.localUid}");
}, },
// - // -
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) { onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
debugPrint("wgs输出===RTC-远端用户或主播加入会议室用户或主机的ID$remoteUid"); debugPrint("wgs输出===RTC-远端用户或主播加入会议室用户或主机的ID$remoteUid");
}, },
// - // -
onUserOffline: (RtcConnection connection, int remoteUid, onUserOffline: (RtcConnection connection, int remoteUid,
UserOfflineReasonType reason) async { UserOfflineReasonType reason) async {
// //
if(remoteUid.toString().length == 9){ if (remoteUid.toString().length == 9) {
for (var i = 0; i < state.cacheUsers.value.length; i++) { for (var i = 0; i < state.cacheUsers.value.length; i++) {
if (remoteUid.toString() == state.cacheUsers.value[i].screenShareId) { if (remoteUid.toString() ==
state.cacheUsers.value[i].enableShare = false; state.cacheUsers.value[i].screenShareId) {
} state.cacheUsers.value[i].enableShare = false;
} }
} }
debugPrint("wgs输出===RTC-远端用户或主播离开会议室用户或主机的ID$remoteUid"); }
}, debugPrint("wgs输出===RTC-远端用户或主播离开会议室用户或主机的ID$remoteUid");
},
// //
onAudioRoutingChanged: (int routing) { onAudioRoutingChanged: (int routing) {
debugPrint("wgs输出===RTC-音频路由切换:$routing"); debugPrint("wgs输出===RTC-音频路由切换:$routing");
state.communicationMode.value = routing; state.communicationMode.value = routing;
if (routing == 1) { if (routing == 1) {
debugPrint("wgs输出===RTC-音频路由切换为听筒"); debugPrint("wgs输出===RTC-音频路由切换为听筒");
} else if (routing == 3) { } else if (routing == 3) {
debugPrint("wgs输出===RTC-音频路由切换为扬声器"); debugPrint("wgs输出===RTC-音频路由切换为扬声器");
} else {
debugPrint("wgs输出===RTC-音频路由切换为外接设备");
}
},
//
onLocalAudioStateChanged: (RtcConnection connection,
LocalAudioStreamState state, LocalAudioStreamReason reason) {
debugPrint("wgs输出===RTC-音频采集开关:$state");
},
//
onRemoteVideoStateChanged: (RtcConnection connection,
int remoteUid,
RemoteVideoState remoteVideoState,
RemoteVideoStateReason remoteVideoStateReason,
int elapsed) {
debugPrint(
"wgs输出===RTC-远端视频状态发生改变ID-$remoteUid-状态-$remoteVideoStateReason");
if (remoteVideoStateReason ==
RemoteVideoStateReason.remoteVideoStateReasonRemoteMuted) {
//
if (remoteUid.toString().length != 9) {
//
if (remoteUid.toString() == state.remoteUid.value) {
//
doHttpGetTvAnchor();
}
} else { } else {
debugPrint("wgs输出===RTC-音频路由切换为外接设备"); //
} }
}, }
},
// //
onLocalAudioStateChanged: (RtcConnection connection, onAudioVolumeIndication: (RtcConnection connection,
LocalAudioStreamState state, LocalAudioStreamReason reason) { List<AudioVolumeInfo> speakers,
debugPrint("wgs输出===RTC-音频采集开关:$state"); int speakerNumber,
}, int totalVolume) {
if (speakers.isNotEmpty) {
// for (AudioVolumeInfo avi in speakers) {
onRemoteVideoStateChanged: (RtcConnection connection, for (MeetingRoomUser mru in state.cacheUsers.value) {
int remoteUid, //
RemoteVideoState remoteVideoState, if (avi.uid == 0) {
RemoteVideoStateReason remoteVideoStateReason, //debugPrint("wgs输出===RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
int elapsed) { mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
debugPrint( state.microphoneVolume.value =
"wgs输出===RTC-远端视频状态发生改变ID-$remoteUid-状态-$remoteVideoStateReason"); CountMicrophoneVolume.getVolume(avi.volume!);
if (remoteVideoStateReason == } else {
RemoteVideoStateReason.remoteVideoStateReasonRemoteMuted) { if (avi.uid.toString() == mru.uid) {
// //debugPrint("wgs输出===RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
if (remoteUid.toString().length != 9) {
//
if (remoteUid.toString() == state.remoteUid.value) {
//
doHttpGetTvAnchor();
}
} else {
//
}
}
},
//
onAudioVolumeIndication: (RtcConnection connection,
List<AudioVolumeInfo> speakers,
int speakerNumber,
int totalVolume) {
if (speakers.isNotEmpty) {
for (AudioVolumeInfo avi in speakers) {
for (MeetingRoomUser mru in state.cacheUsers.value) {
//
if (avi.uid == 0) {
//debugPrint("wgs输出===RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!); mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
state.microphoneVolume.value =
CountMicrophoneVolume.getVolume(avi.volume!);
} else {
if (avi.uid.toString() == mru.uid) {
//debugPrint("wgs输出===RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
if (avi.volume != 0) { if (avi.volume != 0) {
state.spokesman.value = mru.userName; state.spokesman.value = mru.userName;
state.spokesmanVolume.value = state.spokesmanVolume.value =
CountMicrophoneVolume.getVolume(avi.volume!); CountMicrophoneVolume.getVolume(avi.volume!);
} else { } else {
state.spokesman.value = ""; state.spokesman.value = "";
state.spokesmanVolume.value = 0; state.spokesmanVolume.value = 0;
}
} }
} }
} }
} }
} }
}, }
},
// //
onClientRoleChanged: (RtcConnection connection, ClientRoleType oldRole, onClientRoleChanged: (RtcConnection connection,
ClientRoleType newRole, ClientRoleOptions newRoleOptions) { ClientRoleType oldRole,
debugPrint( ClientRoleType newRole,
"wgs输出===RTC-切换用户角色为:${newRole == ClientRoleType.clientRoleBroadcaster ? "主播" : "观众"}"); ClientRoleOptions newRoleOptions) {
}, debugPrint(
"wgs输出===RTC-切换用户角色为:${newRole == ClientRoleType.clientRoleBroadcaster ? "主播" : "观众"}");
},
// token即将在30秒内过期回调 // token即将在30秒内过期回调
onTokenPrivilegeWillExpire: (RtcConnection connection, String token) { onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
doHttpGetMeetingToken(false); doHttpGetMeetingToken(false);
}, },
// //
onLocalVideoStateChanged: (VideoSourceType source, onLocalVideoStateChanged: (VideoSourceType source,
LocalVideoStreamState state, LocalVideoStreamReason reason) { LocalVideoStreamState state, LocalVideoStreamReason reason) {
debugPrint("wgs输出===RTC-本地视频状态发生改变:$source--$state--$reason"); debugPrint("wgs输出===RTC-本地视频状态发生改变:$source--$state--$reason");
}, },
// //
/*onPermissionError: (PermissionType permissionType){ onConnectionStateChanged: (RtcConnection connection,
ConnectionStateType stateType, ConnectionChangedReasonType reason) {
debugPrint("wgs输出===RTC-网络连接状态发生改变:"
"会议室编号(${connection.channelId}"
"网络状态($stateType-${AgoraUtil.getConnectionStateChangedType(stateType)}"
"网络改变原因($reason-${AgoraUtil.getConnectionChangedReasonType(reason)}");
if(stateType == ConnectionStateType.connectionStateReconnecting){
if(EasyLoading.isShow == false){
ToastUtils.showLoadingToMask("网络故障,正在重连...", EasyLoadingMaskType.black);
}
}else if(stateType == ConnectionStateType.connectionStateConnected && reason == ConnectionChangedReasonType.connectionChangedRejoinSuccess){
ToastUtils.dismiss();
if(EasyLoading.isShow == false){
ToastUtils.showSuccessToMask("重连成功!", EasyLoadingMaskType.black);
}
}else if(reason == ConnectionChangedReasonType.connectionChangedLost){
// 15signalR Socket一致SDK继续重连
Future.delayed(const Duration(milliseconds: 15000), () {
ToastUtils.dismiss();
if(state.isShowOkAlertDialog.value == false){
showOkAlertDialog(
context: Get.context!,
title: "提示",
message: "网络错误,请重新加入会议室",
okLabel: "确定",
barrierDismissible: false,
).then((OkCancelResult value){
Get.back();
Get.back();
});
}
});
}
}
//
/*onPermissionError: (PermissionType permissionType){
debugPrint("wgs输出===RTC-获取设备权限出错:$permissionType"); debugPrint("wgs输出===RTC-获取设备权限出错:$permissionType");
if(permissionType == PermissionType.screenCapture){ if(permissionType == PermissionType.screenCapture){
// //
@ -771,7 +856,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
stopScreenCapture(); stopScreenCapture();
} }
}*/ }*/
), ),
); );
} }

View File

@ -46,6 +46,10 @@ class MeetingMainState {
/// ///
late Rx<MeetingRoomInfo?> meetingRoomInfo = Rx(null); late Rx<MeetingRoomInfo?> meetingRoomInfo = Rx(null);
/// showOkAlertDialog
late RxBool isShowOkAlertDialog = false.obs;
/// 退退
late RxBool isNormaExit = false.obs;
/// ///
late RxString duration = "".obs; late RxString duration = "".obs;

View File

@ -3,6 +3,7 @@ import 'dart:ui';
import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_floating/floating/assist/floating_slide_type.dart'; import 'package:flutter_floating/floating/assist/floating_slide_type.dart';
import 'package:flutter_floating/floating/floating.dart'; import 'package:flutter_floating/floating/floating.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -47,21 +48,24 @@ class MeetingMainPageState extends State<MeetingMainPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
state.context.value = context; state.context.value = context;
return Scaffold( return PopScope(
appBar: AppBar( canPop: false,
surfaceTintColor: ColorUtil.Color_41_41_41, child: FlutterEasyLoading(
elevation: 0, child: Scaffold(
toolbarHeight: 0, appBar: AppBar(
systemOverlayStyle: const SystemUiOverlayStyle( surfaceTintColor: ColorUtil.Color_41_41_41,
statusBarColor: Colors.transparent, elevation: 0,
systemNavigationBarColor: ColorUtil.Color_41_41_41, toolbarHeight: 0,
systemNavigationBarIconBrightness: Brightness.light, systemOverlayStyle: const SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light, statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light, systemNavigationBarColor: ColorUtil.Color_41_41_41,
), systemNavigationBarIconBrightness: Brightness.light,
backgroundColor: ColorUtil.Color_41_41_41, statusBarIconBrightness: Brightness.light,
), statusBarBrightness: Brightness.light,
body: Obx(() => Stack( ),
backgroundColor: ColorUtil.Color_41_41_41,
),
body: Obx(() => Stack(
children: [ children: [
Column( Column(
children: [ children: [
@ -201,76 +205,76 @@ class MeetingMainPageState extends State<MeetingMainPage> {
visible: state.pageState.value == 1, visible: state.pageState.value == 1,
child: null != state.rctEngine.value child: null != state.rctEngine.value
? Stack( ? Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
PreloadPageView.builder( PreloadPageView.builder(
preloadPagesCount: 2, preloadPagesCount: 2,
itemCount: 2, itemCount: 2,
itemBuilder: (BuildContext context, itemBuilder: (BuildContext context,
int position) => int position) =>
returnPage(position), returnPage(position),
controller: PreloadPageController( controller: PreloadPageController(
initialPage: 0), initialPage: 0),
onPageChanged: (int position) { onPageChanged: (int position) {
state.pageIndex.value = position; state.pageIndex.value = position;
if (state.isSpeak.value == true && if (state.isSpeak.value == true &&
state.isOpenCamera.value == state.isOpenCamera.value ==
true && true &&
state.remoteUid.value != "0") { state.remoteUid.value != "0") {
if (position == 0) { if (position == 0) {
state.floating.value state.floating.value
?.open(context); ?.open(context);
} else { } else {
state.floating.value?.close(); state.floating.value?.close();
} }
} }
}, },
), ),
/// pageview /// pageview
Positioned( Positioned(
bottom: 16, bottom: 16,
child: Row( child: Row(
children: [ children: [
Container( Container(
width: 8.w, width: 8.w,
height: 8.h, height: 8.h,
margin: const EdgeInsets.only( margin: const EdgeInsets.only(
right: 6), right: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius:
BorderRadius.circular( BorderRadius.circular(
8), 8),
color: state.pageIndex color: state.pageIndex
.value == .value ==
0 0
? ColorUtil ? ColorUtil
.Color_255_255_255 .Color_255_255_255
: ColorUtil : ColorUtil
.Color_108_108_108), .Color_108_108_108),
),
Container(
width: 8.w,
height: 8.h,
margin: const EdgeInsets.only(
left: 6),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
8),
color: state.pageIndex
.value ==
1
? ColorUtil
.Color_255_255_255
: ColorUtil
.Color_108_108_108),
)
],
),
), ),
Container(
width: 8.w,
height: 8.h,
margin: const EdgeInsets.only(
left: 6),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
8),
color: state.pageIndex
.value ==
1
? ColorUtil
.Color_255_255_255
: ColorUtil
.Color_108_108_108),
)
], ],
) ),
),
],
)
: Container()), : Container()),
Row( Row(
@ -295,7 +299,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
), ),
child: Row( child: Row(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Image.asset( Image.asset(
@ -373,44 +377,44 @@ class MeetingMainPageState extends State<MeetingMainPage> {
children: [ children: [
state.isSpeak.value == false state.isSpeak.value == false
? Image.asset( ? Image.asset(
state.isSpeak.value == false state.isSpeak.value == false
? 'assets/images/meeting_main_sqfy.png' ? 'assets/images/meeting_main_sqfy.png'
: state.isOpenMicrophone.value == : state.isOpenMicrophone.value ==
true true
? 'assets/images/meeting_main_microphone_default.png' ? 'assets/images/meeting_main_microphone_default.png'
: 'assets/images/meeting_main_sqfy.png', : 'assets/images/meeting_main_sqfy.png',
width: 20.w, width: 20.w,
height: 20.h, height: 20.h,
) )
: state.isOpenMicrophone.value == true : state.isOpenMicrophone.value == true
? Container( ? Container(
width: 20.w, width: 20.w,
height: 20.h, height: 20.h,
child: LiquidCustomProgressIndicator( child: LiquidCustomProgressIndicator(
value: state value: state
.microphoneVolume.value, .microphoneVolume.value,
valueColor: valueColor:
const AlwaysStoppedAnimation( const AlwaysStoppedAnimation(
ColorUtil ColorUtil
.Color_2_177_136), .Color_2_177_136),
backgroundColor: backgroundColor:
ColorUtil.Color_255_255_255, ColorUtil.Color_255_255_255,
direction: Axis.vertical, direction: Axis.vertical,
shapePath: ViewSvgPath shapePath: ViewSvgPath
.getMicrpphonePath()), .getMicrpphonePath()),
) )
: Image.asset( : Image.asset(
'assets/images/meeting_main_sqfy.png', 'assets/images/meeting_main_sqfy.png',
width: 20.w, width: 20.w,
height: 20.h, height: 20.h,
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
state.isSpeak.value == false state.isSpeak.value == false
? '申请发言' ? '申请发言'
: state.isOpenMicrophone.value == true : state.isOpenMicrophone.value == true
? "手动静音" ? "手动静音"
: "解除静音", : "解除静音",
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: ColorUtil.Color_202_202_202), color: ColorUtil.Color_202_202_202),
@ -441,8 +445,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
Image.asset( Image.asset(
state.isSpeak.value == true state.isSpeak.value == true
? state.isOpenCamera.value == true ? state.isOpenCamera.value == true
? 'assets/images/meeting_main_camera_open.png' ? 'assets/images/meeting_main_camera_open.png'
: 'assets/images/meeting_main_camera_default.png' : 'assets/images/meeting_main_camera_default.png'
: 'assets/images/meeting_main_sp.png', : 'assets/images/meeting_main_sp.png',
width: 22.w, width: 22.w,
height: 22.h, height: 22.h,
@ -545,7 +549,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
meetingInfoFloatingLayer(), meetingInfoFloatingLayer(),
meetingAudioFloatingLayer(), meetingAudioFloatingLayer(),
], ],
))); ))),
)
);
} }
/// 退 /// 退
@ -573,6 +579,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
), ),
), ),
onTap: () { onTap: () {
state.isNormaExit.value = true;
Get.back(); Get.back();
Get.back(); Get.back();
}, },

View File

@ -0,0 +1,110 @@
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
/// SDK相关工具类
class AgoraUtil{
///
static String getConnectionStateChangedType(ConnectionStateType type){
var returnTypeStr = "";
switch(type){
case ConnectionStateType.connectionStateDisconnected:
returnTypeStr = "网络连接断开";
break;
case ConnectionStateType.connectionStateConnecting:
returnTypeStr = "网络连接中";
break;
case ConnectionStateType.connectionStateConnected:
returnTypeStr = "网络已连接";
break;
case ConnectionStateType.connectionStateReconnecting:
returnTypeStr = "网络重新连接中";
break;
case ConnectionStateType.connectionStateFailed:
returnTypeStr = "网络连接失败";
break;
}
return returnTypeStr;
}
///
static String getConnectionChangedReasonType(ConnectionChangedReasonType type){
var returnTypeStr = "";
switch(type){
case ConnectionChangedReasonType.connectionChangedConnecting:
returnTypeStr = "建立网络连接中";
break;
case ConnectionChangedReasonType.connectionChangedJoinSuccess:
returnTypeStr = "成功加入频道";
break;
case ConnectionChangedReasonType.connectionChangedInterrupted:
returnTypeStr = "网络连接中断";
break;
case ConnectionChangedReasonType.connectionChangedBannedByServer:
returnTypeStr = "网络连接被服务器禁止";
break;
case ConnectionChangedReasonType.connectionChangedJoinFailed:
returnTypeStr = "加入频道失败";
break;
case ConnectionChangedReasonType.connectionChangedLeaveChannel:
returnTypeStr = "离开频道";
break;
case ConnectionChangedReasonType.connectionChangedInvalidAppId:
returnTypeStr = "App ID 无效";
break;
case ConnectionChangedReasonType.connectionChangedInvalidChannelName:
returnTypeStr = "频道名无效";
break;
case ConnectionChangedReasonType.connectionChangedInvalidToken:
returnTypeStr = "Token 无效";
break;
case ConnectionChangedReasonType.connectionChangedTokenExpired:
returnTypeStr = "当前使用的 Token 已过期";
break;
case ConnectionChangedReasonType.connectionChangedRejectedByServer:
returnTypeStr = "此用户被服务器禁止";
break;
case ConnectionChangedReasonType.connectionChangedSettingProxyServer:
returnTypeStr = "设置了代理服务器";
break;
case ConnectionChangedReasonType.connectionChangedRenewToken:
returnTypeStr = "更新 Token 引起网络连接状态改变";
break;
case ConnectionChangedReasonType.connectionChangedClientIpAddressChanged:
returnTypeStr = "客户端 IP 地址变更";
break;
case ConnectionChangedReasonType.connectionChangedKeepAliveTimeout:
returnTypeStr = "SDK 和服务器连接保活超时";
break;
case ConnectionChangedReasonType.connectionChangedRejoinSuccess:
returnTypeStr = "重新加入频道成功";
break;
case ConnectionChangedReasonType.connectionChangedLost:
returnTypeStr = "SDK 和服务器失去连接";
break;
case ConnectionChangedReasonType.connectionChangedEchoTest:
returnTypeStr = "连接状态变化由回声测试引起";
break;
case ConnectionChangedReasonType.connectionChangedClientIpAddressChangedByUser:
returnTypeStr = "本地 IP 地址被用户更改";
break;
case ConnectionChangedReasonType.connectionChangedSameUidLogin:
returnTypeStr = "使用相同的 UID 从不同的设备加入同一频道";
break;
case ConnectionChangedReasonType.connectionChangedTooManyBroadcasters:
returnTypeStr = "频道内主播人数已达上限";
break;
case ConnectionChangedReasonType.connectionChangedLicenseValidationFailure:
returnTypeStr = "连接已更改许可证验证失败";
break;
case ConnectionChangedReasonType.connectionChangedCertificationVeryfyFailure:
returnTypeStr = "连接已更改认证版本失败";
break;
case ConnectionChangedReasonType.connectionChangedStreamChannelNotAvailable:
returnTypeStr = "连接已更改流通道不可用";
break;
case ConnectionChangedReasonType.connectionChangedInconsistentAppid:
returnTypeStr = "连接已更改不一致Appid";
break;
}
return returnTypeStr;
}
}

View File

@ -51,6 +51,10 @@ class ToastUtils {
EasyLoading.showError(showMsg, duration: duration); EasyLoading.showError(showMsg, duration: duration);
} }
static showLoadingToMask(String str, EasyLoadingMaskType maskType) {
EasyLoading.show(status: str, maskType: maskType);
}
static showLoading() { static showLoading() {
EasyLoading.show(status: 'loading...'); EasyLoading.show(status: 'loading...');
} }
@ -63,6 +67,10 @@ class ToastUtils {
EasyLoading.showInfo(showMsg, duration: Duration(microseconds: microseconds)); EasyLoading.showInfo(showMsg, duration: Duration(microseconds: microseconds));
} }
static showSuccessToMask(String showMsg, EasyLoadingMaskType maskType, {Duration? duration}) {
EasyLoading.showSuccess(showMsg, maskType: maskType, duration: duration);
}
static showSuccess(String showMsg, {Duration? duration}) { static showSuccess(String showMsg, {Duration? duration}) {
EasyLoading.showSuccess(showMsg, duration: duration); EasyLoading.showSuccess(showMsg, duration: duration);
} }

View File

@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
} }

View File

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -6,20 +6,28 @@ import FlutterMacOS
import Foundation import Foundation
import agora_rtc_engine import agora_rtc_engine
import appkit_ui_element_colors
import device_info_plus import device_info_plus
import dynamic_color
import flutter_inappwebview_macos import flutter_inappwebview_macos
import geolocator_apple import geolocator_apple
import iris_method_channel import iris_method_channel
import macos_ui
import macos_window_utils
import package_info_plus import package_info_plus
import path_provider_foundation import path_provider_foundation
import sqflite_darwin import sqflite_darwin
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AgoraRtcNgPlugin.register(with: registry.registrar(forPlugin: "AgoraRtcNgPlugin")) AgoraRtcNgPlugin.register(with: registry.registrar(forPlugin: "AgoraRtcNgPlugin"))
AppkitUiElementColorsPlugin.register(with: registry.registrar(forPlugin: "AppkitUiElementColorsPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
IrisMethodChannelPlugin.register(with: registry.registrar(forPlugin: "IrisMethodChannelPlugin")) IrisMethodChannelPlugin.register(with: registry.registrar(forPlugin: "IrisMethodChannelPlugin"))
MacOSUiPlugin.register(with: registry.registrar(forPlugin: "MacOSUiPlugin"))
MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))

View File

@ -14,6 +14,14 @@ packages:
description: dart description: dart
source: sdk source: sdk
version: "0.3.2" version: "0.3.2"
adaptive_dialog:
dependency: "direct main"
description:
name: adaptive_dialog
sha256: a87f9e13fdbe0b11d353733a90796129ee79fc0654a27855fa2c9c0a3633a362
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.0"
agora_rtc_engine: agora_rtc_engine:
dependency: "direct main" dependency: "direct main"
description: description:
@ -30,6 +38,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.7.0" version: "6.7.0"
animations:
dependency: transitive
description:
name: animations
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.11"
appkit_ui_element_colors:
dependency: transitive
description:
name: appkit_ui_element_colors
sha256: c3e50f900aae314d339de489535736238627071457c4a4a2dbbb1545b4f04f22
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -254,6 +278,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
dynamic_color:
dependency: transitive
description:
name: dynamic_color
sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.7.0"
easy_debounce: easy_debounce:
dependency: "direct main" dependency: "direct main"
description: description:
@ -554,6 +586,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
gradient_borders:
dependency: transitive
description:
name: gradient_borders
sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
@ -594,6 +634,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
intersperse:
dependency: transitive
description:
name: intersperse
sha256: "2f8a905c96f6cbba978644a3d5b31b8d86ddc44917662df7d27a61f3df66a576"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
intl: intl:
dependency: transitive dependency: transitive
description: description:
@ -698,6 +746,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
macos_ui:
dependency: transitive
description:
name: macos_ui
sha256: "80f6539aba5a3a1182d5225a6c27969a780bcb1d2d8135b4ffb708570cf0c854"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.9"
macos_window_utils:
dependency: transitive
description:
name: macos_window_utils
sha256: "3534f2af024f2f24112ca28789a44e6750083f8c0065414546c6593ee48a5009"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.1"
macros: macros:
dependency: transitive dependency: transitive
description: description:

View File

@ -33,8 +33,6 @@ dependencies:
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8 cupertino_icons: ^1.0.8
@ -86,12 +84,14 @@ dependencies:
preload_page_view: ^0.2.0 preload_page_view: ^0.2.0
# webview # webview
#webview_flutter: ^3.0.4
flutter_inappwebview: ^6.1.5 flutter_inappwebview: ^6.1.5
# 时间组件 # 时间组件
date_format: ^2.0.9 date_format: ^2.0.9
# 弹窗
adaptive_dialog: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter

View File

@ -7,6 +7,7 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <agora_rtc_engine/agora_rtc_engine_plugin.h> #include <agora_rtc_engine/agora_rtc_engine_plugin.h>
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h> #include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <geolocator_windows/geolocator_windows.h> #include <geolocator_windows/geolocator_windows.h>
#include <iris_method_channel/iris_method_channel_plugin_c_api.h> #include <iris_method_channel/iris_method_channel_plugin_c_api.h>
@ -15,6 +16,8 @@
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
AgoraRtcEnginePluginRegisterWithRegistrar( AgoraRtcEnginePluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AgoraRtcEnginePlugin")); registry->GetRegistrarForPlugin("AgoraRtcEnginePlugin"));
DynamicColorPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
GeolocatorWindowsRegisterWithRegistrar( GeolocatorWindowsRegisterWithRegistrar(

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
agora_rtc_engine agora_rtc_engine
dynamic_color
flutter_inappwebview_windows flutter_inappwebview_windows
geolocator_windows geolocator_windows
iris_method_channel iris_method_channel