diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index 96c55d9..fab432d 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -7,7 +7,7 @@ import flutter_local_notifications
// PKPushRegistryDelegate
@UIApplicationMain
-@objc class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate {
+@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
@@ -16,49 +16,49 @@ import flutter_local_notifications
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
GeneratedPluginRegistrant.register(with: registry)
}
- if #available(iOS 10.0, *) {
- UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
- }
+// if #available(iOS 10.0, *) {
+// UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
+// }
GeneratedPluginRegistrant.register(with: self)
//Setup VOIP
- let mainQueue = DispatchQueue.main
- let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
- voipRegistry.delegate = self
- voipRegistry.desiredPushTypes = [PKPushType.voIP]
+// let mainQueue = DispatchQueue.main
+// let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
+// voipRegistry.delegate = self
+// voipRegistry.desiredPushTypes = [PKPushType.voIP]
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// Handle updated push credentials
- func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
- print(credentials.token)
- let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
- //Save deviceToken to your server
- SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken)
- }
+// func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
+// print(credentials.token)
+// let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
+// //Save deviceToken to your server
+// SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken)
+// }
- func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
- print("didInvalidatePushTokenFor")
- SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP("")
- }
+// func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
+// print("didInvalidatePushTokenFor")
+// SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP("")
+// }
- // Handle incoming pushes
- func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
- print("didReceiveIncomingPushWith")
- guard type == .voIP else { return }
- print(payload.dictionaryPayload)
-// let id = payload.dictionaryPayload["id"] as? String ?? ""
-// let nameCaller = payload.dictionaryPayload["nameCaller"] as? String ?? ""
-// let handle = payload.dictionaryPayload["handle"] as? String ?? ""
- let isVideo = payload.dictionaryPayload["isVideo"] as? Bool ?? false
-//
-//
- let data = flutter_callkit_incoming.Data(id: "1", nameCaller: "Mohemm", handle: "handle", type: isVideo ? 1 : 0)
-// data.extra = ["user": "abc@123", "platform": "ios"]
-// data.iconName = "Mohemm"
- SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true)
- }
+// // Handle incoming pushes
+// func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
+// print("didReceiveIncomingPushWith")
+// guard type == .voIP else { return }
+// print(payload.dictionaryPayload)
+//// let id = payload.dictionaryPayload["id"] as? String ?? ""
+//// let nameCaller = payload.dictionaryPayload["nameCaller"] as? String ?? ""
+//// let handle = payload.dictionaryPayload["handle"] as? String ?? ""
+// let isVideo = payload.dictionaryPayload["isVideo"] as? Bool ?? false
+////
+////
+// let data = flutter_callkit_incoming.Data(id: "1", nameCaller: "Mohemm", handle: "handle", type: isVideo ? 1 : 0)
+//// data.extra = ["user": "abc@123", "platform": "ios"]
+//// data.iconName = "Mohemm"
+// SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true)
+// }
}
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index df3e12c..447afb8 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -95,5 +95,13 @@
TAG
+ FIVKIconName
+ AppIcon-VoIPKit
+ FIVKLocalizedName
+ VoIP-Kit
+ FIVKSupportVideo
+
+ FIVKSkipRecallScreen
+
diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart
index 77dcb34..ecd69b0 100644
--- a/lib/api/chat/chat_api_client.dart
+++ b/lib/api/chat/chat_api_client.dart
@@ -34,6 +34,7 @@ class ChatApiClient {
"deviceToken":AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei,
},
+
);
if (!kReleaseMode) {
@@ -186,6 +187,34 @@ class ChatApiClient {
}
return imagesData;
}
+
+
+ // CallUser Login Token
+
+
+ Future getUserCallToken({required String userid}) async {
+ user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel();
+ Response response = await ApiClient().postJsonForResponse(
+ "${ApiConsts.chatLoginTokenUrl}externaluserlogin",
+ {
+ "employeeNumber": userid,
+ "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
+ },
+ );
+
+ if (!kReleaseMode) {
+ logger.i("login-res: " + response.body);
+ }
+ if (response.statusCode == 200) {
+ userLoginResponse = user.userAutoLoginModelFromJson(response.body);
+ } else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) {
+ getUserCallToken(userid: userid);
+ } else {
+ userLoginResponse = user.userAutoLoginModelFromJson(response.body);
+ Utils.showToast(userLoginResponse.errorResponses!.first.message!);
+ }
+ return userLoginResponse;
+ }
// Call Decline On App Terminated State
diff --git a/lib/classes/chat_call_kit.dart b/lib/classes/chat_call_kit.dart
index 65da5c1..99b738e 100644
--- a/lib/classes/chat_call_kit.dart
+++ b/lib/classes/chat_call_kit.dart
@@ -1,6 +1,5 @@
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
-import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart
index 73cd5ca..eb6a837 100644
--- a/lib/classes/notifications.dart
+++ b/lib/classes/notifications.dart
@@ -123,7 +123,9 @@ class AppNotifications {
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);
+ if (Platform.isAndroid) {
+ ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message);
+ }
}
}
@@ -151,6 +153,8 @@ Future backgroundMessageHandler(RemoteMessage message) async {
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, background: true);
+ if (Platform.isAndroid) {
+ ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message, background: true);
+ }
}
}
diff --git a/lib/models/chat/call.dart b/lib/models/chat/call.dart
index 0f0e5a6..9b6c36d 100644
--- a/lib/models/chat/call.dart
+++ b/lib/models/chat/call.dart
@@ -128,3 +128,41 @@ class Sdp {
"sdp": sdp,
};
}
+
+
+
+
+
+// final iosCallPayload = iosCallPayloadFromJson(jsonString);
+
+class IosCallPayload {
+ String? incomingCallType;
+ String? incomingCallerId;
+ String? incomingCallerName;
+ String? uuid;
+
+ IosCallPayload({
+ this.incomingCallType,
+ this.incomingCallerId,
+ this.incomingCallerName,
+ 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"],
+ uuid: json["uuid"],
+ );
+
+ Map toJson() => {
+ "incoming_call_type": incomingCallType,
+ "incoming_caller_id": incomingCallerId,
+ "incoming_caller_name": incomingCallerName,
+ "uuid": uuid,
+ };
+}
diff --git a/lib/provider/chat_call_provider.dart b/lib/provider/chat_call_provider.dart
index 9bdf0f9..c1e44f7 100644
--- a/lib/provider/chat_call_provider.dart
+++ b/lib/provider/chat_call_provider.dart
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:io';
+
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
@@ -163,7 +164,6 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
- allowSnapshotting: false,
)).then((value) {
Navigator.of(providerContext).pop();
});
diff --git a/lib/ui/chat/call/chat_incoming_call_screen.dart b/lib/ui/chat/call/chat_incoming_call_screen.dart
index 32ac3df..48981de 100644
--- a/lib/ui/chat/call/chat_incoming_call_screen.dart
+++ b/lib/ui/chat/call/chat_incoming_call_screen.dart
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:core';
+import 'dart:io';
import 'dart:ui';
import 'package:draggable_widget/draggable_widget.dart';
import 'package:flutter/foundation.dart';
@@ -45,14 +46,18 @@ class _StartCallPageState extends State {
IncomingCallModel? sessionData;
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls.isNotEmpty) {
- sessionData = IncomingCallModel.fromRawJson(jsonEncode(calls[0]));
- }
+ dynamic values = calls[0];
+ logger.d(calls);
+ print("------- We are Here ---------");
+ print(calls[0]);
+ sessionData = await IncomingCallModel.fromRawJson(jsonEncode(values));
+
+ print(sessionData.toRawJson());
if (provider.isUserOnline) {
cProv.isUserOnline = provider.isUserOnline;
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;
@@ -72,15 +77,20 @@ class _StartCallPageState extends State {
logger.w(e);
}
}
+ }
}
-
+ void startIosCall() {}
@override
Widget build(BuildContext context) {
cProv = context.read();
provider = context.read();
- startCall();
+ if (Platform.isAndroid) {
+ startCall();
+ } else if (Platform.isIOS) {
+ startIosCall();
+ }
return Scaffold(
extendBody: true,
body: Consumer2(
diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart
index 898b316..28575cd 100644
--- a/lib/ui/landing/dashboard_screen.dart
+++ b/lib/ui/landing/dashboard_screen.dart
@@ -64,17 +64,19 @@ class _DashboardScreenState extends State with WidgetsBindingOb
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
- callListeners();
- scheduleMicrotask(() {
- data = Provider.of(context, listen: false);
- marathonProvider = Provider.of(context, listen: false);
- cProvider = Provider.of(context, listen: false);
- chatCallProvider = Provider.of(context, listen: false);
- if (checkIfPrivilegedForChat()) {
- _bHubCon();
- }
- _onRefresh(true);
- });
+ if (Platform.isAndroid) {
+ callListeners();
+ }
+ scheduleMicrotask(() {
+ data = Provider.of(context, listen: false);
+ marathonProvider = Provider.of(context, listen: false);
+ cProvider = Provider.of(context, listen: false);
+ chatCallProvider = Provider.of(context, listen: false);
+ if (checkIfPrivilegedForChat()) {
+ _bHubCon();
+ }
+ _onRefresh(true);
+ });
}
Future callListeners() async {
@@ -152,13 +154,13 @@ class _DashboardScreenState extends State with WidgetsBindingOb
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
if (isAppOpendByChat != "null" && isAppOpendByChat == "true") {
Utils.showLoading(context);
- cProvider.buildHubConnection(context: context, ccProvider: chatCallProvider);
+ await cProvider.buildHubConnection(context: context, ccProvider: chatCallProvider);
Future.delayed(const Duration(seconds: 2), () async {
cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!);
gotoChat(context);
});
} else {
- cProvider.buildHubConnection(context: context, ccProvider: chatCallProvider);
+ await cProvider.buildHubConnection(context: context, ccProvider: chatCallProvider);
Future.delayed(const Duration(seconds: 2), () {
cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!);
});
diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart
index fd53752..b716052 100644
--- a/lib/ui/login/login_screen.dart
+++ b/lib/ui/login/login_screen.dart
@@ -1,3 +1,4 @@
+import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -11,6 +12,9 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
+import 'package:flutter_ios_voip_kit/call_state_type.dart';
+import 'package:flutter_ios_voip_kit/flutter_ios_voip_kit.dart';
+import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
import 'package:mohem_flutter_app/api/login_api_client.dart';
@@ -26,7 +30,8 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
-import 'package:mohem_flutter_app/models/chat/incoming_call_model.dart';
+import 'package:mohem_flutter_app/models/chat/call.dart';
+import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/models/check_mobile_app_version_model.dart';
import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart';
import 'package:mohem_flutter_app/models/member_information_list_model.dart';
@@ -48,7 +53,7 @@ class LoginScreen extends StatefulWidget {
}
}
-class _LoginScreenState extends State {
+class _LoginScreenState extends State with WidgetsBindingObserver {
TextEditingController username = TextEditingController();
TextEditingController password = TextEditingController();
@@ -56,6 +61,7 @@ class _LoginScreenState extends State {
MemberLoginListModel? _memberLoginList;
late final FirebaseMessaging _firebaseMessaging;
+ IosCallPayload? _iosCallPayload;
bool _autoLogin = false;
@@ -69,6 +75,9 @@ class _LoginScreenState extends State {
// late HmsApiAvailability hmsApiAvailability;
+ final voIPKit = FlutterIOSVoIPKit.instance;
+ late Timer timeOutTimer;
+
@override
void initState() {
super.initState();
@@ -78,6 +87,74 @@ class _LoginScreenState extends State {
// checkDeviceSafety();
// }
callListeners();
+ WidgetsBinding.instance.addObserver(this);
+ setupVoIPCallBacks();
+ }
+
+ void _timeOut({
+ 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() {
+ if (Platform.isIOS) {
+ voIPKit.getVoIPToken().then((value) {
+ print('🎈 example: getVoIPToken: $value');
+ });
+
+ voIPKit.onDidUpdatePushToken = (String token) {
+ print('🎈 example: onDidUpdatePushToken: $token');
+ };
+ }
+
+ voIPKit.onDidReceiveIncomingPush = (
+ Map payload,
+ ) async {
+ _iosCallPayload = IosCallPayload.fromJson(payload);
+ logger.d(_iosCallPayload!.incomingCallerId!.split("-").last);
+ print('🎈 example: onDidReceiveIncomingPush $payload');
+ _timeOut();
+ };
+
+ voIPKit.onDidRejectIncomingCall = (
+ String uuid,
+ String callerId,
+ ) async {
+ try {
+ var logText = "did reject call $callerId";
+ } catch (err) {}
+ };
+
+ voIPKit.onDidAcceptIncomingCall = (
+ String uuid,
+ String callerId,
+ ) async {
+ var callerID = "did accept call $callerId";
+
+ debugPrint(callerID);
+ logger.d(_iosCallPayload!.incomingCallerId!.split("-").last);
+ debugPrint(_iosCallPayload!.incomingCallerId);
+ debugPrint(_iosCallPayload!.incomingCallerName);
+ debugPrint(_iosCallPayload!.incomingCallType);
+ await connectCall();
+ await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
+ await voIPKit.callConnected();
+
+ Future.delayed(const Duration(milliseconds: 2500), () {
+ voIPKit.endCall().then((value) async {});
+ });
+
+ timeOutTimer.cancel();
+ };
}
// void checkDeviceSafety() async {
@@ -95,6 +172,17 @@ class _LoginScreenState extends State {
// print(error);
// }
// }
+ Future connectCall() async {
+ try {
+ UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserCallToken(userid: _iosCallPayload!.incomingCallerId!.split("-").last);
+ if (userLoginResponse.response != null) {
+ AppState().setchatUserDetails = userLoginResponse;
+ Utils.saveStringFromPrefs("userLoginChatDetails", jsonEncode(userLoginResponse.response));
+ }
+ } catch (e) {
+ logger.d(e);
+ }
+ }
Future callListeners() async {
try {
@@ -119,7 +207,7 @@ class _LoginScreenState extends State {
case Event.ACTION_CALL_ENDED:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
- FlutterCallkitIncoming.endAllCalls();
+ FlutterCallkitIncoming.endAllCalls();
break;
case Event.ACTION_CALL_TIMEOUT:
Utils.saveStringFromPrefs("isIncomingCall", "false");
@@ -135,19 +223,20 @@ class _LoginScreenState extends State {
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls is List) {
if (calls.isNotEmpty) {
- Utils.hideLoading(context);
+ if (Platform.isAndroid) {
+ Utils.hideLoading(context);
+ }
var pageRoute = MaterialPageRoute(builder: (context) => StartCallPage());
- Navigator.push(context, pageRoute).whenComplete((){
+ Navigator.push(context, pageRoute).whenComplete(() {
checkFirebaseToken();
});
- }else{
+ } else {
FlutterCallkitIncoming.endAllCalls();
Utils.showToast("Something wen't wrong");
}
}
}
-
@override
void dispose() {
super.dispose();
diff --git a/pubspec.yaml b/pubspec.yaml
index b50b4c6..d685ecb 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -119,6 +119,9 @@ dependencies:
store_checker: ^1.1.0
google_api_availability: ^3.0.1
+ flutter_ios_voip_kit: ^0.1.0
+ file: ^6.1.4
+
dependency_overrides:
firebase_core_platform_interface: 4.5.1