diff --git a/.gitignore b/.gitignore index cff0e374..55ad4693 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ pubspec.lock .pub-cache/ .pub/ /build/ +/ios/Frameworks/ # Web related lib/generated_plugin_registrant.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index f1799225..b5f2d00f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -56,6 +56,10 @@ android { compileSdkVersion 34 // ndkVersion "24.0.8215888" + buildFeatures { + viewBinding true + } + sourceSets { main.java.srcDirs += 'src/main/kotlin' } @@ -69,7 +73,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.ejada.hmg" - minSdkVersion 24 + minSdkVersion 26 targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName @@ -117,15 +121,16 @@ android { packagingOptions { exclude 'META-INF/proguard/androidx-annotations.pro' -// pickFirst 'lib/x86/libc++_shared.so' -// pickFirst 'lib/x86_64/libc++_shared.so' -// pickFirst 'lib/armeabi-v7a/libc++_shared.so' -// pickFirst 'lib/arm64-v8a/libc++_shared.so' -// pickFirst '**/*.so' + pickFirst 'lib/x86/libc++_shared.so' + pickFirst 'lib/x86_64/libc++_shared.so' + pickFirst 'lib/armeabi-v7a/libc++_shared.so' + pickFirst 'lib/arm64-v8a/libc++_shared.so' + pickFirst '**/*.so' } compileOptions { +// coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } @@ -136,13 +141,15 @@ flutter { } dependencies { +// coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "com.google.firebase:firebase-messaging:21.0.0" // implementation ('com.google.firebase:firebase-inappmessaging-display:19.1.2',{ // exclude group: 'com.google.protobuf',module: 'protobuf-javalite' // exclude group: 'com.google.protobuf',module: 'protobuf-lite' // }) - implementation 'pub.devrel:easypermissions:0.4.0' + implementation 'pub.devrel:easypermissions:3.0.0' // implementation 'com.google.firebase:firebase-inappmessaging-display:17.2.0' // implementation 'com.google.firebase:firebase-inappmessaging-display:17.2.0' implementation 'com.google.guava:guava:27.0.1-android' @@ -163,9 +170,34 @@ dependencies { // implementation "us.zoom.videosdk:ZoomVideoSDK:1.10.11" // implementation group: 'us.zoom.videosdk', name: 'zoomvideosdk-core', version: '1.10.11' - implementation "us.zoom.videosdk:zoomvideosdk-core:1.10.1" - implementation "us.zoom.videosdk:zoomvideosdk-annotation:1.10.1" - implementation "us.zoom.videosdk:zoomvideosdk-videoeffects:1.10.1" +// implementation "us.zoom.videosdk:zoomvideosdk-core:1.10.1" +// implementation "us.zoom.videosdk:zoomvideosdk-annotation:1.10.1" +// implementation "us.zoom.videosdk:zoomvideosdk-videoeffects:1.10.1" + + implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.squareup.retrofit2:adapter-java8:2.4.0' + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.google.android.gms:play-services-location:21.3.0' + implementation 'com.squareup.okhttp3:okhttp:4.10.0' + implementation 'androidx.test.ext:junit:1.1.5' + implementation 'com.android.volley:volley:1.2.1' + def room_version = "2.4.0-alpha04" + implementation "androidx.room:room-runtime:$room_version" + annotationProcessor "androidx.room:room-compiler:$room_version" + implementation 'net.zetetic:android-database-sqlcipher:4.5.2' + implementation 'com.intuit.ssp:ssp-android:1.1.0' + implementation 'com.intuit.sdp:sdp-android:1.1.0' + implementation 'com.github.bumptech.glide:glide:4.12.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' + +// implementation "com.mapbox.maps:android:10.16.6" + implementation 'com.mapbox.maps:android:11.3.1' + + implementation files('libs/PenNavUI.aar') + implementation files('libs/Penguin.aar') + implementation files('libs/PenguinRenderer.aar') implementation "org.jetbrains.anko:anko-commons:0.10.4" implementation 'com.github.kittinunf.fuel:fuel:2.3.0' //for JVM @@ -177,6 +209,7 @@ dependencies { implementation 'com.facebook.stetho:stetho-urlconnection:1.5.1' implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.9.0' androidTestImplementation "androidx.test:core:1.4.0" } diff --git a/android/app/libs/PenNavUI.aar b/android/app/libs/PenNavUI.aar new file mode 100644 index 00000000..6291c4ec Binary files /dev/null and b/android/app/libs/PenNavUI.aar differ diff --git a/android/app/libs/Penguin.aar b/android/app/libs/Penguin.aar new file mode 100644 index 00000000..7cdc0b71 Binary files /dev/null and b/android/app/libs/Penguin.aar differ diff --git a/android/app/libs/PenguinRenderer.aar b/android/app/libs/PenguinRenderer.aar new file mode 100644 index 00000000..c60248c9 Binary files /dev/null and b/android/app/libs/PenguinRenderer.aar differ diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 69cd8026..ab7b2ca4 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -53,4 +53,20 @@ } -dontwarn com.opentok.android.** --dontwarn com.opentok.otc.** \ No newline at end of file +-dontwarn com.opentok.otc.** + +-dontwarn penguin.com.pennav.Model.Navigation.NearLandmark + +-keep,includedescriptorclasses class net.sqlcipher.** { *; } +-keep,includedescriptorclasses interface net.sqlcipher.** { *; } + +-keep class retrofit2.** { *; } +-keep class okhttp3.** { *; } +-dontwarn retrofit2.** + +-keep class com.google.gson.** { *; } +-dontwarn com.google.gson.** + +# Penguin classes +-keep class com.peng.pennavmap.models.** { *; } +-keep class com.peng.pennavmap.db.** { *; } \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b1540644..58ac88b7 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,21 +8,36 @@ FlutterApplication and put your custom class here. --> - - - - + + + + - + - + + + + + + + + + + + + + + + + @@ -42,6 +57,7 @@ + @@ -59,13 +75,13 @@ diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt index 8aa1ef85..df41e342 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt @@ -1,21 +1,19 @@ package com.ejada.hmg -import android.app.NotificationChannel -import android.app.NotificationManager -import android.content.ContentResolver -import android.media.AudioAttributes -import android.net.Uri -import android.os.Bundle -import android.util.Log +import android.content.Intent +import android.content.pm.PackageManager import android.os.Build +import android.util.Log import android.view.WindowManager import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi +import com.cloud.diplomaticquarterapp.PenguinInPlatformBridge import com.ejada.hmg.utils.* import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.GeneratedPluginRegistrant class MainActivity: FlutterFragmentActivity() { + @RequiresApi(Build.VERSION_CODES.O) override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine); // Create Flutter Platform Bridge @@ -23,6 +21,7 @@ class MainActivity: FlutterFragmentActivity() { PlatformBridge(flutterEngine, this).create() OpenTokPlatformBridge(flutterEngine, this).create() + PenguinInPlatformBridge(flutterEngine, this).create() // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // val mChannel = NotificationChannel("video_call_noti", "video call", NotificationManager.IMPORTANCE_HIGH) @@ -43,6 +42,25 @@ class MainActivity: FlutterFragmentActivity() { // val time = timeToMillis("04:00:00", "HH:mm:ss") + } + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } + val intent = Intent("PERMISSION_RESULT_ACTION").apply { + putExtra("PERMISSION_GRANTED", granted) + } + sendBroadcast(intent) + + // Log the request code and permission results + Log.d("PermissionsResult", "Request Code: $requestCode") + Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}") + Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}") + } override fun onResume() { diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PenguinInPlatformBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PenguinInPlatformBridge.kt new file mode 100644 index 00000000..93affaef --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PenguinInPlatformBridge.kt @@ -0,0 +1,52 @@ +package com.cloud.diplomaticquarterapp +import com.ejada.hmg.MainActivity +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import com.cloud.diplomaticquarterapp.penguin.PenguinView +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel + +class PenguinInPlatformBridge( + private var flutterEngine: FlutterEngine, + private var mainActivity: MainActivity +) { + + private lateinit var channel: MethodChannel + + companion object { + private const val CHANNEL = "launch_penguin_ui" + } + + @RequiresApi(Build.VERSION_CODES.O) + fun create() { +// openTok = OpenTok(mainActivity, flutterEngine) + channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) + channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> + when (call.method) { + "launchPenguin" -> { + print("the platform channel is being called") + val args = call.arguments as Map? + Log.d("TAG", "configureFlutterEngine: $args") + println("args") + args?.let { + PenguinView( + mainActivity, + 100, + args, + flutterEngine.dartExecutor.binaryMessenger, + activity = mainActivity, + channel + ) + } + } + + else -> { + result.notImplemented() + } + } + } + } + +} diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionHelper.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionHelper.kt new file mode 100644 index 00000000..b308af05 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionHelper.kt @@ -0,0 +1,28 @@ +package com.cloud.diplomaticquarterapp.PermissionManager + +import android.Manifest +import android.os.Build + +object PermissionHelper { + + fun getRequiredPermissions(): Array { + val permissions = mutableListOf( + Manifest.permission.INTERNET, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_NETWORK_STATE, + Manifest.permission.BLUETOOTH, + Manifest.permission.BLUETOOTH_ADMIN, +// Manifest.permission.ACTIVITY_RECOGNITION + ) + + // For Android 12 (API level 31) and above, add specific permissions + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above + permissions.add(Manifest.permission.BLUETOOTH_SCAN) + permissions.add(Manifest.permission.BLUETOOTH_CONNECT) + permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS) + } + + return permissions.toTypedArray() + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionManager.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionManager.kt new file mode 100644 index 00000000..81f2a6f0 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionManager.kt @@ -0,0 +1,50 @@ +package com.cloud.diplomaticquarterapp.PermissionManager + +import android.app.Activity +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat + +class PermissionManager( + private val context: Context, + val listener: PermissionListener, + private val requestCode: Int, + vararg permissions: String +) { + + private val permissionsArray = permissions + + interface PermissionListener { + fun onPermissionGranted() + fun onPermissionDenied() + } + + fun arePermissionsGranted(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + permissionsArray.all { + ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED + } + } else { + true + } + } + + fun requestPermissions(activity: Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + ActivityCompat.requestPermissions(activity, permissionsArray, requestCode) + } + } + + fun handlePermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (this.requestCode == requestCode) { + val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } + if (allGranted) { + listener.onPermissionGranted() + } else { + listener.onPermissionDenied() + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionResultReceiver.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionResultReceiver.kt new file mode 100644 index 00000000..33765192 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionResultReceiver.kt @@ -0,0 +1,15 @@ +package com.cloud.diplomaticquarterapp.PermissionManager + +// PermissionResultReceiver.kt +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + +class PermissionResultReceiver( + private val callback: (Boolean) -> Unit +) : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false + callback(granted) + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinMethod.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinMethod.kt new file mode 100644 index 00000000..c76f9784 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinMethod.kt @@ -0,0 +1,13 @@ +package com.cloud.diplomaticquarterapp.penguin + +enum class PenguinMethod { + // initializePenguin("initializePenguin"), + // configurePenguin("configurePenguin"), + // showPenguinUI("showPenguinUI"), + // onPenNavUIDismiss("onPenNavUIDismiss"), + // onReportIssue("onReportIssue"), + // onPenNavSuccess("onPenNavSuccess"), + onPenNavInitializationError // onLocationOffCampus("onLocationOffCampus"), + // navigateToPOI("navigateToPOI"), + // openSharedLocation("openSharedLocation"); +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinNavigator.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinNavigator.kt new file mode 100644 index 00000000..98245cc9 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinNavigator.kt @@ -0,0 +1,97 @@ +package com.cloud.diplomaticquarterapp.penguin + +import android.content.Context +import com.google.gson.Gson +import com.peng.pennavmap.PlugAndPlaySDK +import com.peng.pennavmap.connections.ApiController +import com.peng.pennavmap.interfaces.RefIdDelegate +import com.peng.pennavmap.models.TokenModel +import com.peng.pennavmap.models.postmodels.PostToken +import com.peng.pennavmap.utils.AppSharedData +import okhttp3.ResponseBody +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import android.util.Log + + +class PenguinNavigator() { + + fun navigateTo(mContext: Context, refID: String, delegate: RefIdDelegate,clientID : String,clientKey : String ) { + val postToken = PostToken(clientID, clientKey) + getToken(mContext, postToken, object : RefIdDelegate { + override fun onRefByIDSuccess(PoiId: String?) { + Log.e("navigateTo", "PoiId is+++++++ $PoiId") + + PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate { + override fun onRefByIDSuccess(PoiId: String?) { + Log.e("navigateTo", "PoiId 2is+++++++ $PoiId") + + delegate.onRefByIDSuccess(refID) + + } + + override fun onGetByRefIDError(error: String?) { + delegate.onRefByIDSuccess(error) + } + + }) + + + } + + override fun onGetByRefIDError(error: String?) { + delegate.onRefByIDSuccess(error) + } + + }) + + } + + fun getToken(mContext: Context, postToken: PostToken?, apiTokenCallBack: RefIdDelegate) { + try { + // Create the API call + val purposesCall: Call = ApiController.getInstance(mContext) + .apiMethods + .getToken(postToken) + + // Enqueue the call for asynchronous execution + purposesCall.enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful() && response.body() != null) { + try { + response.body()?.use { responseBody -> + val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content + if (responseBodyString.isNotEmpty()) { + val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java) + if (tokenModel != null && tokenModel.token != null) { + AppSharedData.apiToken = tokenModel.token + apiTokenCallBack.onRefByIDSuccess(tokenModel.token) + } else { + apiTokenCallBack.onGetByRefIDError("Failed to parse token model") + } + } else { + apiTokenCallBack.onGetByRefIDError("Response body is empty") + } + } + } catch (e: Exception) { + apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}") + } + } else { + apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code()) + } + } + + override fun onFailure(call: Call, t: Throwable) { + apiTokenCallBack.onGetByRefIDError(t.message) + } + }) + } catch (error: Exception) { + apiTokenCallBack.onGetByRefIDError("Exception during API call: $error") + } + } + +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinView.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinView.kt new file mode 100644 index 00000000..743ce93b --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinView.kt @@ -0,0 +1,316 @@ +package com.cloud.diplomaticquarterapp.penguin + +import android.app.Activity +import android.content.Context +import android.content.Context.RECEIVER_EXPORTED +import android.content.IntentFilter +import android.graphics.Color +import android.os.Build +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.widget.RelativeLayout +import android.widget.Toast +import androidx.annotation.RequiresApi +import com.cloud.diplomaticquarterapp.PermissionManager.PermissionHelper +import com.cloud.diplomaticquarterapp.PermissionManager.PermissionManager +import com.cloud.diplomaticquarterapp.PermissionManager.PermissionResultReceiver +import com.ejada.hmg.MainActivity +import com.peng.pennavmap.PlugAndPlayConfiguration +import com.peng.pennavmap.PlugAndPlaySDK +import com.peng.pennavmap.enums.InitializationErrorType +import com.peng.pennavmap.interfaces.PenNavUIDelegate +import com.peng.pennavmap.utils.Languages +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.platform.PlatformView +import com.cloud.diplomaticquarterapp.penguin.PenguinNavigator +import com.peng.pennavmap.interfaces.PIEventsDelegate +import com.peng.pennavmap.interfaces.PILocationDelegate +import com.peng.pennavmap.interfaces.RefIdDelegate +import com.peng.pennavmap.models.PIReportIssue +/** + * Custom PlatformView for displaying Penguin UI components within a Flutter app. + * Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls, + * and `PenNavUIDelegate` for handling SDK events. + */ +@RequiresApi(Build.VERSION_CODES.O) +internal class PenguinView( + context: Context, + id: Int, + val creationParams: Map, + messenger: BinaryMessenger, + activity: MainActivity, + val channel: MethodChannel +) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate { + // The layout for displaying the Penguin UI + private val mapLayout: RelativeLayout = RelativeLayout(context) + private val _context: Context = context + + private val permissionResultReceiver: PermissionResultReceiver + private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION") + + private companion object { + const val PERMISSIONS_REQUEST_CODE = 1 + } + + private lateinit var permissionManager: PermissionManager + + // Reference to the main activity + private var _activity: Activity = activity + + private lateinit var mContext: Context + + lateinit var navigator: PenguinNavigator + + init { + // Set layout parameters for the mapLayout + mapLayout.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT + ) + + mContext = context + + + permissionResultReceiver = PermissionResultReceiver { granted -> + if (granted) { + onPermissionsGranted() + } else { + onPermissionsDenied() + } + } + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + mContext.registerReceiver( + permissionResultReceiver, + permissionIntentFilter, + RECEIVER_EXPORTED + ) + } else { + mContext.registerReceiver( + permissionResultReceiver, + permissionIntentFilter, + ) + } + + // Set the background color of the layout + mapLayout.setBackgroundColor(Color.RED) + + permissionManager = PermissionManager( + context = mContext, + listener = object : PermissionManager.PermissionListener { + override fun onPermissionGranted() { + // Handle permissions granted + onPermissionsGranted() + } + + override fun onPermissionDenied() { + // Handle permissions denied + onPermissionsDenied() + } + }, + requestCode = PERMISSIONS_REQUEST_CODE, + *PermissionHelper.getRequiredPermissions() + ) + + if (!permissionManager.arePermissionsGranted()) { + permissionManager.requestPermissions(_activity) + } else { + // Permissions already granted + permissionManager.listener.onPermissionGranted() + } + + + } + + private fun onPermissionsGranted() { + // Handle the actions when permissions are granted + Log.d("PermissionsResult", "onPermissionsGranted") + // Register the platform view factory for creating custom views + + // Initialize the Penguin SDK + initPenguin() + + + } + + private fun onPermissionsDenied() { + // Handle the actions when permissions are denied + Log.d("PermissionsResult", "onPermissionsDenied") + + } + + /** + * Returns the view associated with this PlatformView. + * + * @return The main view for this PlatformView. + */ + override fun getView(): View { + return mapLayout + } + + /** + * Cleans up resources associated with this PlatformView. + */ + override fun dispose() { + // Cleanup code if needed + } + + /** + * Handles method calls from Dart code. + * + * @param call The method call from Dart. + * @param result The result callback to send responses back to Dart. + */ + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + // Handle method calls from Dart code here + } + + /** + * Initializes the Penguin SDK with custom configuration and delegates. + */ + private fun initPenguin() { + navigator = PenguinNavigator() + // Configure the PlugAndPlaySDK + val language = when (creationParams["languageCode"] as String) { + "ar" -> Languages.ar + "en" -> Languages.en + else -> { + Languages.en + } + } + Log.d( + "TAG", + "initPenguin: ${Languages.getLanguageEnum(creationParams["languageCode"] as String)}" + ) + PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder() + .setBaseUrl( + creationParams["dataURL"] as String, + creationParams["positionURL"] as String + ) + .setServiceName( + creationParams["dataServiceName"] as String, + creationParams["positionServiceName"] as String + ) + .setClientData( + creationParams["clientID"] as String, + creationParams["clientKey"] as String + ) + .setUserName(creationParams["username"] as String) +// .setLanguageID(Languages.en) + .setLanguageID(language) + .setSimulationModeEnabled(creationParams["isSimulationModeEnabled"] as Boolean) + .setEnableBackButton(true) +// .setDeepLinkData("deeplink") + .setCustomizeColor("#2CA0AF") + .setDeepLinkSchema("") + .build() + + // Set location delegate to handle location updates + PlugAndPlaySDK.setPiLocationDelegate { + // Example code to handle location updates + // Uncomment and modify as needed + // if (location.size() > 0) + // Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show() + } + + // Set events delegate for reporting issues + PlugAndPlaySDK.setPiEventsDelegate { } + + // Start the Penguin SDK + PlugAndPlaySDK.start(mContext, this) + } + + + /** + * Navigates to the specified reference ID. + * + * @param refID The reference ID to navigate to. + */ + fun navigateTo(refID: String) { + try { + if (refID.isBlank()) { + Log.e("navigateTo", "Invalid refID: The reference ID is blank.") + + } + + + +// referenceId = refID + + + navigator.navigateTo(mContext, refID,object : RefIdDelegate { + override fun onRefByIDSuccess(PoiId: String?) { + Log.e("navigateTo", "PoiId is penguin view+++++++ $PoiId") + +// channelFlutter.invokeMethod( +// PenguinMethod.navigateToPOI.name, +// "navigateTo Success" +// ) + } + + override fun onGetByRefIDError(error: String?) { + Log.e("navigateTo", "error is penguin view+++++++ $error") + +// channelFlutter.invokeMethod( +// PenguinMethod.navigateToPOI.name, +// "navigateTo Failed: Invalid refID" +// ) + } + } , creationParams["clientID"] as String, creationParams["clientKey"] as String ) + + } catch (e: Exception) { + Log.e("navigateTo", "Exception occurred during navigation: ${e.message}", e) +// channelFlutter.invokeMethod( +// PenguinMethod.navigateToPOI.name, +// "Failed: Exception - ${e.message}" +// ) + } + } + + /** + * Called when Penguin UI setup is successful. + * + * @param warningCode Optional warning code received from the SDK. + */ + override fun onPenNavSuccess(warningCode: String?) { + val clinicId = creationParams["clinicID"] as String + + if(clinicId.isEmpty()) return + + navigateTo(clinicId) + } + + /** + * Called when there is an initialization error with Penguin UI. + * + * @param description Description of the error. + * @param errorType Type of initialization error. + */ + override fun onPenNavInitializationError( + description: String?, + errorType: InitializationErrorType? + ) { + val arguments: Map = mapOf( + "description" to description, + "type" to errorType?.name + ) + + channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments) + Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show() + } + + /** + * Called when Penguin UI is dismissed. + */ + override fun onPenNavUIDismiss() { + // Handle UI dismissal if needed + try { + mContext.unregisterReceiver(permissionResultReceiver) + dispose(); + } catch (e: IllegalArgumentException) { + Log.e("PenguinView", "Receiver not registered: $e") + } + } +} + diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt index 7fbf859a..57da2eb8 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt @@ -22,7 +22,7 @@ import com.github.kittinunf.fuel.httpPost import com.google.gson.Gson import com.google.gson.reflect.TypeToken import io.flutter.plugin.common.MethodChannel -import org.jetbrains.anko.doAsyncResult +//import org.jetbrains.anko.doAsyncResult import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -149,7 +149,7 @@ fun sendNotification(context: Context, title: String, @Nullable subtitle: String val notificationPendingIntent = stackBuilder.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT) val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) - .setSmallIcon(R.mipmap.ic_launcher) + .setSmallIcon(R.mipmap.ic_launcher_local) .setContentIntent(notificationPendingIntent) .setAutoCancel(true) .setContentTitle(title) @@ -208,7 +208,6 @@ fun httpPost(url: String, body: Map, onSuccess: (response: HTTP .header("Content-Type", "application/json") .header("Allow", "*/*") .response { request, response, result -> - result.doAsyncResult { } result.fold({ data -> val dataString = String(data) if (isJSONValid(dataString)) { diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png similarity index 100% rename from android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png similarity index 100% rename from android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png similarity index 100% rename from android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png similarity index 100% rename from android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png similarity index 100% rename from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 4e107030..1093435a 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -19,4 +19,5 @@ Geofence requests happened too frequently. + sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg diff --git a/android/build.gradle b/android/build.gradle index b5185cca..c5f1baa2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -13,6 +13,20 @@ buildscript { google() jcenter() maven { url 'https://developer.huawei.com/repo/' } + maven { + url 'https://api.mapbox.com/downloads/v2/releases/maven' + + credentials { + username = 'mapbox' + password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg" + if (password == null || password == "") { + throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.") + } + } + authentication { + basic(BasicAuthentication) + } + } // maven { // url "https://dl.bintray.com/kotlin/kotlin-eap/" @@ -26,6 +40,7 @@ buildscript { // classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' classpath 'com.huawei.agconnect:agcp:1.5.2.300' classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12' + classpath "com.mapbox.gradle.plugins:access-token:0.4.0" } } @@ -34,12 +49,29 @@ allprojects { google() // jcenter() mavenCentral() + flatDir { + dirs 'libs' + } maven { url 'https://developer.huawei.com/repo/' } maven { url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local" } + maven { + url 'https://api.mapbox.com/downloads/v2/releases/maven' + + credentials { + username = 'mapbox' + password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg" + if (password == null || password == "") { + throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.") + } + } + authentication { + basic(BasicAuthentication) + } + } } } diff --git a/android/gradle.properties b/android/gradle.properties index 06a44c05..cf554544 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -3,3 +3,5 @@ org.gradle.jvmargs=-Xmx4096m android.useAndroidX=true android.enableJetifier=true android.suppressUnsupportedCompileSdk=33 +MAPBOX_USER_NAME = "mapbox" +MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg" \ No newline at end of file diff --git a/assets/images/new/NFCCheckIn_QR_gps_HMG.png b/assets/images/new/NFCCheckIn_QR_gps_HMG.png new file mode 100644 index 00000000..20fc0ef6 Binary files /dev/null and b/assets/images/new/NFCCheckIn_QR_gps_HMG.png differ diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index cb6be309..c5ff5d37 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 13.0 diff --git a/ios/Podfile b/ios/Podfile index 5495f0ca..5564c00b 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -33,6 +33,7 @@ target 'Runner' do pod 'OpenTok', '~> 2.22.0' pod 'VTO2Lib' + pod 'MapboxMaps', '10.18.2' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end @@ -54,6 +55,7 @@ post_install do |installer| ] build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386' build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' + build_configuration.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES' xcconfig_path = build_configuration.base_configuration_reference.real_path xcconfig = File.read(xcconfig_path) xcconfig_mod = xcconfig.gsub(/DT_TOOLCHAIN_DIR/, "TOOLCHAIN_DIR") @@ -62,6 +64,17 @@ post_install do |installer| if build_configuration.build_settings['WRAPPER_EXTENSION'] == 'bundle' build_configuration.build_settings['DEVELOPMENT_TEAM'] = '3A359E86ZF' end + if target.name == 'MapboxMobileEvents' + `xcrun -sdk iphoneos bitcode_strip -r Pods/MapboxMobileEvents/MapboxMobileEvents.xcframework/ios-arm64_armv7/MapboxMobileEvents.framework/MapboxMobileEvents -o Pods/MapboxMobileEvents/MapboxMobileEvents.xcframework/ios-arm64_armv7/MapboxMobileEvents.framework/MapboxMobileEvents` + end + + if target.name == 'MapboxCommon' + `xcrun -sdk iphoneos bitcode_strip -r Pods/MapboxCommon/MapboxCommon.xcframework/ios-arm64/MapboxCommon.framework/MapboxCommon -o Pods/MapboxCommon/MapboxCommon.xcframework/ios-arm64/MapboxCommon.framework/MapboxCommon` + end + + if target.name == 'MapboxCoreMaps' + `xcrun -sdk iphoneos bitcode_strip -r Pods/MapboxCoreMaps/MapboxCoreMaps.xcframework/ios-arm64/MapboxCoreMaps.framework/MapboxCoreMaps -o Pods/MapboxCoreMaps/MapboxCoreMaps.xcframework/ios-arm64/MapboxCoreMaps.framework/MapboxCoreMaps` + end end end end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e7357518..5dad833f 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,18 +8,30 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 29631B9E2C96C7F600DF5916 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */; }; 301C79AE27200D9F0016307B /* OpenTokRemoteVideoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */; }; 301C79B027200DED0016307B /* OpenTokLocalVideoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */; }; 306FE6C8271D790C002D6EFC /* OpenTokPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */; }; 306FE6CB271D8B73002D6EFC /* OpenTok.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306FE6CA271D8B73002D6EFC /* OpenTok.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 4EE411B2E3CB5D4F81AE5078 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D1513E0724DAFB89C198BDD /* Pods_Runner.framework */; }; + 47C935002C91766800981BA7 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FC2C91766400981BA7 /* Penguin.xcframework */; }; + 47C935012C91766800981BA7 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FC2C91766400981BA7 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 47C935022C91766900981BA7 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */; }; + 47C935032C91766900981BA7 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 47C935042C91766A00981BA7 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */; }; + 47C935052C91766A00981BA7 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 762D738E274E42650063CE73 /* ring_30Sec.caf in Resources */ = {isa = PBXBuildFile; fileRef = 762D738C274E42650063CE73 /* ring_30Sec.caf */; }; 762D738F274E42650063CE73 /* ring_30Sec.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 762D738D274E42650063CE73 /* ring_30Sec.mp3 */; }; 76815B27275F381C00E66E94 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76815B26275F381C00E66E94 /* HealthKit.framework */; }; 76962ECE28AE5C10004EAE09 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 76962ECD28AE5C10004EAE09 /* GoogleService-Info.plist */; }; + 76D71B672C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */; }; + 76D71B6A2C6B819000DAFB84 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B692C6B819000DAFB84 /* PenguinModel.swift */; }; + 76D71B6C2C6B81B300DAFB84 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */; }; + 76D71B6E2C6B81CC00DAFB84 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */; }; + 76D71B702C6B81EA00DAFB84 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */; }; 76F2556127F1FFED0062C1CD /* PassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76F2556027F1FFED0062C1CD /* PassKit.framework */; }; + 76F9B0E22C6DED310064C51B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E5B711BC29EB6ECCE1964C /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -43,12 +55,15 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + 768D81742C6DF6E4005C655F /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( + 47C935032C91766900981BA7 /* PenguinINRenderer.xcframework in Embed Frameworks */, + 47C935012C91766800981BA7 /* Penguin.xcframework in Embed Frameworks */, + 47C935052C91766A00981BA7 /* PenNavUI.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -56,14 +71,18 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 13E5B711BC29EB6ECCE1964C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; }; 301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokRemoteVideoFactory.swift; sourceTree = ""; }; 301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokLocalVideoFactory.swift; sourceTree = ""; }; 306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = ""; }; 306FE6CA271D8B73002D6EFC /* OpenTok.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTok.swift; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3D1513E0724DAFB89C198BDD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = ""; }; + 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = ""; }; + 47C934FC2C91766400981BA7 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = ""; }; 6EE8819867EC2775AB578377 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -74,6 +93,11 @@ 7643E4062BE0D0B400BD2F25 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = ""; }; 76815B26275F381C00E66E94 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; 76962ECD28AE5C10004EAE09 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = ""; }; + 76D71B692C6B819000DAFB84 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; + 76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = ""; }; + 76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = ""; }; + 76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = ""; }; 76F2556027F1FFED0062C1CD /* PassKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PassKit.framework; path = System/Library/Frameworks/PassKit.framework; sourceTree = SDKROOT; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 838788A2BEDC4910F4B029A6 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; @@ -110,10 +134,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 76F9B0E22C6DED310064C51B /* Pods_Runner.framework in Frameworks */, 76F2556127F1FFED0062C1CD /* PassKit.framework in Frameworks */, 76815B27275F381C00E66E94 /* HealthKit.framework in Frameworks */, E9620805255C2ED100D3A35D /* NetworkExtension.framework in Frameworks */, - 4EE411B2E3CB5D4F81AE5078 /* Pods_Runner.framework in Frameworks */, + 47C935042C91766A00981BA7 /* PenNavUI.xcframework in Frameworks */, + 47C935002C91766800981BA7 /* Penguin.xcframework in Frameworks */, + 47C935022C91766900981BA7 /* PenguinINRenderer.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -133,10 +160,13 @@ 555EAAA626EFB641859EF0BE /* Frameworks */ = { isa = PBXGroup; children = ( + 47C934FC2C91766400981BA7 /* Penguin.xcframework */, + 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */, + 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */, 76F2556027F1FFED0062C1CD /* PassKit.framework */, 76815B26275F381C00E66E94 /* HealthKit.framework */, E9620804255C2ED100D3A35D /* NetworkExtension.framework */, - 3D1513E0724DAFB89C198BDD /* Pods_Runner.framework */, + 13E5B711BC29EB6ECCE1964C /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -151,6 +181,18 @@ path = Pods; sourceTree = ""; }; + 76D71B682C6B817500DAFB84 /* Penguin */ = { + isa = PBXGroup; + children = ( + 76D71B692C6B819000DAFB84 /* PenguinModel.swift */, + 76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */, + 76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */, + 76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */, + 29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */, + ); + path = Penguin; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -186,6 +228,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 76D71B682C6B817500DAFB84 /* Penguin */, 762D738C274E42650063CE73 /* ring_30Sec.caf */, 762D738D274E42650063CE73 /* ring_30Sec.mp3 */, 306FE6C9271D8B54002D6EFC /* OpenTok */, @@ -220,6 +263,7 @@ E923EFD52587443800E3E751 /* HMGPlatformBridge.swift */, 306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */, E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */, + 76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */, ); path = Helper; sourceTree = ""; @@ -254,7 +298,7 @@ 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, + 768D81742C6DF6E4005C655F /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 487FDD6493EB9AE7D8E39485 /* [CP] Embed Pods Frameworks */, 4671D3CD126F6635F4B75A6E /* [CP] Copy Pods Resources */, @@ -274,7 +318,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -419,12 +463,18 @@ buildActionMask = 2147483647; files = ( 306FE6C8271D790C002D6EFC /* OpenTokPlatformBridge.swift in Sources */, + 76D71B6E2C6B81CC00DAFB84 /* PenguinPlugin.swift in Sources */, E923EFD225863FDF00E3E751 /* GeoZoneModel.swift in Sources */, E91B539A256AAA6500E96549 /* MainFlutterVC.swift in Sources */, + 76D71B672C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift in Sources */, E91B539C256AAA6500E96549 /* HMG_GUEST_bkp.swift in Sources */, E91B5396256AAA6500E96549 /* GlobalHelper.swift in Sources */, E923EFD4258645C100E3E751 /* HMG_Geofence.swift in Sources */, E923EFD62587443800E3E751 /* HMGPlatformBridge.swift in Sources */, + 76D71B6C2C6B81B300DAFB84 /* PenguinView.swift in Sources */, + 29631B9E2C96C7F600DF5916 /* PenguinNavigator.swift in Sources */, + 76D71B6A2C6B819000DAFB84 /* PenguinModel.swift in Sources */, + 76D71B702C6B81EA00DAFB84 /* PenguinViewFactory.swift in Sources */, 301C79AE27200D9F0016307B /* OpenTokRemoteVideoFactory.swift in Sources */, E9F7623B25922BCE00FB5CCF /* FlutterConstants.swift in Sources */, 306FE6CB271D8B73002D6EFC /* OpenTok.swift in Sources */, @@ -528,6 +578,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; @@ -553,10 +604,13 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; @@ -675,6 +729,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; @@ -700,10 +755,14 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -713,6 +772,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; @@ -738,11 +798,14 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_COMPILATION_MODE = singlefile; "SWIFT_COMPILATION_MODE[arch=*]" = singlefile; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index fab8f735..b2d2f7e5 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ HMGPenguinInPlatformBridge{ + assert((HMGPenguinInPlatformBridge.shared_ != nil), "HMGPenguinInPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.") + return HMGPenguinInPlatformBridge.shared_! + } + + private func openChannel(){ + flutterMethodChannelPenguinIn = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger) + + flutterMethodChannelPenguinIn?.setMethodCallHandler { (methodCall, result) in + print("Called function \(methodCall.method)") + + if let arguments = methodCall.arguments as Any? { + if methodCall.method == "launchPenguin"{ + self.launchPenguinView(arguments: arguments, result: result) + } + } else { + result(FlutterError(code: "INVALID_ARGUMENT", message: "Storyboard name is required", details: nil)) + } + } + } + + private func launchPenguinView(arguments: Any, result: @escaping FlutterResult) { + let penguinView = PenguinView( + frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height), + viewIdentifier: 0, + arguments: arguments, + binaryMessenger: mainViewController.binaryMessenger + ) + + let penguinUIView = penguinView.view() + penguinUIView.frame = mainViewController.view.bounds + penguinUIView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mainViewController.view.addSubview(penguinUIView) + + result(nil) // Call result to indicate the method was successfully handled + } + +} diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 43474d39..13782c80 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -39,7 +39,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 11.0 + 13.0 NFCReaderUsageDescription This app requires NFC Usage access to allow for Online CheckIn for appointments. NSAppTransportSecurity @@ -60,7 +60,7 @@ NSCalendarsUsageDescription This app requires calendar access to set reminders for Virtual & Normal Appointments. NSCalendarsWriteOnlyAccessUsageDescription - This app requires calendar access to set reminders for Virtual & Normal Appointments. + This app requires calendar access to set reminders for Virtual & Normal Appointments. NSCalendarsFullAccessUsageDescription This app requires calendar access to set reminders for Virtual & Normal Appointments. NSCameraUsageDescription diff --git a/ios/Runner/Penguin/PenguinModel.swift b/ios/Runner/Penguin/PenguinModel.swift new file mode 100644 index 00000000..e41979d6 --- /dev/null +++ b/ios/Runner/Penguin/PenguinModel.swift @@ -0,0 +1,76 @@ +// +// PenguinModel.swift +// Runner +// +// Created by Amir on 06/08/2024. +// + +import Foundation + +// Define the model class +struct PenguinModel { + let baseURL: String + let dataURL: String + let dataServiceName: String + let positionURL: String + let clientKey: String + let storyboardName: String + let mapBoxKey: String + let clientID: String + let positionServiceName: String + let username: String + let isSimulationModeEnabled: Bool + let isShowUserName: Bool + let isUpdateUserLocationSmoothly: Bool + let isEnableReportIssue: Bool + let languageCode: String + let clinicID: String + let patientID: String + let projectID: String + + // Initialize the model from a dictionary + init?(from dictionary: [String: Any]) { + guard + let baseURL = dictionary["baseURL"] as? String, + let dataURL = dictionary["dataURL"] as? String, + let dataServiceName = dictionary["dataServiceName"] as? String, + let positionURL = dictionary["positionURL"] as? String, + let clientKey = dictionary["clientKey"] as? String, + let storyboardName = dictionary["storyboardName"] as? String, + let mapBoxKey = dictionary["mapBoxKey"] as? String, + let clientID = dictionary["clientID"] as? String, + let positionServiceName = dictionary["positionServiceName"] as? String, + let username = dictionary["username"] as? String, + let isSimulationModeEnabled = dictionary["isSimulationModeEnabled"] as? Bool, + let isShowUserName = dictionary["isShowUserName"] as? Bool, + let isUpdateUserLocationSmoothly = dictionary["isUpdateUserLocationSmoothly"] as? Bool, + let isEnableReportIssue = dictionary["isEnableReportIssue"] as? Bool, + let languageCode = dictionary["languageCode"] as? String, + let clinicID = dictionary["clinicID"] as? String, + let patientID = dictionary["patientID"] as? String, + let projectID = dictionary["projectID"] as? String + else { + print("Initialization failed due to missing or invalid keys.") + return nil + } + + self.baseURL = baseURL + self.dataURL = dataURL + self.dataServiceName = dataServiceName + self.positionURL = positionURL + self.clientKey = clientKey + self.storyboardName = storyboardName + self.mapBoxKey = mapBoxKey + self.clientID = clientID + self.positionServiceName = positionServiceName + self.username = username + self.isSimulationModeEnabled = isSimulationModeEnabled + self.isShowUserName = isShowUserName + self.isUpdateUserLocationSmoothly = isUpdateUserLocationSmoothly + self.isEnableReportIssue = isEnableReportIssue + self.languageCode = languageCode + self.clinicID = clinicID + self.patientID = patientID + self.projectID = projectID + } +} diff --git a/ios/Runner/Penguin/PenguinNavigator.swift b/ios/Runner/Penguin/PenguinNavigator.swift new file mode 100644 index 00000000..e7ce55b4 --- /dev/null +++ b/ios/Runner/Penguin/PenguinNavigator.swift @@ -0,0 +1,57 @@ +import PenNavUI +import UIKit + +class PenguinNavigator { + private var config: PenguinModel + + init(config: PenguinModel) { + self.config = config + } + + private func logError(_ message: String) { + // Centralized logging function + print("PenguinSDKNavigator Error: \(message)") + } + + func navigateToPOI( referenceId:String,completion: @escaping (Bool, String?) -> Void) { + PenNavUIManager.shared.getToken(clientID: config.clientID, clientKey: config.clientKey) { [weak self] token, error in + + if let error = error { + let errorMessage = "Token error while getting the for Navigate to method" + completion(false, "Failed to get token: \(errorMessage)") + + print("Failed to get token: \(errorMessage)") + return + } + + guard let token = token else { + completion(false, "Token is nil") + print("Token is nil") + return + } + print("Token Generated") + print(token); + + + } + } + + private func handleNavigation(referenceId: String, token: String, completion: @escaping (Bool, String?) -> Void) { + DispatchQueue.main.async { + PenNavUIManager.shared.setToken(token: token) + + PenNavUIManager.shared.navigate(to: referenceId) { [weak self] _, navError in + guard let self = self else { return } + + if let navError = navError { + self.logError("Navigation error: Reference ID invalid") + completion(false, "Navigation error: \(navError.localizedDescription)") + return + } + + // Navigation successful + completion(true, nil) + } + } + } +} diff --git a/ios/Runner/Penguin/PenguinPlugin.swift b/ios/Runner/Penguin/PenguinPlugin.swift new file mode 100644 index 00000000..029bec35 --- /dev/null +++ b/ios/Runner/Penguin/PenguinPlugin.swift @@ -0,0 +1,31 @@ +// +// BlueGpsPlugin.swift +// Runner +// +// Created by Penguin . +// + +//import Foundation +//import Flutter +// +///** +// * A Flutter plugin for integrating Penguin SDK functionality. +// * This class registers a view factory with the Flutter engine to create native views. +// */ +//class PenguinPlugin: NSObject, FlutterPlugin { +// +// /** +// * Registers the plugin with the Flutter engine. +// * +// * @param registrar The [FlutterPluginRegistrar] used to register the plugin. +// * This method is called when the plugin is initialized, and it sets up the communication +// * between Flutter and native code. +// */ +// public static func register(with registrar: FlutterPluginRegistrar) { +// // Create an instance of PenguinViewFactory with the binary messenger from the registrar +// let factory = PenguinViewFactory(messenger: registrar.messenger()) +// +// // Register the view factory with a unique ID for use in Flutter code +// registrar.register(factory, withId: "penguin_native") +// } +//} diff --git a/ios/Runner/Penguin/PenguinView.swift b/ios/Runner/Penguin/PenguinView.swift new file mode 100644 index 00000000..81377f7b --- /dev/null +++ b/ios/Runner/Penguin/PenguinView.swift @@ -0,0 +1,224 @@ +// +// BlueGpsView.swift +// Runner +// +// Created by Penguin. +// + +import Foundation +import UIKit +import Flutter +import PenNavUI + +import Foundation +import Flutter +import UIKit + +/** + * A custom Flutter platform view for displaying Penguin UI components. + * This class integrates with the Penguin navigation SDK and handles UI events. + */ +class PenguinView: NSObject, FlutterPlatformView + +, PIEventsDelegate, PenNavInitializationDelegate +{ + + // The main view displayed within the platform view + private var _view: UIView + private var model: PenguinModel? + + + /** + * Initializes the PenguinView with the provided parameters. + * + * @param frame The frame of the view, specifying its size and position. + * @param viewId A unique identifier for this view instance. + * @param args Optional arguments provided for creating the view. + * @param messenger The [FlutterBinaryMessenger] used for communication with Dart. + */ + init( + frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any?, + binaryMessenger messenger: FlutterBinaryMessenger? + ) { + _view = UIView() + super.init() + + // Get the screen's width and height to set the view's frame + let screenWidth = UIScreen.main.bounds.width + let screenHeight = UIScreen.main.bounds.height + + // Uncomment to set the background color of the view + // _view.backgroundColor = UIColor.red + + // Set the frame of the view to cover the entire screen + _view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight) + print("========Inside Penguin View ========") + print(args) + guard let arguments = args as? [String: Any] else { + print("Error: Arguments are not in the expected format.") + return + } + print("===== i got tha Args=======") + + // Initialize the model from the arguments + if let penguinModel = PenguinModel(from: arguments) { + self.model = penguinModel + initPenguin(args: penguinModel) + } else { + print("Error: Failed to initialize PenguinModel from arguments ") + } + // Initialize the Penguin SDK with required configurations + // initPenguin( arguments: args) + } + + /** + * Initializes the Penguin SDK with custom configuration settings. + */ + func initPenguin(args: PenguinModel) { +// Set the initialization delegate to handle SDK initialization events + PenNavUIManager.shared.initializationDelegate = self + // Configure the Penguin SDK with necessary parameters + PenNavUIManager.shared + .setClientKey(args.clientKey) + .setClientID(args.clientID) + .setUsername(args.username) + .setSimulationModeEnabled(isEnable: args.isSimulationModeEnabled) + .setBaseURL(dataURL: args.dataURL, positionURL: args.positionURL) + .setServiceName(dataServiceName: args.dataServiceName, positionServiceName: args.positionServiceName) + .setIsShowUserName(args.isShowUserName) + .setIsUpdateUserLocationSmoothly(args.isUpdateUserLocationSmoothly) + .setEnableReportIssue(enable: args.isEnableReportIssue) + .setLanguage(args.languageCode) + .setBackButtonVisibility(true) + .build() + } + + /** + * Returns the main view associated with this platform view. + * + * @return The UIView instance that represents this platform view. + */ + func view() -> UIView { + return _view + } + + // MARK: - PIEventsDelegate Methods + + /** + * Called when the Penguin UI is dismissed. + */ + func onPenNavUIDismiss() { + // Handle UI dismissal if needed + print("====== onPenNavUIDismiss =========") + + + self.view().removeFromSuperview() + } + + /** + * Called when a report issue is generated. + * + * @param issue The type of issue reported. + */ + func onReportIssue(_ issue: PenNavUI.IssueType) { + // Handle report issue events if needed + print("====== onReportIssueError =========") + } + + /** + * Called when the Penguin UI setup is successful. + */ + func onPenNavSuccess() { + print("====== onPenNavSuccess =========") + // Obtain the FlutterViewController instance + let controller: FlutterViewController = UIApplication.shared.windows.first?.rootViewController as! FlutterViewController + + print("====== after contoller onPenNavSuccess =========") + + // Set the events delegate to handle SDK events + PenNavUIManager.shared.eventsDelegate = self + + print("====== after eventsDelegate onPenNavSuccess =========") + + // Present the Penguin UI on top of the Flutter view controller + PenNavUIManager.shared.present(root: controller, view: _view) + + + print("====== after present onPenNavSuccess =========") + print(model?.clinicID) + print("====== after present onPenNavSuccess =========") + + guard let config = self.model else { + print("Error: Config Model is nil") + return + } + + guard let clinicID = self.model?.clinicID, + let clientID = self.model?.clientID, !clientID.isEmpty else { + print("Error: Config Client ID is nil or empty") + return + } + + let navigator = PenguinNavigator(config: config) + + PenNavUIManager.shared.getToken(clientID: config.clientID, clientKey: config.clientKey) { [weak self] token, error in + if let error = error { + let errorMessage = "Token error while getting the for Navigate to method" + print("Failed to get token: \(errorMessage)") + return + } + + guard let token = token else { + print("Token is nil") + return + } + print("Token Generated") + print(token); + + self?.handleNavigation(clinicID: clinicID, token: token) { success, errorMessage in + if success { + print("Navigation successful") + } else { + print("Navigation failed: \(errorMessage ?? "Unknown error")") + } + + } + + print("====== after Token onPenNavSuccess =========") + } + + } + + + + private func handleNavigation(clinicID: String, token: String, completion: @escaping (Bool, String?) -> Void) { + DispatchQueue.main.async { + PenNavUIManager.shared.setToken(token: token) + PenNavUIManager.shared.navigate(to: clinicID) + completion(true,nil) + } + } + + + + + /** + * Called when there is an initialization error with the Penguin UI. + * + * @param errorType The type of initialization error. + * @param errorDescription A description of the error. + */ + func onPenNavInitializationError(errorType: PenNavUI.PenNavUIError, errorDescription: String) { + // Handle initialization errors if needed + + print("onPenNavInitializationErrorType: \(errorType.rawValue)") + print("onPenNavInitializationError: \(errorDescription)") + + } + + + + +} diff --git a/ios/Runner/Penguin/PenguinViewFactory.swift b/ios/Runner/Penguin/PenguinViewFactory.swift new file mode 100644 index 00000000..a88bb5d0 --- /dev/null +++ b/ios/Runner/Penguin/PenguinViewFactory.swift @@ -0,0 +1,59 @@ +// +// BlueGpsViewFactory.swift +// Runner +// +// Created by Penguin . +// + +import Foundation +import Flutter + +/** + * A factory class for creating instances of [PenguinView]. + * This class implements `FlutterPlatformViewFactory` to create and manage native views. + */ +class PenguinViewFactory: NSObject, FlutterPlatformViewFactory { + + // The binary messenger used for communication with the Flutter engine + private var messenger: FlutterBinaryMessenger + + /** + * Initializes the PenguinViewFactory with the given messenger. + * + * @param messenger The [FlutterBinaryMessenger] used to communicate with Dart code. + */ + init(messenger: FlutterBinaryMessenger) { + self.messenger = messenger + super.init() + } + + /** + * Creates a new instance of [PenguinView]. + * + * @param frame The frame of the view, specifying its size and position. + * @param viewId A unique identifier for this view instance. + * @param args Optional arguments provided for creating the view. + * @return An instance of [PenguinView] configured with the provided parameters. + */ + func create( + withFrame frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any? + ) -> FlutterPlatformView { + return PenguinView( + frame: frame, + viewIdentifier: viewId, + arguments: args, + binaryMessenger: messenger) + } + + /** + * Returns the codec used for encoding and decoding method channel arguments. + * This method is required when `arguments` in `create` is not `nil`. + * + * @return A [FlutterMessageCodec] instance used for serialization. + */ + public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { + return FlutterStandardMessageCodec.sharedInstance() + } +} diff --git a/lib/config/config.dart b/lib/config/config.dart index 7ceb29c6..605e449d 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -335,18 +335,25 @@ var GET_PATIENT_HEALTH_STATS = 'Services/Patients.svc/REST/Med_GetTransactionsSt var SEND_CHECK_IN_NFC_REQUEST = 'Services/Patients.svc/REST/Patient_CheckAppointmentValidation_ForNFC'; +var CHECK_SCANNED_NFC_QR_CODE = 'Services/Patients.svc/REST/Patient_ValidationMachine_ForNFC'; + var HAS_DENTAL_PLAN = 'Services/Doctors.svc/REST/Dental_IsPatientHasOnGoingEstimation'; var LASER_BODY_PARTS = 'Services/Patients.svc/REST/Laser_GetBodyPartsByCategory'; var INSERT_COVID_QUESTIONNAIRE = 'Services/Doctors.svc/REST/COVID19_Questionnarie_Insert'; + var UPDATE_COVID_QUESTIONNAIRE = 'Services/Doctors.svc/REST/COVID19_Questionnarie_Update'; +var GET_PATIENT_SHARE_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/GetCheckinScreenAppointmentDetailsByAppointmentNOForWalkIn'; + +var CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/CanPayForWalkinAppointment'; + //URL to get medicine and pharmacies list var CHANNEL = 3; var GENERAL_ID = 'Cs2020@2016\$2958'; var IP_ADDRESS = '10.20.10.20'; -var VERSION_ID = 16.3; +var VERSION_ID = 16.4; var SETUP_ID = '91877'; var LANGUAGE = 2; // var PATIENT_OUT_SA = 0; @@ -603,9 +610,9 @@ var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceFor var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental"; -var GET_TAMARA_PLAN = 'https://mdlaboratories.com/tamaralive/Home/GetInstallments'; +var GET_TAMARA_PLAN = 'https://mdlaboratories.com/tamara/Home/GetInstallments'; -var GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; +var GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamara/api/OnlineTamara/order_status?orderid='; var UPDATE_TAMARA_STATUS = 'Services/PayFort_Serv.svc/REST/Tamara_UpdateRequestStatus'; @@ -667,6 +674,8 @@ var GET_WE_CARE_TOUR_URL = 'Services/Consent.svc/Rest/Consent_VirtualJurny_Url_G var GET_DENTAL_INSTRUCTIONS = 'Services/OUTPs.svc/Rest/getProcedureNotification'; +var INSERT_WALKIN_APPOINTMENT = "Services/Doctors.svc/REST/InsertWalkinAppointment"; + //PAYFORT var getPayFortProjectDetails = "Services/PayFort_Serv.svc/REST/GetPayFortProjectDetails"; var addPayFortApplePayResponse = "Services/PayFort_Serv.svc/REST/AddResponse"; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 31dee7cb..2765fd51 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -1981,5 +1981,16 @@ const Map localizedValues = { "newAppointment":{"en":"New Appointment","ar":"موعد جديد"}, "proceedPackage":{"en":"Proceed with package","ar":"المضي قدما في الحزمة"}, + "clinicLocation": {"en": "Clinic Location", "ar": "موقع العيادة"}, + "waitingAppointment": {"en": "Waiting appointment", "ar": "انتظار الموعد"}, + "whatWaitingAppointment": {"en": "What is Waiting appointment?", "ar": "ما هو انتظار الموعد؟"}, + "waitingAppointmentText1": {"en": "The waiting appointments feature allows you to book an appointment while you are inside the hospital building, and in case there is no available slot in the doctor’s schedule.", "ar": "تتيح لك خاصية انتظار المواعيد حجز موعد أثناء تواجدك داخل مبنى المستشفى، وفي حالة عدم وجود وقت متاح في جدول الطبيب."}, + "waitingAppointmentText2": {"en": "The appointment with the doctor is confirmed, but the time of entry is uncertain", "ar": "دخول الموعد مؤكد, التوقيت غير محدد."}, + "waitingAppointmentText3": {"en": "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically", "ar": "ملحوظة: يجب عليك الدفع خلال 10 دقائق من الحجز، وإلا سيتم إلغاء موعدك تلقائيًا"}, + "waitingAppointmentVerificationMethod": {"en": "Please select verification method", "ar": "الرجاء تحديد طريقة التحقق"}, + "howToUseVerificationMethod": {"en": "How to use verification methods?", "ar": "كيفية استخدام طرق التحقق؟"}, + "addToWaitingList": {"en": "Add to waiting list", "ar": "اضافه الى قائمة الانتظار"}, "searchClinic": {"en": "Search Clinic", "ar": "بحث العيادة"}, + "selectBranch":{"en":"Select Branch", "ar":"اختر الفرع"}, + "searchByBranch":{"en":"Search By Branch Name", "ar":"البحث عن طريق اسم الفرع"} }; diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index d8f30f0c..37a3a722 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -31,8 +31,7 @@ AppSharedPreferences sharedPref = new AppSharedPreferences(); /// onFailure: (String error, int statusCode) {}, /// body: Map(); /// -AuthenticatedUserObject authenticatedUserObject = - locator(); +AuthenticatedUserObject authenticatedUserObject = locator(); VitalSignService _vitalSignService = locator(); class BaseAppClient { @@ -40,12 +39,12 @@ class BaseAppClient { post(String endPoint, {required Map body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isExternal = false, - bool isRCService = false, - bool bypassConnectionCheck = false}) async { + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isExternal = false, + bool isRCService = false, + bool bypassConnectionCheck = false}) async { String url; if (isExternal) { url = endPoint; @@ -56,25 +55,20 @@ class BaseAppClient { url = BASE_URL + endPoint; } try { - String? pharmacyToken = - await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); + String? pharmacyToken = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); var user = await sharedPref.getObject(USER_PROFILE); - Map headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }; + Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; if (!isExternal) { String? token = await sharedPref.getString(TOKEN); - String? languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + String? languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); if (endPoint == SEND_ACTIVATION_CODE) { languageID = 'en'; } if (body.containsKey('SetupID')) { body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] != null - ? body['SetupID'] - : SETUP_ID + ? body['SetupID'] + : SETUP_ID : SETUP_ID; } @@ -87,8 +81,8 @@ class BaseAppClient { body['LanguageID'] = body['LanguageID'] == 'ar' ? 1 : body['LanguageID'] == 'en' - ? 2 - : body['LanguageID']; + ? 2 + : body['LanguageID']; } else { body['LanguageID'] = Provider.of(AppGlobal.context, listen: false).isArabic ? 1 : 2; } @@ -120,16 +114,16 @@ class BaseAppClient { if (body.containsKey('isDentalAllowedBackend')) { body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] != null - ? body['isDentalAllowedBackend'] - : IS_DENTAL_ALLOWED_BACKEND + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; } body['DeviceTypeID'] = Platform.isIOS ? 1 : await Utils.isGoogleServicesAvailable() - ? 2 - : 3; + ? 2 + : 3; if (!body.containsKey('IsPublicRequest')) { // if (!body.containsKey('PatientType')) { @@ -166,17 +160,14 @@ class BaseAppClient { if (user != null) { body['TokenID'] = body['TokenID'] != null ? body['TokenID'] : token; - body['PatientID'] = body['PatientID'] != null - ? body['PatientID'] - : user['PatientID']; + body['PatientID'] = body['PatientID'] != null ? body['PatientID'] : user['PatientID']; body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] != null - ? body['PatientOutSA'] - : user['OutSA'] + ? body['PatientOutSA'] + : user['OutSA'] : user['OutSA']; - body['SessionID'] = getSessionId( - body['TokenID'] != null ? body['TokenID'] : ""); //getSe + body['SessionID'] = getSessionId(body['TokenID'] != null ? body['TokenID'] : ""); //getSe // body['SessionID'] = body['TokenID']; //getSe // headers = { @@ -193,7 +184,7 @@ class BaseAppClient { // body['IdentificationNo'] = 1023854217; // body['MobileNo'] = "531940021"; //0560717232 - // body['PatientID'] = 283093; //4609100 + // body['PatientID'] = 4768303; //4609100 // body['TokenID'] = "@dm!n"; // Patient ID: 3027574 @@ -202,21 +193,23 @@ class BaseAppClient { body.removeWhere((key, value) => key == null || value == null); + // if (url == 'https://uat.hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo') { + // url = "https://hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo"; + // body['TokenID'] = "@dm!n"; + // } + // if (AppGlobal.isNetworkDebugEnabled) { - print("URL : $url"); - final jsonBody = json.encode(body); - print(jsonBody); + print("URL : $url"); + final jsonBody = json.encode(body); + print(jsonBody); // } - if (await Utils.checkConnection( - bypassConnectionCheck: bypassConnectionCheck)) { - final response = await http.post(Uri.parse(url.trim()), - body: json.encode(body), headers: headers); + if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) { + final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); - logApiEndpointError( - endPoint, 'Error While Fetching data', statusCode); + logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { // var decoded = utf8.decode(response.bodyBytes); var parsed = json.decode(utf8.decode(response.bodyBytes)); @@ -230,12 +223,8 @@ class BaseAppClient { onSuccess(parsed, statusCode); } else { if (parsed['ErrorType'] == 4) { - navigateToAppUpdate( - AppGlobal.context, parsed['ErrorEndUserMessage']); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + navigateToAppUpdate(AppGlobal.context, parsed['ErrorEndUserMessage']); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } if (parsed['ErrorType'] == 2) { await logout(); @@ -254,46 +243,28 @@ class BaseAppClient { // if (parsed != null) { // onSuccess(parsed, statusCode); // } else { - onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); // logout(); // } } - } else if (parsed['MessageStatus'] == 1 || - parsed['SMSLoginRequired'] == true) { + } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { onSuccess(parsed, statusCode); - } else if (parsed['MessageStatus'] == 2 && - parsed['IsAuthenticated']) { + } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { if (parsed['SameClinicApptList'] != null) { onSuccess(parsed, statusCode); } else { - if (parsed['message'] == null && - parsed['ErrorEndUserMessage'] == null) { + if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { - onFailure("Server Error found with no available message", - statusCode); - logApiEndpointError( - endPoint, - "Server Error found with no available message", - statusCode); + onFailure("Server Error found with no available message", statusCode); + logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { onFailure(parsed['ErrorSearchMsg'], statusCode); - logApiEndpointError( - endPoint, parsed['ErrorSearchMsg'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } } else { - onFailure( - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); - logApiEndpointError(endPoint, - parsed['message'] ?? parsed['message'], statusCode); + onFailure(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } } } @@ -305,18 +276,11 @@ class BaseAppClient { onSuccess(parsed, statusCode); } else { if (parsed['message'] != null) { - onFailure( - parsed['message'] ?? parsed['message'], statusCode); - logApiEndpointError(endPoint, - parsed['message'] ?? parsed['message'], statusCode); + onFailure(parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } else { - onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } @@ -325,23 +289,17 @@ class BaseAppClient { } } else { onFailure('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } catch (e) { print(e); onFailure(e.toString(), -1); - _analytics.errorTracking - .log(endPoint, error: "api exception: $e - API Path: $url"); + _analytics.errorTracking.log(endPoint, error: "api exception: $e - API Path: $url"); } } postPharmacy(String endPoint, - {Map? body, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - bool isAllowAny = false, - bool isExternal = false}) async { + {Map? body, Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure, bool isAllowAny = false, bool isExternal = false}) async { var token = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); var user = await sharedPref.getObject(USER_PROFILE); String url; @@ -358,16 +316,13 @@ class BaseAppClient { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': pharmacyToken ?? '', - 'Mobilenumber': user != null - ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) - : "", + 'Mobilenumber': user != null ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user != null ? user['PatientID'].toString() : "", }; if (!isExternal) { String token = await sharedPref.getString(TOKEN); - var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); // if (body.containsKey('SetupID')) { // body['SetupID'] = body.containsKey('SetupID') @@ -429,14 +384,12 @@ class BaseAppClient { print("Headers : ${json.encode(headers)}"); if (await Utils.checkConnection()) { - final response = await http.post(Uri.parse(url.trim()), - body: json.encode(body), headers: headers); + final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); final int statusCode = response.statusCode; // print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure!('Error While Fetching data', statusCode); - logApiEndpointError( - endPoint, 'Error While Fetching data', statusCode); + logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { // var parsed = json.decode(response.body.toString()); var parsed = json.decode(utf8.decode(response.bodyBytes)); @@ -444,12 +397,8 @@ class BaseAppClient { onSuccess!(parsed, statusCode); } else { if (parsed['ErrorType'] == 4) { - navigateToAppUpdate( - AppGlobal.context, parsed['ErrorEndUserMessage']); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + navigateToAppUpdate(AppGlobal.context, parsed['ErrorEndUserMessage']); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } if (isAllowAny) { onSuccess!(parsed, statusCode); @@ -464,56 +413,29 @@ class BaseAppClient { if (parsed != null) { onSuccess!(parsed, statusCode); } else { - onFailure!( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, 'session logged out', statusCode); + onFailure!(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, 'session logged out', statusCode); logout(); } } - } else if (parsed['MessageStatus'] == 1 || - parsed['SMSLoginRequired'] == true) { + } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { onSuccess!(parsed, statusCode); - } else if (parsed['MessageStatus'] == 2 && - parsed['IsAuthenticated']) { + } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { if (parsed['SameClinicApptList'] != null) { onSuccess!(parsed, statusCode); } else { - if (parsed['message'] == null && - parsed['ErrorEndUserMessage'] == null) { + if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { - onFailure!("Server Error found with no available message", - statusCode); - logApiEndpointError( - endPoint, - "Server Error found with no available message", - statusCode); + onFailure!("Server Error found with no available message", statusCode); + logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { onFailure!(parsed['ErrorSearchMsg'], statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorSearchMsg'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); + logApiEndpointError(endPoint, parsed['ErrorSearchMsg'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } else { - onFailure!( - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); + onFailure!(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } else if (!parsed['IsAuthenticated']) { @@ -525,22 +447,11 @@ class BaseAppClient { onSuccess!(parsed, statusCode); } else { if (parsed['message'] != null) { - onFailure!( - parsed['message'] ?? parsed['message'], statusCode); - logApiEndpointError( - endPoint, - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); + onFailure!(parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } else { - onFailure!( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure!(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } @@ -548,8 +459,7 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } catch (e) { print(e); @@ -560,18 +470,18 @@ class BaseAppClient { Future navigateToAppUpdate(context, String text) async { Navigator.pushAndRemoveUntil( - locator().navigatorKey.currentContext!, + locator().navigatorKey.currentContext!, MaterialPageRoute(builder: (context) => AppUpdatePage(appUpdateText: text)), - (Route route) => false, + (Route route) => false, ); } get(String endPoint, {required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - Map? queryParams, - bool isExternal = false, - bool isRCService = false}) async { + required Function(String error, int statusCode) onFailure, + Map? queryParams, + bool isExternal = false, + bool isRCService = false}) async { String url; if (isExternal) { url = endPoint; @@ -592,10 +502,7 @@ class BaseAppClient { if (await Utils.checkConnection()) { final response = await http.get( Uri.parse(url.trim()), - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, + headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, ); final int statusCode = response.statusCode; // print("statusCode :$statusCode"); @@ -609,17 +516,16 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } getPharmacy(String endPoint, {required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isExternal = false, - Map? queryParams}) async { + required Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isExternal = false, + Map? queryParams}) async { var token = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); var user = await sharedPref.getObject(USER_PROFILE); @@ -642,9 +548,7 @@ class BaseAppClient { 'Content-Type': 'text/html; charset=utf-8', 'Accept': 'application/json', 'Authorization': token ?? '', - 'Mobilenumber': user != null - ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) - : "", + 'Mobilenumber': user != null ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user != null ? user['PatientID'].toString() : "", // 'Host': "mdlaboratories.com", @@ -654,19 +558,14 @@ class BaseAppClient { if (statusCode < 200 || statusCode >= 400 || json == null) { if (statusCode == 401) { - onFailure!(TranslationBase.of(AppGlobal.context).pharmacyRelogin, - statusCode); - logApiEndpointError( - endPoint, - TranslationBase.of(AppGlobal.context).pharmacyRelogin, - statusCode); + onFailure!(TranslationBase.of(AppGlobal.context).pharmacyRelogin, statusCode); + logApiEndpointError(endPoint, TranslationBase.of(AppGlobal.context).pharmacyRelogin, statusCode); Navigator.of(AppGlobal.context).pushNamed(HOME); } else { var bodyUtf = json.decode(utf8.decode(response.bodyBytes)); // print(bodyUtf); onFailure!(bodyUtf['error']['ErrorEndUserMsg'], statusCode); - logApiEndpointError( - endPoint, bodyUtf['error']['ErrorEndUserMsg'], statusCode); + logApiEndpointError(endPoint, bodyUtf['error']['ErrorEndUserMsg'], statusCode); } } else { // var parsed = json.decode(response.body.toString()); @@ -675,25 +574,23 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } simplePost( - String fullUrl, { - required Map body, - required Map headers, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - }) async { + String fullUrl, { + required Map body, + required Map headers, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + }) async { String url = fullUrl; // print("URL Query String: $url"); // print("body: $body"); if (await Utils.checkConnection()) { - headers!.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.post( Uri.parse(url.trim()), body: json.encode(body), @@ -701,12 +598,7 @@ class BaseAppClient { ); final int statusCode = response.statusCode; // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePost(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - body: body, - headers: headers); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); // print(response.body.toString()); @@ -718,16 +610,12 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } simpleGet(String fullUrl, - {Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers}) async { + {Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure, Map? queryParams, Map? headers}) async { headers = headers ?? {}; String url = fullUrl; @@ -739,8 +627,7 @@ class BaseAppClient { } if (await Utils.checkConnection()) { - headers.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.get( Uri.parse(url.trim()), headers: headers, @@ -748,12 +635,7 @@ class BaseAppClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleGet(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - headers: headers, - queryParams: queryParams); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure!('Error While Fetching data', statusCode); @@ -763,22 +645,17 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } simplePut(String fullUrl, - {Map? body, - Map? headers, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure}) async { + {Map? body, Map? headers, Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure}) async { String url = fullUrl; // print("URL Query String: $url"); if (await Utils.checkConnection()) { - headers!.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.put( Uri.parse(url.trim()), body: json.encode(body), @@ -787,12 +664,7 @@ class BaseAppClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePut(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - headers: headers, - body: body); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure!('Error While Fetching data', statusCode); @@ -802,16 +674,12 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } simpleDelete(String fullUrl, - {Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers}) async { + {Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure, Map? queryParams, Map? headers}) async { String url = fullUrl; // print("URL Query String: $url"); @@ -823,8 +691,7 @@ class BaseAppClient { } if (await Utils.checkConnection()) { - headers!.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.delete( Uri.parse(url.trim()), headers: headers, @@ -832,12 +699,7 @@ class BaseAppClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleDelete(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - queryParams: queryParams, - headers: headers); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure!('Error While Fetching data', statusCode); @@ -847,13 +709,11 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } - Future handleUnauthorized(int statusCode, - {required String forUrl}) async { + Future handleUnauthorized(int statusCode, {required String forUrl}) async { if (forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { final token = await generatePackagesToken(); packagesAuthHeader['Authorization'] = 'Bearer $token'; @@ -866,10 +726,8 @@ class BaseAppClient { await sharedPref.remove(LOGIN_TOKEN_ID); await sharedPref.remove(PHARMACY_CUSTOMER_ID); await authenticatedUserObject.getUser(); - Provider.of(AppGlobal.context, listen: false).isLogin = - false; - var model = - Provider.of(AppGlobal.context, listen: false); + Provider.of(AppGlobal.context, listen: false).isLogin = false; + var model = Provider.of(AppGlobal.context, listen: false); _vitalSignService.weightKg = ""; _vitalSignService.heightCm = ""; model.setState(0, 0, false, null); @@ -884,8 +742,7 @@ class BaseAppClient { static defaultHttpParameters() async { String token = await sharedPref.getString(TOKEN); - var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); var user = await sharedPref.getObject(USER_PROFILE); var params = {}; if (user != null) { @@ -905,11 +762,7 @@ class BaseAppClient { } pharmacyPost(String endPoint, - {Map? body, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - bool isAllowAny = false, - bool isExternal = false}) async { + {Map? body, Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure, bool isAllowAny = false, bool isExternal = false}) async { var token = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); var user = await sharedPref.getObject(USER_PROFILE); String url; @@ -921,14 +774,13 @@ class BaseAppClient { try { if (isExternal) { String token = await sharedPref.getString(TOKEN); - var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); var user = await sharedPref.getObject(USER_PROFILE); if (body!.containsKey('SetupID')) { body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] != null - ? body['SetupID'] - : SETUP_ID + ? body['SetupID'] + : SETUP_ID : SETUP_ID; } @@ -940,15 +792,15 @@ class BaseAppClient { body['generalid'] = GENERAL_ID; body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] != null - ? body['PatientOutSA'] - : user['OutSA'] + ? body['PatientOutSA'] + : user['OutSA'] : user['OutSA']; if (body.containsKey('isDentalAllowedBackend')) { body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] != null - ? body['isDentalAllowedBackend'] - : IS_DENTAL_ALLOWED_BACKEND + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; } @@ -957,24 +809,22 @@ class BaseAppClient { if (!body.containsKey('IsPublicRequest')) { body['PatientType'] = body.containsKey('PatientType') ? body['PatientType'] != null - ? body['PatientType'] - : user['PatientType'] != null - ? user['PatientType'] - : user['PatientType'] + ? body['PatientType'] + : user['PatientType'] != null + ? user['PatientType'] + : user['PatientType'] : user['PatientType']; body['PatientTypeID'] = body.containsKey('PatientTypeID') ? body['PatientTypeID'] != null - ? body['PatientTypeID'] - : user['PatientType'] != null - ? user['PatientType'] - : user['PatientType'] + ? body['PatientTypeID'] + : user['PatientType'] != null + ? user['PatientType'] + : user['PatientType'] : user['PatientType']; if (user != null) { body['TokenID'] = token; - body['PatientID'] = body['PatientID'] != null - ? body['PatientID'] - : user['PatientID']; + body['PatientID'] = body['PatientID'] != null ? body['PatientID'] : user['PatientID']; body['PatientOutSA'] = user['OutSA']; // body['SessionID'] = SESSION_ID; //getSessionId(token); } @@ -986,14 +836,11 @@ class BaseAppClient { var ss = json.encode(body); if (await Utils.checkConnection()) { - final response = await http - .post(Uri.parse(url.trim()), body: json.encode(body), headers: { + final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': token ?? '', - 'Mobilenumber': user != null - ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) - : "", + 'Mobilenumber': user != null ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user != null ? user['PatientID'].toString() : "", }); @@ -1001,15 +848,8 @@ class BaseAppClient { // print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400 || json == null) { var parsed = json.decode(utf8.decode(response.bodyBytes)); - onFailure!( - parsed['error']['ErrorEndUserMsgN'] ?? - 'Error While Fetching data', - statusCode); - logApiEndpointError( - endPoint, - parsed['error']['ErrorEndUserMsgN'] ?? - 'Error While Fetching data', - statusCode); + onFailure!(parsed['error']['ErrorEndUserMsgN'] ?? 'Error While Fetching data', statusCode); + logApiEndpointError(endPoint, parsed['error']['ErrorEndUserMsgN'] ?? 'Error While Fetching data', statusCode); } else { // var parsed = json.decode(response.body.toString()); var parsed = json.decode(utf8.decode(response.bodyBytes)); @@ -1017,8 +857,7 @@ class BaseAppClient { onSuccess!(parsed, statusCode); } else { if (parsed['ErrorType'] == 4) { - navigateToAppUpdate( - AppGlobal.context, parsed['ErrorEndUserMessage']); + navigateToAppUpdate(AppGlobal.context, parsed['ErrorEndUserMessage']); } if (isAllowAny) { onSuccess!(parsed, statusCode); @@ -1033,47 +872,25 @@ class BaseAppClient { if (parsed != null) { onSuccess!(parsed, statusCode); } else { - onFailure!( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure!(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); logout(); } } - } else if (parsed['MessageStatus'] == 1 || - parsed['SMSLoginRequired'] == true) { + } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { onSuccess!(parsed, statusCode); - } else if (parsed['MessageStatus'] == 2 && - parsed['IsAuthenticated']) { - if (parsed['message'] == null && - parsed['ErrorEndUserMessage'] == null) { + } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { + if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { - onFailure!("Server Error found with no available message", - statusCode); - logApiEndpointError( - endPoint, - "Server Error found with no available message", - statusCode); + onFailure!("Server Error found with no available message", statusCode); + logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { onFailure!(parsed['ErrorSearchMsg'], statusCode); - logApiEndpointError( - endPoint, parsed['ErrorSearchMsg'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } } else { - onFailure!( - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); + onFailure!(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } else if (!parsed['IsAuthenticated']) { await logout(); @@ -1084,18 +901,11 @@ class BaseAppClient { onSuccess!(parsed, statusCode); } else { if (parsed['message'] != null) { - onFailure!( - parsed['message'] ?? parsed['message'], statusCode); - logApiEndpointError(endPoint, - parsed['message'] ?? parsed['message'], statusCode); + onFailure!(parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } else { - onFailure!( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure!(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } @@ -1103,8 +913,7 @@ class BaseAppClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } catch (e) { print(e); @@ -1116,15 +925,11 @@ class BaseAppClient { Future generatePackagesToken() async { var url = EXA_CART_API_BASE_URL + PACKAGES_TOKEN; var body = { - "api_client": { - "client_id": "a4ab6be4-424f-4836-b032-46caed88e184", - "client_secret": "3c1a3e07-4a40-4510-9fb0-ee5f0a72752c" - } + "api_client": {"client_id": "a4ab6be4-424f-4836-b032-46caed88e184", "client_secret": "3c1a3e07-4a40-4510-9fb0-ee5f0a72752c"} }; String? token; final completer = Completer(); - simplePost(url, body: body, headers: {}, - onSuccess: (dynamic stringResponse, int statusCode) { + simplePost(url, body: body, headers: {}, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); token = jsonResponse['auth_token']; diff --git a/lib/core/viewModels/project_view_model.dart b/lib/core/viewModels/project_view_model.dart index 7216da7b..d4707aa9 100644 --- a/lib/core/viewModels/project_view_model.dart +++ b/lib/core/viewModels/project_view_model.dart @@ -18,7 +18,10 @@ import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart'; +import '../../models/Appointments/DoctorListResponse.dart'; + bool isAppArabic = false; + class ProjectViewModel extends BaseViewModel { GAnalytics get analytics => locator(); @@ -45,6 +48,27 @@ class ProjectViewModel extends BaseViewModel { GetAdmissionInfoResponseModel getAdmissionInfoResponseModel = GetAdmissionInfoResponseModel(); GetAdmissionRequestInfoResponseModel getAdmissionRequestInfoResponseModel = GetAdmissionRequestInfoResponseModel(); + bool isIndoorNavigationEnabled = false; + + int waitingAppointmentProjectID = 0; + DoctorList? waitingAppointmentDoctor; + String waitingAppointmentNFCCode = ""; + + setWaitingAppointmentDoctor(DoctorList waitingAppointmentDoctor) { + this.waitingAppointmentDoctor = waitingAppointmentDoctor; + notifyListeners(); + } + + setWaitingAppointmentNFCCode(String waitingAppointmentNFCCode) { + this.waitingAppointmentNFCCode = waitingAppointmentNFCCode; + notifyListeners(); + } + + setWaitingAppointmentProjectID(int projectID) { + this.waitingAppointmentProjectID = projectID; + notifyListeners(); + } + void setIsAllAppointmentsLoaded(bool value) { _isAllAppointmentsLoaded = value; notifyListeners(); @@ -137,6 +161,11 @@ class ProjectViewModel extends BaseViewModel { notifyListeners(); } + setIsIndoorNavigationEnabled(bool isEnabled) { + this.isIndoorNavigationEnabled = isEnabled; + notifyListeners(); + } + setPatientHasAdmissionRequest(bool hasAdmissionRequest) { this.patientHasAdmissionRequest = hasAdmissionRequest; notifyListeners(); diff --git a/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart b/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart index f23d175d..420f08f1 100644 --- a/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart +++ b/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart @@ -37,6 +37,7 @@ class _AllHabibMedicalSevicePage2State extends State AuthProvider authProvider = new AuthProvider(); WeatherService _weatherService = WeatherService(); double weatherNum = 30; + late ProjectViewModel projectViewModel; @override void initState() { @@ -235,7 +236,7 @@ class _AllHabibMedicalSevicePage2State extends State itemCount: hmgServices.length, padding: EdgeInsets.zero, itemBuilder: (BuildContext context, int index) { - return ServicesView(hmgServices[index], index, false); + return ServicesView(hmgServices[index], index, false, projectViewModel); }, ), ), diff --git a/lib/pages/Blood/blood_donation_book_appointment.dart b/lib/pages/Blood/blood_donation_book_appointment.dart index a0b9f6f7..6485b2d8 100644 --- a/lib/pages/Blood/blood_donation_book_appointment.dart +++ b/lib/pages/Blood/blood_donation_book_appointment.dart @@ -445,7 +445,7 @@ class _BloodDonationBookAppointmentState extends State { bool isEligible = false; bool isCash = false; + String? selectedPaymentMethod = ""; + String? selectedInstallments = ""; + String? tamaraPaymentStatus; + String? tamaraOrderID; + String? transID; + late MyInAppBrowser browser; + @override void initState() { // widget.authUser = new AuthenticatedUser(); @@ -213,13 +235,18 @@ class _BookConfirmState extends State { elevation: 0, onPressed: () async { bool isLiveCareSchedule = await this.sharedPref.getBool(IS_LIVECARE_APPOINTMENT) ?? false; - if (isLiveCareSchedule) { - insertLiveCareScheduledAppointment(context, widget.doctor); + + if (widget.isWalkinAppointment) { + getWalkinAppointmentPatientShare(); } else { - checkPatientHasDermaPackage(widget.doctor, projectViewModel.user.patientID!); + if (isLiveCareSchedule) { + insertLiveCareScheduledAppointment(context, widget.doctor); + } else { + checkPatientHasDermaPackage(widget.doctor, projectViewModel.user.patientID!); + } } }, - child: Text(TranslationBase.of(context).bookAppo, style: TextStyle(fontSize: 16.0, letterSpacing: -0.48, color: Colors.white)), + child: Text(widget.isWalkinAppointment ? TranslationBase.of(context).addToWaitingList : TranslationBase.of(context).bookAppo, style: TextStyle(fontSize: 16.0, letterSpacing: -0.48, color: Colors.white)), ), ), ), @@ -227,6 +254,405 @@ class _BookConfirmState extends State { ); } + getWalkinAppointmentPatientShare() { + String errorMsg = ""; + AppoitmentAllHistoryResultList appo = new AppoitmentAllHistoryResultList(); + GifLoaderDialogUtils.showMyDialog(context); + appo.doctorTitle = widget.doctor.doctorTitle; + appo.doctorNameObj = widget.doctor.name; + appo.appointmentDate = DateUtil.convertDateToString(DateTime.now()); + appo.projectName = widget.doctor.projectName; + + widget.service + .getPatientShareForWalkInAppointment( + widget.doctor.clinicID!, + widget.doctor.projectID!, + widget.doctor.doctorID!, + ) + .then((res) { + + widget.patientShareResponse = new PatientShareResponse.fromJson(res["OnlineCheckInAppointmentsWalkInModel"]); + GifLoaderDialogUtils.hideDialog(context); + + isInsured = res["IsInsured"]; + isEligible = res["IsEligible"]; + isCash = res["IsCash"]; + + if (isCash) { + if (widget.patientShareResponse.patientShareWithTax != 0 || widget.patientShareResponse.patientShareWithTax != 0.0) { + openPaymentDialog(appo, widget.patientShareResponse!); + } else { + insertWalkInAppointment(context, widget.doctor, widget.initialSlotDuration, null); + } + } else { + if (isInsured && isEligible) { + if (widget.patientShareResponse.patientShareWithTax != 0 || widget.patientShareResponse.patientShareWithTax != 0.0) { + openPaymentDialog(appo, widget.patientShareResponse!); + } else { + insertWalkInAppointment(context, widget.doctor, widget.initialSlotDuration, null); + } + } else { + if (isInsured && !isEligible) { + errorMsg = TranslationBase.of(context).invalidEligibility; + } else { + errorMsg = TranslationBase.of(context).invalidInsurance; + } + ConfirmDialog dialog = new ConfirmDialog( + isDissmissable: false, + context: context, + confirmMessage: errorMsg, + okText: TranslationBase.of(context).updateInsuranceText, + cancelText: TranslationBase.of(context).continueCash, + okFunction: () => {openUpdateInsurance()}, + cancelFunction: () => {continueAsCashForWalkIn(widget.doctor.projectID!)}); + dialog.showAlertDialog(context); + } + } + + // widget.patientShareResponse = new PatientShareResponse.fromJson(res["OnlineCheckInAppointmentsWalkInModel"]); + // GifLoaderDialogUtils.hideDialog(context); + // if (widget.patientShareResponse.patientShareWithTax != 0 || widget.patientShareResponse.patientShareWithTax != 0.0) { + // openPaymentDialog(appo, widget.patientShareResponse!); + // } else { + // insertWalkInAppointment(context, widget.doctor, widget.initialSlotDuration, null); + // } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + print(err); + }); + } + + openPaymentDialog(AppoitmentAllHistoryResultList appo, PatientShareResponse patientShareResponse) { + showGeneralDialog( + barrierColor: Colors.black.withOpacity(0.5), + transitionBuilder: (context, a1, a2, widget) { + final curvedValue = Curves.easeInOutBack.transform(a1.value) - 1.0; + return Transform( + transform: Matrix4.translationValues(0.0, curvedValue * 200, 0.0), + child: Opacity( + opacity: a1.value, + child: PaymentDialog( + appo: appo, + patientShareResponse: patientShareResponse, + isCashPatient: isCash, + onPaymentMethodSelected: () {}, + ), + ), + ); + }, + transitionDuration: Duration(milliseconds: 500), + barrierDismissible: false, + barrierLabel: '', + context: context, + pageBuilder: (context, animation1, animation2) => SizedBox()).then((value) { + print(value); + if (value != null) { + navigateToPaymentMethod(context, value as PatientShareResponse); + // projectViewModel.analytics.todoList.to_do_list_confirm_payment_details(appo); + } else { + // projectViewModel.analytics.todoList.to_do_list_cancel_payment_details(appo); + } + }); + } + + Future navigateToPaymentMethod(context, PatientShareResponse patientShareResponse) async { + AppoitmentAllHistoryResultList appo = new AppoitmentAllHistoryResultList(); + appo.projectID = widget.doctor.projectID; + appo.clinicID = widget.doctor.clinicID; + appo.clinicName = widget.doctor.clinicName; + appo.projectName = widget.doctor.projectName; + appo.appointmentNo = DateTime.now().millisecondsSinceEpoch; + appo.isLiveCareAppointment = false; + appo.doctorID = widget.doctor.doctorID; + appo.appointmentDate = DateUtil.convertDateToString(DateTime.now()); //widget.patientShareResponse.appointmentDate; + appo.serviceID = widget.patientShareResponse.serviceID; + + Navigator.push( + context, + FadePage( + page: PaymentMethod( + onSelectedMethod: (String metohd, [String? selectedInstallmentPlan]) { + setState(() {}); + }, + patientShare: widget.patientShareResponse.patientShareWithTax))) + .then((value) { + selectedPaymentMethod = value[0]; + if (value != null) { + if (selectedPaymentMethod == "ApplePay") { + if (projectViewModel.havePrivilege(103)) { + startApplePay(appo, patientShareResponse); + } else { + openPayment(value, projectViewModel.user, double.parse(patientShareResponse.patientShareWithTax.toString()), patientShareResponse, appo); + } + } else { + openPayment(value, projectViewModel.user, double.parse(patientShareResponse.patientShareWithTax.toString()), patientShareResponse, appo); + } + projectViewModel.analytics.appointment.payment_method(appointment_type: 'Walk-In', clinic: widget.doctor.clinicName, payment_method: value[0], payment_type: 'appointment'); + } + }); + } + + void startApplePay(AppoitmentAllHistoryResultList appo, PatientShareResponse patientShareResponse) async { + transID = Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo); + print("TransactionID: $transID"); + GifLoaderDialogUtils.showMyDialog(context); + + LiveCareService service = new LiveCareService(); + ApplePayInsertRequest applePayInsertRequest = new ApplePayInsertRequest(); + + PayfortProjectDetailsRespModel? payfortProjectDetailsRespModel; + await context.read().getProjectDetailsForPayfort(projectId: appo.projectID, serviceId: ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum()).then((value) { + payfortProjectDetailsRespModel = value!; + }); + + applePayInsertRequest.clientRequestID = transID; + applePayInsertRequest.clinicID = appo.clinicID; + applePayInsertRequest.currency = projectViewModel.user.outSA == 1 ? "AED" : "SAR"; + // applePayInsertRequest.customerEmail = projectViewModel.authenticatedUserObject.user.emailAddress; + applePayInsertRequest.customerEmail = "CustID_${projectViewModel.user.patientID}@HMG.com"; + applePayInsertRequest.customerID = projectViewModel.user.patientID; + applePayInsertRequest.customerName = projectViewModel.user.firstName! + " " + projectViewModel.user.lastName!; + applePayInsertRequest.deviceToken = await AppSharedPreferences().getString(PUSH_TOKEN); + applePayInsertRequest.voipToken = await AppSharedPreferences().getString(ONESIGNAL_APNS_TOKEN); + applePayInsertRequest.doctorID = appo.doctorID; + applePayInsertRequest.projectID = appo.projectID.toString(); + applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString(); + applePayInsertRequest.channelID = 3; + applePayInsertRequest.patientID = projectViewModel.user.patientID; + applePayInsertRequest.patientTypeID = projectViewModel.user.patientType; + applePayInsertRequest.patientOutSA = projectViewModel.user.outSA; + applePayInsertRequest.appointmentDate = appo.appointmentDate; + applePayInsertRequest.appointmentNo = appo.appointmentNo; + applePayInsertRequest.orderDescription = "Appointment Payment"; + applePayInsertRequest.liveServiceID = "0"; + applePayInsertRequest.latitude = "0.0"; + applePayInsertRequest.longitude = "0.0"; + applePayInsertRequest.amount = patientShareResponse.patientShareWithTax.toString(); + applePayInsertRequest.isSchedule = appo.isLiveCareAppointment! ? "1" : "0"; + applePayInsertRequest.language = projectViewModel.isArabic ? 'ar' : 'en'; + applePayInsertRequest.languageID = projectViewModel.isArabic ? 1 : 2; + applePayInsertRequest.userName = projectViewModel.user.patientID; + applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html"; + applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html"; + applePayInsertRequest.paymentOption = "ApplePay"; + + applePayInsertRequest.isMobSDK = true; + applePayInsertRequest.merchantReference = transID; + applePayInsertRequest.merchantIdentifier = payfortProjectDetailsRespModel!.merchantIdentifier!; + applePayInsertRequest.commandType = "PURCHASE"; + applePayInsertRequest.signature = payfortProjectDetailsRespModel!.signature; + applePayInsertRequest.accessCode = payfortProjectDetailsRespModel!.accessCode; + applePayInsertRequest.shaRequestPhrase = payfortProjectDetailsRespModel!.shaRequest; + applePayInsertRequest.shaResponsePhrase = payfortProjectDetailsRespModel!.shaResponse; + applePayInsertRequest.returnURL = ""; + + service.applePayInsertRequest(applePayInsertRequest, context).then((res) async { + if (res["MessageStatus"] == 1) { + await context.read().initiateApplePayWithPayfort( + customerName: projectViewModel.user.firstName! + " " + projectViewModel.user.lastName!, + // customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress, + customerEmail: "CustID_${projectViewModel.user.patientID}@HMG.com", + orderDescription: "Walk-In appointment payment", + orderAmount: double.parse(patientShareResponse.patientShareWithTax.toString()), + merchantReference: transID, + payfortProjectDetailsRespModel: payfortProjectDetailsRespModel, + currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR", + onFailed: (failureResult) async { + log("failureResult: ${failureResult.toString()}"); + AppToast.showErrorToast(message: failureResult.toString()); + }, + onSuccess: (successResult) async { + log("Payfort: ${successResult.responseMessage}"); + await context.read().addPayfortApplePayResponse(projectViewModel.user.patientID!, result: successResult); + checkPaymentStatus(appo); + }, + projectId: appo.projectID, + serviceTypeEnum: ServiceTypeEnum.appointmentPayment, + ); + } else { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: "An error occurred while processing your request"); + } + }).catchError((err) { + print(err); + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + }); + } + + openPayment(List paymentMethod, AuthenticatedUser authenticatedUser, num amount, PatientShareResponse patientShareResponse, AppoitmentAllHistoryResultList appo) async { + browser = new MyInAppBrowser(onExitCallback: onBrowserExit, appo: appo, onLoadStartCallback: onBrowserLoadStart, context: context); + selectedPaymentMethod = paymentMethod[0]; + selectedInstallments = paymentMethod[1]; + transID = Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo); + browser.openPaymentBrowser( + amount, + "Walk-In appointment payment", + transID!, + appo.projectID.toString(), + authenticatedUser.emailAddress!, + paymentMethod[0]!, + authenticatedUser.patientType, + authenticatedUser.firstName!, + authenticatedUser.patientID, + authenticatedUser, + browser, + widget.patientShareResponse.isLiveCareAppointment!, + "2", + widget.patientShareResponse.isLiveCareAppointment! ? widget.patientShareResponse.clinicID.toString() : "", + context, + widget.patientShareResponse.appointmentDate, + widget.patientShareResponse.appointmentNo, + widget.patientShareResponse.clinicID, + widget.patientShareResponse.doctorID, + paymentMethod[1]); + // } + } + + onBrowserLoadStart(String url) { + if (selectedPaymentMethod == "TAMARA") { + if (Platform.isAndroid) { + Uri uri = new Uri.dataFromString(url); + tamaraPaymentStatus = uri.queryParameters['status']; + tamaraOrderID = uri.queryParameters['AuthorizePaymentId']; + } else { + Uri uri = new Uri.dataFromString(url); + tamaraPaymentStatus = uri.queryParameters['paymentStatus']; + tamaraOrderID = uri.queryParameters['orderId']; + } + } + + MyInAppBrowser.successURLS.forEach((element) { + if (url.contains(element)) { + if (browser.isOpened()) browser.close(); + MyInAppBrowser.isPaymentDone = true; + return; + } + }); + + MyInAppBrowser.errorURLS.forEach((element) { + if (url.contains(element)) { + if (browser.isOpened()) browser.close(); + MyInAppBrowser.isPaymentDone = false; + return; + } + }); + } + + onBrowserExit(AppoitmentAllHistoryResultList appo, bool isPaymentMade) { + try { + if (selectedPaymentMethod == "TAMARA") { + checkTamaraPaymentStatus(transID!, appo); + // if (tamaraPaymentStatus != null && tamaraPaymentStatus!.toLowerCase() == "approved") { + // updateTamaraRequestStatus("success", "14", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID!, num.parse(selectedInstallments!), appo); + // } else { + // updateTamaraRequestStatus( + // "Failed", "00", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID! != null ? tamaraOrderID! : "", num.parse(selectedInstallments!), appo); + // } + } else { + checkPaymentStatus(appo); + } + } catch (err) { + print(err); + } + } + + checkTamaraPaymentStatus(String orderID, AppoitmentAllHistoryResultList appo) { + GifLoaderDialogUtils.showMyDialog(context); + DoctorsListService service = new DoctorsListService(); + service.getTamaraPaymentStatus(orderID).then((res) { + GifLoaderDialogUtils.hideDialog(context); + if (res["status"].toString().toLowerCase() == "success") { + updateTamaraRequestStatus("success", "14", orderID, tamaraOrderID!, int.parse(selectedInstallments!), appo); + } else { + updateTamaraRequestStatus( + "Failed", "00", Utils.getAppointmentTransID(appo.projectID!, appo.clinicID!, appo.appointmentNo!), tamaraOrderID != null ? tamaraOrderID! : "", int.parse(selectedInstallments!), appo); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + print(err); + }); + } + + updateTamaraRequestStatus(String responseMessage, String status, String clientRequestID, String tamaraOrderID, num selectedInstallments, AppoitmentAllHistoryResultList appo) { + GifLoaderDialogUtils.showMyDialog(context); + try { + DoctorsListService service = new DoctorsListService(); + service.updateTamaraRequestStatus(responseMessage, status, clientRequestID, tamaraOrderID, selectedInstallments).then((res) { + GifLoaderDialogUtils.hideDialog(context); + if (tamaraPaymentStatus!.toLowerCase() == "approved") { + insertWalkInAppointment(context, widget.doctor, widget.initialSlotDuration, tamaraOrderID); + } + }).catchError((err) { + print(err); + AppToast.showErrorToast(message: err); + GifLoaderDialogUtils.hideDialog(context); + }); + } catch (err) { + print(err); + } + } + + addAdvancedNumberRequestTamara(String advanceNumber, String paymentReference, String appointmentID, AppoitmentAllHistoryResultList appo) { + DoctorsListService service = new DoctorsListService(); + service.addAdvancedNumberRequest(advanceNumber, paymentReference, appointmentID, context).then((res) {}).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + print(err); + }); + } + + markAppointmentForTamara(AppoitmentAllHistoryResultList appo) { + GifLoaderDialogUtils.showMyDialog(context); + DoctorsListService service = new DoctorsListService(); + service.markAppointmentForTamara(appo.projectID!, appo.appointmentNo.toString()).then((res) { + GifLoaderDialogUtils.hideDialog(context); + sendNfcCheckInRequest(projectViewModel.waitingAppointmentNFCCode, 2, int.parse(appo.appointmentNo), projectViewModel.waitingAppointmentProjectID); + }).catchError((err) { + print(err); + AppToast.showErrorToast(message: err); + GifLoaderDialogUtils.hideDialog(context); + }); + } + + checkPaymentStatus(AppoitmentAllHistoryResultList appo) { + String txn_ref; + num amount; + String payment_method; + final currency = projectViewModel.user!.outSA == 0 ? "sar" : 'aed'; + GifLoaderDialogUtils.showMyDialog(context); + DoctorsListService service = new DoctorsListService(); + service.checkPaymentStatus(transID!, false, context).then((res) { + String paymentInfo = res['Response_Message']; + if (paymentInfo == 'Success') { + txn_ref = res['Merchant_Reference']; + amount = res['Amount']; + payment_method = res['PaymentMethod']; + GifLoaderDialogUtils.hideDialog(context); + insertWalkInAppointment(context, widget.doctor, widget.initialSlotDuration, res); + projectViewModel.analytics.appointment.payment_success( + appointment_type: 'Walk-In', payment_method: payment_method, clinic: appo.clinicName, hospital: appo.projectName, txn_amount: "$amount", txn_currency: currency, txn_number: txn_ref); + } else { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: res['Response_Message']); + projectViewModel.analytics.appointment.payment_fail( + appointment_type: 'Walk-In', + payment_method: selectedPaymentMethod, + clinic: appo.clinicName, + hospital: appo.projectName, + txn_amount: widget.patientShareResponse.patientShareWithTax.toString(), + txn_currency: currency, + error_type: res['Response_Message']); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err.toString()); + print(err); + }); + } + Widget showInfo(String title, String des) { return Container( child: Row( @@ -266,7 +692,7 @@ class _BookConfirmState extends State { if (isLiveCareSchedule != null && isLiveCareSchedule) { insertLiveCareScheduledAppointment(context, widget.doctor); } else { - insertAppointment(widget.doctor, widget.initialSlotDuration, invoiceNumber: invoiceNumber, lineItemNo: lineItemNo); + insertAppointment(context, widget.doctor, widget.initialSlotDuration); } }); } else { @@ -322,6 +748,111 @@ class _BookConfirmState extends State { }); } + void continueAsCashForWalkIn(int projectID) { + GifLoaderDialogUtils.showMyDialog(context); + widget.service.convertPatientToCash(projectID).then((res) { + GifLoaderDialogUtils.hideDialog(context); + if (res["MessageStatus"] == 1) { + getWalkinAppointmentPatientShare(); + } else { + AppToast.showErrorToast(message: res["ErrorEndUserMessage"]); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + print(err); + }); + } + + insertWalkInAppointment(context, DoctorList docObject, int initialSlotDuration, paymentRes) async { + GifLoaderDialogUtils.showMyDialog( + context, + ); + AppoitmentAllHistoryResultList appo = new AppoitmentAllHistoryResultList(); + appo.doctorID = docObject.doctorID; + appo.clinicID = docObject.clinicID; + appo.projectID = docObject.projectID; + + widget.service + .insertWalkInAppointment( + docObject.doctorID!, docObject.clinicID!, docObject.projectID!, widget.selectedTime, widget.selectedDate, initialSlotDuration, projectViewModel.isArabic ? 1 : 2, context) + .then((res) { + if (res['MessageStatus'] == 1) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showSuccessToast(message: TranslationBase.of(context).bookedSuccess); + appo.appointmentNo = res["AppointmentNo"]; // Add appointment No to the appointment project + Future.delayed(Duration(milliseconds: 500), () { + if (selectedPaymentMethod == "TAMARA") { + markAppointmentForTamara(appo); + addAdvancedNumberRequestTamara("Tamara-Advance-0000", paymentRes, res["AppointmentNo"].toString(), appo); + } else { + if (widget.patientShareResponse.patientShareWithTax != 0 || widget.patientShareResponse.patientShareWithTax != 0.0) { + createAdvancePayment(paymentRes, appo); + } else { + sendNfcCheckInRequest(projectViewModel.waitingAppointmentNFCCode, 2, int.parse(res["AppointmentNo"]), projectViewModel.waitingAppointmentProjectID); + } + } + }); + } else { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: res['ErrorEndUserMessage']); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + }); + } + + createAdvancePayment(res, AppoitmentAllHistoryResultList appo) { + GifLoaderDialogUtils.showMyDialog( + context, + ); + DoctorsListService service = new DoctorsListService(); + String paymentReference = res['Fort_id'].toString(); + service.createAdvancePayment(appo, appo.projectID.toString(), res['Amount'], res['Fort_id'], res['PaymentMethod'], context).then((res) { + GifLoaderDialogUtils.hideDialog(context); + addAdvancedNumberRequest( + Utils.isVidaPlusProject(projectViewModel, appo.projectID!) + ? res['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() + : res['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), + paymentReference, + appo.appointmentNo.toString(), + appo); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + print(err); + }); + } + + addAdvancedNumberRequest(String advanceNumber, String paymentReference, String appointmentID, AppoitmentAllHistoryResultList appo) { + GifLoaderDialogUtils.showMyDialog( + context, + ); + DoctorsListService service = new DoctorsListService(); + service.addAdvancedNumberRequest(advanceNumber, paymentReference, appointmentID, context).then((res) { + GifLoaderDialogUtils.hideDialog(context); + sendNfcCheckInRequest(projectViewModel.waitingAppointmentNFCCode, 2, int.parse(appointmentID), projectViewModel.waitingAppointmentProjectID); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err); + print(err); + }); + } + + sendNfcCheckInRequest(String nfcId, int checkInBy, int appoNo, int projectID) { + GifLoaderDialogUtils.showMyDialog(context); + DoctorsListService service = new DoctorsListService(); + service.sendCheckinNfcRequest(appoNo, nfcId, projectID, checkInBy, context as int).then((res) { + GifLoaderDialogUtils.hideDialog(context); + _showMyDialog(res["SuccessMsg"], this.context); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + print(err); + _showMyDialog(err, this.context); + }); + } + checkPatientHasDermaPackage(DoctorList doctor, int patientID) { GifLoaderDialogUtils.showMyDialog(context); widget.service @@ -358,11 +889,11 @@ class _BookConfirmState extends State { }); } - insertAppointment(DoctorList docObject, int initialSlotDuration, {int? invoiceNumber, int? lineItemNo}) async { + insertAppointment(context, DoctorList docObject, int initialSlotDuration) async { final timeSlot = DocAvailableAppointments.selectedAppoDateTime; String logs = await sharedPref.getString('selectedLogSlots'); List decodedLogs = json.decode(logs); - GifLoaderDialogUtils.showMyDialog(context, barrierDismissible: true); + GifLoaderDialogUtils.showMyDialog(context, barrierDismissible: false); AppoitmentAllHistoryResultList appo; widget.service // .insertAppointment(docObject.doctorID!, docObject.clinicID!, docObject.projectID!, widget.selectedTime, widget.selectedDate, initialSlotDuration, context, 'null', null, null, projectViewModel) @@ -613,4 +1144,32 @@ class _BookConfirmState extends State { ), ); } + + Future _showMyDialog(String message, BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: true, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Alert'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text(message), + ], + ), + ), + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () { + Navigator.of(context).pop(); + Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => LandingPage()), (Route r) => false); + }, + ), + ], + ); + }, + ); + } } diff --git a/lib/pages/BookAppointment/DoctorProfile.dart b/lib/pages/BookAppointment/DoctorProfile.dart index f1738c85..1674c43d 100644 --- a/lib/pages/BookAppointment/DoctorProfile.dart +++ b/lib/pages/BookAppointment/DoctorProfile.dart @@ -10,6 +10,7 @@ import 'package:diplomaticquarterapp/models/Clinics/ClinicListResponse.dart'; import 'package:diplomaticquarterapp/models/header_model.dart'; import 'package:diplomaticquarterapp/pages/BookAppointment/DentalComplaints.dart'; import 'package:diplomaticquarterapp/pages/BookAppointment/doctor_post_pre_images_page.dart'; +import 'package:diplomaticquarterapp/pages/BookAppointment/waiting_appointment/waiting_appointment_info.dart'; import 'package:diplomaticquarterapp/pages/MyAppointments/SchedulePage.dart'; import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; @@ -520,15 +521,9 @@ class _DoctorProfileState extends State with TickerProviderStateM // if (widget.isDoctorNameSearch && widget.doctor.clinicID == 17) { // navigateToDentalComplaints(context); // } else { - if (DocAvailableAppointments.areSlotsAvailable) { + if (DocAvailableAppointments.selectedTime == TranslationBase.of(context).waitingAppointment) { if (projectViewModel.isLogin) { - if (widget.isDoctorNameSearch && widget.doctor.clinicID == 17 && projectViewModel.user!.age! > 12) { - navigateToDentalComplaints(context); - } else { - final timeSlot = DocAvailableAppointments.selectedAppoDateTime; - navigateToBookConfirm(context); - projectViewModel.analytics.appointment.book_appointment_review(appointment_type: 'regular', dateTime: timeSlot!, doctor: widget.doctor); - } + canPayForWalkInAppointment(); } else { ConfirmDialog dialog = new ConfirmDialog( context: context, @@ -539,9 +534,30 @@ class _DoctorProfileState extends State with TickerProviderStateM cancelFunction: () => {}); dialog.showAlertDialog(context); } - } else - AppToast.showErrorToast(message: TranslationBase.of(context).selectSlot); - // } + } else { + if (DocAvailableAppointments.areSlotsAvailable) { + if (projectViewModel.isLogin) { + if (widget.isDoctorNameSearch && widget.doctor.clinicID == 17 && projectViewModel.user!.age! > 12) { + navigateToDentalComplaints(context); + } else { + final timeSlot = DocAvailableAppointments.selectedAppoDateTime; + navigateToBookConfirm(context); + projectViewModel.analytics.appointment.book_appointment_review(appointment_type: 'regular', dateTime: timeSlot!, doctor: widget.doctor); + } + } else { + ConfirmDialog dialog = new ConfirmDialog( + context: context, + confirmMessage: TranslationBase.of(context).loginToUseService, + okText: TranslationBase.of(context).confirm, + cancelText: TranslationBase.of(context).cancel_nocaps, + okFunction: () => {navigateToLogin()}, + cancelFunction: () => {}); + dialog.showAlertDialog(context); + } + } else { + AppToast.showErrorToast(message: TranslationBase.of(context).selectSlot); + } + } } Future navigateToDentalComplaints(BuildContext context) async { @@ -586,8 +602,33 @@ class _DoctorProfileState extends State with TickerProviderStateM selectedDate: DocAvailableAppointments.selectedDate!, selectedTime: DocAvailableAppointments.selectedTime!, initialSlotDuration: DocAvailableAppointments.initialSlotDuration!, + isWalkinAppointment: false, ), ), ); } + + Future navigateToWaitingAppointment(context) async { + projectViewModel.setWaitingAppointmentProjectID(widget.doctor.projectID!); + projectViewModel.setWaitingAppointmentDoctor(widget.doctor); + Navigator.push( + context, + FadePage( + page: WaitingAppointmentInfo(), + ), + ); + } + + canPayForWalkInAppointment() { + DoctorsListService service = new DoctorsListService(); + GifLoaderDialogUtils.showMyDialog(context); + service.canPayForWalkInAppointment(widget.doctor.clinicID!, widget.doctor.projectID!, widget.doctor.doctorID!).then((res) { + GifLoaderDialogUtils.hideDialog(context); + navigateToWaitingAppointment(context); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err, localContext: context); + print(err); + }); + } } diff --git a/lib/pages/BookAppointment/components/DocAvailableAppointments.dart b/lib/pages/BookAppointment/components/DocAvailableAppointments.dart index a2940ce8..d44eee92 100644 --- a/lib/pages/BookAppointment/components/DocAvailableAppointments.dart +++ b/lib/pages/BookAppointment/components/DocAvailableAppointments.dart @@ -60,6 +60,8 @@ class _DocAvailableAppointmentsState extends State wit var language; bool isLiveCareSchedule = false; + bool isWaitingAppointmentAvailable = false; + // String selectedLogSlots =''; @override @@ -198,7 +200,7 @@ class _DocAvailableAppointmentsState extends State wit _events.forEach((key, value) { final DateTime startTime = DateTime(key.year, key.month, key.day, 9, 0, 0); final DateTime endTime = startTime.add(const Duration(hours: 2)); - meetings.add(Meeting("", startTime, endTime, CustomColors.green, false)); + meetings.add(Meeting("", startTime, endTime, CustomColors.green, false, "")); }); return meetings; } @@ -206,7 +208,9 @@ class _DocAvailableAppointmentsState extends State wit openTimeSlotsPickerForDate(DateTime dateStart, List freeSlots) { dayEvents.clear(); DateTime dateStartObj = new DateTime(dateStart.year, dateStart.month, dateStart.day, 0, 0, 0, 0, 0); - + if (isWaitingAppointmentAvailable && DateUtils.isSameDay(dateStart, DateTime.now())) { + dayEvents.add(TimeSlot(isoTime: TranslationBase.of(context).waitingAppointment, start: DateTime.now(), end: DateTime.now(), vidaDate: "")); + } freeSlots.forEach((v) { if (v.start == dateStartObj) dayEvents.add(v); }); @@ -349,20 +353,22 @@ class _DocAvailableAppointmentsState extends State wit GifLoaderDialogUtils.hideDialog(context); if (res['MessageStatus'] == 1) { if (res['FreeTimeSlots'].length != 0) { + isWaitingAppointmentAvailable = res['IsAllowToBookWaitingAppointment']; // true; + // isWaitingAppointmentAvailable = true; // true; DocAvailableAppointments.initialSlotDuration = res['InitialSlotDuration']; DocAvailableAppointments.areAppointmentsAvailable = true; freeSlotsResponse = res['FreeTimeSlots']; _getJSONSlots().then((value) { - setState(() => { - _events.clear(), - _events = value, + setState(() { + _events.clear(); + _events = value; if (widget.doctorSchedule != null) { - _onDaySelected(DateUtil.convertStringToDate(widget.doctorSchedule['Date'])), + _onDaySelected(DateUtil.convertStringToDate(widget.doctorSchedule['Date'])); _calendarController.selectedDate = DateUtil.convertStringToDate( widget.doctorSchedule['Date'], - ) - } + ); + }; }); }); } else { @@ -464,11 +470,12 @@ class MeetingDataSource extends CalendarDataSource { } class Meeting { - Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay); + Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay, this.notes); String eventName; DateTime from; DateTime to; Color background; bool isAllDay; + String notes; } diff --git a/lib/pages/BookAppointment/waiting_appointment/waiting_appointment_info.dart b/lib/pages/BookAppointment/waiting_appointment/waiting_appointment_info.dart new file mode 100644 index 00000000..f1f8d934 --- /dev/null +++ b/lib/pages/BookAppointment/waiting_appointment/waiting_appointment_info.dart @@ -0,0 +1,113 @@ +import 'package:diplomaticquarterapp/pages/BookAppointment/waiting_appointment/waiting_appointment_verification.dart'; +import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class WaitingAppointmentInfo extends StatelessWidget { + const WaitingAppointmentInfo({super.key}); + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: TranslationBase.of(context).waitingAppointment, + isShowAppBar: true, + isShowDecPage: false, + showNewAppBar: true, + showNewAppBarTitle: true, + backgroundColor: CustomColors.appBackgroudGreyColor, + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: MediaQuery.of(context).size.width, + decoration: containerRadius(Colors.white, 10), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset( + "assets/images/new/waitingAppo.svg", + width: 52.0, + height: 52.0, + ), + mHeight(11), + Text( + TranslationBase.of(context).whatWaitingAppointment, + maxLines: 1, + style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: Color(0xff2B353E), letterSpacing: -1.44, height: 35 / 24), + ), + mHeight(11), + Container( + width: MediaQuery.of(context).size.width * 0.8, + child: Text( + TranslationBase.of(context).waitingAppointmentText1, + style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip), + ), + ), + mHeight(18), + Container( + width: MediaQuery.of(context).size.width * 0.8, + child: Text( + TranslationBase.of(context).waitingAppointmentText2, + style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip), + ), + ), + mHeight(24), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + Icons.warning, + size: 20, + color: Color(0xffA78618), + ), + mWidth(10), + Container( + width: MediaQuery.of(context).size.width * 0.7, + child: Text( + TranslationBase.of(context).waitingAppointmentText3, + style: TextStyle( + fontSize: 14, fontStyle: FontStyle.italic, fontWeight: FontWeight.w600, color: Color(0xffA78618), letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip), + ), + ), + ], + ), + ], + ), + ), + ), + ], + ), + ), + ), + bottomSheet: Container( + height: 80, + color: CustomColors.white, + padding: EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 25.0), + child: Container( + child: DefaultButton( + TranslationBase.of(context).continues, + () { + Navigator.push( + context, + FadePage( + page: WaitingAppointmentVerification(), + ), + ); + }, + color: CustomColors.accentColor, + ), + ), + ), + ); + } +} diff --git a/lib/pages/BookAppointment/waiting_appointment/waiting_appointment_verification.dart b/lib/pages/BookAppointment/waiting_appointment/waiting_appointment_verification.dart new file mode 100644 index 00000000..6853c6d9 --- /dev/null +++ b/lib/pages/BookAppointment/waiting_appointment/waiting_appointment_verification.dart @@ -0,0 +1,292 @@ +import 'package:barcode_scan2/barcode_scan2.dart'; +import 'package:diplomaticquarterapp/core/model/privilege/ProjectDetailListModel.dart'; +import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/pages/BookAppointment/BookConfirm.dart'; +import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; +import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/app_toast.dart'; +import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; +import 'package:diplomaticquarterapp/uitl/location_util.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:diplomaticquarterapp/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import '../../../uitl/utils.dart'; + +class WaitingAppointmentVerification extends StatefulWidget { + const WaitingAppointmentVerification({super.key}); + + @override + State createState() => _WaitingAppointmentVerificationState(); +} + +class _WaitingAppointmentVerificationState extends State { + String selectedVerificationMethod = "QR"; + + late ProjectViewModel projectViewModel; + late LocationUtils locationUtils; + ProjectDetailListModel projectDetailListModel = ProjectDetailListModel(); + + @override + Widget build(BuildContext context) { + projectViewModel = Provider.of(context); + return AppScaffold( + appBarTitle: TranslationBase.of(context).waitingAppointment, + isShowAppBar: true, + isShowDecPage: false, + showNewAppBar: true, + showNewAppBarTitle: true, + backgroundColor: CustomColors.appBackgroudGreyColor, + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(11), + Text( + TranslationBase.of(context).waitingAppointmentVerificationMethod, + maxLines: 1, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700, color: Color(0xff2B353E), letterSpacing: -1.04, height: 35 / 24), + ), + mHeight(12), + Container( + width: MediaQuery.of(context).size.width, + decoration: containerRadius(Colors.white, 10), + child: Padding( + padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 0.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + onTap: () { + setState(() { + selectedVerificationMethod = "QR"; + }); + }, + child: Row( + children: [ + Container( + width: 20, + height: 20, + decoration: containerColorRadiusBorderWidth(selectedVerificationMethod == "QR" ? CustomColors.accentColor : Colors.transparent, 100, Colors.grey, 0.5), + ), + mWidth(6), + Container( + height: 40.0, + width: 40.0, + padding: EdgeInsets.all(7.0), + child: SvgPicture.asset( + "assets/images/new/services/qr_code.svg", + ), + ), + Text( + TranslationBase.of(context).pharmaLiveCareScanQR, + style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, fontWeight: FontWeight.w600, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip), + ), + ], + ), + ), + Divider(), + InkWell( + onTap: () { + setState(() { + selectedVerificationMethod = "NFC"; + }); + }, + child: Row( + children: [ + Container( + width: 20, + height: 20, + decoration: containerColorRadiusBorderWidth(selectedVerificationMethod == "NFC" ? CustomColors.accentColor : Colors.transparent, 100, Colors.grey, 0.5), + ), + mWidth(6), + Container( + height: 40.0, + width: 40.0, + padding: EdgeInsets.all(7.0), + child: SvgPicture.asset( + "assets/images/new/services/contactless.svg", + ), + ), + Text( + TranslationBase.of(context).scanNFC, + style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, fontWeight: FontWeight.w600, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip), + ), + ], + ), + ), + Divider(), + InkWell( + onTap: () { + setState(() { + selectedVerificationMethod = "Location"; + }); + }, + child: Row( + children: [ + Container( + width: 20, + height: 20, + decoration: containerColorRadiusBorderWidth(selectedVerificationMethod == "Location" ? CustomColors.accentColor : Colors.transparent, 100, Colors.grey, 0.5), + ), + mWidth(6), + Container( + height: 40.0, + width: 40.0, + padding: EdgeInsets.all(7.0), + child: SvgPicture.asset( + "assets/images/new/services/location.svg", + ), + ), + Text( + TranslationBase.of(context).checkInViaLocation, + style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, fontWeight: FontWeight.w600, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip), + ), + ], + ), + ), + mHeight(6), + ], + ), + ), + ), + mHeight(12), + Container( + width: MediaQuery.of(context).size.width, + decoration: containerRadius(Colors.white, 10), + child: Padding( + padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 0.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(12), + Text( + TranslationBase.of(context).howToUseVerificationMethod, + maxLines: 1, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -1.04, height: 35 / 24), + ), + mHeight(12), + Image.asset( + 'assets/images/new/NFCCheckIn_QR_gps_HMG.png', + fit: BoxFit.fitWidth, + width: MediaQuery.of(context).size.width, + ), + mHeight(12), + ], + ), + ), + ), + ], + ), + ), + ), + bottomSheet: Container( + height: 80, + color: CustomColors.white, + padding: EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 25.0), + child: Container( + child: DefaultButton( + TranslationBase.of(context).continues, + () { + startVerification(); + }, + color: CustomColors.accentColor, + ), + ), + ), + ); + } + + startVerification() { + switch (selectedVerificationMethod) { + case "QR": + startQRCodeScan(); + break; + case "NFC": + startNFCScan(); + break; + case "Location": + startLocationCheckIn(); + break; + } + } + + checkScannedNFCAndQRCode(String nfcId) { + GifLoaderDialogUtils.showMyDialog(context); + DoctorsListService service = new DoctorsListService(); + service.checkScannedNFCAndQRCode(nfcId, projectViewModel.waitingAppointmentDoctor!.projectID!).then((res) { + GifLoaderDialogUtils.hideDialog(context); + projectViewModel.setWaitingAppointmentNFCCode(nfcId); + if (res["returnValue"] == 1) { + navigateToBookConfirm(context); + } else { + AppToast.showErrorToast(message: "Invalid verification point scanned."); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + print(err); + }); + } + + Future navigateToBookConfirm(context) async { + final DateFormat formatter = DateFormat('yyyy-MM-dd'); + Navigator.push( + context, + FadePage( + page: BookConfirm( + doctor: projectViewModel.waitingAppointmentDoctor!, + isLiveCareAppointment: false, + selectedDate: formatter.format(DateTime.now()), + selectedTime: TranslationBase.of(context).waitingAppointment, + initialSlotDuration: 15, + isWalkinAppointment: true, + ), + ), + ); + } + + startLocationCheckIn() async { + locationUtils = new LocationUtils(isShowConfirmDialog: true, context: context); + locationUtils.getCurrentLocation(callBack: (value) { + projectDetailListModel = Utils.getProjectDetailObj(projectViewModel, projectViewModel.waitingAppointmentProjectID); + double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000; + projectViewModel.setWaitingAppointmentNFCCode(projectDetailListModel.checkInQrCode!); + print(dist); + if (dist <= projectDetailListModel.geofenceRadius!) { + navigateToBookConfirm(context); + } else { + AppToast.showErrorToast(message: TranslationBase.of(context).locationCheckInError); + } + }); + } + + startNFCScan() { + Future.delayed(const Duration(milliseconds: 500), () { + showNfcReader(context, onNcfScan: (String nfcId) { + Future.delayed(const Duration(milliseconds: 100), () { + checkScannedNFCAndQRCode(nfcId); + }); + }, onCancel: () { + // Navigator.of(context).pop(); + // locator().todoList.to_do_list_nfc_cancel(widget.appointment!); + }); + }); + } + + startQRCodeScan() async { + String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent)); + if (onlineCheckInQRCode != "") { + checkScannedNFCAndQRCode(onlineCheckInQRCode); + } else {} + } +} diff --git a/lib/pages/Covid-DriveThru/Covid-TimeSlots.dart b/lib/pages/Covid-DriveThru/Covid-TimeSlots.dart index a9a16ce7..88be72dd 100644 --- a/lib/pages/Covid-DriveThru/Covid-TimeSlots.dart +++ b/lib/pages/Covid-DriveThru/Covid-TimeSlots.dart @@ -260,7 +260,7 @@ class _CovidTimeSlotsState extends State with TickerProviderStat _events.forEach((key, value) { final DateTime startTime = DateTime(key.year, key.month, key.day, 9, 0, 0); final DateTime endTime = startTime.add(const Duration(minutes: 20)); - meetings.add(Meeting("", startTime, endTime, CustomColors.green, false)); + meetings.add(Meeting("", startTime, endTime, CustomColors.green, false, "")); }); return meetings; } @@ -584,11 +584,12 @@ class MeetingDataSource extends CalendarDataSource { } class Meeting { - Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay); + Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay, this.notes); String eventName; DateTime from; DateTime to; Color background; bool isAllDay; + String notes; } diff --git a/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart b/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart index 82e6ab96..8281450b 100644 --- a/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart +++ b/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart @@ -272,7 +272,7 @@ class _InPatientPendingAdvancePaymentState extends State with SingleTick } void goToBookConfirm() { - if (DocAvailableAppointments.areSlotsAvailable) - navigateToBookConfirm(context); - else - AppToast.showErrorToast(message: TranslationBase.of(context).selectSlot); + if (DocAvailableAppointments.selectedTime == TranslationBase.of(context).waitingAppointment) { + canPayForWalkInAppointment(); + } else { + if (DocAvailableAppointments.areSlotsAvailable) + navigateToBookConfirm(context); + else + AppToast.showErrorToast(message: TranslationBase.of(context).selectSlot); + } + } + + canPayForWalkInAppointment() { + DoctorsListService service = new DoctorsListService(); + GifLoaderDialogUtils.showMyDialog(context); + service.canPayForWalkInAppointment(widget.appo.clinicID!, widget.appo.projectID!, widget.appo.doctorID!).then((res) { + GifLoaderDialogUtils.hideDialog(context); + navigateToWaitingAppointment(context); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: err, localContext: context); + print(err); + }); + } + + Future navigateToWaitingAppointment(context) async { + DoctorList doctor = new DoctorList(); + doctor.name = widget.appo.doctorNameObj; + doctor.clinicID = widget.appo.clinicID; + doctor.projectID = widget.appo.projectID; + doctor.doctorID = widget.appo.doctorID; + doctor.clinicName = widget.appo.clinicName; + doctor.projectName = widget.appo.projectName; + doctor.doctorTitle = widget.appo.doctorTitle; + doctor.doctorImageURL = widget.appo.doctorImageURL; + doctor.speciality = widget.appo.doctorSpeciality; + doctor.nationalityFlagURL = ""; + doctor.doctorRate = widget.appo.doctorRate; + doctor.noOfPatientsRate = widget.appo.noOfPatientsRate; + + projectViewModel?.setWaitingAppointmentProjectID(widget.appo.projectID!); + projectViewModel?.setWaitingAppointmentDoctor(doctor); + Navigator.push( + context, + FadePage( + page: WaitingAppointmentInfo(), + ), + ); } Future navigateToBookConfirm(context) async { Navigator.push( - context, - FadePage( - page: BookConfirm( + context, + FadePage( + page: BookConfirm( doctor: getDoctorObject(), isLiveCareAppointment: widget.appo.isLiveCareAppointment!, selectedDate: DocAvailableAppointments.selectedDate!, selectedTime: DocAvailableAppointments.selectedTime!, initialSlotDuration: 0, - ))); + isWalkinAppointment: false, + ), + ), + ); } void getDoctorRatingsDetails() { diff --git a/lib/pages/MyAppointments/models/BookedButtons.dart b/lib/pages/MyAppointments/models/BookedButtons.dart index 66e4366f..39aed7cc 100644 --- a/lib/pages/MyAppointments/models/BookedButtons.dart +++ b/lib/pages/MyAppointments/models/BookedButtons.dart @@ -39,6 +39,7 @@ class BookedButtons { "icon": "hosp_location.svg", "caller": "navigateToProject", }, - {"title": TranslationBase.of(AppGlobal.context).online, "subtitle": TranslationBase.of(AppGlobal.context).payment, "icon": "online_payment.svg", "caller": "goToTodoList"} + {"title": TranslationBase.of(AppGlobal.context).online, "subtitle": TranslationBase.of(AppGlobal.context).payment, "icon": "online_payment.svg", "caller": "goToTodoList"}, + // {"title": TranslationBase.of(AppGlobal.context).clinic, "subtitle": TranslationBase.of(AppGlobal.context).locationa, "icon": "hosp_location.svg", "caller": "goToNavigation"} ]; } diff --git a/lib/pages/MyAppointments/models/ConfirmedButtons.dart b/lib/pages/MyAppointments/models/ConfirmedButtons.dart index 7ba3ce1c..d49723e9 100644 --- a/lib/pages/MyAppointments/models/ConfirmedButtons.dart +++ b/lib/pages/MyAppointments/models/ConfirmedButtons.dart @@ -19,6 +19,7 @@ class ConfirmedButtons { // "icon": "assets/images/new-design/generate_visit_ticket.png", // "caller": "visitTicket" // }, - {"title": TranslationBase.of(AppGlobal.context).online, "subtitle": TranslationBase.of(AppGlobal.context).payment, "icon": "online_payment.svg", "caller": "goToTodoList"} + {"title": TranslationBase.of(AppGlobal.context).online, "subtitle": TranslationBase.of(AppGlobal.context).payment, "icon": "online_payment.svg", "caller": "goToTodoList"}, + // {"title": TranslationBase.of(AppGlobal.context).clinic, "subtitle": TranslationBase.of(AppGlobal.context).locationa, "icon": "hosp_location.svg", "caller": "goToNavigation"} ]; } diff --git a/lib/pages/MyAppointments/widgets/AppointmentActions.dart b/lib/pages/MyAppointments/widgets/AppointmentActions.dart index 6347d3f4..fcb698b3 100644 --- a/lib/pages/MyAppointments/widgets/AppointmentActions.dart +++ b/lib/pages/MyAppointments/widgets/AppointmentActions.dart @@ -27,9 +27,11 @@ import 'package:diplomaticquarterapp/pages/medical/prescriptions/prescription_it import 'package:diplomaticquarterapp/pages/medical/radiology/radiology_details_page.dart'; import 'package:diplomaticquarterapp/pages/medical/vital_sign/vital_sign_details_screen.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; +import 'package:diplomaticquarterapp/uitl/app-permissions.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; +import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/widgets/data_display/medical/medical_profile_item.dart'; @@ -40,6 +42,7 @@ import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; import 'package:huawei_map/huawei_map.dart' as hmsMap; import 'package:intl/intl.dart'; import 'package:map_launcher/map_launcher.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -178,6 +181,31 @@ class _AppointmentActionsState extends State { navigateToInsertComplaint(); locator().appointment.appointment_detail_action(appointment: widget.appo, action: 'raise complaint'); break; + + case "goToNavigation": + initPenguinSDK(); + locator().appointment.appointment_detail_action(appointment: widget.appo, action: 'navigate to clinic'); + break; + } + } + + initPenguinSDK() async { + NavigationClinicDetails data = NavigationClinicDetails(); + // data.clinicId = widget.appo.clinicID.toString(); + data.clinicId = "49"; + data.patientId = widget.appo.patientID.toString(); + data.projectId = widget.appo.projectID.toString(); + final bool permited = await AppPermission.askPenguinPermissions(); + if (!permited) { + Map statuses = await [ + Permission.location, + Permission.bluetooth, + Permission.bluetoothConnect, + Permission.bluetoothScan, + Permission.activityRecognition, + ].request().whenComplete(() { + PenguinMethodChannel.launch("penguin", widget.projectViewModel!.isArabic ? "ar" : "en", widget.projectViewModel!.authenticatedUserObject.user.patientID.toString(), details: data); + }); } } diff --git a/lib/pages/ToDoList/ObGyne/ObGyne-TimeSlots.dart b/lib/pages/ToDoList/ObGyne/ObGyne-TimeSlots.dart index 38c09047..9660a616 100644 --- a/lib/pages/ToDoList/ObGyne/ObGyne-TimeSlots.dart +++ b/lib/pages/ToDoList/ObGyne/ObGyne-TimeSlots.dart @@ -253,7 +253,7 @@ class _CovidTimeSlotsState extends State with TickerProviderSta _events!.forEach((key, value) { final DateTime startTime = DateTime(key.year, key.month, key.day, 9, 0, 0); final DateTime endTime = startTime.add(const Duration(minutes: 20)); - meetings.add(Meeting("", startTime, endTime, CustomColors.green, false)); + meetings.add(Meeting("", startTime, endTime, CustomColors.green, false, "")); }); return meetings; } @@ -534,11 +534,12 @@ class MeetingDataSource extends CalendarDataSource { } class Meeting { - Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay); + Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay, this.notes); String eventName; DateTime from; DateTime to; Color background; bool isAllDay; + String notes; } diff --git a/lib/pages/ToDoList/ToDo.dart b/lib/pages/ToDoList/ToDo.dart index 44b0b022..5b8c6801 100644 --- a/lib/pages/ToDoList/ToDo.dart +++ b/lib/pages/ToDoList/ToDo.dart @@ -29,10 +29,12 @@ import 'package:diplomaticquarterapp/services/livecare_services/livecare_provide import 'package:diplomaticquarterapp/services/payfort_services/payfort_project_details_resp_model.dart'; import 'package:diplomaticquarterapp/services/payfort_services/payfort_view_model.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/app-permissions.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; +import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; @@ -50,6 +52,7 @@ import 'package:flutter_countdown_timer/current_remaining_time.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; class ToDo extends StatefulWidget { @@ -354,23 +357,56 @@ class _ToDoState extends State with SingleTickerProviderStateMixin { style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.48, height: 25 / 16), ), ), - InkWell( - onTap: () { - navigateToAppointmentDetails(context, appoList[index]); - }, - child: Padding( - padding: const EdgeInsets.only(top: 0.0), - child: Text( - TranslationBase.of(context).moreDetails, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: CustomColors.accentColor, - letterSpacing: -0.48, - height: 25 / 16, - decoration: TextDecoration.underline), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + navigateToAppointmentDetails(context, appoList[index]); + }, + child: Padding( + padding: const EdgeInsets.only(top: 0.0), + child: Text( + TranslationBase.of(context).moreDetails, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: CustomColors.accentColor, + letterSpacing: -0.48, + height: 25 / 16, + decoration: TextDecoration.underline), + ), + ), ), - ), + if (projectViewModel.isIndoorNavigationEnabled) + InkWell( + onTap: () { + NavigationClinicDetails data = NavigationClinicDetails(); + // data.clinicId = appoList[index].clinicID.toString(); + data.clinicId = "46"; + data.patientId = appoList[index].patientID.toString(); + data.projectId = appoList[index].projectID.toString(); + initPenguinSDK(data); + }, + child: Column( + children: [ + SvgPicture.asset( + "assets/images/new/Indoor_nav_appo.svg", + ), + Text( + TranslationBase.of(context).clinicLocation, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: CustomColors.accentColor, + letterSpacing: -0.48, + height: 25 / 16, + decoration: TextDecoration.underline), + ), + ], + ), + ), + ], ), ], ), @@ -530,6 +566,21 @@ class _ToDoState extends State with SingleTickerProviderStateMixin { ); } + initPenguinSDK(NavigationClinicDetails data) async { + final bool permited = await AppPermission.askPenguinPermissions(); + if (!permited) { + Map statuses = await [ + Permission.location, + Permission.bluetooth, + Permission.bluetoothConnect, + Permission.bluetoothScan, + Permission.activityRecognition, + ].request().whenComplete(() { + PenguinMethodChannel.launch("penguin", projectViewModel.isArabic ? "ar" : "en", projectViewModel.authenticatedUserObject.user.patientID.toString(), details: data); + }); + } + } + String getNextActionImage(nextAction) { switch (nextAction) { case 0: @@ -1115,7 +1166,6 @@ class _ToDoState extends State with SingleTickerProviderStateMixin { projectViewModel.analytics.todoList.to_do_list_cancel_payment_details(appo); } }); - projectViewModel.analytics.todoList.to_do_list_pay_now(appo); } @@ -1465,7 +1515,7 @@ class _ToDoState extends State with SingleTickerProviderStateMixin { }).catchError((err) { print(err); GifLoaderDialogUtils.hideDialog(context); - AppToast.showErrorToast(message: err); + AppToast.showErrorToast(message: err.toString()); }); } diff --git a/lib/pages/insurance/insurance_update_screen.dart b/lib/pages/insurance/insurance_update_screen.dart index 191170ef..4c4d5686 100644 --- a/lib/pages/insurance/insurance_update_screen.dart +++ b/lib/pages/insurance/insurance_update_screen.dart @@ -167,7 +167,7 @@ class _InsuranceUpdateState extends State with SingleTickerProv Container( margin: EdgeInsets.only(top: 6.5, left: 2.0), child: Text( - model.insuranceUpdate[index].statusDescription!, + model.insuranceUpdate[index].statusDescription ?? "", style: TextStyle( fontSize: 10, fontWeight: FontWeight.w600, diff --git a/lib/pages/landing/fragments/home_page_fragment2.dart b/lib/pages/landing/fragments/home_page_fragment2.dart index c1c922ac..7711b4ff 100644 --- a/lib/pages/landing/fragments/home_page_fragment2.dart +++ b/lib/pages/landing/fragments/home_page_fragment2.dart @@ -52,7 +52,11 @@ class _HomePageFragment2State extends State { hmgServices.add(HmgServices(0, TranslationBase.of(context).book, TranslationBase.of(context).appointmentLabel, "assets/images/new/book appointment.svg", isLogin)); hmgServices.add(HmgServices(1, TranslationBase.of(context).liveCare, TranslationBase.of(context).onlineConsulting, "assets/images/new/Live_Care.svg", isLogin)); - hmgServices.add(HmgServices(2, TranslationBase.of(context).emergencyTitle, TranslationBase.of(context).emergencySubtitle, "assets/images/new/emergency.svg", isLogin)); + + projectViewModel.isIndoorNavigationEnabled + ? hmgServices.add(HmgServices(2, "Hospital", "Navigation", "assets/images/new/indoor_nav_home.svg", isLogin)) + : hmgServices.add(HmgServices(2, TranslationBase.of(context).emergencyTitle, TranslationBase.of(context).emergencySubtitle, "assets/images/new/emergency.svg", isLogin)); + hmgServices.add(HmgServices(3, TranslationBase.of(context).hhcHome, TranslationBase.of(context).healthCare, "assets/images/new/HHC.svg", isLogin)); hmgServices.add(HmgServices(4, TranslationBase.of(context).checkup, TranslationBase.of(context).comprehensive, "assets/images/new/comprehensive_checkup.svg", isLogin)); hmgServices.add(HmgServices(5, TranslationBase.of(context).online, TranslationBase.of(context).payment, "assets/images/new/paymentMethods.png", isLogin)); @@ -296,15 +300,16 @@ class _HomePageFragment2State extends State { child: ServicesView( new HmgServices(23, TranslationBase.of(context).InPatient, TranslationBase.of(context).inPatientServices, "assets/images/new/InPatient.svg", false), 23, - true)), + true, + projectViewModel)), ), ), Expanded( flex: 4, child: AspectRatio( aspectRatio: 1.0, - child: ServicesView( - new HmgServices(5, TranslationBase.of(context).online, TranslationBase.of(context).payment, "assets/images/new/paymentMethods.png", false), 2, true)), + child: ServicesView(new HmgServices(5, TranslationBase.of(context).online, TranslationBase.of(context).payment, "assets/images/new/paymentMethods.png", false), 2, + true, projectViewModel)), ), ], ), @@ -322,7 +327,7 @@ class _HomePageFragment2State extends State { itemCount: hmgServices.length, padding: EdgeInsets.zero, itemBuilder: (BuildContext context, int index) { - return ServicesView(hmgServices[index], index, true); + return ServicesView(hmgServices[index], index, true, projectViewModel); }, ), ), @@ -341,7 +346,7 @@ class _HomePageFragment2State extends State { itemCount: hmgServices.length, padding: EdgeInsets.zero, itemBuilder: (BuildContext context, int index) { - return ServicesView(hmgServices[index], index, true); + return ServicesView(hmgServices[index], index, true, projectViewModel, isLocked: hmgServices[index].action == 2 ? !projectViewModel.havePrivilege(107) : false); }, ), ), @@ -489,8 +494,7 @@ class _HomePageFragment2State extends State { flex: 1, child: InkWell( onTap: () { - if (projectViewModel.havePrivilege(100)) - widget.onPharmacyClick!(); + if (projectViewModel.havePrivilege(100)) widget.onPharmacyClick!(); }, child: Stack(children: [ Container( diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 6fe004fc..05d90571 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -22,7 +22,8 @@ import 'package:diplomaticquarterapp/pages/rateAppointment/rate_appointment_doct import 'package:diplomaticquarterapp/pages/videocall-webrtc-rnd/webrtc/start_video_call.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart'; -import 'package:diplomaticquarterapp/services/family_files/family_files_provider.dart' as family; +import 'package:diplomaticquarterapp/services/family_files/family_files_provider.dart' + as family; import 'package:diplomaticquarterapp/services/livecare_services/livecare_provider.dart'; import 'package:diplomaticquarterapp/services/payfort_services/payfort_view_model.dart'; import 'package:diplomaticquarterapp/services/robo_search/event_provider.dart'; @@ -43,7 +44,7 @@ import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_app_icon_badge/flutter_app_icon_badge.dart'; +// import 'package:flutter_app_icon_badge/flutter_app_icon_badge.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart'; @@ -664,7 +665,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { notificationCount = value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString(); model.setState(model.count, 0, true, notificationCount); sharedPref.setString(NOTIFICATION_COUNT, notificationCount); - FlutterAppIconBadge.updateBadge(int.parse(notificationCount)); + // FlutterAppIconBadge.updateBadge(int.parse(notificationCount)); } }); // if (await AppSharedPreferences().getBool(IS_LAST_APPOINTMENT_RATE_SHOWN) == null || !await AppSharedPreferences().getBool(IS_LAST_APPOINTMENT_RATE_SHOWN)) { diff --git a/lib/pages/landing/widgets/services_view.dart b/lib/pages/landing/widgets/services_view.dart index 5635a4a6..c69f772c 100644 --- a/lib/pages/landing/widgets/services_view.dart +++ b/lib/pages/landing/widgets/services_view.dart @@ -4,7 +4,9 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:diplomaticquarterapp/analytics/google-analytics.dart'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/models/hmg_services.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/%E2%80%8B%20health_calculators.dart'; @@ -31,14 +33,20 @@ import 'package:diplomaticquarterapp/pages/medical/smart_watch_health_data/smart import 'package:diplomaticquarterapp/pages/paymentService/payment_service.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/app-permissions.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/location_util.dart'; +import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/widgets/dialogs/covid_consent_dialog.dart'; +import 'package:diplomaticquarterapp/widgets/dialogs/location_selection_dialog.dart'; +import 'package:diplomaticquarterapp/widgets/dialogs/radio_selection_dialog.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../locator.dart'; @@ -52,8 +60,10 @@ class ServicesView extends StatelessWidget { PharmacyModuleViewModel pharmacyModuleViewModel = locator(); late LocationUtils locationUtils; bool isHomePage; + late ProjectViewModel projectViewModel; + bool isLocked; - ServicesView(this.hmgServices, this.index, this.isHomePage); + ServicesView(this.hmgServices, this.index, this.isHomePage, this.projectViewModel, {this.isLocked = false}); @override Widget build(BuildContext context) { @@ -159,12 +169,57 @@ class ServicesView extends StatelessWidget { ], ), ), + isLocked + ? Container( + width: double.infinity, + height: double.infinity, + decoration: containerRadiusWithGradientServices(20, lightColor: Colors.grey.withOpacity(0.6), darkColor: Colors.grey.withOpacity(0.6)), + child: Icon( + Icons.lock_outline, + size: 40, + ), + ) + : Container() ], ), ), ); } + openNavigationProjectSelection(BuildContext context) { + int _selectedHospitalIndex = 0; + List projectsListLocal = []; + Utils.navigationProjectsList.forEach((v) { + projectsListLocal.add(new HospitalsModel.fromJson(v)); + }); + showDialog( + context: context, + builder: (cxt) => LocationSelectionDialog( + data: projectsListLocal, + selectedIndex: _selectedHospitalIndex, + onValueSelected: (index) { + _selectedHospitalIndex = index; + initPenguinSDK(projectsListLocal[index].iD); + }, + ), + ); + } + + initPenguinSDK(int projectID) async { + final bool permited = await AppPermission.askPenguinPermissions(); + if (!permited) { + Map statuses = await [ + Permission.location, + Permission.bluetooth, + Permission.bluetoothConnect, + Permission.bluetoothScan, + Permission.activityRecognition, + ].request().whenComplete(() { + PenguinMethodChannel.launch("penguin", projectViewModel.isArabic ? "ar" : "en", "1231755"); + }); + } // + } + handleHomePageServices(HmgServices hmgServices, BuildContext context) { if (hmgServices.action == 0) { Navigator.push(context, FadePage(page: Search())); @@ -172,8 +227,13 @@ class ServicesView extends StatelessWidget { } else if (hmgServices.action == 1) { openLiveCare(context); } else if (hmgServices.action == 2) { - Navigator.push(context, FadePage(page: ErOptions(isAppbar: true))); - locator().hmgServices.logServiceName('emergency service'); + // initPenguinSDK(); + if (projectViewModel.isIndoorNavigationEnabled) { + if (!isLocked) openNavigationProjectSelection(context); + } else { + Navigator.push(context, FadePage(page: ErOptions(isAppbar: true))); + locator().hmgServices.logServiceName('emergency service'); + } } else if (hmgServices.action == 3) { Navigator.push(context, FadePage(page: HomeHealthCarePage())); locator().hmgServices.logServiceName('home health care'); @@ -266,10 +326,8 @@ class ServicesView extends StatelessWidget { } else if (hmgServices.action == 21) { Navigator.of(context).push( MaterialPageRoute( - builder: (BuildContext context) => MyWebView( - title: "HMG News", - selectedUrl:"https://twitter.com/hmg" //"https://twitter.com/hashtag/مجموعة_د_سليمان_الحبيب_الطبية?src=hashtag_click&f=live", - ), + builder: (BuildContext context) => MyWebView(title: "HMG News", selectedUrl: "https://twitter.com/hmg" //"https://twitter.com/hashtag/مجموعة_د_سليمان_الحبيب_الطبية?src=hashtag_click&f=live", + ), ), ); locator().hmgServices.logServiceName('latest news'); diff --git a/lib/pages/livecare/video-call-web-page.dart b/lib/pages/livecare/video-call-web-page.dart index 46a29924..f755d1b0 100644 --- a/lib/pages/livecare/video-call-web-page.dart +++ b/lib/pages/livecare/video-call-web-page.dart @@ -14,7 +14,7 @@ class VideoCallWebPage extends StatelessWidget{ final String receiverId; final String callerId; VideoCallWebPage({required this.receiverId, required this.callerId}){ - request = URLRequest(url: Uri.parse("https://vcallapi.hmg.com/Mobileindex.html?username=$receiverId&doctorid=$callerId")); + request = URLRequest(url: WebUri.uri(Uri.parse("https://vcallapi.hmg.com/Mobileindex.html?username=$receiverId&doctorid=$callerId"))); } InAppWebViewGroupOptions options = InAppWebViewGroupOptions( diff --git a/lib/pages/livecare/widgets/clinic_list.dart b/lib/pages/livecare/widgets/clinic_list.dart index 44ad58b0..76d70885 100644 --- a/lib/pages/livecare/widgets/clinic_list.dart +++ b/lib/pages/livecare/widgets/clinic_list.dart @@ -373,15 +373,17 @@ class _clinic_listState extends State { String pharmaLiveCareQRCodeValue = widget.pharmacyLiveCareQRCode; Navigator.push( - context, - FadePage( - page: PaymentMethod( + context, + FadePage( + page: PaymentMethod( onSelectedMethod: (String metohd, [String? selectedInstallmentPlan]) { setState(() {}); }, patientShare: num.parse(getERAppointmentFeesList.total!), isFromAdvancePayment: widget.isPharmacyLiveCare, - ))).then((value) { + ), + ), + ).then((value) { if (value != null) { selectedPaymentMethod = value[0]; print(value); diff --git a/lib/pages/login/confirm-login.dart b/lib/pages/login/confirm-login.dart index 5eed62b2..e4a55d25 100644 --- a/lib/pages/login/confirm-login.dart +++ b/lib/pages/login/confirm-login.dart @@ -393,7 +393,7 @@ class _ConfirmLogin extends State { var availableBiometrics; try { availableBiometrics = await auth.getAvailableBiometrics(); - print(availableBiometrics); + // print(availableBiometrics); } on PlatformException catch (e) { AppToast.showErrorToast(message: e.message!); print(e); @@ -1125,7 +1125,6 @@ class _ConfirmLogin extends State { } bool checkIfBiometricAvailable(BiometricType biometricType) { - print(biometricType); bool isAvailable = false; if (_availableBiometrics != null) { for (var i = 0; i < _availableBiometrics.length; i++) { diff --git a/lib/pages/login/register-info.dart b/lib/pages/login/register-info.dart index cbff3f9b..e3d2f020 100644 --- a/lib/pages/login/register-info.dart +++ b/lib/pages/login/register-info.dart @@ -455,10 +455,10 @@ class _RegisterInfo extends State { this .authService .registerUser(request) - .then((result) => { - GifLoaderDialogUtils.hideDialog(context), + .then((result) async => { if (result is String) { + GifLoaderDialogUtils.hideDialog(context), new ConfirmDialog( context: context, confirmMessage: result, @@ -480,14 +480,14 @@ class _RegisterInfo extends State { sharedPref.remove(FAMILY_FILE), result.list.isFamily = false, - sharedPref.setString(BLOOD_TYPE, result.patientBloodType ?? ""), + await sharedPref.setString(BLOOD_TYPE, result.patientBloodType ?? ""), authenticatedUserObject.user = result.list, projectViewModel.setPrivilege(privilegeList: res), - sharedPref.setObject(MAIN_USER, result.list), - sharedPref.setObject(USER_PROFILE, result.list), + await sharedPref.setObject(MAIN_USER, result.list), + await sharedPref.setObject(USER_PROFILE, result.list), - sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID), - sharedPref.setString(TOKEN, result.authenticationTokenID), + await sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID), + await sharedPref.setString(TOKEN, result.authenticationTokenID), AppToast.showSuccessToast(message: TranslationBase.of(context).successRegister), checkIfUserAgreedBefore(result), projectViewModel.analytics.loginRegistration.registration_confirmation() @@ -695,6 +695,7 @@ class _RegisterInfo extends State { insertIMEI() async { var selectedOption = await sharedPref.getInt(LAST_LOGIN); authService.insertDeviceImei(selectedOption).then((value) => {goToHome()}).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); print(err); }); } @@ -705,45 +706,70 @@ class _RegisterInfo extends State { projectViewModel.isLogin = true; projectViewModel.user = authenticatedUserObject.user; await authenticatedUserObject.getUser(getUser: true); - int languageID = Provider.of(context, listen: false).isArabic ? 1 : 2; - appointmentRateViewModel.getIsLastAppointmentRatedList(languageID).then((value) { - getToDoCount(); - GifLoaderDialogUtils.hideDialog(AppGlobal.context); - if (appointmentRateViewModel.isHaveAppointmentNotRate) { - Navigator.pushAndRemoveUntil( + getToDoCount(); + GifLoaderDialogUtils.hideDialog(AppGlobal.context); + ConfirmDialog dialog = new ConfirmDialog( + context: context, + confirmMessage: TranslationBase.of(context).validInsurance, + okText: TranslationBase.of(context).yes, + cancelText: TranslationBase.of(context).no, + okFunction: () { + ConfirmDialog.closeAlertDialog(context); + Navigator.pushAndRemoveUntil( context, - FadePage( - page: RateAppointmentDoctor(isFromRegistration: true), - ), - (r) => false); - } else { - ConfirmDialog dialog = new ConfirmDialog( - context: context, - confirmMessage: TranslationBase.of(context).validInsurance, - okText: TranslationBase.of(context).yes, - cancelText: TranslationBase.of(context).no, - okFunction: () { - ConfirmDialog.closeAlertDialog(context); - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute(builder: (context) => LandingPage()), + MaterialPageRoute(builder: (context) => LandingPage()), (Route route) => false, - ); - Navigator.push(context, FadePage(page: InsuranceUpdate())); - }, - cancelFunction: () { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute(builder: (context) => LandingPage()), - (Route route) => false, - ); - }); - dialog.showAlertDialog(context); - } - }).catchError((err) { - print(err); - //GifLoaderDialogUtils.hideDialog(context); - }); + ); + Navigator.push(context, FadePage(page: InsuranceUpdate())); + }, + cancelFunction: () { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => LandingPage()), + (Route route) => false, + ); + }); + dialog.showAlertDialog(context); + + // int languageID = Provider.of(context, listen: false).isArabic ? 1 : 2; + // appointmentRateViewModel.getIsLastAppointmentRatedList(languageID).then((value) { + // getToDoCount(); + // GifLoaderDialogUtils.hideDialog(AppGlobal.context); + // if (appointmentRateViewModel.isHaveAppointmentNotRate) { + // Navigator.pushAndRemoveUntil( + // context, + // FadePage( + // page: RateAppointmentDoctor(isFromRegistration: true), + // ), + // (r) => false); + // } else { + // ConfirmDialog dialog = new ConfirmDialog( + // context: context, + // confirmMessage: TranslationBase.of(context).validInsurance, + // okText: TranslationBase.of(context).yes, + // cancelText: TranslationBase.of(context).no, + // okFunction: () { + // ConfirmDialog.closeAlertDialog(context); + // Navigator.pushAndRemoveUntil( + // context, + // MaterialPageRoute(builder: (context) => LandingPage()), + // (Route route) => false, + // ); + // Navigator.push(context, FadePage(page: InsuranceUpdate())); + // }, + // cancelFunction: () { + // Navigator.pushAndRemoveUntil( + // context, + // MaterialPageRoute(builder: (context) => LandingPage()), + // (Route route) => false, + // ); + // }); + // dialog.showAlertDialog(context); + // } + // }).catchError((err) { + // print(err); + // //GifLoaderDialogUtils.hideDialog(context); + // }); // SMSOTP.showLoadingDialog(context, false), } diff --git a/lib/pages/login/register.dart b/lib/pages/login/register.dart index a010150d..2dd32163 100644 --- a/lib/pages/login/register.dart +++ b/lib/pages/login/register.dart @@ -2,6 +2,7 @@ import 'package:diplomaticquarterapp/analytics/flows/login_registration.dart'; import 'package:diplomaticquarterapp/analytics/google-analytics.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/models/Authentication/check_user_status_reponse.dart'; import 'package:diplomaticquarterapp/models/Authentication/check_user_status_req.dart'; @@ -25,6 +26,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart'; import 'package:intl/intl.dart' as intl; +import 'package:provider/provider.dart'; class Register extends StatefulWidget { final Function? changePageViewIndex; @@ -297,8 +299,9 @@ class _Register extends State { } checkPatientForRegisteration(request) { + int languageID = Provider.of(context, listen: false).isArabic ? 1 : 2; GifLoaderDialogUtils.showMyDialog(context); - this.authService.checkPatientForRegisteration(request).then((response) => {checkUserStatus(response, request)}).catchError((err) { + this.authService.checkPatientForRegisteration(request, languageID).then((response) => {checkUserStatus(response, request)}).catchError((err) { GifLoaderDialogUtils.hideDialog(context); ConfirmDialog dialog = new ConfirmDialog( context: context, diff --git a/lib/pages/medical/smart_watch_health_data/syncHealthData.dart b/lib/pages/medical/smart_watch_health_data/syncHealthData.dart index e6ec5c9a..6d6fdf4f 100644 --- a/lib/pages/medical/smart_watch_health_data/syncHealthData.dart +++ b/lib/pages/medical/smart_watch_health_data/syncHealthData.dart @@ -34,7 +34,7 @@ class _syncHealthDataButtonState extends State { int MedCategoryID = 0; - HealthFactory health = HealthFactory(); + // HealthFactory health = HealthFactory(); List types = [HealthDataType.STEPS, HealthDataType.HEART_RATE, Platform.isAndroid ? HealthDataType.DISTANCE_DELTA : HealthDataType.DISTANCE_WALKING_RUNNING]; @override @@ -48,29 +48,29 @@ class _syncHealthDataButtonState extends State { } checkPermissions() async { - if (Platform.isAndroid) { - if (await PermissionService.isHealthDataPermissionEnabled()) { - await health.requestAuthorization(types).then((value) { - if (value) { - readAll(); - } - }); - } else { - Utils.showPermissionConsentDialog(context, TranslationBase.of(context).physicalActivityPermission, () async { - await health.requestAuthorization(types).then((value) { - if (value) { - readAll(); - } - }); - }); - } - } else { - await health.requestAuthorization(types).then((value) { - if (value) { - readAll(); - } - }); - } + // if (Platform.isAndroid) { + // if (await PermissionService.isHealthDataPermissionEnabled()) { + // await health.requestAuthorization(types).then((value) { + // if (value) { + // readAll(); + // } + // }); + // } else { + // Utils.showPermissionConsentDialog(context, TranslationBase.of(context).physicalActivityPermission, () async { + // await health.requestAuthorization(types).then((value) { + // if (value) { + // readAll(); + // } + // }); + // }); + // } + // } else { + // await health.requestAuthorization(types).then((value) { + // if (value) { + // readAll(); + // } + // }); + // } } void readAll() async { @@ -83,13 +83,13 @@ class _syncHealthDataButtonState extends State { DateTime startDate = DateTime.now().subtract(new Duration(days: 30)); try { - List healthData = await health.getHealthDataFromTypes(startDate, DateTime.now(), types); - _healthDataList.addAll(healthData); + // List healthData = await health.getHealthDataFromTypes(startDate, DateTime.now(), types); + // _healthDataList.addAll(healthData); } catch (e) { print("Caught exception in getHealthDataFromTypes: $e"); } - _healthDataList = HealthFactory.removeDuplicates(_healthDataList); + // _healthDataList = HealthFactory.removeDuplicates(_healthDataList); _healthDataList.forEach((x) { if (x.type == HealthDataType.STEPS) { diff --git a/lib/services/appointment_services/GetDoctorsList.dart b/lib/services/appointment_services/GetDoctorsList.dart index 98d49db1..2d75be28 100644 --- a/lib/services/appointment_services/GetDoctorsList.dart +++ b/lib/services/appointment_services/GetDoctorsList.dart @@ -334,6 +334,58 @@ class DoctorsListService extends BaseService { return Future.value(localRes); } + Future insertWalkInAppointment(int docID, int clinicID, int projectID, String selectedTime, String selectedDate, int initialSlotDuration, int languageID, BuildContext context) async { + Map request; + + if (await this.sharedPref.getObject(USER_PROFILE) != null) { + var data = AuthenticatedUser.fromJson(await this.sharedPref.getObject(USER_PROFILE)); + authUser = data; + } + + Request req = appGlobal.getPublicRequest(); + request = { + "IsForLiveCare": false, + "ProjectID": projectID, + "ClinicID": clinicID, + "DoctorID": docID, + "StartTime": selectedTime, + "SelectedTime": selectedTime, + "EndTime": selectedTime, + "InitialSlotDuration": initialSlotDuration, + "StrAppointmentDate": selectedDate, + "IsVirtual": false, + "DeviceType": Platform.isIOS ? 'iOS' : 'Android', + "BookedBy": 102, + "VisitType": 1, + "VisitFor": 1, + "GenderID": authUser.gender, + "Age": authUser.age != null ? authUser.age : 0, + "VersionID": req.VersionID, + "Channel": req.Channel, + "IPAdress": req.IPAdress, + "generalid": req.generalid, + "PatientOutSA": authUser.outSA, + "SessionID": "YckwoXhUmWBsnHKEKig", + "isDentalAllowedBackend": false, + "DeviceTypeID": req.DeviceTypeID, + "PatientID": authUser.patientID, + "PatientTypeID": authUser.patientType, + "PatientType": authUser.patientType + }; + + dynamic localRes; + try { + await baseAppClient.post(INSERT_WALKIN_APPOINTMENT, onSuccess: (response, statusCode) async { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: request); + return Future.value(localRes); + } catch (e) { + return Future.error(e); + } + } + Future insertAppointment(int docID, int clinicID, int projectID, String selectedTime, String selectedDate, int initialSlotDuration, int languageID, BuildContext context, [String? procedureID, num? testTypeEnum, num? testProcedureEnum, ProjectViewModel? projectViewModel, int? invoiceNumber, int? lineItemNo]) async { Map request; @@ -638,6 +690,32 @@ class DoctorsListService extends BaseService { return Future.value(localRes); } + Future getPatientShareForWalkInAppointment(int clinicID, int projectID, int doctorID) async { + Map request; + request = {"ProjectID": projectID, "ClinicID": clinicID, "DoctorID": doctorID}; + dynamic localRes; + await baseAppClient.post(GET_PATIENT_SHARE_FOR_WALKIN_APPOINTMENT, onSuccess: (response, statusCode) async { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: request); + + return Future.value(localRes); + } + + Future canPayForWalkInAppointment(int clinicID, int projectID, int doctorID) async { + Map request; + request = {"ProjectID": projectID, "ClinicID": clinicID, "DoctorID": doctorID, "StartTime": "12:00", "EndTime": "12:00"}; + dynamic localRes; + await baseAppClient.post(CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT, onSuccess: (response, statusCode) async { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: request); + + return Future.value(localRes); + } + Future getPatientAppointmentHistory(bool isActiveAppointment, int languageID, BuildContext context, {bool isForCOC = false, isForUpcomming = false, IsForArrived = false}) async { Map request; @@ -1571,6 +1649,19 @@ class DoctorsListService extends BaseService { return Future.value(localRes); } + Future checkScannedNFCAndQRCode(String nfcCode, int projectId) async { + Map request; + + request = {"NFC_Code": nfcCode, "ProjectID": projectId}; + dynamic localRes; + await baseAppClient.post(CHECK_SCANNED_NFC_QR_CODE, onSuccess: (response, statusCode) async { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: request); + return Future.value(localRes); + } + Future checkIfHasDentalPlan(int projectID, BuildContext context) async { Map request; diff --git a/lib/services/authentication/auth_provider.dart b/lib/services/authentication/auth_provider.dart index 1a61ecca..4f4e6a1d 100644 --- a/lib/services/authentication/auth_provider.dart +++ b/lib/services/authentication/auth_provider.dart @@ -339,12 +339,12 @@ class AuthProvider with ChangeNotifier { return authenticatedUser; } - Future checkPatientForRegisteration(CheckPatientForRegistration request) async { + Future checkPatientForRegisteration(CheckPatientForRegistration request, int languageID) async { request.versionID = VERSION_ID; request.channel = CHANNEL; request.iPAdress = IP_ADDRESS; request.generalid = GENERAL_ID; - request.languageID = (languageID == 'ar' ? 1 : 2); + request.languageID = languageID; request.deviceTypeID = Platform.isIOS ? 1 : 2; request.isRegister = false; // request.tokenID = ''; @@ -410,6 +410,1282 @@ class AuthProvider with ChangeNotifier { dynamic localRes; try { + // localRes = { + // "Date": null, + // "LanguageID": 0, + // "ServiceName": 0, + // "Time": null, + // "AndroidLink": null, + // "AuthenticationTokenID": "d+TXwG6BFkSjRuFPvTdSwA==", + // "Data": null, + // "Dataw": false, + // "DietType": 0, + // "DietTypeID": 0, + // "ErrorCode": null, + // "ErrorEndUserMessage": "Patient verified Successfully", + // "ErrorEndUserMessageN": null, + // "ErrorMessage": null, + // "ErrorStatusCode": 0, + // "ErrorType": 0, + // "FoodCategory": 0, + // "IOSLink": null, + // "IsAuthenticated": true, + // "MealOrderStatus": 0, + // "MealType": 0, + // "MessageStatus": 1, + // "NumberOfResultRecords": 0, + // "PatientBlodType": null, + // "SuccessMsg": null, + // "SuccessMsgN": null, + // "VidaUpdatedResponse": null, + // "DoctorInformation_List": null, + // "GetAllPendingRecordsList": null, + // "GetAllSharedRecordsByStatusList": null, + // "GetResponseFileList": null, + // "IsHMGPatient": false, + // "IsLoginSuccessfully": false, + // "IsNeedUpdateIdintificationNo": false, + // "IsPatientAuthorized": false, + // "IsVidaPlus": false, + // "KioskSendSMS": false, + // "List": [ + // { + // "SetupID": "010266", + // "PatientType": 1, + // "PatientID": 5318335, + // "FirstName": "SYED TAHA", + // "MiddleName": "ALAM", + // "LastName": "ALAM", + // "FirstNameN": "سيد طه", + // "MiddleNameN": "علام", + // "LastNameN": "علام", + // "RelationshipID": 0, + // "Gender": 1, + // "DateofBirth": "/Date(839106000000+0300)/", + // "DateofBirthN": null, + // "NationalityID": "PAK", + // "PhoneResi": " ", + // "PhoneOffice": " ", + // "MobileNumber": "0560960398", + // "FaxNumber": " ", + // "EmailAddress": "testtaha@gmail.com", + // "BloodGroup": null, + // "RHFactor": null, + // "IsEmailAlertRequired": false, + // "IsSMSAlertRequired": true, + // "PreferredLanguage": "1", + // "IsPrivilegedMember": false, + // "MemberID": null, + // "ExpiryDate": null, + // "IsHmgEmployee": null, + // "EmployeeID": null, + // "EmergencyContactName": "", + // "EmergencyContactNo": "", + // "PatientPayType": 0, + // "DHCCPatientRefID": null, + // "IsPatientDummy": false, + // "Status": 2, + // "IsStatusCleared": null, + // "PatientIdentificationType": 2, + // "PatientIdentificationNo": "2579628724", + // "ProjectID": 15, + // "InfoSourceID": 0, + // "Address": "", + // "Age": 28, + // "AgeDesc": "28 Yr", + // "AreaID": 0, + // "CRSVerificationStatus": 2, + // "CRSVerificationStatusDesc": "verified", + // "CRSVerificationStatusDescN": "تم التوثيق", + // "CreatedBy": 0, + // "GenderDescription": "Male", + // "HealthIDFromNHICViaVida": "2bcc1b1a-96b7-4f33-86e2-fa955d0e3764", + // "IR": null, + // "ISOCityID": null, + // "ISOCountryID": null, + // "IsVerfiedFromNHIC": true, + // "ListPrivilege": [ + // { + // "ID": 1, + // "ServiceName": "Notifications", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 2, + // "ServiceName": "Family Files", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 3, + // "ServiceName": "Settings", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 4, + // "ServiceName": "My Profile", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 5, + // "ServiceName": "My Appointment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 6, + // "ServiceName": "My Doctors", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 7, + // "ServiceName": "Radiology", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 8, + // "ServiceName": "Radiology Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 9, + // "ServiceName": "Radiology View Image", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 10, + // "ServiceName": "Lab Results", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 11, + // "ServiceName": "Lab Results Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 12, + // "ServiceName": "Precriptions", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 13, + // "ServiceName": "Precriptions Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 14, + // "ServiceName": "Eye Measurments", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 15, + // "ServiceName": "Eye Measurments Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 16, + // "ServiceName": "Sick Leaves", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 17, + // "ServiceName": "Sick Leaves Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 18, + // "ServiceName": "Approvals", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 19, + // "ServiceName": "Monthly Reports", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 20, + // "ServiceName": "Request Medical Report", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 21, + // "ServiceName": "Request Medical Report Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 22, + // "ServiceName": "Insurance Cards", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 23, + // "ServiceName": "Allergies", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 24, + // "ServiceName": "My Trackers", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 25, + // "ServiceName": "Vital Signs", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 26, + // "ServiceName": "My Vaccines", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 27, + // "ServiceName": "My Vaccines Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 28, + // "ServiceName": "Ask Doctors", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 29, + // "ServiceName": "Live Chat", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 30, + // "ServiceName": "Health Data", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 31, + // "ServiceName": "Online Check-in", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 32, + // "ServiceName": "Connect to internet", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 33, + // "ServiceName": "Advance Payment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 34, + // "ServiceName": "Book Appointment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 35, + // "ServiceName": "Child Vaccines", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 36, + // "ServiceName": "Blood Donation", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 38, + // "ServiceName": "H2O", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 40, + // "ServiceName": "ChatBot", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 41, + // "ServiceName": "Parking", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 42, + // "ServiceName": "SymptomChecker", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 47, + // "ServiceName": "AdvanceBalance", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 48, + // "ServiceName": "ActiveMedications", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 49, + // "ServiceName": "VaccineAvailability", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 51, + // "ServiceName": "UpcomingAppointment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 52, + // "ServiceName": "PushNotificationCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 53, + // "ServiceName": "ActiveMedicationCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 54, + // "ServiceName": "LabOrderUnreadCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 55, + // "ServiceName": "RadOrderUnreadCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 56, + // "ServiceName": "MedicalReportUnreadCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 57, + // "ServiceName": "ERWaittingTimeShowing", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 58, + // "ServiceName": "OnlinePayment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 59, + // "ServiceName": "RadiologyDisplayImage", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 60, + // "ServiceName": "EmergencyConsultation", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 61, + // "ServiceName": "PatientQueueCall", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 62, + // "ServiceName": "OnlinePrescriptionOrder", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 63, + // "ServiceName": "Transportations", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 64, + // "ServiceName": "HomeHealthCareService", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 65, + // "ServiceName": "Al-HabibPharmacyOnline", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 66, + // "ServiceName": "Al-HabibOffers", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 67, + // "ServiceName": "ComprehensiveMedicalCheckup", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 68, + // "ServiceName": "RRT", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 72, + // "ServiceName": "CancelLiveCareRequest", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 74, + // "ServiceName": "Exacart", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 76, + // "ServiceName": "Covid19-CarThrow", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 77, + // "ServiceName": "VoiceBot", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 78, + // "ServiceName": "LiveCareBookOnDoctorSchedule", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 79, + // "ServiceName": "CheckIn_QR", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 80, + // "ServiceName": "CheckIn_NFC", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 81, + // "ServiceName": "ED", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 82, + // "ServiceName": "Packages_&_Offers", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 83, + // "ServiceName": "Lakum_Points", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 84, + // "ServiceName": "QR_Reader", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 85, + // "ServiceName": "AncillaryOrders", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 86, + // "ServiceName": "Payment-MADA", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 87, + // "ServiceName": "Payment-VISA", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 88, + // "ServiceName": "Payment-MasterCard", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 89, + // "ServiceName": "Payment-ApplePay", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 90, + // "ServiceName": "Payment-Tamara", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 91, + // "ServiceName": "Payment-Installment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 92, + // "ServiceName": "ED-Checkin", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 93, + // "ServiceName": "NetworkDebug", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 94, + // "ServiceName": "TamaraAncillary", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 95, + // "ServiceName": "Verif-Face", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 96, + // "ServiceName": "Verif-Finger", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 97, + // "ServiceName": "Verif-SMS", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 98, + // "ServiceName": "Verif-WhatsApp", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 99, + // "ServiceName": "PharmacyLivecare", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 100, + // "ServiceName": "ePharmacy", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 102, + // "ServiceName": "CheckIn_Geofence", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 103, + // "ServiceName": "Payment-ApplePay-Web", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 104, + // "ServiceName": "Livecare_Zoom", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 105, + // "ServiceName": "Dental Virtual Tour", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 106, + // "ServiceName": "Dental Medical Instructions", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 107, + // "ServiceName": "Navigation Service", + // "Previlege": false, + // "Region": null + // } + // ], + // "Marital": null, + // "OutSA": 0, + // "POBox": "", + // "ReceiveHealthSummaryReport": false, + // "SourceType": 0, + // "StrDateofBirth": null, + // "TempAddress": "", + // "ZipCode": "", + // "eHealthIDField": null, + // "patientPayType": null, + // "patientType": null, + // "status": null + // } + // ], + // "List_AskHabibMobileLoginInfo": null, + // "List_AskHabibPatientFile": null, + // "List_FamilyRelationships": null, + // "List_MergeFiles": null, + // "List_MobileLoginInfo": null, + // "List_PatientCount": null, + // "LogInTokenID": null, + // "MohemmPrivilege_List": null, + // "PateintID": 5318335, + // "PatientBloodType": "", + // "PatientER_AdminDriverFileList": null, + // "PatientER_AdminFile": null, + // "PatientER_DriverFile": null, + // "PatientER_DriverFileList": null, + // "PatientHasFile": false, + // "PatientMergedIDs": null, + // "PatientOutSA": false, + // "PatientShareRequestID": 0, + // "PatientType": 0, + // "ProjectIDOut": 0, + // "ReturnMessage": null, + // "SMSLoginRequired": false, + // "ServicePrivilege_List": [ + // { + // "ID": 1, + // "ServiceName": "Notifications", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 2, + // "ServiceName": "Family Files", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 3, + // "ServiceName": "Settings", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 4, + // "ServiceName": "My Profile", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 5, + // "ServiceName": "My Appointment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 6, + // "ServiceName": "My Doctors", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 7, + // "ServiceName": "Radiology", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 8, + // "ServiceName": "Radiology Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 9, + // "ServiceName": "Radiology View Image", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 10, + // "ServiceName": "Lab Results", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 11, + // "ServiceName": "Lab Results Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 12, + // "ServiceName": "Precriptions", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 13, + // "ServiceName": "Precriptions Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 14, + // "ServiceName": "Eye Measurments", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 15, + // "ServiceName": "Eye Measurments Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 16, + // "ServiceName": "Sick Leaves", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 17, + // "ServiceName": "Sick Leaves Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 18, + // "ServiceName": "Approvals", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 19, + // "ServiceName": "Monthly Reports", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 20, + // "ServiceName": "Request Medical Report", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 21, + // "ServiceName": "Request Medical Report Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 22, + // "ServiceName": "Insurance Cards", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 23, + // "ServiceName": "Allergies", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 24, + // "ServiceName": "My Trackers", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 25, + // "ServiceName": "Vital Signs", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 26, + // "ServiceName": "My Vaccines", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 27, + // "ServiceName": "My Vaccines Email", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 28, + // "ServiceName": "Ask Doctors", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 29, + // "ServiceName": "Live Chat", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 30, + // "ServiceName": "Health Data", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 31, + // "ServiceName": "Online Check-in", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 32, + // "ServiceName": "Connect to internet", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 33, + // "ServiceName": "Advance Payment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 34, + // "ServiceName": "Book Appointment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 35, + // "ServiceName": "Child Vaccines", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 36, + // "ServiceName": "Blood Donation", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 38, + // "ServiceName": "H2O", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 40, + // "ServiceName": "ChatBot", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 41, + // "ServiceName": "Parking", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 42, + // "ServiceName": "SymptomChecker", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 47, + // "ServiceName": "AdvanceBalance", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 48, + // "ServiceName": "ActiveMedications", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 49, + // "ServiceName": "VaccineAvailability", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 51, + // "ServiceName": "UpcomingAppointment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 52, + // "ServiceName": "PushNotificationCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 53, + // "ServiceName": "ActiveMedicationCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 54, + // "ServiceName": "LabOrderUnreadCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 55, + // "ServiceName": "RadOrderUnreadCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 56, + // "ServiceName": "MedicalReportUnreadCount", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 57, + // "ServiceName": "ERWaittingTimeShowing", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 58, + // "ServiceName": "OnlinePayment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 59, + // "ServiceName": "RadiologyDisplayImage", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 60, + // "ServiceName": "EmergencyConsultation", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 61, + // "ServiceName": "PatientQueueCall", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 62, + // "ServiceName": "OnlinePrescriptionOrder", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 63, + // "ServiceName": "Transportations", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 64, + // "ServiceName": "HomeHealthCareService", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 65, + // "ServiceName": "Al-HabibPharmacyOnline", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 66, + // "ServiceName": "Al-HabibOffers", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 67, + // "ServiceName": "ComprehensiveMedicalCheckup", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 68, + // "ServiceName": "RRT", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 72, + // "ServiceName": "CancelLiveCareRequest", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 74, + // "ServiceName": "Exacart", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 76, + // "ServiceName": "Covid19-CarThrow", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 77, + // "ServiceName": "VoiceBot", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 78, + // "ServiceName": "LiveCareBookOnDoctorSchedule", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 79, + // "ServiceName": "CheckIn_QR", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 80, + // "ServiceName": "CheckIn_NFC", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 81, + // "ServiceName": "ED", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 82, + // "ServiceName": "Packages_&_Offers", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 83, + // "ServiceName": "Lakum_Points", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 84, + // "ServiceName": "QR_Reader", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 85, + // "ServiceName": "AncillaryOrders", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 86, + // "ServiceName": "Payment-MADA", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 87, + // "ServiceName": "Payment-VISA", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 88, + // "ServiceName": "Payment-MasterCard", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 89, + // "ServiceName": "Payment-ApplePay", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 90, + // "ServiceName": "Payment-Tamara", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 91, + // "ServiceName": "Payment-Installment", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 92, + // "ServiceName": "ED-Checkin", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 93, + // "ServiceName": "NetworkDebug", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 94, + // "ServiceName": "TamaraAncillary", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 95, + // "ServiceName": "Verif-Face", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 96, + // "ServiceName": "Verif-Finger", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 97, + // "ServiceName": "Verif-SMS", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 98, + // "ServiceName": "Verif-WhatsApp", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 99, + // "ServiceName": "PharmacyLivecare", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 100, + // "ServiceName": "ePharmacy", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 102, + // "ServiceName": "CheckIn_Geofence", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 103, + // "ServiceName": "Payment-ApplePay-Web", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 104, + // "ServiceName": "Livecare_Zoom", + // "Previlege": false, + // "Region": null + // }, + // { + // "ID": 105, + // "ServiceName": "Dental Virtual Tour", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 106, + // "ServiceName": "Dental Medical Instructions", + // "Previlege": true, + // "Region": null + // }, + // { + // "ID": 107, + // "ServiceName": "Navigation Service", + // "Previlege": false, + // "Region": null + // } + // ], + // "SharePatientName": null, + // "UserAccountIsActivated": false, + // "VerificationCode": null, + // "email": null, + // "errorList": null, + // "hasFile": false, + // "isActiveCode": false, + // "isMerged": false, + // "isNeedUserAgreement": false, + // "isSMSSent": false, + // "memberList": null, + // "message": "Patient Registered Successfully", + // "statusCode": 1 + // }; await new BaseAppClient().post(REGISTER_USER, onSuccess: (dynamic response, int statusCode) { localRes = response; }, onFailure: (String error, int statusCode) { @@ -458,7 +1734,7 @@ class AuthProvider with ChangeNotifier { Request req = appGlobal.getPublicRequest(); request = { - "PatientOutSA": zipCode == '+966' ? 0 : 1, + "PatientOutSA": zipCode == '966' ? 0 : 1, "PatientMobileNumber": mobileNo, "SearchType": 2, "ZipCode": zipCode, diff --git a/lib/services/payfort_services/payfort_service.dart b/lib/services/payfort_services/payfort_service.dart index 755ec7b7..64a015cd 100644 --- a/lib/services/payfort_services/payfort_service.dart +++ b/lib/services/payfort_services/payfort_service.dart @@ -54,7 +54,7 @@ class PayfortService extends BaseService { "Pat_Token": result.tokenName, "IsRefund": false, "RemmeberMe": false, - "Reconciliation_Reference": result.reconciliationReference, + // "Reconciliation_Reference": result.reconciliationReference, "LanguageID": 1, "PatientID": patientID }; diff --git a/lib/services/permission/permission_service.dart b/lib/services/permission/permission_service.dart index 641d6444..cc73c303 100644 --- a/lib/services/permission/permission_service.dart +++ b/lib/services/permission/permission_service.dart @@ -3,7 +3,7 @@ import 'package:diplomaticquarterapp/core/service/base_service.dart'; import 'package:flutter/material.dart'; import 'package:localstorage/localstorage.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:vibration/vibration.dart'; +// import 'package:vibration/vibration.dart'; import 'package:geolocator/geolocator.dart' as geo; class PermissionService extends BaseService { @@ -25,10 +25,10 @@ class PermissionService extends BaseService { vibrate(callback, context) async { if (callback == null) return null; if (isVibrationEnabled() == true) { - if (await Vibration.hasVibrator() !=null) { - Vibration.vibrate(duration: 100); - callback(); - } + // if (await Vibration.hasVibrator() !=null) { + // Vibration.vibrate(duration: 100); + // callback(); + // } } else { callback(); } diff --git a/lib/uitl/app-permissions.dart b/lib/uitl/app-permissions.dart index 62fd484a..94697e4f 100644 --- a/lib/uitl/app-permissions.dart +++ b/lib/uitl/app-permissions.dart @@ -7,9 +7,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'PlatformBridge.dart'; -class AppPermission{ - - +class AppPermission { static Future askVideoCallPermission(BuildContext context) async { if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) { return false; @@ -21,6 +19,30 @@ class AppPermission{ return true; } +// + + // Manifest.permission.INTERNET, + // Manifest.permission.ACCESS_FINE_LOCATION, + // Manifest.permission.ACCESS_COARSE_LOCATION, + // Manifest.permission.ACCESS_NETWORK_STATE, + // Manifest.permission.BLUETOOTH, + // Manifest.permission.BLUETOOTH_ADMIN, + // Manifest.permission.BLUETOOTH_SCAN, + // Manifest.permission.BLUETOOTH_CONNECT, + // Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, + // Manifest.permission.ACTIVITY_RECOGNITION + + static Future askPenguinPermissions() async { + if (!(await Permission.location.request().isGranted) || + !(await Permission.bluetooth.request().isGranted) || + !(await Permission.bluetoothScan.request().isGranted) || + !(await Permission.bluetoothConnect.request().isGranted) || + !(await Permission.activityRecognition.request().isGranted)) { + return false; + } + return true; + } + static Future _drawOverAppsMessageDialog(BuildContext context) async { ConfirmDialog dialog = new ConfirmDialog( context: context, @@ -34,4 +56,4 @@ class AppPermission{ cancelFunction: () => {}); dialog.showAlertDialog(context); } -} \ No newline at end of file +} diff --git a/lib/uitl/penguin_method_channel.dart b/lib/uitl/penguin_method_channel.dart new file mode 100644 index 00000000..12421f5e --- /dev/null +++ b/lib/uitl/penguin_method_channel.dart @@ -0,0 +1,98 @@ +import 'package:flutter/services.dart'; + +class PenguinMethodChannel { + static const MethodChannel _channel = MethodChannel('launch_penguin_ui'); + + static Future launch(String storyboardName, String languageCode, String username, {NavigationClinicDetails? details}) async { + try { + await _channel.invokeMethod('launchPenguin', { + "storyboardName": storyboardName, + "baseURL": "https://prod.hmg.nav.penguinin.com", + // "dataURL": "https://hmg.nav.penguinin.com", + // "positionURL": "https://hmg.nav.penguinin.com", + // "dataURL": "https://hmg-v33.local.penguinin.com", + // "positionURL": "https://hmg-v33.local.penguinin.com", + "dataURL": "https://prod.hmg.nav.penguinin.com", + "positionURL": "https://prod.hmg.nav.penguinin.com", + "dataServiceName": "api", + "positionServiceName": "pe", + "clientID": "HMG", + "username": "test", + "isSimulationModeEnabled": false, + "isShowUserName": false, + "isUpdateUserLocationSmoothly": true, + "isEnableReportIssue": true, + "languageCode": languageCode, + "clientKey": "UGVuZ3VpbklOX1Blbk5hdl9QSUY=", + "mapBoxKey": "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg", + // "clinicID": details?.clinicId ?? "", + "clinicID": details?.clinicId ?? "", // 46 ,49, 133 + "patientID": details?.patientId ?? "", + "projectID": details?.projectId ?? "", + }); + } on PlatformException catch (e) { + print("Failed to launch PenguinIn: '${e.message}'."); + } + } + + void setMethodCallHandler(){ + _channel.setMethodCallHandler((MethodCall call) async { + try { + + print(call.method); + + switch (call.method) { + + case PenguinMethodNames.onPenNavInitializationError: + _handleInitializationError(call.arguments); // Handle onPenNavInitializationError errors. + break; + case PenguinMethodNames.onPenNavUIDismiss: + //todo handle pen dismissable + // _handlePenNavUIDismiss(); // Handle UI dismissal event. + break; + case PenguinMethodNames.onReportIssue: + // Handle the report issue event. + _handleInitializationError(call.arguments); + break; + default: + _handleUnknownMethod(call.method); // Handle unknown method calls. + } + } catch (e) { + print("Error handling method call '${call.method}': $e"); + // Optionally, log this error to an external service + } + }); + } + static void _handleUnknownMethod(String method) { + print("Unknown method: $method"); + // Optionally, handle this unknown method case, such as reporting or ignoring it + } + + + static void _handleInitializationError(Map error) { + final type = error['type'] as String?; + final description = error['description'] as String?; + print("Initialization Error: ${type ?? 'Unknown Type'}, ${description ?? 'No Description'}"); + + } + +} +// Define constants for method names +class PenguinMethodNames { + static const String showPenguinUI = 'showPenguinUI'; + static const String openSharedLocation = 'openSharedLocation'; + + // ---- Handler Method + static const String onPenNavSuccess = 'onPenNavSuccess'; // Tested Android,iOS + static const String onPenNavInitializationError = 'onPenNavInitializationError'; // Tested Android,iOS + static const String onPenNavUIDismiss = 'onPenNavUIDismiss'; //Tested Android,iOS + static const String onReportIssue = 'onReportIssue'; // Tested Android,iOS + static const String onLocationOffCampus = 'onLocationOffCampus'; // Tested iOS,Android + static const String navigateToPOI = 'navigateToPOI'; // Tested Android,iOS +} + +class NavigationClinicDetails { + String? clinicId; + String? patientId; + String? projectId; +} diff --git a/lib/uitl/push-notification-handler.dart b/lib/uitl/push-notification-handler.dart index f1c53bbe..5bf073b3 100644 --- a/lib/uitl/push-notification-handler.dart +++ b/lib/uitl/push-notification-handler.dart @@ -15,6 +15,7 @@ import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.dart'; import 'package:diplomaticquarterapp/uitl/LocalNotification.dart'; import 'package:diplomaticquarterapp/uitl/app-permissions.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; +import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart' as fir; @@ -388,9 +389,16 @@ class PushNotificationHandler { if (remoteMessage.data.isEmpty) { return; } + debugPrint('the value of the remote message is ${remoteMessage.data}'); if (remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) { _incomingCall(remoteMessage.data); // showCallkitIncoming(remoteMessage.data); + }if(remoteMessage.data['is_navigation'] == 'true' || remoteMessage.data['is_navigation'] == true ){ + NavigationClinicDetails data = NavigationClinicDetails(); + data.clinicId = remoteMessage.data['clinic_Id']; + data.patientId = remoteMessage.data['patient_Id']; + data.projectId = remoteMessage.data['project_Id']; + initPenguinSDK(data); } else { GetNotificationsResponseModel notification = new GetNotificationsResponseModel(); @@ -408,6 +416,21 @@ class PushNotificationHandler { } } + initPenguinSDK(NavigationClinicDetails data) async { + final bool permited = await AppPermission.askPenguinPermissions(); + if (!permited) { + Map statuses = await [ + Permission.location, + Permission.bluetooth, + Permission.bluetoothConnect, + Permission.bluetoothScan, + Permission.activityRecognition, + ].request().whenComplete(() { + PenguinMethodChannel.launch("penguin", "en", "1231755", details: data); + }); + } + } + onToken(String token) async { // print("Push Notification Token: " + token); await AppSharedPreferences().setString(PUSH_TOKEN, token); diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index d9e61698..ad3cc15c 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -2963,7 +2963,18 @@ class TranslationBase { String get selectHospitalBloodDonation => localizedValues["selectHospitalBloodDonation"][locale.languageCode]; String get wecare => localizedValues["wecare"][locale.languageCode]; String get myinstructions => localizedValues["myinstructions"][locale.languageCode]; + String get clinicLocation => localizedValues["clinicLocation"][locale.languageCode]; + String get waitingAppointment => localizedValues["waitingAppointment"][locale.languageCode]; + String get whatWaitingAppointment => localizedValues["whatWaitingAppointment"][locale.languageCode]; + String get waitingAppointmentText1 => localizedValues["waitingAppointmentText1"][locale.languageCode]; + String get waitingAppointmentText2 => localizedValues["waitingAppointmentText2"][locale.languageCode]; + String get waitingAppointmentText3 => localizedValues["waitingAppointmentText3"][locale.languageCode]; + String get waitingAppointmentVerificationMethod => localizedValues["waitingAppointmentVerificationMethod"][locale.languageCode]; + String get howToUseVerificationMethod => localizedValues["howToUseVerificationMethod"][locale.languageCode]; + String get addToWaitingList => localizedValues["addToWaitingList"][locale.languageCode]; String get searchClinic => localizedValues["searchClinic"][locale.languageCode]; + String get selectBranch => localizedValues["selectBranch"][locale.languageCode]; + String get searchByBranch => localizedValues["searchByBranch"][locale.languageCode]; String get existingPackage => localizedValues["existingPackage"][locale.languageCode]; String get continueOrbookNew => localizedValues["continueOrbookNew"][locale.languageCode]; diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index d923dfed..01779851 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -65,6 +65,30 @@ AppSharedPreferences sharedPref = new AppSharedPreferences(); class Utils { // static ProgressDialog pr; + static var navigationProjectsList = [ + { + "Desciption": "Sahafa Hospital", + "DesciptionN": null, + "ID": 130, + "LegalName": "Sahafa Hospital", + "LegalNameN": "مستشفى الصحافة", + "Name": "Sahafa Hospital", + "NameN": null, + "PhoneNumber": "+966115222222", + "SetupID": "013311", + "DistanceInKilometers": 0, + "HasVida3": false, + "IsActive": true, + "IsHmg": true, + "IsVidaPlus": false, + "Latitude": "24.8113774", + "Longitude": "46.6239813", + "MainProjectID": 130, + "ProjectOutSA": false, + "UsingInDoctorApp": false + } + ]; + ///show custom Error Toast /// [message] to show for user static showErrorToast([String? message]) { @@ -909,7 +933,7 @@ class Utils { return projectDetailListModel; } - //static String generateSignature() {} +//static String generateSignature() {} } Widget applyShadow({Color color = Colors.grey, double shadowOpacity = 0.5, double spreadRadius = 2, double blurRadius = 7, Offset offset = const Offset(2, 2), required Widget child}) { diff --git a/lib/widgets/dialogs/location_selection_dialog.dart b/lib/widgets/dialogs/location_selection_dialog.dart new file mode 100644 index 00000000..9181615f --- /dev/null +++ b/lib/widgets/dialogs/location_selection_dialog.dart @@ -0,0 +1,290 @@ +import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/medical/radiology_view_model.dart'; +import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:flutter/material.dart'; + +import '../../uitl/translations_delegate_base.dart'; + +class LocationSelectionDialog extends StatelessWidget { + final List data; + final Function(int)? onValueSelected; + final int? selectedIndex; + + const LocationSelectionDialog( + {super.key, + required this.data, + this.onValueSelected, + this.selectedIndex}); + + @override + Widget build(BuildContext context) { + return Dialog( + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + child: LocationDialogBody( + data: data, + onValueSelected: onValueSelected, + selectedIndex: selectedIndex, + )); + } +} + +class LocationDialogBody extends StatefulWidget { + final List data; + final Function(int)? onValueSelected; + final int? selectedIndex; + + const LocationDialogBody( + {super.key, + required this.data, + this.onValueSelected, + this.selectedIndex}); + + @override + State createState() => _LocationDialogBodyState(); +} + +class _LocationDialogBodyState extends State { + bool isListVisible = false; + int currentlySelected = -1; + + @override + Widget build(BuildContext context) { + return isListVisible + ? LocationListExpandedBody( + data: widget.data, + onItemClick: (data) { + if (data.isEmpty) return; + var selected = widget.data.indexWhere( + (item) => item.name == data, + ); + + if (selected == -1) return; + setState(() { + currentlySelected = selected; + isListVisible = false; + }); + }, + ) + : LocationListWrapBody( + onConfirmClicked: () { + widget.onValueSelected?.call(currentlySelected); + }, + onTextBoxClicked: () { + setState(() { + isListVisible = true; + }); + }, + selectedText: currentlySelected == -1 + ? "" + : widget.data[currentlySelected].name ?? ""); + } +} + +class LocationListExpandedBody extends StatefulWidget { + final List data; + final Function(String) onItemClick; + + const LocationListExpandedBody( + {super.key, required this.data, required this.onItemClick}); + + @override + State createState() => + _LocationListExpandedBodyState(); +} + +class _LocationListExpandedBodyState extends State { + List tempListData = []; + TextEditingController controller = new TextEditingController(); + + @override + void initState() { + super.initState(); + setState(() { + tempListData.addAll(widget.data); + }); + } + + @override + Widget build(BuildContext context) { + return Container( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SelectBranchHeader(), + SizedBox(height: 8,), + TextField( + controller: controller, + onChanged: (v) { + tempListData.clear(); + if (v.length > 0) { + for (int i = 0; i < widget.data.length; i++) { + if (widget.data[i].name + ?.toLowerCase() + .contains(v.toLowerCase()) == + true) { + tempListData.add(widget.data[i]); + } + } + } else { + tempListData.addAll(widget.data); + } + setState(() {}); + }, + decoration: InputDecoration( + hintStyle: TextStyle(fontSize: 12), + hintText: TranslationBase.of(context).searchByBranch, + suffixIcon: Icon(Icons.search), + contentPadding: EdgeInsets.symmetric(vertical: 9,horizontal: 14), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: Colors.grey, // Normal border color + width: 1.0, + ), + ), + ), + ), + SizedBox( + height: 16, + ), + ListView.builder( + itemCount: tempListData.length, + shrinkWrap: true, + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.only(bottom: 8), + child: SizedBox( + height: 24, + child: InkWell( + onTap: () { + widget + .onItemClick(tempListData[index].name ?? ""); + }, + child: Text( + "${tempListData[index].name ?? ""} ( ${tempListData[index].distanceInKilometers} km )", + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Colors.black, + letterSpacing: -0.96), + ), + ), + ), + ); + }) + ], + ), + ), + ); + } +} + +class LocationListWrapBody extends StatelessWidget { + final VoidCallback? onConfirmClicked; + final VoidCallback? onTextBoxClicked; + final String selectedText; + + const LocationListWrapBody( + {super.key, + this.onConfirmClicked, + this.onTextBoxClicked, + required this.selectedText}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SelectBranchHeader(), + SizedBox( + height: 24, + ), + ListTile( + onTap: () { + onTextBoxClicked?.call(); + }, + title: Text( + TranslationBase.of(context).selectBranch, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Colors.black, + letterSpacing: -0.96), + ), + subtitle: selectedText.isEmpty + ? null + : Text( + selectedText, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.black, + letterSpacing: -0.96), + ), + trailing: Icon( + Icons.arrow_drop_down_outlined, + color: Colors.black, + ), + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 1), + borderRadius: BorderRadius.circular(8), + ), + ), + SizedBox( + height: 24, + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: DefaultButton( + TranslationBase.of(context).confirm, + () { + Navigator.pop(context); + onConfirmClicked?.call(); + }, + color: CustomColors.accentColor, + ), + ), + ], + ), + ], + ), + ); + } +} + +class SelectBranchHeader extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + TranslationBase.of(context).selectBranch, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w600, + color: Colors.black, + letterSpacing: -0.96), + ), + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Icon(Icons.close), + )) + ], + ); + } +} diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index 0db27626..f82047a5 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -171,7 +171,7 @@ class _AppDrawerState extends State { // ), mHeight(20.0), (user != null && projectProvider!.isLogin) - ? Image.network("https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${user!.patientID.toString()}", fit: BoxFit.fill, height: 73.5, width: 73.5) + ? Image.network("https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${user!.patientID.toString()}", fit: BoxFit.fill, height: 70, width: 70) : Container(), ], ), @@ -719,7 +719,7 @@ class _AppDrawerState extends State { // result.list.cRSVerificationStatus = result['CRSVerificationStatus']; await this.sharedPref.setString(APP_LANGUAGE, currentLang); await this.sharedPref.setString(BLOOD_TYPE, bloodType); - await this.sharedPref.setInt(LAST_LOGIN, loginType ?? 1 ); + await this.sharedPref.setInt(LAST_LOGIN, loginType ?? 1); await this.sharedPref.setObject(MAIN_USER, mainUser); await this.sharedPref.setObject(USER_PROFILE, result.list); await this.sharedPref.setObject(FAMILY_FILE, familyFile); diff --git a/lib/widgets/in_app_browser/InAppBrowser.dart b/lib/widgets/in_app_browser/InAppBrowser.dart index 4700d068..6f61ac8a 100644 --- a/lib/widgets/in_app_browser/InAppBrowser.dart +++ b/lib/widgets/in_app_browser/InAppBrowser.dart @@ -138,7 +138,7 @@ class MyInAppBrowser extends InAppBrowser { openPackagesPaymentBrowser({required int customer_id, required int order_id}) { paymentType = _PAYMENT_TYPE.PACKAGES; var full_url = '$PACKAGES_REQUEST_PAYMENT_URL?customer_id=$customer_id&order_id=$order_id'; - this.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(full_url)), options: _InAppBrowserOptions); + this.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(full_url))), options: _InAppBrowserOptions); } openPaymentBrowser(num amount, String orderDesc, String transactionID, String projId, String emailId, String paymentMethod, dynamic patientType, String patientName, dynamic patientID, @@ -190,7 +190,7 @@ class MyInAppBrowser extends InAppBrowser { String url = "https://hmgwebservices.com/HMGApplePayLive/applepay/pay?apq=" + res['result']; // Prod // String url = "https://uat.hmgwebservices.com/HMGApplePayLive/applepay/pay?apq=" + res['result']; // UAT // safariBrowser.open(url: Uri.parse(url)); - this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(url)), options: _InAppBrowserOptions); + this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(url))), options: _InAppBrowserOptions); }).catchError((err) { print(err); if (context != null) GifLoaderDialogUtils.hideDialog(context); @@ -233,7 +233,7 @@ class MyInAppBrowser extends InAppBrowser { appoNo, clinicID, doctorID, "", installments) .then((value) { paymentType = _PAYMENT_TYPE.PATIENT; - this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(value)), options: _InAppBrowserOptions); + this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(value))), options: _InAppBrowserOptions); }); }).catchError((err) { print(err); @@ -245,7 +245,7 @@ class MyInAppBrowser extends InAppBrowser { clinicID, doctorID) .then((value) { paymentType = _PAYMENT_TYPE.PATIENT; - this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(value)), options: _InAppBrowserOptions); + this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(value))), options: _InAppBrowserOptions); }); } } @@ -258,16 +258,16 @@ class MyInAppBrowser extends InAppBrowser { // getPatientData(); generatePharmacyURL(order, amount, orderDesc, transactionID, emailId, paymentMethod, patientName, patientID, authenticatedUser).then((value) { if (order.customValuesXml!.contains("ApplePay")) { - safariBrowser.open(url: Uri.parse(value)); + safariBrowser.open(url: WebUri.uri(Uri.parse(value))); } else { - this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(value)), options: _InAppBrowserOptions); + this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(value))), options: _InAppBrowserOptions); } }); } openBrowser(String url) { this.browser = browser; - this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(url)), options: _InAppBrowserOptions); + this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(url))), options: _InAppBrowserOptions); } Future generateURL(num amount, String orderDesc, String transactionID, String projId, String emailId, String paymentMethod, dynamic patientType, String patientName, dynamic patientID, @@ -343,7 +343,7 @@ class MyInAppBrowser extends InAppBrowser { form = form.replaceFirst('PROJECT_ID_VALUE', projId); form = form.replaceFirst('PAYMENT_OPTION_VALUE', paymentMethod); form = form.replaceFirst('LANG_VALUE', currentLanguageID); - form = form.replaceFirst('SERVICE_URL_VALUE', "https://mdlaboratories.com/tamaralive/Home/Checkout"); + form = form.replaceFirst('SERVICE_URL_VALUE', "https://mdlaboratories.com/tamara/Home/Checkout"); form = form.replaceFirst('INSTALLMENTS_VALUE', installments); form = form.replaceFirst('CUSTNATIONALID_VALUE', authUser.patientIdentificationNo!); @@ -489,7 +489,7 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser { } @override - void onCompletedInitialLoad() { + void onCompletedInitialLoad(bool? didLoadSuccessfully) { print("ChromeSafari browser initial load completed"); onLoadStartCallback!("ApplePay"); } diff --git a/pubspec.yaml b/pubspec.yaml index 151d3e8d..02c894e1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: diplomaticquarterapp description: A new Flutter application. -version: 4.5.063+4050063 +version: 4.5.065+4050065 environment: sdk: ">=3.0.0 <3.13.0" @@ -34,7 +34,8 @@ dependencies: get_it: ^7.2.0 #Google Fit & Apple HealthKit - health: ^3.0.3 +# health: ^3.0.3 + health: ^11.1.0 #chart fl_chart: ^0.64.0 @@ -99,7 +100,7 @@ dependencies: flutter_rating_bar: ^4.0.1 # Calendar -# syncfusion_flutter_calendar: ^23.1.42 + # syncfusion_flutter_calendar: ^23.1.42 syncfusion_flutter_calendar: ^24.1.47 # SVG Images @@ -109,7 +110,7 @@ dependencies: manage_calendar_events: ^2.0.3 #InAppBrowser - flutter_inappwebview: ^5.8.0 + flutter_inappwebview: ^6.1.5 #Circular progress bar for reverse timer circular_countdown_timer: ^0.2.0 @@ -124,7 +125,7 @@ dependencies: flutter_datetime_picker_plus: ^2.1.0 carousel_pro_nullsafety: ^2.0.0 flutter_local_notifications: any - device_calendar: ^4.3.2 + device_calendar: ^4.3.3 geolocator: ^9.0.2 geocoding: ^2.0.1 jiffy: ^6.2.1 @@ -135,13 +136,15 @@ dependencies: google_maps_place_picker_mb: ^3.0.0 map_launcher: ^3.0.1 flutter_countdown_timer: ^4.1.0 + carousel_slider: ^5.0.0 #Dependencies for video call implementation native_device_orientation: ^1.0.0 - wakelock: ^0.6.2 +# wakelock: ^0.6.2 + wakelock_plus: ^1.1.4 after_layout: ^1.1.0 cached_network_image: ^3.3.0 flutter_tts: ^3.6.1 - vibration: ^1.7.3 +# vibration: ^1.7.3 flutter_nfc_kit: ^3.3.1 #geofencing: any speech_to_text: ^6.1.1 @@ -151,16 +154,16 @@ dependencies: in_app_review: ^2.0.3 badges: ^3.1.2 - flutter_app_icon_badge: ^2.0.0 +# flutter_app_icon_badge: ^2.0.0 # dropdown_search: 5.0.6 - youtube_player_flutter: ^8.1.2 + youtube_player_flutter: ^9.1.0 # shimmer: ^3.0.0 - carousel_slider: ^4.0.0 +# carousel_slider: ^4.0.0 # flutter_staggered_grid_view: ^0.7.0 huawei_hmsavailability: ^6.11.0+301 huawei_location: ^6.11.0+301 - share_plus: ^6.3.4 + share_plus: ^10.0.2 # Marker Animation auto_size_text: ^3.0.0 equatable: ^2.0.3 @@ -170,12 +173,13 @@ dependencies: google_api_availability: ^5.0.0 open_filex: ^4.3.2 path_provider: ^2.0.8 - amazon_payfort: ^1.1.0 + amazon_payfort: ^1.1.3 logger: ^2.0.2+1 network_info_plus: any - flutter_zoom_videosdk: ^1.10.11 + flutter_zoom_videosdk: ^1.11.2 dart_jsonwebtoken: ^2.14.0 + win32: ^5.5.4 cloudflare_turnstile: ^2.0.1