Merge branch 'dev_v3.13.6' into dev_v_3.13.6_CR_6804

# Conflicts:
#	lib/config/localized_values.dart
#	lib/pages/BookAppointment/BookConfirm.dart
#	lib/pages/BookAppointment/QRCode.dart
merge-update-with-lab-changes
Haroon Amjad 1 year ago
commit 69493934b1

1
.gitignore vendored

@ -31,6 +31,7 @@ pubspec.lock
.pub-cache/
.pub/
/build/
/ios/Frameworks/
# Web related
lib/generated_plugin_registrant.dart

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

Binary file not shown.

Binary file not shown.

@ -53,4 +53,20 @@
}
-dontwarn com.opentok.android.**
-dontwarn com.opentok.otc.**
-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.** { *; }

@ -8,21 +8,36 @@
FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" tools:node="remove"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove"/>
<uses-permission android:name="android.permission.BLUETOOTH" tools:node="remove"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:node="remove"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" tools:node="remove"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" tools:node="remove"/>
<!-- <uses-permission android:name="android.permission.BLUETOOTH" tools:node="remove"/>-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:node="remove"/>-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" tools:node="remove"/>-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_SCAN" tools:node="remove"/>-->
<uses-permission android:name="android.permission.BROADCAST_STICKY" tools:node="remove"/>
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" tools:node="remove"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:node="remove" />
<!-- <uses-permission android:name="android.permission.INTERNET" />-->
<!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@ -42,6 +57,7 @@
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
<!-- <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />-->
@ -59,13 +75,13 @@
</queries>
<application
android:name=".Application"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/ic_launcher_local"
android:usesCleartextTraffic="true"
android:showOnLockScreen="true"
android:screenOrientation="sensorPortrait"
android:allowBackup="false"
android:extractNativeLibs="true"
tools:replace="android:extractNativeLibs"
tools:replace="android:extractNativeLibs,android:label"
android:label="Dr. Alhabib">
<meta-data android:name="push_kit_auto_init_enabled" android:value="true" />

@ -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<out String>,
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() {

@ -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<String, Any>?
Log.d("TAG", "configureFlutterEngine: $args")
println("args")
args?.let {
PenguinView(
mainActivity,
100,
args,
flutterEngine.dartExecutor.binaryMessenger,
activity = mainActivity,
channel
)
}
}
else -> {
result.notImplemented()
}
}
}
}
}

@ -0,0 +1,28 @@
package com.cloud.diplomaticquarterapp.PermissionManager
import android.Manifest
import android.os.Build
object PermissionHelper {
fun getRequiredPermissions(): Array<String> {
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()
}
}

@ -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<out String>, grantResults: IntArray) {
if (this.requestCode == requestCode) {
val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
if (allGranted) {
listener.onPermissionGranted()
} else {
listener.onPermissionDenied()
}
}
}
}

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

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

@ -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<ResponseBody> = ApiController.getInstance(mContext)
.apiMethods
.getToken(postToken)
// Enqueue the call for asynchronous execution
purposesCall.enqueue(object : Callback<ResponseBody?> {
override fun onResponse(
call: Call<ResponseBody?>,
response: Response<ResponseBody?>
) {
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<ResponseBody?>, t: Throwable) {
apiTokenCallBack.onGetByRefIDError(t.message)
}
})
} catch (error: Exception) {
apiTokenCallBack.onGetByRefIDError("Exception during API call: $error")
}
}
}

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

@ -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 <T>httpPost(url: String, body: Map<String, Any?>, 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)) {

@ -19,4 +19,5 @@
<string name="GEOFENCE_REQUEST_TOO_FREQUENT">
Geofence requests happened too frequently.
</string>
<string name="mapbox_access_token" translatable="false">sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg</string>
</resources>

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>13.0</string>
</dict>
</plist>

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

@ -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 = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = "<group>"; };
301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokRemoteVideoFactory.swift; sourceTree = "<group>"; };
301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokLocalVideoFactory.swift; sourceTree = "<group>"; };
306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = "<group>"; };
306FE6CA271D8B73002D6EFC /* OpenTok.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTok.swift; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
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 = "<group>"; };
47C934FB2C91766400981BA7 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = "<group>"; };
47C934FC2C91766400981BA7 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = "<group>"; };
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 = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -74,6 +93,11 @@
7643E4062BE0D0B400BD2F25 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
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 = "<group>"; };
76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = "<group>"; };
76D71B692C6B819000DAFB84 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = "<group>"; };
76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = "<group>"; };
76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = "<group>"; };
76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
@ -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 = "<group>";
@ -151,6 +181,18 @@
path = Pods;
sourceTree = "<group>";
};
76D71B682C6B817500DAFB84 /* Penguin */ = {
isa = PBXGroup;
children = (
76D71B692C6B819000DAFB84 /* PenguinModel.swift */,
76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */,
76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */,
76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */,
29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */,
);
path = Penguin;
sourceTree = "<group>";
};
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 = "<group>";
@ -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;

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -4,7 +4,7 @@ import GoogleMaps
var userNotificationCenterDelegate:UNUserNotificationCenterDelegate? = nil
@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
let locationManager = CLLocationManager()
var flutterViewController:MainFlutterVC!
@ -30,11 +30,13 @@ var userNotificationCenterDelegate:UNUserNotificationCenterDelegate? = nil
flutterViewController = mainViewController
HMGPlatformBridge.initialize(flutterViewController: flutterViewController)
OpenTokPlatformBridge.initialize(flutterViewController: flutterViewController, registrar: self.registrar(forPlugin: "open-tok"))
HMGPenguinInPlatformBridge.initialize(flutterViewController: flutterViewController)
}else if let mainViewController = initialViewController(){ // platform initialization suppose to be in background
flutterViewController = mainViewController
HMGPlatformBridge.initialize(flutterViewController: flutterViewController)
OpenTokPlatformBridge.initialize(flutterViewController: flutterViewController, registrar: self.registrar(forPlugin: "open-tok"))
HMGPenguinInPlatformBridge.initialize(flutterViewController: flutterViewController)
}
}

@ -0,0 +1,61 @@
//
// HMGPenguinInPlatformBridge.swift
// Runner
//
// Created by Haroon Amjad on 13/08/2024.
//
import Foundation
var flutterMethodChannelPenguinIn:FlutterMethodChannel? = nil
fileprivate var mainViewController:MainFlutterVC!
class HMGPenguinInPlatformBridge{
private let channelName = "launch_penguin_ui"
private static var shared_:HMGPenguinInPlatformBridge?
class func initialize(flutterViewController:MainFlutterVC){
shared_ = HMGPenguinInPlatformBridge()
mainViewController = flutterViewController
shared_?.openChannel()
}
func shared() -> 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
}
}

@ -39,7 +39,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>13.0</string>
<key>NFCReaderUsageDescription</key>
<string>This app requires NFC Usage access to allow for Online CheckIn for appointments.</string>
<key>NSAppTransportSecurity</key>
@ -60,7 +60,7 @@
<key>NSCalendarsUsageDescription</key>
<string>This app requires calendar access to set reminders for Virtual &amp; Normal Appointments.</string>
<key>NSCalendarsWriteOnlyAccessUsageDescription</key>
<string>This app requires calendar access to set reminders for Virtual &amp; Normal Appointments.</string>
<string>This app requires calendar access to set reminders for Virtual &amp; Normal Appointments.</string>
<key>NSCalendarsFullAccessUsageDescription</key>
<string>This app requires calendar access to set reminders for Virtual &amp; Normal Appointments.</string>
<key>NSCameraUsageDescription</key>

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

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

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

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

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

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

@ -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 doctors 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":"البحث عن طريق اسم الفرع"}
};

@ -31,8 +31,7 @@ AppSharedPreferences sharedPref = new AppSharedPreferences();
/// onFailure: (String error, int statusCode) {},
/// body: Map();
///
AuthenticatedUserObject authenticatedUserObject =
locator<AuthenticatedUserObject>();
AuthenticatedUserObject authenticatedUserObject = locator<AuthenticatedUserObject>();
VitalSignService _vitalSignService = locator<VitalSignService>();
class BaseAppClient {
@ -40,12 +39,12 @@ class BaseAppClient {
post(String endPoint,
{required Map<String, dynamic> 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<String, String> headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
};
Map<String, String> 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<ProjectViewModel>(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<String, dynamic>? body,
Function(dynamic response, int statusCode)? onSuccess,
Function(String error, int statusCode)? onFailure,
bool isAllowAny = false,
bool isExternal = false}) async {
{Map<String, dynamic>? 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<NavigationService>().navigatorKey.currentContext!,
locator<NavigationService>().navigatorKey.currentContext!,
MaterialPageRoute(builder: (context) => AppUpdatePage(appUpdateText: text)),
(Route<dynamic> route) => false,
(Route<dynamic> route) => false,
);
}
get(String endPoint,
{required Function(dynamic response, int statusCode) onSuccess,
required Function(String error, int statusCode) onFailure,
Map<String, dynamic>? queryParams,
bool isExternal = false,
bool isRCService = false}) async {
required Function(String error, int statusCode) onFailure,
Map<String, dynamic>? 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<String, dynamic>? queryParams}) async {
required Function(String error, int statusCode) onFailure,
bool isAllowAny = false,
bool isExternal = false,
Map<String, dynamic>? 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<dynamic, dynamic> body,
required Map<String, String> headers,
required Function(dynamic response, int statusCode) onSuccess,
required Function(String error, int statusCode) onFailure,
}) async {
String fullUrl, {
required Map<dynamic, dynamic> body,
required Map<String, String> 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<String, dynamic>? queryParams,
Map<String, String>? headers}) async {
{Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure, Map<String, dynamic>? queryParams, Map<String, String>? 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<String, dynamic>? body,
Map<String, String>? headers,
Function(dynamic response, int statusCode)? onSuccess,
Function(String error, int statusCode)? onFailure}) async {
{Map<String, dynamic>? body, Map<String, String>? 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<String, String>? queryParams,
Map<String, String>? headers}) async {
{Function(dynamic response, int statusCode)? onSuccess, Function(String error, int statusCode)? onFailure, Map<String, String>? queryParams, Map<String, String>? 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<bool> handleUnauthorized(int statusCode,
{required String forUrl}) async {
Future<bool> 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<ProjectViewModel>(AppGlobal.context, listen: false).isLogin =
false;
var model =
Provider.of<ToDoCountProviderModel>(AppGlobal.context, listen: false);
Provider.of<ProjectViewModel>(AppGlobal.context, listen: false).isLogin = false;
var model = Provider.of<ToDoCountProviderModel>(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<String, dynamic>? body,
Function(dynamic response, int statusCode)? onSuccess,
Function(String error, int statusCode)? onFailure,
bool isAllowAny = false,
bool isExternal = false}) async {
{Map<String, dynamic>? 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<String> 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'];

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

@ -37,6 +37,7 @@ class _AllHabibMedicalSevicePage2State extends State<AllHabibMedicalSevicePage2>
AuthProvider authProvider = new AuthProvider();
WeatherService _weatherService = WeatherService();
double weatherNum = 30;
late ProjectViewModel projectViewModel;
@override
void initState() {
@ -235,7 +236,7 @@ class _AllHabibMedicalSevicePage2State extends State<AllHabibMedicalSevicePage2>
itemCount: hmgServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
return ServicesView(hmgServices[index], index, false);
return ServicesView(hmgServices[index], index, false, projectViewModel);
},
),
),

@ -445,7 +445,7 @@ class _BloodDonationBookAppointmentState extends State<BloodDonationBookAppointm
_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;
}
@ -492,11 +492,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;
}

@ -1,26 +1,38 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/core/enum/PayfortEnums.dart';
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart';
import 'package:diplomaticquarterapp/models/Appointments/DoctorListResponse.dart';
import 'package:diplomaticquarterapp/models/Appointments/PatientShareResposne.dart';
import 'package:diplomaticquarterapp/models/Appointments/toDoCountProviderModel.dart';
import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart';
import 'package:diplomaticquarterapp/models/LiveCare/ApplePayInsertRequest.dart';
import 'package:diplomaticquarterapp/models/header_model.dart';
import 'package:diplomaticquarterapp/pages/ToDoList/payment_method_select.dart';
import 'package:diplomaticquarterapp/pages/ToDoList/widgets/paymentDialog.dart';
import 'package:diplomaticquarterapp/pages/insurance/insurance_update_screen.dart';
import 'package:diplomaticquarterapp/pages/landing/landing_page.dart';
import 'package:diplomaticquarterapp/routes.dart';
import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart';
import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart';
import 'package:diplomaticquarterapp/services/livecare_services/livecare_provider.dart';
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_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/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/uitl/utils_new.dart';
import 'package:diplomaticquarterapp/widgets/buttons/custom_text_button.dart';
import 'package:diplomaticquarterapp/widgets/dialogs/confirm_dialog.dart';
import 'package:diplomaticquarterapp/widgets/in_app_browser/InAppBrowser.dart';
import 'package:diplomaticquarterapp/widgets/new_design/doctor_header.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
@ -42,7 +54,10 @@ class BookConfirm extends StatefulWidget {
bool isLiveCareAppointment;
int initialSlotDuration;
BookConfirm({required this.doctor, required this.selectedDate, required this.isLiveCareAppointment, required this.selectedTime, required this.initialSlotDuration});
bool isWalkinAppointment = false;
BookConfirm(
{required this.doctor, required this.selectedDate, required this.isLiveCareAppointment, required this.selectedTime, required this.initialSlotDuration, required this.isWalkinAppointment});
late DoctorsListService service;
late PatientShareResponse patientShareResponse;
@ -63,6 +78,13 @@ class _BookConfirmState extends State<BookConfirm> {
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<BookConfirm> {
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<BookConfirm> {
);
}
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<PayfortViewModel>().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<PayfortViewModel>().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<PayfortViewModel>().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<String?> 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<BookConfirm> {
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<BookConfirm> {
});
}
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<BookConfirm> {
});
}
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<dynamic> 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<BookConfirm> {
),
);
}
Future<void> _showMyDialog(String message, BuildContext context) async {
return showDialog<void>(
context: context,
barrierDismissible: true, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Alert'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(message),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => LandingPage()), (Route<dynamic> r) => false);
},
),
],
);
},
);
}
}

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

@ -60,6 +60,8 @@ class _DocAvailableAppointmentsState extends State<DocAvailableAppointments> wit
var language;
bool isLiveCareSchedule = false;
bool isWaitingAppointmentAvailable = false;
// String selectedLogSlots ='';
@override
@ -198,7 +200,7 @@ class _DocAvailableAppointmentsState extends State<DocAvailableAppointments> 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<DocAvailableAppointments> wit
openTimeSlotsPickerForDate(DateTime dateStart, List<TimeSlot> 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<DocAvailableAppointments> 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;
}

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

@ -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<WaitingAppointmentVerification> createState() => _WaitingAppointmentVerificationState();
}
class _WaitingAppointmentVerificationState extends State<WaitingAppointmentVerification> {
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<GAnalytics>().todoList.to_do_list_nfc_cancel(widget.appointment!);
});
});
}
startQRCodeScan() async {
String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent));
if (onlineCheckInQRCode != "") {
checkScannedNFCAndQRCode(onlineCheckInQRCode);
} else {}
}
}

@ -260,7 +260,7 @@ class _CovidTimeSlotsState extends State<CovidTimeSlots> 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;
}

@ -272,7 +272,7 @@ class _InPatientPendingAdvancePaymentState extends State<InPatientPendingAdvance
if (isCopy) {
Share.share(paymentLink);
} else {
this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(paymentLink)), options: _InAppBrowserOptions);
this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(paymentLink))), options: _InAppBrowserOptions);
}
} else {
AppToast.showErrorToast(message: res["endUserMessage"]);

@ -10,6 +10,7 @@ import 'package:diplomaticquarterapp/models/Appointments/toDoCountProviderModel.
import 'package:diplomaticquarterapp/models/header_model.dart';
import 'package:diplomaticquarterapp/pages/BookAppointment/BookConfirm.dart';
import 'package:diplomaticquarterapp/pages/BookAppointment/components/DocAvailableAppointments.dart';
import 'package:diplomaticquarterapp/pages/BookAppointment/waiting_appointment/waiting_appointment_info.dart';
import 'package:diplomaticquarterapp/pages/MyAppointments/SchedulePage.dart';
import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart';
import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart';
@ -299,23 +300,68 @@ class _AppointmentDetailsState extends State<AppointmentDetails> 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() {

@ -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"}
];
}

@ -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"}
];
}

@ -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<AppointmentActions> {
navigateToInsertComplaint();
locator<GAnalytics>().appointment.appointment_detail_action(appointment: widget.appo, action: 'raise complaint');
break;
case "goToNavigation":
initPenguinSDK();
locator<GAnalytics>().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<Permission, PermissionStatus> 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);
});
}
}

@ -253,7 +253,7 @@ class _CovidTimeSlotsState extends State<ObGyneTimeSlots> 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;
}

@ -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<ToDo> 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<ToDo> with SingleTickerProviderStateMixin {
);
}
initPenguinSDK(NavigationClinicDetails data) async {
final bool permited = await AppPermission.askPenguinPermissions();
if (!permited) {
Map<Permission, PermissionStatus> 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<ToDo> 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<ToDo> with SingleTickerProviderStateMixin {
}).catchError((err) {
print(err);
GifLoaderDialogUtils.hideDialog(context);
AppToast.showErrorToast(message: err);
AppToast.showErrorToast(message: err.toString());
});
}

@ -167,7 +167,7 @@ class _InsuranceUpdateState extends State<InsuranceUpdate> 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,

@ -52,7 +52,11 @@ class _HomePageFragment2State extends State<HomePageFragment2> {
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<HomePageFragment2> {
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<HomePageFragment2> {
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<HomePageFragment2> {
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<HomePageFragment2> {
flex: 1,
child: InkWell(
onTap: () {
if (projectViewModel.havePrivilege(100))
widget.onPharmacyClick!();
if (projectViewModel.havePrivilege(100)) widget.onPharmacyClick!();
},
child: Stack(children: [
Container(

@ -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<LandingPage> 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)) {

@ -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<PharmacyModuleViewModel>();
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<HospitalsModel> 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<Permission, PermissionStatus> 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<GAnalytics>().hmgServices.logServiceName('emergency service');
// initPenguinSDK();
if (projectViewModel.isIndoorNavigationEnabled) {
if (!isLocked) openNavigationProjectSelection(context);
} else {
Navigator.push(context, FadePage(page: ErOptions(isAppbar: true)));
locator<GAnalytics>().hmgServices.logServiceName('emergency service');
}
} else if (hmgServices.action == 3) {
Navigator.push(context, FadePage(page: HomeHealthCarePage()));
locator<GAnalytics>().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<GAnalytics>().hmgServices.logServiceName('latest news');

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

@ -373,15 +373,17 @@ class _clinic_listState extends State<ClinicList> {
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);

@ -393,7 +393,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
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<ConfirmLogin> {
}
bool checkIfBiometricAvailable(BiometricType biometricType) {
print(biometricType);
bool isAvailable = false;
if (_availableBiometrics != null) {
for (var i = 0; i < _availableBiometrics.length; i++) {

@ -455,10 +455,10 @@ class _RegisterInfo extends State<RegisterInfo> {
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<RegisterInfo> {
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<RegisterInfo> {
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<RegisterInfo> {
projectViewModel.isLogin = true;
projectViewModel.user = authenticatedUserObject.user;
await authenticatedUserObject.getUser(getUser: true);
int languageID = Provider.of<ProjectViewModel>(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<dynamic> route) => false,
);
Navigator.push(context, FadePage(page: InsuranceUpdate()));
},
cancelFunction: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => LandingPage()),
(Route<dynamic> 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<dynamic> route) => false,
);
});
dialog.showAlertDialog(context);
// int languageID = Provider.of<ProjectViewModel>(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<dynamic> route) => false,
// );
// Navigator.push(context, FadePage(page: InsuranceUpdate()));
// },
// cancelFunction: () {
// Navigator.pushAndRemoveUntil(
// context,
// MaterialPageRoute(builder: (context) => LandingPage()),
// (Route<dynamic> route) => false,
// );
// });
// dialog.showAlertDialog(context);
// }
// }).catchError((err) {
// print(err);
// //GifLoaderDialogUtils.hideDialog(context);
// });
// SMSOTP.showLoadingDialog(context, false),
}

@ -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<Register> {
}
checkPatientForRegisteration(request) {
int languageID = Provider.of<ProjectViewModel>(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,

@ -34,7 +34,7 @@ class _syncHealthDataButtonState extends State<syncHealthDataButton> {
int MedCategoryID = 0;
HealthFactory health = HealthFactory();
// HealthFactory health = HealthFactory();
List<HealthDataType> types = [HealthDataType.STEPS, HealthDataType.HEART_RATE, Platform.isAndroid ? HealthDataType.DISTANCE_DELTA : HealthDataType.DISTANCE_WALKING_RUNNING];
@override
@ -48,29 +48,29 @@ class _syncHealthDataButtonState extends State<syncHealthDataButton> {
}
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<syncHealthDataButton> {
DateTime startDate = DateTime.now().subtract(new Duration(days: 30));
try {
List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(startDate, DateTime.now(), types);
_healthDataList.addAll(healthData);
// List<HealthDataPoint> 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) {

@ -334,6 +334,58 @@ class DoctorsListService extends BaseService {
return Future.value(localRes);
}
Future<Map> insertWalkInAppointment(int docID, int clinicID, int projectID, String selectedTime, String selectedDate, int initialSlotDuration, int languageID, BuildContext context) async {
Map<String, dynamic> 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<Map> 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<String, dynamic> request;
@ -638,6 +690,32 @@ class DoctorsListService extends BaseService {
return Future.value(localRes);
}
Future<Map> getPatientShareForWalkInAppointment(int clinicID, int projectID, int doctorID) async {
Map<String, dynamic> 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<Map> canPayForWalkInAppointment(int clinicID, int projectID, int doctorID) async {
Map<String, dynamic> 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<Map> getPatientAppointmentHistory(bool isActiveAppointment, int languageID, BuildContext context, {bool isForCOC = false, isForUpcomming = false, IsForArrived = false}) async {
Map<String, dynamic> request;
@ -1571,6 +1649,19 @@ class DoctorsListService extends BaseService {
return Future.value(localRes);
}
Future<Map> checkScannedNFCAndQRCode(String nfcCode, int projectId) async {
Map<String, dynamic> 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<Map> checkIfHasDentalPlan(int projectID, BuildContext context) async {
Map<String, dynamic> request;

File diff suppressed because it is too large Load Diff

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

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

@ -7,9 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'PlatformBridge.dart';
class AppPermission{
class AppPermission {
static Future<bool> 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<bool> 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);
}
}
}

@ -0,0 +1,98 @@
import 'package:flutter/services.dart';
class PenguinMethodChannel {
static const MethodChannel _channel = MethodChannel('launch_penguin_ui');
static Future<void> 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<dynamic, dynamic> 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;
}

@ -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<Permission, PermissionStatus> 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);

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

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

@ -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<HospitalsModel> 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<HospitalsModel> data;
final Function(int)? onValueSelected;
final int? selectedIndex;
const LocationDialogBody(
{super.key,
required this.data,
this.onValueSelected,
this.selectedIndex});
@override
State<LocationDialogBody> createState() => _LocationDialogBodyState();
}
class _LocationDialogBodyState extends State<LocationDialogBody> {
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<HospitalsModel> data;
final Function(String) onItemClick;
const LocationListExpandedBody(
{super.key, required this.data, required this.onItemClick});
@override
State<LocationListExpandedBody> createState() =>
_LocationListExpandedBodyState();
}
class _LocationListExpandedBodyState extends State<LocationListExpandedBody> {
List<HospitalsModel> 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),
))
],
);
}
}

@ -171,7 +171,7 @@ class _AppDrawerState extends State<AppDrawer> {
// ),
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<AppDrawer> {
// 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);

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

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

Loading…
Cancel
Save