You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
7.4 KiB
272 lines
7.4 KiB
6 months ago
|
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:healthcare_pharmacy/settings.dart';
|
||
|
import 'dart:async';
|
||
|
import 'package:permission_handler/permission_handler.dart';
|
||
|
|
||
|
import 'package:agora_rtc_engine/rtc_engine.dart';
|
||
|
import 'package:agora_rtc_engine/rtc_engine.dart' as rtc_engine;
|
||
|
import 'package:agora_rtc_engine/rtc_local_view.dart' as rtc_local_view;
|
||
|
import 'package:agora_rtc_engine/rtc_remote_view.dart' as rtc_remote_view;
|
||
|
|
||
|
class CallPage extends StatefulWidget {
|
||
|
final String? channelName;
|
||
|
final ClientRole? role;
|
||
|
const CallPage({Key? key, this.channelName, this.role}) : super(key: key);
|
||
|
|
||
|
@override
|
||
|
State<CallPage> createState() => _CallPageState();
|
||
|
}
|
||
|
|
||
|
class _CallPageState extends State<CallPage> {
|
||
|
final _users = <int>[];
|
||
|
final _infoString = <String>[];
|
||
|
late RtcEngine _engine;
|
||
|
bool muted = false; // Define the muted variable
|
||
|
bool viewPanel = true;
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
initialize();
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
_users.clear();
|
||
|
_engine.leaveChannel();
|
||
|
_engine.destroy();
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
|
Future<void> initialize() async {
|
||
|
if (appId.isEmpty) {
|
||
|
setState(() {
|
||
|
_infoString.add('AppId is missing please provide AppId');
|
||
|
_infoString.add('Agora Engine is not starting');
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
_engine = await rtc_engine.RtcEngine.create(appId);
|
||
|
await _engine.enableVideo();
|
||
|
await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
|
||
|
await _engine.setClientRole(widget.role!);
|
||
|
_addAgoraEventHandler();
|
||
|
VideoEncoderConfiguration configuration = VideoEncoderConfiguration(
|
||
|
dimensions: VideoDimensions(width: 1920, height: 1080),
|
||
|
);
|
||
|
await _engine.setVideoEncoderConfiguration(configuration);
|
||
|
await _engine.joinChannel(token, widget.channelName!, null, 0);
|
||
|
}
|
||
|
|
||
|
void _addAgoraEventHandler() {
|
||
|
_engine.setEventHandler(
|
||
|
rtc_engine.RtcEngineEventHandler(
|
||
|
error: (code) {
|
||
|
setState(() {
|
||
|
final info = 'Error: $code';
|
||
|
_infoString.add(info);
|
||
|
});
|
||
|
},
|
||
|
joinChannelSuccess: (channel, uid, elapsed) {
|
||
|
setState(() {
|
||
|
final info = 'Join Channel: $channel, uid:$uid';
|
||
|
_infoString.add(info);
|
||
|
});
|
||
|
},
|
||
|
leaveChannel: (stats) {
|
||
|
setState(() {
|
||
|
_infoString.add('Leave Channel');
|
||
|
_users.clear();
|
||
|
});
|
||
|
},
|
||
|
userJoined: (uid, elapsed) {
|
||
|
setState(() {
|
||
|
final info = 'User joined: $uid';
|
||
|
_infoString.add(info);
|
||
|
_users.add(uid);
|
||
|
});
|
||
|
},
|
||
|
userOffline: (uid, elapsed) {
|
||
|
setState(() {
|
||
|
final info = 'User Offline: $uid';
|
||
|
_infoString.add(info);
|
||
|
_users.remove(uid);
|
||
|
});
|
||
|
},
|
||
|
firstRemoteVideoFrame: (uid, width, height, elapsed) {
|
||
|
setState(() {
|
||
|
final info = 'First Remote Video: $uid $width*$height';
|
||
|
_infoString.add(info);
|
||
|
_users.remove(uid);
|
||
|
});
|
||
|
},
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Widget _viewRows() {
|
||
|
final List<StatefulWidget> list = [];
|
||
|
if (widget.role == ClientRole.Broadcaster) {
|
||
|
list.add(const rtc_local_view.SurfaceView());
|
||
|
}
|
||
|
for (var uid in _users) {
|
||
|
list.add(rtc_remote_view.SurfaceView(
|
||
|
uid: uid,
|
||
|
channelId: widget.channelName!,
|
||
|
));
|
||
|
}
|
||
|
final views=list;
|
||
|
return Column(
|
||
|
children: List.generate(
|
||
|
views.length,
|
||
|
(index) => Expanded(
|
||
|
child: views[index],
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
Widget _toolbar() {
|
||
|
if (widget.role == ClientRole.Audience) return SizedBox();
|
||
|
|
||
|
return Container(
|
||
|
alignment: Alignment.bottomCenter,
|
||
|
padding: const EdgeInsets.symmetric(vertical: 48),
|
||
|
child: Row(
|
||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
children: <Widget>[
|
||
|
RawMaterialButton(
|
||
|
onPressed: () {
|
||
|
setState(() {
|
||
|
muted = !muted;
|
||
|
});
|
||
|
_engine.muteLocalAudioStream(muted);
|
||
|
},
|
||
|
child: Icon(
|
||
|
muted ? Icons.mic_off : Icons.mic,
|
||
|
color: muted ? Colors.white : Colors.blueAccent,
|
||
|
size: 20.0,
|
||
|
),
|
||
|
shape: CircleBorder(),
|
||
|
elevation: 2.0,
|
||
|
fillColor: muted ? Colors.blueAccent : Colors.white,
|
||
|
padding: EdgeInsets.all(12.0),
|
||
|
),
|
||
|
RawMaterialButton(
|
||
|
onPressed: () => Navigator.pop(context),
|
||
|
child: Icon(
|
||
|
Icons.call_end,
|
||
|
color: Colors.white,
|
||
|
size: 35.0,
|
||
|
),
|
||
|
shape: CircleBorder(),
|
||
|
elevation: 2.0,
|
||
|
fillColor: Colors.redAccent,
|
||
|
padding: EdgeInsets.all(15.0),
|
||
|
),
|
||
|
RawMaterialButton(
|
||
|
onPressed: () {
|
||
|
_engine.switchCamera();
|
||
|
},
|
||
|
child: Icon(
|
||
|
Icons.switch_camera,
|
||
|
color: Colors.blueAccent,
|
||
|
size: 20.0,
|
||
|
),
|
||
|
shape: CircleBorder(),
|
||
|
elevation: 2.0,
|
||
|
fillColor: Colors.white,
|
||
|
padding: EdgeInsets.all(12.0),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
Widget _panel()
|
||
|
{
|
||
|
return Visibility(
|
||
|
visible: viewPanel,
|
||
|
child: Container(
|
||
|
padding: const EdgeInsets.symmetric(vertical: 48),
|
||
|
alignment: Alignment.bottomCenter,
|
||
|
child: FractionallySizedBox(
|
||
|
heightFactor: 0.5,
|
||
|
child: Container(
|
||
|
padding: EdgeInsets.symmetric(vertical: 48),
|
||
|
child: ListView.builder(
|
||
|
reverse: true,
|
||
|
itemCount: _infoString.length,
|
||
|
itemBuilder:(BuildContext context,int index)
|
||
|
{
|
||
|
if(_infoString.isEmpty)
|
||
|
{
|
||
|
return const Text("null");
|
||
|
}
|
||
|
return Padding(
|
||
|
padding: const EdgeInsets.symmetric(vertical: 3,horizontal: 10),
|
||
|
child: Row(
|
||
|
mainAxisSize: MainAxisSize.min,
|
||
|
children: [
|
||
|
Flexible(
|
||
|
child: Container(
|
||
|
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||
|
decoration: BoxDecoration(
|
||
|
color: Colors.white,
|
||
|
borderRadius: BorderRadius.circular(5)
|
||
|
),
|
||
|
child: Text(
|
||
|
_infoString[index],
|
||
|
style: const TextStyle(color:Colors.blueGrey),
|
||
|
),
|
||
|
),
|
||
|
|
||
|
)
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return Scaffold(
|
||
|
appBar: AppBar(
|
||
|
title: const Text("VideoCall"),
|
||
|
centerTitle: true,
|
||
|
actions: [
|
||
|
IconButton(onPressed:()
|
||
|
{
|
||
|
setState(() {
|
||
|
viewPanel=!viewPanel;
|
||
|
});
|
||
|
}, icon: const Icon(Icons.ice_skating))
|
||
|
],
|
||
|
),
|
||
|
backgroundColor: Colors.black,
|
||
|
body: Center(
|
||
|
child: Stack(
|
||
|
children: <Widget>[
|
||
|
_viewRows(),
|
||
|
_panel(),
|
||
|
_toolbar(),
|
||
|
]
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|