Chat Fix & Web RTC Methods
parent
2b35c3d8d6
commit
74e01e60fb
Binary file not shown.
Binary file not shown.
@ -0,0 +1,61 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final remoteIceCandidatePayLoad = remoteIceCandidatePayLoadFromJson(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
class RemoteIceCandidatePayLoad {
|
||||
RemoteIceCandidatePayLoad({
|
||||
this.target,
|
||||
this.candidate,
|
||||
});
|
||||
|
||||
int? target;
|
||||
Candidate? candidate;
|
||||
|
||||
factory RemoteIceCandidatePayLoad.fromRawJson(String str) => RemoteIceCandidatePayLoad.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory RemoteIceCandidatePayLoad.fromJson(Map<String, dynamic> json) => RemoteIceCandidatePayLoad(
|
||||
target: json["target"],
|
||||
candidate: json["candidate"] == null ? null : Candidate.fromJson(json["candidate"]),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"target": target,
|
||||
"candidate": candidate?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
class Candidate {
|
||||
Candidate({
|
||||
this.candidate,
|
||||
this.sdpMid,
|
||||
this.sdpMLineIndex,
|
||||
this.usernameFragment,
|
||||
});
|
||||
|
||||
String? candidate;
|
||||
String? sdpMid;
|
||||
int? sdpMLineIndex;
|
||||
String? usernameFragment;
|
||||
|
||||
factory Candidate.fromRawJson(String str) => Candidate.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory Candidate.fromJson(Map<String, dynamic> json) => Candidate(
|
||||
candidate: json["candidate"],
|
||||
sdpMid: json["sdpMid"],
|
||||
sdpMLineIndex: json["sdpMLineIndex"],
|
||||
usernameFragment: json["usernameFragment"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"candidate": candidate,
|
||||
"sdpMid": sdpMid,
|
||||
"sdpMLineIndex": sdpMLineIndex,
|
||||
"usernameFragment": usernameFragment,
|
||||
};
|
||||
}
|
||||
@ -1,381 +1,233 @@
|
||||
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:flutter_webrtc/flutter_webrtc.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:mohem_flutter_app/provider/chat_provider_model.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class IncomingCall extends StatefulWidget {
|
||||
CallDataModel incomingCallData;
|
||||
bool? isVideoCall;
|
||||
CallDataModel outGoingCallData;
|
||||
bool isVideoCall;
|
||||
|
||||
IncomingCall({Key? key, required this.incomingCallData, this.isVideoCall}) : super(key: key);
|
||||
IncomingCall({Key? key, required this.outGoingCallData, required this.isVideoCall}) : super(key: key);
|
||||
|
||||
@override
|
||||
_IncomingCallState createState() => _IncomingCallState();
|
||||
}
|
||||
|
||||
class _IncomingCallState extends State<IncomingCall> with SingleTickerProviderStateMixin {
|
||||
AnimationController? _animationController;
|
||||
CameraController? _controller;
|
||||
Future<void>? _initializeControllerFuture;
|
||||
bool isCameraReady = false;
|
||||
late ChatCallProvider callProvider;
|
||||
late ChatProviderModel chatProvider;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(
|
||||
milliseconds: 500,
|
||||
),
|
||||
);
|
||||
//_runAnimation();
|
||||
// connectSignaling();
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => _runAnimation(),
|
||||
);
|
||||
|
||||
chatProvider = Provider.of<ChatProviderModel>(context, listen: false);
|
||||
callProvider = Provider.of<ChatCallProvider>(context, listen: false);
|
||||
init();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void init() {
|
||||
widget.isVideoCall ? callProvider.isVideoCall = true : callProvider.isVideoCall = false;
|
||||
callProvider.initLocalCamera(chatProvmodel: chatProvider, callData: widget.outGoingCallData, context: context, isIncomingCall: true);
|
||||
callProvider.init();
|
||||
}
|
||||
|
||||
@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: AspectRatio(
|
||||
aspectRatio: _controller!.value.aspectRatio,
|
||||
child: CameraPreview(
|
||||
_controller!,
|
||||
body: Consumer<ChatCallProvider>(builder: (BuildContext context, ChatCallProvider chatcp, Widget? child) {
|
||||
if (chatcp.isCallEnded) Navigator.pop(context);
|
||||
return Stack(
|
||||
alignment: FractionalOffset.center,
|
||||
children: <Widget>[
|
||||
if (widget.isVideoCall)
|
||||
Positioned.fill(
|
||||
child: RTCVideoView(
|
||||
callProvider.localVideoRenderer,
|
||||
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MyColors.grey57Color.withOpacity(
|
||||
0.3,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MyColors.grey57Color.withOpacity(
|
||||
0.7,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
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: Row(
|
||||
children: <Widget>[
|
||||
Image.asset(
|
||||
"assets/images/logos/main_mohemm_logo.png",
|
||||
height: 70,
|
||||
width: 70,
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(
|
||||
left: 10.0,
|
||||
right: 10.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: const <Widget>[
|
||||
|
||||
// todo @aamir, need to use extension mehtods
|
||||
Text(
|
||||
"Aamir Saleem Ahmad",
|
||||
style: TextStyle(
|
||||
fontSize: 21,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MyColors.white,
|
||||
letterSpacing: -1.26,
|
||||
height: 23 / 12,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Calling...",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(
|
||||
0xffC6C6C6,
|
||||
),
|
||||
letterSpacing: -0.48,
|
||||
height: 23 / 24,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
],
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 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.incomingCallData.appointmentdate + widget.incomingCallData.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.incomingCallData.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>[
|
||||
RotationTransition(
|
||||
turns: Tween(
|
||||
begin: 0.0,
|
||||
end: -.1,
|
||||
)
|
||||
.chain(
|
||||
CurveTween(
|
||||
curve: Curves.elasticIn,
|
||||
),
|
||||
)
|
||||
.animate(
|
||||
_animationController!,
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
onPressed: () {
|
||||
_submit();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: MyColors.green2DColor,
|
||||
padding: const EdgeInsets.all(
|
||||
15.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: const Icon(
|
||||
Icons.call,
|
||||
10.height,
|
||||
Text(
|
||||
widget.outGoingCallData.receiverName.toString().replaceAll(".", " "),
|
||||
style: const TextStyle(
|
||||
fontSize: 21,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MyColors.white,
|
||||
size: 35.0,
|
||||
letterSpacing: -1.26,
|
||||
height: 23 / 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
RawMaterialButton(
|
||||
onPressed: () {
|
||||
backToHome();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: MyColors.redA3Color,
|
||||
padding: const EdgeInsets.all(
|
||||
15.0,
|
||||
const Text(
|
||||
"Ringing...",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(
|
||||
0xffC6C6C6,
|
||||
),
|
||||
letterSpacing: -0.48,
|
||||
height: 23 / 24,
|
||||
),
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: const Icon(
|
||||
Icons.call_end,
|
||||
color: MyColors.white,
|
||||
size: 35.0,
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
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: () {
|
||||
callProvider.camOff();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: callProvider.isCamOff ? MyColors.green2DColor : Colors.grey,
|
||||
padding: const EdgeInsets.all(
|
||||
15.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(
|
||||
callProvider.isCamOff ? Icons.videocam_off : Icons.videocam,
|
||||
color: MyColors.white,
|
||||
size: 35.0,
|
||||
),
|
||||
)
|
||||
else
|
||||
RawMaterialButton(
|
||||
onPressed: () {
|
||||
callProvider.loudOn();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: callProvider.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: () {
|
||||
callProvider.micOff();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: callProvider.isMicOff ? MyColors.green2DColor : Colors.grey,
|
||||
padding: const EdgeInsets.all(
|
||||
15.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(
|
||||
callProvider.isMicOff ? Icons.mic_off : Icons.mic,
|
||||
color: MyColors.white,
|
||||
size: 35.0,
|
||||
),
|
||||
),
|
||||
RawMaterialButton(
|
||||
onPressed: () {
|
||||
callProvider.endCall().then((value) {
|
||||
if (value) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
});
|
||||
},
|
||||
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 {
|
||||
List<CameraDescription> 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();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _submit() async {
|
||||
try {
|
||||
// backToHome();
|
||||
// final roomModel = RoomModel(name: widget.incomingCallData.name, token: widget.incomingCallData.sessionId, identity: widget.incomingCallData.identity);
|
||||
await _controller?.dispose();
|
||||
|
||||
// changeCallStatusAPI(4);
|
||||
|
||||
// if (_session != null && _signaling != null) {
|
||||
// await Navigator.of(context).pushReplacement(
|
||||
// MaterialPageRoute(
|
||||
// // fullscreenDialog: true,
|
||||
// builder: (BuildContext context) {
|
||||
// // if (widget.incomingCallData.isWebRTC == "true") {
|
||||
// return StartVideoCall(signaling: _signaling, session: _session);
|
||||
//
|
||||
// // else {
|
||||
// // return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: widget.incomingCallData.sessionId, token: widget.incomingCallData.token);
|
||||
// // }
|
||||
//
|
||||
// // return VideoCallWebPage(receiverId: widget.incomingCallData.receiverID, callerId: widget.incomingCallData.callerID); // Web WebRTC VideoCall
|
||||
//
|
||||
// // return CallHomePage(receiverId: widget.incomingCallData.receiverID, callerId: widget.incomingCallData.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.incomingCallData.sessionId, sessionStatus, context).then((res) {}).catchError((err) {
|
||||
// print(err);
|
||||
// });
|
||||
// }
|
||||
|
||||
void backToHome() async {
|
||||
// final connected = await signaling.declineCall(widget.incomingCallData.callerID, widget.incomingCallData.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.incomingCallData.callerID;
|
||||
// var receiver = widget.incomingCallData.receiverID;
|
||||
// var host = widget.incomingCallData.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,
|
||||
),
|
||||
),
|
||||
],
|
||||
borderRadius: BorderRadius.all(Radius.circular(radius)),
|
||||
boxShadow: <BoxShadow>[BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: elevation ?? 27, offset: const Offset(-2, 3))],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,171 @@
|
||||
// import 'dart:async';
|
||||
// import 'dart:io';
|
||||
// import 'package:flutter/material.dart';
|
||||
//
|
||||
// class DraggableCam extends StatefulWidget {
|
||||
// //final Size availableScreenSize;
|
||||
// final Widget child;
|
||||
// final double scaleFactor;
|
||||
// // final Stream<bool> onButtonBarVisible;
|
||||
// // final Stream<double> onButtonBarHeight;
|
||||
//
|
||||
// const DraggableCam({
|
||||
// Key? key,
|
||||
// //@required this.availableScreenSize,
|
||||
// required this.child,
|
||||
// // @required this.onButtonBarVisible,
|
||||
// // @required this.onButtonBarHeight,
|
||||
//
|
||||
// /// The portion of the screen the DraggableWidget should use.
|
||||
// this.scaleFactor = .25,
|
||||
// }) : assert(scaleFactor != null && scaleFactor > 0 && scaleFactor <= .4),
|
||||
// // assert(availableScreenSize != null),
|
||||
// // assert(onButtonBarVisible != null),
|
||||
// // assert(onButtonBarHeight != null),
|
||||
// super(key: key);
|
||||
//
|
||||
// @override
|
||||
// _DraggablePublisherState createState() => _DraggablePublisherState();
|
||||
// }
|
||||
//
|
||||
// class _DraggablePublisherState extends State<DraggableCam> {
|
||||
// bool _isButtonBarVisible = true;
|
||||
// double _buttonBarHeight = 0;
|
||||
// late double _width;
|
||||
// late double _height;
|
||||
// late double _top;
|
||||
// late double _left;
|
||||
// late double _viewPaddingTop;
|
||||
// late double _viewPaddingBottom;
|
||||
// final double _padding = 8.0;
|
||||
// final Duration _duration300ms = const Duration(milliseconds: 300);
|
||||
// final Duration _duration0ms = const Duration(milliseconds: 0);
|
||||
// late Duration _duration;
|
||||
// late StreamSubscription _streamSubscription;
|
||||
// late StreamSubscription _streamHeightSubscription;
|
||||
//
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// _duration = _duration300ms;
|
||||
// _width = widget.availableScreenSize.width * widget.scaleFactor;
|
||||
// _height = _width * (widget.availableScreenSize.height / widget.availableScreenSize.width);
|
||||
// _top = widget.availableScreenSize.height - (_buttonBarHeight + _padding) - _height;
|
||||
// _left = widget.availableScreenSize.width - _padding - _width;
|
||||
//
|
||||
// _streamSubscription = widget.onButtonBarVisible.listen(_buttonBarVisible);
|
||||
// _streamHeightSubscription = widget.onButtonBarHeight.listen(_getButtonBarHeight);
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void didChangeDependencies() {
|
||||
// var mediaQuery = MediaQuery.of(context);
|
||||
// _viewPaddingTop = mediaQuery.viewPadding.top;
|
||||
// _viewPaddingBottom = mediaQuery.viewPadding.bottom;
|
||||
// super.didChangeDependencies();
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _streamSubscription.cancel();
|
||||
// _streamHeightSubscription.cancel();
|
||||
// super.dispose();
|
||||
// }
|
||||
//
|
||||
// void _getButtonBarHeight(double height) {
|
||||
// setState(() {
|
||||
// _buttonBarHeight = height;
|
||||
// _positionWidget();
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// void _buttonBarVisible(bool visible) {
|
||||
// if (!mounted) {
|
||||
// return;
|
||||
// }
|
||||
// setState(() {
|
||||
// _isButtonBarVisible = visible;
|
||||
// if (_duration == _duration300ms) {
|
||||
// // only position the widget when we are not currently dragging it around
|
||||
// _positionWidget();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return AnimatedPositioned(
|
||||
// top: _top,
|
||||
// left: _left,
|
||||
// width: _width,
|
||||
// height: _height,
|
||||
// duration: _duration,
|
||||
// child: Listener(
|
||||
// onPointerDown: (_) => _duration = _duration0ms,
|
||||
// onPointerMove: (PointerMoveEvent event) {
|
||||
// setState(() {
|
||||
// _left = (_left + event.delta.dx).roundToDouble();
|
||||
// _top = (_top + event.delta.dy).roundToDouble();
|
||||
// });
|
||||
// },
|
||||
// onPointerUp: (_) => _positionWidget(),
|
||||
// onPointerCancel: (_) => _positionWidget(),
|
||||
// child: ClippedVideo(
|
||||
// height: _height,
|
||||
// width: _width,
|
||||
// child: widget.child,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// double _getCurrentStatusBarHeight() {
|
||||
// if (_isButtonBarVisible) {
|
||||
// return _viewPaddingTop;
|
||||
// }
|
||||
// final _defaultViewPaddingTop = Platform.isIOS ? 20.0 : Platform.isAndroid ? 24.0 : 0.0;
|
||||
// if (_viewPaddingTop > _defaultViewPaddingTop) {
|
||||
// // There must be a hardware notch in the display.
|
||||
// return _viewPaddingTop;
|
||||
// }
|
||||
// return 0.0;
|
||||
// }
|
||||
//
|
||||
// double _getCurrentButtonBarHeight() {
|
||||
// if (_isButtonBarVisible) {
|
||||
// return _buttonBarHeight + _viewPaddingBottom;
|
||||
// }
|
||||
// return _viewPaddingBottom;
|
||||
// }
|
||||
//
|
||||
// void _positionWidget() {
|
||||
// // Determine the center of the object being dragged so we can decide
|
||||
// // in which corner the object should be placed.
|
||||
// var dx = (_width / 2) + _left;
|
||||
// dx = dx < 0 ? 0 : dx >= widget.availableScreenSize.width ? widget.availableScreenSize.width - 1 : dx;
|
||||
// var dy = (_height / 2) + _top;
|
||||
// dy = dy < 0 ? 0 : dy >= widget.availableScreenSize.height ? widget.availableScreenSize.height - 1 : dy;
|
||||
// final draggableCenter = Offset(dx, dy);
|
||||
//
|
||||
// setState(() {
|
||||
// _duration = _duration300ms;
|
||||
// if (Rect.fromLTRB(0, 0, widget.availableScreenSize.width / 2, widget.availableScreenSize.height / 2).contains(draggableCenter)) {
|
||||
// // Top-left
|
||||
// _top = _getCurrentStatusBarHeight() + _padding;
|
||||
// _left = _padding;
|
||||
// } else if (Rect.fromLTRB(widget.availableScreenSize.width / 2, 0, widget.availableScreenSize.width, widget.availableScreenSize.height / 2).contains(draggableCenter)) {
|
||||
// // Top-right
|
||||
// _top = _getCurrentStatusBarHeight() + _padding;
|
||||
// _left = widget.availableScreenSize.width - _padding - _width;
|
||||
// } else if (Rect.fromLTRB(0, widget.availableScreenSize.height / 2, widget.availableScreenSize.width / 2, widget.availableScreenSize.height).contains(draggableCenter)) {
|
||||
// // Bottom-left
|
||||
// _top = widget.availableScreenSize.height - (_getCurrentButtonBarHeight() + _padding) - _height;
|
||||
// _left = _padding;
|
||||
// } else if (Rect.fromLTRB(widget.availableScreenSize.width / 2, widget.availableScreenSize.height / 2, widget.availableScreenSize.width, widget.availableScreenSize.height).contains(draggableCenter)) {
|
||||
// // Bottom-right
|
||||
// _top = widget.availableScreenSize.height - (_getCurrentButtonBarHeight() + _padding) - _height;
|
||||
// _left = widget.availableScreenSize.width - _padding - _width;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
@ -0,0 +1,267 @@
|
||||
import 'dart:async';
|
||||
import 'dart:core';
|
||||
import 'dart:ui';
|
||||
import 'package:draggable_widget/draggable_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class StartCallPage extends StatefulWidget {
|
||||
RTCVideoRenderer localRenderer;
|
||||
RTCVideoRenderer remoteRenderer;
|
||||
|
||||
StartCallPage({required this.localRenderer, required this.remoteRenderer});
|
||||
|
||||
@override
|
||||
_StartCallPageState createState() => _StartCallPageState();
|
||||
}
|
||||
|
||||
class _StartCallPageState extends State<StartCallPage> {
|
||||
final dragController = DragController();
|
||||
late ChatCallProvider callProvider;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
callProvider = Provider.of<ChatCallProvider>(context, listen: false);
|
||||
super.initState();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
callProvider.notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<ChatCallProvider>(builder: (BuildContext context, ChatCallProvider provider, Widget? child) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: Stack(
|
||||
alignment: FractionalOffset.center,
|
||||
children: [
|
||||
if (provider.isVideoCall)
|
||||
Positioned.fill(
|
||||
child: RTCVideoView(
|
||||
widget.remoteRenderer,
|
||||
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
|
||||
key: const Key('remote'),
|
||||
),
|
||||
),
|
||||
if (provider.isVideoCall)
|
||||
DraggableWidget(
|
||||
bottomMargin: 20,
|
||||
topMargin: 40,
|
||||
intialVisibility: true,
|
||||
horizontalSpace: 20,
|
||||
shadowBorderRadius: 50,
|
||||
initialPosition: AnchoringPosition.topLeft,
|
||||
dragController: dragController,
|
||||
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
|
||||
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
|
||||
child: SizedBox(
|
||||
height: 200,
|
||||
width: 140,
|
||||
child: RTCVideoView(
|
||||
widget.localRenderer,
|
||||
mirror: true,
|
||||
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!provider.isVideoCall)
|
||||
Positioned.fill(
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.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(
|
||||
callProvider.outGoingCallData.receiverName!,
|
||||
style: const TextStyle(
|
||||
fontSize: 21,
|
||||
decoration: TextDecoration.none,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MyColors.white,
|
||||
letterSpacing: -1.26,
|
||||
height: 23 / 12,
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
"On Call",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
decoration: TextDecoration.none,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(
|
||||
0xffC6C6C6,
|
||||
),
|
||||
letterSpacing: -0.48,
|
||||
height: 23 / 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 20,
|
||||
left: 40,
|
||||
right: 40,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
// if (provider.isVideoCall)
|
||||
RawMaterialButton(
|
||||
constraints: BoxConstraints(),
|
||||
onPressed: () {
|
||||
callProvider.loudOn();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: callProvider.isLoudSpeaker ? MyColors.green2DColor : Colors.grey,
|
||||
padding: const EdgeInsets.all(
|
||||
10.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: const Icon(
|
||||
Icons.volume_up,
|
||||
color: MyColors.white,
|
||||
size: 30.0,
|
||||
),
|
||||
),
|
||||
RawMaterialButton(
|
||||
constraints: BoxConstraints(),
|
||||
onPressed: () {
|
||||
provider.camOff();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: provider.isCamOff ? MyColors.green2DColor : Colors.grey,
|
||||
padding: const EdgeInsets.all(
|
||||
10.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(
|
||||
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
|
||||
color: MyColors.white,
|
||||
size: 30.0,
|
||||
),
|
||||
),
|
||||
RawMaterialButton(
|
||||
constraints: BoxConstraints(),
|
||||
onPressed: () {
|
||||
provider.switchCamera();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.green2DColor,
|
||||
padding: const EdgeInsets.all(
|
||||
10.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(
|
||||
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
|
||||
color: MyColors.white,
|
||||
size: 30.0,
|
||||
),
|
||||
),
|
||||
RawMaterialButton(
|
||||
constraints: BoxConstraints(),
|
||||
onPressed: () {
|
||||
provider.micOff();
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: provider.isMicOff ? MyColors.green2DColor : Colors.grey,
|
||||
padding: const EdgeInsets.all(
|
||||
10.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(
|
||||
provider.isMicOff ? Icons.mic_off : Icons.mic,
|
||||
color: MyColors.white,
|
||||
size: 30.0,
|
||||
),
|
||||
),
|
||||
RawMaterialButton(
|
||||
constraints: BoxConstraints(),
|
||||
onPressed: () {
|
||||
provider.endCall().then((value) {
|
||||
if (value) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
});
|
||||
},
|
||||
elevation: 2.0,
|
||||
fillColor: MyColors.redA3Color,
|
||||
padding: const EdgeInsets.all(
|
||||
10.0,
|
||||
),
|
||||
shape: const CircleBorder(),
|
||||
child: const Icon(
|
||||
Icons.call_end,
|
||||
color: MyColors.white,
|
||||
size: 30.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue