diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 42fc0237..06893b6d 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -92,12 +92,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart
index 0fd54e74..6a2626be 100644
--- a/lib/app_state/app_state.dart
+++ b/lib/app_state/app_state.dart
@@ -1,3 +1,5 @@
+import 'package:diplomaticquarterapp/voipcall/model/get_user_login_token.dart';
+
class AppState {
static final AppState _instance = AppState._internal();
@@ -10,4 +12,35 @@ class AppState {
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;
+ }
}
diff --git a/lib/main.dart b/lib/main.dart
index 4be8957b..da7c7097 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -13,6 +13,7 @@ import 'package:diplomaticquarterapp/uitl/LocalNotification.dart';
import 'package:diplomaticquarterapp/uitl/PlatformBridge.dart';
import 'package:diplomaticquarterapp/uitl/navigation_service.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
+import 'package:diplomaticquarterapp/voipcall/provider/chat_call_provider.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
@@ -120,6 +121,9 @@ class _MyApp extends State {
ChangeNotifierProvider(create: (context) => CompareList()),
ChangeNotifierProvider(create: (context) => OrderPreviewViewModel()),
ChangeNotifierProvider(create: (context) => PayfortViewModel()),
+ ChangeNotifierProvider(
+ create: (context) => ChatCallProvider(),
+ ),
],
child: Consumer(
builder: (context, projectProvider, child) => MaterialApp(
diff --git a/lib/models/chat/call.dart b/lib/models/chat/call.dart
new file mode 100644
index 00000000..1efaebb3
--- /dev/null
+++ b/lib/models/chat/call.dart
@@ -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 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 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 json) => CallSessionPayLoad(
+ target: json["target"],
+ caller: json["caller"],
+ sdp: json["sdp"] == null ? null : Sdp.fromJson(json["sdp"]),
+ );
+
+ Map 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 json) => Sdp(
+ type: json["type"],
+ sdp: json["sdp"],
+ );
+
+ Map 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 json) => IosCallPayload(
+ incomingCallType: json["incoming_call_type"],
+ incomingCallerId: json["incoming_caller_id"],
+ incomingCallerName: json["incoming_caller_name"],
+ incomingCallReciverId: null,
+ uuid: json["uuid"],
+ );
+
+ Map toJson() => {
+ "incoming_call_type": incomingCallType,
+ "incoming_caller_id": incomingCallerId,
+ "incoming_caller_name": incomingCallerName,
+ "uuid": uuid,
+ };
+}
diff --git a/lib/models/chat/incoming_call_model.dart b/lib/models/chat/incoming_call_model.dart
new file mode 100644
index 00000000..a36c11b3
--- /dev/null
+++ b/lib/models/chat/incoming_call_model.dart
@@ -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 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 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 json) => Args();
+
+ Map 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 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 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 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 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 json) => FileTypeResponse(
+ fileTypeId: json["fileTypeId"].toInt(),
+ );
+
+ Map 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 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 toJson() => {
+ "isActiveCode": isActiveCode,
+ "id": id,
+ "encryptedUserName": encryptedUserName,
+ "userName": userName,
+ "title": title,
+ "encryptedUserId": encryptedUserId,
+ "email": email,
+ "isDomainUser": isDomainUser,
+ "token": token,
+ };
+}
diff --git a/lib/models/chat/webrtc_payloads.dart b/lib/models/chat/webrtc_payloads.dart
new file mode 100644
index 00000000..768155d2
--- /dev/null
+++ b/lib/models/chat/webrtc_payloads.dart
@@ -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 json) => RemoteIceCandidatePayLoad(
+ target: json["target"],
+ candidate: json["candidate"] == null ? null : Candidate.fromJson(json["candidate"]),
+ );
+
+ Map 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 json) => Candidate(
+ candidate: json["candidate"],
+ sdpMid: json["sdpMid"],
+ sdpMLineIndex: json["sdpMLineIndex"],
+ usernameFragment: json["usernameFragment"],
+ );
+
+ Map toJson() => {
+ "candidate": candidate,
+ "sdpMid": sdpMid,
+ "sdpMLineIndex": sdpMLineIndex,
+ "usernameFragment": usernameFragment,
+ };
+}
diff --git a/lib/voipcall/call/chat_incoming_call_screen.dart b/lib/voipcall/call/chat_incoming_call_screen.dart
new file mode 100644
index 00000000..cec8a2ee
--- /dev/null
+++ b/lib/voipcall/call/chat_incoming_call_screen.dart
@@ -0,0 +1,613 @@
+import 'dart:convert';
+import 'dart:core';
+import 'dart:io';
+import 'dart:ui';
+
+import 'package:diplomaticquarterapp/app_state/app_state.dart';
+import 'package:diplomaticquarterapp/models/chat/call.dart';
+import 'package:diplomaticquarterapp/models/chat/incoming_call_model.dart';
+import 'package:diplomaticquarterapp/voipcall/consts.dart';
+import 'package:diplomaticquarterapp/voipcall/model/get_single_user_chat_call.dart';
+import 'package:diplomaticquarterapp/voipcall/model/get_user_login_token.dart';
+import 'package:diplomaticquarterapp/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 {
+ 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 (cProv.isUserOnline) {
+ AppState().isBackgroundCall = true;
+ if (kDebugMode) {
+ print("====== Processing Incoming Call in Online State =========");
+ }
+ await cProv.startIncomingCallViaKit(inCallData: inCallData.toJson(), isVCall: callType == "video" ? true : false);
+ cProv.init();
+ isCallConnected = true;
+ } else {
+ if (kDebugMode) {
+ print("====== Processing Incoming Call =========");
+ }
+ AppState().isBackgroundCall = true;
+ UserAutoLoginModel userLoginResponse = await ChatService().getUserCallToken(userid: userID.toString());
+ if (userLoginResponse.response != null) {
+ AppState().setchatUserDetails = userLoginResponse;
+ AppSharedPrefs().setStringFromPrefs("userLoginChatDetails", jsonEncode(userLoginResponse.response));
+
+ await cProv.startIncomingCallViaKit(inCallData: inCallData.toJson(), isVCall: callType == "video" ? true : false);
+ try {
+ AppState().setchatUserDetails = UserAutoLoginModel(response: userLoginResponse.response, errorResponses: null);
+ await cProv.buildHubConnection().whenComplete(() {
+ cProv.init();
+ isCallConnected = true;
+ });
+ } catch (e) {
+ print(e);
+ }
+ }
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ cProv = context.read();
+ if (!cProv.isOutGoingCall) {
+ if (Platform.isAndroid) {
+ startCall();
+ } else if (Platform.isIOS) {
+ cProv.buildHubConnection();
+ startIosCall();
+ }
+ }
+
+ return Scaffold(
+ extendBody: true,
+ body: Consumer(
+ 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: [
+ 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: [
+ SizedBox(
+ height: 40,
+ ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ 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: [
+ 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: [
+ // 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: [
+ 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: [
+ SizedBox(
+ height: 40,
+ ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ 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: [
+ 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: [
+ // 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();
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/voipcall/call/chat_outgoing_call_screen.dart b/lib/voipcall/call/chat_outgoing_call_screen.dart
new file mode 100644
index 00000000..f3d6b950
--- /dev/null
+++ b/lib/voipcall/call/chat_outgoing_call_screen.dart
@@ -0,0 +1,198 @@
+import 'dart:ui';
+
+import 'package:diplomaticquarterapp/models/chat/call.dart';
+import 'package:diplomaticquarterapp/voipcall/consts.dart';
+import 'package:diplomaticquarterapp/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}) : super(key: key);
+
+ @override
+ _OutGoingCallState createState() => _OutGoingCallState();
+}
+
+class _OutGoingCallState extends State {
+ ChatCallProvider callProvider;
+ //late ChatProviderModel chatProvider;
+ bool loader = true;
+
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ Future init() async {
+ widget.isVideoCall ? callProvider.isVideoCall = true : callProvider.isVideoCall = false;
+ 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, context: context);
+ loader = false;
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ callProvider = Provider.of(context, listen: false);
+ init();
+ return Scaffold(
+ body: Consumer(builder: (BuildContext context, ChatCallProvider chatcp, Widget child) {
+ return loader
+ ? const Center(
+ child: CircularProgressIndicator(),
+ )
+ : Stack(
+ alignment: FractionalOffset.center,
+ children: [
+ 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: [
+ SizedBox(
+ height: 40,
+ ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ 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: [
+ 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: [
+ 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(color: const Color(0xff000000).withOpacity(.05), blurRadius: elevation ?? 27, offset: const Offset(-2, 3))],
+ );
+ }
+}
diff --git a/lib/voipcall/call/draggable_cam_screen.dart b/lib/voipcall/call/draggable_cam_screen.dart
new file mode 100644
index 00000000..14f0fc8a
--- /dev/null
+++ b/lib/voipcall/call/draggable_cam_screen.dart
@@ -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 onButtonBarVisible;
+// // final Stream 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 {
+// 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;
+// }
+// });
+// }
+// }
diff --git a/lib/voipcall/consts.dart b/lib/voipcall/consts.dart
new file mode 100644
index 00000000..659787d9
--- /dev/null
+++ b/lib/voipcall/consts.dart
@@ -0,0 +1,33 @@
+import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
+import 'package:flutter/material.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 {
+ AppSharedPreferences sharedPref = AppSharedPreferences();
+
+ Future setStringFromPrefs(String key, String value) {
+ sharedPref.setString(key, value);
+ }
+
+ Future 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);
+}
diff --git a/lib/voipcall/model/get_single_user_chat_call.dart b/lib/voipcall/model/get_single_user_chat_call.dart
new file mode 100644
index 00000000..f150a27b
--- /dev/null
+++ b/lib/voipcall/model/get_single_user_chat_call.dart
@@ -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 singleUserChatModelFromJson(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x)));
+
+String singleUserChatModelToJson(List data) => json.encode(List.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 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 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 json) => FileTypeResponse(
+ fileTypeId: json["fileTypeId"] == null ? null : json["fileTypeId"],
+ fileTypeName: json["fileTypeName"],
+ fileTypeDescription: json["fileTypeDescription"],
+ fileKind: json["fileKind"],
+ fileName: json["fileName"],
+ );
+
+ Map 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 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 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(),
+ };
+}
diff --git a/lib/voipcall/model/get_user_login_token.dart b/lib/voipcall/model/get_user_login_token.dart
new file mode 100644
index 00000000..10853e8b
--- /dev/null
+++ b/lib/voipcall/model/get_user_login_token.dart
@@ -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 errorResponses;
+
+ factory UserAutoLoginModel.fromJson(Map json) => UserAutoLoginModel(
+ response: json["response"] == null ? null : Response.fromJson(json["response"]),
+ errorResponses: json["errorResponses"] == null ? null : List.from(json["errorResponses"].map((x) => ErrorResponse.fromJson(x))),
+ );
+
+ Map toJson() => {
+ "response": response == null ? null : response.toJson(),
+ "errorResponses": errorResponses == null ? null : List.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 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 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 json) => ErrorResponse(
+ fieldName: json["fieldName"] == null ? null : json["fieldName"],
+ message: json["message"] == null ? null : json["message"],
+ );
+
+ Map toJson() => {
+ "fieldName": fieldName == null ? null : fieldName,
+ "message": message == null ? null : message,
+ };
+}
diff --git a/lib/voipcall/provider/chat_call_provider.dart b/lib/voipcall/provider/chat_call_provider.dart
new file mode 100644
index 00000000..902b916f
--- /dev/null
+++ b/lib/voipcall/provider/chat_call_provider.dart
@@ -0,0 +1,867 @@
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:diplomaticquarterapp/app_state/app_state.dart';
+import 'package:diplomaticquarterapp/core/service/base_service.dart';
+import 'package:diplomaticquarterapp/locator.dart';
+import 'package:diplomaticquarterapp/models/chat/call.dart';
+import 'package:diplomaticquarterapp/models/chat/webrtc_payloads.dart';
+import 'package:diplomaticquarterapp/routes.dart';
+import 'package:diplomaticquarterapp/uitl/navigation_service.dart';
+import 'package:diplomaticquarterapp/uitl/utils.dart';
+import 'package:diplomaticquarterapp/voipcall/call/chat_incoming_call_screen.dart';
+import 'package:diplomaticquarterapp/voipcall/consts.dart';
+import 'package:diplomaticquarterapp/voipcall/model/get_single_user_chat_call.dart';
+import 'package:diplomaticquarterapp/voipcall/model/get_user_login_token.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:just_audio/just_audio.dart';
+import 'package:signalr_netcore/http_connection_options.dart';
+import 'package:signalr_netcore/hub_connection.dart';
+import 'package:signalr_netcore/hub_connection_builder.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;
+ bool isVideoCall = false;
+ 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;
+
+ BuildContext providerContext;
+
+ List devices = [];
+
+ Future buildHubConnection() async {
+ try {
+ chatHubConnection = await getHubConnection();
+ } catch (e) {
+ Utils.showErrorToast(e.toString());
+ }
+ await chatHubConnection.start();
+ if (kDebugMode) {
+ print("Hub Conn: Startedddddddd");
+ }
+ // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
+ // chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion);
+ // chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived);
+ 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 getHubConnection() async {
+ AppState().chatDetails.response = Response.fromJson(
+ {
+ "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=="
+ },
+ );
+
+ 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: [2000, 5000, 10000, 20000]).build();
+ return hub;
+ }
+
+ 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 audioConstraints = {
+ "sampleRate": 8000,
+ "sampleSize": 16,
+ "channelCount": 2,
+ "echoCancellation": true,
+ "audio": true,
+ };
+
+ Future init() async {
+ _pc = await creatOfferWithCon();
+ Future.delayed(const Duration(seconds: 2), () {
+ connectIncomingCall();
+ });
+ }
+
+ ///////////////////////////////////////////////OutGoing Call////////////////////////////////////////////////////
+
+ Future initLocalCamera({callData, BuildContext context, bool isIncomingCall = false}) async {
+ isCallEnded = false;
+ outGoingCallData = callData;
+ await initStreams();
+
+ await startCall(callType: isVideoCall ? "Video" : "Audio", context: context);
+ _pc = await creatOfferWithCon();
+ connectOutgoing();
+ notifyListeners();
+ }
+
+ void connectOutgoing() {
+ isOutGoingCall = true;
+ // notifyListeners();
+ }
+
+ Future startCall({String callType, BuildContext context}) 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