Voip Call

update_flutter_3.16.0_voipcall
Aamir Muhammad 2 years ago
parent c47c93b2d9
commit 0b98bb3e37

@ -12,6 +12,7 @@ import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart';
import 'package:doctor_app_flutter/locator.dart';
import 'package:doctor_app_flutter/routes.dart';
import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart';
import 'package:doctor_app_flutter/voipcall/provider/chat_call_provider.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -43,6 +44,9 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider<LiveCareViewModel>(
create: (context) => LiveCareViewModel(),
),
ChangeNotifierProvider<ChatCallProvider>(
create: (context) => ChatCallProvider(),
),
StreamProvider.value(
value: RobotProvider().intStream(),
initialData: RobotProvider().setValue({}),

@ -6,26 +6,12 @@ import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart
import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart';
import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart';
import 'package:doctor_app_flutter/utils/utils.dart';
import 'package:doctor_app_flutter/voipcall/provider/chat_call_provider.dart';
import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart';
import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart';
import 'package:flutter/material.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:provider/provider.dart';
import '../../widgets/shared/app_scaffold_widget.dart';
class LoginScreen extends StatefulWidget {
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
String? platformImei;
bool allowCallApi = true;
//TODO change AppTextFormField to AppTextFormFieldCustom
final loginFormKey = GlobalKey<FormState>();
import 'package:hexcolor/hexcolo= GlobalKey<FormState>();
var projectIdController = TextEditingController();
var userIdController = TextEditingController();
var passwordController = TextEditingController();
@ -34,11 +20,14 @@ class _LoginScreenState extends State<LoginScreen> {
FocusNode focusProject = FocusNode();
late AuthenticationViewModel authenticationViewModel;
late ProjectViewModel projectViewModel;
ChatCallProvider? callProv;
@override
Widget build(BuildContext context) {
authenticationViewModel = Provider.of<AuthenticationViewModel>(context);
projectViewModel = Provider.of<ProjectViewModel>(context);
callProv = Provider.of<ChatCallProvider>(context);
return AppScaffold(
isShowAppBar: false,
backgroundColor: HexColor('#F8F8F8'),
@ -174,7 +163,35 @@ class _LoginScreenState extends State<LoginScreen> {
),
SizedBox(
height: 25,
)
),
// AppButton(
// title: "Call Test",
// color: AppGlobal.appGreenColor,
// fontWeight: FontWeight.w600,
// disabled: false,
// onPressed: () async {
// Future<PermissionStatus> micPer = Permission.microphone.request();
// Future<PermissionStatus> camPer = Permission.camera.request();
// if (await micPer.isGranted && await camPer.isGranted) {
// await callProv!.buildHubConnection();
// IosCallPayload _iosCallPayload = IosCallPayload(
// uuid: "342h8f=-few-3f23rsd-s-f32-r--sd-3rt-2", incomingCallerId: "341682", incomingCallReciverId: "266642", incomingCallerName: "Aamir.Muhammad", incomingCallType: "video");
//
// Future.delayed(Duration(seconds: 2), () {
// MaterialPageRoute pageRoute = MaterialPageRoute(
// builder: (BuildContext context) => StartCallPage(
// payload: _iosCallPayload,
// ),
// );
// Navigator.push(context, pageRoute);
// });
// } else if (await micPer.isDenied) {
// micPer = Permission.microphone.request();
// } else if (await camPer.isDenied) {
// camPer = Permission.camera.request();
// }
// },
// ),
],
),
),

@ -0,0 +1,46 @@
import 'package:doctor_app_flutter/voipcall/model/get_user_login_token.dart';
class AppState {
static final AppState _instance = AppState._internal();
AppState._internal();
factory AppState() => _instance;
bool isLogged = false;
set setLogged(v) => isLogged = v;
bool get getIsLogged => isLogged;
// Calling
UserAutoLoginModel? chatDetails;
set setchatUserDetails(UserAutoLoginModel details) => chatDetails = details;
UserAutoLoginModel get getchatUserDetails => chatDetails!;
String _iosVoipPlayerID = "";
String get iosVoipPlayerID => _iosVoipPlayerID;
set setiosVoipPlayerID(String value) {
_iosVoipPlayerID = value;
}
bool _isUserOnline = false;
bool get getisUserOnline => _isUserOnline;
set setisUserOnline(bool value) {
_isUserOnline = value;
}
bool _isBackgroundCall = false;
bool get isBackgroundCall => _isBackgroundCall;
set isBackgroundCall(bool value) {
_isBackgroundCall = value;
}
}

@ -0,0 +1,596 @@
import 'dart:core';
import 'dart:io';
import 'dart:ui';
import 'package:doctor_app_flutter/voipcall/app_state.dart';
import 'package:doctor_app_flutter/voipcall/consts.dart';
import 'package:doctor_app_flutter/voipcall/model/call.dart';
import 'package:doctor_app_flutter/voipcall/model/get_single_user_chat_call.dart';
import 'package:doctor_app_flutter/voipcall/model/get_user_login_token.dart';
import 'package:doctor_app_flutter/voipcall/model/incoming_call_model.dart';
import 'package:doctor_app_flutter/voipcall/provider/chat_call_provider.dart';
import 'package:draggable_widget/draggable_widget.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:provider/provider.dart';
bool isCallConnected = false;
class StartCallPage extends StatefulWidget {
IosCallPayload? payload;
StartCallPage({this.payload});
@override
_StartCallPageState createState() => _StartCallPageState();
}
class _StartCallPageState extends State<StartCallPage> {
DragController dragController = DragController();
ChatCallProvider? cProv;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
void startCall() async {
IncomingCallModel? sessionData;
// dynamic calls = await FlutterCallkitIncoming.activeCalls();
// if (calls.isNotEmpty) {
// sessionData.extra.callerDetails = {"id":341682,"userName":"Aamir.Muhammad","email":"Aamir.Muhammad@cloudsolutions.com.sa","phone":null,"title":"Aamir Saleem Ahmad Dost Muhammad","token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzNDE2ODIiLCJlbWFpbCI6IkFhbWlyLk11aGFtbWFkQGNsb3Vkc29sdXRpb25zLmNvbS5zYSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvdXNlcmRhdGEiOiJBYW1pci5NdWhhbW1hZCIsIm5iZiI6MTcwNzIwNTAyMywiZXhwIjoxNzA3MjkxNDIzLCJpYXQiOjE3MDcyMDUwMjN9.Zz2bcsMwiLAAWGZh2E_p5Qs6ItMt0JHhDFI_0DLdggCQtt6HHcT4n8nvqMZx-uYr3jLwqhA_IAjTuaCeSE15sw","isDomainUser":true,"isActiveCode":false,"encryptedUserId":"nn7RkYzbnQc=","encryptedUserName":"/QruOyp4QMcmNXKZlljUgg=="};
// sessionData = IncomingCallModel.fromRawJson(jsonEncode(calls[0]));
if (kDebugMode) {
print(sessionData!.toRawJson());
}
if (cProv!.isUserOnline) {
AppState().isBackgroundCall = true;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
}
await cProv!.startIncomingCallViaKit(inCallData: sessionData!.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
cProv!.init();
isCallConnected = true;
} else {
AppState().isBackgroundCall = true;
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
// cProv.isUserOnline = provider.isUserOnline;
await cProv!.startIncomingCallViaKit(inCallData: sessionData!.extra!.callerDetails!.toJson(), isVCall: sessionData!.extra!.callType == "video" ? true : false);
try {
AppState().setchatUserDetails = UserAutoLoginModel(response: Response.fromJson(sessionData.extra!.loginDetails!.toJson()), errorResponses: null);
await cProv!.buildHubConnection().whenComplete(() {
cProv!.init();
isCallConnected = true;
});
} catch (e) {
print(e);
}
}
//}
// cProv.startRecording();
}
void startIosCall() async {
IosCallPayload iosCallPayload = widget.payload!;
var userID = iosCallPayload.incomingCallReciverId;
var callType = iosCallPayload.incomingCallType;
SingleUserChatModel inCallData = SingleUserChatModel(
targetUserName: iosCallPayload.incomingCallerName,
chatEventId: 3,
targetUserId: int.parse(iosCallPayload.incomingCallerId!),
currentUserId: int.parse(userID.toString()),
);
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
AppState().isBackgroundCall = true;
await cProv!.startIncomingCallViaKit(inCallData: inCallData.toJson(), isVCall: callType == "video" ? true : false);
try {
AppState().setchatUserDetails = UserAutoLoginModel(response: AppState().chatDetails!.response, errorResponses: null);
await cProv!.buildHubConnection().whenComplete(() {
cProv!.init();
isCallConnected = true;
});
} catch (e) {
print(e);
}
}
@override
Widget build(BuildContext context) {
cProv = context.read<ChatCallProvider>();
if (!cProv!.isOutGoingCall) {
if (Platform.isAndroid) {
startCall();
} else if (Platform.isIOS) {
cProv!.buildHubConnection();
startIosCall();
}
}
return Scaffold(
extendBody: true,
body: Consumer<ChatCallProvider>(
builder: (BuildContext context, ChatCallProvider prov, Widget? child) {
return prov.isIncomingCallLoader
? const SizedBox(
width: double.infinity,
height: double.infinity,
child: Center(child: CircularProgressIndicator()),
)
: prov.isIncomingCall
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!prov.isAudioCall && prov.isVideoCall)
RTCVideoView(
prov.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
key: const Key('remote'),
),
if (prov.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(
prov.localVideoRenderer!,
mirror: true,
// filterQuality: FilterQuality.high,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!prov.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>[
SizedBox(
height: 40,
),
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,
),
SizedBox(
height: 10,
),
Text(
prov.incomingCallData!.targetUserName ?? "",
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: const BoxConstraints(),
onPressed: () {
prov.loudOn();
},
elevation: 2.0,
fillColor: prov.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.camOff();
},
elevation: 2.0,
fillColor: prov.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.switchCamera();
},
elevation: 2.0,
fillColor: prov.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.micOff();
},
elevation: 2.0,
fillColor: prov.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.endCall(isUserOnline: prov.isUserOnline).then((bool 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,
),
),
],
),
),
),
],
),
)
: prov.isOutGoingCall
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!prov.isAudioCall && prov.isVideoCall)
RTCVideoView(
prov.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
key: const Key('remote'),
),
if (prov.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(
prov.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!prov.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>[
SizedBox(
height: 40,
),
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,
),
SizedBox(
height: 10,
),
Text(
prov.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: const BoxConstraints(),
onPressed: () {
prov.loudOn();
},
elevation: 2.0,
fillColor: prov.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.camOff();
},
elevation: 2.0,
fillColor: prov.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.switchCamera();
},
elevation: 2.0,
fillColor: prov.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.micOff();
},
elevation: 2.0,
fillColor: prov.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.endCall(isUserOnline: prov.isUserOnline).then(
(bool 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,
),
),
],
),
),
),
],
),
)
: const SizedBox();
},
),
);
}
}

@ -0,0 +1,200 @@
import 'dart:ui';
import 'package:doctor_app_flutter/voipcall/consts.dart';
import 'package:doctor_app_flutter/voipcall/model/call.dart';
import 'package:doctor_app_flutter/voipcall/provider/chat_call_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:provider/provider.dart';
class OutGoingCall extends StatefulWidget {
CallDataModel? outGoingCallData;
bool isVideoCall;
OutGoingCall({Key? key, this.outGoingCallData, this.isVideoCall = false}) : super(key: key);
@override
_OutGoingCallState createState() => _OutGoingCallState();
}
class _OutGoingCallState extends State<OutGoingCall> {
ChatCallProvider? callProvider;
//late ChatProviderModel chatProvider;
bool loader = true;
@override
void initState() {
super.initState();
}
Future<void> init() async {
// widget.isVideoCall ? callProvider!.isVideoCall = true : callProvider!.isVideoCall = false;
widget.isVideoCall = true;
callProvider!.isOutGoingCall = true;
// IosCallPayload payload = IosCallPayload(
// incomingCallerId: widget.outGoingCallData.callerId.toString(),
// incomingCallerName: widget.outGoingCallData.callerName,
// incomingCallReciverId: widget.outGoingCallData.receiverId.toString(),
// incomingCallType: widget.outGoingCallData.callType,
// uuid: "",
// callData: widget.outGoingCallData.toRawJson());
// await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(payload));
await callProvider!.initLocalCamera(callData: widget.outGoingCallData);
loader = false;
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
callProvider = Provider.of<ChatCallProvider>(context, listen: false);
init();
return Scaffold(
body: Consumer<ChatCallProvider>(builder: (BuildContext context, ChatCallProvider chatcp, Widget? child) {
return loader
? const Center(
child: CircularProgressIndicator(),
)
: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (chatcp.isVideoCall)
Positioned.fill(
child: RTCVideoView(
chatcp.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,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(
height: 40,
),
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,
),
SizedBox(
height: 10,
),
Text(
widget.outGoingCallData!.receiverName.toString().replaceAll(".", " "),
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,
),
],
),
),
),
],
),
const Spacer(),
Container(
margin: const EdgeInsets.only(
bottom: 70.0,
left: 49,
right: 49,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () {
chatcp.endCall(isUserOnline: chatcp.isUserOnline).then((bool 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,
),
),
],
),
),
],
),
),
),
),
),
],
);
}),
);
}
BoxDecoration cardRadius(double radius, {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), 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,37 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ApiConsts {
static String chatServerBaseUrl = "https://apiderichat.hmg.com/";
static String chatServerBaseApiUrl = chatServerBaseUrl + "api/";
static String chatLoginTokenUrl = chatServerBaseApiUrl + "user/";
static String chatHubConnectionUrl = chatServerBaseUrl + "ConnectionChatHub";
}
class AppSharedPrefs {
SharedPreferences? sharedPref;
init() async {
sharedPref = await SharedPreferences.getInstance();
}
Future<void> setStringFromPrefs(String key, String value) async {
sharedPref!.setString(key, value);
}
Future<String> getStringFromPrefs(String key) async {
return await sharedPref!.getString(key) ?? "";
}
}
class MyColors {
static const Color backgroundColor = Color(0xffF8F8F8);
static const Color grey41Color = Color(0xff414141);
static const Color grey57Color = Color(0xff575757);
static const Color grey67Color = Color(0xff676767);
static const Color grey77Color = Color(0xff777777);
static const Color greyF7Color = Color(0xffF7F7F7);
static const Color white = Color(0xffffffff);
static const Color redA3Color = Color(0xffCA3332);
static const Color textMixColor = Color(0xff2BB8A6);
}

@ -0,0 +1,164 @@
// To parse this JSON data, do
//
// final callDataModel = callDataModelFromJson(jsonString);
import 'dart:convert';
class CallDataModel {
CallDataModel({
this.callerId,
this.callerName,
this.callerEmail,
this.callerTitle,
this.callerPhone,
this.receiverId,
this.receiverName,
this.receiverEmail,
this.receiverTitle,
this.receiverPhone,
this.title,
this.callType,
});
int? callerId;
String? callerName;
String? callerEmail;
String? callerTitle;
dynamic? callerPhone;
int? receiverId;
String? receiverName;
String? receiverEmail;
dynamic? receiverTitle;
dynamic? receiverPhone;
String? title;
String? callType;
factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory CallDataModel.fromJson(Map<String, dynamic> json) => CallDataModel(
callerId: json["callerID"],
callerName: json["callerName"],
callerEmail: json["callerEmail"],
callerTitle: json["callerTitle"],
callerPhone: json["callerPhone"],
receiverId: json["receiverID"],
receiverName: json["receiverName"],
receiverEmail: json["receiverEmail"],
receiverTitle: json["receiverTitle"],
receiverPhone: json["receiverPhone"],
title: json["title"],
callType: json["callType"],
);
Map<String, dynamic> toJson() => {
"callerID": callerId,
"callerName": callerName,
"callerEmail": callerEmail,
"callerTitle": callerTitle,
"callerPhone": callerPhone,
"receiverID": receiverId,
"receiverName": receiverName,
"receiverEmail": receiverEmail,
"receiverTitle": receiverTitle,
"receiverPhone": receiverPhone,
"title": title,
"callType": callType,
};
}
// To parse this JSON data, do
//
// final callSessionPayLoad = callSessionPayLoadFromJson(jsonString);
class CallSessionPayLoad {
CallSessionPayLoad({
this.target,
this.caller,
this.sdp,
});
int? target;
int? caller;
Sdp? sdp;
factory CallSessionPayLoad.fromRawJson(String str) => CallSessionPayLoad.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory CallSessionPayLoad.fromJson(Map<String, dynamic> json) => CallSessionPayLoad(
target: json["target"],
caller: json["caller"],
sdp: json["sdp"] == null ? null : Sdp.fromJson(json["sdp"]),
);
Map<String, dynamic> toJson() => {
"target": target,
"caller": caller,
"sdp": sdp?.toJson(),
};
}
class Sdp {
Sdp({
this.type,
this.sdp,
});
String? type;
String? sdp;
factory Sdp.fromRawJson(String str) => Sdp.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Sdp.fromJson(Map<String, dynamic> json) => Sdp(
type: json["type"],
sdp: json["sdp"],
);
Map<String, dynamic> toJson() => {
"type": type,
"sdp": sdp,
};
}
// final iosCallPayload = iosCallPayloadFromJson(jsonString);
class IosCallPayload {
String? incomingCallType;
String? incomingCallerId;
String? incomingCallReciverId;
String? incomingCallerName;
String? callData;
String? uuid;
IosCallPayload({
this.incomingCallType,
this.incomingCallerId,
this.incomingCallReciverId,
this.incomingCallerName,
this.callData,
this.uuid,
});
factory IosCallPayload.fromRawJson(String str) => IosCallPayload.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory IosCallPayload.fromJson(Map<String, dynamic> json) => IosCallPayload(
incomingCallType: json["incoming_call_type"],
incomingCallerId: json["incoming_caller_id"],
incomingCallerName: json["incoming_caller_name"],
incomingCallReciverId: null,
uuid: json["uuid"],
);
Map<String, dynamic> toJson() => {
"incoming_call_type": incomingCallType,
"incoming_caller_id": incomingCallerId,
"incoming_caller_name": incomingCallerName,
"uuid": uuid,
};
}

@ -0,0 +1,207 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:just_audio/just_audio.dart';
List<SingleUserChatModel> singleUserChatModelFromJson(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x)));
String singleUserChatModelToJson(List<SingleUserChatModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SingleUserChatModel {
SingleUserChatModel(
{this.userChatHistoryId,
this.userChatHistoryLineId,
this.contant,
this.contantNo,
this.currentUserId,
this.currentUserName,
this.targetUserId,
this.targetUserName,
this.encryptedTargetUserId,
this.encryptedTargetUserName,
this.currentUserEmail,
this.targetUserEmail,
this.chatEventId,
this.fileTypeId,
this.isSeen,
this.isDelivered,
this.createdDate,
this.chatSource,
this.conversationId,
this.fileTypeResponse,
this.userChatReplyResponse,
this.isReplied,
this.isImageLoaded,
this.image,
this.voice,
this.voiceController});
int? userChatHistoryId;
int? userChatHistoryLineId;
String? contant;
String? contantNo;
int? currentUserId;
String? currentUserName;
String? currentUserEmail;
int? targetUserId;
String? targetUserName;
String? targetUserEmail;
String? encryptedTargetUserId;
String? encryptedTargetUserName;
int? chatEventId;
dynamic fileTypeId;
bool? isSeen;
bool? isDelivered;
DateTime? createdDate;
int? chatSource;
String? conversationId;
FileTypeResponse? fileTypeResponse;
UserChatReplyResponse? userChatReplyResponse;
bool? isReplied;
bool? isImageLoaded;
Uint8List? image;
File? voice;
AudioPlayer? voiceController;
factory SingleUserChatModel.fromJson(Map<String, dynamic> json) => SingleUserChatModel(
userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"],
userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"],
contant: json["contant"] == null ? null : json["contant"],
contantNo: json["contantNo"] == null ? null : json["contantNo"],
currentUserId: json["currentUserId"] == null ? null : json["currentUserId"],
currentUserName: json["currentUserName"] == null ? null : json["currentUserName"],
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"],
targetUserName: json["targetUserName"] == null ? null : json["targetUserName"],
targetUserEmail: json["targetUserEmail"] == null ? null : json["targetUserEmail"],
currentUserEmail: json["currentUserEmail"] == null ? null : json["currentUserEmail"],
encryptedTargetUserId: json["encryptedTargetUserId"] == null ? null : json["encryptedTargetUserId"],
encryptedTargetUserName: json["encryptedTargetUserName"] == null ? null : json["encryptedTargetUserName"],
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"],
fileTypeId: json["fileTypeId"],
isSeen: json["isSeen"] == null ? null : json["isSeen"],
isDelivered: json["isDelivered"] == null ? null : json["isDelivered"],
createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
chatSource: json["chatSource"] == null ? null : json["chatSource"],
conversationId: json["conversationId"] == null ? null : json["conversationId"],
fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]),
isReplied: false,
isImageLoaded: false,
image: null,
voice: null,
voiceController: json["fileTypeId"] == 13 ? AudioPlayer() : null);
Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,
"userChatHistoryLineId": userChatHistoryLineId == null ? null : userChatHistoryLineId,
"contant": contant == null ? null : contant,
"contantNo": contantNo == null ? null : contantNo,
"currentUserId": currentUserId == null ? null : currentUserId,
"currentUserName": currentUserName == null ? null : currentUserName,
"targetUserId": targetUserId == null ? null : targetUserId,
"targetUserName": targetUserName == null ? null : targetUserName,
"encryptedTargetUserId": encryptedTargetUserId == null ? null : encryptedTargetUserId,
"encryptedTargetUserName": encryptedTargetUserName == null ? null : encryptedTargetUserName,
"currentUserEmail": currentUserEmail == null ? null : currentUserEmail,
"targetUserEmail": targetUserEmail == null ? null : targetUserEmail,
"chatEventId": chatEventId == null ? null : chatEventId,
"fileTypeId": fileTypeId,
"isSeen": isSeen == null ? null : isSeen,
"isDelivered": isDelivered == null ? null : isDelivered,
"createdDate": createdDate == null ? null : createdDate!.toIso8601String(),
"chatSource": chatSource == null ? null : chatSource,
"conversationId": conversationId == null ? null : conversationId,
"fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(),
"userChatReplyResponse": userChatReplyResponse == null ? null : userChatReplyResponse!.toJson(),
};
}
class FileTypeResponse {
FileTypeResponse({
this.fileTypeId,
this.fileTypeName,
this.fileTypeDescription,
this.fileKind,
this.fileName,
});
int? fileTypeId;
dynamic fileTypeName;
dynamic fileTypeDescription;
dynamic fileKind;
dynamic fileName;
factory FileTypeResponse.fromJson(Map<String, dynamic> json) => FileTypeResponse(
fileTypeId: json["fileTypeId"] == null ? null : json["fileTypeId"],
fileTypeName: json["fileTypeName"],
fileTypeDescription: json["fileTypeDescription"],
fileKind: json["fileKind"],
fileName: json["fileName"],
);
Map<String, dynamic> toJson() => {
"fileTypeId": fileTypeId == null ? null : fileTypeId,
"fileTypeName": fileTypeName,
"fileTypeDescription": fileTypeDescription,
"fileKind": fileKind,
"fileName": fileName,
};
}
class UserChatReplyResponse {
UserChatReplyResponse(
{this.userChatHistoryId,
this.chatEventId,
this.contant,
this.contantNo,
this.fileTypeId,
this.createdDate,
this.targetUserId,
this.targetUserName,
this.fileTypeResponse,
this.isImageLoaded,
this.image,
this.voice});
int? userChatHistoryId;
int? chatEventId;
String? contant;
String? contantNo;
dynamic fileTypeId;
DateTime? createdDate;
int? targetUserId;
String? targetUserName;
FileTypeResponse? fileTypeResponse;
bool? isImageLoaded;
Uint8List? image;
Uint8List? voice;
factory UserChatReplyResponse.fromJson(Map<String, dynamic> json) => UserChatReplyResponse(
userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"],
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"],
contant: json["contant"] == null ? null : json["contant"],
contantNo: json["contantNo"] == null ? null : json["contantNo"],
fileTypeId: json["fileTypeId"],
createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"],
targetUserName: json["targetUserName"] == null ? null : json["targetUserName"],
fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
isImageLoaded: false,
image: null,
voice: null,
);
Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId,
"chatEventId": chatEventId == null ? null : chatEventId,
"contant": contant == null ? null : contant,
"contantNo": contantNo == null ? null : contantNo,
"fileTypeId": fileTypeId,
"createdDate": createdDate == null ? null : createdDate!.toIso8601String(),
"targetUserId": targetUserId == null ? null : targetUserId,
"targetUserName": targetUserName == null ? null : targetUserName,
"fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(),
};
}

@ -0,0 +1,97 @@
import 'dart:convert';
UserAutoLoginModel userAutoLoginModelFromJson(String str) => UserAutoLoginModel.fromJson(json.decode(str));
String userAutoLoginModelToJson(UserAutoLoginModel data) => json.encode(data.toJson());
class UserAutoLoginModel {
UserAutoLoginModel({
this.response,
this.errorResponses,
});
Response? response;
List<ErrorResponse>? errorResponses;
factory UserAutoLoginModel.fromJson(Map<String, dynamic> json) => UserAutoLoginModel(
response: json["response"] == null ? null : Response.fromJson(json["response"]),
errorResponses: json["errorResponses"] == null ? null : List<ErrorResponse>.from(json["errorResponses"].map((x) => ErrorResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"response": response == null ? null : response!.toJson(),
"errorResponses": errorResponses == null ? null : List<dynamic>.from(errorResponses!.map((x) => x.toJson())),
};
}
class Response {
Response({
this.id,
this.userName,
this.email,
this.phone,
this.title,
this.token,
this.isDomainUser,
this.isActiveCode,
this.encryptedUserId,
this.encryptedUserName,
});
int? id;
String? userName;
String? email;
String? phone;
String? title;
String? token;
bool? isDomainUser;
bool? isActiveCode;
String? encryptedUserId;
String? encryptedUserName;
factory Response.fromJson(Map<String, dynamic> json) => Response(
id: json["id"] == null ? null : json["id"],
userName: json["userName"] == null ? null : json["userName"],
email: json["email"] == null ? null : json["email"],
phone: json["phone"] == null ? null : json["phone"],
title: json["title"] == null ? null : json["title"],
token: json["token"] == null ? null : json["token"],
isDomainUser: json["isDomainUser"] == null ? null : json["isDomainUser"],
isActiveCode: json["isActiveCode"] == null ? null : json["isActiveCode"],
encryptedUserId: json["encryptedUserId"] == null ? null : json["encryptedUserId"],
encryptedUserName: json["encryptedUserName"] == null ? null : json["encryptedUserName"],
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"userName": userName == null ? null : userName,
"email": email == null ? null : email,
"phone": phone == null ? null : phone,
"title": title == null ? null : title,
"token": token == null ? null : token,
"isDomainUser": isDomainUser == null ? null : isDomainUser,
"isActiveCode": isActiveCode == null ? null : isActiveCode,
"encryptedUserId": encryptedUserId == null ? null : encryptedUserId,
"encryptedUserName": encryptedUserName == null ? null : encryptedUserName,
};
}
class ErrorResponse {
ErrorResponse({
this.fieldName,
this.message,
});
String? fieldName;
String? message;
factory ErrorResponse.fromJson(Map<String, dynamic> json) => ErrorResponse(
fieldName: json["fieldName"] == null ? null : json["fieldName"],
message: json["message"] == null ? null : json["message"],
);
Map<String, dynamic> toJson() => {
"fieldName": fieldName == null ? null : fieldName,
"message": message == null ? null : message,
};
}

@ -0,0 +1,333 @@
// To parse this JSON data, do
//
// final incomingCallModel = incomingCallModelFromJson(jsonString);
import 'dart:convert';
class IncomingCallModel {
String? actionColor;
String? appName;
Args? args;
String? avatar;
String? backgroundColor;
String? backgroundUrl;
int? duration;
Extra? extra;
String? from;
String? handle;
Args? headers;
String? id;
bool? isAccepted;
bool? isCustomNotification;
bool? isCustomSmallExNotification;
bool? isShowCallback;
bool? isShowLogo;
bool? isShowMissedCallNotification;
String? nameCaller;
String? ringtonePath;
String? textAccept;
String? textCallback;
String? textDecline;
String? textMissedCall;
int? type;
String? uuid;
IncomingCallModel({
this.actionColor,
this.appName,
this.args,
this.avatar,
this.backgroundColor,
this.backgroundUrl,
this.duration,
this.extra,
this.from,
this.handle,
this.headers,
this.id,
this.isAccepted,
this.isCustomNotification,
this.isCustomSmallExNotification,
this.isShowCallback,
this.isShowLogo,
this.isShowMissedCallNotification,
this.nameCaller,
this.ringtonePath,
this.textAccept,
this.textCallback,
this.textDecline,
this.textMissedCall,
this.type,
this.uuid,
});
factory IncomingCallModel.fromRawJson(String str) => IncomingCallModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory IncomingCallModel.fromJson(Map<String, dynamic> json) => IncomingCallModel(
actionColor: json["actionColor"],
appName: json["appName"],
args: json["args"] == null ? null : Args.fromJson(json["args"]),
avatar: json["avatar"],
backgroundColor: json["backgroundColor"],
backgroundUrl: json["backgroundUrl"],
duration: json["duration"] == null ? null : json["duration"].toInt(),
extra: json["extra"] == null ? null : Extra.fromJson(json["extra"]),
from: json["from"],
handle: json["handle"],
headers: json["headers"] == null ? null : Args.fromJson(json["headers"]),
id: json["id"],
isAccepted: json["isAccepted"],
isCustomNotification: json["isCustomNotification"],
isCustomSmallExNotification: json["isCustomSmallExNotification"],
isShowCallback: json["isShowCallback"],
isShowLogo: json["isShowLogo"],
isShowMissedCallNotification: json["isShowMissedCallNotification"],
nameCaller: json["nameCaller"],
ringtonePath: json["ringtonePath"],
textAccept: json["textAccept"],
textCallback: json["textCallback"],
textDecline: json["textDecline"],
textMissedCall: json["textMissedCall"],
type: json["type"] == null ? null : json["type"].toInt(),
uuid: json["uuid"],
);
Map<String, dynamic> toJson() => {
"actionColor": actionColor,
"appName": appName,
"args": args?.toJson(),
"avatar": avatar,
"backgroundColor": backgroundColor,
"backgroundUrl": backgroundUrl,
"duration": duration,
"extra": extra?.toJson(),
"from": from,
"handle": handle,
"headers": headers?.toJson(),
"id": id,
"isAccepted": isAccepted,
"isCustomNotification": isCustomNotification,
"isCustomSmallExNotification": isCustomSmallExNotification,
"isShowCallback": isShowCallback,
"isShowLogo": isShowLogo,
"isShowMissedCallNotification": isShowMissedCallNotification,
"nameCaller": nameCaller,
"ringtonePath": ringtonePath,
"textAccept": textAccept,
"textCallback": textCallback,
"textDecline": textDecline,
"textMissedCall": textMissedCall,
"type": type,
"uuid": uuid,
};
}
class Args {
Args();
factory Args.fromRawJson(String str) => Args.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Args.fromJson(Map<String, dynamic> json) => Args();
Map<String, dynamic> toJson() => {};
}
class Extra {
LoginDetails? loginDetails;
bool? isIncomingCall;
CallerDetails? callerDetails;
String? callType;
Extra({
this.loginDetails,
this.isIncomingCall,
this.callerDetails,
this.callType,
});
factory Extra.fromRawJson(String str) => Extra.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Extra.fromJson(Map<String, dynamic> json) => Extra(
loginDetails: json["loginDetails"] == null ? null : LoginDetails.fromJson(json["loginDetails"]),
isIncomingCall: json["isIncomingCall"],
callType: json["callType"],
callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]),
);
Map<String, dynamic> toJson() => {
"loginDetails": loginDetails?.toJson(),
"isIncomingCall": isIncomingCall,
"callType": callType,
"callerDetails": callerDetails?.toJson(),
};
}
class CallerDetails {
int? userChatHistoryId;
String? contant;
FileTypeResponse? fileTypeResponse;
String? currentUserName;
String? targetUserEmail;
String? conversationId;
String? encryptedTargetUserId;
int? targetUserId;
bool? isSeen;
int? userChatHistoryLineId;
bool? isDelivered;
String? targetUserName;
int? currentUserId;
DateTime? createdDate;
String? currentUserEmail;
String? contantNo;
int? chatEventId;
String? encryptedTargetUserName;
int? chatSource;
CallerDetails({
this.userChatHistoryId,
this.contant,
this.fileTypeResponse,
this.currentUserName,
this.targetUserEmail,
this.conversationId,
this.encryptedTargetUserId,
this.targetUserId,
this.isSeen,
this.userChatHistoryLineId,
this.isDelivered,
this.targetUserName,
this.currentUserId,
this.createdDate,
this.currentUserEmail,
this.contantNo,
this.chatEventId,
this.encryptedTargetUserName,
this.chatSource,
});
factory CallerDetails.fromRawJson(String str) => CallerDetails.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory CallerDetails.fromJson(Map<String, dynamic> json) => CallerDetails(
userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"].toInt(),
contant: json["contant"],
fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
currentUserName: json["currentUserName"],
targetUserEmail: json["targetUserEmail"],
conversationId: json["conversationId"],
encryptedTargetUserId: json["encryptedTargetUserId"],
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"].toInt(),
isSeen: json["isSeen"],
userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"].toInt(),
isDelivered: json["isDelivered"],
targetUserName: json["targetUserName"],
currentUserId: json["currentUserId"] == null ? null : json["currentUserId"].toInt(),
createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
currentUserEmail: json["currentUserEmail"],
contantNo: json["contantNo"],
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"].toInt(),
encryptedTargetUserName: json["encryptedTargetUserName"],
chatSource: json["chatSource"] == null ? null : json["chatSource"].toInt(),
);
Map<String, dynamic> toJson() => {
"userChatHistoryId": userChatHistoryId,
"contant": contant,
"fileTypeResponse": fileTypeResponse?.toJson(),
"currentUserName": currentUserName,
"targetUserEmail": targetUserEmail,
"conversationId": conversationId,
"encryptedTargetUserId": encryptedTargetUserId,
"targetUserId": targetUserId,
"isSeen": isSeen,
"userChatHistoryLineId": userChatHistoryLineId,
"isDelivered": isDelivered,
"targetUserName": targetUserName,
"currentUserId": currentUserId,
"createdDate": createdDate?.toIso8601String(),
"currentUserEmail": currentUserEmail,
"contantNo": contantNo,
"chatEventId": chatEventId,
"encryptedTargetUserName": encryptedTargetUserName,
"chatSource": chatSource,
};
}
class FileTypeResponse {
int? fileTypeId;
FileTypeResponse({
this.fileTypeId,
});
factory FileTypeResponse.fromRawJson(String str) => FileTypeResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory FileTypeResponse.fromJson(Map<String, dynamic> json) => FileTypeResponse(
fileTypeId: json["fileTypeId"].toInt(),
);
Map<String, dynamic> toJson() => {
"fileTypeId": fileTypeId,
};
}
class LoginDetails {
bool? isActiveCode;
int? id;
String? encryptedUserName;
String? userName;
String? title;
String? encryptedUserId;
String? email;
bool? isDomainUser;
String? token;
LoginDetails({
this.isActiveCode,
this.id,
this.encryptedUserName,
this.userName,
this.title,
this.encryptedUserId,
this.email,
this.isDomainUser,
this.token,
});
factory LoginDetails.fromRawJson(String str) => LoginDetails.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory LoginDetails.fromJson(Map<String, dynamic> json) => LoginDetails(
isActiveCode: json["isActiveCode"],
id: json["id"] == null ? null : json["id"].toInt(),
encryptedUserName: json["encryptedUserName"],
userName: json["userName"],
title: json["title"],
encryptedUserId: json["encryptedUserId"],
email: json["email"],
isDomainUser: json["isDomainUser"],
token: json["token"],
);
Map<String, dynamic> toJson() => {
"isActiveCode": isActiveCode,
"id": id,
"encryptedUserName": encryptedUserName,
"userName": userName,
"title": title,
"encryptedUserId": encryptedUserId,
"email": email,
"isDomainUser": isDomainUser,
"token": token,
};
}

@ -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,
};
}

@ -0,0 +1,821 @@
import 'dart:convert';
import 'dart:io';
import 'package:doctor_app_flutter/core/service/NavigationService.dart';
import 'package:doctor_app_flutter/locator.dart';
import 'package:doctor_app_flutter/routes.dart';
import 'package:doctor_app_flutter/utils/utils.dart';
import 'package:doctor_app_flutter/voipcall/app_state.dart';
import 'package:doctor_app_flutter/voipcall/call/chat_incoming_call_screen.dart';
import 'package:doctor_app_flutter/voipcall/consts.dart';
import 'package:doctor_app_flutter/voipcall/model/call.dart';
import 'package:doctor_app_flutter/voipcall/model/get_single_user_chat_call.dart';
import 'package:doctor_app_flutter/voipcall/model/get_user_login_token.dart';
import 'package:doctor_app_flutter/voipcall/model/webrtc_payloads.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:http/http.dart' as http;
import 'package:just_audio/just_audio.dart';
import 'package:signalr_netcore/signalr_client.dart';
class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
///////////////////// Web RTC Video Calling //////////////////////
// Video Call
HubConnection? chatHubConnection;
RTCPeerConnection? _pc;
//late ChatProviderModel chatProvModel;
RTCVideoRenderer? localVideoRenderer;
RTCVideoRenderer? remoteRenderer;
final AudioPlayer player = AudioPlayer();
MediaStream? _localStream;
CallDataModel? outGoingCallData;
bool isMicOff = false;
bool isLoudSpeaker = false;
bool isCamOff = false;
bool isCallEnded = false;
// This need to Be Changed to dynamic
bool isVideoCall = true;
bool isAudioCall = false;
bool isCallStarted = false;
bool isFrontCamera = true;
SingleUserChatModel? incomingCallData;
/// WebRTC Connection Variables
bool isIncomingCallLoader = true;
bool isIncomingCall = false;
bool isOutGoingCall = false;
bool isUserOnline = false;
List<MediaDeviceInfo> devices = [];
Future<void> buildHubConnection() async {
try {
chatHubConnection = await getHubConnection();
await chatHubConnection!.start();
} catch (e) {
print(e.toString());
Utils.showErrorToast(e.toString());
}
if (kDebugMode) {
print("Hub Conn: Startedddddddd");
}
registerCallListners();
}
//{"id":341682,"userName":"Aamir.Muhammad","email":"Aamir.Muhammad@cloudsolutions.com.sa","phone":null,"title":"Aamir Saleem Ahmad Dost Muhammad","token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzNDE2ODIiLCJlbWFpbCI6IkFhbWlyLk11aGFtbWFkQGNsb3Vkc29sdXRpb25zLmNvbS5zYSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvdXNlcmRhdGEiOiJBYW1pci5NdWhhbW1hZCIsIm5iZiI6MTcwNzIwNTAyMywiZXhwIjoxNzA3MjkxNDIzLCJpYXQiOjE3MDcyMDUwMjN9.Zz2bcsMwiLAAWGZh2E_p5Qs6ItMt0JHhDFI_0DLdggCQtt6HHcT4n8nvqMZx-uYr3jLwqhA_IAjTuaCeSE15sw","isDomainUser":true,"isActiveCode":false,"encryptedUserId":"nn7RkYzbnQc=","encryptedUserName":"/QruOyp4QMcmNXKZlljUgg=="}
Future<HubConnection> getHubConnection() async {
AppState().chatDetails = UserAutoLoginModel(
response: Response.fromJson({
"id": 266642,
"userName": "Muhamad.Alam",
"email": "Muhamad.Alam@cloudsolutions.com.sa",
"phone": null,
"title": "Muhamad.Alam",
"token":
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIyNjY2NDIiLCJlbWFpbCI6Ik11aGFtYWQuQWxhbUBjbG91ZHNvbHV0aW9ucy5jb20uc2EiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoiTXVoYW1hZC5BbGFtIiwibmJmIjoxNzA4MjU2MjU4LCJleHAiOjE3MDgzNDI2NTgsImlhdCI6MTcwODI1NjI1OH0.Ol8VJFhaFMFgcMXpFi8XI38v8dDmh8-tpPaXSWTXQF1yXqPFNtnyN2t_6ar3-N92bS60yZ1w3v4s3Tx7dirfow",
"isDomainUser": true,
"isActiveCode": false,
"encryptedUserId": "8NOEvvO7oi0=",
"encryptedUserName": "YaYBnsXyEusQT8TAOmYQqA=="
}),
);
HubConnection hub;
HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
hub = HubConnectionBuilder()
.withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp)
.withAutomaticReconnect(retryDelays: <int>[2000, 5000, 10000, 20000]).build();
return hub;
}
Future<CallDataModel> makeCall({required String callType}) async {
Map<String, dynamic> json = {
"callerID": AppState().chatDetails!.response!.id,
"callerName": AppState().chatDetails!.response!.userName,
"callerEmail": AppState().chatDetails!.response!.email,
"callerTitle": AppState().chatDetails!.response!.title,
"callerPhone": AppState().chatDetails!.response!.phone,
"receiverID": 266642,
"receiverName": "Muhammad Alam",
"receiverEmail": "Muhamad.Alam@cloudsolutions.com.sa",
"receiverTitle": "Muhammad Alam",
"receiverPhone": "123456789",
"title": "Muhammad Alam",
"callType": callType == "VIDEO" ? "Video" : "Audio",
};
CallDataModel res = CallDataModel.fromJson(json);
return res;
}
void registerCallListners() {
if (kDebugMode) {
print("=================== Call Listeners Registered =======================");
}
chatHubConnection!.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection!.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection!.on("OnOfferAsync", onOfferAsync);
chatHubConnection!.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection!.on("OnHangUpAsync", onHangUpAsync);
// chatHubConnection!.on("OnCallDeclinedAsync", onCallDeclinedAsync);
// chatHubConnection!.on("OnIncomingCallAsync", OnIncomingCallAsync);
}
// Audio Constraints
Map<String, Object> audioConstraints = {
"sampleRate": 8000,
"sampleSize": 16,
"channelCount": 2,
"echoCancellation": true,
"audio": true,
};
Future<void> init() async {
_pc = await creatOfferWithCon();
Future.delayed(const Duration(seconds: 2), () {
connectIncomingCall();
});
}
///////////////////////////////////////////////OutGoing Call////////////////////////////////////////////////////
Future<void> initLocalCamera({callData, bool isIncomingCall = false}) async {
isCallEnded = false;
outGoingCallData = callData;
await initStreams();
await startCall();
_pc = await creatOfferWithCon();
connectOutgoing();
notifyListeners();
}
void connectOutgoing() {
isOutGoingCall = true;
// notifyListeners();
}
Future<void> startCall() async {
// chatProvModel.isTextMsg = true;
// chatProvModel.isAttachmentMsg = false;
// chatProvModel.isVoiceMsg = false;
// chatProvModel.isReplyMsg = false;
// chatProvModel.isCall = true;
// chatProvModel.message.text = "Start $callType call ${outGoingCallData.receiverName.toString().replaceAll(".", " ")}";
// chatProvModel.sendChatMessage(
// context,
// targetUserId: outGoingCallData.receiverId,
// userStatus: 1,
// userEmail: outGoingCallData.receiverEmail,
// targetUserName: outGoingCallData.receiverName,
// );
await invoke(
invokeMethod: "CallUserAsync",
currentUserID: outGoingCallData!.callerId!,
targetUserID: outGoingCallData!.receiverId!,
);
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 4);
}
// OutGoing Listeners
void onCallAcceptedAsync(List<Object?>? params) async {
dynamic items = params!.toList();
RTCSessionDescription description = await _createOffer();
await _pc!.setLocalDescription(description);
dynamic payload = {"target": items[0]["id"], "caller": outGoingCallData!.callerId, "sdp": description.toMap()};
invoke(invokeMethod: "OfferAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload));
}
Future<void> onIceCandidateAsync(List<Object?>? params) async {
dynamic items = params!.toList();
if (isIncomingCall) {
RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString()));
if (_pc != null) {
await _pc!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex));
}
} else {
if (kDebugMode) {
print("res: " + items.toString());
}
RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString()));
if (_pc != null) {
await _pc!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex));
if (!isCallStarted) {
isCallStarted = true;
notifyListeners();
if (isCallStarted) {
isIncomingCallLoader = false;
isOutGoingCall = true;
if (Platform.isIOS) {
Future.delayed(Duration(seconds: 2), () {
Navigator.pushReplacement(
locator<NavigationService>().navigatorKey.currentContext!,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
));
});
} else {
Navigator.pushReplacement(
locator<NavigationService>().navigatorKey.currentContext!,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
));
}
}
}
}
notifyListeners();
}
}
Future<void> onOfferAsync(List<Object?>? params) async {
dynamic items = params!.toList();
var data = jsonDecode(items.toString());
if (isIncomingCall) {
_pc!.setRemoteDescription(RTCSessionDescription(data[0]["sdp"]["sdp"], data[0]["sdp"]["type"]));
RTCSessionDescription description = await _createAnswer();
await _pc!.setLocalDescription(description);
dynamic payload = {"target": data[0]["caller"], "caller": AppState().chatDetails!.response!.id!, "sdp": description.toMap()};
invoke(invokeMethod: "AnswerOfferAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, data: jsonEncode(payload));
}
// else {
// RTCSessionDescription description = await _createAnswer();
// await _pc.setLocalDescription(description);
// var payload = {"target": items[0]["id"], "caller": outGoingCallData.callerId, "sdp": description.toMap()};
// invoke(invokeMethod: "AnswerOffer", currentUserID: outGoingCallData.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload));
// }
notifyListeners();
}
//////////////////////////// OutGoing Call End ///////////////////////////////////////
Future<bool> endCall({bool? isUserOnline}) async {
if (isIncomingCall) {
print("-----------------------Endeddddd By Me---------------------------");
if (chatHubConnection!.state == HubConnectionState.Connected) {
await invoke(invokeMethod: "HangUpAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 0);
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 1);
}
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
isIncomingCall = false;
isOutGoingCall = false;
isAudioCall = false;
if (isCallConnected) {
if (_pc!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
if (kDebugMode) {
print("------------------ PC Stopped ----------------------------");
}
_pc!.close();
_pc!.dispose();
}
}
if (remoteRenderer != null) {
remoteRenderer!.dispose();
remoteRenderer = null;
}
if (localVideoRenderer != null) {
localVideoRenderer!.dispose();
localVideoRenderer = null;
}
if (_localStream != null) {
_localStream!.dispose();
_localStream = null;
}
if (chatHubConnection != null && !isUserOnline!) {
chatHubConnection!.stop();
}
await FlutterCallkitIncoming.endAllCalls();
return true;
} else {
if (isOutGoingCall) {
await invoke(invokeMethod: "HangUpAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 1);
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 1);
} else if (isIncomingCall) {
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 1);
}
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
if (isCallConnected) {
if (_pc!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
_pc!.close();
_pc!.dispose();
}
}
if (remoteRenderer != null) {
remoteRenderer!.dispose();
remoteRenderer = null;
}
if (localVideoRenderer != null) {
localVideoRenderer!.dispose();
localVideoRenderer = null;
}
if (_localStream != null) {
_localStream!.dispose();
_localStream = null;
}
isOutGoingCall = false;
isIncomingCall = false;
isAudioCall = false;
return true;
}
}
// Incoming Listeners
void onAnswerOffer(List<Object?>? payload) async {
// if (isIncomingCall) {
// // print("--------------------- On Answer Offer Async ---------------------------------------");
// //await invoke(invokeMethod: "InvokeMobile", currentUserID: AppState().getchatUserDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, debugData: {"On Answer Offer Async"});
// } else {
var items = payload!.toList();
if (kDebugMode) {
print("res: " + items.toString());
}
CallSessionPayLoad data = CallSessionPayLoad.fromJson(jsonDecode(items.first.toString()));
RTCSessionDescription description = RTCSessionDescription(data.sdp!.sdp, 'answer');
_pc!.setRemoteDescription(description);
// }
}
void onHangUpAsync(List<Object?>? params) {
print("--------------------- onHangUp ASYNC ---------------------------------");
dynamic items = params!.toList();
// if (kDebugMode) {
// logger.i("res: " + items.toString());
// }
if (items[0]["id"] != AppState().chatDetails!.response!.id!) {
if (kDebugMode) {
print("Call Ended By Other User");
}
if (isIncomingCall) {
endCall(isUserOnline: isUserOnline).then((bool value) {
if (isCallConnected && isUserOnline) {
isCallConnected = false;
if (!AppState().isLogged) {
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
} else {
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME));
}
} else {
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
}
});
} else {
if (isOutGoingCall) {
endCall(isUserOnline: isUserOnline).then((bool value) {
if (isCallConnected && isUserOnline) {
isCallConnected = false;
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME));
} else {
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
}
});
}
}
} else {
if (kDebugMode) {
print("Call Ended By Me");
}
if (isOutGoingCall) {
if (isCallConnected && isUserOnline) {
isCallConnected = false;
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME));
} else {
Navigator.of(locator<NavigationService>().navigatorKey.currentContext!).pop();
}
}
}
// endCall(isUserOnline: isUserOnline).then((bool value) {
// if (isCallConnected && isUserOnline) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
// isCallConnected = false;
// }
// if (items[0]["id"] != AppState().chatDetails!!.response!.id && !AppState().isBackgroundCall) {
// if (kDebugMode) {
// print("Popped Due to Another User");
// }
// if (AppState().isBackgroundCall) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
// // Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.login));
// } else {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chat));
// }
// }
// if (AppState().isBackgroundCall) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
// }
//
notifyListeners();
isCallEnded = true;
// });
}
// Future<void> OnIncomingCallAsync(List<Object?>? params) async {
// print("--------------------- On Incoming Call ---------------------------------------");
// dynamic items = params!.toList();
// logger.d(items);
// // Map<String, dynamic> json = {
// // "callerID": items[0]["id"],
// // "callerName": items[0]["userName"],
// // "callerEmail": items[0]["email"],
// // "callerTitle": items[0]["title"],
// // "callerPhone": null,
// // "receiverID": AppState().chatDetails!!.response!.id,
// // "receiverName": AppState().chatDetails!!.response!.userName,
// // "receiverEmail": AppState().chatDetails!!.response!.email,
// // "receiverTitle": AppState().chatDetails!!.response!.title,
// // "receiverPhone": AppState().chatDetails!!.response!.phone,
// // "title": AppState().chatDetails!!.response!.userName!.replaceAll(".", " "),
// // "callType": items[1] ? "Video" : "Audio",
// // };
// // CallDataModel callData = CallDataModel.fromJson(json);
// // ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), isOnline: true, incomingCallData: callData);
// //
// // if (!isOnIncomingCallPage) {
// // Map<String, dynamic> json = {
// // "callerID": items[0]["id"],
// // "callerName": items[0]["userName"],
// // "callerEmail": items[0]["email"],
// // "callerTitle": items[0]["title"],
// // "callerPhone": null,
// // "receiverID": AppState().chatDetails!!.response!.id,
// // "receiverName": AppState().chatDetails!!.response!.userName,
// // "receiverEmail": AppState().chatDetails!!.response!.email,
// // "receiverTitle": AppState().chatDetails!!.response!.title,
// // "receiverPhone": AppState().chatDetails!!.response!.phone,
// // "title": AppState().chatDetails!!.response!.userName!.replaceAll(".", " "),
// // "callType": items[1] ? "Video" : "Audio",
// // };
// // CallDataModel callData = CallDataModel.fromJson(json);
// // await Navigator.push(
// // providerContext,
// // MaterialPageRoute(
// // builder: (BuildContext context) => IncomingCall(
// // isVideoCall: items[1] ? true : false,
// // outGoingCallData: callData,
// // ),
// // ),
// // );
// // isOnIncomingCallPage = true;
// // }
// }
void onCallDeclinedAsync(List<Object> params) {
print("================= On Declained ========================");
print(params);
// endCall().then((bool value) {
// if (value) {
// isCallEnded = true;
// notifyListeners();
// }
// });
// if (params != null) {
// endCall(isUserOnline: isUserOnline).then((bool value) {
// if (isCallConnected) {
// // Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
// isCallConnected = false;
// }
// isCallEnded = true;
// });
// }
}
//// Invoke Methods
Future<void> invoke({required String invokeMethod, required int currentUserID, required int targetUserID, var data, int userStatus = 1, var debugData}) async {
List<Object> args = [];
if (invokeMethod == "CallUserAsync") {
args = [currentUserID, targetUserID, isVideoCall];
} else if (invokeMethod == "answerCallAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "IceCandidateAsync") {
args = [targetUserID, data];
} else if (invokeMethod == "OfferAsync") {
args = [targetUserID, data];
} else if (invokeMethod == "AnswerOfferAsync") {
args = [targetUserID, data];
// json In Data
} else if (invokeMethod == "UpdateUserStatusAsync") {
args = [currentUserID, userStatus];
} else if (invokeMethod == "HangUpAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "InvokeMobile") {
args = [debugData];
}
try {
await chatHubConnection!.invoke("$invokeMethod", args: args);
} catch (e) {
print(e);
}
}
void stopListeners() async {
chatHubConnection!.off('OnCallDeclinedAsync');
chatHubConnection!.off('OnCallAcceptedAsync');
chatHubConnection!.off('OnIceCandidateAsync');
chatHubConnection!.off('OnAnswerOffer');
}
void playRingtone() async {
player.stop();
await player.setVolume(1.0);
String audioAsset = "";
if (Platform.isAndroid) {
audioAsset = "assets/audio/ring_60Sec.mp3";
} else {
audioAsset = "assets/audio/ring_30Sec.caf";
}
try {
await player.setAsset(audioAsset);
await player.load();
player.play();
} catch (e) {
print("Error: $e");
}
}
//////////////////// Web RTC Offers & Connections ////////////////////////
Future<RTCPeerConnection> creatOfferWithCon() async {
Map<String, dynamic> configuration = {
"sdpSemantics": "plan-b",
'iceServers': [
{
'urls': 'stun:15.185.116.59:3478',
},
{
'urls': 'turn:15.185.116.59:3479',
'username': 'admin',
'credential': 'admin',
},
]
};
Map<String, dynamic> offerSdpConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true,
},
'optional': []
};
RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
// await pc.addStream(_localStream!);
//Changed By Aamir
_localStream?.getTracks().forEach((track) {
pc.addTrack(track, _localStream!);
});
pc.onConnectionState = (RTCPeerConnectionState state) {};
pc.onAddStream = (MediaStream stream) {
remoteRenderer!.srcObject = stream;
notifyListeners();
};
pc.onIceCandidate = (RTCIceCandidate e) async {
if (isIncomingCall) {
if (e.candidate != null) {
var payload = {"target": incomingCallData!.targetUserId, "candidate": e.toMap()};
invoke(invokeMethod: "IceCandidateAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, data: jsonEncode(payload));
notifyListeners();
}
} else {
if (e.candidate != null) {
var payload = {"target": outGoingCallData!.callerId, "candidate": e.toMap()};
invoke(invokeMethod: "IceCandidateAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, data: jsonEncode(payload));
}
}
};
// pc!.onTrack = (RTCTrackEvent event) async {
//
// String streamId = const Uuid().toString();
// MediaStream remoteStream = await createLocalMediaStream(streamId);
// event.streams[0].getTracks().forEach((MediaStreamTrack element) {
// logger.i("Stream Track: " + element.id.toString());
// // remoteRenderer.srcObject = element;
// remoteStream.addTrack(element);
// });
// };
pc.onSignalingState = (RTCSignalingState state) {
print("signaling state: " + state.name);
// invoke(
// invokeMethod: "InvokeMobile",
// currentUserID: AppState().getchatUserDetails!.response!.id!,
// targetUserID: incomingCallData.targetUserId!,
// debugData: {"location": "Signaling", "parms": state.name});
};
pc.onIceGatheringState = (RTCIceGatheringState state) {
print("rtc ice gathering state: " + state.name);
};
pc.onIceConnectionState = (RTCIceConnectionState state) {
if (RTCIceConnectionState.RTCIceConnectionStateFailed == state ||
RTCIceConnectionState.RTCIceConnectionStateDisconnected == state ||
RTCIceConnectionState.RTCIceConnectionStateClosed == state) {
print("Ice Connection State:" + state.name);
// endCall().then((value) {
// notifyListeners();
// });
}
};
// pc!.onRenegotiationNeeded = _onRenegotiate;
return pc;
}
// void _onRenegotiate() async {
// try {
// print('onRenegotiationNeeded start');
// // makingOffer = true;
// await _pc.setLocalDescription(await _pc.createOffer(videoConstraints));
// print('onRenegotiationNeeded state after setLocalDescription: ' + _pc.signalingState.toString());
// // send offer via callManager
// var localDesc = await _pc.getLocalDescription();
// // callManager.sendCallMessage(MsgType.rtc_offer, RtcOfferAnswer(localDesc.sdp, localDesc.type));
// print('onRenegotiationNeeded; offer sent');
// } catch (e) {
// print("onRenegotiationNeeded error: " + e.toString());
// } finally {
// // makingOffer = false;
// print('onRenegotiationNeeded done');
// }
// }
Future<RTCSessionDescription> _createOffer() async {
RTCSessionDescription description = await _pc!.createOffer();
// _offer = true;
return description;
}
Future<RTCSessionDescription> _createAnswer() async {
RTCSessionDescription description = await _pc!.createAnswer();
// _offer = false;
return description;
}
//////////////////// Web RTC End Offers ////////////////////
//////////////////// CallPage Buttons //////////////////////
void micOff() {
isMicOff = !isMicOff;
_localStream!.getAudioTracks().forEach((track) {
track.enabled = !track.enabled;
});
notifyListeners();
}
void camOff() {
isCamOff = !isCamOff;
_localStream!.getVideoTracks().forEach((track) {
track.enabled = !track.enabled;
});
// if (isCamOff) {
// isVideoCall = false;
// } else {
// isVideoCall = true;
// }
notifyListeners();
}
void loudOn() {
isLoudSpeaker = !isLoudSpeaker;
remoteRenderer!.srcObject?.getAudioTracks().forEach((track) {
if (isLoudSpeaker) {
track.enableSpeakerphone(true);
} else {
track.enableSpeakerphone(false);
}
});
notifyListeners();
}
void switchCamera() {
isFrontCamera = !isFrontCamera;
Helper.switchCamera(_localStream!.getVideoTracks()[0]);
notifyListeners();
}
///////////////// Incoming Call ///////////////////////////////
Future<void> initStreams() async {
List<MediaDeviceInfo> devices = await navigator.mediaDevices.enumerateDevices();
remoteRenderer = RTCVideoRenderer();
localVideoRenderer ??= RTCVideoRenderer();
await localVideoRenderer!.initialize();
try {
_localStream = await navigator.mediaDevices.getUserMedia({
'audio': true,
'video':
//isVideoCall?
{
'mandatory': {
'minWidth': '640', // Provide your own width, height and frame rate here
'minHeight': '480',
'minFrameRate': '30',
},
'facingMode': 'user',
'optional': [],
"audio": true,
}
// : false
});
localVideoRenderer!.srcObject = _localStream;
localVideoRenderer!.value = (const RTCVideoValue(
width: 200,
height: 200,
renderVideo: true,
));
print("Working localStream");
} catch (e) {
print("Failed to get user media: $e");
}
// localVideoRenderer.srcObject = _localStream;
await remoteRenderer!.initialize();
notifyListeners();
}
Future<void> startIncomingCallViaKit({bool isVCall = true, var inCallData}) async {
//AppSharedPrefs().setStringFromPrefs("isIncomingCall", "false");
if (isVCall) {
isVideoCall = isVCall;
} else {
isAudioCall = true;
}
await initStreams();
isIncomingCall = true;
incomingCallData = SingleUserChatModel.fromJson(inCallData);
loudOn();
// notifyListeners();
}
void connectIncomingCall() {
invoke(invokeMethod: "answerCallAsync", currentUserID: AppState().getchatUserDetails.response!.id!, targetUserID: incomingCallData!.targetUserId!);
isIncomingCallLoader = false;
isIncomingCall = true;
// isVideoCall = true;
notifyListeners();
}
// void startRecording() async {
// print("=-=-=-=-=-=-= Call Recoding Started -=-=-=-=-=-=-=-=-==-=");
// if (_localStream == null) throw Exception('Stream is not initialized');
// if (Platform.isIOS) {
// print('Recording is not available on iOS');
// return;
// }
// Directory appDirectory = await getApplicationDocumentsDirectory();
// String dirPath = '${appDirectory.path}/webrtc_sample';
// if (!await Directory(dirPath).exists()) {
// await Directory(dirPath).create();
// await File('$dirPath/.nomedia').create();
// }
// if (appDirectory == null) throw Exception('Can\'t find storagePath');
// String filePath = dirPath + '/mobile.mp4';
// mobileRecoder = MediaRecorder();
// notifyListeners();
// MediaStreamTrack videoTrack = _localStream!.getVideoTracks().firstWhere((track) => track.kind == 'video');
// await mobileRecoder!.start(filePath, videoTrack: videoTrack);
//
// Future.delayed(Duration(minutes: 1), () {
// stopRecording();
// });
// }
//
// void stopRecording() async {
// print("=-=-=-=-=-=-= Call Recoding Stopped -=-=-=-=-=-=-=-=-==-=");
// await mobileRecoder!.stop();
// mobileRecoder = null;
// notifyListeners();
// }
}
class ChatService {
Future<UserAutoLoginModel> getUserCallToken({required String userid}) async {
UserAutoLoginModel userLoginResponse = UserAutoLoginModel();
var headers = {'Content-Type': 'application/json'};
var request = http.Request('POST', Uri.parse("${ApiConsts.chatLoginTokenUrl}externaluserlogin"));
request.body = json.encode({"employeeNumber": "341682", "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG"});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
userLoginResponse = userAutoLoginModelFromJson(await response.stream.bytesToString());
} else {
print(response.reasonPhrase);
}
return userLoginResponse;
}
}

File diff suppressed because it is too large Load Diff

@ -76,7 +76,7 @@ dependencies:
# Firebase
firebase_messaging: ^14.7.5
firebase_analytics : ^10.7.1
firebase_analytics: ^10.7.1
#GIF image
# flutter_gifimage: ^1.0.1
@ -131,6 +131,17 @@ dependencies:
flutter_math_fork: ^0.7.2
#Chat
signalr_netcore: ^1.3.6
logging: ^1.0.1
swipe_to: ^1.0.5
flutter_webrtc: ^0.9.48+hotfix.1
draggable_widget: ^2.0.0
flutter_callkit_incoming: ^2.0.0+1
camera: ^0.10.5+9
just_audio: ^0.9.36
dependency_overrides:
flutter_localizations:

Loading…
Cancel
Save