Ios Voip Kit

development_aamir
Aamir Muhammad 2 years ago
parent 364d1292a0
commit 23820e7e5e

@ -33,8 +33,8 @@ class ChatApiClient {
"isMobile": true, "isMobile": true,
"deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei, "isHuaweiDevice": AppState().getIsHuawei,
//"platform" : "", // ios, android "platform": Platform.isIOS ? "ios" : "android", // ios, android
//"voipToken": "" "voipToken": Platform.isIOS ? AppState().iosVoipPlayerID : ""
}, },
); );
@ -188,6 +188,7 @@ class ChatApiClient {
} }
return imagesData; return imagesData;
} }
// CallUser Login Token // CallUser Login Token
Future<user.UserAutoLoginModel> getUserCallToken({required String userid}) async { Future<user.UserAutoLoginModel> getUserCallToken({required String userid}) async {
@ -216,9 +217,6 @@ class ChatApiClient {
// Call Decline On App Terminated State // Call Decline On App Terminated State
Future<Response> callDecline({required int cUserID, required int tUserID, required String targetUsertoken}) async { Future<Response> callDecline({required int cUserID, required int tUserID, required String targetUsertoken}) async {
// var headers = {'Content-Type': 'application/json'};
// var request = http.Request('POST', Uri.parse('https://apiderichat.hmg.com/api/user/calldecline'));
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatLoginTokenUrl}calldecline", "${ApiConsts.chatLoginTokenUrl}calldecline",
{"currentUserId": cUserID, "targetUserId": tUserID, "secretKey": "derichatmobileuser", "targetUserToken": targetUsertoken}, {"currentUserId": cUserID, "targetUserId": tUserID, "secretKey": "derichatmobileuser", "targetUserToken": targetUsertoken},
@ -231,14 +229,18 @@ class ChatApiClient {
return response; return response;
} }
Future<Response> OneSignalVoip({required String deviceID}) async { Future<String> oneSignalVoip(String value) async {
String id = "";
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.oneSignalCall}players", "${ApiConsts.oneSignalCall}players",
{"app_id": ApiConsts.oneSignalAppID, "identifier": deviceID, "device_type": 0, "test_type": !kReleaseMode ? 0 : 1}, {"app_id": ApiConsts.oneSignalAppID, "identifier": value, "device_type": 0, "test_type": !kReleaseMode ? 1 : 0},
); );
Map<String, dynamic> values = jsonDecode(response.body) as Map<String, dynamic>;
id = values["id"];
if (!kReleaseMode) { if (!kReleaseMode) {
print("res: " + response.body); print("res: " + response.body);
} }
return response; return id;
} }
} }

@ -193,4 +193,15 @@ class AppState {
} }
bool cancelRequestTrancsection = true; bool cancelRequestTrancsection = true;
String _iosVoipPlayerID = "";
String get iosVoipPlayerID => _iosVoipPlayerID;
set setiosVoipPlayerID(String value) {
_iosVoipPlayerID = value;
}
} }

@ -153,6 +153,15 @@ class ChatVoipCall {
//await ChatApiClient().callDecline(cUserID: data.extra!.callerDetails!.targetUserId!, tUserID: data.extra!.callerDetails!.currentUserId!, targetUsertoken: data.extra!.loginDetails!.token!); //await ChatApiClient().callDecline(cUserID: data.extra!.callerDetails!.targetUserId!, tUserID: data.extra!.callerDetails!.currentUserId!, targetUsertoken: data.extra!.loginDetails!.token!);
// logger.log(Level.error, "API-EVENT-END"); // logger.log(Level.error, "API-EVENT-END");
} }
Future<void> voipDeclineCall(IosCallPayload? _iosCallPayload ) async {
try {
ALM.UserAutoLoginModel model = await ChatApiClient().getUserCallToken(userid: _iosCallPayload!.callData!.split("-").first);
dynamic Res = await ChatApiClient().callDecline(cUserID: int.parse(_iosCallPayload!.incomingCallerId!), tUserID: int.parse(_iosCallPayload!.callData!.split("-").first), targetUsertoken: model.response!.token!);
} catch (err) {
print(err);
}
}
Future<HubConnection> makeHub({required IncomingCallModel sessionData}) async { Future<HubConnection> makeHub({required IncomingCallModel sessionData}) async {
late HubConnection hc; late HubConnection hc;
@ -168,3 +177,4 @@ class ChatVoipCall {
} }
} }
} }

@ -139,12 +139,14 @@ class IosCallPayload {
String? incomingCallType; String? incomingCallType;
String? incomingCallerId; String? incomingCallerId;
String? incomingCallerName; String? incomingCallerName;
String? callData;
String? uuid; String? uuid;
IosCallPayload({ IosCallPayload({
this.incomingCallType, this.incomingCallType,
this.incomingCallerId, this.incomingCallerId,
this.incomingCallerName, this.incomingCallerName,
this.callData,
this.uuid, this.uuid,
}); });
@ -156,6 +158,7 @@ class IosCallPayload {
incomingCallType: json["incoming_call_type"], incomingCallType: json["incoming_call_type"],
incomingCallerId: json["incoming_caller_id"], incomingCallerId: json["incoming_caller_id"],
incomingCallerName: json["incoming_caller_name"], incomingCallerName: json["incoming_caller_name"],
callData: json["call_data"],
uuid: json["uuid"], uuid: json["uuid"],
); );
@ -163,6 +166,7 @@ class IosCallPayload {
"incoming_call_type": incomingCallType, "incoming_call_type": incomingCallType,
"incoming_caller_id": incomingCallerId, "incoming_caller_id": incomingCallerId,
"incoming_caller_name": incomingCallerName, "incoming_caller_name": incomingCallerName,
"call_data": callData,
"uuid": uuid, "uuid": uuid,
}; };
} }

@ -47,6 +47,9 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
late BuildContext providerContext; late BuildContext providerContext;
List<MediaDeviceInfo> devices = [];
var _videoDeviceId ;
void initCallListeners({required BuildContext context}) { void initCallListeners({required BuildContext context}) {
providerContext = context; providerContext = context;
if (kDebugMode) { if (kDebugMode) {
@ -62,6 +65,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
} }
//Video Constraints //Video Constraints
Map<String, Object> videoConstraints = { Map<String, Object> videoConstraints = {
"video": { "video": {
"mandatory": { "mandatory": {
@ -69,6 +73,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
"height": {"min": 720} "height": {"min": 720}
}, },
"optional": [ "optional": [
// {'sourceId': _videoDeviceId},
{ {
"width": {"max": 1280} "width": {"max": 1280}
}, },
@ -80,7 +85,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
"width": 1280, //420,//640,//1280, "width": 1280, //420,//640,//1280,
"height": 720, //240//480//720 "height": 720, //240//480//720
"audio": true, "audio": true,
}; };
// Audio Constraints // Audio Constraints
Map<String, Object> audioConstraints = { Map<String, Object> audioConstraints = {
@ -584,9 +589,12 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
///////////////// Incoming Call /////////////////////////////// ///////////////// Incoming Call ///////////////////////////////
Future<void> initStreams() async { Future<void> initStreams() async {
devices = await navigator.mediaDevices.enumerateDevices();
localVideoRenderer = RTCVideoRenderer(); localVideoRenderer = RTCVideoRenderer();
remoteRenderer = RTCVideoRenderer(); remoteRenderer = RTCVideoRenderer();
await localVideoRenderer!.initialize(); await localVideoRenderer!.initialize();
_localStream ??= await navigator.mediaDevices.getUserMedia(isVideoCall ? videoConstraints : audioConstraints); _localStream ??= await navigator.mediaDevices.getUserMedia(isVideoCall ? videoConstraints : audioConstraints);
localVideoRenderer!.srcObject = _localStream; localVideoRenderer!.srcObject = _localStream;
await remoteRenderer!.initialize(); await remoteRenderer!.initialize();

@ -107,7 +107,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} catch (e) { } catch (e) {
disableChatForThisUser = true; disableChatForThisUser = true;
isUserOnline = false; isUserOnline = false;
notifyListeners(); notifyListeners();
} }
} }

@ -8,10 +8,15 @@ import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/main.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'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/models/chat/incoming_call_model.dart'; import 'package:mohem_flutter_app/models/chat/incoming_call_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
@ -46,7 +51,7 @@ class _StartCallPageState extends State<StartCallPage> {
IncomingCallModel? sessionData; IncomingCallModel? sessionData;
dynamic calls = await FlutterCallkitIncoming.activeCalls(); dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls.isNotEmpty) { if (calls.isNotEmpty) {
sessionData = IncomingCallModel.fromRawJson(jsonEncode(calls[0])); sessionData = IncomingCallModel.fromRawJson(jsonEncode(calls[0]));
print(sessionData.toRawJson()); print(sessionData.toRawJson());
if (provider.isUserOnline) { if (provider.isUserOnline) {
cProv.isUserOnline = provider.isUserOnline; cProv.isUserOnline = provider.isUserOnline;
@ -75,7 +80,47 @@ class _StartCallPageState extends State<StartCallPage> {
} }
} }
void startIosCall() {} void startIosCall() async {
IosCallPayload _iosCallPayload = IosCallPayload.fromRawJson(await Utils.getStringFromPrefs("iosCallPayload"));
var userID = _iosCallPayload!.callData!.split("-").first;
var callType = _iosCallPayload!.callData!.split("-").last;
SingleUserChatModel inCallData = SingleUserChatModel(
targetUserName: _iosCallPayload.incomingCallerName,
chatEventId: 3,
targetUserId: int.parse(_iosCallPayload.incomingCallerId!),
currentUserId: int.parse(userID),
);
if (provider.isUserOnline) {
cProv.isUserOnline = provider.isUserOnline;
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 =========");
}
cProv.isUserOnline = provider.isUserOnline;
UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserCallToken(userid: userID);
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
Utils.saveStringFromPrefs("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 provider.buildHubConnection(context: context, ccProvider: cProv).whenComplete(() {
cProv.init();
isCallConnected = true;
});
} catch (e) {
logger.w(e);
}
}
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -92,459 +137,459 @@ class _StartCallPageState extends State<StartCallPage> {
builder: (BuildContext context, ChatCallProvider provider, ChatProviderModel cpm, Widget? child) { builder: (BuildContext context, ChatCallProvider provider, ChatProviderModel cpm, Widget? child) {
return provider.isIncomingCallLoader return provider.isIncomingCallLoader
? const SizedBox( ? const SizedBox(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
child: Center(child: CircularProgressIndicator()), child: Center(child: CircularProgressIndicator()),
) )
: provider.isIncomingCall : provider.isIncomingCall
? SizedBox( ? SizedBox(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
child: Stack( child: Stack(
alignment: FractionalOffset.center, alignment: FractionalOffset.center,
children: <Widget>[ children: <Widget>[
if (!provider.isAudioCall && provider.isVideoCall) if (!provider.isAudioCall && provider.isVideoCall)
Positioned.fill( Positioned.fill(
child: RTCVideoView( child: RTCVideoView(
provider.remoteRenderer!, provider.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover, objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
key: const Key('remote'), 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(
provider.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
), ),
), if (provider.isVideoCall)
child: Column( DraggableWidget(
crossAxisAlignment: CrossAxisAlignment.start, bottomMargin: 20,
mainAxisSize: MainAxisSize.max, topMargin: 40,
children: <Widget>[ intialVisibility: true,
40.height, horizontalSpace: 20,
Row( shadowBorderRadius: 50,
crossAxisAlignment: CrossAxisAlignment.center, initialPosition: AnchoringPosition.topLeft,
mainAxisAlignment: MainAxisAlignment.center, dragController: dragController,
children: <Widget>[ normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
Container( draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
margin: const EdgeInsets.all(21.0), child: SizedBox(
child: Container( height: 200,
margin: const EdgeInsets.only( width: 140,
left: 10.0, child: RTCVideoView(
right: 10.0, provider.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
), ),
child: Column( ),
crossAxisAlignment: CrossAxisAlignment.center, child: Column(
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisSize: MainAxisSize.max,
children: <Widget>[ children: <Widget>[
SvgPicture.asset( 40.height,
"assets/images/user.svg", Row(
height: 70, crossAxisAlignment: CrossAxisAlignment.center,
width: 70, mainAxisAlignment: MainAxisAlignment.center,
fit: BoxFit.cover, children: <Widget>[
), Container(
10.height, margin: const EdgeInsets.all(21.0),
Text( child: Container(
provider.incomingCallData.targetUserName!, margin: const EdgeInsets.only(
style: const TextStyle( left: 10.0,
fontSize: 21, right: 10.0,
decoration: TextDecoration.none, ),
fontWeight: FontWeight.bold, child: Column(
color: MyColors.white, crossAxisAlignment: CrossAxisAlignment.center,
letterSpacing: -1.26, mainAxisSize: MainAxisSize.min,
height: 23 / 12, mainAxisAlignment: MainAxisAlignment.spaceAround,
), children: <Widget>[
), SvgPicture.asset(
const Text( "assets/images/user.svg",
"On Call", height: 70,
style: TextStyle( width: 70,
fontSize: 16, fit: BoxFit.cover,
decoration: TextDecoration.none, ),
fontWeight: FontWeight.w600, 10.height,
color: Color( Text(
0xffC6C6C6, provider.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,
),
],
),
), ),
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: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.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,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : 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.textMixColor,
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.textMixColor : 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(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
// print("Reintiiiiiiitttiiiiiiii");
// provider.initStreams();
}
});
},
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,
), ),
), ),
], ],
), ),
],
),
),
),
),
),
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: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.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,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : 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.textMixColor,
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.textMixColor : 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(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
// print("Reintiiiiiiitttiiiiiiii");
// provider.initStreams();
}
});
},
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.isOutGoingCall
? SizedBox(
width: double.infinity,
height: double.infinity,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!provider.isAudioCall && provider.isVideoCall)
Positioned.fill(
child: RTCVideoView(
provider.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(
provider.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
), ),
), ),
child: Column( ],
crossAxisAlignment: CrossAxisAlignment.start, ),
mainAxisSize: MainAxisSize.max, )
: provider.isOutGoingCall
? SizedBox(
width: double.infinity,
height: double.infinity,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[ children: <Widget>[
40.height, if (!provider.isAudioCall && provider.isVideoCall)
Row( Positioned.fill(
crossAxisAlignment: CrossAxisAlignment.center, child: RTCVideoView(
mainAxisAlignment: MainAxisAlignment.center, provider.remoteRenderer!,
children: <Widget>[ objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
Container( key: const Key('remote'),
margin: const EdgeInsets.all(21.0), ),
child: Container( ),
margin: const EdgeInsets.only( if (provider.isVideoCall)
left: 10.0, DraggableWidget(
right: 10.0, bottomMargin: 20,
), topMargin: 40,
child: Column( intialVisibility: true,
crossAxisAlignment: CrossAxisAlignment.center, horizontalSpace: 20,
mainAxisSize: MainAxisSize.min, shadowBorderRadius: 50,
mainAxisAlignment: MainAxisAlignment.spaceAround, initialPosition: AnchoringPosition.topLeft,
children: <Widget>[ dragController: dragController,
SvgPicture.asset( normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
"assets/images/user.svg", draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
height: 70, child: SizedBox(
width: 70, height: 200,
fit: BoxFit.cover, width: 140,
child: RTCVideoView(
provider.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
), ),
10.height, ),
Text( child: Column(
provider.outGoingCallData.receiverName!, crossAxisAlignment: CrossAxisAlignment.start,
style: const TextStyle( mainAxisSize: MainAxisSize.max,
fontSize: 21, children: <Widget>[
decoration: TextDecoration.none, 40.height,
fontWeight: FontWeight.bold, Row(
color: MyColors.white, crossAxisAlignment: CrossAxisAlignment.center,
letterSpacing: -1.26, mainAxisAlignment: MainAxisAlignment.center,
height: 23 / 12, 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(
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,
),
],
),
),
),
],
), ),
), ],
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: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.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,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : 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.textMixColor,
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.textMixColor : 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(isUserOnline: cpm.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();
),
),
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: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.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,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : 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.textMixColor,
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.textMixColor : 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(isUserOnline: cpm.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();
}, },
), ),
); );

@ -55,7 +55,7 @@ class LoginScreen extends StatefulWidget {
} }
} }
class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
TextEditingController username = TextEditingController(); TextEditingController username = TextEditingController();
TextEditingController password = TextEditingController(); TextEditingController password = TextEditingController();
@ -65,7 +65,6 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
late final FirebaseMessaging _firebaseMessaging; late final FirebaseMessaging _firebaseMessaging;
IosCallPayload? _iosCallPayload; IosCallPayload? _iosCallPayload;
bool _autoLogin = false; bool _autoLogin = false;
bool? isAppOpenBySystem; bool? isAppOpenBySystem;
@ -80,8 +79,7 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
final voIPKit = FlutterIOSVoIPKit.instance; final voIPKit = FlutterIOSVoIPKit.instance;
late Timer timeOutTimer; late Timer timeOutTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -98,82 +96,70 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
setupVoIPCallBacks(); setupVoIPCallBacks();
} }
void _timeOut({ // IOS Voip Call
int seconds = 15,
}) async {
timeOutTimer = Timer(Duration(seconds: seconds), () async {
print('🎈 example: timeOut');
var incomingCallerName = await voIPKit.getIncomingCallerName();
voIPKit.unansweredIncomingCall(
skipLocalNotification: false,
missedCallTitle: '📞 Missed call',
missedCallBody: 'There was a call from $incomingCallerName',
);
});
}
void setupVoIPCallBacks() { void setupVoIPCallBacks() {
if (Platform.isIOS) { if (Platform.isIOS) {
voIPKit.getVoIPToken().then((value) { voIPKit.getVoIPToken().then((value) async {
print('🎈 example: getVoIPToken: $value'); if (value != null) {
ChatApiClient().OneSignalVoip(deviceID: value!); AppState().setiosVoipPlayerID = await ChatApiClient().oneSignalVoip(value!);
}
}); });
voIPKit.onDidUpdatePushToken = (String token) {
print('🎈 example: onDidUpdatePushToken: $token');
};
} }
voIPKit.onDidUpdatePushToken = (String token) {
print('🎈 example: onDidUpdatePushToken: $token');
};
voIPKit.onDidReceiveIncomingPush = ( voIPKit.onDidReceiveIncomingPush = (
Map<String, dynamic> payload, Map<String, dynamic> payload,
) async { ) async {
_iosCallPayload = IosCallPayload.fromJson(payload); _iosCallPayload = IosCallPayload.fromJson(payload);
logger.d(_iosCallPayload!.incomingCallerId!.split("-").last); isIncomingCall = true;
print('🎈 example: onDidReceiveIncomingPush $payload');
_timeOut(); _timeOut();
}; };
voIPKit.onDidRejectIncomingCall = ( voIPKit.onDidRejectIncomingCall = (
String uuid, String uuid,
String callerId, String callerId,
) async { ) async {
try { await ChatVoipCall().voipDeclineCall(_iosCallPayload);
var logText = "did reject call $callerId"; await voIPKit.endCall();
} catch (err) {}
}; };
voIPKit.onDidAcceptIncomingCall = ( voIPKit.onDidAcceptIncomingCall = (
String uuid, String uuid,
String callerId, String callerId,
) async { ) async {
var callerID = "did accept call $callerId"; var callerID = "did accept call $callerId";
timeOutTimer.cancel();
debugPrint(callerID);
logger.d(_iosCallPayload!.incomingCallerId!.split("-").last);
debugPrint(_iosCallPayload!.incomingCallerId);
debugPrint(_iosCallPayload!.incomingCallerName);
debugPrint(_iosCallPayload!.incomingCallType);
await connectCall(); await connectCall();
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling); await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected(); await voIPKit.callConnected();
Future.delayed(const Duration(milliseconds: 2500), () {
voIPKit.endCall().then((value) async {});
});
timeOutTimer.cancel();
}; };
} }
void _timeOut() async {
timeOutTimer = Timer(const Duration(seconds: 25), () async {
var incomingCallerName = await voIPKit.getIncomingCallerName();
voIPKit.unansweredIncomingCall(
skipLocalNotification: false,
missedCallTitle: '📞 Missed call',
missedCallBody: 'There was a call from $incomingCallerName',
);
await ChatVoipCall().voipDeclineCall(_iosCallPayload);
await voIPKit.endCall();
});
}
Future<void> connectCall() async { Future<void> connectCall() async {
try { try {
UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserCallToken(userid: _iosCallPayload!.incomingCallerId!.split("-").last); BuildContext context = AppRoutes.navigatorKey.currentContext!;
if (userLoginResponse.response != null) { Utils.hideLoading(context);
AppState().setchatUserDetails = userLoginResponse; Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
Utils.saveStringFromPrefs("userLoginChatDetails", jsonEncode(userLoginResponse.response)); var pageRoute = MaterialPageRoute(builder: (context) => StartCallPage());
} Navigator.push(context, pageRoute).whenComplete(() {
checkFirebaseToken();
});
} catch (e) { } catch (e) {
logger.d(e); logger.d(e);
} }
@ -206,13 +192,11 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
// } // }
// } // }
Future<void> callListeners() async { Future<void> callListeners() async {
try { try {
print("Call Listeners Init"); print("Call Listeners Init");
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async { FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async {
switch (event!.event) { switch (event!.event) {
case Event.actionCallIncoming: case Event.actionCallIncoming:
break; break;
case Event.actionCallStart: case Event.actionCallStart:
@ -239,10 +223,8 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
Utils.saveStringFromPrefs("inComingCallData", "null"); Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls(); FlutterCallkitIncoming.endAllCalls();
break; break;
} }
print( '${event.toString()}\n'); print('${event.toString()}\n');
}); });
} on Exception { } on Exception {
logger.log(Level.info, "EXCEPTION-ON-EVENTS"); logger.log(Level.info, "EXCEPTION-ON-EVENTS");
@ -289,9 +271,6 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
} }
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
@ -408,7 +387,7 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver{
// 13777 // 13777
// Ab12345cd // Ab12345cd
} }
// if (isAppOpenBySystem!) checkFirebaseToken(); // if (isAppOpenBySystem!) checkFirebaseToken();
Utils.showLoading(context); Utils.showLoading(context);
Future.delayed(const Duration(seconds: 2)).whenComplete(() { Future.delayed(const Duration(seconds: 2)).whenComplete(() {

@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State<OffersAndDiscountsDetails> {
: getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center,
Html( Html(
data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "",
onLinkTap: (String? url, RenderContext context, Map<String, String> attributes, _) { onLinkTap: (String? url, Map<String, String> attributes, _) {
launchUrl(Uri.parse(url!)); launchUrl(Uri.parse(url!));
}, },
), ),

@ -87,7 +87,7 @@ dependencies:
signalr_netcore: ^1.3.3 signalr_netcore: ^1.3.3
logging: ^1.0.1 logging: ^1.0.1
swipe_to: ^1.0.2 swipe_to: ^1.0.2
flutter_webrtc: ^0.9.20 flutter_webrtc: ^0.9.34
draggable_widget: ^2.0.0 draggable_widget: ^2.0.0
flutter_local_notifications: any flutter_local_notifications: any
flutter_callkit_incoming: ^2.0.0+1 flutter_callkit_incoming: ^2.0.0+1
@ -119,7 +119,6 @@ dependencies:
google_api_availability: ^3.0.1 google_api_availability: ^3.0.1
flutter_ios_voip_kit: ^0.1.0 flutter_ios_voip_kit: ^0.1.0
file: ^6.1.4
dependency_overrides: dependency_overrides:

Loading…
Cancel
Save