diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 15b0c54..d092ef9 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -19,6 +19,8 @@
+
+
diff --git a/android/app/src/main/kotlin/com/mohem_flutter_app/CallDecline.kt b/android/app/src/main/kotlin/com/mohem_flutter_app/CallDecline.kt
new file mode 100644
index 0000000..73df479
--- /dev/null
+++ b/android/app/src/main/kotlin/com/mohem_flutter_app/CallDecline.kt
@@ -0,0 +1,318 @@
+//package com.mohem_flutter_app
+//import kotlinx.coroutines.Dispatchers
+//import kotlinx.coroutines.GlobalScope
+//import kotlinx.coroutines.launch
+//import okhttp3.*
+//import okhttp3.MediaType.Companion.toMediaType
+//import okhttp3.RequestBody.Companion.toRequestBody
+//import java.io.IOException
+//
+//class NativeIncomingCallDecline {
+// fun declineCall(currentUserID: String, targetUserID: String, 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).enqueue(object : Callback {
+// override fun onResponse(call: Call, response: 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")
+// }
+// }
+//
+// override fun onFailure(call: Call, e: IOException) {
+// println("API Request Failed. Exception: ${e.message}")
+// }
+// })
+// }
+// }
+//}
+//
+
+
+
+//This code is included into CallkitIncomingBroadcastReceiver.kt file under Flutter_callKit_incoming Package
+//Below is the Whole Code
+
+// Implemented Libraries into Kotlin
+// implementation 'com.squareup.okhttp3:okhttp:4.9.1'
+// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0'
+
+//package com.hiennv.flutter_callkit_incoming
+//import android.annotation.SuppressLint
+//import android.content.BroadcastReceiver
+//import android.content.Context
+//import android.content.Intent
+//import android.os.Build
+//import android.os.Bundle
+//import android.util.Log
+////http
+//import okhttp3.MediaType.Companion.toMediaType
+//import okhttp3.OkHttpClient
+//import okhttp3.Request
+//import okhttp3.RequestBody.Companion.toRequestBody
+//
+//// Async
+//import kotlinx.coroutines.Dispatchers
+//import kotlinx.coroutines.GlobalScope
+//import kotlinx.coroutines.launch
+//
+//class CallkitIncomingBroadcastReceiver : BroadcastReceiver() {
+//
+// companion object {
+// private const val TAG = "CallkitIncomingReceiver"
+//
+// fun getIntent(context: Context, action: String, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// this.action = "${context.packageName}.${action}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentIncoming(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_INCOMING}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentStart(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_START}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentAccept(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_ACCEPT}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentDecline(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_DECLINE}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentEnded(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_ENDED}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentTimeout(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_TIMEOUT}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+//
+// fun getIntentCallback(context: Context, data: Bundle?) =
+// Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
+// action = "${context.packageName}.${CallkitConstants.ACTION_CALL_CALLBACK}"
+// putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
+// }
+// }
+//
+//
+// @SuppressLint("MissingPermission")
+// override fun onReceive(context: Context, intent: Intent) {
+// val callkitNotificationManager = CallkitNotificationManager(context)
+// val action = intent.action ?: return
+// val data = intent.extras?.getBundle(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA) ?: return
+//
+// when (action) {
+// "${context.packageName}.${CallkitConstants.ACTION_CALL_INCOMING}" -> {
+// 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/app/src/main/kotlin/com/mohem_flutter_app/VoIPCenter.swift b/android/app/src/main/kotlin/com/mohem_flutter_app/VoIPCenter.swift
new file mode 100644
index 0000000..8f0ca9b
--- /dev/null
+++ b/android/app/src/main/kotlin/com/mohem_flutter_app/VoIPCenter.swift
@@ -0,0 +1,420 @@
+// VoIPCenter.swift
+//
+//
+// //
+// // VoIPCenter.swift
+// // flutter_ios_voip_kit
+// //
+// // Created by ้ ่คๅฐๅฒ on 2020/07/02.
+// //
+//
+// import Foundation
+// import Flutter
+// import PushKit
+// import CallKit
+// import AVFoundation
+//
+// extension String {
+// internal init(deviceToken: Data) {
+// self = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
+// }
+// }
+//
+// class VoIPCenter: NSObject, URLSessionDelegate {
+//
+//
+//
+//
+// // MARK: - event channel
+//
+// private let eventChannel: FlutterEventChannel
+// private var eventSink: FlutterEventSink?
+//
+// private enum EventChannel: String {
+// case onDidReceiveIncomingPush
+// case onDidAcceptIncomingCall
+// case onDidRejectIncomingCall
+//
+// case onDidUpdatePushToken
+// case onDidActivateAudioSession
+// case onDidDeactivateAudioSession
+// }
+//
+// // MARK: - PushKit
+//
+// private let didUpdateTokenKey = "Did_Update_VoIP_Device_Token"
+// private let pushRegistry: PKPushRegistry
+//
+// var token: String? {
+// if let didUpdateDeviceToken = UserDefaults.standard.data(forKey: didUpdateTokenKey) {
+// let token = String(deviceToken: didUpdateDeviceToken)
+// print("๐ VoIP didUpdateDeviceToken: \(token)")
+// return token
+// }
+//
+// guard let cacheDeviceToken = self.pushRegistry.pushToken(for: .voIP) else {
+// return nil
+// }
+//
+// let token = String(deviceToken: cacheDeviceToken)
+// print("๐ VoIP cacheDeviceToken: \(token)")
+// return token
+// }
+//
+// // MARK: - CallKit
+//
+// let callKitCenter: CallKitCenter
+//
+// fileprivate var audioSessionMode: AVAudioSession.Mode
+// fileprivate let ioBufferDuration: TimeInterval
+// fileprivate let audioSampleRate: Double
+//
+// init(eventChannel: FlutterEventChannel) {
+// self.eventChannel = eventChannel
+// self.pushRegistry = PKPushRegistry(queue: .main)
+// self.pushRegistry.desiredPushTypes = [.voIP]
+// self.callKitCenter = CallKitCenter()
+//
+// if let path = Bundle.main.path(forResource: "Info", ofType: "plist"), let plist = NSDictionary(contentsOfFile: path) {
+// self.audioSessionMode = ((plist["FIVKAudioSessionMode"] as? String) ?? "audio") == "video" ? .videoChat : .voiceChat
+// self.ioBufferDuration = plist["FIVKIOBufferDuration"] as? TimeInterval ?? 0.005
+// self.audioSampleRate = plist["FIVKAudioSampleRate"] as? Double ?? 44100.0
+// } else {
+// self.audioSessionMode = .voiceChat
+// self.ioBufferDuration = TimeInterval(0.005)
+// self.audioSampleRate = 44100.0
+// }
+//
+// super.init()
+// self.eventChannel.setStreamHandler(self)
+// self.pushRegistry.delegate = self
+// self.callKitCenter.setup(delegate: self)
+// }
+// }
+//
+// extension VoIPCenter: PKPushRegistryDelegate {
+//
+// // MARK: - PKPushRegistryDelegate
+//
+// public func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
+// print("๐ VoIP didUpdate pushCredentials")
+// UserDefaults.standard.set(pushCredentials.token, forKey: didUpdateTokenKey)
+//
+// self.eventSink?(["event": EventChannel.onDidUpdatePushToken.rawValue,
+// "token": pushCredentials.token.hexString])
+// }
+//
+// // NOTE: iOS11 or more support
+//
+// public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
+// print("๐ VoIP didRecyeiveIncomingPushWith completion: \(payload.dictionaryPayload)")
+//
+// let info = self.parse(payload: payload)
+// let callerName = info?["incoming_caller_name"] as! String
+// self.callKitCenter.incomingCall(uuidString: info?["uuid"] as! String,
+// callerId: info?["incoming_caller_id"] as! String,
+// callerName: callerName) { error in
+// if let error = error {
+// print("โ reportNewIncomingCall error: \(error.localizedDescription)")
+// return
+// }
+// self.eventSink?(["event": EventChannel.onDidReceiveIncomingPush.rawValue,
+// "payload": info as Any,
+// "incoming_caller_name": callerName])
+// completion()
+// }
+// }
+//
+// // NOTE: iOS10 support
+//
+// public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
+// print("๐ VoIP didReceiveIncomingPushWith: \(payload.dictionaryPayload)")
+//
+//
+// let info = self.parse(payload: payload)
+// let callerName = info?["incoming_caller_name"] as! String
+// self.callKitCenter.incomingCall(uuidString: info?["uuid"] as! String,
+// callerId: info?["incoming_caller_id"] as! String,
+// callerName: callerName) { error in
+// if let error = error {
+// print("โ reportNewIncomingCall error: \(error.localizedDescription)")
+// return
+// }
+// self.eventSink?(["event": EventChannel.onDidReceiveIncomingPush.rawValue,
+// "payload": info as Any,
+// "incoming_caller_name": callerName])
+// }
+// }
+//
+// private func parse(payload: PKPushPayload) -> [String: Any]? {
+// do {
+// let data = try JSONSerialization.data(withJSONObject: payload.dictionaryPayload, options: .prettyPrinted)
+// let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
+//
+// if let aps = json?["aps"] as? [String: Any] {
+// if let alertString = aps["alert"] as? String {
+// let alertData = alertString.data(using: .utf8)
+// let alertJson = try JSONSerialization.jsonObject(with: alertData!, options: []) as? [String: Any]
+// return alertJson
+// } else if let alertDictionary = aps["alert"] as? [String: Any] {
+// return alertDictionary
+// }
+// }
+//
+// return nil
+// } catch let error as NSError {
+// print("โ VoIP parsePayload: \(error.localizedDescription)")
+// return nil
+// }
+// }
+//
+//
+//
+// // private func parse(payload: PKPushPayload) -> [String: Any]? {
+// // do {
+// // let data = try JSONSerialization.data(withJSONObject: payload.dictionaryPayload, options: .prettyPrinted)
+// // let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
+// // let aps = json?["aps"] as? [String: Any]
+// // return aps?["alert"] as? [String: Any]
+// // } catch let error as NSError {
+// // print("โ VoIP parsePayload: \(error.localizedDescription)")
+// // return nil
+// // }
+// // }
+//
+//
+// }
+//
+// extension VoIPCenter: CXProviderDelegate , APIDelegate {
+// func didReceiveAPIResponse(data: Data?) {
+// print("didReceiveAPIResponse")
+// }
+//
+// func didFailAPIRequest(error: Error) {
+// print("didFailAPIRequest")
+// }
+//
+//
+// // MARK: - CXProviderDelegate
+//
+// public func providerDidReset(_ provider: CXProvider) {
+// print("๐ซ VoIP providerDidReset")
+// }
+//
+// public func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
+// print("๐ค VoIP CXStartCallAction")
+// self.callKitCenter.connectingOutgoingCall()
+// action.fulfill()
+// }
+//
+// public func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
+// print("โ
VoIP CXAnswerCallAction")
+// self.callKitCenter.answerCallAction = action
+// self.configureAudioSession()
+// self.eventSink?(["event": EventChannel.onDidAcceptIncomingCall.rawValue,
+// "uuid": self.callKitCenter.uuidString as Any,
+// "incoming_caller_id": self.callKitCenter.incomingCallerId as Any])
+// }
+//
+// public func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
+// print("โ VoIP CXEndCallAction")
+// if (self.callKitCenter.isCalleeBeforeAcceptIncomingCall) {
+// self.eventSink?(["event": EventChannel.onDidRejectIncomingCall.rawValue,
+// "uuid": self.callKitCenter.uuidString as Any,
+// "incoming_caller_id": self.callKitCenter.incomingCallerId as Any])
+// if let callerId = self.callKitCenter.incomingCallerId {
+// let components = callerId.components(separatedBy: "-")
+// if components.count == 3 {
+// let targetUserID = components[0]
+// let currentUserID = components[1]
+// print("โ VoIP CXEndCallBeforeApi")
+// APIClient.shared.postRequest(delegate: self, currentUserID: currentUserID,targetUserID:targetUserID)
+// self.callKitCenter.disconnected(reason: .remoteEnded)
+// action.fulfill()
+// print("โ VoIP CXEndCallAfterApi")
+// } else {
+// print("Invalid input string format")
+// }
+// } else {
+// print("incomingCallerId is not a String")
+// }
+// }
+//
+// }
+//
+//
+//
+// public func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
+// print("๐ VoIP didActivate audioSession")
+// self.eventSink?(["event": EventChannel.onDidActivateAudioSession.rawValue])
+// }
+//
+// public func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
+// print("๐ VoIP didDeactivate audioSession")
+// self.eventSink?(["event": EventChannel.onDidDeactivateAudioSession.rawValue])
+// }
+//
+// // This is a workaround for known issue, when audio doesn't start from lockscreen call
+// // https://stackoverflow.com/questions/55391026/no-sound-after-connecting-to-webrtc-when-app-is-launched-in-background-using-pus
+// private func configureAudioSession() {
+// let sharedSession = AVAudioSession.sharedInstance()
+// do {
+// try sharedSession.setCategory(.playAndRecord,
+// options: [AVAudioSession.CategoryOptions.allowBluetooth,
+// AVAudioSession.CategoryOptions.defaultToSpeaker])
+// try sharedSession.setMode(audioSessionMode)
+// try sharedSession.setPreferredIOBufferDuration(ioBufferDuration)
+// try sharedSession.setPreferredSampleRate(audioSampleRate)
+// } catch {
+// print("โ VoIP Failed to configure `AVAudioSession`")
+// }
+// }
+// }
+//
+// // Aamir Work
+//
+// protocol APIDelegate: AnyObject {
+// func didReceiveAPIResponse(data: Data?)
+// func didFailAPIRequest(error: Error)
+// }
+//
+//
+// class APIClient {
+// static let shared = APIClient()
+//
+// func postRequest(delegate: APIDelegate, currentUserID: String, targetUserID: String) {
+// DispatchQueue.global(qos: .background).async {
+// self.getApiToken(currentUserID: currentUserID) { data, error in
+// if let error = error {
+// print("Error: \(error.localizedDescription)")
+// } else if let data = data {
+// do{
+// let sem = DispatchSemaphore(value: 0)
+// do {
+// let json = try JSONSerialization.jsonObject(with: data, options: [])
+// guard let dictionary = json as? [String: Any] else {
+// print("Error parsing JSON")
+// return
+// }
+// guard let responseDictionary = dictionary["response"] as? [String: Any] else {
+// print("Error parsing response")
+// return
+// }
+//
+// guard let token = responseDictionary["token"] as? String else {
+// print("Error getting token")
+// return
+// }
+// print("OneSignal User Token After Login JSON: \(token)")
+//
+// self.makeEndCallRequest(currentUserID: currentUserID, targetUserID: targetUserID, token: token) { data, error in
+// if let error = error {
+// print("Error: \(error.localizedDescription)")
+// } else if let data = data {
+// sem.signal()
+// _ = String(data: data, encoding: .utf8)
+// print("Call Ended Successfully")
+// }
+// }
+// }
+// sem.wait()
+// }catch{
+// print("Error parsing JSON: \(error)")
+// }
+// }
+//
+// }
+// }
+//
+// }
+//
+// private func getApiToken(currentUserID: String, completion: @escaping (Data?, Error?) -> Void) {
+// let parameters = """
+// {
+// "employeeNumber": "\(currentUserID)",
+// "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG"
+// }
+// """
+// let postData = parameters.data(using: .utf8)
+// var request = URLRequest(url: URL(string: "https://apiderichat.hmg.com/api/user/`externaluserlogin")!,
+// timeoutInterval: Double.infinity)
+// request.addValue("application/json", forHTTPHeaderField: "Content-Type")
+// request.httpMethod = "POST"
+// request.httpBody = postData
+// let task = URLSession.shared.dataTask(with: request) { data, response, error in
+// if let error = error {
+// completion(nil, error)
+// return
+// }
+// guard let httpResponse = response as? HTTPURLResponse else {
+// let error = NSError(domain: "InvalidResponse", code: 0, userInfo: nil)
+// completion(nil, error)
+// return
+// }
+// guard (200...299).contains(httpResponse.statusCode) else {
+// let error = NSError(domain: "HTTPError", code: httpResponse.statusCode, userInfo: nil)
+// completion(nil, error)
+// return
+// }
+// completion(data, nil)
+// }
+//
+// task.resume()
+// }
+//
+//
+// private func makeEndCallRequest(currentUserID: String, targetUserID: String, token: String, completion: @escaping (Data?, Error?) -> Void) {
+// let parameters = """
+// {
+// "currentUserId": \(currentUserID),
+// "targetUserId": \(targetUserID),
+// "secretKey": "derichatmobileuser",
+// "targetUserToken": "\(token)"
+// }
+// """
+// print("OneSignal Params: \(parameters)")
+// let postData = parameters.data(using: .utf8)
+// var request = URLRequest(url: URL(string: "https://apiderichat.hmg.com/api/user/calldecline")!,
+// timeoutInterval: Double.infinity)
+// request.addValue("application/json", forHTTPHeaderField: "Content-Type")
+// request.httpMethod = "POST"
+// request.httpBody = postData
+// let task = URLSession.shared.dataTask(with: request) { data, response, error in
+// if let error = error {
+// completion(nil, error)
+// return
+// }
+// guard let httpResponse = response as? HTTPURLResponse else {
+// let error = NSError(domain: "InvalidResponse", code: 0, userInfo: nil)
+// completion(nil, error)
+// return
+// }
+// guard (200...299).contains(httpResponse.statusCode) else {
+// let error = NSError(domain: "HTTPError", code: httpResponse.statusCode, userInfo: nil)
+// completion(nil, error)
+// return
+// }
+// completion(data, nil)
+// }
+//
+// task.resume()
+// }
+//
+// }
+//
+//
+// // End Aamir Work
+// extension VoIPCenter: FlutterStreamHandler {
+//
+// // MARK: - FlutterStreamHandler๏ผevent channel๏ผ
+//
+// public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
+// self.eventSink = events
+// return nil
+// }
+//
+// public func onCancel(withArguments arguments: Any?) -> FlutterError? {
+// self.eventSink = nil
+// return nil
+// }
+// }
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 2f8758c..2d15a3d 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,7 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+#distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
+#distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
\ No newline at end of file
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/assets/icons/chat/avi.svg b/assets/icons/chat/avi.svg
new file mode 100644
index 0000000..e99eaef
--- /dev/null
+++ b/assets/icons/chat/avi.svg
@@ -0,0 +1,50 @@
+
+
+
diff --git a/assets/icons/chat/flv.svg b/assets/icons/chat/flv.svg
new file mode 100644
index 0000000..febd584
--- /dev/null
+++ b/assets/icons/chat/flv.svg
@@ -0,0 +1,51 @@
+
+
+
diff --git a/assets/icons/chat/mov.svg b/assets/icons/chat/mov.svg
new file mode 100644
index 0000000..22e41fe
--- /dev/null
+++ b/assets/icons/chat/mov.svg
@@ -0,0 +1,54 @@
+
+
+
diff --git a/assets/icons/chat/mp4.svg b/assets/icons/chat/mp4.svg
new file mode 100644
index 0000000..5d8e9ec
--- /dev/null
+++ b/assets/icons/chat/mp4.svg
@@ -0,0 +1,14 @@
+
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 cb62b88..729a8ef 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -22,6 +22,14 @@
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ FIVKIconName
+ AppIcon-VoIPKit
+ FIVKLocalizedName
+ VoIP-Kit
+ FIVKSkipRecallScreen
+
+ FIVKSupportVideo
+
FirebaseAppDelegateProxyEnabled
ITSAppUsesNonExemptEncryption
@@ -63,6 +71,8 @@
UIBackgroundModes
+ voip
+ processing
fetch
remote-notification
diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart
index 3fbe57c..a82b520 100644
--- a/lib/api/api_client.dart
+++ b/lib/api/api_client.dart
@@ -111,6 +111,8 @@ class ApiClient {
Future postJsonForResponse(String url, T jsonObject,
{String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async {
String? requestBody;
+ print(url);
+ print(jsonObject);
late Map stringObj;
if (jsonObject != null) {
requestBody = jsonEncode(jsonObject);
@@ -124,6 +126,7 @@ class ApiClient {
if (isFormData) {
headers = {'Content-Type': 'application/x-www-form-urlencoded'};
stringObj = ((jsonObject ?? {}) as Map).map((key, value) => MapEntry(key, value?.toString() ?? ""));
+ print(stringObj);
}
return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart
index daafa92..3feec0c 100644
--- a/lib/api/chat/chat_api_client.dart
+++ b/lib/api/chat/chat_api_client.dart
@@ -1,9 +1,8 @@
+import 'dart:async';
import 'dart:convert';
import 'dart:io';
-import 'dart:typed_data';
import 'package:flutter/foundation.dart';
-import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
@@ -34,12 +33,13 @@ class ChatApiClient {
"${ApiConsts.chatLoginTokenUrl}externaluserlogin",
{
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
+ // "employeeNumber": ApiConsts.baseUrl.contains("uat") ? "266642" : AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
"isMobile": true,
- "platform": Platform.isIOS ? "ios" : "android",
"deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei,
- "voipToken": "",
+ "platform": Platform.isIOS ? "ios" : "android", // ios, android
+ "voipToken": Platform.isIOS ? AppState().iosVoipPlayerID : ""
},
);
@@ -49,7 +49,12 @@ class ChatApiClient {
if (response.statusCode == 200) {
userLoginResponse = user.userAutoLoginModelFromJson(response.body);
} else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) {
- getUserLoginToken();
+ try {
+ await getUserLoginToken();
+ } on TimeoutException catch (e) {
+ return userLoginResponse;
+ }
+ ;
} else {
userLoginResponse = user.userAutoLoginModelFromJson(response.body);
Utils.showToast(userLoginResponse.errorResponses!.first.message!);
@@ -78,9 +83,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;
}
@@ -145,14 +148,14 @@ class ChatApiClient {
}
// Upload Chat Media
- Future