Chat Fix & Calling

merge-requests/188/head
Aamir Muhammad 3 years ago
parent 7191e25ea5
commit d1ccaf7f56

@ -10,6 +10,7 @@ import 'package:huawei_push/huawei_push.dart' as huawei_push;
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/classes/voip_chat_call.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
@ -116,10 +117,18 @@ class AppNotifications {
void _handleMessage(RemoteMessage message) {
Utils.saveStringFromPrefs("isAppOpendByChat", "false");
logger.d("Onlyyyyy Msg");
if (message.data.isNotEmpty && message.data["messageType"] == 'chat') {
Utils.saveStringFromPrefs("isAppOpendByChat", "true");
Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString());
} else if (message.data.isNotEmpty && message.data["messageType"] == 'call') {
ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message);
}
}
void _handleOpenApp(RemoteMessage message) {
if (message.data.isNotEmpty && message.data["type"] == 'chat') {
if (message.data.isNotEmpty && message.data["messageType"] == 'chat') {
Utils.saveStringFromPrefs("isAppOpendByChat", "true");
Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString());
}
@ -134,9 +143,10 @@ AndroidNotificationChannel channel = const AndroidNotificationChannel(
Future<dynamic> backgroundMessageHandler(RemoteMessage message) async {
await Firebase.initializeApp();
Utils.saveStringFromPrefs("isAppOpendByChat", "false");
Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString());
if (message.data.isNotEmpty && message.data["type"] == 'call') {
if (message.data.isNotEmpty && message.data["messageType"] == 'chat') {
Utils.saveStringFromPrefs("isAppOpendByChat", "false");
Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString());
} else if (message.data.isNotEmpty && message.data["messageType"] == 'call') {
ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message);
}
}

@ -6,9 +6,15 @@ import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as ALM;
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:provider/provider.dart';
class ChatVoipCall {
static final ChatVoipCall _instance = ChatVoipCall._internal();
@ -17,58 +23,110 @@ class ChatVoipCall {
factory ChatVoipCall() => _instance;
Future<void> showCallkitIncoming({required String uuid, required RemoteMessage data}) async {
late ChatProviderModel chatProvider;
late ChatCallProvider callProvider;
dynamic inCallData;
Future<void> showCallkitIncoming({required String uuid, RemoteMessage? data, bool isOnline = false, CallDataModel? incomingCallData}) async {
await ChatVoipCall().listenerEvent();
SingleUserChatModel callerData = SingleUserChatModel.fromJson(jsonDecode(data.data["user_chat_history_response"]));
ALM.Response autoLoginData = ALM.Response.fromJson(jsonDecode(data.data["user_token_response"]));
var values = {
"loginDetails": autoLoginData.toJson(),
"callerDetails": callerData.toJson(),
};
CallKitParams params = CallKitParams(
id: uuid,
nameCaller: callerData.targetUserName,
appName: 'Mohemm',
handle: '',
type: 0,
duration: 25000,
textAccept: 'Accept',
textDecline: 'Decline',
textMissedCall: 'Missed call',
textCallback: 'Call back',
extra: values,
android: const AndroidParams(
isCustomNotification: true,
isShowLogo: true,
isShowCallback: false,
isShowMissedCallNotification: true,
ringtonePath: 'system_ringtone_default',
backgroundColor: '#0955fa',
backgroundUrl: 'assets/test.png',
actionColor: '#4CAF50',
),
ios: IOSParams(
iconName: 'Mohemm',
handleType: '',
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
audioSessionMode: 'default',
audioSessionActive: true,
audioSessionPreferredSampleRate: 38000.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
ringtonePath: 'system_ringtone_default',
),
);
if (callerData.chatEventId == 3) {
await Utils.saveStringFromPrefs("isIncomingCall", "true");
await Utils.saveStringFromPrefs("inComingCallData",jsonEncode(values));
await FlutterCallkitIncoming.showCallkitIncoming(params);
}
if (isOnline) {
// if (incomingCallData.chatEventId == 3) {
// await Utils.saveStringFromPrefs("isIncomingCall", "true");
// await Utils.saveStringFromPrefs(
// "inComingCallData",
// jsonEncode([
// {
// "loginDetails": autoLoginData.toJson(),
// "callerDetails": callerData.toJson(),
// }
// ]));
// await FlutterCallkitIncoming.showCallkitIncoming(params);
// }
} else {
await initProviders();
SingleUserChatModel callerData = SingleUserChatModel.fromJson(jsonDecode(data!.data["user_chat_history_response"]));
ALM.Response autoLoginData = ALM.Response.fromJson(jsonDecode(data.data["user_token_response"]));
CallKitParams params = CallKitParams(
id: uuid,
nameCaller: callerData.targetUserName,
appName: 'Mohemm',
handle: '',
type: 0,
duration: 25000,
textAccept: 'Accept',
textDecline: 'Decline',
textMissedCall: 'Missed call',
textCallback: 'Call back',
extra: {
"loginDetails": autoLoginData.toJson(),
"callerDetails": callerData.toJson(),
},
android: const AndroidParams(
isCustomNotification: true,
isShowLogo: false,
isShowCallback: false,
isShowMissedCallNotification: true,
ringtonePath: 'system_ringtone_default',
backgroundColor: '#0955fa',
backgroundUrl: 'assets/test.png',
actionColor: '#4CAF50',
),
ios: IOSParams(
iconName: 'Mohemm',
handleType: '',
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
audioSessionMode: 'default',
audioSessionActive: true,
audioSessionPreferredSampleRate: 38000.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
ringtonePath: 'system_ringtone_default',
),
);
if (callerData.chatEventId == 3) {
await Utils.saveStringFromPrefs("isIncomingCall", "true");
// await Utils.saveStringFromPrefs(
// "inComingCallData",
// jsonEncode([
// {
// "loginDetails": autoLoginData.toJson(),
// "callerDetails": callerData.toJson(),
// }
// ]));
connection(
data: jsonEncode([
{"loginDetails": autoLoginData.toJson(), "callerDetails": callerData.toJson()}
]));
await FlutterCallkitIncoming.showCallkitIncoming(params);
}
}
}
Future<void> initProviders() async {
callProvider = Provider.of<ChatCallProvider>(AppRoutes.navigatorKey.currentContext!, listen: false);
chatProvider = Provider.of<ChatProviderModel>(AppRoutes.navigatorKey.currentContext!, listen: false);
}
void connection({required data}) async {
// inCallData = await Utils.getStringFromPrefs("inComingCallData");
dynamic callData = await jsonDecode(data);
AppState().setchatUserDetails = UserAutoLoginModel(
response: Response.fromJson(callData[0]["loginDetails"]),
errorResponses: null,
);
callProvider.startIncomingCallViaKit(inCallData: inCallData);
try {
await chatProvider.buildHubConnection(context: AppRoutes.navigatorKey.currentContext!, ccProvider: callProvider).whenComplete(() {
callProvider.init();
});
} catch (e) {
logger.w(e);
}
}
//Function(CallEvent) callback
@ -84,17 +142,18 @@ class ChatVoipCall {
// TODO: show screen calling in Flutter
break;
case Event.ACTION_CALL_ACCEPT:
Navigator.pushNamedAndRemoveUntil(AppRoutes.navigatorKey.currentContext!, AppRoutes.chatStartCall, (_) => false);
// Navigator.pushNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.chatStartCall);
break;
case Event.ACTION_CALL_DECLINE:
callProvider.isIncomingCall = true;
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
callProvider.endCall();
break;
case Event.ACTION_CALL_ENDED:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
// TODO: ended an incoming/outgoing call
break;
case Event.ACTION_CALL_TIMEOUT:
Utils.saveStringFromPrefs("isIncomingCall", "false");

@ -7,12 +7,12 @@ import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:just_audio/just_audio.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/classes/voip_chat_call.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/incomingCall.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/webrtc_payloads.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/ui/chat/call/start_call_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:uuid/uuid.dart';
@ -27,7 +27,6 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
final AudioPlayer player = AudioPlayer();
late MediaStream localStream;
late CallDataModel outGoingCallData;
late IncomingCallDataPayload inComingCallData;
bool isMicOff = false;
bool isLoudSpeaker = false;
bool isCamOff = false;
@ -36,10 +35,12 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
bool isCallStarted = false;
bool isFrontCamera = true;
bool isOnIncomingCallPage = false;
late SingleUserChatModel incomingCallData;
/// WebRTC Connection Variables
bool _offer = false;
//bool _offer = false;
bool isIncomingCallLoader = true;
bool isIncomingCall = false;
late BuildContext providerContext;
/// Temp Variable Remove After Development
@ -90,7 +91,10 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
};
Future<void> init() async {
creatOfferWithCon();
_pc = await creatOfferWithCon();
Future.delayed(const Duration(seconds: 2), () {
connectIncomingCall();
});
}
Future<void> initLocalCamera({required ChatProviderModel chatProvmodel, required callData, required BuildContext context, bool isIncomingCall = false}) async {
@ -131,19 +135,34 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
}
Future<bool> endCall() async {
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 1);
await invoke(invokeMethod: "HangUpAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 1);
_pc.dispose();
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
localVideoRenderer.srcObject = null;
remoteRenderer.srcObject = null;
//player.stop();
_offer = false;
return true;
if (isIncomingCall) {
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 1);
await invoke(invokeMethod: "HangUpAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 1);
_pc.dispose();
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
localVideoRenderer.srcObject = null;
remoteRenderer.srcObject = null;
isIncomingCall = false;
return true;
} else {
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 1);
await invoke(invokeMethod: "HangUpAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 1);
_pc.dispose();
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
localVideoRenderer.srcObject = null;
remoteRenderer.srcObject = null;
//player.stop();
// _offer = false;
return true;
}
}
// OutGoing Listeners
@ -157,52 +176,71 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
}
Future<void> onIceCandidateAsync(List<Object?>? params) async {
print("--------------------- onIceCandidateAsync ---------------------------------------");
var items = params!.toList();
if (kDebugMode) {
logger.i("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;
if (isCallStarted) {
Navigator.push(
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(localRenderer: localVideoRenderer, remoteRenderer: remoteRenderer),
allowSnapshotting: false,
)).then((value) {
Navigator.of(providerContext).pop();
});
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) {
logger.i("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;
if (isCallStarted) {
Navigator.push(
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
allowSnapshotting: false,
)).then((value) {
Navigator.of(providerContext).pop();
});
}
}
}
notifyListeners();
}
notifyListeners();
}
Future<void> onOfferAsync(List<Object?>? params) async {
// tempPayLoad = {"values": params!.toList()};
dynamic items = params!.toList();
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));
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);
var 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();
}
// Incoming Listeners
void onAnswerOffer(List<Object?>? payload) async {
print("--------------------- On Answer Offer Async ---------------------------------------");
var items = payload!.toList();
if (kDebugMode) {
logger.i("res: " + items.toString());
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) {
logger.i("res: " + items.toString());
}
CallSessionPayLoad data = CallSessionPayLoad.fromJson(jsonDecode(items.first.toString()));
RTCSessionDescription description = RTCSessionDescription(data.sdp!.sdp, 'answer');
_pc.setRemoteDescription(description);
}
CallSessionPayLoad data = CallSessionPayLoad.fromJson(jsonDecode(items.first.toString()));
RTCSessionDescription description = RTCSessionDescription(data.sdp!.sdp, 'answer');
_pc.setRemoteDescription(description);
}
void onHangUpAsync(List<Object?>? params) {
@ -217,37 +255,53 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
print("--------------------- On Incoming Call ---------------------------------------");
dynamic items = params!.toList();
logger.d(items);
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;
}
// 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 Call Declined ---------------------------------------");
endCall().then((bool value) {
if (value) {
isCallEnded = true;
@ -258,7 +312,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
//// Invoke Methods
Future<void> invoke({required String invokeMethod, required int currentUserID, required int targetUserID, var data, int userStatus = 1}) async {
Future<void> invoke({required String invokeMethod, required int currentUserID, required int targetUserID, var data, int userStatus = 1, var debugData}) async {
List<Object> args = [];
// Utils.showToast(currentUserID.toString() + " -- " + targetUserID.toString() + " -- " + isVideoCall.toString());
if (invokeMethod == "CallUserAsync") {
@ -276,8 +330,9 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
args = [currentUserID, userStatus];
} else if (invokeMethod == "HangUpAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "InvokeMobile") {
args = [debugData];
}
logger.d(args);
try {
await chatHubConnection.invoke("$invokeMethod", args: args);
} catch (e) {
@ -319,7 +374,9 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
},
'optional': []
};
RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
logger.w(pc.connectionState);
await pc!.addStream(localStream!);
pc?.onConnectionState = (RTCPeerConnectionState state) {};
pc?.onAddStream = (MediaStream stream) {
@ -327,10 +384,19 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners();
};
pc!.onIceCandidate = (RTCIceCandidate e) async {
if (e.candidate != null) {
var payload = {"target": outGoingCallData.callerId, "candidate": e.toMap()};
logger.i("Candidate:" + e.toMap().toString());
await invoke(invokeMethod: "IceCandidateAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, data: jsonEncode(payload));
if (isIncomingCall) {
if (e.candidate != null) {
var payload = {"target": incomingCallData.targetUserId, "candidate": e.toMap()};
logger.i("Candidate:" + e.toMap().toString());
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()};
logger.i("Candidate:" + e.toMap().toString());
invoke(invokeMethod: "IceCandidateAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, data: jsonEncode(payload));
}
}
};
// pc!.onTrack = (RTCTrackEvent event) async {
@ -345,12 +411,21 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
// };
pc!.onSignalingState = (RTCSignalingState state) {
logger.i("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) {
logger.i("rtc ice gathering state: " + state.name);
};
pc!.onIceConnectionState = (RTCIceConnectionState state) {
logger.i("rtc ice connection state: " + state.name);
// invoke(
// invokeMethod: "InvokeMobile",
// currentUserID: AppState().getchatUserDetails!.response!.id!,
// targetUserID: incomingCallData.targetUserId!,
// debugData: {"location": "onIceConnection", "parms": state.name});
};
pc!.onRenegotiationNeeded = () {};
return pc;
@ -376,13 +451,13 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
Future<RTCSessionDescription> _createOffer() async {
RTCSessionDescription description = await _pc!.createOffer();
_offer = true;
// _offer = true;
return description;
}
Future<RTCSessionDescription> _createAnswer() async {
RTCSessionDescription description = await _pc!.createAnswer();
_offer = false;
// _offer = false;
return description;
}
@ -421,7 +496,6 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
void switchCamera() {
isFrontCamera = !isFrontCamera;
print("================= Camera Switch Triggered ===================");
Helper.switchCamera(localStream.getVideoTracks()[0]);
notifyListeners();
}
@ -431,11 +505,22 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
localStream = await navigator.mediaDevices.getUserMedia(isVideoCall ? videoConstraints : audioConstraints);
localVideoRenderer.srcObject = localStream;
await remoteRenderer.initialize();
_pc = await creatOfferWithCon();
}
Future<void> startIncomingCallViaKit() async {
Future<void> startIncomingCallViaKit({bool isVCall = true, required var inCallData}) async {
Utils.saveStringFromPrefs("isIncomingCall", "false");
isVideoCall = isVCall;
await startIncomingCall();
await invoke(invokeMethod: "answerCallAsync", currentUserID: inComingCallData.extra!.loginDetails!.id!, targetUserID: inComingCallData.extra!.callerDetails!.targetUserId!);
isIncomingCall = true;
dynamic callData = await jsonDecode(inCallData);
incomingCallData = SingleUserChatModel.fromJson(callData[0]["callerDetails"]);
notifyListeners();
}
void connectIncomingCall() {
invoke(invokeMethod: "answerCallAsync", currentUserID: AppState().getchatUserDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!);
isIncomingCallLoader = false;
isVideoCall = true;
notifyListeners();
}
}

@ -139,15 +139,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
// Calling
// chatHubConnection.on("OnCallAcceptedAsync", callP.onCallAcceptedAsync);
// chatHubConnection.on("OnIceCandidateAsync", callP.onIceCandidateAsync);
// chatHubConnection.on("OnOfferAsync", callP.onOfferAsync);
// chatHubConnection.on("OnAnswerOffer", callP.onAnswerOffer);
// chatHubConnection.on("OnHangUpAsync", callP.onHangUpAsync);
// chatHubConnection.on("OnCallDeclinedAsync", callP.onCallDeclinedAsync);
if (kDebugMode) {
logger.i("All listeners registered");
}
@ -1478,21 +1469,4 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
return Material.TextDirection.ltr;
}
void openChatByNoti(BuildContext context) async {
SingleUserChatModel nUser = SingleUserChatModel();
Utils.saveStringFromPrefs("isAppOpendByChat", "false");
if (await Utils.getStringFromPrefs("notificationData") != "null") {
nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData")));
Utils.saveStringFromPrefs("notificationData", "null");
Future.delayed(const Duration(seconds: 2));
for (ChatUser user in searchedChats!) {
if (user.id == nUser.targetUserId) {
Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false));
return;
}
}
}
Utils.saveStringFromPrefs("notificationData", "null");
}
}

@ -9,6 +9,8 @@ import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/models/chat/incomingCall.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
@ -17,27 +19,22 @@ import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:provider/provider.dart';
class StartCallPage extends StatefulWidget {
RTCVideoRenderer? localRenderer;
RTCVideoRenderer? remoteRenderer;
StartCallPage({this.localRenderer, this.remoteRenderer});
@override
_StartCallPageState createState() => _StartCallPageState();
}
class _StartCallPageState extends State<StartCallPage> {
final dragController = DragController();
late ChatProviderModel cPro;
late ChatCallProvider callPro;
late ChatProviderModel chatProvider;
late ChatCallProvider callProvider;
var inCallData;
bool isIncomingCall = false;
//userChatDetails
@override
void initState() {
callPro = Provider.of<ChatCallProvider>(context, listen: false);
cPro = Provider.of<ChatProviderModel>(context, listen: false);
// callProvider = Provider.of<ChatCallProvider>(context, listen: false);
// chatProvider = Provider.of<ChatProviderModel>(context, listen: false);
// connection();
super.initState();
}
@ -49,278 +46,260 @@ class _StartCallPageState extends State<StartCallPage> {
super.dispose();
}
void connection() async {
isIncomingCall = (Utils.getStringFromPrefs("isIncomingCall") == "true" ? true : false);
Utils.saveStringFromPrefs("isIncomingCall", "false");
callPro.tempPayLoad = inCallData;
// callPro.isIncomingCallLoader = false;
// callPro.notifyListeners();
cPro.userLoginData = UserAutoLoginModel(
response: Response.fromJson(jsonDecode(inCallData["loginDetails"])),
errorResponses: null,
);
AppState().setchatUserDetails = cPro.userLoginData;
await cPro.buildHubConnection(context: context, ccProvider: callPro);
//callPro.inComingCallData = inCallData;
callPro.isIncomingCallLoader = false;
Future.delayed(const Duration(seconds: 2)).then((value) {
callPro.startIncomingCallViaKit();
//Utils.showToast(inCallData.extra!.loginDetails!.toRawJson(), longDuration: false);
callPro.notifyListeners();
});
}
// void connection() async {
// inCallData = await Utils.getStringFromPrefs("inComingCallData");
// dynamic callData = await jsonDecode(inCallData);
// AppState().setchatUserDetails = UserAutoLoginModel(
// response: Response.fromJson(callData[0]["loginDetails"]),
// errorResponses: null,
// );
// callProvider.startIncomingCallViaKit(inCallData: inCallData);
// try {
// await chatProvider.buildHubConnection(context: context, ccProvider: callProvider).whenComplete(() {
// callProvider.init();
// });
// } catch (e) {
// logger.w(e);
// }
//
// // callProvider.afterHub();
// }
@override
Widget build(BuildContext context) {
inCallData = ModalRoute.of(context)!.settings.arguments;
if (inCallData != null) {
connection();
}
return Consumer2<ChatCallProvider, ChatProviderModel>(builder: (BuildContext context, ChatCallProvider provider, ChatProviderModel cpm, Widget? child) {
return SizedBox(
width: double.infinity,
height: double.infinity,
child: provider.isVideoCall
? Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (provider.isVideoCall)
Positioned.fill(
child: RTCVideoView(
widget.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
key: const Key('remote'),
),
),
if (provider.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
intialVisibility: true,
horizontalSpace: 20,
shadowBorderRadius: 50,
initialPosition: AnchoringPosition.topLeft,
dragController: dragController,
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
child: SizedBox(
height: 200,
width: 140,
child: RTCVideoView(
widget.localRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
return Scaffold(
extendBody: true,
body: Consumer2<ChatCallProvider, ChatProviderModel>(builder: (BuildContext context, ChatCallProvider provider, ChatProviderModel cpm, Widget? child) {
return SizedBox(
width: double.infinity,
height: double.infinity,
child: provider.isVideoCall
? Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (provider.isVideoCall)
Positioned.fill(
child: RTCVideoView(
provider.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
key: const Key('remote'),
),
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
if (provider.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
intialVisibility: true,
horizontalSpace: 20,
shadowBorderRadius: 50,
initialPosition: AnchoringPosition.topLeft,
dragController: dragController,
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
child: SizedBox(
height: 200,
width: 140,
child: RTCVideoView(
provider.localVideoRenderer,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
40.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
SvgPicture.asset(
"assets/images/user.svg",
height: 70,
width: 70,
fit: BoxFit.cover,
),
10.height,
Text(
callPro.outGoingCallData.receiverName!,
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
40.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
),
const Text(
"On Call",
style: TextStyle(
fontSize: 16,
decoration: TextDecoration.none,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
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,
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
const SizedBox(
height: 2,
10.height,
Text(
provider.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: () {
callPro.loudOn();
},
elevation: 2.0,
fillColor: callPro.isLoudSpeaker ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.only(
bottom: 20,
left: 40,
right: 40,
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.switchCamera();
},
elevation: 2.0,
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.green2DColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.micOff();
},
elevation: 2.0,
fillColor: provider.isMicOff ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.endCall().then((value) {
if (value) {
Navigator.of(context).pop();
}
});
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call_end,
color: MyColors.white,
size: 30.0,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// if (provider.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.isLoudSpeaker ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.switchCamera();
},
elevation: 2.0,
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.green2DColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.micOff();
},
elevation: 2.0,
fillColor: provider.isMicOff ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.endCall().then((value) {
if (value) {
Navigator.of(context).pop();
}
});
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call_end,
color: MyColors.white,
size: 30.0,
),
),
],
),
],
),
),
),
),
],
)
: provider.isIncomingCallLoader
? SizedBox(
],
)
: const SizedBox(
width: double.infinity,
height: 500,
child: Center(
child: CircularProgressIndicator(),
),
)
: ListView(
padding: EdgeInsets.fromLTRB(20,40,20,20),
children: [
Consumer<ChatCallProvider>(
builder: (BuildContext cxt, ChatCallProvider data, Widget? child) {
return Text(
data.tempPayLoad.toString(),style: TextStyle(fontSize: 12, color: Colors.white, decoration: TextDecoration.none,),
);
},
),
],
),
);
});
));
}),
);
}
}

@ -101,7 +101,7 @@ class _LoginScreenState extends State<LoginScreen> {
Future<void> checkFirebaseToken() async {
if (await Utils.getStringFromPrefs("isIncomingCall") == "true") {
Utils.hideLoading(context);
Navigator.pushNamed(context, AppRoutes.chatStartCall, arguments: await Utils.getStringFromPrefs("inComingCallData"));
Navigator.pushNamed(context, AppRoutes.chatStartCall);
} else {
try {
Utils.showLoading(context);

Loading…
Cancel
Save