|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:ui';
|
|
|
|
|
|
|
|
|
|
import 'package:camera/camera.dart';
|
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_svg/flutter_svg.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/classes/utils.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/main.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/models/chat/call.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
|
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
|
|
class OutGoingCall extends StatefulWidget {
|
|
|
|
|
CallDataModel outGoingCallData;
|
|
|
|
|
bool isVideoCall;
|
|
|
|
|
|
|
|
|
|
OutGoingCall({Key? key, required this.outGoingCallData, required this.isVideoCall}) : super(key: key);
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
_OutGoingCallState createState() => _OutGoingCallState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderStateMixin {
|
|
|
|
|
AnimationController? _animationController;
|
|
|
|
|
late CameraController controller;
|
|
|
|
|
late List<CameraDescription> _cameras;
|
|
|
|
|
Future<void>? _initializeControllerFuture;
|
|
|
|
|
bool isCameraReady = false;
|
|
|
|
|
bool isMicOff = false;
|
|
|
|
|
bool isLoudSpeaker = false;
|
|
|
|
|
bool isCamOff = false;
|
|
|
|
|
late ChatCallProvider callProviderd;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
callProviderd = Provider.of<ChatCallProvider>(context, listen: false);
|
|
|
|
|
_animationController = AnimationController(
|
|
|
|
|
vsync: this,
|
|
|
|
|
duration: const Duration(
|
|
|
|
|
milliseconds: 500,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
// _runAnimation();
|
|
|
|
|
// connectSignaling();
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback(
|
|
|
|
|
(_) => _runAnimation(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
super.initState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Scaffold(
|
|
|
|
|
body: FutureBuilder<void>(
|
|
|
|
|
future: _initializeControllerFuture,
|
|
|
|
|
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
|
|
|
|
|
if (snapshot.connectionState == ConnectionState.done) {
|
|
|
|
|
return Stack(
|
|
|
|
|
alignment: FractionalOffset.center,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
if (widget.isVideoCall)
|
|
|
|
|
Positioned.fill(
|
|
|
|
|
child: CameraPreview(
|
|
|
|
|
controller,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Positioned.fill(
|
|
|
|
|
child: ClipRect(
|
|
|
|
|
child: BackdropFilter(
|
|
|
|
|
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
|
|
|
|
|
child: Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: MyColors.grey57Color.withOpacity(
|
|
|
|
|
0.3,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
mainAxisSize: MainAxisSize.max,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
40.height,
|
|
|
|
|
Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
Container(
|
|
|
|
|
margin: const EdgeInsets.all(21.0),
|
|
|
|
|
child: Container(
|
|
|
|
|
margin: const EdgeInsets.only(
|
|
|
|
|
left: 10.0,
|
|
|
|
|
right: 10.0,
|
|
|
|
|
),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
SvgPicture.asset(
|
|
|
|
|
"assets/images/user.svg",
|
|
|
|
|
height: 70,
|
|
|
|
|
width: 70,
|
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
|
),
|
|
|
|
|
10.height,
|
|
|
|
|
Text(
|
|
|
|
|
widget.outGoingCallData.title,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontSize: 21,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
letterSpacing: -1.26,
|
|
|
|
|
height: 23 / 12,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const Text(
|
|
|
|
|
"Ringing...",
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
color: Color(
|
|
|
|
|
0xffC6C6C6,
|
|
|
|
|
),
|
|
|
|
|
letterSpacing: -0.48,
|
|
|
|
|
height: 23 / 24,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(
|
|
|
|
|
height: 2,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
// Container(
|
|
|
|
|
// margin: const EdgeInsets.all(21.0),
|
|
|
|
|
// width: MediaQuery.of(context).size.width,
|
|
|
|
|
// decoration: cardRadius(15.0, color: MyColors.black, elevation: null),
|
|
|
|
|
// child: Column(
|
|
|
|
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
// mainAxisSize: MainAxisSize.min,
|
|
|
|
|
// children: [
|
|
|
|
|
// Container(
|
|
|
|
|
// padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 6.0),
|
|
|
|
|
// child: Text(
|
|
|
|
|
// "TranslationBase.of(context).appoInfo",
|
|
|
|
|
// style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.white, letterSpacing: -0.64, height: 23 / 12),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// Container(
|
|
|
|
|
// padding: const EdgeInsets.only(left: 16.0, right: 16.0),
|
|
|
|
|
// child: Text(
|
|
|
|
|
// "widget.OutGoingCallData.appointmentdate + widget.OutGoingCallData.appointmenttime",
|
|
|
|
|
// style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// Container(
|
|
|
|
|
// padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 21.0),
|
|
|
|
|
// child: Text(
|
|
|
|
|
// "widget.OutGoingCallData.clinicname",
|
|
|
|
|
// style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// ],
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
const Spacer(),
|
|
|
|
|
Container(
|
|
|
|
|
margin: const EdgeInsets.only(
|
|
|
|
|
bottom: 70.0,
|
|
|
|
|
left: 49,
|
|
|
|
|
right: 49,
|
|
|
|
|
),
|
|
|
|
|
child: Row(
|
|
|
|
|
mainAxisSize: MainAxisSize.max,
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
if (widget.isVideoCall)
|
|
|
|
|
RawMaterialButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
_camOff();
|
|
|
|
|
},
|
|
|
|
|
elevation: 2.0,
|
|
|
|
|
fillColor: isCamOff ? MyColors.green2DColor : Colors.grey,
|
|
|
|
|
padding: const EdgeInsets.all(
|
|
|
|
|
15.0,
|
|
|
|
|
),
|
|
|
|
|
shape: const CircleBorder(),
|
|
|
|
|
child: Icon(
|
|
|
|
|
isCamOff ? Icons.videocam_off : Icons.videocam,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
size: 35.0,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
else
|
|
|
|
|
RawMaterialButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
_loudOn();
|
|
|
|
|
},
|
|
|
|
|
elevation: 2.0,
|
|
|
|
|
fillColor: isLoudSpeaker ? MyColors.green2DColor : Colors.grey,
|
|
|
|
|
padding: const EdgeInsets.all(
|
|
|
|
|
15.0,
|
|
|
|
|
),
|
|
|
|
|
shape: const CircleBorder(),
|
|
|
|
|
child: const Icon(
|
|
|
|
|
Icons.volume_up,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
size: 35.0,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
RawMaterialButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
_micOff();
|
|
|
|
|
},
|
|
|
|
|
elevation: 2.0,
|
|
|
|
|
fillColor: isMicOff ? MyColors.green2DColor : Colors.grey,
|
|
|
|
|
padding: const EdgeInsets.all(
|
|
|
|
|
15.0,
|
|
|
|
|
),
|
|
|
|
|
shape: const CircleBorder(),
|
|
|
|
|
child: Icon(
|
|
|
|
|
isMicOff ? Icons.mic_off : Icons.mic,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
size: 35.0,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
RawMaterialButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
backToHome();
|
|
|
|
|
},
|
|
|
|
|
elevation: 2.0,
|
|
|
|
|
fillColor: MyColors.redA3Color,
|
|
|
|
|
padding: const EdgeInsets.all(
|
|
|
|
|
15.0,
|
|
|
|
|
),
|
|
|
|
|
shape: const CircleBorder(),
|
|
|
|
|
child: const Icon(
|
|
|
|
|
Icons.call_end,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
size: 35.0,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return const Center(
|
|
|
|
|
child: CircularProgressIndicator(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _runAnimation() async {
|
|
|
|
|
_cameras = await availableCameras();
|
|
|
|
|
CameraDescription firstCamera = _cameras[1];
|
|
|
|
|
controller = CameraController(firstCamera, ResolutionPreset.medium);
|
|
|
|
|
_initializeControllerFuture = controller.initialize();
|
|
|
|
|
setState(() {});
|
|
|
|
|
// setAudioFile();
|
|
|
|
|
for (int i = 0; i < 100; i++) {
|
|
|
|
|
await _animationController!.forward();
|
|
|
|
|
await _animationController!.reverse();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _micOff() {
|
|
|
|
|
setState(() {
|
|
|
|
|
isMicOff = !isMicOff;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _camOff() {
|
|
|
|
|
setState(() {
|
|
|
|
|
isCamOff = !isCamOff;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _loudOn() {
|
|
|
|
|
setState(() {
|
|
|
|
|
isLoudSpeaker = !isLoudSpeaker;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _submit() async {
|
|
|
|
|
try {
|
|
|
|
|
// backToHome();
|
|
|
|
|
// final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity);
|
|
|
|
|
await controller?.dispose();
|
|
|
|
|
|
|
|
|
|
// changeCallStatusAPI(4);
|
|
|
|
|
|
|
|
|
|
// if (_session != null && _signaling != null) {
|
|
|
|
|
// await Navigator.of(context).pushReplacement(
|
|
|
|
|
// MaterialPageRoute(
|
|
|
|
|
// // fullscreenDialog: true,
|
|
|
|
|
// builder: (BuildContext context) {
|
|
|
|
|
// // if (widget.OutGoingCallData.isWebRTC == "true") {
|
|
|
|
|
// return StartVideoCall(signaling: _signaling, session: _session);
|
|
|
|
|
//
|
|
|
|
|
// // else {
|
|
|
|
|
// // return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: widget.OutGoingCallData.sessionId, token: widget.OutGoingCallData.token);
|
|
|
|
|
// // }
|
|
|
|
|
//
|
|
|
|
|
// // return VideoCallWebPage(receiverId: widget.OutGoingCallData.receiverID, callerId: widget.OutGoingCallData.callerID); // Web WebRTC VideoCall
|
|
|
|
|
//
|
|
|
|
|
// // return CallHomePage(receiverId: widget.OutGoingCallData.receiverID, callerId: widget.OutGoingCallData.callerID); // App WebRTC VideoCall
|
|
|
|
|
// },
|
|
|
|
|
// ),
|
|
|
|
|
// );
|
|
|
|
|
// } else {
|
|
|
|
|
// // Invalid Params/Data
|
|
|
|
|
// Utils.showToast("Failed to establish connection with server");
|
|
|
|
|
// }
|
|
|
|
|
} catch (err) {
|
|
|
|
|
print(err);
|
|
|
|
|
// await PlatformExceptionAlertDialog(
|
|
|
|
|
// exception: err,
|
|
|
|
|
// ).show(context);
|
|
|
|
|
|
|
|
|
|
Utils.showToast(err.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// void changeCallStatusAPI(int sessionStatus) {
|
|
|
|
|
// LiveCareService service = new LiveCareService();
|
|
|
|
|
// service.endCallAPI(widget.OutGoingCallData.sessionId, sessionStatus, context).then((res) {}).catchError((err) {
|
|
|
|
|
// print(err);
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
void backToHome() async {
|
|
|
|
|
// final connected = await signaling.declineCall(widget.OutGoingCallData.callerID, widget.OutGoingCallData.receiverID);
|
|
|
|
|
// LandingPage.isOpenCallPage = false;
|
|
|
|
|
// _signaling
|
|
|
|
|
_animationController!.dispose();
|
|
|
|
|
// player.stop();
|
|
|
|
|
// changeCallStatusAPI(3);
|
|
|
|
|
// _signaling.bye(_session, callRejected: true);
|
|
|
|
|
// _signaling.callDisconnected(_session, callRejected: true);
|
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// void disposeAudioResources() async {
|
|
|
|
|
// await player.dispose();
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void setAudioFile() async {
|
|
|
|
|
// player.stop();
|
|
|
|
|
// await player.setVolume(1.0); // full volume
|
|
|
|
|
// try {
|
|
|
|
|
// await player.setAsset('assets/sounds/ring_60Sec.mp3').then((value) {
|
|
|
|
|
// player.setLoopMode(LoopMode.one); // loop ring sound
|
|
|
|
|
// player.play();
|
|
|
|
|
// }).catchError((err) {
|
|
|
|
|
// print("Error: $err");
|
|
|
|
|
// });
|
|
|
|
|
// } catch (e) {
|
|
|
|
|
// print("Error: $e");
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void connectSignaling({@required bool iAmCaller = false}) async {
|
|
|
|
|
// print("----------------- + Signaling Connection Started ---------------------------");
|
|
|
|
|
// var caller = widget.OutGoingCallData.callerID;
|
|
|
|
|
// var receiver = widget.OutGoingCallData.receiverID;
|
|
|
|
|
// var host = widget.OutGoingCallData.server;
|
|
|
|
|
//
|
|
|
|
|
// var selfRole = iAmCaller ? "Caller" : "Receiver";
|
|
|
|
|
// var selfId = iAmCaller ? caller : receiver;
|
|
|
|
|
// var selfUser = SocketUser(id: selfId, name: "$selfRole-$selfId", userAgent: DeviceInfo.userAgent, moreInfo: {});
|
|
|
|
|
//
|
|
|
|
|
// var remoteRole = !iAmCaller ? "Caller" : "Receiver";
|
|
|
|
|
// var remoteId = !iAmCaller ? caller : receiver;
|
|
|
|
|
// var remoteUser = SocketUser(id: remoteId, name: "$remoteRole-$remoteId", userAgent: DeviceInfo.userAgent, moreInfo: {});
|
|
|
|
|
//
|
|
|
|
|
// var sessionId = "$caller-$receiver";
|
|
|
|
|
// _session = SessionOneToOne(id: sessionId, local_user: selfUser, remote_user: remoteUser);
|
|
|
|
|
//
|
|
|
|
|
// _signaling = Signaling(host, session: _session);
|
|
|
|
|
// await _signaling.connect();
|
|
|
|
|
//
|
|
|
|
|
// if (_signaling.state == SignalingState.Open) {
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
BoxDecoration cardRadius(double radius, {required Color color, double? elevation}) {
|
|
|
|
|
return BoxDecoration(
|
|
|
|
|
shape: BoxShape.rectangle,
|
|
|
|
|
color: color ?? Colors.white,
|
|
|
|
|
borderRadius: BorderRadius.all(
|
|
|
|
|
Radius.circular(radius),
|
|
|
|
|
),
|
|
|
|
|
boxShadow: <BoxShadow>[
|
|
|
|
|
BoxShadow(
|
|
|
|
|
color: const Color(
|
|
|
|
|
0xff000000,
|
|
|
|
|
).withOpacity(
|
|
|
|
|
.05,
|
|
|
|
|
),
|
|
|
|
|
//spreadRadius: 5,
|
|
|
|
|
blurRadius: elevation ?? 27,
|
|
|
|
|
offset: const Offset(
|
|
|
|
|
-2,
|
|
|
|
|
3,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|