Sorry for that,
here is the updated code
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_zoom_videosdk/flutter_zoom_view.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk_event_listener.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk_live_transcription_message_info.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk_share_action.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk_user.dart';
import 'package:flutter_zoom_videosdk_example/utils/jwt.dart';
import 'package:google_fonts/google_fonts.dart';
import '../components/video_view.dart';
import 'intro_screen.dart';
import 'join_screen.dart';
class CallScreen extends StatefulHookWidget {
const CallScreen({Key? key}) : super(key: key);
@override
State<CallScreen> createState() => _CallScreenState();
}
class _CallScreenState extends State<CallScreen> {
double opacityLevel = 1.0;
void _changeOpacity() {
setState(() => opacityLevel = opacityLevel == 0 ? 1.0 : 0.0);
}
@override
Widget build(BuildContext context) {
var zoom = ZoomVideoSdk();
var eventListener = ZoomVideoSdkEventListener();
var isInSession = useState(false);
var sessionName = useState('');
var sessionPassword = useState('');
var users = useState(<ZoomVideoSdkUser>[]);
var fullScreenUser = useState<ZoomVideoSdkUser?>(null);
var sharingUser = useState<ZoomVideoSdkUser?>(null);
var isSharing = useState(false);
var isMuted = useState(true);
var isVideoOn = useState(false);
var isSpeakerOn = useState(false);
var isRecordingStarted = useState(false);
var isMounted = useIsMounted();
var audioStatusFlag = useState(false);
var videoStatusFlag = useState(false);
var userNameFlag = useState(false);
var userShareStatusFlag = useState(false);
var isReceiveSpokenLanguageContentEnabled = useState(false);
var isPiPView = useState(false);
var isSharedCamera = useState(false);
CameraShareView cameraShareView = const CameraShareView(creationParams: {});
//hide status bar
SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack);
Color backgroundColor = const Color(0xFF232323);
final args = ModalRoute.of(context)!.settings.arguments as CallArguments;
useEffect(() {
Future<void>.microtask(() async {
var token = generateJwt(args.sessionName, args.role);
try {
Map<String, bool> SDKaudioOptions = {"connect": true, "mute": true, "autoAdjustSpeakerVolume": false};
Map<String, bool> SDKvideoOptions = {
"localVideoOn": true,
};
JoinSessionConfig joinSession = JoinSessionConfig(
sessionName: args.sessionName,
sessionPassword: args.sessionPwd,
token: token,
userName: args.displayName,
audioOptions: SDKaudioOptions,
videoOptions: SDKvideoOptions,
sessionIdleTimeoutMins: int.parse(args.sessionIdleTimeoutMins),
);
await zoom.joinSession(joinSession);
} catch (e) {
const AlertDialog(
title: Text("Error"),
content: Text("Failed to join the session"),
);
Future.delayed(const Duration(milliseconds: 1000)).asStream().listen((event) {
Navigator.popAndPushNamed(
context,
"Join",
arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
);
});
}
});
return null;
}, []);
useEffect(() {
final sessionJoinListener = eventListener.addListener(EventType.onSessionJoin, (data) async {
data = data as Map;
isInSession.value = true;
zoom.session.getSessionName().then((value) => sessionName.value = value!);
sessionPassword.value = await zoom.session.getSessionPassword();
debugPrint("sessionPhonePasscode: ${await zoom.session.getSessionPhonePasscode()}");
ZoomVideoSdkUser mySelf = ZoomVideoSdkUser.fromJson(jsonDecode(data['sessionUser']));
List<ZoomVideoSdkUser>? remoteUsers = await zoom.session.getRemoteUsers();
var muted = await mySelf.audioStatus?.isMuted();
var videoOn = await mySelf.videoStatus?.isOn();
var speakerOn = await zoom.audioHelper.getSpeakerStatus();
fullScreenUser.value = mySelf;
remoteUsers?.insert(0, mySelf);
isMuted.value = muted!;
isSpeakerOn.value = speakerOn;
isVideoOn.value = videoOn!;
users.value = remoteUsers!;
isReceiveSpokenLanguageContentEnabled.value = await zoom.liveTranscriptionHelper.isReceiveSpokenLanguageContentEnabled();
});
final sessionLeaveListener = eventListener.addListener(EventType.onSessionLeave, (data) async {
data = data as Map;
debugPrint("onSessionLeave: ${data['reason']}");
isInSession.value = false;
users.value = <ZoomVideoSdkUser>[];
fullScreenUser.value = null;
Navigator.popAndPushNamed(
context,
"Join",
arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
);
});
final sessionNeedPasswordListener = eventListener.addListener(EventType.onSessionNeedPassword, (data) async {
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Session Need Password'),
content: const Text('Password is required'),
actions: <Widget>[
TextButton(
onPressed: () async => {
Navigator.popAndPushNamed(context, 'Join',
arguments: JoinArguments(args.isJoin, args.sessionName, "", args.displayName, args.sessionIdleTimeoutMins, args.role)),
await zoom.leaveSession(false),
},
child: const Text('OK'),
),
],
),
);
});
final sessionPasswordWrongListener = eventListener.addListener(EventType.onSessionPasswordWrong, (data) async {
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Session Password Incorrect'),
content: const Text('Password is wrong'),
actions: <Widget>[
TextButton(
onPressed: () async => {
Navigator.popAndPushNamed(context, 'Join',
arguments: JoinArguments(args.isJoin, args.sessionName, "", args.displayName, args.sessionIdleTimeoutMins, args.role)),
await zoom.leaveSession(false),
},
child: const Text('OK'),
),
],
),
);
});
final userVideoStatusChangedListener = eventListener.addListener(EventType.onUserVideoStatusChanged, (data) async {
data = data as Map;
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
var userListJson = jsonDecode(data['changedUsers']) as List;
List<ZoomVideoSdkUser> userList = userListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
for (var user in userList) {
{
if (user.userId == mySelf?.userId) {
mySelf?.videoStatus?.isOn().then((on) => isVideoOn.value = on);
}
}
}
videoStatusFlag.value = !videoStatusFlag.value;
});
final userAudioStatusChangedListener = eventListener.addListener(EventType.onUserAudioStatusChanged, (data) async {
data = data as Map;
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
var userListJson = jsonDecode(data['changedUsers']) as List;
List<ZoomVideoSdkUser> userList = userListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
for (var user in userList) {
{
if (user.userId == mySelf?.userId) {
mySelf?.audioStatus?.isMuted().then((muted) => isMuted.value = muted);
}
}
}
audioStatusFlag.value = !audioStatusFlag.value;
});
final userShareStatusChangeListener = eventListener.addListener(EventType.onUserShareStatusChanged, (data) async {
data = data as Map;
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
ZoomVideoSdkUser shareUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['user'].toString()));
ZoomVideoSdkShareAction? shareAction = ZoomVideoSdkShareAction.fromJson(jsonDecode(data['shareAction']));
if (shareAction.shareStatus == ShareStatus.Start || shareAction.shareStatus == ShareStatus.Resume) {
sharingUser.value = shareUser;
fullScreenUser.value = shareUser;
isSharing.value = (shareUser.userId == mySelf?.userId);
} else {
sharingUser.value = null;
isSharing.value = false;
isSharedCamera.value = false;
fullScreenUser.value = mySelf;
}
userShareStatusFlag.value = !userShareStatusFlag.value;
});
final shareContentChangedListener = eventListener.addListener(EventType.onShareContentChanged, (data) async {
data = data as Map;
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
ZoomVideoSdkUser shareUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['user'].toString()));
ZoomVideoSdkShareAction? shareAction = ZoomVideoSdkShareAction.fromJson(jsonDecode(data['shareAction']));
if (shareAction.shareType == ShareType.Camera) {
debugPrint("Camera share started");
isSharedCamera.value = (shareUser.userId == mySelf?.userId);
}
});
final userJoinListener = eventListener.addListener(EventType.onUserJoin, (data) async {
if (!isMounted()) return;
data = data as Map;
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
var userListJson = jsonDecode(data['remoteUsers']) as List;
List<ZoomVideoSdkUser> remoteUserList = userListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
remoteUserList.insert(0, mySelf!);
users.value = remoteUserList;
});
final userLeaveListener = eventListener.addListener(EventType.onUserLeave, (data) async {
if (!isMounted()) return;
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
data = data as Map;
List<ZoomVideoSdkUser>? remoteUserList = await zoom.session.getRemoteUsers();
var leftUserListJson = jsonDecode(data['leftUsers']) as List;
List<ZoomVideoSdkUser> leftUserLis = leftUserListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
if (fullScreenUser.value != null) {
for (var user in leftUserLis) {
{
if (fullScreenUser.value?.userId == user.userId) {
fullScreenUser.value = mySelf;
}
}
}
} else {
fullScreenUser.value = mySelf;
}
remoteUserList?.add(mySelf!);
users.value = remoteUserList!;
});
final userNameChangedListener = eventListener.addListener(EventType.onUserNameChanged, (data) async {
if (!isMounted()) return;
data = data as Map;
ZoomVideoSdkUser? changedUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['changedUser']));
int index;
for (var user in users.value) {
if (user.userId == changedUser.userId) {
index = users.value.indexOf(user);
users.value[index] = changedUser;
}
}
userNameFlag.value = !userNameFlag.value;
});
final commandReceived = eventListener.addListener(EventType.onCommandReceived, (data) async {
data = data as Map;
debugPrint("sender: ${ZoomVideoSdkUser.fromJson(jsonDecode(data['sender']))}, command: ${data['command']}");
});
final liveStreamStatusChangeListener = eventListener.addListener(EventType.onLiveStreamStatusChanged, (data) async {
data = data as Map;
debugPrint("onLiveStreamStatusChanged: status: ${data['status']}");
});
final liveTranscriptionStatusChangeListener = eventListener.addListener(EventType.onLiveTranscriptionStatus, (data) async {
data = data as Map;
debugPrint("onLiveTranscriptionStatus: status: ${data['status']}");
});
final cloudRecordingStatusListener = eventListener.addListener(EventType.onCloudRecordingStatus, (data) async {
data = data as Map;
debugPrint("onCloudRecordingStatus: status: ${data['status']}");
ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
if (data['status'] == RecordingStatus.Start) {
if (mySelf != null && !mySelf.isHost!) {
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
content: const Text('The session is being recorded.'),
actions: <Widget>[
TextButton(
onPressed: () async {
await zoom.acceptRecordingConsent();
if (context.mounted) {
Navigator.pop(context);
}
;
},
child: const Text('accept'),
),
TextButton(
onPressed: () async {
String currentConsentType = await zoom.getRecordingConsentType();
if (currentConsentType == ConsentType.ConsentType_Individual) {
await zoom.declineRecordingConsent();
Navigator.pop(context);
} else {
await zoom.declineRecordingConsent();
zoom.leaveSession(false);
if (!context.mounted) return;
Navigator.popAndPushNamed(
context,
"Join",
arguments:
JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
);
}
},
child: const Text('decline'),
),
],
),
);
}
isRecordingStarted.value = true;
} else {
isRecordingStarted.value = false;
}
});
final liveTranscriptionMsgInfoReceivedListener = eventListener.addListener(EventType.onLiveTranscriptionMsgInfoReceived, (data) async {
data = data as Map;
ZoomVideoSdkLiveTranscriptionMessageInfo? messageInfo = ZoomVideoSdkLiveTranscriptionMessageInfo.fromJson(jsonDecode(data['messageInfo']));
debugPrint("onLiveTranscriptionMsgInfoReceived: content: ${messageInfo.messageContent}");
});
final inviteByPhoneStatusListener = eventListener.addListener(EventType.onInviteByPhoneStatus, (data) async {
data = data as Map;
debugPrint("onInviteByPhoneStatus: status: ${data['status']}, reason: ${data['reason']}");
});
final multiCameraStreamStatusChangedListener = eventListener.addListener(EventType.onMultiCameraStreamStatusChanged, (data) async {
data = data as Map;
ZoomVideoSdkUser? changedUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['changedUser']));
var status = data['status'];
for (var user in users.value) {
{
if (changedUser.userId == user.userId) {
if (status == MultiCameraStreamStatus.Joined) {
user.hasMultiCamera = true;
} else if (status == MultiCameraStreamStatus.Left) {
user.hasMultiCamera = false;
}
}
}
}
});
final requireSystemPermission = eventListener.addListener(EventType.onRequireSystemPermission, (data) async {
data = data as Map;
ZoomVideoSdkUser? changedUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['changedUser']));
var permissionType = data['permissionType'];
switch (permissionType) {
case SystemPermissionType.Camera:
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text("Can't Access Camera"),
content: const Text("please turn on the toggle in system settings to grant permission"),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'OK'),
child: const Text('OK'),
),
],
),
);
break;
case SystemPermissionType.Microphone:
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text("Can't Access Microphone"),
content: const Text("please turn on the toggle in system settings to grant permission"),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'OK'),
child: const Text('OK'),
),
],
),
);
break;
}
});
final networkStatusChangeListener = eventListener.addListener(EventType.onUserVideoNetworkStatusChanged, (data) async {
data = data as Map;
ZoomVideoSdkUser? networkUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['user']));
if (data['status'] == NetworkStatus.Bad) {
debugPrint("onUserVideoNetworkStatusChanged: status: ${data['status']}, user: ${networkUser.userName}");
}
});
final eventErrorListener = eventListener.addListener(EventType.onError, (data) async {
data = data as Map;
String errorType = data['errorType'];
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text("Error"),
content: Text(errorType),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'OK'),
child: const Text('OK'),
),
],
),
);
if (errorType == Errors.SessionJoinFailed || errorType == Errors.SessionDisconnecting) {
Timer(
const Duration(milliseconds: 1000),
() => {
Navigator.popAndPushNamed(
context,
"Join",
arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
),
});
}
});
final userRecordingConsentListener = eventListener.addListener(EventType.onUserRecordingConsent, (data) async {
data = data as Map;
ZoomVideoSdkUser? user = ZoomVideoSdkUser.fromJson(jsonDecode(data['user']));
debugPrint('userRecordingConsentListener: user= ${user.userName}');
});
final callCRCDeviceStatusListener = eventListener.addListener(EventType.onCallCRCDeviceStatusChanged, (data) async {
data = data as Map;
debugPrint('onCallCRCDeviceStatusChanged: status = ${data['status']}');
});
final originalLanguageMsgReceivedListener = eventListener.addListener(EventType.onOriginalLanguageMsgReceived, (data) async {
data = data as Map;
ZoomVideoSdkLiveTranscriptionMessageInfo? messageInfo = ZoomVideoSdkLiveTranscriptionMessageInfo.fromJson(jsonDecode(data['messageInfo']));
debugPrint("onOriginalLanguageMsgReceived: content: ${messageInfo.messageContent}");
});
final chatPrivilegeChangedListener = eventListener.addListener(EventType.onChatPrivilegeChanged, (data) async {
data = data as Map;
String type = data['privilege'];
debugPrint('chatPrivilegeChangedListener: type= $type');
});
final testMicStatusListener = eventListener.addListener(EventType.onTestMicStatusChanged, (data) async {
data = data as Map;
String status = data['status'];
debugPrint('testMicStatusListener: status= $status');
});
final micSpeakerVolumeChangedListener = eventListener.addListener(EventType.onMicSpeakerVolumeChanged, (data) async {
data = data as Map;
int type = data['micVolume'];
debugPrint('onMicSpeakerVolumeChanged: micVolume= $type, speakerVolume');
});
final cameraControlRequestResultListener = eventListener.addListener(EventType.onCameraControlRequestResult, (data) async {
data = data as Map;
bool approved = data['approved'];
debugPrint('onCameraControlRequestResult: approved= $approved');
});
final callOutUserJoinListener = eventListener.addListener(EventType.onCalloutJoinSuccess, (data) async {
data = data as Map;
String phoneNumber = data['phoneNumber'];
ZoomVideoSdkUser? user = ZoomVideoSdkUser.fromJson(jsonDecode(data['user']));
debugPrint('onCalloutJoinSuccess: phoneNumber= $phoneNumber, user= ${user.userName}');
});
return () => {
sessionJoinListener.cancel(),
sessionLeaveListener.cancel(),
sessionPasswordWrongListener.cancel(),
sessionNeedPasswordListener.cancel(),
userVideoStatusChangedListener.cancel(),
userAudioStatusChangedListener.cancel(),
userJoinListener.cancel(),
userLeaveListener.cancel(),
userNameChangedListener.cancel(),
userShareStatusChangeListener.cancel(),
liveStreamStatusChangeListener.cancel(),
cloudRecordingStatusListener.cancel(),
inviteByPhoneStatusListener.cancel(),
eventErrorListener.cancel(),
commandReceived.cancel(),
liveTranscriptionStatusChangeListener.cancel(),
liveTranscriptionMsgInfoReceivedListener.cancel(),
multiCameraStreamStatusChangedListener.cancel(),
requireSystemPermission.cancel(),
userRecordingConsentListener.cancel(),
networkStatusChangeListener.cancel(),
callCRCDeviceStatusListener.cancel(),
originalLanguageMsgReceivedListener.cancel(),
chatPrivilegeChangedListener.cancel(),
testMicStatusListener.cancel(),
micSpeakerVolumeChangedListener.cancel(),
cameraControlRequestResultListener.cancel(),
callOutUserJoinListener.cancel(),
shareContentChangedListener.cancel(),
};
}, [zoom, users.value, isMounted]);
void onSelectedUserVolume(ZoomVideoSdkUser user) async {
var isShareAudio = user.isSharing;
bool canSetVolume = await user.canSetUserVolume(user.userId, isShareAudio);
num userVolume;
List<ListTile> options = [
ListTile(
title: Text(
'Adjust Volume',
style: GoogleFonts.lato(
textStyle: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
),
),
ListTile(
title: Text(
'Current volume',
style: GoogleFonts.lato(
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.black,
),
),
),
onTap: () async => {
debugPrint('user volume'),
userVolume = await user.getUserVolume(user.userId, isShareAudio),
debugPrint('user ${user.userName}\'s volume is ${userVolume!}'),
},
),
];
if (canSetVolume) {
options.add(
ListTile(
title: Text(
'Volume up',
style: GoogleFonts.lato(
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.black,
),
),
),
onTap: () async => {
userVolume = await user.getUserVolume(user.userId, isShareAudio),
if (userVolume < 10)
{
await user.setUserVolume(user.userId, userVolume + 1, isShareAudio),
}
else
{
debugPrint("Cannot volume up."),
}
},
),
);
options.add(
ListTile(
title: Text(
'Volume down',
style: GoogleFonts.lato(
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.black,
),
),
),
onTap: () async => {
userVolume = await user.getUserVolume(user.userId, isShareAudio),
if (userVolume > 0)
{
await user.setUserVolume(user.userId, userVolume - 1, isShareAudio),
}
else
{
debugPrint("Cannot volume down."),
}
},
),
);
}
showDialog(
context: context,
builder: (context) {
return Dialog(
elevation: 0.0,
insetPadding: const EdgeInsets.symmetric(horizontal: 40),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: SizedBox(
height: options.length * 58,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ListView(
shrinkWrap: true,
children: ListTile.divideTiles(
context: context,
tiles: options,
).toList(),
),
],
),
));
});
}
void onSelectedUser(ZoomVideoSdkUser user) async {
log("user selected for FullScreen : ${user.userName}");
setState(() {
fullScreenUser.value = user;
});
}
Widget fullScreenView;
Widget smallView;
Widget cameraView;
if (isInSession.value && fullScreenUser.value != null && users.value.isNotEmpty) {
fullScreenView = AnimatedOpacity(
opacity: opacityLevel,
duration: const Duration(seconds: 3),
child: VideoView(
user: fullScreenUser.value,
hasMultiCamera: false,
isPiPView: isPiPView.value,
sharing: sharingUser.value == null ? false : (sharingUser.value?.userId == fullScreenUser.value?.userId),
preview: false,
focused: false,
multiCameraIndex: "0",
videoAspect: VideoAspect.Original,
fullScreen: true,
resolution: VideoResolution.Resolution360,
),
);
smallView = Container(
height: 110,
margin: const EdgeInsets.only(left: 20, right: 20),
alignment: Alignment.center,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: users.value.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () async {
onSelectedUser(users.value[index]);
},
onDoubleTap: () async {
onSelectedUserVolume(users.value[index]);
},
child: Center(
child: VideoView(
user: users.value[index],
hasMultiCamera: false,
isPiPView: false,
sharing: false,
preview: false,
focused: false,
multiCameraIndex: "0",
videoAspect: VideoAspect.Original,
fullScreen: false,
resolution: VideoResolution.Resolution180,
),
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
);
} else {
fullScreenView = Container(
color: Colors.black,
child: const Center(
child: Text(
"Connecting...",
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
));
smallView = Container(
height: 110,
color: Colors.transparent,
);
}
cameraView = Offstage(
offstage: !isSharedCamera.value,
child: AnimatedOpacity(
opacity: isSharedCamera.value ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: cameraShareView,
),
);
_changeOpacity;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: backgroundColor,
body: Stack(
children: [
fullScreenView,
cameraView,
Container(
padding: const EdgeInsets.only(top: 35),
child: Stack(
children: [
Container(
alignment: Alignment.bottomLeft,
margin: const EdgeInsets.only(bottom: 120),
child: smallView,
),
],
)),
],
));
}
}
The issue is whenever a user is manually selected from the list.
void onSelectedUser(ZoomVideoSdkUser user) async {
log("user selected for FullScreen : ${user.userName}");
setState(() {
fullScreenUser.value = user;
});
}
The log()
shows the change — but the actual big screen video view does not update.