sultan-dev #17

Open
khansultan1 wants to merge 64 commits from sultan-dev into master

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

@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
#distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip

Binary file not shown.

Binary file not shown.

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
@ -144,6 +144,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C4CFBC4C5CAC00182015ACD5 /* [CP] Embed Pods Frameworks */,
1C704830960BB41251F31356 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -203,6 +204,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
1C704830960BB41251F31356 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
2D06B7AD3B87C9C9059E4168 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -227,7 +245,6 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -242,7 +259,6 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -366,18 +382,17 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Mohemm;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.7.2;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemmtest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -504,18 +519,17 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Mohemm;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.7.2;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemmtest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -534,18 +548,17 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 99Z3UD3LJM;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Mohemm;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.7.2;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemmtest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

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

@ -63,6 +63,7 @@
<true/>
<key>UIBackgroundModes</key>
<array>
<string>processing</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
@ -93,5 +94,13 @@
<array>
<string>TAG</string>
</array>
<key>FIVKIconName</key>
<string>AppIcon-VoIPKit</string>
<key>FIVKLocalizedName</key>
<string>VoIP-Kit</string>
<key>FIVKSupportVideo</key>
<true/>
<key>FIVKSkipRecallScreen</key>
<true/>
</dict>
</plist>

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

@ -35,9 +35,10 @@ class ChatApiClient {
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
"isMobile": true,
"platform": Platform.isIOS ? "ios" : "android",
"deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei,
"platform": Platform.isIOS ? "ios" : "android", // ios, android
"voipToken": Platform.isIOS ? AppState().iosVoipPlayerID : ""
},
);
@ -76,9 +77,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;
}
@ -143,14 +142,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();
@ -162,10 +161,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);
@ -311,4 +310,59 @@ 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) {
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, required String targetUsertoken}) async {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatLoginTokenUrl}calldecline",
{"currentUserId": cUserID, "targetUserId": tUserID, "secretKey": "derichatmobileuser", "targetUserToken": targetUsertoken},
);
print("res: " + response.body);
if (!kReleaseMode) {
logger.i({"currentUserId": cUserID, "targetUserId": tUserID, "secretKey": "derichatmobileuser", "targetUserToken": targetUsertoken});
print("res: " + response.body);
}
return response;
}
Future<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 ? 1 : 0},
);
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,21 @@ class AppState {
}
bool cancelRequestTrancsection = true;
String _iosVoipPlayerID = "";
String get iosVoipPlayerID => _iosVoipPlayerID;
set setiosVoipPlayerID(String value) {
_iosVoipPlayerID = value;
}
bool _isUserOnline = false;
bool get getisUserOnline => _isUserOnline;
set setisUserOnline(bool value) {
_isUserOnline = value;
}
}

@ -0,0 +1,180 @@
import 'dart:convert';
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:logger/logger.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as ALM;
import 'package:mohem_flutter_app/models/chat/incoming_call_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:path_provider/path_provider.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/signalr_client.dart';
class ChatVoipCall {
static final ChatVoipCall _instance = ChatVoipCall._internal();
ChatVoipCall._internal();
factory ChatVoipCall() => _instance;
late ChatProviderModel prov;
late ChatCallProvider cProv;
dynamic inCallData;
bool isUserOnline = false;
dynamic callData;
static const platform = MethodChannel('com.example.httpchannel/http');
Future<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: IOSParams(
iconName: 'Mohemm',
handleType: '',
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
audioSessionMode: 'default',
audioSessionActive: true,
audioSessionPreferredSampleRate: 38000.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
ringtonePath: 'system_ringtone_default',
),
);
if (callerData.chatEventId == 3) {
await Utils.saveStringFromPrefs("isIncomingCall", "true");
await FlutterCallkitIncoming.showCallkitIncoming(params);
}
}
Future<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 {
ALM.UserAutoLoginModel model = await ChatApiClient().getUserCallToken(userid: _iosCallPayload!.incomingCallReciverId.toString());
dynamic Res = await ChatApiClient().callDecline(cUserID: int.parse(_iosCallPayload!.incomingCallerId!), tUserID: int.parse(_iosCallPayload!.incomingCallReciverId.toString()), targetUsertoken: model.response!.token!);
} catch (err) {
print(err);
}
}
Future<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/";
@ -20,13 +20,13 @@ class ApiConsts {
static String chatLoginTokenUrl = chatServerBaseApiUrl + "user/";
static String chatHubConnectionUrl = chatServerBaseUrl + "ConnectionChatHub";
//Groups
static String getGroupByUserId = chatServerBaseApiUrl + "group/getgroupsbyuserid/";
static String deleteGroup = chatServerBaseApiUrl + "group/updateGroupIsDeleted/";
static String updateGroupAdmin = chatServerBaseApiUrl + "group/updateGroupAdmin/";
static String getGroupChatHistoryAsync = chatServerBaseApiUrl + "GroupChat/GetGroupChatHistoryAsync/";
static String addGroupsAndUsers = chatServerBaseApiUrl + "group/addgroupandusers/";
static String updateGroupsAndUsers = chatServerBaseApiUrl + "group/updategroupandusers/";
//Groups
static String getGroupByUserId = chatServerBaseApiUrl + "group/getgroupsbyuserid/";
static String deleteGroup = chatServerBaseApiUrl + "group/updateGroupIsDeleted/";
static String updateGroupAdmin = chatServerBaseApiUrl + "group/updateGroupAdmin/";
static String getGroupChatHistoryAsync = chatServerBaseApiUrl + "GroupChat/GetGroupChatHistoryAsync/";
static String addGroupsAndUsers = chatServerBaseApiUrl + "group/addgroupandusers/";
static String updateGroupsAndUsers = chatServerBaseApiUrl + "group/updategroupandusers/";
// static String chatSearchMember = chatLoginTokenUrl + "user/";
static String chatRecentUrl = chatServerBaseApiUrl + "UserChatHistory/"; //For a Mem
@ -34,13 +34,12 @@ 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;
//Brain Marathon Constants
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 +52,7 @@ class ApiConsts {
static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants";
//DummyCards for the UI
static CardContent dummyQuestion = const CardContent();
static int tabletMinLength = 500;
}
@ -70,5 +70,3 @@ class SharedPrefsConsts {
static String mohemmWifiPassword = "mohemmWifiPassword";
static String editItemForSale = "editItemForSale";
}

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
@ -9,11 +10,13 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
import 'package:huawei_push/huawei_push.dart' as huawei_push;
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/chat_call_kit.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/models/get_notifications_response_model.dart';
import 'package:mohem_flutter_app/ui/notifications/notification_details_page.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
@ -53,6 +56,7 @@ class AppNotifications {
this.context = context;
print("Firebase init");
await requestPermissions();
AppState().setDeviceToken = firebaseToken;
await Permission.notification.isDenied.then((bool value) {
@ -60,12 +64,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);
@ -126,23 +134,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 +192,22 @@ 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);
}
}
}

@ -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,16 +7,13 @@
// ignore_for_file: depend_on_referenced_packages
import 'package:audio_session/audio_session_web.dart';
import 'package:camera_web/camera_web.dart';
import 'package:file_picker/_internal/file_picker_web.dart';
import 'package:firebase_core_web/firebase_core_web.dart';
import 'package:firebase_messaging_web/firebase_messaging_web.dart';
import 'package:fluttertoast/fluttertoast_web.dart';
import 'package:geolocator_web/geolocator_web.dart';
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
import 'package:image_picker_for_web/image_picker_for_web.dart';
import 'package:just_audio_web/just_audio_web.dart';
// import 'package:record_web/record_web.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
import 'package:url_launcher_web/url_launcher_web.dart';
import 'package:video_player_web/video_player_web.dart';
@ -26,16 +23,13 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
AudioSessionWeb.registerWith(registrar);
CameraPlugin.registerWith(registrar);
FilePickerWeb.registerWith(registrar);
FirebaseCoreWeb.registerWith(registrar);
FirebaseMessagingWeb.registerWith(registrar);
FluttertoastWebPlugin.registerWith(registrar);
GeolocatorPlugin.registerWith(registrar);
GoogleMapsPlugin.registerWith(registrar);
ImagePickerPlugin.registerWith(registrar);
JustAudioPlugin.registerWith(registrar);
//RecordPluginWeb.registerWith(registrar);
SharedPreferencesPlugin.registerWith(registrar);
UrlLauncherPlugin.registerWith(registrar);
VideoPlayerPlugin.registerWith(registrar);

@ -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,13 +18,9 @@ import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:month_year_picker/month_year_picker.dart';
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:sizer/sizer.dart';
// test uat account
// username 199067
// pass h123456
late HubConnection chatHubConnection;
Logger logger = Logger(
// filter: null, // Use the default LogFilter (-> only log in debug mode)
printer: PrettyPrinter(
@ -74,9 +71,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,71 @@
import 'dart:convert';
import 'dart:ui';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:just_audio/just_audio.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/webrtc_payloads.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:signalr_netcore/hub_connection.dart';
class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
///////////////////// Web RTC Video Calling //////////////////////
// Video Call
late RTCPeerConnection _peerConnection;
RTCVideoRenderer _localVideoRenderer = RTCVideoRenderer();
final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
late RTCPeerConnection _pc;
late ChatProviderModel chatProvModel;
RTCVideoRenderer? localVideoRenderer;
RTCVideoRenderer? remoteRenderer;
final AudioPlayer player = AudioPlayer();
MediaStream? _localStream;
MediaStream? _remoteStream;
late CallDataModel outGoingCallData;
bool isMicOff = false;
bool isLoudSpeaker = false;
bool isCamOff = false;
bool isCallEnded = false;
bool isVideoCall = false;
bool isAudioCall = false;
bool isCallStarted = false;
bool isFrontCamera = true;
late SingleUserChatModel incomingCallData;
void initCallListeners() {
/// WebRTC Connection Variables
bool isIncomingCallLoader = true;
bool isIncomingCall = false;
bool isOutGoingCall = false;
bool isUserOnline = false;
late BuildContext providerContext;
List<MediaDeviceInfo> devices = [];
var _videoDeviceId;
void initCallListeners({required BuildContext context}) {
providerContext = context;
if (kDebugMode) {
print("=================== Call Listeners Registered =======================");
}
chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection.on("OnOfferAsync", onOfferAsync);
chatHubConnection.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection.on("OnHangUpAsync", onHangUpAsync);
chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync);
// chatHubConnection.on("OnIncomingCallAsync", OnIncomingCallAsync);
}
//Video Constraints
var videoConstraints = {
"video": {
"mandatory": {
"width": {"min": 320},
"height": {"min": 180}
},
"optional": [
{
"width": {"max": 1280}
},
{"frameRate": 25},
{"facingMode": "user"}
]
},
"frameRate": 25,
"width": 420, //420,//640,//1280,
"height": 240 //240//480//720
};
// Audio Constraints
var audioConstraints = {
Map<String, Object> audioConstraints = {
"sampleRate": 8000,
"sampleSize": 16,
"channelCount": 2,
@ -54,128 +73,322 @@ 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();
await startCall(callType: isVideoCall ? "Video" : "Audio", context: context);
_pc = await creatOfferWithCon();
connectOutgoing();
notifyListeners();
}
pc.onIceCandidate = (e) {
if (e.candidate != null) {
print(json.encode({
'candidate': e.candidate.toString(),
'sdpMid': e.sdpMid.toString(),
'sdpMlineIndex': e.sdpMLineIndex,
}));
}
};
pc.onIceConnectionState = (e) {
print(e);
};
pc.onAddStream = (stream) {
print('addStream: ' + stream.id);
_remoteRenderer.srcObject = stream;
};
return pc;
void connectOutgoing() {
isOutGoingCall = true;
notifyListeners();
}
void init() {
initRenderers();
_createPeerConnection().then((pc) {
_peerConnection = pc;
// _setRemoteDescription(widget.info);
});
Future<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);
}
void initRenderers() {
_localVideoRenderer.initialize();
_remoteRenderer.initialize();
initLocalCamera();
// OutGoing Listeners
void onCallAcceptedAsync(List<Object?>? params) async {
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));
}
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}');
notifyListeners();
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;
Navigator.push(
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
)).then((value) {
Navigator.of(providerContext).pop();
});
}
}
}
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;
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();
}
//// Listeners Methods ////
//////////////////////////// OutGoing Call End ///////////////////////////////////////
void onCallAcceptedAsync(List<Object?>? params) {}
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;
void onIceCandidateAsync(List<Object?>? params) {}
if (isCallConnected) {
if (_pc.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
print("------------------ PC Stopped ----------------------------");
_pc.close();
_pc.dispose();
}
}
if (remoteRenderer != null) {
remoteRenderer!.dispose();
remoteRenderer = null;
}
if (localVideoRenderer != null) {
localVideoRenderer!.dispose();
localVideoRenderer = null;
}
void onOfferAsync(List<Object?>? params) {}
if (_localStream != null) {
_localStream!.dispose();
_localStream = null;
}
if (chatHubConnection != null && !isUserOnline) {
chatHubConnection.stop();
}
await FlutterCallkitIncoming.endAllCalls();
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;
}
void onAnswerOffer(List<Object?>? params) {}
if (_localStream != null) {
_localStream!.dispose();
_localStream = null;
}
isOutGoingCall = false;
isIncomingCall = false;
isAudioCall = false;
return true;
}
}
void onHangUpAsync(List<Object?>? params) {}
// Incoming Listeners
void onCallDeclinedAsync(List<Object?>? params) {}
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);
// }
}
void onHangUpAsync(List<Object?>? params) {
print("--------------------- onHangUp ---------------------------------------");
endCall(isUserOnline: isUserOnline).then((bool value) {
if (isCallConnected) {
Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
isCallConnected = false;
}
isCallEnded = true;
});
}
// 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) {
print("================= On Declained ========================");
logger.d(params);
// endCall().then((bool value) {
// if (value) {
// isCallEnded = true;
// notifyListeners();
// }
// });
if (params != null) {
endCall(isUserOnline: isUserOnline).then((bool value) {
// if (isCallConnected) {
Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
// isCallConnected = false;
// }
isCallEnded = 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 {
@ -184,4 +397,268 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
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!);
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();
localVideoRenderer = RTCVideoRenderer();
remoteRenderer = RTCVideoRenderer();
await localVideoRenderer!.initialize();
_localStream ??= await navigator.mediaDevices.getUserMedia(isVideoCall
// ? Platform.isIOS
// ? // iOS media constraints for maximum quality camera
// {
// '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)
// },
// },
// }
// : // Android media constraints for maximum quality camera
// {
// '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": [
{'sourceId': devices[1].deviceId},
{
"width": {"max": 1080}
},
{"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();
}
}

@ -34,12 +34,14 @@ import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat
as fav;
import 'package:mohem_flutter_app/models/chat/target_users.dart';
import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:uuid/uuid.dart';
@ -95,27 +97,52 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
/// Search Provider
List<ChatUser>? chatUsersList = [];
int pageNo = 1;
bool disbaleChatForThisUser = false;
List<groups.GroupResponse>? uGroups = [], searchGroups = [];
bool disableChatForThisUser = false;
bool isUserOnline = false;
bool isCall = false;
userLoginToken.UserAutoLoginModel userLoginData = userLoginToken.UserAutoLoginModel();
Future<void> getUserAutoLoginToken() async {
userLoginToken.UserAutoLoginModel userLoginResponse =
await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
} else {
AppState().setchatUserDetails = userLoginResponse;
Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
);
disbaleChatForThisUser = true;
try {
userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
AppState().setchatUserDetails = userLoginResponse;
Utils.saveStringFromPrefs("userLoginChatDetails", jsonEncode(userLoginResponse.response));
isUserOnline = true;
if(Platform.isIOS){
AppState().setisUserOnline = true;
}
} else {
AppState().setchatUserDetails = userLoginResponse;
Utils.saveStringFromPrefs("userLoginChatDetails", "null");
Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
);
disableChatForThisUser = false;
isUserOnline = false;
if(Platform.isIOS){
AppState().setisUserOnline = false;
}
notifyListeners();
}
} catch (e) {
disableChatForThisUser = true;
isUserOnline = false;
if(Platform.isIOS){
AppState().setisUserOnline = false;
}
notifyListeners();
}
}
Future<void> buildHubConnection() async {
chatHubConnection = await getHubConnection();
Future<void> buildHubConnection({required BuildContext context, required ChatCallProvider ccProvider}) async {
try {
chatHubConnection = await getHubConnection();
} catch (e) {
Utils.showToast(e.toString());
}
await chatHubConnection.start();
if (kDebugMode) {
logger.i("Hub Conn: Startedddddddd");
@ -126,6 +153,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
//group On message
chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived);
ccProvider.initCallListeners(context: context);
}
Future<HubConnection> getHubConnection() async {
@ -156,7 +184,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
"OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
chatHubConnection.on(
"OnGetGroupUserStatusAsync", getGroupUserStatus);
chatHubConnection.on(
"OnAddGroupChatHistoryAsync", groupChatHistoryAsync);
//
// {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]}
@ -168,7 +197,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<void> getUserRecentChats() async {
ChatUserModel recentChat = await ChatApiClient().getRecentChats();
ChatUserModel favUList = await ChatApiClient().getFavUsers();
// userGroups = await ChatApiClient().getGroupsByUserId();
userGroups = await ChatApiClient().getGroupsByUserId();
if (favUList.response != null && recentChat.response != null) {
favUsersList = favUList.response!;
favUsersList.sort((ChatUser a, ChatUser b) =>
@ -304,10 +333,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x)));
Future<dynamic> uploadAttachments(String userId, File file) async {
Future<dynamic> uploadAttachments(String userId, File file, String fileSource) async {
dynamic result;
try {
Object? response = await ChatApiClient().uploadMedia(userId, file);
Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource);
if (response != null) {
result = response;
} else {
@ -333,9 +362,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
void getGroupUserStatus(List<Object?>? args){
//note: need to implement this function...
//note: need to implement this function when group user status
print(args);
}
void groupChatHistoryAsync(List<Object?>? args){
//need to imlement this event when any group details updated.
print(args);
}
void onChatSeen(List<Object?>? args) {
dynamic items = args!.toList();
@ -423,6 +457,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<void> onMsgReceived(List<Object?>? parameters) async {
List<SingleUserChatModel> data = [], temp = [];
for (dynamic msg in parameters!) {
data = getSingleUserChatModel(jsonEncode(msg));
temp = getSingleUserChatModel(jsonEncode(msg));
@ -432,15 +467,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
data.first.currentUserId = temp.first.targetUserId;
data.first.currentUserName = temp.first.targetUserName;
data.first.currentUserEmail = temp.first.targetUserEmail;
if (data.first.fileTypeId == 12 ||
data.first.fileTypeId == 4 ||
data.first.fileTypeId == 3) {
data.first.image = await ChatApiClient().downloadURL(
fileName: data.first.contant!,
fileTypeDescription:
data.first.fileTypeResponse!.fileTypeDescription ??
"image/jpg");
if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) {
data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg",fileSource: 1);
}
if (data.first.userChatReplyResponse != null) {
if (data.first.fileTypeResponse != null) {
@ -452,7 +480,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
fileName: data.first.userChatReplyResponse!.contant!,
fileTypeDescription:
data.first.fileTypeResponse!.fileTypeDescription ??
"image/jpg");
"image/jpg",
fileSource:1
);
data.first.userChatReplyResponse!.isImageLoaded = true;
}
}
@ -486,7 +516,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
);
}
}
setMsgTune();
if (data.first.chatEventId != 3) {
setMsgTune();
}
if (isChatScreenActive && data.first.currentUserId == receiverID) {
userChatHistory.insert(0, data.first);
} else {
@ -538,7 +570,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
fileName: data.first.contant!,
fileTypeDescription:
data.first.fileTypeResponse!.fileTypeDescription ??
"image/jpg");
"image/jpg",
fileSource:2
);
}
if (data.first.groupChatReplyResponse != null) {
if (data.first.fileTypeResponse != null) {
@ -550,7 +584,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
fileName: data.first.groupChatReplyResponse!.contant!,
fileTypeDescription:
data.first.fileTypeResponse!.fileTypeDescription ??
"image/jpg");
"image/jpg",
fileSource:2);
data.first.groupChatReplyResponse!.isImageLoaded = true;
}
}
@ -618,10 +653,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void OnSubmitChatAsync(List<Object?>? parameters) {
print(isChatScreenActive);
print(receiverID);
print(isChatScreenActive);
logger.i(parameters);
List<SingleUserChatModel> data = [], temp = [];
for (dynamic msg in parameters!) {
data = getSingleUserChatModel(jsonEncode(msg));
@ -634,9 +665,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
data.first.currentUserEmail = temp.first.targetUserEmail;
}
if (isChatScreenActive && data.first.currentUserId == receiverID) {
int index = userChatHistory.indexWhere(
(SingleUserChatModel element) => element.userChatHistoryId == 0);
logger.d(index);
int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0);
userChatHistory[index] = data.first;
}
@ -698,6 +727,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return 13;
case ".mp3":
return 14;
case ".mp4":
return 16;
case ".mov":
return 16;
case ".avi":
return 16;
case ".flv":
return 16;
default:
return 0;
}
@ -735,6 +772,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return "audio/aac";
case ".mp3":
return "audio/mp3";
case ".mp4":
return "video/mp4";
case ".avi":
return "video/avi";
case ".flv":
return "video/flv";
case ".mov":
return "video/mov";
default:
return "";
}
@ -761,7 +806,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
msg = voiceFile!.path.split("/").last;
} else {
msg = message.text;
logger.w(msg);
}
SingleUserChatModel data = SingleUserChatModel(
userChatHistoryId: 0,
@ -874,7 +918,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
if (kDebugMode) {
logger.i("model data: " + jsonEncode(data));
}
groupChatHistory.insert(0, data);
// groupChatHistory.insert(0, data);
isTextMsg = false;
isReplyMsg = false;
isAttachmentMsg = false;
@ -951,7 +995,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
logger.d("// Normal Image Message");
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), selectedFile);
AppState().chatDetails!.response!.id.toString(), selectedFile,'2');
String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context);
sendGroupChatToServer(
@ -973,7 +1017,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
logger.d("// Image as Reply Msg");
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), selectedFile);
AppState().chatDetails!.response!.id.toString(), selectedFile,'2');
String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context);
sendGroupChatToServer(
@ -1012,7 +1056,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isRecoding = false;
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), voiceFile);
AppState().chatDetails!.response!.id.toString(), voiceFile,'2');
String? ext = getFileExtension(voiceFile.path);
Utils.hideLoading(context);
sendGroupChatToServer(
@ -1050,7 +1094,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), voiceFile);
AppState().chatDetails!.response!.id.toString(), voiceFile,'2');
String? ext = getFileExtension(voiceFile.path);
Utils.hideLoading(context);
sendGroupChatToServer(
@ -1119,7 +1163,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return;
}
sendChatToServer(
chatEventId: 1,
chatEventId: isCall ? 3 : 1,
fileTypeId: null,
targetUserId: targetUserId,
targetUserName: targetUserName,
@ -1156,7 +1200,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
logger.d("// Normal Image Message");
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), selectedFile);
AppState().chatDetails!.response!.id.toString(), selectedFile,'1');
String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context);
sendChatToServer(
@ -1176,7 +1220,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
logger.d("// Image as Reply Msg");
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), selectedFile);
AppState().chatDetails!.response!.id.toString(), selectedFile,'1');
String? ext = getFileExtension(selectedFile.path);
Utils.hideLoading(context);
sendChatToServer(
@ -1212,7 +1256,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isRecoding = false;
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), voiceFile);
AppState().chatDetails!.response!.id.toString(), voiceFile, '1');
String? ext = getFileExtension(voiceFile.path);
Utils.hideLoading(context);
sendChatToServer(
@ -1247,7 +1291,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Utils.showLoading(context);
dynamic value = await uploadAttachments(
AppState().chatDetails!.response!.id.toString(), voiceFile);
AppState().chatDetails!.response!.id.toString(), voiceFile, '1');
String? ext = getFileExtension(voiceFile.path);
Utils.hideLoading(context);
sendChatToServer(
@ -1353,8 +1397,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
bool checkFileSize(String path) {
int fileSizeLimit = 1024;
File f = File(path);
double fileSizeInKB = f.lengthSync() / 1024;
double fileSizeInMB = fileSizeInKB / 1024;
double fileSizeInKB = f.lengthSync() / 5000;
double fileSizeInMB = fileSizeInKB / 5000;
if (fileSizeInKB > fileSizeLimit) {
return false;
} else {
@ -1523,7 +1567,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
void disposeData() {
if (!disbaleChatForThisUser) {
if (!disableChatForThisUser) {
search.clear();
isChatScreenActive = false;
receiverID = 0;
@ -1541,6 +1585,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
pChatHistory?.clear();
uGroups?.clear();
searchGroup?.clear();
// callP.stopListeners();
chatHubConnection.stop();
AppState().chatDetails = null;
}
@ -1660,17 +1705,20 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<void> getChatMedia(BuildContext context,
{required String fileName,
required String fileTypeName,
required int fileTypeID}) async {
required int fileTypeID,
required int fileSource}) async {
Utils.showLoading(context);
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8 ||
fileTypeID == 2) {
fileTypeID == 2 || fileTypeID ==16) {
Uint8List encodedString = await ChatApiClient().downloadURL(
fileName: fileName,
fileTypeDescription: getFileTypeDescription(fileTypeName));
fileTypeDescription: getFileTypeDescription(fileTypeName),
fileSource: fileSource
);
try {
String path = await downChatMedia(encodedString, fileTypeName ?? "");
Utils.hideLoading(context);

@ -1,4 +1,5 @@
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';
@ -26,7 +27,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 +45,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);
@ -304,10 +306,15 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
if (details.date.month == formattedDate.month && details.date.year == formattedDate.year) {
int val = details.date.day;
//check day is off
if (getDayHoursTypeDetailsList.isNotEmpty) {
bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF';
bool isDayIsPresent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].aBSENTFLAG == 'Y';
List<GetDayHoursTypeDetailsList> getDayHours = getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) => DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date.day).toList();
if (getDayHours.isNotEmpty) {
bool isDayIsOff = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].dAYTYPE == 'OFF';
bool isDayIsPresent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].aBSENTFLAG == 'Y';
if (isDayIsOff) {
return Container(

@ -1,381 +1,604 @@
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/consts.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;
IncomingCall({Key? key, required this.incomingCallData, this.isVideoCall}) : super(key: key);
bool isCallConnected = false;
class StartCallPage extends StatefulWidget {
@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();
bool isOutGoingCall = false;
bool isIncomingCall = false;
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]));
print(sessionData.toRawJson());
if (provider.isUserOnline) {
cProv.isUserOnline = provider.isUserOnline;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
}
await cProv.startIncomingCallViaKit(inCallData: sessionData!.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
cProv.init();
isCallConnected = true;
} else {
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);
}
}
}
}
void startIosCall() async {
print(await Utils.getStringFromPrefs("iosCallPayload"));
IosCallPayload _iosCallPayload = IosCallPayload.fromRawJson(await Utils.getStringFromPrefs("iosCallPayload"));
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) {
cProv.isUserOnline = provider.isUserOnline;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
}
await cProv.startIncomingCallViaKit(inCallData: inCallData.toJson(), isVCall: callType == "video" ? true : false);
cProv.init();
isCallConnected = true;
} else {
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
cProv.isUserOnline = provider.isUserOnline;
UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserCallToken(userid: userID.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 (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 provider, ChatProviderModel cpm, Widget? child) {
return provider.isIncomingCallLoader
? const SizedBox(
width: double.infinity,
height: double.infinity,
child: Center(child: CircularProgressIndicator()),
)
: provider.isIncomingCall
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!provider.isAudioCall && provider.isVideoCall)
RTCVideoView(
provider.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
// filterQuality: FilterQuality.high,
key: const Key('remote'),
),
if (provider.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
intialVisibility: true,
horizontalSpace: 20,
shadowBorderRadius: 50,
initialPosition: AnchoringPosition.topLeft,
dragController: dragController,
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
child: SizedBox(
height: 200,
width: 140,
child: RTCVideoView(
provider.localVideoRenderer!,
mirror: true,
// filterQuality: FilterQuality.high,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.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(
provider.incomingCallData.targetUserName!,
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
),
const Text(
"On Call",
style: TextStyle(
fontSize: 16,
decoration: TextDecoration.none,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
const SizedBox(
height: 2,
),
],
),
),
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
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(
onPressed: () {
_submit();
},
elevation: 2.0,
fillColor: MyColors.green2DColor,
padding: const EdgeInsets.all(
15.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call,
color: MyColors.white,
size: 35.0,
),
// if (provider.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.switchCamera();
},
elevation: 2.0,
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.micOff();
},
elevation: 2.0,
fillColor: provider.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
backToHome();
provider.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
// print("Reintiiiiiiitttiiiiiiii");
// provider.initStreams();
}
});
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
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(),
);
}
)
: provider.isOutGoingCall
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!provider.isAudioCall && provider.isVideoCall)
RTCVideoView(
provider.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
key: const Key('remote'),
),
if (provider.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
intialVisibility: true,
horizontalSpace: 20,
shadowBorderRadius: 50,
initialPosition: AnchoringPosition.topLeft,
dragController: dragController,
normalShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
draggingShadow: const BoxShadow(spreadRadius: 0.0, blurRadius: 0.0),
child: SizedBox(
height: 200,
width: 140,
child: RTCVideoView(
provider.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.3,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
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(
provider.outGoingCallData.receiverName!,
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
color: MyColors.white,
letterSpacing: -1.26,
height: 23 / 12,
),
),
const Text(
"On Call",
style: TextStyle(
fontSize: 16,
decoration: TextDecoration.none,
fontWeight: FontWeight.w600,
color: Color(
0xffC6C6C6,
),
letterSpacing: -0.48,
height: 23 / 24,
),
),
const SizedBox(
height: 2,
),
],
),
),
),
],
),
],
),
),
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.only(
bottom: 20,
left: 40,
right: 40,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// if (provider.isVideoCall)
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.loudOn();
},
elevation: 2.0,
fillColor: provider.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.volume_up,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.switchCamera();
},
elevation: 2.0,
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.micOff();
},
elevation: 2.0,
fillColor: provider.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
),
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
}
});
},
elevation: 2.0,
fillColor: MyColors.redA3Color,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: const Icon(
Icons.call_end,
color: MyColors.white,
size: 30.0,
),
),
],
),
),
),
],
),
)
: const SizedBox();
},
),
);
}
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;
// }
// }
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,
),
),
],
);
}
}
/// if (Platform.isAndroid) {
// SystemNavigator.pop();
// } else if (Platform.isIOS) {
// exit(0);
// }

@ -1,16 +1,15 @@
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/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 +22,175 @@ 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;
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) {
if (chatcp.isCallEnded) {
Navigator.pop(context);
}
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).pop();
// print("Reintiiiiiiitttzzzz");
// chatcp.initStreams();
}
});
},
elevation: 2.0,
fillColor: isLoudSpeaker ? MyColors.green2DColor : Colors.grey,
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;
// }
// });
// }
// }

@ -82,7 +82,7 @@ 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) {
@ -342,7 +342,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) {

@ -1,5 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -10,11 +10,9 @@ 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';
@ -23,9 +21,9 @@ import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart';
import 'package:mohem_flutter_app/ui/chat/common.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 {
@ -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();
if (await camPer.isGranted) {
makeCall(callType: "VIDEO");
} else {
Permission.camera.request().isGranted.then((value) {
makeCall(callType: "VIDEO");
});
}
}),
// if (Platform.isAndroid)
21.width,
],
),
body: SafeArea(
@ -149,7 +165,7 @@ 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 ||
@ -159,7 +175,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
// || m.userChatHistory[i].fileTypeId! == 2
) {
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 +368,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)));
}
}

@ -7,6 +7,8 @@ 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';
@ -28,12 +30,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
@ -45,7 +50,7 @@ class _ChatHomeState extends State<ChatHome> {
void fetchAgain() {
if (chatHubConnection.state != HubConnectionState.Connected) {
data.getUserAutoLoginToken().whenComplete(() async {
await data.buildHubConnection();
await data.buildHubConnection(context: context, ccProvider: callProvider);
data.getUserRecentChats();
});
@ -54,11 +59,6 @@ class _ChatHomeState extends State<ChatHome> {
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);
// }
});
}
}
@ -68,7 +68,8 @@ 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 +92,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 +108,7 @@ class _ChatHomeState extends State<ChatHome> {
},
children: <Widget>[
ChatHomeScreen(),
// GropChatHomeScreen(),
GropChatHomeScreen(),
ChatFavoriteUsersScreen(),
AppState().getempStatusIsManager ? const MyTeamScreen() : const SizedBox(),
],

@ -217,9 +217,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,

@ -199,9 +199,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,

@ -22,6 +22,7 @@ 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})
@ -100,7 +101,7 @@ class GroupChatBubble extends StatelessWidget {
Uint8List encodedString = await ChatApiClient().downloadURL(
fileName: data.contant!,
fileTypeDescription: provider.getFileTypeDescription(
data.fileTypeResponse!.fileTypeName ?? ""));
data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 2);
// try {
File sFile = await provider.downChatVoice(
encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
@ -245,8 +246,11 @@ class GroupChatBubble extends StatelessWidget {
child: showImage(
isReplyPreview: false,
fileName: cItem.contant!,
fileTypeDescription:
cItem.fileTypeResponse!.fileTypeDescription)
fileTypeDescription: cItem.fileTypeResponse != null &&
cItem.fileTypeResponse!.fileTypeDescription !=
null
? cItem.fileTypeResponse!.fileTypeDescription
: cItem.fileTypeResponse!.fileTypeName)
.onPress(() {
showDialog(
context: context,
@ -258,17 +262,19 @@ class GroupChatBubble extends StatelessWidget {
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
currentWaveBubble(context, cItem)
currentWaveBubble(context, cItem),
if (fileTypeID == 16)
showVideoThumb(context, cItem)
else
Row(
children: [
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""),
height: 30,
width: 22,
@ -279,12 +285,12 @@ class GroupChatBubble extends StatelessWidget {
textDirection: provider.getTextDirection(cItem.contant ?? ""),
child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
//|| fileTypeID == 2
)
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, size: 16)
],
),
@ -422,23 +428,27 @@ class GroupChatBubble extends StatelessWidget {
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
recipetWaveBubble(context, cItem)
recipetWaveBubble(context, cItem),
if (fileTypeID == 16)
showVideoThumb(context, cItem)
else
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
cItem.currentUserName!.toText10(
color: Colors.black,
).paddingOnly(bottom: 5),
cItem.currentUserName!
.toText10(
color: Colors.black,
)
.paddingOnly(bottom: 5),
Row(
children: [
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""),
height: 30,
width: 22,
@ -452,21 +462,23 @@ class GroupChatBubble extends StatelessWidget {
.toText12(color: Colors.white)
.expanded),
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
//|| fileTypeID == 2
)
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),
child: dateTime
.toText10(
color: Colors.white.withOpacity(.71),
)
.paddingOnly(top: 5),
),
],
),
@ -492,7 +504,7 @@ class GroupChatBubble extends StatelessWidget {
} else {
return FutureBuilder<Uint8List>(
future: ChatApiClient().downloadURL(
fileName: fileName, fileTypeDescription: fileTypeDescription),
fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource:2),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
if (snapshot.data == null) {
@ -557,6 +569,11 @@ class GroupChatBubble extends StatelessWidget {
).circle(5);
}
Widget showVideoThumb(BuildContext context, GetGroupChatHistoryAsync data) {
return LoadVideo(data: data);
}
Widget recipetWaveBubble(
BuildContext context, GetGroupChatHistoryAsync data) {
return Container(
@ -641,3 +658,51 @@ 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 Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
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,
),
)
],
),
));
}
}

@ -153,17 +153,17 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
);
},
).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
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.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!);
fileTypeName: m.groupChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.groupChatHistory[i].fileTypeId!, fileName: m.groupChatHistory[i].contant!,fileSource: 2);
}
}
});
@ -362,7 +362,7 @@ class _GroupChatDetailScreenState extends State<GroupChatDetailScreen> {
}
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(),

@ -1,14 +1,18 @@
import 'dart:async';
import 'dart:convert';
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';
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/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
@ -16,10 +20,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/incoming_call_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';
@ -32,8 +42,7 @@ import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
late HubConnection chatHubConnection;
import 'package:http/http.dart' as http;
class DashboardScreen extends StatefulWidget {
DashboardScreen({Key? key}) : super(key: key);
@ -48,20 +57,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 +81,52 @@ 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:
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) {
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 +146,24 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
if (!cProvider.disbaleChatForThisUser) {
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!);
});
@ -153,17 +211,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 +237,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 +266,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(
@ -271,106 +378,106 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
child: Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
return (model.isAttendanceTrackingLoading
? GetAttendanceTrackingShimmer()
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
gradient: const LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
]),
),
child: Stack(
alignment: Alignment.center,
? GetAttendanceTrackingShimmer()
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
gradient: const LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [
MyColors.gradiantEndColor,
MyColors.gradiantStartColor,
]),
),
child: Stack(
alignment: Alignment.center,
children: [
if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"),
Column(
LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true),
if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white),
if (model.isTimeRemainingInSeconds != 0)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
9.height,
Directionality(
textDirection: ui.TextDirection.ltr,
child: CountdownTimer(
endTime: model.endTime,
onEnd: null,
endWidget: "00:00:00".toText14(color: Colors.white, isBold: true),
textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold),
),
),
LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white),
9.height,
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(20)),
child: LinearProgressIndicator(
value: model.progress,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
),
],
),
],
).paddingOnly(top: 12, right: 15, left: 12),
),
Row(
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true),
if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white),
if (model.isTimeRemainingInSeconds != 0)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
9.height,
Directionality(
textDirection: ui.TextDirection.ltr,
child: CountdownTimer(
endTime: model.endTime,
onEnd: null,
endWidget: "00:00:00".toText14(color: Colors.white, isBold: true),
textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold),
),
),
LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white),
9.height,
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(20)),
child: LinearProgressIndicator(
value: model.progress,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
),
],
),
],
).paddingOnly(top: 12, right: 15, left: 12),
),
Row(
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.checkIn.tr().toText12(color: Colors.white),
(model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn)
.toString()
.toText14(color: Colors.white, isBold: true),
4.height,
],
).paddingOnly(left: 12, right: 12),
),
Container(
margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0),
width: 45,
height: 45,
padding: const EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
color: Color(0xff259EA4),
borderRadius: BorderRadius.only(
bottomRight: AppState().isArabic(context) ? Radius.circular(0) : Radius.circular(15),
bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0),
),
),
child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"),
).onPress(() {
showMyBottomSheet(
context,
callBackFunc: () {},
child: MarkAttendanceWidget(model, isFromDashboard: true),
);
}),
],
),
LocaleKeys.checkIn.tr().toText12(color: Colors.white),
(model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn)
.toString()
.toText14(color: Colors.white, isBold: true),
4.height,
],
).paddingOnly(left: 12, right: 12),
),
Container(
margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0),
width: 45,
height: 45,
padding: const EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
color: Color(0xff259EA4),
borderRadius: BorderRadius.only(
bottomRight: AppState().isArabic(context) ? Radius.circular(0) : Radius.circular(15),
bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0),
),
),
],
),
).onPress(
() {
Navigator.pushNamed(context, AppRoutes.todayAttendance);
},
))
child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"),
).onPress(() {
showMyBottomSheet(
context,
callBackFunc: () {},
child: MarkAttendanceWidget(model, isFromDashboard: true),
);
}),
],
),
],
),
],
),
).onPress(
() {
Navigator.pushNamed(context, AppRoutes.todayAttendance);
},
))
.animatedSwither();
},
),
@ -431,48 +538,48 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
return model.isOffersLoading
? const OffersShimmerWidget()
: InkWell(
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 73,
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(
Radius.circular(100),
),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(50),
),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(
data.getOffersList[index].logo ?? "",
fit: BoxFit.contain,
),
),
),
),
4.height,
Expanded(
child: AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(
Radius.circular(100),
),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(50),
),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(
data.getOffersList[index].logo ?? "",
fit: BoxFit.contain,
),
],
),
),
),
);
4.height,
Expanded(
child: AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
),
],
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 8.width,
itemCount: 9),
@ -565,30 +672,29 @@ 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()
? const SizedBox()
: Positioned(
right: 0,
top: 0,
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)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white),
),
);
right: 0,
top: 0,
child: Container(
padding: const EdgeInsets.only(left: 4, right: 4),
alignment: Alignment.center,
decoration: BoxDecoration(color: data.disableChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white),
),
);
},
),
],
@ -612,9 +718,9 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
} else if (index == 3) {
Navigator.pushNamed(context, AppRoutes.itemsForSale);
} else if (index == 4) {
if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) {
// if (!cProvider.disableChatForThisUser) {
Navigator.pushNamed(context, AppRoutes.chat);
}
// }
}
},
),
@ -637,6 +743,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
}
});
Navigator.pushNamed(context, AppRoutes.offersAndDiscountsDetails, arguments: getOffersDetailList);
}

@ -1,3 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -8,10 +10,17 @@ 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';
import 'package:mohem_flutter_app/classes/chat_call_kit.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/notifications.dart';
@ -21,15 +30,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/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:wifi_iot/wifi_iot.dart';
class LoginScreen extends StatefulWidget {
@ -41,7 +51,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 +59,7 @@ class _LoginScreenState extends State<LoginScreen> {
MemberLoginListModel? _memberLoginList;
late final FirebaseMessaging _firebaseMessaging;
IosCallPayload? _iosCallPayload;
bool _autoLogin = false;
@ -58,9 +69,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 +84,99 @@ class _LoginScreenState extends State<LoginScreen> {
// if (kReleaseMode) {
// checkDeviceSafety();
// }
WidgetsBinding.instance.addObserver(this);
if (Platform.isAndroid) {
callListeners();
checkAndNavigationCallingPage();
}
if (Platform.isIOS) {
setupVoIPCallBacks();
}
}
// IOS Voip Call
void setupVoIPCallBacks() {
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();
};
voIPKit.onDidRejectIncomingCall = (
String uuid,
String callerId,
) async {
await ChatVoipCall().voipDeclineCall(_iosCallPayload);
await voIPKit.endCall();
};
voIPKit.onDidAcceptIncomingCall = (
String uuid,
String callerId,
) async {
await connectCall(uuid: uuid, callDetails: callerId);
voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
voIPKit.callConnected();
};
}
void _timeOut() async {
timeOutTimer = Timer(const Duration(seconds: 25), () async {
String? incomingCallerName = await voIPKit.getIncomingCallerName();
voIPKit.unansweredIncomingCall(
skipLocalNotification: false,
missedCallTitle: '📞 Missed call',
missedCallBody: 'There was a call from $incomingCallerName',
);
await ChatVoipCall().voipDeclineCall(_iosCallPayload);
await voIPKit.endCall();
});
}
Future<void> connectCall({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);
}
await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
MaterialPageRoute pageRoute = await MaterialPageRoute(builder: (BuildContext context) => StartCallPage());
Navigator.push(context, pageRoute);
} else if (AppState().getisUserOnline) {
await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
BuildContext context = AppRoutes.navigatorKey.currentContext!;
MaterialPageRoute pageRoute = await MaterialPageRoute(builder: (BuildContext context) => StartCallPage());
Navigator.push(context, pageRoute);
} else {
FlutterCallkitIncoming.endAllCalls();
Utils.showToast("Something wen't wrong");
}
}
// void checkDeviceSafety() async {
@ -87,6 +195,83 @@ 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");
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.toString()}\n');
});
} on Exception {
logger.log(Level.info, "EXCEPTION-ON-EVENTS");
}
}
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();
@ -224,7 +409,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";

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

@ -360,6 +360,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) {

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

@ -8,21 +8,25 @@ import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/attachment_options.dart';
final ImagePicker picker = ImagePicker();
class ImageOptions {
static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) {
showMyBottomSheet(
context,
callBackFunc: () {},
child: AttachmentOptions(
showFilesOption: showFilesOption,
onCameraTap: () async {
if (Platform.isAndroid) {
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);
@ -33,7 +37,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);
@ -126,7 +130,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();
@ -137,7 +141,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);

Loading…
Cancel
Save