diff --git a/android/app/build.gradle b/android/app/build.gradle
index 5279c1f..e66b465 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -71,10 +71,10 @@ android {
signingConfig signingConfigs.debug
}
release {
- signingConfig signingConfigs.release
- minifyEnabled true
- shrinkResources true
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.debug
+ minifyEnabled false
+ shrinkResources false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
@@ -85,4 +85,6 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'com.squareup.okhttp3:okhttp:4.9.1'
+
}
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
new file mode 100644
index 0000000..419bd27
--- /dev/null
+++ b/android/app/proguard-rules.pro
@@ -0,0 +1,27 @@
+-ignorewarnings
+-keepattributes *Annotation*
+-keepattributes Exceptions
+-keepattributes InnerClasses
+-keepattributes Signature
+-keepattributes SourceFile,LineNumberTable
+-keep class com.huawei.hianalytics.**{*;}
+-keep class com.huawei.updatesdk.**{*;}
+-keep class com.huawei.hms.**{*;}
+-keep class com.huawei.hms.flutter.**{*;}
+-keep class com.hiennv.flutter_callkit_incoming.** { *; }
+-keep class microsoft.aspnet.signalr.client.hubs.** { *; }
+-keep class com.microsoft.signalr.** { *; }
+-keep class tvi.webrtc.** { *; }
+-keep interface com.microsoft.signalr.** { *; }
+
+
+-repackageclasses
+
+## Flutter wrapper
+-keep class io.flutter.app.** { *; }
+-keep class io.flutter.plugin.** { *; }
+-keep class io.flutter.util.** { *; }
+-keep class io.flutter.view.** { *; }
+-keep class io.flutter.** { *; }
+-keep class io.flutter.plugins.** { *; }
+-dontwarn io.flutter.embedding.**
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 3f5e424..91e7ba3 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -8,6 +8,8 @@
+
+
@@ -22,6 +24,7 @@
android:icon="@mipmap/ic_launcher"
android:label="Mohemm"
android:extractNativeLibs="true"
+ android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round">
{
+// try {
+// callkitNotificationManager.showIncomingNotification(data)
+// sendEventFlutter(CallkitConstants.ACTION_CALL_INCOMING, data)
+// addCall(context, Data.fromBundle(data))
+// if (callkitNotificationManager.incomingChannelEnabled()) {
+// val soundPlayerServiceIntent =
+// Intent(context, CallkitSoundPlayerService::class.java)
+// soundPlayerServiceIntent.putExtras(data)
+// context.startService(soundPlayerServiceIntent)
+// }
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+//
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_START}" -> {
+// try {
+// sendEventFlutter(CallkitConstants.ACTION_CALL_START, data)
+// addCall(context, Data.fromBundle(data), true)
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+//
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_ACCEPT}" -> {
+// try {
+// sendEventFlutter(CallkitConstants.ACTION_CALL_ACCEPT, data)
+// context.stopService(Intent(context, CallkitSoundPlayerService::class.java))
+// callkitNotificationManager.clearIncomingNotification(data, true)
+// addCall(context, Data.fromBundle(data), true)
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+//
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_DECLINE}" -> {
+// try {
+// sendEventFlutter(CallkitConstants.ACTION_CALL_DECLINE, data)
+// context.stopService(Intent(context, CallkitSoundPlayerService::class.java))
+// callkitNotificationManager.clearIncomingNotification(data, false)
+// removeCall(context, Data.fromBundle(data))
+// println("----------- Code By Aamir on 2222-----------------------");
+// var callData = data.getSerializable(CallkitConstants.EXTRA_CALLKIT_EXTRA) as HashMap
+// val token = (callData["loginDetails"] as HashMap<*, *>)["token"] as? String
+// val targetUserId = (callData["callerDetails"] as HashMap<*, *>)["targetUserId"] as? Int
+// val currentUserId = (callData["callerDetails"] as HashMap<*, *>)["currentUserId"] as? Int
+// delineCall(currentUserID = currentUserId, targetUserID = targetUserId, token = token)
+// println("----------- Code By Aamir On BroadCast -----------------------");
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+//
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_ENDED}" -> {
+// try {
+// sendEventFlutter(CallkitConstants.ACTION_CALL_ENDED, data)
+// context.stopService(Intent(context, CallkitSoundPlayerService::class.java))
+// callkitNotificationManager.clearIncomingNotification(data, false)
+// removeCall(context, Data.fromBundle(data))
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+//
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_TIMEOUT}" -> {
+// try {
+// sendEventFlutter(CallkitConstants.ACTION_CALL_TIMEOUT, data)
+// context.stopService(Intent(context, CallkitSoundPlayerService::class.java))
+// if (data.getBoolean(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_SHOW, true)) {
+// callkitNotificationManager.showMissCallNotification(data)
+// }
+// removeCall(context, Data.fromBundle(data))
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+//
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_CALLBACK}" -> {
+// try {
+// callkitNotificationManager.clearMissCallNotification(data)
+// sendEventFlutter(CallkitConstants.ACTION_CALL_CALLBACK, data)
+// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+// val closeNotificationPanel = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+// context.sendBroadcast(closeNotificationPanel)
+// }
+// } catch (error: Exception) {
+// Log.e(TAG, null, error)
+// }
+// }
+// }
+// }
+//
+//
+// private fun delineCall(currentUserID: Int?, targetUserID: Int?, token: String?) {
+// println("--------------- Inside Decline Call ----------------");
+// val url = "https://apiderichat.hmg.com/api/user/calldecline"
+// val payload = """
+// {
+// "currentUserId": $targetUserID,
+// "targetUserId": $currentUserID,
+// "secretKey": "derichatmobileuser",
+// "targetUserToken": "$token"
+// }
+// """.trimIndent()
+//
+//
+// val jsonMediaType = "application/json".toMediaType()
+//
+// GlobalScope.launch(Dispatchers.IO) {
+// val client = OkHttpClient()
+// val requestBody = payload.toRequestBody(jsonMediaType)
+// val request = Request.Builder()
+// .url(url)
+// .post(requestBody)
+// .build()
+//
+// client.newCall(request).execute().use { response ->
+// if (response.isSuccessful) {
+// val responseData = response.body?.string()
+// println("API Successful. Response data: $responseData")
+// } else {
+// val errorMessage = response.body?.string()
+// println("API Failed. Error message: $errorMessage")
+// }
+// }
+// }
+//
+//
+// }
+//
+//
+// private fun sendEventFlutter(event: String, data: Bundle) {
+// val android = mapOf(
+// "isCustomNotification" to data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_NOTIFICATION, false),
+// "isCustomSmallExNotification" to data.getBoolean(
+// CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_SMALL_EX_NOTIFICATION,
+// false
+// ),
+// "ringtonePath" to data.getString(CallkitConstants.EXTRA_CALLKIT_RINGTONE_PATH, ""),
+// "backgroundColor" to data.getString(CallkitConstants.EXTRA_CALLKIT_BACKGROUND_COLOR, ""),
+// "backgroundUrl" to data.getString(CallkitConstants.EXTRA_CALLKIT_BACKGROUND_URL, ""),
+// "actionColor" to data.getString(CallkitConstants.EXTRA_CALLKIT_ACTION_COLOR, ""),
+// "incomingCallNotificationChannelName" to data.getString(
+// CallkitConstants.EXTRA_CALLKIT_INCOMING_CALL_NOTIFICATION_CHANNEL_NAME,
+// ""
+// ),
+// "missedCallNotificationChannelName" to data.getString(
+// CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_NOTIFICATION_CHANNEL_NAME,
+// ""
+// ),
+// )
+// val notification = mapOf(
+// "id" to data.getInt(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_ID),
+// "showNotification" to data.getBoolean(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_SHOW),
+// "count" to data.getInt(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_COUNT),
+// "subtitle" to data.getString(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_SUBTITLE),
+// "callbackText" to data.getString(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_TEXT),
+// "isShowCallback" to data.getBoolean(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_SHOW),
+// )
+// val forwardData = mapOf(
+// "id" to data.getString(CallkitConstants.EXTRA_CALLKIT_ID, ""),
+// "nameCaller" to data.getString(CallkitConstants.EXTRA_CALLKIT_NAME_CALLER, ""),
+// "avatar" to data.getString(CallkitConstants.EXTRA_CALLKIT_AVATAR, ""),
+// "number" to data.getString(CallkitConstants.EXTRA_CALLKIT_HANDLE, ""),
+// "type" to data.getInt(CallkitConstants.EXTRA_CALLKIT_TYPE, 0),
+// "duration" to data.getLong(CallkitConstants.EXTRA_CALLKIT_DURATION, 0L),
+// "textAccept" to data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_ACCEPT, ""),
+// "textDecline" to data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_DECLINE, ""),
+// "extra" to data.getSerializable(CallkitConstants.EXTRA_CALLKIT_EXTRA)!!,
+// "missedCallNotification" to notification,
+// "android" to android
+// )
+// FlutterCallkitIncomingPlugin.sendEvent(event, forwardData)
+// }
+//}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/mohem_flutter_app/MainActivity.kt b/android/app/src/main/kotlin/com/mohem_flutter_app/MainActivity.kt
index 0023ec9..aafee53 100644
--- a/android/app/src/main/kotlin/com/mohem_flutter_app/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/mohem_flutter_app/MainActivity.kt
@@ -9,9 +9,18 @@ package com.mohem_flutter_app
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
+import io.flutter.plugin.common.MethodChannel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class MainActivity : FlutterFragmentActivity() {
-class MainActivity: FlutterFragmentActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
}
+
+
}
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index dc67123..12dceb5 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = '1.7.20'
+ ext.kotlin_version = '1.8.21'
repositories {
google()
mavenCentral()
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index ed1a787..176eb48 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
+#distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
diff --git a/assets/audio/ring_30Sec.caf b/assets/audio/ring_30Sec.caf
new file mode 100644
index 0000000..b5bb4b8
Binary files /dev/null and b/assets/audio/ring_30Sec.caf differ
diff --git a/assets/audio/ring_60Sec.mp3 b/assets/audio/ring_60Sec.mp3
new file mode 100644
index 0000000..ac32394
Binary files /dev/null and b/assets/audio/ring_60Sec.mp3 differ
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 073c15f..43841a1 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 54;
+ objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
@@ -144,6 +144,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C4CFBC4C5CAC00182015ACD5 /* [CP] Embed Pods Frameworks */,
+ 1C704830960BB41251F31356 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -203,6 +204,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
+ 1C704830960BB41251F31356 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
2D06B7AD3B87C9C9059E4168 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -227,7 +245,6 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -242,7 +259,6 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -366,18 +382,17 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Mohemm;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.7.2;
- PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
+ PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemmtest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -504,18 +519,17 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Mohemm;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.7.2;
- PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
+ PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemmtest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -534,18 +548,17 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Mohemm;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.7.2;
- PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
+ PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemmtest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index b4ad5b3..fab432d 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -1,9 +1,11 @@
import UIKit
+import PushKit
import Flutter
import Firebase
+import flutter_callkit_incoming
import flutter_local_notifications
-
+// PKPushRegistryDelegate
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
@@ -14,10 +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)
- return super.application(application, didFinishLaunchingWithOptions: launchOptions)
- }
+
+ //Setup 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, 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)
+// }
+
+
}
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 24ba08c..447afb8 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -63,6 +63,7 @@
UIBackgroundModes
+ processing
fetch
remote-notification
voip
@@ -94,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 f727c7d..d127a3a 100644
--- a/lib/api/chat/chat_api_client.dart
+++ b/lib/api/chat/chat_api_client.dart
@@ -31,8 +31,10 @@ class ChatApiClient {
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
"isMobile": true,
- "deviceToken":AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
+ "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei,
+ "platform": Platform.isIOS ? "ios" : "android", // ios, android
+ "voipToken": Platform.isIOS ? AppState().iosVoipPlayerID : ""
},
);
@@ -71,9 +73,7 @@ class ChatApiClient {
if (!kReleaseMode) {
logger.i("res: " + response.body);
}
- return ChatUserModel.fromJson(
- json.decode(response.body),
- );
+ return ChatUserModel.fromJson(json.decode(response.body));
} catch (e) {
throw e;
}
@@ -188,4 +188,59 @@ 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
+ Future callDecline({required int cUserID, required int tUserID, required String targetUsertoken}) async {
+ Response response = await ApiClient().postJsonForResponse(
+ "${ApiConsts.chatLoginTokenUrl}calldecline",
+ {"currentUserId": cUserID, "targetUserId": tUserID, "secretKey": "derichatmobileuser", "targetUserToken": targetUsertoken},
+ );
+ print("res: " + response.body);
+ if (!kReleaseMode) {
+ logger.i({"currentUserId": cUserID, "targetUserId": tUserID, "secretKey": "derichatmobileuser", "targetUserToken": targetUsertoken});
+ print("res: " + response.body);
+ }
+ return response;
+ }
+
+ Future oneSignalVoip(String value) async {
+ String id = "";
+ Response response = await ApiClient().postJsonForResponse(
+ "${ApiConsts.oneSignalCall}players",
+ {"app_id": ApiConsts.oneSignalAppID, "identifier": value, "device_type": 0, "test_type": !kReleaseMode ? 1 : 0},
+ );
+
+ Map values = jsonDecode(response.body) as Map;
+ id = values["id"];
+ if (!kReleaseMode) {
+ print("res: " + response.body);
+ }
+ return id;
+ }
}
diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart
index b0c93ee..d86acd8 100644
--- a/lib/app_state/app_state.dart
+++ b/lib/app_state/app_state.dart
@@ -193,4 +193,21 @@ class AppState {
}
bool cancelRequestTrancsection = true;
+
+
+ String _iosVoipPlayerID = "";
+
+ String get iosVoipPlayerID => _iosVoipPlayerID;
+
+ set setiosVoipPlayerID(String value) {
+ _iosVoipPlayerID = value;
+ }
+
+ bool _isUserOnline = false;
+
+ bool get getisUserOnline => _isUserOnline;
+
+ set setisUserOnline(bool value) {
+ _isUserOnline = value;
+ }
}
diff --git a/lib/classes/chat_call_kit.dart b/lib/classes/chat_call_kit.dart
new file mode 100644
index 0000000..644c552
--- /dev/null
+++ b/lib/classes/chat_call_kit.dart
@@ -0,0 +1,180 @@
+import 'dart:convert';
+import 'dart:io';
+import 'package:firebase_messaging/firebase_messaging.dart';
+import 'package:flutter/material.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:logger/logger.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/classes/consts.dart';
+import 'package:mohem_flutter_app/classes/utils.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/incoming_call_model.dart';
+import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
+import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
+import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:signalr_netcore/hub_connection.dart';
+import 'package:signalr_netcore/signalr_client.dart';
+
+class ChatVoipCall {
+ static final ChatVoipCall _instance = ChatVoipCall._internal();
+
+ ChatVoipCall._internal();
+
+ factory ChatVoipCall() => _instance;
+
+ late ChatProviderModel prov;
+ late ChatCallProvider cProv;
+ dynamic inCallData;
+ bool isUserOnline = false;
+ dynamic callData;
+ static const platform = MethodChannel('com.example.httpchannel/http');
+
+ Future showCallkitIncoming({required String uuid, RemoteMessage? data, CallDataModel? incomingCallData, bool background = false}) async {
+ await FlutterCallkitIncoming.endAllCalls();
+ ALM.Response autoLoginData;
+ SingleUserChatModel callerData;
+ if (data!.data["user_token_response"] == null || data.data["user_token_response"].isEmpty) {
+ // Online & App Logged In
+ ALM.Response sharedDetails = ALM.Response.fromJson(jsonDecode(await Utils.getStringFromPrefs("userLoginChatDetails")));
+ autoLoginData = ALM.Response.fromJson(AppState().getchatUserDetails == null ? sharedDetails.toJson() : AppState().getchatUserDetails!.response!.toJson());
+ dynamic items = jsonDecode(data.data["user_chat_history_response"]);
+ callerData = SingleUserChatModel(
+ targetUserId: items["CurrentUserId"],
+ targetUserEmail: items["CurrentUserEmail"],
+ targetUserName: items["CurrentUserName"].split("@").first,
+ currentUserId: autoLoginData.id,
+ currentUserEmail: autoLoginData.email,
+ currentUserName: autoLoginData.userName,
+ chatEventId: 3);
+ isUserOnline = true;
+ } else {
+ // Offline or App in Background or App is At Verify Screen
+ autoLoginData = ALM.Response.fromJson(jsonDecode(data.data["user_token_response"]));
+ callerData = SingleUserChatModel.fromJson(json.decode(data.data["user_chat_history_response"]));
+ }
+ CallKitParams params = CallKitParams(
+ id: uuid,
+ nameCaller: callerData.targetUserName,
+ appName: 'Mohemm',
+ handle: '',
+ type: 0,
+ duration: 20000,
+ textAccept: 'Accept',
+ textDecline: 'Decline',
+ extra: {
+ "loginDetails": autoLoginData.toJson(),
+ "callerDetails": callerData.toJson(),
+ 'isIncomingCall': true,
+ 'isUserOnline': isUserOnline,
+ 'callType': data.data["callType"],
+ },
+ android: const AndroidParams(
+ isCustomNotification: true,
+ isShowLogo: false,
+ 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 FlutterCallkitIncoming.showCallkitIncoming(params);
+ }
+ }
+
+ Future declineCall({ payload}) async {
+ IncomingCallModel data = IncomingCallModel.fromJson(jsonDecode(payload));
+
+ if (isUserOnline) {
+ HubConnection _hc = await makeHub(sessionData: data);
+ await _hc.start();
+ if (_hc.state == HubConnectionState.Connected) {
+ if (data.extra != null) {
+ await _hc.invoke("HangUpAsync", args: [data.extra!.callerDetails!.currentUserId!, data.extra!.callerDetails!.targetUserId!]);
+ await _hc.invoke("UpdateUserStatusAsync", args: [int.parse(data.extra!.callerDetails!.currentUserId.toString()), 1]);
+ FlutterCallkitIncoming.endAllCalls();
+ chatHubConnection = _hc;
+ }
+ }
+ }
+ //else {
+ // Future.delayed(const Duration(seconds: 3), () {
+ // ChatApiClient().callDecline(cUserID: data.extra!.callerDetails!.targetUserId!, tUserID: data.extra!.callerDetails!.currentUserId!, targetUsertoken: data.extra!.loginDetails!.token!);
+ // });
+ // HubConnection _hc = await makeHub(sessionData: data);
+ // await _hc.start();
+ // if (_hc.state == HubConnectionState.Connected) {
+ // logger.log(Level.info, "HUB-EVENT");
+ // await _hc.invoke("HangUpAsync", args: [
+ // data.extra!.callerDetails!.currentUserId!,
+ // data.extra!.callerDetails!.targetUserId!,
+ // ]);
+ // FlutterCallkitIncoming.endAllCalls();
+ // await _hc.stop();
+ // }
+ // }
+
+ //
+ // try {
+ // var response = await platform.invokeMethod(
+ // 'executeHttpPostRequest', {"currentUserID": data.extra!.callerDetails!.targetUserId, "targetUserID": data.extra!.callerDetails!.currentUserId, "token": data.extra!.loginDetails!.token});
+ // print('HTTP POST response: $response');
+ // Future.delayed(Duration(seconds: 3), () {
+ // ChatApiClient().callDecline(cUserID: data.extra!.callerDetails!.targetUserId!, tUserID: data.extra!.callerDetails!.currentUserId!, targetUsertoken: data.extra!.loginDetails!.token!);
+ // });
+ // } on PlatformException catch (e) {
+ // print('Error invoking method: ${e.message}');
+ // }
+
+ //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");
+ }
+
+ Future voipDeclineCall(IosCallPayload? _iosCallPayload ) async {
+ try {
+ ALM.UserAutoLoginModel model = await ChatApiClient().getUserCallToken(userid: _iosCallPayload!.incomingCallReciverId.toString());
+ dynamic Res = await ChatApiClient().callDecline(cUserID: int.parse(_iosCallPayload!.incomingCallerId!), tUserID: int.parse(_iosCallPayload!.incomingCallReciverId.toString()), targetUsertoken: model.response!.token!);
+ } catch (err) {
+ print(err);
+ }
+ }
+
+ Future makeHub({required IncomingCallModel sessionData}) async {
+ late HubConnection hc;
+ try {
+ HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
+ hc = HubConnectionBuilder()
+ .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${sessionData.extra!.loginDetails!.id}&source=Desktop&access_token=${sessionData.extra?.loginDetails!.token}", options: httpOp)
+ .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build();
+ return hc;
+ } catch (e) {
+ print(e);
+ return hc;
+ }
+ }
+}
+
diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart
index 45ef661..318bb81 100644
--- a/lib/classes/consts.dart
+++ b/lib/classes/consts.dart
@@ -3,8 +3,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
class ApiConsts {
//static String baseUrl = "http://10.200.204.20:2801/"; // Local server
// static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server
- // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server
- static String baseUrl = "https://hmgwebservices.com"; // Live server
+ // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server
+ static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrlServices = baseUrl + "/Services/"; // server
// static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server
static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/";
@@ -26,6 +26,9 @@ class ApiConsts {
static String chatMediaImageUploadUrl = chatServerBaseApiUrl + "shared/";
static String chatFavUser = chatServerBaseApiUrl + "FavUser/";
static String chatUserImages = chatServerBaseUrl + "empservice/api/employee/";
+ static String oneSignalCall = "https://onesignal.com/api/v1/";
+ static String oneSignalAppID = "472e4582-5c44-47ab-a5f5-9369b8967107";
+
//Brain Marathon Constants
static String marathonBaseUrl = "https://marathoon.com/service/api/";
diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart
index 8f432d7..80f0d79 100644
--- a/lib/classes/notifications.dart
+++ b/lib/classes/notifications.dart
@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
+import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
@@ -9,11 +10,13 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
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/chat_call_kit.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/models/get_notifications_response_model.dart';
import 'package:mohem_flutter_app/ui/notifications/notification_details_page.dart';
import 'package:permission_handler/permission_handler.dart';
+import 'package:uuid/uuid.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
@@ -53,6 +56,7 @@ class AppNotifications {
this.context = context;
+ print("Firebase init");
await requestPermissions();
AppState().setDeviceToken = firebaseToken;
await Permission.notification.isDenied.then((bool value) {
@@ -60,6 +64,10 @@ class AppNotifications {
Permission.notification.request();
}
});
+
+ await FirebaseMessaging.instance.setAutoInitEnabled(true);
+ await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(alert: true, badge: true, sound: true);
+
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) _handleMessage(initialMessage);
@@ -143,6 +151,14 @@ class AppNotifications {
),
);
});
+ 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') {
+ if (Platform.isAndroid) {
+ ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message);
+ }
+ }
}
void _handleOpenApp(RemoteMessage message) {
@@ -171,19 +187,26 @@ class AppNotifications {
});
}
}
+
+
}
-AndroidNotificationChannel channel = const AndroidNotificationChannel(
- "high_importance_channel",
- "High Importance Notifications",
+const AndroidNotificationChannel channel = AndroidNotificationChannel(
+ 'high_importance_channel', // id
+ 'High Importance Notifications', // title
+ description: 'This channel is used for important notifications.', // description
importance: Importance.high,
);
-Future backgroundMessageHandler(RemoteMessage message) async {
+@pragma('vm:entry-point')
+Future 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') {
- // ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message);
+ 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') {
+ if (Platform.isAndroid) {
+ ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message, background: true);
+ }
}
}
diff --git a/lib/config/routes.dart b/lib/config/routes.dart
index 705e40d..2a6ed46 100644
--- a/lib/config/routes.dart
+++ b/lib/config/routes.dart
@@ -5,6 +5,7 @@ import 'package:mohem_flutter_app/ui/attendance/add_vacation_rule_screen.dart';
import 'package:mohem_flutter_app/ui/attendance/monthly_attendance_screen.dart';
import 'package:mohem_flutter_app/ui/attendance/vacation_rule_screen.dart';
import 'package:mohem_flutter_app/ui/bottom_sheets/attendence_details_bottom_sheet.dart';
+import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/ui/chat/chat_home.dart';
import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
@@ -189,6 +190,7 @@ class AppRoutes {
static const String chat = "/chat";
static const String chatDetailed = "/chatDetailed";
static const String chatFavoriteUsers = "/chatFavoriteUsers";
+ static const String chatStartCall = "/chatStartCall";
//Marathon
static const String marathonIntroScreen = "/marathonIntroScreen";
@@ -301,6 +303,8 @@ class AppRoutes {
chat: (BuildContext context) => ChatHome(),
chatDetailed: (BuildContext context) => ChatDetailScreen(),
chatFavoriteUsers: (BuildContext context) => ChatFavoriteUsersScreen(),
+ chatStartCall: (BuildContext context) => StartCallPage(),
+
// Marathon
marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(),
diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart
index 642c8ec..4105def 100644
--- a/lib/generated_plugin_registrant.dart
+++ b/lib/generated_plugin_registrant.dart
@@ -7,16 +7,13 @@
// ignore_for_file: depend_on_referenced_packages
import 'package:audio_session/audio_session_web.dart';
-import 'package:camera_web/camera_web.dart';
import 'package:file_picker/_internal/file_picker_web.dart';
import 'package:firebase_core_web/firebase_core_web.dart';
import 'package:firebase_messaging_web/firebase_messaging_web.dart';
import 'package:fluttertoast/fluttertoast_web.dart';
import 'package:geolocator_web/geolocator_web.dart';
-import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
import 'package:image_picker_for_web/image_picker_for_web.dart';
import 'package:just_audio_web/just_audio_web.dart';
-import 'package:record_web/record_web.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
import 'package:url_launcher_web/url_launcher_web.dart';
import 'package:video_player_web/video_player_web.dart';
@@ -26,16 +23,13 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
AudioSessionWeb.registerWith(registrar);
- CameraPlugin.registerWith(registrar);
FilePickerWeb.registerWith(registrar);
FirebaseCoreWeb.registerWith(registrar);
FirebaseMessagingWeb.registerWith(registrar);
FluttertoastWebPlugin.registerWith(registrar);
GeolocatorPlugin.registerWith(registrar);
- GoogleMapsPlugin.registerWith(registrar);
ImagePickerPlugin.registerWith(registrar);
JustAudioPlugin.registerWith(registrar);
- RecordPluginWeb.registerWith(registrar);
SharedPreferencesPlugin.registerWith(registrar);
UrlLauncherPlugin.registerWith(registrar);
VideoPlayerPlugin.registerWith(registrar);
diff --git a/lib/main.dart b/lib/main.dart
index 07590f3..b31ccc3 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -18,8 +18,9 @@ import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:month_year_picker/month_year_picker.dart';
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
+import 'package:signalr_netcore/hub_connection.dart';
import 'package:sizer/sizer.dart';
-
+late HubConnection chatHubConnection;
Logger logger = Logger(
// filter: null, // Use the default LogFilter (-> only log in debug mode)
printer: PrettyPrinter(
@@ -70,9 +71,9 @@ Future main() async {
ChangeNotifierProvider(
create: (_) => MarathonProvider(),
),
- // ChangeNotifierProvider(
- // create: (_) => ChatCallProvider(),
- // ),
+ ChangeNotifierProvider(
+ create: (_) => ChatCallProvider(),
+ ),
],
child: const MyApp(),
),
diff --git a/lib/models/chat/call.dart b/lib/models/chat/call.dart
index ce58ae3..7deaccb 100644
--- a/lib/models/chat/call.dart
+++ b/lib/models/chat/call.dart
@@ -7,19 +7,31 @@ import 'dart:convert';
class CallDataModel {
CallDataModel({
this.callerId,
- this.callerDetails,
+ this.callerName,
+ this.callerEmail,
+ this.callerTitle,
+ this.callerPhone,
this.receiverId,
- this.receiverDetails,
+ this.receiverName,
+ this.receiverEmail,
+ this.receiverTitle,
+ this.receiverPhone,
this.title,
- this.calltype,
+ this.callType,
});
- String? callerId;
- CallerDetails? callerDetails;
- String? receiverId;
- ReceiverDetails? receiverDetails;
- dynamic title;
- String? calltype;
+ int? callerId;
+ String? callerName;
+ String? callerEmail;
+ String? callerTitle;
+ dynamic callerPhone;
+ int? receiverId;
+ String? receiverName;
+ String? receiverEmail;
+ dynamic receiverTitle;
+ dynamic receiverPhone;
+ String? title;
+ String? callType;
factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str));
@@ -27,171 +39,135 @@ class CallDataModel {
factory CallDataModel.fromJson(Map json) => CallDataModel(
callerId: json["callerID"],
- callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]),
+ callerName: json["callerName"],
+ callerEmail: json["callerEmail"],
+ callerTitle: json["callerTitle"],
+ callerPhone: json["callerPhone"],
receiverId: json["receiverID"],
- receiverDetails: json["receiverDetails"] == null ? null : ReceiverDetails.fromJson(json["receiverDetails"]),
+ receiverName: json["receiverName"],
+ receiverEmail: json["receiverEmail"],
+ receiverTitle: json["receiverTitle"],
+ receiverPhone: json["receiverPhone"],
title: json["title"],
- calltype: json["calltype"],
+ callType: json["callType"],
);
Map toJson() => {
"callerID": callerId,
- "callerDetails": callerDetails?.toJson(),
+ "callerName": callerName,
+ "callerEmail": callerEmail,
+ "callerTitle": callerTitle,
+ "callerPhone": callerPhone,
"receiverID": receiverId,
- "receiverDetails": receiverDetails?.toJson(),
+ "receiverName": receiverName,
+ "receiverEmail": receiverEmail,
+ "receiverTitle": receiverTitle,
+ "receiverPhone": receiverPhone,
"title": title,
- "calltype": calltype,
+ "callType": callType,
};
}
-class CallerDetails {
- CallerDetails({
- this.response,
- this.errorResponses,
+
+
+
+
+// To parse this JSON data, do
+//
+// final callSessionPayLoad = callSessionPayLoadFromJson(jsonString);
+
+
+class CallSessionPayLoad {
+ CallSessionPayLoad({
+ this.target,
+ this.caller,
+ this.sdp,
});
- Response? response;
- dynamic errorResponses;
+ int? target;
+ int? caller;
+ Sdp? sdp;
- factory CallerDetails.fromRawJson(String str) => CallerDetails.fromJson(json.decode(str));
+ factory CallSessionPayLoad.fromRawJson(String str) => CallSessionPayLoad.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
- factory CallerDetails.fromJson(Map json) => CallerDetails(
- response: json["response"] == null ? null : Response.fromJson(json["response"]),
- errorResponses: json["errorResponses"],
+ factory CallSessionPayLoad.fromJson(Map json) => CallSessionPayLoad(
+ target: json["target"],
+ caller: json["caller"],
+ sdp: json["sdp"] == null ? null : Sdp.fromJson(json["sdp"]),
);
Map toJson() => {
- "response": response?.toJson(),
- "errorResponses": errorResponses,
+ "target": target,
+ "caller": caller,
+ "sdp": sdp?.toJson(),
};
}
-class Response {
- Response({
- this.id,
- this.userName,
- this.email,
- this.phone,
- this.title,
- this.token,
- this.isDomainUser,
- this.isActiveCode,
- this.encryptedUserId,
- this.encryptedUserName,
+class Sdp {
+ Sdp({
+ this.type,
+ this.sdp,
});
- int? id;
- String? userName;
- String? email;
- dynamic phone;
- String? title;
- String? token;
- bool? isDomainUser;
- bool? isActiveCode;
- String? encryptedUserId;
- String? encryptedUserName;
+ String? type;
+ String? sdp;
- factory Response.fromRawJson(String str) => Response.fromJson(json.decode(str));
+ factory Sdp.fromRawJson(String str) => Sdp.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
- factory Response.fromJson(Map json) => Response(
- id: json["id"],
- userName: json["userName"],
- email: json["email"],
- phone: json["phone"],
- title: json["title"],
- token: json["token"],
- isDomainUser: json["isDomainUser"],
- isActiveCode: json["isActiveCode"],
- encryptedUserId: json["encryptedUserId"],
- encryptedUserName: json["encryptedUserName"],
+ factory Sdp.fromJson(Map json) => Sdp(
+ type: json["type"],
+ sdp: json["sdp"],
);
Map toJson() => {
- "id": id,
- "userName": userName,
- "email": email,
- "phone": phone,
- "title": title,
- "token": token,
- "isDomainUser": isDomainUser,
- "isActiveCode": isActiveCode,
- "encryptedUserId": encryptedUserId,
- "encryptedUserName": encryptedUserName,
+ "type": type,
+ "sdp": sdp,
};
}
-class ReceiverDetails {
- ReceiverDetails({
- this.id,
- this.userName,
- this.email,
- this.phone,
- this.title,
- this.userStatus,
- this.image,
- this.unreadMessageCount,
- this.userAction,
- this.isPin,
- this.isFav,
- this.isAdmin,
- this.rKey,
- this.totalCount,
+
+
+
+
+// final iosCallPayload = iosCallPayloadFromJson(jsonString);
+
+class IosCallPayload {
+ String? incomingCallType;
+ String? incomingCallerId;
+ String? incomingCallReciverId;
+ String? incomingCallerName;
+ String? callData;
+ String? uuid;
+
+ IosCallPayload({
+ this.incomingCallType,
+ this.incomingCallerId,
+ this.incomingCallReciverId,
+ this.incomingCallerName,
+ this.callData,
+ this.uuid,
});
- int? id;
- String? userName;
- String? email;
- dynamic phone;
- dynamic title;
- int? userStatus;
- String? image;
- int? unreadMessageCount;
- dynamic userAction;
- bool? isPin;
- bool? isFav;
- bool? isAdmin;
- String? rKey;
- int? totalCount;
-
- factory ReceiverDetails.fromRawJson(String str) => ReceiverDetails.fromJson(json.decode(str));
+ factory IosCallPayload.fromRawJson(String str) => IosCallPayload.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
- factory ReceiverDetails.fromJson(Map json) => ReceiverDetails(
- id: json["id"],
- userName: json["userName"],
- email: json["email"],
- phone: json["phone"],
- title: json["title"],
- userStatus: json["userStatus"],
- image: json["image"],
- unreadMessageCount: json["unreadMessageCount"],
- userAction: json["userAction"],
- isPin: json["isPin"],
- isFav: json["isFav"],
- isAdmin: json["isAdmin"],
- rKey: json["rKey"],
- totalCount: json["totalCount"],
+ factory IosCallPayload.fromJson(Map json) => IosCallPayload(
+ incomingCallType: json["incoming_call_type"],
+ incomingCallerId: json["incoming_caller_id"],
+ incomingCallerName: json["incoming_caller_name"],
+ incomingCallReciverId: null,
+ uuid: json["uuid"],
);
Map toJson() => {
- "id": id,
- "userName": userName,
- "email": email,
- "phone": phone,
- "title": title,
- "userStatus": userStatus,
- "image": image,
- "unreadMessageCount": unreadMessageCount,
- "userAction": userAction,
- "isPin": isPin,
- "isFav": isFav,
- "isAdmin": isAdmin,
- "rKey": rKey,
- "totalCount": totalCount,
+ "incoming_call_type": incomingCallType,
+ "incoming_caller_id": incomingCallerId,
+ "incoming_caller_name": incomingCallerName,
+ "uuid": uuid,
};
}
diff --git a/lib/models/chat/incoming_call_model.dart b/lib/models/chat/incoming_call_model.dart
new file mode 100644
index 0000000..9494505
--- /dev/null
+++ b/lib/models/chat/incoming_call_model.dart
@@ -0,0 +1,333 @@
+// To parse this JSON data, do
+//
+// final incomingCallModel = incomingCallModelFromJson(jsonString);
+
+import 'dart:convert';
+
+class IncomingCallModel {
+ String? actionColor;
+ String? appName;
+ Args? args;
+ String? avatar;
+ String? backgroundColor;
+ String? backgroundUrl;
+ int? duration;
+ Extra? extra;
+ String? from;
+ String? handle;
+ Args? headers;
+ String? id;
+ bool? isAccepted;
+ bool? isCustomNotification;
+ bool? isCustomSmallExNotification;
+ bool? isShowCallback;
+ bool? isShowLogo;
+ bool? isShowMissedCallNotification;
+ String? nameCaller;
+ String? ringtonePath;
+ String? textAccept;
+ String? textCallback;
+ String? textDecline;
+ String? textMissedCall;
+ int? type;
+ String? uuid;
+
+ IncomingCallModel({
+ this.actionColor,
+ this.appName,
+ this.args,
+ this.avatar,
+ this.backgroundColor,
+ this.backgroundUrl,
+ this.duration,
+ this.extra,
+ this.from,
+ this.handle,
+ this.headers,
+ this.id,
+ this.isAccepted,
+ this.isCustomNotification,
+ this.isCustomSmallExNotification,
+ this.isShowCallback,
+ this.isShowLogo,
+ this.isShowMissedCallNotification,
+ this.nameCaller,
+ this.ringtonePath,
+ this.textAccept,
+ this.textCallback,
+ this.textDecline,
+ this.textMissedCall,
+ this.type,
+ this.uuid,
+ });
+
+ factory IncomingCallModel.fromRawJson(String str) => IncomingCallModel.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory IncomingCallModel.fromJson(Map json) => IncomingCallModel(
+ actionColor: json["actionColor"],
+ appName: json["appName"],
+ args: json["args"] == null ? null : Args.fromJson(json["args"]),
+ avatar: json["avatar"],
+ backgroundColor: json["backgroundColor"],
+ backgroundUrl: json["backgroundUrl"],
+ duration: json["duration"] == null ? null : json["duration"].toInt(),
+ extra: json["extra"] == null ? null : Extra.fromJson(json["extra"]),
+ from: json["from"],
+ handle: json["handle"],
+ headers: json["headers"] == null ? null : Args.fromJson(json["headers"]),
+ id: json["id"],
+ isAccepted: json["isAccepted"],
+ isCustomNotification: json["isCustomNotification"],
+ isCustomSmallExNotification: json["isCustomSmallExNotification"],
+ isShowCallback: json["isShowCallback"],
+ isShowLogo: json["isShowLogo"],
+ isShowMissedCallNotification: json["isShowMissedCallNotification"],
+ nameCaller: json["nameCaller"],
+ ringtonePath: json["ringtonePath"],
+ textAccept: json["textAccept"],
+ textCallback: json["textCallback"],
+ textDecline: json["textDecline"],
+ textMissedCall: json["textMissedCall"],
+ type: json["type"] == null ? null : json["type"].toInt(),
+ uuid: json["uuid"],
+ );
+
+ Map toJson() => {
+ "actionColor": actionColor,
+ "appName": appName,
+ "args": args?.toJson(),
+ "avatar": avatar,
+ "backgroundColor": backgroundColor,
+ "backgroundUrl": backgroundUrl,
+ "duration": duration,
+ "extra": extra?.toJson(),
+ "from": from,
+ "handle": handle,
+ "headers": headers?.toJson(),
+ "id": id,
+ "isAccepted": isAccepted,
+ "isCustomNotification": isCustomNotification,
+ "isCustomSmallExNotification": isCustomSmallExNotification,
+ "isShowCallback": isShowCallback,
+ "isShowLogo": isShowLogo,
+ "isShowMissedCallNotification": isShowMissedCallNotification,
+ "nameCaller": nameCaller,
+ "ringtonePath": ringtonePath,
+ "textAccept": textAccept,
+ "textCallback": textCallback,
+ "textDecline": textDecline,
+ "textMissedCall": textMissedCall,
+ "type": type,
+ "uuid": uuid,
+ };
+}
+
+class Args {
+ Args();
+
+ factory Args.fromRawJson(String str) => Args.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory Args.fromJson(Map json) => Args();
+
+ Map toJson() => {};
+}
+
+class Extra {
+ LoginDetails? loginDetails;
+ bool? isIncomingCall;
+ CallerDetails? callerDetails;
+ String? callType;
+
+ Extra({
+ this.loginDetails,
+ this.isIncomingCall,
+ this.callerDetails,
+ this.callType,
+ });
+
+ factory Extra.fromRawJson(String str) => Extra.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory Extra.fromJson(Map json) => Extra(
+ loginDetails: json["loginDetails"] == null ? null : LoginDetails.fromJson(json["loginDetails"]),
+ isIncomingCall: json["isIncomingCall"],
+ callType: json["callType"],
+ callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]),
+ );
+
+ Map toJson() => {
+ "loginDetails": loginDetails?.toJson(),
+ "isIncomingCall": isIncomingCall,
+ "callType": callType,
+ "callerDetails": callerDetails?.toJson(),
+ };
+}
+
+class CallerDetails {
+ int? userChatHistoryId;
+ String? contant;
+ FileTypeResponse? fileTypeResponse;
+ String? currentUserName;
+ String? targetUserEmail;
+ String? conversationId;
+ String? encryptedTargetUserId;
+ int? targetUserId;
+ bool? isSeen;
+ int? userChatHistoryLineId;
+ bool? isDelivered;
+ String? targetUserName;
+ int? currentUserId;
+ DateTime? createdDate;
+ String? currentUserEmail;
+ String? contantNo;
+ int? chatEventId;
+ String? encryptedTargetUserName;
+ int? chatSource;
+
+ CallerDetails({
+ this.userChatHistoryId,
+ this.contant,
+ this.fileTypeResponse,
+ this.currentUserName,
+ this.targetUserEmail,
+ this.conversationId,
+ this.encryptedTargetUserId,
+ this.targetUserId,
+ this.isSeen,
+ this.userChatHistoryLineId,
+ this.isDelivered,
+ this.targetUserName,
+ this.currentUserId,
+ this.createdDate,
+ this.currentUserEmail,
+ this.contantNo,
+ this.chatEventId,
+ this.encryptedTargetUserName,
+ this.chatSource,
+ });
+
+ factory CallerDetails.fromRawJson(String str) => CallerDetails.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory CallerDetails.fromJson(Map json) => CallerDetails(
+ userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"].toInt(),
+ contant: json["contant"],
+ fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]),
+ currentUserName: json["currentUserName"],
+ targetUserEmail: json["targetUserEmail"],
+ conversationId: json["conversationId"],
+ encryptedTargetUserId: json["encryptedTargetUserId"],
+ targetUserId: json["targetUserId"] == null ? null : json["targetUserId"].toInt(),
+ isSeen: json["isSeen"],
+ userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"].toInt(),
+ isDelivered: json["isDelivered"],
+ targetUserName: json["targetUserName"],
+ currentUserId: json["currentUserId"] == null ? null : json["currentUserId"].toInt(),
+ createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]),
+ currentUserEmail: json["currentUserEmail"],
+ contantNo: json["contantNo"],
+ chatEventId: json["chatEventId"] == null ? null : json["chatEventId"].toInt(),
+ encryptedTargetUserName: json["encryptedTargetUserName"],
+ chatSource: json["chatSource"] == null ? null : json["chatSource"].toInt(),
+ );
+
+ Map toJson() => {
+ "userChatHistoryId": userChatHistoryId,
+ "contant": contant,
+ "fileTypeResponse": fileTypeResponse?.toJson(),
+ "currentUserName": currentUserName,
+ "targetUserEmail": targetUserEmail,
+ "conversationId": conversationId,
+ "encryptedTargetUserId": encryptedTargetUserId,
+ "targetUserId": targetUserId,
+ "isSeen": isSeen,
+ "userChatHistoryLineId": userChatHistoryLineId,
+ "isDelivered": isDelivered,
+ "targetUserName": targetUserName,
+ "currentUserId": currentUserId,
+ "createdDate": createdDate?.toIso8601String(),
+ "currentUserEmail": currentUserEmail,
+ "contantNo": contantNo,
+ "chatEventId": chatEventId,
+ "encryptedTargetUserName": encryptedTargetUserName,
+ "chatSource": chatSource,
+ };
+}
+
+class FileTypeResponse {
+ int? fileTypeId;
+
+ FileTypeResponse({
+ this.fileTypeId,
+ });
+
+ factory FileTypeResponse.fromRawJson(String str) => FileTypeResponse.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory FileTypeResponse.fromJson(Map json) => FileTypeResponse(
+ fileTypeId: json["fileTypeId"].toInt(),
+ );
+
+ Map toJson() => {
+ "fileTypeId": fileTypeId,
+ };
+}
+
+class LoginDetails {
+ bool? isActiveCode;
+ int? id;
+ String? encryptedUserName;
+ String? userName;
+ String? title;
+ String? encryptedUserId;
+ String? email;
+ bool? isDomainUser;
+ String? token;
+
+ LoginDetails({
+ this.isActiveCode,
+ this.id,
+ this.encryptedUserName,
+ this.userName,
+ this.title,
+ this.encryptedUserId,
+ this.email,
+ this.isDomainUser,
+ this.token,
+ });
+
+ factory LoginDetails.fromRawJson(String str) => LoginDetails.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory LoginDetails.fromJson(Map json) => LoginDetails(
+ isActiveCode: json["isActiveCode"],
+ id: json["id"] == null ? null : json["id"].toInt(),
+ encryptedUserName: json["encryptedUserName"],
+ userName: json["userName"],
+ title: json["title"],
+ encryptedUserId: json["encryptedUserId"],
+ email: json["email"],
+ isDomainUser: json["isDomainUser"],
+ token: json["token"],
+ );
+
+ Map toJson() => {
+ "isActiveCode": isActiveCode,
+ "id": id,
+ "encryptedUserName": encryptedUserName,
+ "userName": userName,
+ "title": title,
+ "encryptedUserId": encryptedUserId,
+ "email": email,
+ "isDomainUser": isDomainUser,
+ "token": token,
+ };
+}
diff --git a/lib/models/chat/webrtc_payloads.dart b/lib/models/chat/webrtc_payloads.dart
new file mode 100644
index 0000000..1a3463f
--- /dev/null
+++ b/lib/models/chat/webrtc_payloads.dart
@@ -0,0 +1,61 @@
+// To parse this JSON data, do
+//
+// final remoteIceCandidatePayLoad = remoteIceCandidatePayLoadFromJson(jsonString);
+
+import 'dart:convert';
+
+class RemoteIceCandidatePayLoad {
+ RemoteIceCandidatePayLoad({
+ this.target,
+ this.candidate,
+ });
+
+ int? target;
+ Candidate? candidate;
+
+ factory RemoteIceCandidatePayLoad.fromRawJson(String str) => RemoteIceCandidatePayLoad.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory RemoteIceCandidatePayLoad.fromJson(Map json) => RemoteIceCandidatePayLoad(
+ target: json["target"],
+ candidate: json["candidate"] == null ? null : Candidate.fromJson(json["candidate"]),
+ );
+
+ Map toJson() => {
+ "target": target,
+ "candidate": candidate?.toJson(),
+ };
+}
+
+class Candidate {
+ Candidate({
+ this.candidate,
+ this.sdpMid,
+ this.sdpMLineIndex,
+ this.usernameFragment,
+ });
+
+ String? candidate;
+ String? sdpMid;
+ int? sdpMLineIndex;
+ String? usernameFragment;
+
+ factory Candidate.fromRawJson(String str) => Candidate.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory Candidate.fromJson(Map json) => Candidate(
+ candidate: json["candidate"],
+ sdpMid: json["sdpMid"],
+ sdpMLineIndex: json["sdpMLineIndex"],
+ usernameFragment: json["usernameFragment"],
+ );
+
+ Map toJson() => {
+ "candidate": candidate,
+ "sdpMid": sdpMid,
+ "sdpMLineIndex": sdpMLineIndex,
+ "usernameFragment": usernameFragment,
+ };
+}
diff --git a/lib/provider/chat_call_provider.dart b/lib/provider/chat_call_provider.dart
index 45205df..0bfa728 100644
--- a/lib/provider/chat_call_provider.dart
+++ b/lib/provider/chat_call_provider.dart
@@ -1,52 +1,71 @@
import 'dart:convert';
-import 'dart:ui';
+import 'dart:io';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
+import 'package:just_audio/just_audio.dart';
+import 'package: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/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/landing/dashboard_screen.dart';
+import 'package:signalr_netcore/hub_connection.dart';
class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
///////////////////// Web RTC Video Calling //////////////////////
// Video Call
- late RTCPeerConnection _peerConnection;
- RTCVideoRenderer _localVideoRenderer = RTCVideoRenderer();
- final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
+ late RTCPeerConnection _pc;
+ late ChatProviderModel chatProvModel;
+ RTCVideoRenderer? localVideoRenderer;
+ RTCVideoRenderer? remoteRenderer;
+ final AudioPlayer player = AudioPlayer();
MediaStream? _localStream;
- MediaStream? _remoteStream;
+ late CallDataModel outGoingCallData;
+ bool isMicOff = false;
+ bool isLoudSpeaker = false;
+ bool isCamOff = false;
+ bool isCallEnded = false;
+ bool isVideoCall = false;
+ bool isAudioCall = false;
+ bool isCallStarted = false;
+ bool isFrontCamera = true;
+ late SingleUserChatModel incomingCallData;
- void initCallListeners() {
+ /// WebRTC Connection Variables
+ bool isIncomingCallLoader = true;
+ bool isIncomingCall = false;
+ bool isOutGoingCall = false;
+ bool isUserOnline = false;
+
+ late BuildContext providerContext;
+
+ List devices = [];
+ var _videoDeviceId;
+
+ void initCallListeners({required BuildContext context}) {
+ providerContext = context;
+ if (kDebugMode) {
+ print("=================== Call Listeners Registered =======================");
+ }
chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection.on("OnOfferAsync", onOfferAsync);
chatHubConnection.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection.on("OnHangUpAsync", onHangUpAsync);
chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync);
+ // chatHubConnection.on("OnIncomingCallAsync", OnIncomingCallAsync);
}
- //Video Constraints
- var videoConstraints = {
- "video": {
- "mandatory": {
- "width": {"min": 320},
- "height": {"min": 180}
- },
- "optional": [
- {
- "width": {"max": 1280}
- },
- {"frameRate": 25},
- {"facingMode": "user"}
- ]
- },
- "frameRate": 25,
- "width": 420, //420,//640,//1280,
- "height": 240 //240//480//720
- };
-
// Audio Constraints
- var audioConstraints = {
+ Map audioConstraints = {
"sampleRate": 8000,
"sampleSize": 16,
"channelCount": 2,
@@ -54,128 +73,322 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
"audio": true,
};
- Future _createPeerConnection() async {
- // {"url": "stun:stun.l.google.com:19302"},
- Map configuration = {
- "iceServers": [
- {"urls": 'stun:15.185.116.59:3478'},
- {"urls": "turn:15.185.116.59:3479", "username": "admin", "credential": "admin"}
- ]
- };
+ Future init() async {
+ _pc = await creatOfferWithCon();
+ Future.delayed(const Duration(seconds: 2), () {
+ connectIncomingCall();
+ });
+ }
- Map offerSdpConstraints = {
- "mandatory": {
- "OfferToReceiveAudio": true,
- "OfferToReceiveVideo": true,
- },
- "optional": [],
- };
+ ///////////////////////////////////////////////OutGoing Call////////////////////////////////////////////////////
- RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
- // if (pc != null) print(pc);
- //pc.addStream(widget.localStream);
+ Future initLocalCamera({required ChatProviderModel chatProvmodel, required callData, required BuildContext context, bool isIncomingCall = false}) async {
+ isCallEnded = false;
+ chatProvModel = chatProvmodel;
+ outGoingCallData = callData;
+ await initStreams();
+ await startCall(callType: isVideoCall ? "Video" : "Audio", context: context);
+ _pc = await creatOfferWithCon();
+ connectOutgoing();
+ notifyListeners();
+ }
- pc.onIceCandidate = (e) {
- if (e.candidate != null) {
- print(json.encode({
- 'candidate': e.candidate.toString(),
- 'sdpMid': e.sdpMid.toString(),
- 'sdpMlineIndex': e.sdpMLineIndex,
- }));
- }
- };
- pc.onIceConnectionState = (e) {
- print(e);
- };
- pc.onAddStream = (stream) {
- print('addStream: ' + stream.id);
- _remoteRenderer.srcObject = stream;
- };
- return pc;
+ void connectOutgoing() {
+ isOutGoingCall = true;
+ notifyListeners();
}
- void init() {
- initRenderers();
- _createPeerConnection().then((pc) {
- _peerConnection = pc;
- // _setRemoteDescription(widget.info);
- });
+ Future startCall({required String callType, required BuildContext context}) async {
+ chatProvModel.isTextMsg = true;
+ chatProvModel.isAttachmentMsg = false;
+ chatProvModel.isVoiceMsg = false;
+ chatProvModel.isReplyMsg = false;
+ chatProvModel.isCall = true;
+ chatProvModel.message.text = "Start $callType call ${outGoingCallData.receiverName.toString().replaceAll(".", " ")}";
+ chatProvModel.sendChatMessage(
+ context,
+ targetUserId: outGoingCallData.receiverId!,
+ userStatus: 1,
+ userEmail: outGoingCallData.receiverEmail!,
+ targetUserName: outGoingCallData.receiverName!,
+ );
+ await invoke(
+ invokeMethod: "CallUserAsync",
+ currentUserID: outGoingCallData.callerId!,
+ targetUserID: outGoingCallData.receiverId!,
+ );
+ await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 4);
}
- void initRenderers() {
- _localVideoRenderer.initialize();
- _remoteRenderer.initialize();
- initLocalCamera();
+ // OutGoing Listeners
+ void onCallAcceptedAsync(List