Voip #12

Open
aamir.muhammad wants to merge 79 commits from development_aamir into master

@ -19,6 +19,8 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- Chat Web RTC Calling -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

@ -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<String, Any?>
// 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)
// }
//}

@ -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)
}
}

@ -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: - FlutterStreamHandlerevent 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
// }
// }

@ -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

Binary file not shown.

Binary file not shown.

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#F15642;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M121.408,384.016c-4.096-2.32-6.656-6.912-4.096-12.288l36.72-71.76
c3.456-6.784,12.656-7.04,15.856,0l36.08,71.76c5.248,9.968-10.24,17.904-14.848,7.92l-5.632-11.248h-47.2l-5.488,11.264
C130.752,384.016,126.016,384.912,121.408,384.016z M176.416,351.52l-14.464-31.6l-15.728,31.6H176.416z"/>
<path style="fill:#FFFFFF;" d="M241.6,378.256l-33.776-70.736c-4.992-10.112,10.112-18.416,15.728-7.808l11.392,25.712
l14.704,33.76l14.448-33.76l11.392-25.712c5.12-9.712,19.952-3.584,15.616,7.04l-32.624,71.504
C255.536,386.32,246.448,388.24,241.6,378.256z"/>
<path style="fill:#FFFFFF;" d="M306.88,303.152c0-10.48,16.896-10.88,16.896,0v73.04c0,10.624-16.896,10.88-16.896,0V303.152z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#F7B84E;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M133.312,312.096v20.336h32.624c4.608,0,9.216,4.608,9.216,9.088c0,4.224-4.608,7.664-9.216,7.664
h-32.624v26.864c0,4.48-3.184,7.936-7.664,7.936c-5.632,0-9.072-3.456-9.072-7.936v-72.656c0-4.608,3.456-7.936,9.072-7.936h44.912
c5.632,0,8.96,3.328,8.96,7.936c0,4.096-3.328,8.688-8.96,8.688h-37.248V312.096z"/>
<path style="fill:#FFFFFF;" d="M195.072,303.152c0-4.224,3.584-7.808,8.064-7.808c4.096,0,7.552,3.6,7.552,7.808v64.096h34.8
c12.528,0,12.8,16.752,0,16.752h-42.336c-4.48,0-8.064-3.184-8.064-7.808v-73.04H195.072z"/>
<path style="fill:#FFFFFF;" d="M286.88,378.256l-33.776-70.752c-4.992-10.112,10.112-18.416,15.728-7.808l11.392,25.712
l14.704,33.776l14.448-33.776l11.392-25.712c5.12-9.712,19.952-3.584,15.616,7.04l-32.624,71.52
C300.816,386.32,291.728,388.224,286.88,378.256z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#50BEE8;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M96.928,327.84v47.328c0,5.648-4.608,8.832-9.216,8.832c-4.096,0-7.68-3.184-7.68-8.832v-72.016
c0-6.656,5.632-8.848,7.68-8.848c3.696,0,5.872,2.192,8.064,4.624l28.128,37.984l29.168-39.408c4.24-5.232,14.592-3.2,14.592,5.648
v72.016c0,5.648-3.568,8.832-7.664,8.832c-4.608,0-8.192-3.184-8.192-8.832V327.84l-21.248,26.864
c-4.592,5.648-10.352,5.648-14.576,0L96.928,327.84z"/>
<path style="fill:#FFFFFF;" d="M234.096,385.28c-23.664,1.024-48.24-14.72-48.24-46.064c0-31.472,24.56-46.944,48.24-46.944
c22.384,1.136,45.792,16.624,45.792,46.944C279.888,369.552,256.48,385.28,234.096,385.28z M232.688,308.912
c-14.336,0-29.936,10.112-29.936,30.32c0,20.096,15.616,30.336,29.936,30.336c14.72,0,30.448-10.24,30.448-30.336
C263.136,319.008,247.408,308.912,232.688,308.912z"/>
<path style="fill:#FFFFFF;" d="M323.664,378.256l-33.776-70.752c-4.992-10.112,10.112-18.416,15.728-7.808l11.392,25.712
l14.704,33.776l14.448-33.776l11.392-25.712c5.12-9.712,19.952-3.584,15.616,7.04l-32.624,71.52
C337.6,386.32,328.512,388.224,323.664,378.256z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="448" height="512" viewBox="0 0 448 512">
<g id="mp3" transform="translate(-32)">
<path id="Path_5167" data-name="Path 5167" d="M128,0A32.094,32.094,0,0,0,96,32V480a32.084,32.084,0,0,0,32,32H448a32.084,32.084,0,0,0,32-32V128L352,0Z" fill="#e2e5e7"/>
<path id="Path_5168" data-name="Path 5168" d="M384,128h96L352,0V96A32.094,32.094,0,0,0,384,128Z" fill="#b0b7bd"/>
<path id="Path_5169" data-name="Path 5169" d="M480,224l-96-96h96Z" fill="#cad1d8"/>
<path id="Path_5170" data-name="Path 5170" d="M416,416a16.047,16.047,0,0,1-16,16H48a16.047,16.047,0,0,1-16-16V256a16.047,16.047,0,0,1,16-16H400a16.047,16.047,0,0,1,16,16Z" fill="#50bee8"/>
<g id="Group_8310" data-name="Group 8310">
<path id="Path_5171" data-name="Path 5171" d="M117.184,327.84v47.344c0,5.632-4.592,8.832-9.216,8.832-4.1,0-7.664-3.2-7.664-8.832V303.152a8.527,8.527,0,0,1,7.664-8.832c3.712,0,5.888,2.192,8.064,4.608l28.16,38,29.152-39.408c4.24-5.248,14.592-3.2,14.592,5.632v72.032c0,5.632-3.6,8.832-7.68,8.832-4.592,0-8.192-3.2-8.192-8.832V327.84l-21.232,26.88c-4.592,5.632-10.352,5.632-14.576,0Z" fill="#fff"/>
<path id="Path_5172" data-name="Path 5172" d="M210.288,303.152a8.807,8.807,0,0,1,8.7-8.832h29.552c16.64,0,31.616,11.136,31.616,32.5,0,20.224-14.976,31.472-31.616,31.472h-21.36v16.9c0,5.632-3.584,8.832-8.192,8.832a8.647,8.647,0,0,1-8.7-8.832V303.152Zm16.88,7.3V342.3h21.36c8.576,0,15.36-7.552,15.36-15.488,0-8.96-6.784-16.368-15.36-16.368Z" fill="#fff"/>
<text id="_4" data-name="4" transform="translate(287 383)" fill="#fff" font-size="120" font-family="Poppins-SemiBold, Poppins" font-weight="600" letter-spacing="-0.03em"><tspan x="0" y="0">4</tspan></text>
</g>
<path id="Path_5174" data-name="Path 5174" d="M400,432H96v16H400a16.047,16.047,0,0,0,16-16V416A16.047,16.047,0,0,1,400,432Z" fill="#cad1d8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -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)
// }
}

@ -22,6 +22,14 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FIVKIconName</key>
<string>AppIcon-VoIPKit</string>
<key>FIVKLocalizedName</key>
<string>VoIP-Kit</string>
<key>FIVKSkipRecallScreen</key>
<true/>
<key>FIVKSupportVideo</key>
<true/>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>ITSAppUsesNonExemptEncryption</key>
@ -63,6 +71,8 @@
<true/>
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>processing</string>
<string>fetch</string>
<string>remote-notification</string>
</array>

@ -111,6 +111,8 @@ class ApiClient {
Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
String? requestBody;
print(url);
print(jsonObject);
late Map<String, String> 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<String, dynamic>).map((key, value) => MapEntry(key, value?.toString() ?? ""));
print(stringObj);
}
return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);

@ -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<Object?> uploadMedia(String userId, File file) async {
Future<Object?> uploadMedia(String userId, File file, String fileSource) async {
if (kDebugMode) {
print("${ApiConsts.chatMediaImageUploadUrl}upload");
print(AppState().chatDetails!.response!.token);
}
dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload'));
request.fields.addAll({'userId': userId, 'fileSource': '1'});
request.fields.addAll({'userId': userId, 'fileSource': fileSource});
request.files.add(await MultipartFile.fromPath('files', file.path));
request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'});
StreamedResponse response = await request.send();
@ -164,10 +167,10 @@ class ChatApiClient {
}
// Download File For Chat
Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription}) async {
Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatMediaImageUploadUrl}download",
{"fileType": fileTypeDescription, "fileName": fileName, "fileSource": 1},
{"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource},
token: AppState().chatDetails!.response!.token,
);
Uint8List data = Uint8List.fromList(response.bodyBytes);
@ -203,6 +206,7 @@ class ChatApiClient {
"${ApiConsts.getGroupByUserId}${AppState().chatDetails!.response!.id}",
token: AppState().chatDetails!.response!.token,
);
if (!kReleaseMode) {
logger.i("res: " + response.body);
}
@ -313,4 +317,65 @@ class ChatApiClient {
throw e;
}
}
// CallUser Login Token
Future<user.UserAutoLoginModel> 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) {
await getUserCallToken(userid: userid);
} else {
userLoginResponse = user.userAutoLoginModelFromJson(response.body);
Utils.showToast(userLoginResponse.errorResponses!.first.message!);
}
return userLoginResponse;
}
// Call Decline On App Terminated State
Future<Response> callDecline({required int cUserID, required int tUserID, 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<String> 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 || kDebugMode ? 1 : 0
// 1
},
);
Map<String, dynamic> values = jsonDecode(response.body) as Map<String, dynamic>;
id = values["id"];
if (!kReleaseMode) {
print("res: " + response.body);
}
return id;
}
}

@ -193,4 +193,28 @@ 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;
}
bool _isBackgroundCall = false;
bool get isBackgroundCall => _isBackgroundCall;
set isBackgroundCall(bool value) {
_isBackgroundCall = value;
}
}

@ -0,0 +1,200 @@
import 'dart:async';
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/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: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;
Timer? _timer;
int _start = 25;
void startTimer() {
Duration oneSec = const Duration(seconds: 1);
_timer = Timer.periodic(
oneSec,
(Timer timer) {
if (_start == 0) {
timer.cancel();
} else {
_start--;
}
},
);
}
Future<void> 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: const 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) {
startTimer();
await Utils.saveStringFromPrefs("isIncomingCall", "true");
await FlutterCallkitIncoming.showCallkitIncoming(params);
if (_start == 0) {
_timer!.cancel();
//await FlutterCallkitIncoming.showMissCallNotification(params);
await FlutterCallkitIncoming.endAllCalls();
}
}
}
Future<void> 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<void> voipDeclineCall(IosCallPayload? iosCallPayload) async {
// try {
// print("DeclineVia Flutter");
// print(iosCallPayload!.toRawJson());
// IosCallPayload _iosCallPayload = IosCallPayload(incomingCallerId: iosCallPayload.incomingCallerId!.split("-")[0], incomingCallReciverId: iosCallPayload.incomingCallerId!.split("-")[1]);
// ALM.UserAutoLoginModel model = await ChatApiClient().getUserCallToken(userid: iosCallPayload.incomingCallerId!.split("-")[1]);
// await ChatApiClient()
// .callDecline(cUserID: int.parse(_iosCallPayload.incomingCallerId!), tUserID: int.parse(_iosCallPayload.incomingCallReciverId.toString()), targetUsertoken: model.response!.token);
// } catch (err) {
// print(err);
// }
// }
Future<HubConnection> 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: <int>[2000, 5000, 10000, 20000]).build();
return hc;
} catch (e) {
print(e);
return hc;
}
}
}

@ -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 ser343622ver
// 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/";
@ -34,13 +34,11 @@ 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 marathonBaseUrlLive = "https://marathoon.com/service/api/";
static String marathonBaseUrlUAT = "https://marathoon.com/uatservice/api/";
static String marathonBaseUrl = marathonBaseUrlLive;
// static String marathonBaseUrl = marathonBaseUrlUAT;
static String marathonBaseUrl = "https://marathoon.com/service/api/";
static String marathonBaseUrlServices = "https://marathoon.com/service/";
static String marathonParticipantLoginUrl = marathonBaseUrl + "auth/participantlogin";
static String marathonProjectGetUrl = marathonBaseUrl + "Project/Project_Get";
@ -53,6 +51,7 @@ class ApiConsts {
static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants";
//DummyCards for the UI
static CardContent dummyQuestion = const CardContent();
static int tabletMinLength = 500;
}
@ -70,5 +69,3 @@ class SharedPrefsConsts {
static String mohemmWifiPassword = "mohemmWifiPassword";
static String editItemForSale = "editItemForSale";
}

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
@ -5,15 +6,16 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
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();
@ -47,12 +49,8 @@ class AppNotifications {
}
void init(String? firebaseToken, BuildContext context) async {
// if (Platform.isAndroid) {
// hmsApiAvailability = HmsApiAvailability();
// }
this.context = context;
debugPrint("Firebase init");
await requestPermissions();
AppState().setDeviceToken = firebaseToken;
await Permission.notification.isDenied.then((bool value) {
@ -60,12 +58,16 @@ 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);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) _handleMessage(message);
_handleMessage(message);
});
FirebaseMessaging.onMessageOpenedApp.listen(_handleOpenApp);
@ -76,30 +78,60 @@ class AppNotifications {
AppState().setDeviceToken = token;
});
if (Platform.isAndroid) {
// await hmsApiAvailability.isHMSAvailable().then((value) async {
if (!(await Utils.isGoogleServicesAvailable())) {
huawei_push.Push.enableLogger();
var result = await huawei_push.Push.setAutoInitEnabled(true);
huawei_push.Push.onNotificationOpenedApp.listen((message) {
// newMessage(toFirebaseRemoteMessage(message));
}, onError: (e) => print(e.toString()));
huawei_push.Push.onMessageReceivedStream.listen((message) {
// newMessage(toFirebaseRemoteMessage(message));
}, onError: (e) => print(e.toString()));
}
// }).catchError((err) {
// print(err);
// });
}
// if (Platform.isAndroid) {
// // await hmsApiAvailability.isHMSAvailable().then((value) async {
// if (!(await Utils.isGoogleServicesAvailable())) {
// huawei_push.Push.enableLogger();
// var result = await huawei_push.Push.setAutoInitEnabled(true);
//
// huawei_push.Push.onNotificationOpenedApp.listen((message) {
// print("onNotificationOpenedApp");
// print(message);
// // newMessage(toFirebaseRemoteMessage(message));
// }, onError: (e) => print(e.toString()));
//
// huawei_push.Push.onMessageReceivedStream.listen((message) {
// print("onMessageReceivedStream");
// print(message);
// // newMessage(toFirebaseRemoteMessage(message));
// }, onError: (e) => print(e.toString()));
// }
// // }).catchError((err) {
// // print(err);
// // });
// }
}
void initHuaweiPush(Function loginCallback) {
Future<void> initHuaweiPush(Function loginCallback) async {
AppState().setIsHuawei = true;
initTokenStream(loginCallback);
huawei_push.Push.enableLogger();
huawei_push.Push.getToken("");
var result = await huawei_push.Push.setAutoInitEnabled(true);
debugPrint("HUAWEI PUSH TOKEN RESULT: $result");
huawei_push.Push.onMessageReceivedStream.listen(onMessageReceived);
//huawei_push.Push.registerBackgroundMessageHandler(huaweiBackgroundMessage);
bool backgroundMessageHandler = await huawei_push.Push.registerBackgroundMessageHandler(huaweiBackgroundMessage);
debugPrint("Huawei Background Message Handler Registered: $backgroundMessageHandler");
initTokenStream(loginCallback);
}
void onMessageReceived(huawei_push.RemoteMessage remoteMessage) {
dynamic data = remoteMessage.data;
if (data != null) {
huawei_push.Push.localNotification(
<String, String>{
huawei_push.HMSLocalNotificationAttr.TITLE: 'DataMessage Received',
huawei_push.HMSLocalNotificationAttr.MESSAGE: data,
},
);
print('onMessageReceived' + 'Data: $data');
RemoteMessage message = RemoteMessage(
data: jsonDecode(remoteMessage.data!),
);
_handleMessage(message);
} else {
print('onMessageReceived' + 'No data is present.');
}
}
// HUAWEI PUSH TOKEN IMPLEMENTATION
@ -114,8 +146,8 @@ class AppNotifications {
Utils.hideLoading(context);
}
Future<void> initTokenStream(Function loginCallback) async {
huawei_push.Push.getTokenStream.listen(_onTokenEvent, onError: _onTokenError).onData((data) {
void initTokenStream(Function loginCallback) {
huawei_push.Push.getTokenStream.listen(_onTokenEvent, onError: _onTokenError).onData((data) async {
AppState().setHuaweiPushToken = data;
debugPrint("HUAWEI PUSH TOKEN: $data");
loginCallback();
@ -126,23 +158,34 @@ class AppNotifications {
Utils.saveStringFromPrefs("isAppOpendByChat", "false");
GetNotificationsResponseModel notification = GetNotificationsResponseModel();
notification.createdOn = DateUtil.getMonthDayYearDateFormatted(DateTime.now());
notification.messageTypeData = message.data['picture'];
notification.message = message.data['message'];
notification.notificationType = message.data["NotificationType"].toString();
if (message.data["NotificationType"] == "2") {
notification.videoURL = message.data["VideoUrl"];
}
if (message.notification != null) {
notification.createdOn = DateUtil.getMonthDayYearDateFormatted(DateTime.now());
notification.messageTypeData = message.data['picture'];
notification.message = message.data['message'];
notification.notificationType = message.data["NotificationType"].toString();
if (message.data["NotificationType"] == "2") {
notification.videoURL = message.data["VideoUrl"];
}
Future.delayed(Duration(seconds: 5), () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => NotificationsDetailsPage(
notification: notification,
Future.delayed(Duration(seconds: 5), () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => NotificationsDetailsPage(
notification: notification,
),
),
),
);
});
);
});
}
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) {
@ -173,17 +216,41 @@ 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<dynamic> backgroundMessageHandler(RemoteMessage message) async {
@pragma('vm:entry-point')
Future<void> 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);
}
}
}
void huaweiBackgroundMessage(huawei_push.RemoteMessage remoteMessage) async {
dynamic data = remoteMessage.data;
if (data != null) {
print(
'Background message is received, sending local notification.',
);
huawei_push.Push.localNotification(
<String, String>{
huawei_push.HMSLocalNotificationAttr.TITLE: '[Headless] DataMessage Received',
huawei_push.HMSLocalNotificationAttr.MESSAGE: data,
},
);
} else {
print(
'Background message is received. There is no data in the message.',
);
}
}

@ -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';
@ -192,6 +193,7 @@ class AppRoutes {
static const String chat = "/chat";
static const String chatDetailed = "/chatDetailed";
static const String chatFavoriteUsers = "/chatFavoriteUsers";
static const String chatStartCall = "/chatStartCall";
//Group Chat
static const String manageGroup = "/manageGroup";
@ -308,6 +310,8 @@ class AppRoutes {
chat: (BuildContext context) => ChatHome(),
chatDetailed: (BuildContext context) => ChatDetailScreen(),
chatFavoriteUsers: (BuildContext context) => ChatFavoriteUsersScreen(),
chatStartCall: (BuildContext context) => StartCallPage(),
//Group Chat
manageGroup: (BuildContext context) => ManageGroupScreen(),

@ -7,35 +7,28 @@
// 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:flutter_web_plugins/flutter_web_plugins.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';
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);

@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/generated/codegen_loader.g.dart';
import 'package:mohem_flutter_app/models/post_params_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/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/provider/eit_provider_model.dart';
@ -17,8 +18,10 @@ 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';
HubConnection? chatHubConnection;
// test uat account
// username 199067
@ -74,9 +77,9 @@ Future<void> main() async {
ChangeNotifierProvider<MarathonProvider>(
create: (_) => MarathonProvider(),
),
// ChangeNotifierProvider<ChatCallProvider>(
// create: (_) => ChatCallProvider(),
// ),
ChangeNotifierProvider<ChatCallProvider>(
create: (_) => ChatCallProvider(),
),
],
child: const MyApp(),
),

@ -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<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) => CallerDetails(
response: json["response"] == null ? null : Response.fromJson(json["response"]),
errorResponses: json["errorResponses"],
factory CallSessionPayLoad.fromJson(Map<String, dynamic> json) => CallSessionPayLoad(
target: json["target"],
caller: json["caller"],
sdp: json["sdp"] == null ? null : Sdp.fromJson(json["sdp"]),
);
Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) => Sdp(
type: json["type"],
sdp: json["sdp"],
);
Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) => IosCallPayload(
incomingCallType: json["incoming_call_type"],
incomingCallerId: json["incoming_caller_id"],
incomingCallerName: json["incoming_caller_name"],
incomingCallReciverId: null,
uuid: json["uuid"],
);
Map<String, dynamic> 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,
};
}

@ -4,6 +4,8 @@ class CreateGroupRequest {
String? groupName;
int? adminUserId;
List<ChatUser>? groupUserList;
List<ChatUser>? addedUsers;
List<ChatUser>? removedUsers;
bool? canAttach;
bool? canAudioC;
bool? canShareS;
@ -15,6 +17,8 @@ class CreateGroupRequest {
{this.groupName,
this.adminUserId,
this.groupUserList,
this.addedUsers,
this.removedUsers,
this.canAttach,
this.canAudioC,
this.canShareS,
@ -27,12 +31,24 @@ class CreateGroupRequest {
CreateGroupRequest.fromJson(Map<String, dynamic> json) {
groupName = json['groupName'];
adminUserId = json['adminUserId'];
if (json['removedUsers'] != null) {
groupUserList = <ChatUser>[];
json['removedUsers'].forEach((v) {
groupUserList!.add(new ChatUser.fromJson(v));
});
}
if (json['groupUserList'] != null) {
groupUserList = <ChatUser>[];
json['groupUserList'].forEach((v) {
groupUserList!.add(new ChatUser.fromJson(v));
});
}
if (json['addedUsers'] != null) {
groupUserList = <ChatUser>[];
json['addedUsers'].forEach((v) {
groupUserList!.add(new ChatUser.fromJson(v));
});
}
canAttach = json['canAttach'];
canAudioC = json['canAudioC'];
canShareS = json['canShareS'];
@ -50,6 +66,14 @@ class CreateGroupRequest {
data['groupUserList'] =
this.groupUserList!.map((v) => v.toJson()).toList();
}
if (this.addedUsers != null) {
data['addedUsers'] =
this.addedUsers!.map((v) => v.toJson()).toList();
}
if (this.removedUsers != null) {
data['removedUsers'] =
this.removedUsers!.map((v) => v.toJson()).toList();
}
data['canAttach'] = this.canAttach;
data['canAudioC'] = this.canAudioC;
data['canShareS'] = this.canShareS;

@ -1,7 +1,7 @@
import 'dart:convert';
class GetUserGroups {
List<GroupResponse>? groupresponse;
List<GroupResponse>? groupresponse =[];
Null? errorResponses;
GetUserGroups({this.groupresponse, this.errorResponses});

@ -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<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) => Args();
Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) => FileTypeResponse(
fileTypeId: json["fileTypeId"].toInt(),
);
Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> toJson() => {
"isActiveCode": isActiveCode,
"id": id,
"encryptedUserName": encryptedUserName,
"userName": userName,
"title": title,
"encryptedUserId": encryptedUserId,
"email": email,
"isDomainUser": isDomainUser,
"token": token,
};
}

@ -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<String, dynamic> json) => RemoteIceCandidatePayLoad(
target: json["target"],
candidate: json["candidate"] == null ? null : Candidate.fromJson(json["candidate"]),
);
Map<String, dynamic> 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<String, dynamic> json) => Candidate(
candidate: json["candidate"],
sdpMid: json["sdpMid"],
sdpMLineIndex: json["sdpMLineIndex"],
usernameFragment: json["usernameFragment"],
);
Map<String, dynamic> toJson() => {
"candidate": candidate,
"sdpMid": sdpMid,
"sdpMLineIndex": sdpMLineIndex,
"usernameFragment": usernameFragment,
};
}

@ -1,52 +1,70 @@
import 'dart:async';
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_ios_voip_kit/flutter_ios_voip_kit.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.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: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();
final FlutterIOSVoIPKit voIPKit = FlutterIOSVoIPKit.instance;
MediaStream? _localStream;
MediaStream? _remoteStream;
void initCallListeners() {
chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection.on("OnOfferAsync", onOfferAsync);
chatHubConnection.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection.on("OnHangUpAsync", onHangUpAsync);
chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync);
}
//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
};
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;
/// WebRTC Connection Variables
bool isIncomingCallLoader = true;
bool isIncomingCall = false;
bool isOutGoingCall = false;
bool isUserOnline = false;
late BuildContext providerContext;
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);
}
// Audio Constraints
var audioConstraints = {
Map<String, Object> audioConstraints = {
"sampleRate": 8000,
"sampleSize": 16,
"channelCount": 2,
@ -54,134 +72,769 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
"audio": true,
};
Future<RTCPeerConnection> _createPeerConnection() async {
// {"url": "stun:stun.l.google.com:19302"},
Map<String, dynamic> configuration = {
"iceServers": [
{"urls": 'stun:15.185.116.59:3478'},
{"urls": "turn:15.185.116.59:3479", "username": "admin", "credential": "admin"}
]
};
Future<void> init() async {
_pc = await creatOfferWithCon();
Future.delayed(const Duration(seconds: 2), () {
connectIncomingCall();
});
}
Map<String, dynamic> 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<void> initLocalCamera({required ChatProviderModel chatProvmodel, required callData, required BuildContext context, bool isIncomingCall = false}) async {
isCallEnded = false;
chatProvModel = chatProvmodel;
outGoingCallData = callData;
await initStreams();
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;
await startCall(callType: isVideoCall ? "Video" : "Audio", context: context);
_pc = await creatOfferWithCon();
connectOutgoing();
notifyListeners();
}
void init() {
initRenderers();
_createPeerConnection().then((pc) {
_peerConnection = pc;
// _setRemoteDescription(widget.info);
});
void connectOutgoing() {
isOutGoingCall = true;
// notifyListeners();
}
void initRenderers() {
_localVideoRenderer.initialize();
_remoteRenderer.initialize();
initLocalCamera();
Future<void> 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);
}
// OutGoing Listeners
void onCallAcceptedAsync(List<Object?>? params) async {
if (_timer!.isActive && _start > 5) {
_timer!.cancel();
_start = 25;
}
dynamic items = params!.toList();
RTCSessionDescription description = await _createOffer();
await _pc.setLocalDescription(description);
dynamic payload = {"target": items[0]["id"], "caller": outGoingCallData.callerId, "sdp": description.toMap()};
invoke(invokeMethod: "OfferAsync", currentUserID: outGoingCallData.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload));
}
Future<void> onIceCandidateAsync(List<Object?>? params) async {
dynamic items = params!.toList();
if (isIncomingCall) {
RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString()));
if (_pc != null) {
await _pc.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex));
}
} else {
if (kDebugMode) {
logger.i("res: " + items.toString());
}
RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString()));
if (_pc != null) {
await _pc.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex));
if (!isCallStarted) {
isCallStarted = true;
notifyListeners();
if (isCallStarted) {
isIncomingCallLoader = false;
isOutGoingCall = true;
if (Platform.isIOS) {
Future.delayed(Duration(seconds: 2), () {
Navigator.pushReplacement(
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
));
});
} else {
Navigator.pushReplacement(
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
));
}
}
}
}
notifyListeners();
}
}
void initLocalCamera() async {
_localStream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true});
_localVideoRenderer.srcObject = _localStream;
// _localVideoRenderer.srcObject = await navigator.mediaDevices
// .getUserMedia({'video': true, 'audio': true});
print('this source Object');
print('this suarce ${_localVideoRenderer.srcObject != null}');
Future<void> onOfferAsync(List<Object?>? params) async {
dynamic items = params!.toList();
var data = jsonDecode(items.toString());
if (isIncomingCall) {
_pc.setRemoteDescription(RTCSessionDescription(data[0]["sdp"]["sdp"], data[0]["sdp"]["type"]));
RTCSessionDescription description = await _createAnswer();
await _pc.setLocalDescription(description);
dynamic payload = {"target": data[0]["caller"], "caller": AppState().chatDetails!.response!.id, "sdp": description.toMap()};
invoke(invokeMethod: "AnswerOfferAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, data: jsonEncode(payload));
}
// else {
// RTCSessionDescription description = await _createAnswer();
// await _pc.setLocalDescription(description);
// var payload = {"target": items[0]["id"], "caller": outGoingCallData.callerId, "sdp": description.toMap()};
// invoke(invokeMethod: "AnswerOffer", currentUserID: outGoingCallData.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload));
// }
notifyListeners();
}
void startCall({required String callType}) {}
void endCall() {}
void checkCall(Map<String, dynamic> message) {
switch (message["callStatus"]) {
case 'connected':
{}
break;
case 'offer':
{}
break;
case 'accept':
{}
break;
case 'candidate':
{}
break;
case 'bye':
{}
break;
case 'leave':
{}
break;
//////////////////////////// OutGoing Call End ///////////////////////////////////////
Future<bool> endCall({required bool isUserOnline}) async {
if (isIncomingCall) {
logger.i("-----------------------Endeddddd By Me---------------------------");
if (chatHubConnection!.state == HubConnectionState.Connected) {
await invoke(invokeMethod: "HangUpAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 0);
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 1);
}
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
isIncomingCall = false;
isOutGoingCall = false;
isAudioCall = false;
if (isCallConnected) {
if (_pc.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
if (kDebugMode) {
print("------------------ PC Stopped ----------------------------");
}
_pc.close();
_pc.dispose();
}
}
if (remoteRenderer != null) {
remoteRenderer!.dispose();
remoteRenderer = null;
}
if (localVideoRenderer != null) {
localVideoRenderer!.dispose();
localVideoRenderer = null;
}
if (_localStream != null) {
_localStream!.dispose();
_localStream = null;
}
if (chatHubConnection != null && !isUserOnline) {
chatHubConnection!.stop();
}
if (Platform.isAndroid) await FlutterCallkitIncoming.endAllCalls();
if (Platform.isIOS) await voIPKit.endCall();
return true;
} else {
if (isOutGoingCall) {
await invoke(invokeMethod: "HangUpAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 1);
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, userStatus: 1);
} else if (isIncomingCall) {
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 1);
}
isCallStarted = false;
isVideoCall = false;
isCamOff = false;
isMicOff = false;
isLoudSpeaker = false;
if (isCallConnected) {
if (_pc.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
_pc.close();
_pc.dispose();
}
}
if (remoteRenderer != null) {
remoteRenderer!.dispose();
remoteRenderer = null;
}
if (localVideoRenderer != null) {
localVideoRenderer!.dispose();
localVideoRenderer = null;
}
if (_localStream != null) {
_localStream!.dispose();
_localStream = null;
}
isOutGoingCall = false;
isIncomingCall = false;
isAudioCall = false;
return true;
}
}
// Incoming Listeners
void onAnswerOffer(List<Object?>? payload) async {
// if (isIncomingCall) {
// // print("--------------------- On Answer Offer Async ---------------------------------------");
// //await invoke(invokeMethod: "InvokeMobile", currentUserID: AppState().getchatUserDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, debugData: {"On Answer Offer Async"});
// } else {
var items = payload!.toList();
if (kDebugMode) {
logger.i("res: " + items.toString());
}
CallSessionPayLoad data = CallSessionPayLoad.fromJson(jsonDecode(items.first.toString()));
RTCSessionDescription description = RTCSessionDescription(data.sdp!.sdp, 'answer');
_pc.setRemoteDescription(description);
// }
}
//// Listeners Methods ////
Future<void> onHangUpAsync(List<Object?>? params) async {
print("--------------------- onHangUp ASYNC ---------------------------------");
void onCallAcceptedAsync(List<Object?>? params) {}
dynamic items = params!.toList();
if (items[0]["id"] != AppState().chatDetails!.response!.id) {
if (Platform.isIOS) await voIPKit.endCall();
if (Platform.isAndroid) await FlutterCallkitIncoming.endAllCalls();
if (isIncomingCall) {
endCall(isUserOnline: isUserOnline).then((bool value) {
if (isCallConnected && isUserOnline) {
isCallConnected = false;
if (!AppState().isLogged) {
Navigator.of(AppRoutes.navigatorKey.currentContext!).canPop();
} else {
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.dashboard));
}
} else {
Navigator.of(AppRoutes.navigatorKey.currentContext!).canPop();
}
});
} else {
if (isOutGoingCall) {
endCall(isUserOnline: isUserOnline).then((bool value) {
if (isCallConnected && isUserOnline) {
isCallConnected = false;
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.dashboard));
} else {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).canPop();
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.dashboard));
}
});
}
}
} else {
if (kDebugMode) {
print("Call Ended By Me");
}
if (isOutGoingCall) {
// if (!isCallConnected) {
// if (_timer!.isActive && _start == 5) {
// _timer!.cancel();
// _start = 25;
// Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
// endCall(isUserOnline: isUserOnline);
// return Utils.showToast("${items[0]["userName"]}" + " has declined call", longDuration: true);
// }
// }
if (isCallConnected && isUserOnline) {
isCallConnected = false;
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
} else {
Navigator.of(AppRoutes.navigatorKey.currentContext!).canPop();
}
}
}
// endCall(isUserOnline: isUserOnline).then((bool value) {
// if (isCallConnected && isUserOnline) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
// isCallConnected = false;
// }
// if (items[0]["id"] != AppState().chatDetails!.response!.id && !AppState().isBackgroundCall) {
// if (kDebugMode) {
// print("Popped Due to Another User");
// }
// if (AppState().isBackgroundCall) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
// // Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.login));
// } else {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chat));
// }
// }
// if (AppState().isBackgroundCall) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
// }
//
notifyListeners();
isCallEnded = true;
// });
}
void onIceCandidateAsync(List<Object?>? params) {}
//Outgoing Timer for Decline Call
void onOfferAsync(List<Object?>? params) {}
Timer? _timer;
int _start = 25;
void onAnswerOffer(List<Object?>? params) {}
void startTimer() {
Duration oneSec = const Duration(seconds: 1);
_timer = Timer.periodic(
oneSec,
(Timer timer) {
if (_start == 0) {
timer.cancel();
} else {
print(_start);
_start--;
if (isOutGoingCall) {
if (!isCallConnected) {
if (_timer!.isActive && _start == 5) {
_timer!.cancel();
_start = 25;
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
endCall(isUserOnline: isUserOnline);
return Utils.showToast("${outGoingCallData.receiverName}" + " has declined call", longDuration: true);
}
} else {
if (isCallConnected) {
_timer!.cancel();
_start = 25;
}
}
notifyListeners();
}
}
},
);
}
void onHangUpAsync(List<Object?>? params) {}
// Future<void> OnIncomingCallAsync(List<Object?>? params) async {
// print("--------------------- On Incoming Call ---------------------------------------");
// dynamic items = params!.toList();
// logger.d(items);
// // Map<String, dynamic> json = {
// // "callerID": items[0]["id"],
// // "callerName": items[0]["userName"],
// // "callerEmail": items[0]["email"],
// // "callerTitle": items[0]["title"],
// // "callerPhone": null,
// // "receiverID": AppState().chatDetails!.response!.id,
// // "receiverName": AppState().chatDetails!.response!.userName,
// // "receiverEmail": AppState().chatDetails!.response!.email,
// // "receiverTitle": AppState().chatDetails!.response!.title,
// // "receiverPhone": AppState().chatDetails!.response!.phone,
// // "title": AppState().chatDetails!.response!.userName!.replaceAll(".", " "),
// // "callType": items[1] ? "Video" : "Audio",
// // };
// // CallDataModel callData = CallDataModel.fromJson(json);
// // ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), isOnline: true, incomingCallData: callData);
// //
// // if (!isOnIncomingCallPage) {
// // Map<String, dynamic> json = {
// // "callerID": items[0]["id"],
// // "callerName": items[0]["userName"],
// // "callerEmail": items[0]["email"],
// // "callerTitle": items[0]["title"],
// // "callerPhone": null,
// // "receiverID": AppState().chatDetails!.response!.id,
// // "receiverName": AppState().chatDetails!.response!.userName,
// // "receiverEmail": AppState().chatDetails!.response!.email,
// // "receiverTitle": AppState().chatDetails!.response!.title,
// // "receiverPhone": AppState().chatDetails!.response!.phone,
// // "title": AppState().chatDetails!.response!.userName!.replaceAll(".", " "),
// // "callType": items[1] ? "Video" : "Audio",
// // };
// // CallDataModel callData = CallDataModel.fromJson(json);
// // await Navigator.push(
// // providerContext,
// // MaterialPageRoute(
// // builder: (BuildContext context) => IncomingCall(
// // isVideoCall: items[1] ? true : false,
// // outGoingCallData: callData,
// // ),
// // ),
// // );
// // isOnIncomingCallPage = true;
// // }
// }
void onCallDeclinedAsync(List<Object?>? params) {}
Future<void> onCallDeclinedAsync(List<Object?>? params) async {
print("================= On Declined ========================");
dynamic items = params!.toList();
if (isOutGoingCall) {
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
bool val = await endCall(isUserOnline: isUserOnline);
if (Platform.isIOS) await voIPKit.endCall();
if (Platform.isAndroid) await FlutterCallkitIncoming.endAllCalls();
return Utils.showToast("${items[1]["userName"]}" + " has declined call", longDuration: true);
}
}
//// Invoke Methods
Future<void> invoke({required String invokeMethod, required String currentUserID, required String targetUserID, bool isVideoCall = false, var data}) async {
Future<void> invoke({required String invokeMethod, required int currentUserID, required int targetUserID, var data, int userStatus = 1, var debugData}) async {
List<Object> args = [];
if (invokeMethod == "answerCallAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "CallUserAsync") {
if (invokeMethod == "CallUserAsync") {
args = [currentUserID, targetUserID, isVideoCall];
} else if (invokeMethod == "answerCallAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "IceCandidateAsync") {
args = [targetUserID, data];
} else if (invokeMethod == "OfferAsync") {
args = [targetUserID, data];
} else if (invokeMethod == "AnswerOfferAsync") {
args = [targetUserID, data];
//json In Data
// json In Data
} else if (invokeMethod == "UpdateUserStatusAsync") {
args = [currentUserID, userStatus];
} else if (invokeMethod == "HangUpAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "InvokeMobile") {
args = [debugData];
}
try {
await chatHubConnection!.invoke("$invokeMethod", args: args);
} catch (e) {
logger.w(e);
}
await chatHubConnection.invoke(invokeMethod, args: args);
}
void stopListeners() async {
chatHubConnection.off('OnCallDeclinedAsync');
chatHubConnection.off('OnCallAcceptedAsync');
chatHubConnection.off('OnIceCandidateAsync');
chatHubConnection.off('OnAnswerOffer');
chatHubConnection!.off('OnCallDeclinedAsync');
chatHubConnection!.off('OnCallAcceptedAsync');
chatHubConnection!.off('OnIceCandidateAsync');
chatHubConnection!.off('OnAnswerOffer');
}
void playRingtone() async {
player.stop();
await player.setVolume(1.0);
String audioAsset = "";
if (Platform.isAndroid) {
audioAsset = "assets/audio/ring_60Sec.mp3";
} else {
audioAsset = "assets/audio/ring_30Sec.caf";
}
try {
await player.setAsset(audioAsset);
await player.load();
player.play();
} catch (e) {
print("Error: $e");
}
}
//////////////////// Web RTC Offers & Connections ////////////////////////
Future<RTCPeerConnection> creatOfferWithCon() async {
Map<String, dynamic> configuration = {
"sdpSemantics": "plan-b",
'iceServers': [
{
'urls': 'stun:15.185.116.59:3478',
},
{
'urls': 'turn:15.185.116.59:3479',
'username': 'admin',
'credential': 'admin',
},
]
};
Map<String, dynamic> offerSdpConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true,
},
'optional': []
};
RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
// await pc.addStream(_localStream!);
//Changed By Aamir
_localStream?.getTracks().forEach((track) {
pc.addTrack(track, _localStream!);
});
pc.onConnectionState = (RTCPeerConnectionState state) {};
pc.onAddStream = (MediaStream stream) {
remoteRenderer!.srcObject = stream;
notifyListeners();
};
pc.onIceCandidate = (RTCIceCandidate e) async {
if (isIncomingCall) {
if (e.candidate != null) {
var payload = {"target": incomingCallData.targetUserId, "candidate": e.toMap()};
invoke(invokeMethod: "IceCandidateAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, data: jsonEncode(payload));
notifyListeners();
}
} else {
if (e.candidate != null) {
var payload = {"target": outGoingCallData.callerId, "candidate": e.toMap()};
invoke(invokeMethod: "IceCandidateAsync", currentUserID: outGoingCallData.callerId!, targetUserID: outGoingCallData.receiverId!, data: jsonEncode(payload));
}
}
};
// pc!.onTrack = (RTCTrackEvent event) async {
//
// String streamId = const Uuid().toString();
// MediaStream remoteStream = await createLocalMediaStream(streamId);
// event.streams[0].getTracks().forEach((MediaStreamTrack element) {
// logger.i("Stream Track: " + element.id.toString());
// // remoteRenderer.srcObject = element;
// remoteStream.addTrack(element);
// });
// };
pc.onSignalingState = (RTCSignalingState state) {
logger.i("signaling state: " + state.name);
// invoke(
// invokeMethod: "InvokeMobile",
// currentUserID: AppState().getchatUserDetails!.response!.id!,
// targetUserID: incomingCallData.targetUserId!,
// debugData: {"location": "Signaling", "parms": state.name});
};
pc.onIceGatheringState = (RTCIceGatheringState state) {
logger.i("rtc ice gathering state: " + state.name);
};
pc.onIceConnectionState = (RTCIceConnectionState state) {
if (RTCIceConnectionState.RTCIceConnectionStateFailed == state ||
RTCIceConnectionState.RTCIceConnectionStateDisconnected == state ||
RTCIceConnectionState.RTCIceConnectionStateClosed == state) {
logger.i("Ice Connection State:" + state.name);
// endCall().then((value) {
// notifyListeners();
// });
}
};
// pc!.onRenegotiationNeeded = _onRenegotiate;
return pc;
}
// void _onRenegotiate() async {
// try {
// print('onRenegotiationNeeded start');
// // makingOffer = true;
// await _pc.setLocalDescription(await _pc.createOffer(videoConstraints));
// print('onRenegotiationNeeded state after setLocalDescription: ' + _pc.signalingState.toString());
// // send offer via callManager
// var localDesc = await _pc.getLocalDescription();
// // callManager.sendCallMessage(MsgType.rtc_offer, RtcOfferAnswer(localDesc.sdp, localDesc.type));
// print('onRenegotiationNeeded; offer sent');
// } catch (e) {
// print("onRenegotiationNeeded error: " + e.toString());
// } finally {
// // makingOffer = false;
// print('onRenegotiationNeeded done');
// }
// }
Future<RTCSessionDescription> _createOffer() async {
RTCSessionDescription description = await _pc.createOffer();
// _offer = true;
return description;
}
Future<RTCSessionDescription> _createAnswer() async {
RTCSessionDescription description = await _pc!.createAnswer();
// _offer = false;
return description;
}
//////////////////// Web RTC End Offers ////////////////////
//////////////////// CallPage Buttons //////////////////////
void micOff() {
isMicOff = !isMicOff;
_localStream!.getAudioTracks().forEach((track) {
track.enabled = !track.enabled;
});
notifyListeners();
}
void camOff() {
isCamOff = !isCamOff;
_localStream!.getVideoTracks().forEach((track) {
track.enabled = !track.enabled;
});
// if (isCamOff) {
// isVideoCall = false;
// } else {
// isVideoCall = true;
// }
notifyListeners();
}
void loudOn() {
isLoudSpeaker = !isLoudSpeaker;
remoteRenderer!.srcObject?.getAudioTracks().forEach((track) {
if (isLoudSpeaker) {
track.enableSpeakerphone(true);
} else {
track.enableSpeakerphone(false);
}
});
notifyListeners();
}
void switchCamera() {
isFrontCamera = !isFrontCamera;
Helper.switchCamera(_localStream!.getVideoTracks()[0]);
notifyListeners();
}
///////////////// Incoming Call ///////////////////////////////
Future<void> initStreams() async {
List<MediaDeviceInfo> devices = await navigator.mediaDevices.enumerateDevices();
remoteRenderer = RTCVideoRenderer();
localVideoRenderer ??= RTCVideoRenderer();
await localVideoRenderer!.initialize();
try {
_localStream = await navigator.mediaDevices.getUserMedia({
'audio': true,
'video': isVideoCall
? {
'mandatory': {
'minWidth': '640', // Provide your own width, height and frame rate here
'minHeight': '480',
'minFrameRate': '30',
},
'facingMode': 'user',
'optional': [],
}
: false
});
if (kDebugMode) {
print(_localStream..toString());
}
localVideoRenderer!.srcObject = _localStream;
localVideoRenderer!.value = (const RTCVideoValue(width: 200, height: 200, renderVideo: true));
print("Working localStream");
} catch (e) {
print("Failed to get user media: $e");
}
// _localStream = await navigator.mediaDevices.getUserMedia(isVideoCall
// ? Platform.isIOS
// ? {
// 'audio': true,
// 'video': {
// 'facingMode': 'user', // Use 'user' for front camera, 'environment' for back camera
// 'width': {
// 'ideal': 1080, // Set the ideal width (maximum quality)
// },
// 'height': {
// 'ideal': 1920, // Set the ideal height (maximum quality)
// },
// 'frameRate': {
// 'ideal': 30, // Set the ideal frame rate (adjust as needed)
// },
// },
// }
// : {
// 'audio': true,
// 'video': {
// 'facingMode': 'user', // Use 'user' for front camera, 'environment' for back camera
// 'width': {
// 'ideal': 1920, // Set the ideal width (maximum quality)
// },
// 'height': {
// 'ideal': 1080, // Set the ideal height (maximum quality)
// },
// 'frameRate': {
// 'ideal': 30, // Set the ideal frame rate (adjust as needed)
// },
// },
// }
//
// // ? {
// // "video": {
// // "mandatory": {
// // "width": {"min": 1080},
// // "height": {"min": 1920}
// // },
// // "optional": Platform.isAndroid
// // ? [
// // {'sourceId': devices[1].deviceId},
// // {
// // "width": {"max": 1080}
// // },
// // {"frameRate": 30},
// // {"facingMode": "user"}
// // ]
// // : [
// // {"frameRate": 30},
// // {"facingMode": "user"}
// // ]
// // },
// // "frameRate": 30,
// // "width": 1080, //420,//640,//1280,
// // "height": 1920, //240//480//720
// // "audio": true,
// // }
// : audioConstraints);
// localVideoRenderer.srcObject = _localStream;
await remoteRenderer!.initialize();
notifyListeners();
}
Future<void> startIncomingCallViaKit({bool isVCall = true, required var inCallData}) async {
Utils.saveStringFromPrefs("isIncomingCall", "false");
if (isVCall) {
isVideoCall = isVCall;
} else {
isAudioCall = true;
}
await initStreams();
isIncomingCall = true;
incomingCallData = SingleUserChatModel.fromJson(inCallData);
loudOn();
// notifyListeners();
}
void connectIncomingCall() {
invoke(invokeMethod: "answerCallAsync", currentUserID: AppState().getchatUserDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!);
isIncomingCallLoader = false;
isIncomingCall = true;
// isVideoCall = true;
notifyListeners();
}
MediaRecorder? mobileRecoder;
// void startRecording() async {
// print("=-=-=-=-=-=-= Call Recoding Started -=-=-=-=-=-=-=-=-==-=");
// if (_localStream == null) throw Exception('Stream is not initialized');
// if (Platform.isIOS) {
// print('Recording is not available on iOS');
// return;
// }
// Directory appDirectory = await getApplicationDocumentsDirectory();
// String dirPath = '${appDirectory.path}/webrtc_sample';
// if (!await Directory(dirPath).exists()) {
// await Directory(dirPath).create();
// await File('$dirPath/.nomedia').create();
// }
// if (appDirectory == null) throw Exception('Can\'t find storagePath');
// String filePath = dirPath + '/mobile.mp4';
// mobileRecoder = MediaRecorder();
// notifyListeners();
// MediaStreamTrack videoTrack = _localStream!.getVideoTracks().firstWhere((track) => track.kind == 'video');
// await mobileRecoder!.start(filePath, videoTrack: videoTrack);
//
// Future.delayed(Duration(minutes: 1), () {
// stopRecording();
// });
// }
//
// void stopRecording() async {
// print("=-=-=-=-=-=-= Call Recoding Stopped -=-=-=-=-=-=-=-=-==-=");
// await mobileRecoder!.stop();
// mobileRecoder = null;
// notifyListeners();
// }
}

File diff suppressed because it is too large Load Diff

@ -1,11 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/theme/colors.dart';
class AppTheme {
static ThemeData getTheme(isArabic) => ThemeData(
useMaterial3: false,
fontFamily: isArabic ? 'Cairo' : 'Poppins',
primarySwatch: Colors.red,
visualDensity: VisualDensity.adaptivePlatformDensity,
brightness: Brightness.light,
pageTransitionsTheme: const PageTransitionsTheme(
@ -26,7 +29,7 @@ class AppTheme {
splashColor: Colors.transparent,
primaryColor: primaryColor,
primaryColorDark: primaryColor,
buttonColor: Colors.black,
cardColor: Colors.black,
toggleableActiveColor: secondaryColor,
indicatorColor: secondaryColor,
bottomSheetTheme: const BottomSheetThemeData(
@ -44,7 +47,11 @@ class AppTheme {
floatingActionButtonTheme: const FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2),
appBarTheme: AppBarTheme(
color: const Color(0xff515A5D),
brightness: Brightness.light,
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.light,
systemNavigationBarIconBrightness: Brightness.light,
),
elevation: 0.0,
actionsIconTheme: IconThemeData(
color: Colors.grey[800],

@ -16,7 +16,7 @@ import 'package:mohem_flutter_app/models/get_schedule_shifts_details_list_model.
import 'package:mohem_flutter_app/models/get_time_card_summary_list_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart';
import 'package:month_picker_dialog_2/month_picker_dialog_2.dart';
import 'package:month_picker_dialog/month_picker_dialog.dart';
import 'package:pie_chart/pie_chart.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
@ -117,8 +117,10 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
initialDate: formattedDate,
firstDate: DateTime(searchYear - 2),
lastDate: DateTime.now(),
confirmText: Text(LocaleKeys.confirm.tr()),
cancelText: Text(LocaleKeys.cancel.tr()),
confirmWidget: Text(LocaleKeys.confirm.tr()),
cancelWidget: Text(LocaleKeys.cancel.tr()),
// confirmText: Text(LocaleKeys.confirm.tr()),
// cancelText: Text(LocaleKeys.cancel.tr()),
).then((selectedDate) {
if (selectedDate != null) {
searchMonth = getMonth(selectedDate.month);

@ -1,381 +1,623 @@
import 'dart:convert';
import 'dart:core';
import 'dart:io';
import 'dart:ui';
import 'package:camera/camera.dart';
import 'package:draggable_widget/draggable_widget.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/models/chat/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:provider/provider.dart';
class IncomingCall extends StatefulWidget {
CallDataModel incomingCallData;
bool? isVideoCall;
bool isCallConnected = false;
IncomingCall({Key? key, required this.incomingCallData, this.isVideoCall}) : super(key: key);
class StartCallPage extends StatefulWidget {
IosCallPayload? payload;
StartCallPage({this.payload});
@override
_IncomingCallState createState() => _IncomingCallState();
_StartCallPageState createState() => _StartCallPageState();
}
class _IncomingCallState extends State<IncomingCall> with SingleTickerProviderStateMixin {
AnimationController? _animationController;
CameraController? _controller;
Future<void>? _initializeControllerFuture;
bool isCameraReady = false;
class _StartCallPageState extends State<StartCallPage> {
DragController dragController = DragController();
late ChatCallProvider cProv;
late ChatProviderModel provider;
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 500,
),
);
//_runAnimation();
// connectSignaling();
WidgetsBinding.instance.addPostFrameCallback(
(_) => _runAnimation(),
super.initState();
}
@override
void dispose() {
super.dispose();
}
void startCall() async {
IncomingCallModel? sessionData;
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls.isNotEmpty) {
sessionData = IncomingCallModel.fromRawJson(jsonEncode(calls[0]));
if (kDebugMode) {
print(sessionData.toRawJson());
}
if (provider.isUserOnline) {
AppState().isBackgroundCall = true;
cProv.isUserOnline = provider.isUserOnline;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
}
await cProv.startIncomingCallViaKit(inCallData: sessionData.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
cProv.init();
isCallConnected = true;
} else {
AppState().isBackgroundCall = true;
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
cProv.isUserOnline = provider.isUserOnline;
await cProv.startIncomingCallViaKit(inCallData: sessionData.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
try {
AppState().setchatUserDetails = UserAutoLoginModel(response: Response.fromJson(sessionData.extra!.loginDetails!.toJson()), errorResponses: null);
await provider.buildHubConnection(context: context, ccProvider: cProv).whenComplete(() {
cProv.init();
isCallConnected = true;
});
} catch (e) {
logger.w(e);
}
}
}
// cProv.startRecording();
}
void startIosCall() async {
print("🎈 Call Payload:" + widget.payload!.toRawJson());
// IosCallPayload? iosCallPayload = IosCallPayload.fromRawJson(await Utils.getStringFromPrefs("iosCallPayload"));
IosCallPayload? iosCallPayload = widget.payload;
var userID = iosCallPayload!.incomingCallReciverId;
var callType = iosCallPayload.incomingCallType;
SingleUserChatModel inCallData = SingleUserChatModel(
targetUserName: iosCallPayload.incomingCallerName,
chatEventId: 3,
targetUserId: int.parse(iosCallPayload.incomingCallerId!),
currentUserId: int.parse(userID.toString()),
);
if (provider.isUserOnline) {
AppState().isBackgroundCall = true;
cProv.isUserOnline = provider.isUserOnline;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
}
await cProv.startIncomingCallViaKit(inCallData: inCallData.toJson(), isVCall: callType == "video" ? true : false);
cProv.init();
isCallConnected = true;
} else {
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
AppState().isBackgroundCall = true;
cProv.isUserOnline = provider.isUserOnline;
UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserCallToken(userid: userID.toString());
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
Utils.saveStringFromPrefs("userLoginChatDetails", jsonEncode(userLoginResponse.response));
super.initState();
await cProv.startIncomingCallViaKit(inCallData: inCallData.toJson(), isVCall: callType == "video" ? true : false);
try {
AppState().setchatUserDetails = UserAutoLoginModel(response: userLoginResponse.response, errorResponses: null);
await provider.buildHubConnection(context: context, ccProvider: cProv).whenComplete(() {
cProv.init();
isCallConnected = true;
});
} catch (e) {
logger.w(e);
}
}
}
}
@override
Widget build(BuildContext context) {
cProv = context.read<ChatCallProvider>();
provider = context.read<ChatProviderModel>();
if (!cProv.isOutGoingCall) {
if (Platform.isAndroid) {
startCall();
} else if (Platform.isIOS) {
startIosCall();
}
}
return Scaffold(
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (widget.isVideoCall!)
Positioned.fill(
child: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: CameraPreview(
_controller!,
),
),
),
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.7,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Row(
children: <Widget>[
Image.asset(
"assets/images/logos/main_mohemm_logo.png",
height: 70,
width: 70,
),
Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
extendBody: true,
body: Consumer2<ChatCallProvider, ChatProviderModel>(
builder: (BuildContext context, ChatCallProvider prov, ChatProviderModel cpm, Widget? child) {
return prov.isIncomingCallLoader
? const SizedBox(
width: double.infinity,
height: double.infinity,
child: Center(child: CircularProgressIndicator()),
)
: prov.isIncomingCall
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!prov.isAudioCall && prov.isVideoCall)
RTCVideoView(
prov.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
// filterQuality: FilterQuality.high,
key: const Key('remote'),
),
if (prov.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
intialVisibility: true,
horizontalSpace: 20,
shadowBorderRadius: 50,
initialPosition: AnchoringPosition.topLeft,
dragController: dragController,
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
child: SizedBox(
height: 200,
width: 140,
child: RTCVideoView(
prov.localVideoRenderer!,
mirror: true,
// filterQuality: FilterQuality.high,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!prov.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: const <Widget>[
// todo @aamir, need to use extension mehtods
Text(
"Aamir Saleem Ahmad",
style: TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
),
Text(
"Calling...",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
40.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
SvgPicture.asset(
"assets/images/user.svg",
height: 70,
width: 70,
fit: BoxFit.cover,
),
10.height,
Text(
prov.incomingCallData.targetUserName ?? "",
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
),
const Text(
"On Call",
style: TextStyle(
fontSize: 16,
decoration: TextDecoration.none,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
const SizedBox(
height: 2,
),
],
),
),
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
SizedBox(
height: 2,
],
),
],
),
),
],
),
),
),
// Container(
// margin: const EdgeInsets.all(21.0),
// width: MediaQuery.of(context).size.width,
// decoration: cardRadius(15.0, color: MyColors.black, elevation: null),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// Container(
// padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 6.0),
// child: Text(
// "TranslationBase.of(context).appoInfo",
// style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.white, letterSpacing: -0.64, height: 23 / 12),
// ),
// ),
// Container(
// padding: const EdgeInsets.only(left: 16.0, right: 16.0),
// child: Text(
// "widget.incomingCallData.appointmentdate + widget.incomingCallData.appointmenttime",
// style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600),
// ),
// ),
// Container(
// padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 21.0),
// child: Text(
// "widget.incomingCallData.clinicname",
// style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600),
// ),
// ),
// ],
// ),
// ),
const Spacer(),
Container(
margin: const EdgeInsets.only(
bottom: 70.0,
left: 49,
right: 49,
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.only(
bottom: 20,
left: 40,
right: 40,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RotationTransition(
turns: Tween(
begin: 0.0,
end: -.1,
)
.chain(
CurveTween(
curve: Curves.elasticIn,
),
)
.animate(
_animationController!,
),
child: RawMaterialButton(
// if (provider.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.loudOn();
},
elevation: 2.0,
fillColor: prov.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.camOff();
},
elevation: 2.0,
fillColor: prov.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
_submit();
prov.switchCamera();
},
elevation: 2.0,
fillColor: MyColors.green2DColor,
fillColor: prov.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
15.0,
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call,
child: Icon(
prov.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 35.0,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.micOff();
},
elevation: 2.0,
fillColor: prov.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
backToHome();
prov.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
// print("Reintiiiiiiitttiiiiiiii");
// provider.initStreams();
}
});
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
15.0,
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call_end,
color: MyColors.white,
size: 35.0,
size: 30.0,
),
),
],
),
),
],
),
),
],
),
),
),
),
],
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
void _runAnimation() async {
List<CameraDescription> cameras = await availableCameras();
CameraDescription firstCamera = cameras[1];
_controller = CameraController(
firstCamera,
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller!.initialize();
setState(() {});
// setAudioFile();
for (int i = 0; i < 100; i++) {
await _animationController!.forward();
await _animationController!.reverse();
}
}
Future<void> _submit() async {
try {
// backToHome();
// final roomModel = RoomModel(name: widget.incomingCallData.name, token: widget.incomingCallData.sessionId, identity: widget.incomingCallData.identity);
await _controller?.dispose();
// changeCallStatusAPI(4);
// if (_session != null && _signaling != null) {
// await Navigator.of(context).pushReplacement(
// MaterialPageRoute(
// // fullscreenDialog: true,
// builder: (BuildContext context) {
// // if (widget.incomingCallData.isWebRTC == "true") {
// return StartVideoCall(signaling: _signaling, session: _session);
//
// // else {
// // return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: widget.incomingCallData.sessionId, token: widget.incomingCallData.token);
// // }
//
// // return VideoCallWebPage(receiverId: widget.incomingCallData.receiverID, callerId: widget.incomingCallData.callerID); // Web WebRTC VideoCall
//
// // return CallHomePage(receiverId: widget.incomingCallData.receiverID, callerId: widget.incomingCallData.callerID); // App WebRTC VideoCall
// },
// ),
// );
// } else {
// // Invalid Params/Data
// Utils.showToast("Failed to establish connection with server");
// }
} catch (err) {
print(err);
// await PlatformExceptionAlertDialog(
// exception: err,
// ).show(context);
Utils.showToast(err.toString());
}
}
// void changeCallStatusAPI(int sessionStatus) {
// LiveCareService service = new LiveCareService();
// service.endCallAPI(widget.incomingCallData.sessionId, sessionStatus, context).then((res) {}).catchError((err) {
// print(err);
// });
// }
void backToHome() async {
// final connected = await signaling.declineCall(widget.incomingCallData.callerID, widget.incomingCallData.receiverID);
// LandingPage.isOpenCallPage = false;
// _signaling
_animationController!.dispose();
// player.stop();
// changeCallStatusAPI(3);
// _signaling.bye(_session, callRejected: true);
// _signaling.callDisconnected(_session, callRejected: true);
Navigator.of(context).pop();
}
//
// void disposeAudioResources() async {
// await player.dispose();
// }
//
// void setAudioFile() async {
// player.stop();
// await player.setVolume(1.0); // full volume
// try {
// await player.setAsset('assets/sounds/ring_60Sec.mp3').then((value) {
// player.setLoopMode(LoopMode.one); // loop ring sound
// player.play();
// }).catchError((err) {
// print("Error: $err");
// });
// } catch (e) {
// print("Error: $e");
// }
// }
//
// void connectSignaling({@required bool iAmCaller = false}) async {
// print("----------------- + Signaling Connection Started ---------------------------");
// var caller = widget.incomingCallData.callerID;
// var receiver = widget.incomingCallData.receiverID;
// var host = widget.incomingCallData.server;
//
// var selfRole = iAmCaller ? "Caller" : "Receiver";
// var selfId = iAmCaller ? caller : receiver;
// var selfUser = SocketUser(id: selfId, name: "$selfRole-$selfId", userAgent: DeviceInfo.userAgent, moreInfo: {});
//
// var remoteRole = !iAmCaller ? "Caller" : "Receiver";
// var remoteId = !iAmCaller ? caller : receiver;
// var remoteUser = SocketUser(id: remoteId, name: "$remoteRole-$remoteId", userAgent: DeviceInfo.userAgent, moreInfo: {});
//
// var sessionId = "$caller-$receiver";
// _session = SessionOneToOne(id: sessionId, local_user: selfUser, remote_user: remoteUser);
//
// _signaling = Signaling(host, session: _session);
// await _signaling.connect();
//
// if (_signaling.state == SignalingState.Open) {
// return;
// }
// }
)
: prov.isOutGoingCall
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!prov.isAudioCall && prov.isVideoCall)
RTCVideoView(
prov.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
key: const Key('remote'),
),
if (prov.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
intialVisibility: true,
horizontalSpace: 20,
shadowBorderRadius: 50,
initialPosition: AnchoringPosition.topLeft,
dragController: dragController,
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
child: SizedBox(
height: 200,
width: 140,
child: RTCVideoView(
prov.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!prov.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
40.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
SvgPicture.asset(
"assets/images/user.svg",
height: 70,
width: 70,
fit: BoxFit.cover,
),
10.height,
Text(
prov.outGoingCallData.receiverName!,
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
),
const Text(
"On Call",
style: TextStyle(
fontSize: 16,
decoration: TextDecoration.none,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
const SizedBox(
height: 2,
),
],
),
),
),
],
),
],
),
),
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.only(
bottom: 20,
left: 40,
right: 40,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// if (provider.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.loudOn();
},
elevation: 2.0,
fillColor: prov.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
BoxDecoration cardRadius(double radius, {required Color color, double? elevation}) {
return BoxDecoration(
shape: BoxShape.rectangle,
color: color ?? Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(radius),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.camOff();
},
elevation: 2.0,
fillColor: prov.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
if (prov.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.switchCamera();
},
elevation: 2.0,
fillColor: prov.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.micOff();
},
elevation: 2.0,
fillColor: prov.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
prov.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
prov.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
}
});
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call_end,
color: MyColors.white,
size: 30.0,
),
),
],
),
),
),
],
),
)
: const SizedBox();
},
),
boxShadow: <BoxShadow>[
BoxShadow(
color: const Color(
0xff000000,
).withOpacity(
.05,
),
//spreadRadius: 5,
blurRadius: elevation ?? 27,
offset: const Offset(
-2,
3,
),
),
],
);
}
}
/// if (Platform.isAndroid) {
// SystemNavigator.pop();
// } else if (Platform.isIOS) {
// exit(0);
// }

@ -1,16 +1,14 @@
import 'dart:convert';
import 'dart:ui';
import 'package:camera/camera.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:provider/provider.dart';
class OutGoingCall extends StatefulWidget {
@ -23,407 +21,169 @@ class OutGoingCall extends StatefulWidget {
_OutGoingCallState createState() => _OutGoingCallState();
}
class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderStateMixin {
AnimationController? _animationController;
late CameraController controller;
late List<CameraDescription> _cameras;
Future<void>? _initializeControllerFuture;
bool isCameraReady = false;
bool isMicOff = false;
bool isLoudSpeaker = false;
bool isCamOff = false;
late ChatCallProvider callProviderd;
class _OutGoingCallState extends State<OutGoingCall> {
late ChatCallProvider callProvider;
late ChatProviderModel chatProvider;
bool loader = true;
@override
void initState() {
callProviderd = Provider.of<ChatCallProvider>(context, listen: false);
_animationController = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 500,
),
);
// _runAnimation();
// connectSignaling();
WidgetsBinding.instance.addPostFrameCallback(
(_) => _runAnimation(),
);
super.initState();
}
Future<void> init() async {
widget.isVideoCall ? callProvider.isVideoCall = true : callProvider.isVideoCall = false;
callProvider.isOutGoingCall = true;
callProvider.startTimer();
await callProvider.initLocalCamera(chatProvmodel: chatProvider, callData: widget.outGoingCallData, context: context);
loader = false;
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
chatProvider = Provider.of<ChatProviderModel>(context, listen: false);
callProvider = Provider.of<ChatCallProvider>(context, listen: false);
init();
return Scaffold(
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (widget.isVideoCall)
Positioned.fill(
child: CameraPreview(
controller,
body: Consumer<ChatCallProvider>(builder: (BuildContext context, ChatCallProvider chatcp, Widget? child) {
return loader
? const Center(
child: CircularProgressIndicator(),
)
: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (chatcp.isVideoCall)
Positioned.fill(
child: RTCVideoView(
chatcp.localVideoRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
40.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
SvgPicture.asset(
"assets/images/user.svg",
height: 70,
width: 70,
fit: BoxFit.cover,
),
10.height,
Text(
widget.outGoingCallData.title,
style: const TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
40.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(21.0),
child: Container(
margin: const EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
SvgPicture.asset(
"assets/images/user.svg",
height: 70,
width: 70,
fit: BoxFit.cover,
),
10.height,
Text(
widget.outGoingCallData.receiverName.toString().replaceAll(".", " "),
style: const TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
),
),
const Text(
"Ringing...",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
const Text(
"Ringing...",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
),
letterSpacing: -0.48,
height: 23 / 24,
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
const SizedBox(
height: 2,
),
],
const SizedBox(
height: 2,
),
],
),
),
),
),
],
),
// Container(
// margin: const EdgeInsets.all(21.0),
// width: MediaQuery.of(context).size.width,
// decoration: cardRadius(15.0, color: MyColors.black, elevation: null),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// Container(
// padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 6.0),
// child: Text(
// "TranslationBase.of(context).appoInfo",
// style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.white, letterSpacing: -0.64, height: 23 / 12),
// ),
// ),
// Container(
// padding: const EdgeInsets.only(left: 16.0, right: 16.0),
// child: Text(
// "widget.OutGoingCallData.appointmentdate + widget.OutGoingCallData.appointmenttime",
// style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600),
// ),
// ),
// Container(
// padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 21.0),
// child: Text(
// "widget.OutGoingCallData.clinicname",
// style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600),
// ),
// ),
// ],
// ),
// ),
const Spacer(),
Container(
margin: const EdgeInsets.only(
bottom: 70.0,
left: 49,
right: 49,
],
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
if (widget.isVideoCall)
RawMaterialButton(
onPressed: () {
_camOff();
},
elevation: 2.0,
fillColor: isCamOff ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
15.0,
),
shape: const CircleBorder(),
child: Icon(
isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 35.0,
),
)
else
const Spacer(),
Container(
margin: const EdgeInsets.only(
bottom: 70.0,
left: 49,
right: 49,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () {
_loudOn();
chatcp.endCall(isUserOnline: chatProvider.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
}
});
},
elevation: 2.0,
fillColor: isLoudSpeaker ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
15.0,
),
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(15.0),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
Icons.call_end,
color: MyColors.white,
size: 35.0,
),
),
RawMaterialButton(
onPressed: () {
_micOff();
},
elevation: 2.0,
fillColor: isMicOff ? MyColors.green2DColor : Colors.grey,
padding: const EdgeInsets.all(
15.0,
),
shape: const CircleBorder(),
child: Icon(
isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 35.0,
),
),
RawMaterialButton(
onPressed: () {
backToHome();
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
15.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call_end,
color: MyColors.white,
size: 35.0,
),
),
],
],
),
),
),
],
],
),
),
),
),
),
),
],
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
],
);
}),
);
}
void _runAnimation() async {
_cameras = await availableCameras();
CameraDescription firstCamera = _cameras[1];
controller = CameraController(firstCamera, ResolutionPreset.medium);
_initializeControllerFuture = controller.initialize();
setState(() {});
// setAudioFile();
for (int i = 0; i < 100; i++) {
await _animationController!.forward();
await _animationController!.reverse();
}
}
void _micOff() {
setState(() {
isMicOff = !isMicOff;
});
}
void _camOff() {
setState(() {
isCamOff = !isCamOff;
});
}
void _loudOn() {
setState(() {
isLoudSpeaker = !isLoudSpeaker;
});
}
Future<void> _submit() async {
try {
// backToHome();
// final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity);
await controller?.dispose();
// changeCallStatusAPI(4);
// if (_session != null && _signaling != null) {
// await Navigator.of(context).pushReplacement(
// MaterialPageRoute(
// // fullscreenDialog: true,
// builder: (BuildContext context) {
// // if (widget.OutGoingCallData.isWebRTC == "true") {
// return StartVideoCall(signaling: _signaling, session: _session);
//
// // else {
// // return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: widget.OutGoingCallData.sessionId, token: widget.OutGoingCallData.token);
// // }
//
// // return VideoCallWebPage(receiverId: widget.OutGoingCallData.receiverID, callerId: widget.OutGoingCallData.callerID); // Web WebRTC VideoCall
//
// // return CallHomePage(receiverId: widget.OutGoingCallData.receiverID, callerId: widget.OutGoingCallData.callerID); // App WebRTC VideoCall
// },
// ),
// );
// } else {
// // Invalid Params/Data
// Utils.showToast("Failed to establish connection with server");
// }
} catch (err) {
print(err);
// await PlatformExceptionAlertDialog(
// exception: err,
// ).show(context);
Utils.showToast(err.toString());
}
}
// void changeCallStatusAPI(int sessionStatus) {
// LiveCareService service = new LiveCareService();
// service.endCallAPI(widget.OutGoingCallData.sessionId, sessionStatus, context).then((res) {}).catchError((err) {
// print(err);
// });
// }
void backToHome() async {
// final connected = await signaling.declineCall(widget.OutGoingCallData.callerID, widget.OutGoingCallData.receiverID);
// LandingPage.isOpenCallPage = false;
// _signaling
_animationController!.dispose();
// player.stop();
// changeCallStatusAPI(3);
// _signaling.bye(_session, callRejected: true);
// _signaling.callDisconnected(_session, callRejected: true);
Navigator.of(context).pop();
}
//
// void disposeAudioResources() async {
// await player.dispose();
// }
//
// void setAudioFile() async {
// player.stop();
// await player.setVolume(1.0); // full volume
// try {
// await player.setAsset('assets/sounds/ring_60Sec.mp3').then((value) {
// player.setLoopMode(LoopMode.one); // loop ring sound
// player.play();
// }).catchError((err) {
// print("Error: $err");
// });
// } catch (e) {
// print("Error: $e");
// }
// }
//
// void connectSignaling({@required bool iAmCaller = false}) async {
// print("----------------- + Signaling Connection Started ---------------------------");
// var caller = widget.OutGoingCallData.callerID;
// var receiver = widget.OutGoingCallData.receiverID;
// var host = widget.OutGoingCallData.server;
//
// var selfRole = iAmCaller ? "Caller" : "Receiver";
// var selfId = iAmCaller ? caller : receiver;
// var selfUser = SocketUser(id: selfId, name: "$selfRole-$selfId", userAgent: DeviceInfo.userAgent, moreInfo: {});
//
// var remoteRole = !iAmCaller ? "Caller" : "Receiver";
// var remoteId = !iAmCaller ? caller : receiver;
// var remoteUser = SocketUser(id: remoteId, name: "$remoteRole-$remoteId", userAgent: DeviceInfo.userAgent, moreInfo: {});
//
// var sessionId = "$caller-$receiver";
// _session = SessionOneToOne(id: sessionId, local_user: selfUser, remote_user: remoteUser);
//
// _signaling = Signaling(host, session: _session);
// await _signaling.connect();
//
// if (_signaling.state == SignalingState.Open) {
// return;
// }
// }
BoxDecoration cardRadius(double radius, {required Color color, double? elevation}) {
return BoxDecoration(
shape: BoxShape.rectangle,
color: color ?? Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(radius),
),
boxShadow: <BoxShadow>[
BoxShadow(
color: const Color(
0xff000000,
).withOpacity(
.05,
),
//spreadRadius: 5,
blurRadius: elevation ?? 27,
offset: const Offset(
-2,
3,
),
),
],
borderRadius: BorderRadius.all(Radius.circular(radius)),
boxShadow: <BoxShadow>[BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: elevation ?? 27, offset: const Offset(-2, 3))],
);
}
}

@ -0,0 +1,171 @@
// import 'dart:async';
// import 'dart:io';
// import 'package:flutter/material.dart';
//
// class DraggableCam extends StatefulWidget {
// //final Size availableScreenSize;
// final Widget child;
// final double scaleFactor;
// // final Stream<bool> onButtonBarVisible;
// // final Stream<double> onButtonBarHeight;
//
// const DraggableCam({
// Key? key,
// //@required this.availableScreenSize,
// required this.child,
// // @required this.onButtonBarVisible,
// // @required this.onButtonBarHeight,
//
// /// The portion of the screen the DraggableWidget should use.
// this.scaleFactor = .25,
// }) : assert(scaleFactor != null && scaleFactor > 0 && scaleFactor <= .4),
// // assert(availableScreenSize != null),
// // assert(onButtonBarVisible != null),
// // assert(onButtonBarHeight != null),
// super(key: key);
//
// @override
// _DraggablePublisherState createState() => _DraggablePublisherState();
// }
//
// class _DraggablePublisherState extends State<DraggableCam> {
// bool _isButtonBarVisible = true;
// double _buttonBarHeight = 0;
// late double _width;
// late double _height;
// late double _top;
// late double _left;
// late double _viewPaddingTop;
// late double _viewPaddingBottom;
// final double _padding = 8.0;
// final Duration _duration300ms = const Duration(milliseconds: 300);
// final Duration _duration0ms = const Duration(milliseconds: 0);
// late Duration _duration;
// late StreamSubscription _streamSubscription;
// late StreamSubscription _streamHeightSubscription;
//
// @override
// void initState() {
// super.initState();
// _duration = _duration300ms;
// _width = widget.availableScreenSize.width * widget.scaleFactor;
// _height = _width * (widget.availableScreenSize.height / widget.availableScreenSize.width);
// _top = widget.availableScreenSize.height - (_buttonBarHeight + _padding) - _height;
// _left = widget.availableScreenSize.width - _padding - _width;
//
// _streamSubscription = widget.onButtonBarVisible.listen(_buttonBarVisible);
// _streamHeightSubscription = widget.onButtonBarHeight.listen(_getButtonBarHeight);
// }
//
// @override
// void didChangeDependencies() {
// var mediaQuery = MediaQuery.of(context);
// _viewPaddingTop = mediaQuery.viewPadding.top;
// _viewPaddingBottom = mediaQuery.viewPadding.bottom;
// super.didChangeDependencies();
// }
//
// @override
// void dispose() {
// _streamSubscription.cancel();
// _streamHeightSubscription.cancel();
// super.dispose();
// }
//
// void _getButtonBarHeight(double height) {
// setState(() {
// _buttonBarHeight = height;
// _positionWidget();
// });
// }
//
// void _buttonBarVisible(bool visible) {
// if (!mounted) {
// return;
// }
// setState(() {
// _isButtonBarVisible = visible;
// if (_duration == _duration300ms) {
// // only position the widget when we are not currently dragging it around
// _positionWidget();
// }
// });
// }
//
// @override
// Widget build(BuildContext context) {
// return AnimatedPositioned(
// top: _top,
// left: _left,
// width: _width,
// height: _height,
// duration: _duration,
// child: Listener(
// onPointerDown: (_) => _duration = _duration0ms,
// onPointerMove: (PointerMoveEvent event) {
// setState(() {
// _left = (_left + event.delta.dx).roundToDouble();
// _top = (_top + event.delta.dy).roundToDouble();
// });
// },
// onPointerUp: (_) => _positionWidget(),
// onPointerCancel: (_) => _positionWidget(),
// child: ClippedVideo(
// height: _height,
// width: _width,
// child: widget.child,
// ),
// ),
// );
// }
//
// double _getCurrentStatusBarHeight() {
// if (_isButtonBarVisible) {
// return _viewPaddingTop;
// }
// final _defaultViewPaddingTop = Platform.isIOS ? 20.0 : Platform.isAndroid ? 24.0 : 0.0;
// if (_viewPaddingTop > _defaultViewPaddingTop) {
// // There must be a hardware notch in the display.
// return _viewPaddingTop;
// }
// return 0.0;
// }
//
// double _getCurrentButtonBarHeight() {
// if (_isButtonBarVisible) {
// return _buttonBarHeight + _viewPaddingBottom;
// }
// return _viewPaddingBottom;
// }
//
// void _positionWidget() {
// // Determine the center of the object being dragged so we can decide
// // in which corner the object should be placed.
// var dx = (_width / 2) + _left;
// dx = dx < 0 ? 0 : dx >= widget.availableScreenSize.width ? widget.availableScreenSize.width - 1 : dx;
// var dy = (_height / 2) + _top;
// dy = dy < 0 ? 0 : dy >= widget.availableScreenSize.height ? widget.availableScreenSize.height - 1 : dy;
// final draggableCenter = Offset(dx, dy);
//
// setState(() {
// _duration = _duration300ms;
// if (Rect.fromLTRB(0, 0, widget.availableScreenSize.width / 2, widget.availableScreenSize.height / 2).contains(draggableCenter)) {
// // Top-left
// _top = _getCurrentStatusBarHeight() + _padding;
// _left = _padding;
// } else if (Rect.fromLTRB(widget.availableScreenSize.width / 2, 0, widget.availableScreenSize.width, widget.availableScreenSize.height / 2).contains(draggableCenter)) {
// // Top-right
// _top = _getCurrentStatusBarHeight() + _padding;
// _left = widget.availableScreenSize.width - _padding - _width;
// } else if (Rect.fromLTRB(0, widget.availableScreenSize.height / 2, widget.availableScreenSize.width / 2, widget.availableScreenSize.height).contains(draggableCenter)) {
// // Bottom-left
// _top = widget.availableScreenSize.height - (_getCurrentButtonBarHeight() + _padding) - _height;
// _left = _padding;
// } else if (Rect.fromLTRB(widget.availableScreenSize.width / 2, widget.availableScreenSize.height / 2, widget.availableScreenSize.width, widget.availableScreenSize.height).contains(draggableCenter)) {
// // Bottom-right
// _top = widget.availableScreenSize.height - (_getCurrentButtonBarHeight() + _padding) - _height;
// _left = widget.availableScreenSize.width - _padding - _width;
// }
// });
// }
// }

@ -1,5 +1,4 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -18,9 +17,9 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';
import 'package:video_player/video_player.dart';
class ChatBubble extends StatelessWidget {
ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
@ -82,7 +81,8 @@ class ChatBubble extends StatelessWidget {
}
} else {
Utils.showLoading(context);
Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""));
Uint8List encodedString =
await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 1);
// try {
File sFile = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
if (sFile.path.isEmpty) {
@ -195,20 +195,26 @@ class ChatBubble extends StatelessWidget {
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
currentWaveBubble(context, cItem)
if (fileTypeID == 13 && cItem.voiceController != null) currentWaveBubble(context, cItem),
if (fileTypeID == 16)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
showVideoThumb(context, cItem),
Row(
children: [
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2
)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, size: 16)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, size: 16)
],
),
Align(
@ -300,20 +306,26 @@ class ChatBubble extends StatelessWidget {
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
recipetWaveBubble(context, cItem)
if (fileTypeID == 13 && cItem.voiceController != null) recipetWaveBubble(context, cItem),
if (fileTypeID == 16)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
showVideoThumb(context, cItem),
Row(
children: [
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2
)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, color: Colors.white, size: 16)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, color: Colors.white, size: 16)
],
),
Align(
@ -324,11 +336,7 @@ class ChatBubble extends StatelessWidget {
),
],
),
).paddingOnly(right: MediaQuery.of(context).size.width * 0.3);
}
Widget voiceMsg(BuildContext context) {
return Container();
).paddingOnly(right: MediaQuery.of(context).size.width * 0.33);
}
Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) {
@ -342,7 +350,7 @@ class ChatBubble extends StatelessWidget {
);
} else {
return FutureBuilder<Uint8List>(
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription),
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource: 1),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
if (snapshot.data == null) {
@ -470,4 +478,50 @@ class ChatBubble extends StatelessWidget {
},
);
}
Widget showVideoThumb(BuildContext context, SingleUserChatModel data) {
return LoadVideo(data: data);
}
}
class LoadVideo extends StatefulWidget {
final SingleUserChatModel data;
const LoadVideo({Key? key, required this.data}) : super(key: key);
@override
State<LoadVideo> createState() => _LoadVideoState();
}
class _LoadVideoState extends State<LoadVideo> {
late VideoPlayerController videoController;
@override
void initState() {
videoController = VideoPlayerController.networkUrl(Uri.parse('https://apiderichat.hmg.com/attachments/${widget.data.fileTypeResponse?.fileName}'))..initialize().then((_) {});
super.initState();
}
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: AspectRatio(
aspectRatio: videoController.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(videoController),
Align(
alignment: Alignment.center,
child: Icon(
Icons.play_arrow,
color: Colors.white.withOpacity(.7),
size: 56,
),
)
],
),
));
}
}

@ -1,5 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -10,22 +10,20 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart';
import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart';
import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:swipe_to/swipe_to.dart';
class ChatDetailedScreenParams {
@ -78,7 +76,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
Widget build(BuildContext context) {
params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams;
data = Provider.of<ChatProviderModel>(context, listen: false);
// callPro = Provider.of<ChatCallProvider>(context, listen: false);
callPro = Provider.of<ChatCallProvider>(context, listen: false);
if (params != null) {
data.getSingleUserChatHistory(
senderUID: AppState().chatDetails!.response!.id!.toInt(),
@ -98,14 +96,32 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
showTyping: true,
chatUser: params!.chatUser,
actions: [
// SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() {
// makeCall(callType: "AUDIO");
// }),
// 24.width,
// SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() {
// makeCall(callType: "VIDEO");
// }),
// 21.width,
// if (Platform.isAndroid)
SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() async {
Future<PermissionStatus> micPer = Permission.microphone.request();
if (await micPer.isGranted) {
makeCall(callType: "AUDIO");
} else {
Permission.microphone.request().isGranted.then((value) {
makeCall(callType: "AUDIO");
});
}
}),
// if (Platform.isAndroid)
24.width,
// if (Platform.isAndroid)
SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() async {
Future<PermissionStatus> camPer = Permission.camera.request();
Future<PermissionStatus> micPer = Permission.microphone.request();
if (await camPer.isGranted && await micPer.isGranted) {
makeCall(callType: "VIDEO");
} else {
if (await Permission.camera.request().isGranted && await Permission.microphone.isGranted) makeCall(callType: "VIDEO");
}
}),
// if (Platform.isAndroid)
21.width,
],
),
body: SafeArea(
@ -149,17 +165,19 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
);
},
).onPress(() async {
logger.w(m.userChatHistory[i].toJson());
// logger.w(m.userChatHistory[i].toJson());
if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) {
if (m.userChatHistory[i].fileTypeId! == 1 ||
m.userChatHistory[i].fileTypeId! == 5 ||
m.userChatHistory[i].fileTypeId! == 7 ||
m.userChatHistory[i].fileTypeId! == 6 ||
m.userChatHistory[i].fileTypeId! == 8
// || m.userChatHistory[i].fileTypeId! == 2
) {
m.userChatHistory[i].fileTypeId! == 5 ||
m.userChatHistory[i].fileTypeId! == 7 ||
m.userChatHistory[i].fileTypeId! == 6 ||
m.userChatHistory[i].fileTypeId! == 8 ||
m.userChatHistory[i].fileTypeId! == 16) {
m.getChatMedia(context,
fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!);
fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "",
fileTypeID: m.userChatHistory[i].fileTypeId!,
fileName: m.userChatHistory[i].contant!,
fileSource: 1);
}
}
});
@ -352,29 +370,21 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
}
void makeCall({required String callType}) async {
callPro.initCallListeners();
print("================== Make call Triggered ============================");
Map<String, dynamic> json = {
"callerID": AppState().chatDetails!.response!.id!.toString(),
"callerDetails": AppState().chatDetails!.toJson(),
"receiverID": params!.chatUser!.id.toString(),
"receiverDetails": params!.chatUser!.toJson(),
"callerID": AppState().chatDetails!.response!.id,
"callerName": AppState().chatDetails!.response!.userName,
"callerEmail": AppState().chatDetails!.response!.email,
"callerTitle": AppState().chatDetails!.response!.title,
"callerPhone": AppState().chatDetails!.response!.phone,
"receiverID": params!.chatUser!.id,
"receiverName": params!.chatUser!.userName,
"receiverEmail": params!.chatUser!.email,
"receiverTitle": params!.chatUser!.title,
"receiverPhone": params!.chatUser!.phone,
"title": params!.chatUser!.userName!.replaceAll(".", " "),
"calltype": callType == "VIDEO" ? "Video" : "Audio",
"callType": callType == "VIDEO" ? "Video" : "Audio",
};
logger.w(json);
CallDataModel callData = CallDataModel.fromJson(json);
await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => OutGoingCall(
isVideoCall: callType == "VIDEO" ? true : false,
outGoingCallData: callData,
),
),
).then((value) {
print("then");
callPro.stopListeners();
});
await Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => OutGoingCall(isVideoCall: callType == "VIDEO" ? true : false, outGoingCallData: callData)));
}
}

@ -2,17 +2,17 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_home_screen.dart';
import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat.dart';
import 'package:mohem_flutter_app/ui/chat/my_team_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:provider/provider.dart';
import 'package:signalr_netcore/signalr_client.dart';
@ -28,12 +28,15 @@ class _ChatHomeState extends State<ChatHome> {
int tabIndex = 0;
PageController controller = PageController();
late ChatProviderModel data;
late ChatCallProvider callProvider;
@override
void initState() {
super.initState();
data = Provider.of<ChatProviderModel>(context, listen: false);
callProvider = Provider.of<ChatCallProvider>(context, listen: false);
data.registerEvents();
// callProvider.initCallListeners();
}
@override
@ -43,23 +46,16 @@ class _ChatHomeState extends State<ChatHome> {
}
void fetchAgain() {
if (chatHubConnection.state != HubConnectionState.Connected) {
if (chatHubConnection!.state != HubConnectionState.Connected) {
data.getUserAutoLoginToken().whenComplete(() async {
await data.buildHubConnection();
await data.buildHubConnection(context: context, ccProvider: callProvider);
data.getUserRecentChats();
});
return;
}
if (data.searchedChats == null || data.searchedChats!.isEmpty) {
data.isLoading = true;
data.getUserRecentChats().whenComplete(() async {
// String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
// String notificationData = await Utils.getStringFromPrefs("notificationData");
// if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") {
// data.openChatByNoti(context);
// }
});
data.getUserRecentChats().whenComplete(() async {});
}
}
@ -68,7 +64,7 @@ class _ChatHomeState extends State<ChatHome> {
fetchAgain();
return Scaffold(
backgroundColor: MyColors.white,
appBar: AppBarWidget(context, title: LocaleKeys.chat.tr(), showHomeButton: true),
appBar: AppBarWidget(context, title: LocaleKeys.chat.tr(), showHomeButton: true, isBackButton: false),
body: Column(
children: <Widget>[
Container(
@ -91,7 +87,7 @@ class _ChatHomeState extends State<ChatHome> {
child: Row(
children: <Widget>[
myTab(LocaleKeys.mychats.tr(), 0),
// myTab(LocaleKeys.group.tr(), 1),
myTab(LocaleKeys.group.tr(), 1),
myTab(LocaleKeys.favorite.tr(), 2),
AppState().getempStatusIsManager ? myTab(LocaleKeys.myTeam.tr(), 3) : const SizedBox(),
],
@ -107,7 +103,7 @@ class _ChatHomeState extends State<ChatHome> {
},
children: <Widget>[
ChatHomeScreen(),
// GropChatHomeScreen(),
GropChatHomeScreen(),
ChatFavoriteUsersScreen(),
AppState().getempStatusIsManager ? const MyTeamScreen() : const SizedBox(),
],

@ -1,7 +1,5 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
@ -15,7 +13,6 @@ import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class ChatHomeScreen extends StatefulWidget {
const ChatHomeScreen({Key? key}) : super(key: key);
@ -154,16 +151,9 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
alignment: Alignment.center,
width: 18,
height: 18,
decoration: const BoxDecoration(
color: MyColors.redColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: (m.searchedChats![index].unreadMessageCount!.toString())
.toText10(
color: MyColors.white,
)
decoration: const BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.all(Radius.circular(22))),
child: (m.searchedChats![index].unreadMessageCount! >= 10 ? "10+" : m.searchedChats![index].unreadMessageCount!.toString())
.toText10(color: MyColors.white)
.center,
).paddingOnly(right: 10).center,
Icon(
@ -172,22 +162,14 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
).onPress(
() {
if (m.searchedChats![index].isFav == null || m.searchedChats![index].isFav == false) {
m.favoriteUser(
userID: AppState().chatDetails!.response!.id!,
targetUserID: m.searchedChats![index].id!,
fromSearch: false
);
m.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: m.searchedChats![index].id!, fromSearch: false);
} else if (m.searchedChats![index].isFav == true) {
m.unFavoriteUser(
userID: AppState().chatDetails!.response!.id!,
targetUserID: m.searchedChats![index].id!,
);
} else {
m.favoriteUser(
userID: AppState().chatDetails!.response!.id!,
targetUserID: m.searchedChats![index].id!,
fromSearch: false
);
m.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: m.searchedChats![index].id!, fromSearch: false);
}
},
).center
@ -217,9 +199,10 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
child: Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
//shape: BoxShape.circle,
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
@ -187,3 +188,40 @@ class WaveBubble extends StatelessWidget {
);
}
}
class CallTimer extends StatefulWidget {
const CallTimer({Key? key}) : super(key: key);
@override
State<CallTimer> createState() => _CallTimerState();
}
class _CallTimerState extends State<CallTimer> {
late Timer _timer;
int _timeExpandedBySeconds = 0;
@override
void initState() {
// TODO: implement initState
super.initState();
_timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
setState(() {
_timeExpandedBySeconds += 1;
});
});
}
@override
Widget build(BuildContext context) {
return Text(
_timeExpandedBySeconds.toString(),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
);
}
}

@ -36,7 +36,6 @@ class CreateGroupBottomSheet extends StatefulWidget {
Function(ReplacementList) onSelectEmployee;
bool fromChat;
groups.GroupResponse groupDetails;
CreateGroupBottomSheet({
Key? key,
required this.title,
@ -77,7 +76,8 @@ class _CreateGroupBottomSheetState extends State<CreateGroupBottomSheet> {
int _selectedSearchIndex = 0;
List<ChatUser> selectedUsers = [];
List<ChatUser> addedUser = [];
List<ChatUser> removedUser = [];
void fetchUserByInput({bool isNeedLoading = true}) async {
try {
Utils.showLoading(context);
@ -397,6 +397,8 @@ class _CreateGroupBottomSheetState extends State<CreateGroupBottomSheet> {
if (user.isNotEmpty) {
user.first.isChecked = false;
}
selectedUsers[index2].userAction =2;
removedUser.add(selectedUsers[index2]);
selectedUsers.remove(
selectedUsers[index2]);
});
@ -535,8 +537,12 @@ class _CreateGroupBottomSheetState extends State<CreateGroupBottomSheet> {
if (provider.chatUsersList![index]
.isChecked ==
true) {
provider
.chatUsersList![index].userAction =1;
selectedUsers.add(provider
.chatUsersList![index]);
} else {
selectedUsers.remove(provider
.chatUsersList![index]);
@ -677,7 +683,7 @@ class _CreateGroupBottomSheetState extends State<CreateGroupBottomSheet> {
admin.totalCount = 0;
mainUsers.add(admin);
CreateGroupRequest request = CreateGroupRequest(
groupUserList: [...selectedUsers, ...mainUsers].toList(),
groupUserList: [...selectedUsers, ...mainUsers, ...removedUser].toList(),
canArchive: false,
isMeeting: false,
canShareS: isShareScreen,

@ -1,28 +1,20 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart';
import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart';
import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/ui/chat/create_group.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart';
import 'package:mohem_flutter_app/ui/chat/manage_group.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class GropChatHomeScreen extends StatefulWidget {
const GropChatHomeScreen({Key? key}) : super(key: key);
@ -59,26 +51,17 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
children: <Widget>[
TextField(
controller: m.searchGroup,
style: const TextStyle(
color: MyColors.darkTextColor,
fontWeight: FontWeight.w500,
fontSize: 12),
style: const TextStyle(color: MyColors.darkTextColor, fontWeight: FontWeight.w500, fontSize: 12),
onChanged: (String val) {
m.filterGroups(val);
},
decoration: InputDecoration(
border: fieldBorder(radius: 5, color: 0xFFE5E5E5),
focusedBorder:
fieldBorder(radius: 5, color: 0xFFE5E5E5),
enabledBorder:
fieldBorder(radius: 5, color: 0xFFE5E5E5),
focusedBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5),
enabledBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5),
contentPadding: const EdgeInsets.all(11),
hintText: LocaleKeys.searchGroup.tr(),
hintStyle: const TextStyle(
color: MyColors.lightTextColor,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w500,
fontSize: 12),
hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic, fontWeight: FontWeight.w500, fontSize: 12),
filled: true,
fillColor: MyColors.greyF7Color,
suffixIconConstraints: const BoxConstraints(),
@ -112,70 +95,53 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
border: Border.all(
width: 1, color: Colors.black),
border: Border.all(width: 1, color: Colors.black),
),
child: SvgPicture.asset(
"assets/images/chat-group.svg",
)),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
(m.uGroups![index]
.groupName!
.toText14(
color: MyColors.darkTextColor)
.paddingOnly(left: 11, top: 16))!,
]),
Column(mainAxisAlignment: MainAxisAlignment.start, children: [
(m.uGroups![index].groupName!.toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 16)),
]),
Align(
alignment: Alignment.centerRight,
child: PopupMenuButton(
onSelected: (String value){
goToSelected(m.uGroups![index], m, value);
},
itemBuilder: (context) => [
PopupMenuItem<String>(
value: '1',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.edit
.tr()
.toText14(color: m.userGroups?.groupresponse![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '2',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.delete
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '3',
enabled: m.uGroups![index].isAdmin ?? false,
onTap: () {
},
child: (LocaleKeys.manage
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '4',
child: (LocaleKeys.members
.tr()
.toText14(color: MyColors.darkTextColor)
.paddingOnly(left: 11, top: 16))),
],
)
)
.expanded
alignment: Alignment.centerRight,
child: PopupMenuButton(
onSelected: (String value) {
goToSelected(m.uGroups![index], m, value);
},
itemBuilder: (context) => [
PopupMenuItem<String>(
value: '1',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.edit
.tr()
.toText14(color: m.userGroups.groupresponse![index].isAdmin == true ? MyColors.darkTextColor : MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '2',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.delete
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor : MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '3',
enabled: m.uGroups![index].isAdmin ?? false,
onTap: () {},
child: (LocaleKeys.manage
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor : MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(value: '4', child: (LocaleKeys.members.tr().toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 16))),
],
)).expanded
],
),
).onPress(() {
chatDetails(m.uGroups![index], m,);
chatDetails(
m.uGroups![index],
m,
);
// Navigator.pushNamed(
// context,
// AppRoutes.chatDetailed,
@ -187,9 +153,7 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
// });
});
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(color: MyColors.black)
.paddingOnly(left: 59),
separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.black).paddingOnly(left: 59),
).expanded,
],
).paddingOnly(left: 21, right: 21);
@ -199,9 +163,10 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
child: Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
// shape: BoxShape.circle,
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
@ -218,16 +183,15 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
),
),
onPressed: () async {
showMyBottomSheet(
context,
callBackFunc: () {},
child: CreateGroupBottomSheet(
title:LocaleKeys.addUsers.tr(),
title: LocaleKeys.addUsers.tr(),
apiMode: LocaleKeys.delegate.tr(),
fromChat: true,
onSelectEmployee: (ReplacementList _selectedEmployee) {},
groupDetails:GroupResponse(),
groupDetails: GroupResponse(),
),
);
},
@ -244,30 +208,32 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
);
}
void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value) {
switch(value) {
case '1':
void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value) {
switch (value) {
case '1':
editGroup(groupDetails, m);
break;
case '2':
deleteGroup(groupDetails, m, context);
break;
case '3':
Navigator.pushNamed(context,
case '2':
deleteGroup(groupDetails, m, context);
break;
case '3':
Navigator.pushNamed(
context,
AppRoutes.manageGroup,
arguments: groupDetails ,
);
break;
case '4':
Navigator.pushNamed(context,
AppRoutes.groupMembers,
arguments: groupDetails!.groupUserList,
);
break;
}
arguments: groupDetails,
);
break;
case '4':
Navigator.pushNamed(
context,
AppRoutes.groupMembers,
arguments: groupDetails!.groupUserList,
);
break;
}
}
void deleteGroup(
GroupResponse? groupDetails, ChatProviderModel m, BuildContext context) {
void deleteGroup(GroupResponse? groupDetails, ChatProviderModel m, BuildContext context) {
groupDetails!.groupUserList;
Utils.confirmDialog(
context,
@ -280,28 +246,22 @@ void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value
}
Future<void> chatDetails(GroupResponse? groupDetails, ChatProviderModel m) async {
// await m.getGroupChatHistory(groupDetails!);
// await m.getGroupChatHistory(groupDetails!);
Navigator.pushNamed(context,
AppRoutes.groupChatDetailed,
arguments:
GroupChatDetailedScreenParams(
groupDetails,
false));
Navigator.pushNamed(context, AppRoutes.groupChatDetailed, arguments: GroupChatDetailedScreenParams(groupDetails, false));
}
Future<void> editGroup(GroupResponse? groupDetails, ChatProviderModel m) async {
showMyBottomSheet(
context,
callBackFunc: () {},
child: CreateGroupBottomSheet(
title:LocaleKeys.editGroups.tr(),
title: LocaleKeys.editGroups.tr(),
apiMode: LocaleKeys.delegate.tr(),
fromChat: true,
onSelectEmployee: (ReplacementList _selectedEmployee) {},
groupDetails: groupDetails!,
),
);
}
}

@ -1,5 +1,4 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -19,13 +18,12 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';
import 'package:video_player/video_player.dart';
class GroupChatBubble extends StatelessWidget {
GroupChatBubble({Key? key, required this.dateTime, required this.cItem})
: super(key: key);
GroupChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
final String dateTime;
final GetGroupChatHistoryAsync cItem;
@ -52,27 +50,15 @@ class GroupChatBubble extends StatelessWidget {
late Offset screenOffset;
void makeAssign() {
isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id
? true
: false;
isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id ? true : false;
isSeen = cItem.isSeen == true ? true : false;
isReplied = cItem.groupChatReplyResponse != null ? true : false;
// isVoice = cItem.fileTypeId == 13 && cItem.voiceController != null ? true : false;
fileTypeID = cItem.fileTypeId;
fileTypeName = cItem.fileTypeResponse != null
? cItem.fileTypeResponse!.fileTypeName
: "";
fileTypeDescription = cItem.fileTypeResponse != null
? cItem.fileTypeResponse!.fileTypeDescription
: "";
isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id &&
cItem.isDelivered == true
? true
: false;
userName = AppState().chatDetails!.response!.userName ==
cItem.currentUserName.toString()
? "You"
: cItem.currentUserName.toString();
fileTypeName = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeName : "";
fileTypeDescription = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeDescription : "";
isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && cItem.isDelivered == true ? true : false;
userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString();
}
void playVoice(
@ -81,8 +67,7 @@ class GroupChatBubble extends StatelessWidget {
}) async {
if (data.voice != null && data.voice!.existsSync()) {
if (Platform.isIOS) {
Duration? duration = await data.voiceController!
.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
Duration? duration = await data.voiceController!.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
await data.voiceController!.seek(duration);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.setVolume(1.0);
@ -97,13 +82,10 @@ class GroupChatBubble extends StatelessWidget {
}
} else {
Utils.showLoading(context);
Uint8List encodedString = await ChatApiClient().downloadURL(
fileName: data.contant!,
fileTypeDescription: provider.getFileTypeDescription(
data.fileTypeResponse!.fileTypeName ?? ""));
Uint8List encodedString =
await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 2);
// try {
File sFile = await provider.downChatVoice(
encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
File sFile = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
if (sFile.path.isEmpty) {
logger.d("Path Is Emptyyyyyyy");
} else {
@ -112,8 +94,7 @@ class GroupChatBubble extends StatelessWidget {
data.voice = sFile;
if (Platform.isIOS) {
logger.d("isIOS");
Duration? duration = await data.voiceController!
.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
Duration? duration = await data.voiceController!.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
await data.voiceController!.seek(duration);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.setVolume(1.0);
@ -121,8 +102,7 @@ class GroupChatBubble extends StatelessWidget {
Utils.hideLoading(context);
data.voiceController!.play();
} else {
Duration? duration =
await data.voiceController!.setFilePath(sFile.path);
Duration? duration = await data.voiceController!.setFilePath(sFile.path);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.seek(duration);
Utils.hideLoading(context);
@ -131,8 +111,7 @@ class GroupChatBubble extends StatelessWidget {
}
}
void pausePlaying(BuildContext context,
{required SingleUserChatModel data}) async {
void pausePlaying(BuildContext context, {required SingleUserChatModel data}) async {
await data.voiceController!.pause();
}
@ -143,14 +122,8 @@ class GroupChatBubble extends StatelessWidget {
}
}
Stream<PositionData> get _positionDataStream =>
Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(
cItem.voiceController!.positionStream,
cItem.voiceController!.bufferedPositionStream,
cItem.voiceController!.durationStream,
(Duration position, Duration bufferedPosition, Duration? duration) =>
PositionData(
position, bufferedPosition, duration ?? Duration.zero));
Stream<PositionData> get _positionDataStream => Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(cItem.voiceController!.positionStream, cItem.voiceController!.bufferedPositionStream,
cItem.voiceController!.durationStream, (Duration position, Duration bufferedPosition, Duration? duration) => PositionData(position, bufferedPosition, duration ?? Duration.zero));
@override
Widget build(BuildContext context) {
@ -172,49 +145,26 @@ class GroupChatBubble extends StatelessWidget {
width: double.infinity,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color: isCurrentUser
? MyColors.gradiantStartColor
: MyColors.white),
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(userName)
.toText12(
color: MyColors.gradiantStartColor, isBold: false)
.paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
(userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
Directionality(
textDirection: provider.getTextDirection(
cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: ""),
child: (cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: "")
.toText10(
color: isCurrentUser
? MyColors.grey71Color
: MyColors.white.withOpacity(0.5),
isBold: false,
maxlines: 4)
textDirection: provider.getTextDirection(cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : ""),
child: (cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : "")
.toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4)
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
),
],
).expanded,
if (cItem.groupChatReplyResponse != null)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 ||
cItem.groupChatReplyResponse!.fileTypeId == 3 ||
cItem.groupChatReplyResponse!.fileTypeId == 4)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 || cItem.groupChatReplyResponse!.fileTypeId == 3 || cItem.groupChatReplyResponse!.fileTypeId == 4)
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: SizedBox(
@ -222,13 +172,8 @@ class GroupChatBubble extends StatelessWidget {
width: 32,
child: showImage(
isReplyPreview: false,
fileName:
cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem
.groupChatReplyResponse!
.fileTypeResponse!
.fileTypeDescription ??
"image/jpg")),
fileName: cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem.groupChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg")),
).paddingOnly(left: 10, right: 10, bottom: 16, top: 16),
],
),
@ -246,46 +191,35 @@ class GroupChatBubble extends StatelessWidget {
isReplyPreview: false,
fileName: cItem.contant!,
fileTypeDescription:
cItem.fileTypeResponse!.fileTypeDescription)
cItem.fileTypeResponse != null && cItem.fileTypeResponse!.fileTypeDescription != null ? cItem.fileTypeResponse!.fileTypeDescription : cItem.fileTypeResponse!.fileTypeName)
.onPress(() {
showDialog(
context: context,
anchorPoint: screenOffset,
builder: (BuildContext context) => ChatImagePreviewScreen(
imgTitle: cItem.contant!, img: cItem.image!),
builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!),
);
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
currentWaveBubble(context, cItem)
if (fileTypeID == 13 && cItem.voiceController != null) currentWaveBubble(context, cItem),
if (fileTypeID == 16)
Column(
children: [
showVideoThumb(context, cItem),
Row(
children: [
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""),
height: 30,
width: 22,
alignment: Alignment.center,
fit: BoxFit.cover)
.paddingOnly(left: 0, right: 10),
Directionality(
textDirection: provider.getTextDirection(cItem.contant ?? ""),
child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, size: 16)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, size: 16)
],
),
Align(
@ -297,32 +231,24 @@ class GroupChatBubble extends StatelessWidget {
color: MyColors.grey41Color.withOpacity(.5),
),
7.width,
Icon(isDelivered ? Icons.done_all : Icons.done_all,
color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor,
size: 14),
Icon(isDelivered ? Icons.done_all : Icons.done_all, color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, size: 14),
],
),
),
],
)
.paddingOnly(top: 11, left: 13, right: 13, bottom: 5)
.objectContainerView(disablePadding: true)
.paddingOnly(left: MediaQuery.of(context).size.width * 0.3);
).paddingOnly(top: 11, left: 13, right: 13, bottom: 5).objectContainerView(disablePadding: true).paddingOnly(left: MediaQuery.of(context).size.width * 0.3);
}
Widget receiptUser(BuildContext context) {
return Container(
padding: const EdgeInsets.only(top: 5, left: 8, right: 13, bottom: 5),
padding: const EdgeInsets.only(top: 11, left: 13, right: 13, bottom: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: const LinearGradient(
transform: GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: <Color>[
MyColors.gradiantEndColor,
MyColors.gradiantStartColor
],
colors: <Color>[MyColors.gradiantEndColor, MyColors.gradiantStartColor],
),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
@ -332,51 +258,25 @@ class GroupChatBubble extends StatelessWidget {
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color: isCurrentUser
? MyColors.gradiantStartColor
: MyColors.white)),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
border: Border(left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white)),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(userName)
.toText12(
color: MyColors.gradiantStartColor,
isBold: false)
.paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
(userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
Directionality(
textDirection: provider.getTextDirection(
cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: ""),
child: (cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: "")
.toText10(
color: isCurrentUser
? MyColors.grey71Color
: MyColors.white.withOpacity(0.5),
isBold: false,
maxlines: 4)
.paddingOnly(
right: 5, top: 5, bottom: 8, left: 5),
textDirection: provider.getTextDirection(cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : ""),
child: (cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : "")
.toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4)
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
),
],
).expanded,
if (cItem.groupChatReplyResponse != null)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 ||
cItem.groupChatReplyResponse!.fileTypeId == 3 ||
cItem.groupChatReplyResponse!.fileTypeId == 4)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 || cItem.groupChatReplyResponse!.fileTypeId == 3 || cItem.groupChatReplyResponse!.fileTypeId == 4)
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: SizedBox(
@ -384,13 +284,8 @@ class GroupChatBubble extends StatelessWidget {
width: 32,
child: showImage(
isReplyPreview: true,
fileName:
cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem
.groupChatReplyResponse!
.fileTypeResponse!
.fileTypeDescription ??
"image/jpg"),
fileName: cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem.groupChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"),
),
).paddingOnly(left: 10, right: 10, bottom: 16, top: 16)
],
@ -405,82 +300,55 @@ class GroupChatBubble extends StatelessWidget {
child: SizedBox(
height: 140,
width: 227,
child: showImage(
isReplyPreview: false,
fileName: cItem.contant ?? "",
fileTypeDescription:
cItem.fileTypeResponse!.fileTypeDescription ??
"image/jpg")
.onPress(() {
child: showImage(isReplyPreview: false, fileName: cItem.contant ?? "", fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription ?? "image/jpg").onPress(() {
showDialog(
context: context,
anchorPoint: screenOffset,
builder: (BuildContext context) => ChatImagePreviewScreen(
imgTitle: cItem.contant ?? "", img: cItem.image!),
builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant ?? "", img: cItem.image!),
);
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
recipetWaveBubble(context, cItem)
else
if (fileTypeID == 13 && cItem.voiceController != null) recipetWaveBubble(context, cItem),
if (fileTypeID == 16)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
cItem.currentUserName!.toText10(
color: Colors.black,
).paddingOnly(bottom: 5),
showVideoThumb(context, cItem),
Row(
children: [
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""),
height: 30,
width: 22,
alignment: Alignment.center,
fit: BoxFit.cover)
.paddingOnly(left: 0, right: 10),
Directionality(
textDirection:
provider.getTextDirection(cItem.contant ?? ""),
child: (cItem.contant ?? "")
.toText12(color: Colors.white)
.expanded),
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye,
color: Colors.white, size: 16)
],
),
Align(
alignment: Alignment.topRight,
child: dateTime.toText10(
color: Colors.white.withOpacity(.71),
).paddingOnly(top:5),
),
const Icon(Icons.remove_red_eye, color: Colors.white, size: 16)
],
),
])).paddingOnly(right: MediaQuery.of(context).size.width * 0.3);
Align(
alignment: Alignment.centerRight,
child: dateTime.toText10(
color: Colors.white.withOpacity(.71),
),
),
])).paddingOnly(right: MediaQuery.of(context).size.width * 0.33);
}
Widget voiceMsg(BuildContext context) {
return Container();
}
Widget showImage(
{required bool isReplyPreview,
required String fileName,
required String fileTypeDescription}) {
Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) {
if (cItem.isImageLoaded != null && cItem.image != null) {
return Image.memory(
cItem.image!,
@ -491,8 +359,7 @@ class GroupChatBubble extends StatelessWidget {
);
} else {
return FutureBuilder<Uint8List>(
future: ChatApiClient().downloadURL(
fileName: fileName, fileTypeDescription: fileTypeDescription),
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource: 2),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
if (snapshot.data == null) {
@ -519,20 +386,14 @@ class GroupChatBubble extends StatelessWidget {
}
}
Widget currentWaveBubble(
BuildContext context, GetGroupChatHistoryAsync data) {
Widget currentWaveBubble(BuildContext context, GetGroupChatHistoryAsync data) {
return Container(
margin: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color:
isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
children: [
@ -540,14 +401,12 @@ class GroupChatBubble extends StatelessWidget {
// getPlayer(player: data.voiceController!, modelData: data),
StreamBuilder<PositionData>(
stream: _positionDataStream,
builder:
(BuildContext context, AsyncSnapshot<PositionData> snapshot) {
builder: (BuildContext context, AsyncSnapshot<PositionData> snapshot) {
PositionData? positionData = snapshot.data;
return SeekBar(
duration: positionData?.duration ?? Duration.zero,
position: positionData?.position ?? Duration.zero,
bufferedPosition:
positionData?.bufferedPosition ?? Duration.zero,
bufferedPosition: positionData?.bufferedPosition ?? Duration.zero,
onChangeEnd: data.voiceController!.seek,
).expanded;
},
@ -557,20 +416,18 @@ class GroupChatBubble extends StatelessWidget {
).circle(5);
}
Widget recipetWaveBubble(
BuildContext context, GetGroupChatHistoryAsync data) {
Widget showVideoThumb(BuildContext context, GetGroupChatHistoryAsync data) {
return LoadVideo(data: data);
}
Widget recipetWaveBubble(BuildContext context, GetGroupChatHistoryAsync data) {
return Container(
margin: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color:
isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
mainAxisSize: MainAxisSize.max,
@ -579,14 +436,12 @@ class GroupChatBubble extends StatelessWidget {
//getPlayer(player: data.voiceController!, modelData: data),
StreamBuilder<PositionData>(
stream: _positionDataStream,
builder:
(BuildContext context, AsyncSnapshot<PositionData> snapshot) {
builder: (BuildContext context, AsyncSnapshot<PositionData> snapshot) {
PositionData? positionData = snapshot.data;
return SeekBar(
duration: positionData?.duration ?? Duration.zero,
position: positionData?.position ?? Duration.zero,
bufferedPosition:
positionData?.bufferedPosition ?? Duration.zero,
bufferedPosition: positionData?.bufferedPosition ?? Duration.zero,
onChangeEnd: data.voiceController!.seek,
).expanded;
},
@ -596,16 +451,14 @@ class GroupChatBubble extends StatelessWidget {
).circle(5);
}
Widget getPlayer(
{required AudioPlayer player, required SingleUserChatModel modelData}) {
Widget getPlayer({required AudioPlayer player, required SingleUserChatModel modelData}) {
return StreamBuilder<PlayerState>(
stream: player.playerStateStream,
builder: (BuildContext context, AsyncSnapshot<PlayerState> snapshot) {
PlayerState? playerState = snapshot.data;
ProcessingState? processingState = playerState?.processingState;
bool? playing = playerState?.playing;
if (processingState == ProcessingState.loading ||
processingState == ProcessingState.buffering) {
if (processingState == ProcessingState.loading || processingState == ProcessingState.buffering) {
return Container(
margin: const EdgeInsets.all(8.0),
width: 30.0,
@ -641,3 +494,45 @@ class GroupChatBubble extends StatelessWidget {
);
}
}
class LoadVideo extends StatefulWidget {
final GetGroupChatHistoryAsync data;
const LoadVideo({Key? key, required this.data}) : super(key: key);
@override
State<LoadVideo> createState() => _LoadVideoState();
}
class _LoadVideoState extends State<LoadVideo> {
late VideoPlayerController videoController;
@override
void initState() {
videoController = VideoPlayerController.networkUrl(Uri.parse('https://apiderichat.hmg.com/groupattachments/${widget.data.fileTypeResponse?.fileName}'))..initialize().then((_) {});
super.initState();
}
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: AspectRatio(
aspectRatio: videoController.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(videoController),
Align(
alignment: Alignment.center,
child: Icon(
Icons.play_arrow,
color: Colors.white.withOpacity(.7),
size: 56,
),
)
],
),
));
}
}

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -11,24 +12,17 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart';
import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat_bubble.dart';
import 'package:mohem_flutter_app/widgets/chat_app_bar_widge.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:swipe_to/swipe_to.dart';
class GroupChatDetailedScreenParams {
@ -58,11 +52,11 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
data.paginationVal = data.paginationVal + 10;
if (params != null) {
data.getGroupChatHistory(params!.groupChatDetails!
// senderUID: AppState().chatDetails!.response!.id!.toInt(),
// receiverUID: params!.groupChatDetails!.groupId!,
// loadMore: true,
// isNewChat: false,
);
// senderUID: AppState().chatDetails!.response!.id!.toInt(),
// receiverUID: params!.groupChatDetails!.groupId!,
// loadMore: true,
// isNewChat: false,
);
}
}
await Future.delayed(
@ -83,13 +77,12 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
data = Provider.of<ChatProviderModel>(context, listen: false);
// callPro = Provider.of<ChatCallProvider>(context, listen: false);
if (params != null) {
data.getGroupChatHistory(
params!.groupChatDetails!
// senderUID: AppState().chatDetails!.response!.id!.toInt(),
// receiverUID: params!.groupChatHistory!.groupId!,
// loadMore: false,
// isNewChat: params!.isNewChat!,
);
data.getGroupChatHistory(params!.groupChatDetails!
// senderUID: AppState().chatDetails!.response!.id!.toInt(),
// receiverUID: params!.groupChatHistory!.groupId!,
// loadMore: false,
// isNewChat: params!.isNewChat!,
);
data.initAudio(receiverId: params!.groupChatDetails!.groupId!);
}
@ -99,8 +92,8 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
context,
title: params!.groupChatDetails!.groupName.toString().replaceAll(".", " ").capitalizeFirstofEach,
showHomeButton: false,
// showTyping: true,
// chatUser: params!.groupChatHistory!.groupChatHistoryTargetUserList as ChatUser,
// showTyping: true,
// chatUser: params!.groupChatHistory!.groupChatHistoryTargetUserList as ChatUser,
actions: [
// SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() {
// makeCall(callType: "AUDIO");
@ -117,224 +110,222 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
builder: (BuildContext context, ChatProviderModel m, Widget? child) {
return (m.isLoading
? ChatHomeShimmer(
isDetailedScreen: true,
)
isDetailedScreen: true,
)
: Column(
children: <Widget>[
SmartRefresher(
enablePullDown: false,
enablePullUp: true,
onLoading: () {
getMoreChat();
},
header: const MaterialClassicHeader(
color: MyColors.gradiantEndColor,
),
controller: _rc,
reverse: true,
child: ListView.separated(
controller: m.scrollController,
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
reverse: true,
itemCount: m.groupChatHistory.length,
padding: const EdgeInsets.all(21),
separatorBuilder: (BuildContext cxt, int index) => 8.height,
itemBuilder: (BuildContext context, int i) {
return SwipeTo(
iconColor: MyColors.lightGreenColor,
child: GroupChatBubble(
dateTime: m.groupChatHistory[i].createdDate!,
cItem: m.groupChatHistory[i],
),
onRightSwipe: (val) {
m.groupChatReply(
m.groupChatHistory[i],
);
children: <Widget>[
SmartRefresher(
enablePullDown: false,
enablePullUp: true,
onLoading: () {
getMoreChat();
},
).onPress(() async {
logger.w(m.userChatHistory[i].toJson());
if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) {
if (m.userChatHistory[i].fileTypeId! == 1 ||
m.userChatHistory[i].fileTypeId! == 5 ||
m.userChatHistory[i].fileTypeId! == 7 ||
m.userChatHistory[i].fileTypeId! == 6 ||
m.userChatHistory[i].fileTypeId! == 8
// || m.userChatHistory[i].fileTypeId! == 2
) {
m.getChatMedia(context,
fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!);
}
}
});
},
),
).expanded,
if (m.isReplyMsg)
SizedBox(
height: 82,
child: Row(
children: <Widget>[
Container(height: 82, color: MyColors.textMixColor, width: 6),
Container(
color: MyColors.darkTextColor.withOpacity(0.10),
padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21),
header: const MaterialClassicHeader(
color: MyColors.gradiantEndColor,
),
controller: _rc,
reverse: true,
child: ListView.separated(
controller: m.scrollController,
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
reverse: true,
itemCount: m.groupChatHistory.length,
padding: const EdgeInsets.all(21),
separatorBuilder: (BuildContext cxt, int index) => 8.height,
itemBuilder: (BuildContext context, int i) {
return SwipeTo(
iconColor: MyColors.lightGreenColor,
child: GroupChatBubble(
dateTime: m.groupChatHistory[i].createdDate!,
cItem: m.groupChatHistory[i],
),
onRightSwipe: (val) {
m.groupChatReply(
m.groupChatHistory[i],
);
},
).onPress(() async {
logger.w(m.groupChatHistory[i].toJson());
if (m.groupChatHistory[i].fileTypeResponse != null && m.groupChatHistory[i].fileTypeId != null) {
if (m.groupChatHistory[i].fileTypeId! == 1 ||
m.groupChatHistory[i].fileTypeId! == 5 ||
m.groupChatHistory[i].fileTypeId! == 7 ||
m.groupChatHistory[i].fileTypeId! == 6 ||
m.groupChatHistory[i].fileTypeId! == 8 ||
m.groupChatHistory[i].fileTypeId! == 16) {
m.getChatMedia(context,
fileTypeName: m.groupChatHistory[i].fileTypeResponse!.fileTypeName ?? "",
fileTypeID: m.groupChatHistory[i].fileTypeId!,
fileName: m.groupChatHistory[i].contant!,
fileSource: 2);
}
}
});
},
),
).expanded,
if (m.isReplyMsg)
SizedBox(
height: 82,
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(AppState().chatDetails!.response!.userName == m.groupChatReplyData.first.currentUserName.toString()
? "You"
: m.groupChatReplyData.first.currentUserName.toString().replaceAll(".", " "))
.toText14(color: MyColors.lightGreenColor),
(m.groupChatReplyData.isNotEmpty ? m.groupChatReplyData.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2)
],
children: <Widget>[
Container(height: 82, color: MyColors.textMixColor, width: 6),
Container(
color: MyColors.darkTextColor.withOpacity(0.10),
padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(AppState().chatDetails!.response!.userName == m.groupChatReplyData.first.currentUserName.toString()
? "You"
: m.groupChatReplyData.first.currentUserName.toString().replaceAll(".", " "))
.toText14(color: MyColors.lightGreenColor),
(m.groupChatReplyData.isNotEmpty ? m.groupChatReplyData.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2)
],
).expanded,
12.width,
if (m.isReplyMsg && m.groupChatReplyData.isNotEmpty) showReplyImage(m.groupChatReplyData, m),
12.width,
const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe),
],
),
).expanded,
12.width,
if (m.isReplyMsg && m.groupChatReplyData.isNotEmpty) showReplyImage(m.groupChatReplyData, m),
12.width,
const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe),
],
),
).expanded,
],
),
),
if (m.isAttachmentMsg && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg")
SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21),
const Divider(height: 1, color: MyColors.lightGreyEFColor),
if (m.isRecoding)
Column(
children: <Widget>[
Row(
children: [
Text(m.buildTimer()).paddingAll(10),
if (m.isRecoding && m.isPlaying)
WaveBubble(
playerController: m.playerController,
isPlaying: m.playerController.playerState == PlayerState.playing,
onTap: () {},
).expanded
else
AudioWaveforms(
waveStyle: const WaveStyle(
waveColor: MyColors.lightGreenColor,
middleLineColor: Colors.transparent,
extendWaveform: true,
showBottom: true,
showTop: true,
waveThickness: 2,
showMiddleLine: false,
middleLineThickness: 0,
),
padding: const EdgeInsets.all(5),
shouldCalculateScrolledPosition: false,
margin: EdgeInsets.zero,
size: const Size(double.infinity, 30.0),
recorderController: m.recorderController,
backgroundColor: Colors.white,
).expanded,
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(
Icons.delete_outlined,
size: 26,
color: MyColors.lightGreenColor,
).paddingAll(10).onPress(() {
m.deleteRecoding();
}),
SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26)
.onPress(
() => m.sendGroupChatMessage(context,
targetUserId: params!.groupChatDetails!.groupId!,
userStatus: 0,
userEmail: "",
targetUserName: params!.groupChatDetails!.groupName!,
userList: params!.groupChatDetails!.groupUserList!
),
)
.paddingOnly(right: 21),
],
),
],
).objectContainerView(disablePadding: true, radius: 0),
if (!m.isRecoding)
Row(
children: [
CustomAutoDirection(
onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL),
text: m.msgText,
child: TextField(
// textDirection: m.textDirection,
controller: m.message,
decoration: InputDecoration(
hintTextDirection: m.textDirection,
hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
filled: true,
fillColor: MyColors.white,
contentPadding: const EdgeInsets.only(
left: 21,
top: 20,
bottom: 20,
),
prefixIconConstraints: const BoxConstraints(),
prefixIcon: m.sFileType.isNotEmpty
? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15)
: null,
),
onChanged: (String val) {
m.inputBoxDirection(val);
m.groupTypingInvoke(groupDetails: params!.groupChatDetails!, groupId: params!.groupChatDetails!.groupId!);
},
).expanded,
),
if (m.sFileType.isNotEmpty)
Row(
),
if (m.isAttachmentMsg && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg")
SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21),
const Divider(height: 1, color: MyColors.lightGreyEFColor),
if (m.isRecoding)
Column(
children: <Widget>[
const Icon(Icons.cancel, size: 15, color: MyColors.redA3Color).paddingOnly(right: 5),
("Clear").toText11(color: MyColors.redA3Color, isUnderLine: true).paddingOnly(left: 0),
Row(
children: [
Text(m.buildTimer()).paddingAll(10),
if (m.isRecoding && m.isPlaying)
WaveBubble(
playerController: m.playerController,
isPlaying: m.playerController.playerState == PlayerState.playing,
onTap: () {},
).expanded
else
AudioWaveforms(
waveStyle: const WaveStyle(
waveColor: MyColors.lightGreenColor,
middleLineColor: Colors.transparent,
extendWaveform: true,
showBottom: true,
showTop: true,
waveThickness: 2,
showMiddleLine: false,
middleLineThickness: 0,
),
padding: const EdgeInsets.all(5),
shouldCalculateScrolledPosition: false,
margin: EdgeInsets.zero,
size: const Size(double.infinity, 30.0),
recorderController: m.recorderController,
backgroundColor: Colors.white,
).expanded,
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(
Icons.delete_outlined,
size: 26,
color: MyColors.lightGreenColor,
).paddingAll(10).onPress(() {
m.deleteRecoding();
}),
SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26)
.onPress(
() => m.sendGroupChatMessage(context,
targetUserId: params!.groupChatDetails!.groupId!,
userStatus: 0,
userEmail: "",
targetUserName: params!.groupChatDetails!.groupName!,
userList: params!.groupChatDetails!.groupUserList!),
)
.paddingOnly(right: 21),
],
),
],
).onPress(() => m.removeAttachment()).paddingOnly(right: 15),
if (m.sFileType.isEmpty)
RotationTransition(
turns: const AlwaysStoppedAnimation(45 / 360),
child: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor).onPress(
() => {
m.selectImageToUpload(context)
).objectContainerView(disablePadding: true, radius: 0),
if (!m.isRecoding)
Row(
children: [
CustomAutoDirection(
onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL),
text: m.msgText,
child: TextField(
// textDirection: m.textDirection,
controller: m.message,
decoration: InputDecoration(
hintTextDirection: m.textDirection,
hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
filled: true,
fillColor: MyColors.white,
contentPadding: const EdgeInsets.only(
left: 21,
top: 20,
bottom: 20,
),
prefixIconConstraints: const BoxConstraints(),
prefixIcon: m.sFileType.isNotEmpty
? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15)
: null,
),
onChanged: (String val) {
m.inputBoxDirection(val);
m.groupTypingInvoke(groupDetails: params!.groupChatDetails!, groupId: params!.groupChatDetails!.groupId!);
},
),
).paddingOnly(right: 15),
const Icon(
Icons.mic,
color: MyColors.lightGreenColor,
).paddingOnly(right: 15).onPress(() {
m.startRecoding(context);
}),
SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26)
.onPress(
() =>m.sendGroupChatMessage(context,
targetUserId: params!.groupChatDetails!.groupId!,
userStatus: 0,
userEmail: "",
targetUserName: params!.groupChatDetails!.groupName!,
userList: params!.groupChatDetails!.groupUserList!
).expanded,
),
)
.paddingOnly(right: 21),
if (m.sFileType.isNotEmpty)
Row(
children: <Widget>[
const Icon(Icons.cancel, size: 15, color: MyColors.redA3Color).paddingOnly(right: 5),
("Clear").toText11(color: MyColors.redA3Color, isUnderLine: true).paddingOnly(left: 0),
],
).onPress(() => m.removeAttachment()).paddingOnly(right: 15),
if (m.sFileType.isEmpty)
RotationTransition(
turns: const AlwaysStoppedAnimation(45 / 360),
child: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor).onPress(
() => {m.selectImageToUpload(context)},
),
).paddingOnly(right: 15),
const Icon(
Icons.mic,
color: MyColors.lightGreenColor,
).paddingOnly(right: 15).onPress(() {
m.startRecoding(context);
}),
SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26)
.onPress(
() => m.sendGroupChatMessage(context,
targetUserId: params!.groupChatDetails!.groupId!,
userStatus: 0,
userEmail: "",
targetUserName: params!.groupChatDetails!.groupName!,
userList: params!.groupChatDetails!.groupUserList!),
)
.paddingOnly(right: 21),
],
).objectContainerView(disablePadding: true, radius: 0),
],
).objectContainerView(disablePadding: true, radius: 0),
],
));
));
},
),
),
@ -352,17 +343,17 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
} else {
return data.first.fileTypeResponse != null && data.first.fileTypeResponse!.fileTypeName != null
? Container(
width: 43,
height: 43,
constraints: const BoxConstraints(),
decoration: BoxDecoration(border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), color: Colors.white),
child: SvgPicture.asset(m.getType(data.first.fileTypeResponse!.fileTypeName ?? ""), alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 5, right: 5, top: 5, bottom: 5))
width: 43,
height: 43,
constraints: const BoxConstraints(),
decoration: BoxDecoration(border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), color: Colors.white),
child: SvgPicture.asset(m.getType(data.first.fileTypeResponse!.fileTypeName ?? ""), alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 5, right: 5, top: 5, bottom: 5))
: const SizedBox();
}
}
void makeCall({required String callType}) async {
callPro.initCallListeners();
callPro.initCallListeners(context: context);
print("================== Make call Triggered ============================");
// Map<String, dynamic> json = {
// "callerID": AppState().chatDetails!.response!.id!.toString(),
@ -373,22 +364,22 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
// "calltype": callType == "VIDEO" ? "Video" : "Audio",
// };
logger.w(json);
// CallDataModel callData = CallDataModel.fromJson(json);
// await Navigator.push(
// context,
// MaterialPageRoute(
// builder: (BuildContext context) => OutGoingCall(
// isVideoCall: callType == "VIDEO" ? true : false,
// outGoingCallData: callData,
// ),
// ),
// ).then((value) {
// print("then");
// callPro.stopListeners();
// });
// CallDataModel callData = CallDataModel.fromJson(json);
// await Navigator.push(
// context,
// MaterialPageRoute(
// builder: (BuildContext context) => OutGoingCall(
// isVideoCall: callType == "VIDEO" ? true : false,
// outGoingCallData: callData,
// ),
// ),
// ).then((value) {
// print("then");
// callPro.stopListeners();
// });
}
GroupUserList getCurrentUser(int id, GroupResponse groupChatDetails) {
return groupChatDetails.groupUserList!.firstWhere((GroupUserList item) => item.id ==id);
return groupChatDetails.groupUserList!.firstWhere((GroupUserList item) => item.id == id);
}
}

@ -3,8 +3,9 @@ import 'dart:io';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
@ -16,10 +17,16 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_main_response.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/models/privilege_list_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/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/ui/landing/widget/app_drawer.dart';
import 'package:mohem_flutter_app/ui/landing/widget/menus_widget.dart';
import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart';
@ -33,8 +40,6 @@ import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
late HubConnection chatHubConnection;
class DashboardScreen extends StatefulWidget {
DashboardScreen({Key? key}) : super(key: key);
@ -48,20 +53,23 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
late DashboardProviderModel data;
late MarathonProvider marathonProvider;
late ChatProviderModel cProvider;
late ChatCallProvider chatCallProvider;
final GlobalKey<ScaffoldState> _scaffoldState = GlobalKey();
final RefreshController _refreshController = RefreshController(initialRefresh: false);
int currentIndex = 0;
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
if (Platform.isAndroid) {
callListeners();
}
scheduleMicrotask(() {
data = Provider.of<DashboardProviderModel>(context, listen: false);
marathonProvider = Provider.of<MarathonProvider>(context, listen: false);
cProvider = Provider.of<ChatProviderModel>(context, listen: false);
chatCallProvider = Provider.of<ChatCallProvider>(context, listen: false);
if (checkIfPrivilegedForChat()) {
_bHubCon();
}
@ -69,6 +77,66 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
});
}
Future<void> callListeners() async {
try {
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async {
switch (event!.event) {
case Event.actionCallIncoming:
break;
case Event.actionCallStart:
break;
case Event.actionCallAccept:
if (mounted) {
moveToCallScreen();
}
break;
case Event.actionCallDecline:
SingleUserChatModel callerData;
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
declineCall(cuserid: event.body["extra"]["callerDetails"]["currentUserId"], ruserid: event.body["extra"]["callerDetails"]["targetUserId"]);
FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallEnded:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallTimeout:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
}
});
} on Exception {}
}
void declineCall({required int cuserid, required int ruserid}) async {
logger.i("-----------------------Call Decline Hit---------------------------");
if (chatHubConnection!.state == HubConnectionState.Connected) {
try {
await chatHubConnection!.invoke("CallDeclinedAsync", args: <Object>[cuserid, ruserid]);
await chatHubConnection!.invoke("UpdateUserStatusAsync", args: <Object>[cuserid, 1]);
} catch (e) {
logger.w(e);
}
}
}
Future<void> moveToCallScreen() async {
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls is List) {
if (calls.isNotEmpty) {
Future.delayed(const Duration(seconds: 1)).whenComplete(() {
MaterialPageRoute pageRoute = MaterialPageRoute(builder: (BuildContext context) => StartCallPage());
Navigator.push(context, pageRoute);
});
}
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
@ -88,24 +156,24 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
if (!cProvider.disbaleChatForThisUser) {
chatHubConnection.stop();
if (!cProvider.disableChatForThisUser) {
chatHubConnection!.stop();
}
}
void _bHubCon() {
cProvider.getUserAutoLoginToken().whenComplete(() async {
if (!cProvider.disbaleChatForThisUser) {
if (!cProvider.disableChatForThisUser) {
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
if (isAppOpendByChat != "null" && isAppOpendByChat == "true") {
Utils.showLoading(context);
cProvider.buildHubConnection();
await cProvider.buildHubConnection(context: context, ccProvider: chatCallProvider);
Future.delayed(const Duration(seconds: 2), () async {
cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!);
gotoChat(context);
});
} else {
cProvider.buildHubConnection();
await cProvider.buildHubConnection(context: context, ccProvider: chatCallProvider);
Future.delayed(const Duration(seconds: 2), () {
cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!);
});
@ -115,16 +183,16 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
Future<void> checkHubCon() async {
if (chatHubConnection.state == HubConnectionState.Connected) {
await chatHubConnection.stop();
await chatHubConnection.start();
} else if (chatHubConnection.state != HubConnectionState.Connected) {
await chatHubConnection.start();
if (chatHubConnection!.state == HubConnectionState.Connected) {
await chatHubConnection!.stop();
await chatHubConnection!.start();
} else if (chatHubConnection!.state != HubConnectionState.Connected) {
await chatHubConnection!.start();
}
}
void gotoChat(BuildContext context) async {
if (chatHubConnection.state == HubConnectionState.Connected) {
if (chatHubConnection!.state == HubConnectionState.Connected) {
Utils.hideLoading(context);
Navigator.pushNamed(context, AppRoutes.chat);
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
@ -153,17 +221,17 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
if (isFromInit) {
checkERMChannel();
}
if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
if (!cProvider.disableChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted();
}
void checkERMChannel() {
data.getITGNotification().then((val) {
data.getITGNotification().then((MohemmItgResponseItem? val) {
if (val!.result!.data != null) {
print("-------------------- Survey ----------------------------");
if (val.result!.data!.notificationType == "Survey") {
DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
(value) {
(ItgMainRes? value) {
if (value!.mohemmItgResponseItem!.statusCode == 200) {
if (value.mohemmItgResponseItem!.result!.data != null) {
// Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data);
@ -179,13 +247,22 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
} else {
print("------------------------------------------- Ads --------------------");
DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
(value) {
(ItgMainRes? value) {
if (value!.mohemmItgResponseItem!.statusCode == 200) {
if (value.mohemmItgResponseItem!.result!.data != null) {
Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
"masterId": val.result!.data!.notificationMasterId,
"advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement,
});
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (BuildContext context) => ITGAdsScreen(
// addMasterId: val.result!.data!.notificationMasterId!,
// advertisement: value.mohemmItgResponseItem!.result!.data!.advertisement!,
// ),
// ),
// );
}
}
},
@ -199,6 +276,46 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldState,
// appBar: AppBar(
// actions: [
// IconButton(
// onPressed: () {
// data.getITGNotification().then((val) {
// if (val!.result!.data != null) {
// print("-------------------- Survey ----------------------------");
// if (val.result!.data!.notificationType == "Survey") {
// Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data);
// } else {
// print("------------------------------------------- Ads --------------------");
// DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
// (value) {
// if (value!.mohemmItgResponseItem!.statusCode == 200) {
// if (value.mohemmItgResponseItem!.result!.data != null) {
// Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
// "masterId": val.result!.data!.notificationMasterId,
// "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement,
// });
//
// // Navigator.push(
// // context,
// // MaterialPageRoute(
// // builder: (BuildContext context) => ITGAdsScreen(
// // addMasterId: val.result!.data!.notificationMasterId!,
// // advertisement: value.mohemmItgResponseItem!.result!.data!.advertisement!,
// // ),
// // ),
// // );
// }
// }
// },
// );
// }
// }
// });
// },
// icon: Icon(Icons.add))
// ],
// ),
body: Column(
children: [
Row(
@ -565,16 +682,15 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
icon: Stack(
alignment: Alignment.centerLeft,
children: [
SvgPicture.asset(
"assets/icons/chat/chat.svg",
color: !checkIfPrivilegedForChat()
? MyColors.lightGreyE3Color
: currentIndex == 4
? MyColors.grey3AColor
: cProvider.disbaleChatForThisUser
? MyColors.lightGreyE3Color
: MyColors.grey98Color,
).paddingAll(4),
SvgPicture.asset("assets/icons/chat/chat.svg", color: !checkIfPrivilegedForChat() ? MyColors.lightGreyE3Color : MyColors.grey98Color
// currentIndex == 4
// ? MyColors.grey3AColor
// : cProvider.disableChatForThisUser
// ? MyColors.lightGreyE3Color
// : MyColors.grey98Color,
)
.paddingAll(4),
Consumer<ChatProviderModel>(
builder: (BuildContext cxt, ChatProviderModel data, Widget? child) {
return !checkIfPrivilegedForChat()
@ -585,7 +701,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
child: Container(
padding: const EdgeInsets.only(left: 4, right: 4),
alignment: Alignment.center,
decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
decoration: BoxDecoration(color: data.disableChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white),
),
);
@ -637,6 +753,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
}
});
Navigator.pushNamed(context, AppRoutes.offersAndDiscountsDetails, arguments: getOffersDetailList);
}

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -8,7 +9,12 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_ios_voip_kit/call_state_type.dart';
import 'package:flutter_ios_voip_kit/flutter_ios_voip_kit.dart';
import 'package:logger/logger.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
import 'package:mohem_flutter_app/api/login_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
@ -21,15 +27,17 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/check_mobile_app_version_model.dart';
import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart';
import 'package:mohem_flutter_app/models/member_information_list_model.dart';
import 'package:mohem_flutter_app/models/member_login_list_model.dart';
import 'package:mohem_flutter_app/models/privilege_list_model.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/input_widget.dart';
// import 'package:safe_device/safe_device.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:wifi_iot/wifi_iot.dart';
class LoginScreen extends StatefulWidget {
@ -41,7 +49,7 @@ class LoginScreen extends StatefulWidget {
}
}
class _LoginScreenState extends State<LoginScreen> {
class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
TextEditingController username = TextEditingController();
TextEditingController password = TextEditingController();
@ -49,6 +57,7 @@ class _LoginScreenState extends State<LoginScreen> {
MemberLoginListModel? _memberLoginList;
late final FirebaseMessaging _firebaseMessaging;
IosCallPayload? _iosCallPayload;
bool _autoLogin = false;
@ -58,9 +67,13 @@ class _LoginScreenState extends State<LoginScreen> {
bool isRealDevice = false;
bool isOnExternalStorage = false;
bool isDevelopmentModeEnable = false;
bool isIncomingCall = false;
// late HmsApiAvailability hmsApiAvailability;
final FlutterIOSVoIPKit voIPKit = FlutterIOSVoIPKit.instance;
late Timer timeOutTimer;
@override
void initState() {
super.initState();
@ -69,6 +82,119 @@ class _LoginScreenState extends State<LoginScreen> {
// if (kReleaseMode) {
// checkDeviceSafety();
// }
WidgetsBinding.instance.addObserver(this);
if (Platform.isAndroid) {
callListeners();
checkAndNavigationCallingPage();
}
if (Platform.isIOS) {
setupVoIPCallBacks();
}
}
// IOS Voip Call
Future<void> setupVoIPCallBacks() async {
if (Platform.isIOS) {
voIPKit.getVoIPToken().then((String? value) async {
print('🎈 example: getVoIPToken: $value');
if (value != null) {
AppState().setiosVoipPlayerID = await ChatApiClient().oneSignalVoip(value);
print('🎈 example: OneSignal ID: ${AppState().iosVoipPlayerID}');
}
});
}
voIPKit.onDidUpdatePushToken = (String token) {
print('🎈 example: onDidUpdatePushToken: $token');
};
voIPKit.onDidReceiveIncomingPush = (
Map<String, dynamic> payload,
) async {
_iosCallPayload = IosCallPayload.fromJson(payload);
_timeOut(callDetails: _iosCallPayload!.incomingCallerId!);
};
voIPKit.onDidRejectIncomingCall = (
String uuid,
String callerId,
) async {
timeOutTimer.cancel();
declineCall(
cuserid: int.parse(callerId.split("-")[1]),
ruserid: int.parse(callerId.split("-")[0]),
);
await voIPKit.endCall();
};
voIPKit.onDidAcceptIncomingCall = (
String uuid,
String callerId,
) async {
await connectCall(uuid: uuid, callDetails: callerId);
voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
voIPKit.callConnected().then((value) => timeOutTimer.cancel());
};
}
void _timeOut({required String callDetails}) async {
timeOutTimer = Timer(const Duration(seconds: 25), () async {
String? incomingCallerName = await voIPKit.getIncomingCallerName();
voIPKit.unansweredIncomingCall(
skipLocalNotification: true,
missedCallTitle: '📞 Missed call',
missedCallBody: 'There was a call from $incomingCallerName',
);
declineCall(cuserid: int.parse(callDetails.split("-")[1]), ruserid: int.parse(callDetails.split("-")[0]));
await voIPKit.endCall();
});
}
Future<void> connectCall({required String uuid, required String callDetails}) async {
isIncomingCall = true;
if (AppState().getisUserOnline) {
_iosCallPayload = IosCallPayload(
uuid: uuid,
incomingCallerId: callDetails.split("-")[0],
incomingCallReciverId: callDetails.split("-")[1],
incomingCallerName: _iosCallPayload!.incomingCallerName,
incomingCallType: callDetails.split("-").last);
} else {
_iosCallPayload = IosCallPayload(
uuid: uuid, incomingCallerId: callDetails.split("-")[0], incomingCallReciverId: callDetails.split("-")[1], incomingCallerName: null, incomingCallType: callDetails.split("-").last);
}
if (_iosCallPayload!.incomingCallerName == null) {
if (Platform.isIOS) {
Utils.hideLoading(context);
}
if (Platform.isIOS) {
Future.delayed(Duration(seconds: 3), () async {
MaterialPageRoute pageRoute = await MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(
payload: _iosCallPayload,
),
);
Navigator.push(context, pageRoute);
});
}
} else if (AppState().getisUserOnline) {
BuildContext context = AppRoutes.navigatorKey.currentContext!;
if (Platform.isIOS) {
Future.delayed(Duration(seconds: 3), () async {
MaterialPageRoute pageRoute = await MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(
payload: _iosCallPayload,
),
);
Navigator.push(context, pageRoute);
});
}
} else {
if (Platform.isAndroid) FlutterCallkitIncoming.endAllCalls();
if (Platform.isIOS) await voIPKit.endCall();
Utils.showToast("Something wen't wrong");
}
}
// void checkDeviceSafety() async {
@ -87,6 +213,96 @@ class _LoginScreenState extends State<LoginScreen> {
// }
// }
Future<void> callListeners() async {
try {
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async {
switch (event!.event) {
case Event.actionCallIncoming:
break;
case Event.actionCallStart:
break;
case Event.actionCallAccept:
if (mounted) {
isIncomingCall = true;
moveToCallScreen();
}
break;
case Event.actionCallDecline:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
declineCall(cuserid: event.body["extra"]["callerDetails"]["currentUserId"], ruserid: event.body["extra"]["callerDetails"]["targetUserId"]);
FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallEnded:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallTimeout:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
}
print('${event.body}\n');
});
} on Exception {
logger.log(Level.info, "EXCEPTION-ON-EVENTS");
}
}
void declineCall({required int cuserid, required int ruserid}) async {
logger.i("-----------------------Call Decline Hit---------------------------");
if (chatHubConnection!.state == HubConnectionState.Connected) {
try {
await chatHubConnection!.invoke("CallDeclinedAsync", args: <Object>[cuserid, ruserid]);
await chatHubConnection!.invoke("UpdateUserStatusAsync", args: <Object>[cuserid, 1]);
} catch (e) {
logger.w(e);
}
}
}
Future<void> moveToCallScreen() async {
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls is List) {
if (calls.isNotEmpty) {
if (Platform.isAndroid) {
Utils.hideLoading(context);
}
MaterialPageRoute pageRoute = MaterialPageRoute(builder: (BuildContext context) => StartCallPage());
Navigator.push(context, pageRoute).whenComplete(() {
checkFirebaseToken();
});
} else {
FlutterCallkitIncoming.endAllCalls();
Utils.showToast("Something wen't wrong");
}
}
}
Future<dynamic> getCurrentCall() async {
//check current call from pushkit if possible
var calls = await FlutterCallkitIncoming.activeCalls();
if (calls is List) {
if (calls.isNotEmpty) {
return calls[0];
} else {
return null;
}
}
}
Future<void> checkAndNavigationCallingPage() async {
var currentCall = await getCurrentCall();
if (currentCall != null && Platform.isAndroid) {
isIncomingCall = true;
Utils.hideLoading(context);
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => StartCallPage()));
}
}
@override
void dispose() {
super.dispose();
@ -102,8 +318,8 @@ class _LoginScreenState extends State<LoginScreen> {
if (Platform.isAndroid) {
try {
if (!(await Utils.isGoogleServicesAvailable())) {
print("HUAWEI APPPP GALLERYYYY!!!!");
AppNotifications().init(firebaseToken, context);
debugPrint("HUAWEI APPPP GALLERYYYY!!!!");
// AppNotifications().init(firebaseToken, context);
AppState().setIsHuawei = true;
AppNotifications().initHuaweiPush(checkLoginInfo);
} else {
@ -224,7 +440,15 @@ class _LoginScreenState extends State<LoginScreen> {
// 13777
// Ab12345cd
}
if (isAppOpenBySystem!) checkFirebaseToken();
// if (isAppOpenBySystem!) checkFirebaseToken();
Utils.showLoading(context);
Future.delayed(Duration(seconds: Platform.isIOS ? 3 : 2)).whenComplete(() {
if (!isIncomingCall) {
Utils.hideLoading(context);
if (isAppOpenBySystem!) checkFirebaseToken();
}
});
}
// username.text = "15444";
@ -299,7 +523,11 @@ class _LoginScreenState extends State<LoginScreen> {
DefaultButton(LocaleKeys.login.tr(), () async {
SystemChannels.textInput.invokeMethod('TextInput.hide');
performLogin();
}).insideContainer
}).insideContainer,
// DefaultButton("Call", () async {
// SystemChannels.textInput.invokeMethod('TextInput.hide');
// connectCall();
// }).insideContainer
],
),
);

@ -3,8 +3,9 @@ import 'dart:io';
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_svg/svg.dart';
import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
import 'package:mohem_flutter_app/api/login_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
@ -20,10 +21,12 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/basic_member_information_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/ui/dialogs/id/business_card_dialog.dart';
import 'package:mohem_flutter_app/ui/dialogs/id/employee_digital_id_dialog.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart';
import 'package:local_auth_ios/local_auth_ios.dart';
// WhatsApp 4
// SMS 1
@ -52,15 +55,71 @@ class _VerifyLastLoginScreenState extends State<VerifyLastLoginScreen> {
void initState() {
_getAvailableBiometrics();
// setDefault();
if (Platform.isAndroid) {
callListeners();
}
super.initState();
}
Future<void> callListeners() async {
try {
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async {
switch (event!.event) {
case Event.actionCallIncoming:
// await ChatVoipCall().declineCall(payload: jsonEncode(event.body));
break;
case Event.actionCallStart:
break;
case Event.actionCallAccept:
if (mounted) {
// isIncomingCall = true;
moveToCallScreen();
}
break;
case Event.actionCallDecline:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallEnded:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallTimeout:
Utils.saveStringFromPrefs("isIncomingCall", "false");
Utils.saveStringFromPrefs("inComingCallData", "null");
FlutterCallkitIncoming.endAllCalls();
break;
}
});
} on Exception {}
}
Future<void> moveToCallScreen() async {
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls is List) {
if (calls.isNotEmpty) {
if (Platform.isAndroid) {
Utils.hideLoading(context);
}
var pageRoute = MaterialPageRoute(builder: (context) => StartCallPage());
Navigator.push(context, pageRoute).whenComplete(() {
// checkFirebaseToken();
});
} else {
FlutterCallkitIncoming.endAllCalls();
Utils.showToast("Something wen't wrong");
}
}
}
@override
Widget build(BuildContext context) {
mobileLoginInfoListModel ??= ModalRoute.of(context)!.settings.arguments as GetMobileLoginInfoListModel;
// String empName = AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!;
String empName = mobileLoginInfoListModel!.employeeName!;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
@ -220,10 +279,18 @@ class _VerifyLastLoginScreenState extends State<VerifyLastLoginScreen> {
Future<bool> loginWithFaceIDAndBiometrics() async {
IOSAuthMessages iosStrings =
const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID');
const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please re enable your Touch ID');
bool authenticated = false;
try {
authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, biometricOnly: true, iOSAuthStrings: iosStrings);
authenticated = await auth.authenticate(
localizedReason: 'Scan your fingerprint to authenticate',
authMessages: [iosStrings],
options: const AuthenticationOptions(
useErrorDialogs: true,
stickyAuth: true,
biometricOnly: true,
),
);
} on PlatformException catch (e) {
print(e);
Utils.hideLoading(context);
@ -289,7 +356,7 @@ class _VerifyLastLoginScreenState extends State<VerifyLastLoginScreen> {
width: 38,
color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null,
),
_title.toText16(height: 20/16)
_title.toText16(height: 20 / 16)
],
),
),
@ -404,5 +471,4 @@ class _VerifyLastLoginScreenState extends State<VerifyLastLoginScreen> {
// // isLoading = isTrue;
// });
// }
}

@ -4,7 +4,6 @@ import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
import 'package:mohem_flutter_app/api/login_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
@ -13,13 +12,13 @@ import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/dialogs/otp_dialog.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/basic_member_information_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/member_information_list_model.dart';
import 'package:mohem_flutter_app/models/privilege_list_model.dart';
import 'package:local_auth_ios/local_auth_ios.dart';
// WhatsApp 2
// SMS 1
@ -516,7 +515,16 @@ class _VerifyLoginScreenState extends State<VerifyLoginScreen> {
const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID');
bool authenticated = false;
try {
authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, biometricOnly: true, iOSAuthStrings: iosStrings);
// authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, biometricOnly: true, iOSAuthStrings: iosStrings);
authenticated = await auth.authenticate(
localizedReason: 'Scan your fingerprint to authenticate',
authMessages: [iosStrings],
options: const AuthenticationOptions(
useErrorDialogs: true,
stickyAuth: true,
biometricOnly: true,
)
);
} on PlatformException catch (e) {
print(e);
Utils.hideLoading(context);
@ -572,7 +580,7 @@ class _VerifyLoginScreenState extends State<VerifyLoginScreen> {
width: 38,
color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null,
),
_title.toText16(height: 20/16)
_title.toText16(height: 20 / 16)
],
),
),
@ -679,5 +687,4 @@ class _VerifyLoginScreenState extends State<VerifyLoginScreen> {
// // isLoading = isTrue;
// });
// }
}

@ -96,7 +96,8 @@ class _DynamicInputScreenState extends State<DynamicInputScreen> {
SubmitEITTransactionList submitEITTransactionList = await MyAttendanceApiClient().submitEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp);
Utils.hideLoading(context);
await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen,
arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit',isAttachmentMandatory: dynamicParams!.isAttachmentMandatory));
arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit',
isAttachmentMandatory: dynamicParams!.isAttachmentMandatory));
if (!AppState().cancelRequestTrancsection) {
return;
}
@ -360,6 +361,10 @@ class _DynamicInputScreenState extends State<DynamicInputScreen> {
idColName = idColName.parseMonth();
}
}
idColName = Utils.formatDateDefault(idColName!);
// commenting to test
// DateTime date = DateFormat('yyyy-MM-dd').parse(idColName!);
// idColName = DateFormat('yyyy-MM-dd HH:mm:ss').format(date);
}
}

@ -15,7 +15,7 @@ import 'package:mohem_flutter_app/models/get_time_card_summary_list_model.dart';
import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart';
import 'package:month_picker_dialog_2/month_picker_dialog_2.dart';
import 'package:month_picker_dialog/month_picker_dialog.dart';
import 'package:pie_chart/pie_chart.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
@ -169,8 +169,10 @@ class _ViewAttendanceState extends State<ViewAttendance> {
initialDate: formattedDate,
firstDate: DateTime(searchYear - 2),
lastDate: DateTime.now(),
confirmText: Text(LocaleKeys.confirm.tr()),
cancelText: Text(LocaleKeys.cancel.tr()),
confirmWidget: Text(LocaleKeys.confirm.tr()),
cancelWidget: Text(LocaleKeys.cancel.tr()),
// confirmText: Text(LocaleKeys.confirm.tr()),
// cancelText: Text(LocaleKeys.cancel.tr()),
).then(
(selectedDate) {
if (selectedDate != null) {

@ -115,8 +115,8 @@ class _DeleteFamilyMemberState extends State<DeleteFamilyMember> {
padding: EdgeInsets.only(left: 50, right: 50),
child: TextButton(
style: TextButton.styleFrom(
primary: MyColors.white,
onSurface: MyColors.white,
foregroundColor: MyColors.white,
disabledForegroundColor: MyColors.white,
backgroundColor: MyColors.gradiantEndColor,
),
onPressed: () {

@ -1,13 +1,12 @@
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
@ -16,7 +15,7 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share/share.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
class OffersAndDiscountsDetails extends StatefulWidget {
@ -76,7 +75,7 @@ class _OffersAndDiscountsDetailsState extends State<OffersAndDiscountsDetails> {
: getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center,
Html(
data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "",
onLinkTap: (String? url, RenderContext context, Map<String, String> attributes, _) {
onLinkTap: (String? url, Map<String, String> attributes, _) {
launchUrl(Uri.parse(url!));
},
),
@ -125,9 +124,10 @@ class _OffersAndDiscountsDetailsState extends State<OffersAndDiscountsDetails> {
Uint8List pngBytes = byteData!.buffer.asUint8List();
Directory tempDir = await getTemporaryDirectory();
File file = await File('${tempDir.path}/${DateTime.now().toString()}.png').create();
String fileName = "${DateTime.now().toString()}.png";
File file = await File('${tempDir.path}/$fileName').create();
await file.writeAsBytes(pngBytes);
await Share.shareFiles([(file.path)], text: AppState().isArabic(context) ? getOffersList[0].titleAr : getOffersList[0].titleEn);
await Share.shareXFiles([XFile(file.path)], text: AppState().isArabic(context) ? getOffersList[0].titleAr : getOffersList[0].titleEn);
} catch (ex) {
debugPrint(ex.toString());
}

@ -10,11 +10,14 @@ AppBar AppBarWidget(BuildContext context,
bool showHomeButton = true,
bool showWorkListSettingButton = false,
bool showMemberButton = false,
bool isBackButton =true,
List<Widget>? actions,
void Function()? onHomeTapped,
void Function()? onBackTapped}) {
return AppBar(
automaticallyImplyLeading:false,
leadingWidth: 0,
leading:null,
title: Row(
children: [
GestureDetector(
@ -22,8 +25,8 @@ AppBar AppBarWidget(BuildContext context,
onTap: Feedback.wrapForTap(() {
(onBackTapped == null ? Navigator.maybePop(context) : onBackTapped());
}, context),
child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor),
),
child: const Icon(Icons.arrow_back_ios_new, color: MyColors.darkIconColor),
) ,
4.width,
title.toText24(color: MyColors.darkTextColor, isBold: true).expanded,
],

@ -9,7 +9,7 @@ class AttachmentOptions extends StatelessWidget {
VoidCallback onGalleryTap;
VoidCallback onFilesTap;
bool showFilesOption;
String pickSelection ="";
AttachmentOptions({Key? key, required this.onCameraTap, required this.onGalleryTap, required this.onFilesTap, this.showFilesOption = true}) : super(key: key);
@override
@ -21,6 +21,7 @@ class AttachmentOptions extends StatelessWidget {
children: [
"Upload Attachment".toSectionHeading(),
"Select from gallery or open camera".toText11(weight: FontWeight.w500),
GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 105 / 105, crossAxisSpacing: 9, mainAxisSpacing: 9),
physics: const NeverScrollableScrollPhysics(),

@ -13,6 +13,7 @@ AppBar ChatAppBarWidget(BuildContext context,
{required String title, bool showHomeButton = true, ChatUser? chatUser, bool showTyping = false, List<Widget>? actions, void Function()? onHomeTapped, void Function()? onBackTapped}) {
return AppBar(
leadingWidth: 0,
automaticallyImplyLeading:false,
title: Consumer<ChatProviderModel>(builder: (BuildContext cxt, ChatProviderModel data, Widget? child) {
return Row(
children: [

@ -11,6 +11,8 @@ import 'package:mohem_flutter_app/widgets/bottom_sheets/attachment_options.dart'
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:permission_handler/permission_handler.dart';
final ImagePicker picker = ImagePicker();
class ImageOptions {
static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) {
showMyBottomSheet(
@ -23,8 +25,9 @@ class ImageOptions {
cameraImageAndroid(image);
} else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
// XFile? media = await picker.pickMedia();
String? fileName = _image?.path;
var bytes = File(fileName!).readAsBytesSync();
String base64Encode = base64.encode(bytes);
if (base64Encode != null) {
image(base64Encode, _image);
@ -35,7 +38,7 @@ class ImageOptions {
if (Platform.isAndroid) {
galleryImageAndroid(image);
} else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? "");
File _image = File((await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
@ -146,7 +149,7 @@ class ImageOptions {
}
void galleryImageAndroid(Function(String, File) image) async {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? "");
File _image = File((await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
@ -157,7 +160,7 @@ void galleryImageAndroid(Function(String, File) image) async {
}
void cameraImageAndroid(Function(String, File) image) async {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? "");
File _image = File((await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
#version: 3.3.01+300040
version: 3.3.6+300046
version: 3.7.7+1
environment:
sdk: ">=2.16.0 <3.0.0"
@ -44,10 +44,10 @@ dependencies:
permission_handler: ^10.2.0
flutter_svg: any
sizer: ^2.0.15
local_auth: ^1.1.9
local_auth: ^2.1.6
fluttertoast: ^8.0.8
syncfusion_flutter_calendar: ^19.4.48
# flutter_calendar_carousel: ^2.1.0
syncfusion_flutter_calendar: ^20.1.58
# flutter_calendar_carousel: ^2.1.0
pie_chart: ^5.1.0
shared_preferences: ^2.0.12
firebase_messaging: ^13.0.4
@ -62,8 +62,8 @@ dependencies:
image_picker: ^0.8.5+3
file_picker: 5.2.5
geolocator: ^9.0.2
month_year_picker: ^0.2.0+1
month_picker_dialog_2: 0.5.5
month_year_picker: any
month_picker_dialog: ^2.0.2
open_file: ^3.2.1
wifi_iot: ^0.3.18
flutter_html: ^3.0.0-alpha.6
@ -71,7 +71,7 @@ dependencies:
qr_code_scanner: ^1.0.1
# qr_flutter: ^4.0.0
url_launcher: ^6.0.15
share: 2.0.4
share_plus: ^4.5.3
flutter_rating_bar: ^4.0.1
auto_size_text: ^3.0.0
pull_to_refresh: ^2.0.0
@ -85,14 +85,18 @@ dependencies:
cached_network_image: ^3.2.2
#Chat
signalr_netcore: ^1.3.3
signalr_netcore: ^1.3.6
logging: ^1.0.1
swipe_to: ^1.0.2
flutter_webrtc: ^0.9.17
camera: ^0.10.3
swipe_to: ^1.0.5
#flutter_webrtc: ^0.9.34
flutter_webrtc: ^0.9.47
draggable_widget: ^2.0.0
flutter_callkit_incoming: ^2.0.0+1
camera: ^0.10.5+9
flutter_local_notifications: ^10.0.0
#firebase_analytics: any
#Chat Voice Message Recoding & Play
audio_waveforms: ^0.1.5+1
rxdart: ^0.27.7
@ -119,11 +123,12 @@ dependencies:
# store_checker: ^1.1.0
google_api_availability: ^3.0.1
in_app_update: 3.0.0
#todo its for temporary purpose, later will remove this.
dotted_border: ^2.0.0+3
in_app_update: 3.0.0
flutter_ios_voip_kit: ^0.1.0
# saf: ^1.0.3+4

Loading…
Cancel
Save