Merge branch 'master' into faiz_dev

# Conflicts:
#	lib/core/api/api_client.dart
#	lib/core/app_state.dart
faiz_dev
haroon amjad 4 days ago
commit 0a5014a285

6
.gitignore vendored

@ -43,3 +43,9 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
/ios/
/ios/Penguin.xcframework/
/ios/PenguinINRenderer.xcframework/
/ios/PenNavUI.xcframework/

@ -7,6 +7,11 @@
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
exclude:
- build/**
- android/**
- ios/**
include: package:flutter_lints/flutter.yaml
linter:

@ -1 +1,74 @@
{"agcgw":{"url":"connect-drcn.dbankcloud.cn","backurl":"connect-drcn.hispace.hicloud.com","websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn","websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com"},"agcgw_all":{"SG":"connect-dra.dbankcloud.cn","SG_back":"connect-dra.hispace.hicloud.com","CN":"connect-drcn.dbankcloud.cn","CN_back":"connect-drcn.hispace.hicloud.com","RU":"connect-drru.hispace.dbankcloud.ru","RU_back":"connect-drru.hispace.dbankcloud.cn","DE":"connect-dre.dbankcloud.cn","DE_back":"connect-dre.hispace.hicloud.com"},"websocketgw_all":{"SG":"connect-ws-dra.hispace.dbankcloud.cn","SG_back":"connect-ws-dra.hispace.dbankcloud.com","CN":"connect-ws-drcn.hispace.dbankcloud.cn","CN_back":"connect-ws-drcn.hispace.dbankcloud.com","RU":"connect-ws-drru.hispace.dbankcloud.ru","RU_back":"connect-ws-drru.hispace.dbankcloud.cn","DE":"connect-ws-dre.hispace.dbankcloud.cn","DE_back":"connect-ws-dre.hispace.dbankcloud.com"},"client":{"cp_id":"2640966000002322881","product_id":"736430079244816567","client_id":"563735388191982656","client_secret":"650C7C799812AFFD53A10C7756CF05FB9F215A7E49032ABA8EBF3E14B77535CF","project_id":"736430079244816567","app_id":"116912301","api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI","package_name":"com.cloudsolutions.HMGPatientApp"},"oauth_client":{"client_id":"116912301","client_type":1},"app_info":{"app_id":"116912301","package_name":"com.cloudsolutions.HMGPatientApp"},"service":{"analytics":{"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn","collector_url_ru":"datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com","collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn","resource_id":"p1","channel_id":""},"ml":{"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"},"cloudstorage":{"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg":"https://ops-dra.agcstorage.link","storage_url_de":"https://ops-dre.agcstorage.link","storage_url_cn":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru_back":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg_back":"https://agc-storage-dra.cloud.huawei.asia","storage_url_de_back":"https://agc-storage-dre.cloud.huawei.eu","storage_url_cn_back":"https://agc-storage-drcn.cloud.huawei.com.cn"},"search":{"url":"https://search-drcn.cloud.huawei.com"},"edukit":{"edu_url":"edukit.cloud.huawei.com.cn","dh_url":"edukit.cloud.huawei.com.cn"}},"region":"CN","configuration_version":"3.0","appInfos":[{"package_name":"com.cloudsolutions.HMGPatientApp","client":{"app_id":"116912301"},"app_info":{"package_name":"com.cloudsolutions.HMGPatientApp","app_id":"116912301"},"oauth_client":{"client_type":1,"client_id":"116912301"}},{"package_name":"com.ejada.hmg","client":{"app_id":"102857389"},"app_info":{"package_name":"com.ejada.hmg","app_id":"102857389"},"oauth_client":{"client_type":1,"client_id":"102857389"}}]}
{
"agcgw":{
"backurl":"connect-drcn.hispace.hicloud.com",
"url":"connect-drcn.dbankcloud.cn",
"websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com",
"websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn"
},
"agcgw_all":{
"CN":"connect-drcn.dbankcloud.cn",
"CN_back":"connect-drcn.hispace.hicloud.com",
"DE":"connect-dre.dbankcloud.cn",
"DE_back":"connect-dre.hispace.hicloud.com",
"RU":"connect-drru.dbankcloud.cn",
"RU_back":"connect-drru.hispace.hicloud.com",
"SG":"connect-dra.dbankcloud.cn",
"SG_back":"connect-dra.hispace.hicloud.com"
},
"client":{
"cp_id":"2640966000002322881",
"product_id":"736430079244816567",
"client_id":"563735388191982656",
"client_secret":"650C7C799812AFFD53A10C7756CF05FB9F215A7E49032ABA8EBF3E14B77535CF",
"project_id":"736430079244816567",
"app_id":"102857389",
"api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI",
"package_name":"com.ejada.hmg"
},
"oauth_client":{
"client_id":"102857389",
"client_type":1
},
"app_info":{
"app_id":"102857389",
"package_name":"com.ejada.hmg"
},
"service":{
"analytics":{
"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
"collector_url_ru":"datacollector-drru.dt.hicloud.com,datacollector-drru.dt.dbankcloud.cn",
"collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
"collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
"collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
"resource_id":"p1",
"channel_id":""
},
"search":{
"url":"https://search-drcn.cloud.huawei.com"
},
"cloudstorage":{
"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn"
},
"ml":{
"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
}
},
"region":"CN",
"configuration_version":"3.0",
"appInfos":[
{
"package_name":"com.ejada.hmg",
"client":{
"app_id":"102857389"
},
"app_info":{
"package_name":"com.ejada.hmg",
"app_id":"102857389"
},
"oauth_client":{
"client_type":1,
"client_id":"102857389"
}
}
]
}

@ -19,7 +19,8 @@ if (keystorePropertiesFile.exists()) {
}
android {
namespace = "com.cloudsolutions.HMGPatientApp"
// namespace = "com.cloudsolutions.HMGPatientApp"
namespace = "com.ejada.hmg"
compileSdk = 36
// Using NDK 26 for better compatibility with Zoom SDK native libraries
// ndkVersion = "27.0.12077973"
@ -33,7 +34,8 @@ android {
}
defaultConfig {
applicationId = "com.cloudsolutions.HMGPatientApp"
// applicationId = "com.cloudsolutions.HMGPatientApp"
applicationId = "com.ejada.hmg"
// minSdk = 24
minSdk = 29
targetSdk = 36
@ -141,6 +143,10 @@ flutter {
source = "../.."
}
configurations.all {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-android-extensions-runtime")
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20")
implementation("com.google.firebase:firebase-messaging:24.1.2")
@ -155,8 +161,8 @@ dependencies {
// implementation("us.zoom.videosdk:zoomvideosdk-videoeffects:1.12.10")
implementation("us.zoom.videosdk:zoomvideosdk-core:2.1.10")
implementation("us.zoom.videosdk:zoomvideosdk-videoeffects:2.1.10")
implementation("us.zoom.videosdk:zoomvideosdk-annotation:2.1.10")
// implementation("us.zoom.videosdk:zoomvideosdk-videoeffects:2.1.10")
// implementation("us.zoom.videosdk:zoomvideosdk-annotation:2.1.10")
// Networking
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11")
@ -200,8 +206,8 @@ dependencies {
implementation("com.huawei.hms:health:6.11.0.300")
implementation("com.huawei.hms:hmscoreinstaller:6.6.0.300")
implementation("com.github.kittinunf.fuel:fuel:2.3.1")
implementation("com.github.kittinunf.fuel:fuel-android:2.3.1")
// implementation("com.github.kittinunf.fuel:fuel:2.3.1")
// implementation("com.github.kittinunf.fuel:fuel-android:2.3.1")
// implementation("com.opentok.android:opentok-android-sdk:2.25.2")
@ -213,14 +219,33 @@ dependencies {
implementation("com.google.android.material:material:1.12.0")
implementation("pl.droidsonroids.gif:android-gif-drawable:1.2.29")
implementation("com.mapbox.mapboxsdk:mapbox-sdk-turf:7.3.1")
// implementation("com.mapbox.mapboxsdk:mapbox-sdk-turf:7.3.1")
androidTestImplementation("androidx.test:core:1.6.1")
implementation("com.whatsapp.otp:whatsapp-otp-android-sdk:0.1.0")
// implementation("com.whatsapp.otp:whatsapp-otp-android-sdk:0.1.0")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
// implementation(project(":vitalSignEngine"))
}
tasks.matching { it.name.contains("minify") && it.name.contains("R8") }.configureEach {
doFirst {
inputs.files.forEach { file ->
if (file.isFile && (file.name.endsWith(".txt") || file.name.endsWith(".pro")) && file.canWrite()) {
val content = file.readText()
val sanitized = content
.replace(Regex("""(?m)^\s*-keep\s+class\s+\*\s*\{.*$"""), "# stripped -keep class *")
.replace(Regex("""(?m)^\s*-keep\s+class\s+androidx\.\*\*\s*\{.*$"""), "# stripped -keep class androidx.**")
.replace(Regex("""(?m)^\s*-keep\s+class\s+android\.\*\*\s*\{.*$"""), "# stripped -keep class android.**")
.replace(Regex("""(?m)^\s*-keep\s+class\s+com\.google\.\*\*\s*\{.*$"""), "# stripped -keep class com.google.**")
if (sanitized != content) {
println("Sanitizing overly broad ProGuard rules in: ${file.absolutePath}")
file.writeText(sanitized)
}
}
}
}
}
tasks.whenTaskAdded {
if (name.contains("merge") && name.contains("NativeLibs")) {
doLast {

@ -3,45 +3,9 @@
"project_number": "815750722565",
"firebase_url": "https://api-project-815750722565.firebaseio.com",
"project_id": "api-project-815750722565",
"storage_bucket": "api-project-815750722565.firebasestorage.app"
"storage_bucket": "api-project-815750722565.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:815750722565:android:fa20b3a2401e08633c186c",
"android_client_info": {
"package_name": "com.cloudsolutions.HMGPatientApp"
}
},
"oauth_client": [
{
"client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDZDeWcBlRE3YfJWYt_DCiToVnANfaj8qg"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "815750722565-0cq9366orvsk5ipivq6lijcj56u03fr7.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.void.demo"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:815750722565:android:62281cd3e5df4063",

@ -3,7 +3,7 @@
-keep class com.twilio.common.** { *; }
-keepattributes InnerClasses
-keep class com.ejada.** { *; }
#-keep class com.ejada.** { *; }
-keep class org.webrtc.** { *; }
-keep class com.builttoroam.devicecalendar.** { *; }
@ -26,7 +26,7 @@
-keep class io.flutter.plugins.** { *; }
-dontwarn io.flutter.embedding.**
-keep class com.huawei.hms.flutter.** { *; }
-repackageclasses
#-repackageclasses
## Flutter WebRTC
-keep class com.cloudwebrtc.webrtc.** { *; }
@ -89,3 +89,15 @@
-keep interface com.payfort.fortpaymentsdk.** {*;}
-keep class com.payfort.fortpaymentsdk.** {*;}
# MyFatoorah SDK (scoped rules without global -keep class *)
-dontwarn org.slf4j.impl.**
-dontwarn java.lang.invoke.StringConcatFactory
-dontwarn com.google.android.play.core.**
-dontwarn android.content.res.**
-keep class org.xmlpull.** { *; }
-keepclassmembers class org.xmlpull.** { *; }
-keep class com.myfatoorah.sdk.** { *; }
-keep class com.myfatoorah.** { *; }
-keep class com.myfatoorahflutter.** { *; }
-keep class org.apache.http.** { *; }

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.cloudsolutions.HMGPatientApp">
package="com.ejada.hmg">
<!--
io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
@ -41,6 +41,11 @@
android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"
tools:node="remove" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_LOCATION"
tools:node="remove" />
<!-- Gallery/Photo permissions for Android 13+ (API 33+) -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
<!-- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />-->
@ -133,7 +138,7 @@
android:name=".Application"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher_local"
android:label="Dr. Alhabib Beta"
android:label="Dr. Alhabib"
android:screenOrientation="sensorPortrait"
android:showOnLockScreen="true"
android:usesCleartextTraffic="true"
@ -267,6 +272,9 @@
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng" />
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=116912301" />
<!--
Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java

@ -1,5 +1,5 @@
//package com.cloud.diplomaticquarterapp
package com.cloudsolutions.HMGPatientApp
package com.ejada.hmg
import io.flutter.app.FlutterApplication

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp
package com.ejada.hmg
import android.content.Intent
import android.content.pm.PackageManager
@ -7,7 +7,8 @@ import android.util.Log
import android.view.WindowManager
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi
import com.cloudsolutions.HMGPatientApp.watch.samsung_watch.SamsungWatch
import com.ejada.hmg.watch.samsung_watch.SamsungWatch
import com.ejada.hmg.watch.huawei.HuaweiWatch
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
@ -24,6 +25,7 @@ class MainActivity: FlutterFragmentActivity() {
PenguinInPlatformBridge(flutterEngine, this).create()
SamsungWatch(flutterEngine, this)
HuaweiWatch(flutterEngine, this)
}
override fun onRequestPermissionsResult(

@ -1,14 +1,14 @@
package com.cloudsolutions.HMGPatientApp
package com.ejada.hmg
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.cloudsolutions.HMGPatientApp.penguin.PenguinView
import com.ejada.hmg.penguin.PenguinView
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import com.cloudsolutions.HMGPatientApp.PermissionManager.HostNotificationPermissionManager
import com.cloudsolutions.HMGPatientApp.PermissionManager.HostBgLocationManager
import com.cloudsolutions.HMGPatientApp.PermissionManager.HostGpsStateManager
import com.ejada.hmg.PermissionManager.HostNotificationPermissionManager
import com.ejada.hmg.PermissionManager.HostBgLocationManager
import com.ejada.hmg.PermissionManager.HostGpsStateManager
import io.flutter.plugin.common.MethodChannel
class PenguinInPlatformBridge(

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager;
package com.ejada.hmg.PermissionManager;
import android.content.Context;
import android.content.SharedPreferences;

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager;
package com.ejada.hmg.PermissionManager;
import android.Manifest;
import android.app.Activity;

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager;
package com.ejada.hmg.PermissionManager;
import android.Manifest;
import android.app.Activity;

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager;
package com.ejada.hmg.PermissionManager;
import android.app.Activity;
import android.content.pm.PackageManager;

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager
package com.ejada.hmg.PermissionManager
import android.Manifest

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager
package com.ejada.hmg.PermissionManager
import android.app.Activity
import android.content.Context

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.PermissionManager
package com.ejada.hmg.PermissionManager
// PermissionResultReceiver.kt
import android.content.BroadcastReceiver

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.penguin
package com.ejada.hmg.penguin
enum class PenguinMethod {
// initializePenguin("initializePenguin"),

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.penguin
package com.ejada.hmg.penguin
import android.content.Context
import com.google.gson.Gson

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.penguin
package com.ejada.hmg.penguin
import android.app.Activity
import android.content.Context
@ -12,10 +12,10 @@ import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.annotation.RequiresApi
import com.cloudsolutions.HMGPatientApp.PermissionManager.PermissionManager
import com.cloudsolutions.HMGPatientApp.PermissionManager.PermissionResultReceiver
import com.cloudsolutions.HMGPatientApp.MainActivity
import com.cloudsolutions.HMGPatientApp.PermissionManager.PermissionHelper
import com.ejada.hmg.PermissionManager.PermissionManager
import com.ejada.hmg.PermissionManager.PermissionResultReceiver
import com.ejada.hmg.MainActivity
import com.ejada.hmg.PermissionManager.PermissionHelper
import com.peng.pennavmap.PlugAndPlayConfiguration
import com.peng.pennavmap.PlugAndPlaySDK
import com.peng.pennavmap.enums.InitializationErrorType

@ -0,0 +1,87 @@
package com.ejada.hmg.watch.huawei
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.ejada.hmg.watch.samsung_watch.model.Vitals
import com.huawei.hms.adapter.AvailableAdapter
import com.huawei.hms.adapter.internal.AvailableCode
import com.samsung.android.sdk.health.data.HealthDataStore
import com.samsung.android.sdk.health.data.permission.AccessType
import com.samsung.android.sdk.health.data.permission.Permission
import com.samsung.android.sdk.health.data.request.DataType
import com.samsung.android.sdk.health.data.request.DataTypes
import com.samsung.android.sdk.health.data.request.LocalTimeFilter
import com.samsung.android.sdk.health.data.request.LocalTimeGroup
import com.samsung.android.sdk.health.data.request.LocalTimeGroupUnit
import com.samsung.android.sdk.health.data.request.Ordering
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.LocalTime
import com.huawei.hms.hihealth.HuaweiHiHealth
import com.ejada.hmg.MainActivity
class HuaweiWatch(
private var flutterEngine: FlutterEngine,
private var mainActivity: MainActivity
) {
private lateinit var channel: MethodChannel
private lateinit var dataStore: HealthDataStore
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val TAG = "HuaweiWatch"
private lateinit var vitals: MutableMap<String, List<Vitals>>
companion object {
private const val CHANNEL = "huawei_watch"
}
init{
create()
}
@RequiresApi(Build.VERSION_CODES.O)
fun create() {
Log.d(TAG, "create: is called")
// openTok = OpenTok(mainActivity, flutterEngine)
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
when (call.method) {
"init" -> {
init(result)
}
else -> {
result.notImplemented()
}
}
}
}
fun init(result: MethodChannel.Result) {
Log.d(TAG, "onMethodCall: init called")
val mSettingController = HuaweiHiHealth.getSettingController(mainActivity);
val availableAdapter = AvailableAdapter(60400312)
val results= availableAdapter.isHuaweiMobileServicesAvailable(mainActivity) // context indicates a context object.
if (results != AvailableCode.SUCCESS) {
availableAdapter.startResolution(mainActivity, object : AvailableAdapter.AvailableCallBack {
override fun onComplete(result: Int) {
Log.d(TAG, "onComplete result: " + result)
}
})
}
result.success("init success")
}
}

@ -1,12 +1,12 @@
package com.cloudsolutions.HMGPatientApp.watch.samsung_watch
package com.ejada.hmg.watch.samsung_watch
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.cloudsolutions.HMGPatientApp.MainActivity
import com.cloudsolutions.HMGPatientApp.watch.samsung_watch.model.Vitals
import com.ejada.hmg.MainActivity
import com.ejada.hmg.watch.samsung_watch.model.Vitals
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import com.samsung.android.sdk.health.data.HealthDataService
@ -75,12 +75,22 @@ class SamsungWatch(
Permission.of(DataTypes.ACTIVITY_SUMMARY, AccessType.READ),
Permission.of(DataTypes.SLEEP, AccessType.READ),
Permission.of(DataTypes.BODY_TEMPERATURE, AccessType.READ),
Permission.of(DataTypes.EXERCISE, AccessType.READ),
// Permission.of(DataTypes.EXERCISE, AccessType.READ),
// Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ),
// Permission.of(DataTypes.NUTRITION, AccessType.READ),
)
scope.launch {
val typesToTest = listOf(
DataTypes.HEART_RATE,
DataTypes.STEPS,
DataTypes.BLOOD_OXYGEN,
DataTypes.ACTIVITY_SUMMARY,
DataTypes.SLEEP,
DataTypes.BODY_TEMPERATURE,
// DataTypes.EXERCISE
)
scope.launch(Dispatchers.IO) {
try {
var granted = dataStore.getGrantedPermissions(permSet)
@ -89,6 +99,17 @@ class SamsungWatch(
return@launch
}
// for (type in typesToTest) {
// try {
// val result = dataStore.requestPermissions(
// setOf(Permission.of(type, AccessType.READ)),
// mainActivity
// )
// Log.d("PermCheck", "OK: $type and the result is $result")
// } catch (e: Exception) {
// Log.e("PermCheck", "FAILED: $type -> ${e.message}")
// }
// }
granted = dataStore.requestPermissions(permSet, mainActivity)
if (granted.containsAll(permSet)) {
@ -111,7 +132,7 @@ class SamsungWatch(
.setOrdering(Ordering.DESC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val heartRateList = dataStore.readData(readRequest).dataList
processHeartVital(heartRateList)
Log.d("TAG"," the data is ${vitals}")
@ -128,7 +149,7 @@ class SamsungWatch(
.setLocalTimeFilter(localTimeFilter)
.setOrdering(Ordering.ASC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val sleepData = dataStore.readData(readRequest).dataList
processSleepVital(sleepData)
print("the data is $vitals")
@ -147,7 +168,7 @@ class SamsungWatch(
.setOrdering(Ordering.ASC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val steps = dataStore.aggregateData(aggregateRequest)
processStepsCount(steps)
print("the data is $vitals")
@ -166,7 +187,7 @@ class SamsungWatch(
.setOrdering(Ordering.DESC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val activityResult = dataStore.aggregateData(readRequest).dataList
processActivity(activityResult)
Log.d("TAG"," the data is ${vitals}")
@ -201,7 +222,7 @@ class SamsungWatch(
.setOrdering(Ordering.DESC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val bloodOxygenList = dataStore.readData(readRequest).dataList
processBloodOxygen(bloodOxygenList)
Log.d("TAG"," the data is ${vitals}")
@ -219,7 +240,7 @@ class SamsungWatch(
.setOrdering(Ordering.DESC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val bodyTemperatureList = dataStore.readData(readRequest).dataList
processBodyTemperature(bodyTemperatureList)
Log.d("TAG"," the data is ${vitals}")
@ -237,7 +258,7 @@ class SamsungWatch(
.setOrdering(Ordering.DESC)
.build()
scope.launch {
scope.launch(Dispatchers.IO) {
val activityResult = dataStore.aggregateData(readRequest).dataList
processDistance(activityResult)
Log.d("TAG"," the data is ${vitals}")

@ -1,4 +1,4 @@
package com.cloudsolutions.HMGPatientApp.watch.samsung_watch.model
package com.ejada.hmg.watch.samsung_watch.model
data class Vitals(
var value : String = "",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.cloudsolutions.HMGPatientApp">
package="com.cloudsolutions.hmg">
<!--
io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.

@ -54,12 +54,24 @@ allprojects {
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "21"
// kotlinOptions {
// jvmTarget = "21"
// }
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
}
}
subprojects {
project.buildscript.repositories {
google()
mavenCentral()
}
project.repositories {
google()
mavenCentral()
}
afterEvaluate {
if (project.hasProperty("android")) {
project.extensions.findByName("android")?.let { androidExt ->
@ -76,6 +88,31 @@ allprojects {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
if (project.name == "myfatoorah_flutter") {
android.defaultConfig.consumerProguardFiles.clear()
android.buildTypes.all {
consumerProguardFiles.clear()
}
}
}
}
project.tasks.matching { it.name.contains("ConsumerProguardFiles") }.configureEach {
doLast {
outputs.files.forEach { dirOrFile ->
dirOrFile.walkTopDown()
.filter { it.isFile && (it.name.endsWith(".txt") || it.name.endsWith(".pro")) }
.forEach { proFile ->
val content = proFile.readText()
val sanitized = content
.replace(Regex("""(?m)^\s*-keep\s+class\s+\*\s*\{.*$"""), "# stripped -keep class *")
.replace(Regex("""(?m)^\s*-keep\s+class\s+androidx\.\*\*\s*\{.*$"""), "# stripped -keep class androidx.**")
.replace(Regex("""(?m)^\s*-keep\s+class\s+android\.\*\*\s*\{.*$"""), "# stripped -keep class android.**")
.replace(Regex("""(?m)^\s*-keep\s+class\s+com\.google\.\*\*\s*\{.*$"""), "# stripped -keep class com.google.**")
if (sanitized != content) {
proFile.writeText(sanitized)
}
}
}
}
}
project.tasks.withType<JavaCompile>().configureEach {
@ -83,8 +120,11 @@ allprojects {
targetCompatibility = JavaVersion.VERSION_21.toString()
}
project.tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "21"
// kotlinOptions {
// jvmTarget = "21"
// }
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
}
}
}

File diff suppressed because one or more lines are too long

@ -1,10 +1,18 @@
#org.gradle.jvmargs=-xmx4608m
android.enableR8=true
android.enableR8.fullMode=false
android.enableJetifier=true
android.useDeprecatedNdk=true
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#org.gradle.jvmargs=-Xmx6144m -XX:MaxMetaspaceSize=1024m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx12g -XX:MaxMetaspaceSize=2048m -XX:+UseG1GC -Dfile.encoding=UTF-8
kotlin.daemon.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
android.useAndroidX=true
android.enableImpeller=false
# This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false
# This newDsl flag was added automatically by Flutter migrator
android.newDsl=false
# Enabled parallel sync for Gradle 9.4+
org.gradle.tooling.parallel=true

@ -2,4 +2,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
#distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip

@ -16,14 +16,35 @@ pluginManagement {
}
}
dependencyResolutionManagement {
// repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
repositories {
google()
mavenCentral()
maven {
url = uri("https://storage.googleapis.com/download.flutter.io")
}
// Huawei HMS repo
maven {
url = uri("https://developer.huawei.com/repo/")
}
// Mapbox repo
maven {
url = uri("https://api.mapbox.com/downloads/v2/releases/maven")
}
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
// id("com.android.application") version "8.9.3" apply false
// START: FlutterFire Configuration
id("com.google.gms.google-services") version("4.4.1") apply false
// END: FlutterFire Configuration
id("com.android.application") version "8.9.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
id("com.android.application") version "8.11.1" apply false
// id("org.jetbrains.kotlin.android") version "2.2.20" apply false
id("org.jetbrains.kotlin.android") version "2.4.20" apply false
}
include(":app")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 902 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 KiB

After

Width:  |  Height:  |  Size: 445 KiB

@ -0,0 +1,10 @@
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="120" height="120" rx="60" fill="#ED1C2B" fill-opacity="0.0784314"/>
<rect x="27" y="45" width="18" height="30" rx="3" fill="white"/>
<rect x="27" y="45" width="18" height="30" rx="3" stroke="#ED1C2B" stroke-width="2"/>
<rect x="30" y="52" width="12" height="16" rx="2" fill="#ED1C2B" fill-opacity="0.101961"/>
<path d="M55.333 59.9992H64.6674M60.0002 64.6664L64.6674 59.9992L60.0002 55.332" stroke="#ED1C2B" stroke-width="2" stroke-linecap="round"/>
<rect x="75" y="45" width="18" height="30" rx="3" fill="white"/>
<rect x="75" y="45" width="18" height="30" rx="3" stroke="#ED1C2B" stroke-width="2"/>
<rect x="78" y="52" width="12" height="16" rx="2" fill="#ED1C2B" fill-opacity="0.101961"/>
</svg>

After

Width:  |  Height:  |  Size: 812 B

@ -0,0 +1,7 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<g transform="translate(8.8, 8.8) scale(1.6)">
<path d="M11.5658 1.95717C9.82689 0.890531 8.26692 1.31563 7.32452 2.02335C7.26938 2.06476 7.22039 2.10153 7.17659 2.13413C7.08676 2.20099 7.04185 2.23442 6.98387 2.23442C6.92589 2.23442 6.88098 2.20099 6.79115 2.13413C6.74735 2.10153 6.69836 2.06476 6.64322 2.02335C5.70082 1.31563 4.14085 0.890531 2.40195 1.95717C1.53619 2.48823 0.943044 3.43564 0.767402 4.5853C0.741775 4.75304 0.728961 4.83691 0.781341 4.89789C0.83372 4.95888 0.923033 4.95887 1.10166 4.95885L3.00095 4.95868C3.24133 4.95767 3.64619 4.95596 4.03964 5.0991C4.19392 5.15522 4.33336 5.22877 4.4573 5.3094C4.63656 5.42602 4.72618 5.48433 4.79864 5.46761C4.87109 5.45089 4.92018 5.36908 5.01835 5.20545L5.44147 4.50026C5.71062 4.05168 6.19943 3.78162 6.72246 3.79256C7.24549 3.80349 7.72259 4.09374 7.97275 4.55319L8.72948 5.94294C8.77795 6.03196 8.80218 6.07647 8.8435 6.10102C8.88482 6.12557 8.9355 6.12557 9.03686 6.12557H9.31698C10.1224 6.12557 10.7753 6.77849 10.7753 7.5839C10.7753 8.38932 10.1224 9.04224 9.31698 9.04224L8.66574 9.04348C8.42373 9.04908 7.69714 9.06588 7.06184 8.57794C7.0432 8.56363 7.02501 8.54906 7.00725 8.5343C6.81047 8.37075 6.71208 8.28898 6.63276 8.30247C6.55344 8.31596 6.49635 8.41111 6.38218 8.6014L6.19249 8.91754C5.93991 9.33851 5.49248 9.60414 5.00197 9.62434C4.51146 9.64453 4.0437 9.41658 3.75738 9.0178L3.04199 8.02146C2.99064 7.94995 2.96497 7.91419 2.92736 7.8949C2.88975 7.8756 2.84573 7.8756 2.75769 7.8756L1.88603 7.87559C1.63453 7.87558 1.50878 7.87558 1.45819 7.96269C1.40759 8.0498 1.46788 8.15548 1.58846 8.36685C2.2106 9.45742 3.18686 10.5632 4.58832 11.6005C5.43495 12.2275 6.05634 12.6877 6.98387 12.6877C7.91141 12.6877 8.53279 12.2275 9.37943 11.6005C11.8175 9.79586 12.9688 7.78416 13.2073 6.00548C13.4447 4.23535 12.7682 2.69472 11.5658 1.95717Z" fill="#8F9AA3"/>
<path d="M7.20469 4.97105C7.10463 4.78727 6.91379 4.67117 6.70458 4.66679C6.49537 4.66242 6.29984 4.77044 6.19218 4.94988L4.8987 7.10568L4.50819 6.5618C4.50002 6.55043 4.49145 6.53935 4.48248 6.52859C4.47338 6.51766 4.4634 6.50547 4.45255 6.49222C4.32787 6.33991 4.08822 6.04716 3.74091 5.92081C3.49697 5.83206 3.23003 5.83265 2.965 5.83324L2.90072 5.83333H1.73405C1.41188 5.83333 1.15072 6.0945 1.15072 6.41667C1.15072 6.73883 1.41188 7 1.73405 7H2.90072C3.27245 7 3.31696 7.00823 3.34111 7.01684C3.34329 7.01792 3.36229 7.02776 3.40145 7.06546C3.45005 7.11226 3.4979 7.16947 3.57276 7.25931L4.46854 8.50689C4.58307 8.6664 4.77018 8.75758 4.96638 8.74951C5.16258 8.74143 5.34156 8.63518 5.44259 8.46679L6.66782 6.42473L7.16648 7.34054C7.17206 7.35078 7.17794 7.36086 7.18412 7.37075L7.20842 7.40983C7.30282 7.56206 7.41744 7.74688 7.59523 7.88343C7.98366 8.18176 8.4448 8.17225 8.67006 8.16761C8.69423 8.16711 8.71569 8.16667 8.73405 8.16667H9.31738C9.63955 8.16667 9.90072 7.9055 9.90072 7.58333C9.90072 7.26117 9.63955 7 9.31738 7H8.73405C8.69863 7 8.66723 7.00017 8.63892 7.00032C8.53614 7.00086 8.47421 7.00119 8.40933 6.99253C8.35288 6.98499 8.32768 6.97346 8.31135 6.96218C8.30864 6.95892 8.30403 6.95313 8.29726 6.94384C8.27206 6.90926 8.24113 6.86063 8.18271 6.76722L7.20469 4.97105Z" fill="#8F9AA3"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@ -1533,6 +1533,7 @@
"vatPercent": "ضريبة القيمة المضافة (15%)",
"proceedToPayment": "المتابعة للدفع",
"supportedSmartWatches": "كيف تعمل؟",
"smartwatchHowItWorks": "كيف تعمل الساعة الذكية",
"pleaseMakeSureSamsungWatchConnected": "يرجى التأكد من أن ساعة Samsung الخاصة بك متصلة بهاتفك، ومتزامنة ومحدثة بشكل نشط.",
"beforeSyncingDataFollowInstructions": "قبل مزامنة البيانات، يرجى التأكد من اتباع التعليمات بشكل صحيح.",
"viewWatchInstructions": "عرض تعليمات الساعة",
@ -1544,6 +1545,18 @@
"seconds": "ثواني",
"secs": "ثواني",
"noAllergiesDataFound": "لم يتم العثور على بيانات الحساسية...",
"allHealthData": "جميع البيانات الصحية",
"activityCalories": "سعرات النشاط",
"activityCaloriesDescription": "توفر حلقات النشاط مرجعًا بصريًا سريعًا لمدى نشاطك خلال كل يوم.",
"steps": "الخطوات",
"distanceCovered": "المسافة المقطوعة",
"distanceCoveredDescription": "المسافة المقطوعة على مدار اليوم",
"sleepScore": "مؤشر النوم",
"sleepScoreDescription": "يتتبع هذا عدد ساعات نومك خلال اليوم",
"bloodOxygen": "أكسجين الدم",
"bloodOxygenTrackingDescription": "يتتبع هذا مستوى أكسجين الدم لمراقبة السجل الصحي وتحديثه",
"bodyTemperature": "درجة حرارة الجسم",
"bodyTemperatureTrackingDescription": "يتتبع هذا درجة حرارة الجسم لمراقبة السجل الصحي وتحديثه",
"heartRateDescription": "معدل ضربات قلبك يشير إلى عدد المرات التي ينبض فيها قلبك في الدقيقة",
"bloodOxygenDescription": "مستوى الأكسجين في الدم يشير إلى كمية الأكسجين التي تحملها خلايا الدم الحمراء",
"stepsDescription": "عدد الخطوات المتخذة على مدار اليوم",
@ -1987,5 +2000,94 @@
"hide": "إخفاء",
"viewPatientQR": "عرض رمز الاستجابة السريعة للمريض",
"patientQR": "رمز الاستجابة السريعة للمريض",
"forText": "عن"
"forText": "عن",
"liveCareTermsHeading": "شروط خدمات الرعاية الصحية عن بُعد",
"liveCareTermsIntroHeading": "مقدمة",
"liveCareTermsConditions1": "تعتبر شركة مجموعة الدكتور سليمان الحبيب للخدمات الطبية ('المجموعة') واحدة من الشركات الرائدة في قطاع الرعاية الصحية في المملكة العربية السعودية والتي تسعى دائمًا لتحسين خدماتها في المنطقة، وكخطوة لنقل خدماتنا إلى مستوى آخر ولتسهيل عملية تلقي خدمات الرعاية الصحية، فقد اعتمدنا نهج تقديم بعض خدماتنا عن بُعد للمرضى. تنطبق هذه الشروط على خدمات الرعاية الصحية عن بُعد التي نقدمها، والتي تتيح إجراء الاستشارات بين الطبيب والمريض عبر الإنترنت، باستخدام تقنية الاتصالات الصوتية أو المرئية (يشار إليها غالباً باسم 'خدمات الرعاية الصحية عن بُعد').",
"liveCareTermsConditions2": "الغرض من خدمات الرعاية الصحية عن بعد هو تسهيل الاتصالات بين الممارسين الصحيين والمرضى لتقديم خدمات الرعاية الصحية من خلال وسائل الاتصال الإلكترونية المتقدمة، والتي تتيح للممارسين الصحيين تقييم وتشخيص وعلاج ومتابعة المرضى عن بُعد دون الحاجة إلى حضور المرضى شخصياً.",
"liveCareTermsHeading2": "الاتفاقية",
"liveCareTermsConditions3": "يتم تقديم خدمات الرعاية الصحية عن بُعد عبر تطبيق الهاتف المحمول أو الموقع الإلكتروني للمجموعة. تنطبق الشروط التالية على خدمات الرعاية الصحية عن بُعد: ",
"liveCareTermsConditions3a": "شروط استخدام الموقع الالكتروني - ",
"liveCareTermsConditions3b": "تفاقية مستخدم التطبيق - ",
"liveCareTermsConditions3c": "روط استخدام الخدمات الإلكترونية - ",
"liveCareTermsConditions3d": "شروط خدمات الرعاية الصحية عن بُعد هذه - ",
"liveCareTermsConditions4": "بالموافقة على الاستمرار في خدمات الرعاية الصحية عن بُعد وقبول هذه الشروط، فإنك تدخل في اتفاقية مع المجموعة تتضمن جميع الشروط المذكورة أعلاه (اتفاقية خدمات الرعاية الصحية عن بُعد).",
"liveCareTermsConditions5": "يتعين عليك أيضاً قراءة سياسة الخصوصية الخاصة بنا حيث تحتوي سياسة الخصوصية على تفاصيل حول كيفية استخدامنا لمعلوماتك الشخصية وحقوقك بشأنها. من خلال متابعة استخدام خدمات الرعاية الصحية عن بُعد، فإنك توافق على استخدامنا لمعلوماتك الشخصية وفقاً لسياسة الخصوصية الخاصة بنا وتوافق صراحةً على استخدامنا لمعلوماتك الشخصية لأداء خدمات الرعاية الصحية عن بُعد وأداء واجباتنا المهنية كمقدم لخدمات الرعاية الطبية.",
"liveCareTermsConditions6": "يتعين عليك أيضاً قراءة سياسة الخصوصية الخاصة بنا حيث تحتوي سياسة الخصوصية على تفاصيل حول كيفية استخدامنا لمعلوماتك الشخصية وحقوقك بشأنها. من خلال متابعة استخدام خدمات الرعاية الصحية عن بُعد، فإنك توافق على استخدامنا لمعلوماتك الشخصية وفقاً لسياسة الخصوصية الخاصة بنا وتوافق صراحةً على استخدامنا لمعلوماتك الشخصية لأداء خدمات الرعاية الصحية عن بُعد وأداء واجباتنا المهنية كمقدم لخدمات الرعاية الطبية.",
"liveCareTermsHeading3": "1.\tالتعاريف",
"liveCareTermsConditions7": "المجموعة تعني شركة مجموعة الدكتور سليمان الحبيب للخدمات الطبية والشركات التابعة لها.",
"liveCareTermsConditions8": "خدمات الرعاية الصحية عن بُعد تعني خدمة الرعاية الصحية عن بُعد التي تقدمها المجموعة، والتي تتيح الاستشارة والتشخيص والمتابعة عن بُعد بين المريض والطبيب، باستخدام التطبيق و/أو موقع الويب.",
"liveCareTermsConditions9": "خدماتنا تعني بعض الخدمات التي تقدمها المجموعة والتي تغطي استعراض السجلات الطبية للمرضى ونتائج الفحوصات الطبية، وتوفير التشخيصات الطبية بالإضافة إلى توفر خدمة الرعاية الصحية عن بعد بالصوت والفيديو بين ممارسي الرعاية الصحية والمرضى.",
"liveCareTermsConditions10": "التطبيق يعني تطبيق (Dr. ALHABIB) وهو عبارة عن منصة يتم من خلالها تقديم خدماتنا ويمكن للمستخدمين الولوج إليها.",
"liveCareTermsConditions11": "موقع الويب يعني موقع الويب الخاص بالمجموعة وهو عبارة عن منصة يتم من خلالها تقديم خدماتنا ويمكن للمستخدمين الدخول إليها.",
"liveCareTermsConditions12": "الشروط والأحكام تعني شروط خدمات الرعاية الصحية عن بُعد هذه.",
"liveCareTermsConditions13": "المحتوى يعني أي رسالة أو بيانات أو معلومات أو نص أو صوت أو صور أو فيديو أو رسومات أو رمز أو أي مادة أخرى واردة في التطبيق أو موقع الويب أو يتم نقلها عبر التطبيق أو موقع الويب.",
"liveCareTermsHeading4": "2.\tتعهدات المستخدم",
"liveCareTermsConditions14": "2-1\tمن خلال دخولك إلى خدمات الرعاية الصحية عن بُعد واستخدامها، فإنك توافق على هذه الشروط والأحكام ويتعين عليك ألا تحاول الدخول إلى خدماتنا إذا كنت لا توافق عليها.",
"liveCareTermsConditions15": "2-2\tأنت تضمن وتقر وتتعهد بأن جميع المعلومات التي تقدمها عن نفسك وعن أي شخص آخر صحيحة ودقيقة.",
"liveCareTermsConditions16": "2-3\tخدمات الرعاية الصحية عن بعد مخصصة للاستخدام من قبل المرضى الموجودين فعلياً في المملكة العربية السعودية (المنطقة المسموح بها) ولا ينبغي استخدامها من قبل المرضى خارج المنطقة المسموح بها. بالموافقة على هذه الشروط والأحكام والدخول إلى خدمات الرعاية الصحية عن بُعد عبر التطبيق أو موقع الويب، فإنك تقر وتضمن لنا أنك موجود فعلياً في إحدى المناطق المسموح بها.",
"liveCareTermsHeading5": "3.\tالقيود على خدمات الرعاية الصحية عن بعد والمخاطر المرتبطة بها",
"liveCareTermsConditions17": "3-1\tلا تستخدم التطبيق أو موقع الويب أو خدمات الرعاية الصحية عن بُعد للتواصل بشأن الحالات الطبية الطارئة أو علاجها. لا التطبيق ولا موقع الويب ولا خدمات الرعاية الصحية عن بُعد توفر الرعاية في الحالات الطبية الطارئة. إذا كانت هناك حالة طبية طارئة عاجلة أو كانت هناك حاجة إلى استجابة سريعة فيما يتعلق بصحتك، فانتقل إلى أقرب مركز/مستشفى طوارئ أو اتصل على الفور بأي رقم هاتف للطوارئ.",
"liveCareTermsConditions18": "3-2\tخدمات الرعاية الصحية عن بعد ليست مناسبة للحالات الطبية الطارئة وقد تكون هناك بعض العلاجات أو الأدوية التي لا يمكن تقديمها دون استشارة متابعة في حضور المريض شخصياً. إذا كنت تعتقد أن لديك حالة طبية خطيرة، فعليك طلب استشارة شخصية مع أخصائي طبي مرخص.",
"liveCareTermsConditions19": "3-3\tتهدف خدمات الرعاية الصحية عن بُعد إلى توفير مزايا تشمل راحة المريض. لذلك، فهو قد يكون الأنسب كبديل للاستشارة الشخصية للأمور الطبية الروتينية. ومع ذلك، هناك مخاطر محتملة مرتبطة باستخدام أي خدمة للرعاية الصحية عن بُعد، بما في ذلك خدمات الرعاية الصحية عن بُعد، وقد تشمل هذه المخاطر على سبيل المثال لا الحصر ما يلي:",
"liveCareTermsConditions19a": "(1) المعلومات المنقولة قد لا تكون كافية (مثل ضعف دقة الصور) للسماح باتخاذ القرار الطبي المناسب من قبل الممارسين الصحيين",
"liveCareTermsConditions19b": "(2) قد يقرر الممارسين الصحيين أن المعلومات المنقولة ليست ذات جودة كافية، مما يستلزم مقابلة المريض وجهاً لوجه، أو على الأقل إعادة جدولة استشارة طبية صوتية ومرئية في وقت لاحق",
"liveCareTermsConditions19c": "(3) يمكن أن يحدث تأخير في تقديم الرعاية الطبية بسبب أوجه القصور أو الأعطال في الأجهزة الإلكترونية",
"liveCareTermsConditions19d": "(4) يعتمد الممارس الصحي على المريض لتقديم جميع المعلومات ذات الصلة شفوياً وعبر الاستخدام المناسب لجهاز الكاميرا الخاص بالمريض. من الممكن ألا يتم تقديم المعلومات إلى الممارس أو قد لا تكون واضحة بقدر الوضوح الذي يتوفر للممارس الصحي أثناء إجراء الفحص البدني الشخصي",
"liveCareTermsConditions19e": "(5) قد تفشل البروتوكولات الأمنية، مما يتسبب في انتهاك خصوصية المعلومات الطبية الشخصية. على الرغم من أننا نتخذ تدابير معقولة لحماية أمن المعلومات المنقولة عبر التطبيق و/أو الموقع الإلكتروني، إلا أنه لا يمكن أبدًا ضمان أن تكون عمليات الإرسال هذه آمنة تماماً، والمعلومات المنقولة عبر شبكات الاتصالات العامة خارجة عن سيطرتنا ولا يمكننا تأمينها.",
"liveCareTermsConditions20": "3-4\tفي حال كنت تستخدم خدمات الرعاية الصحية عن بُعد ولكنك تواجه أي حالة أو مخاوف مستمرة، فإننا نوصيك بحجز استشارة شخصية.",
"liveCareTermsHeading6": "4.\tإخلاء المسؤولية عن الضمان",
"liveCareTermsConditions21": "4-1\tنحن لا نضمن ولا نقر أو نتعهد بأن خدمات الرعاية الصحية عن بُعد ستلبي احتياجاتك، أو أنها ستكون مستمرة دون انقطاع أو سيتم توفيرها في الوقت المناسب أو أنها آمنة أو خالية من الأخطاء أو خالية من الفيروسات. لن نتحمل أي مسؤولية تجاهك في حالة تعذر حدوث جلسة خدمات الرعاية الصحية عن بُعد أو تمت مقاطعتها أو التخلي عنها بسبب عدم توفر منصتنا عبر الإنترنت ومع ذلك، في حالة تعذر علينا إجراء جلسة خدمات الرعاية الصحية عن بُعد بالكامل بسبب تعطل منصتنا، فلن نتقاضى منك أي أجور عن جلسة الاستشارة البديلة.",
"liveCareTermsConditions22": "4-2\tتُستثنى جميع الضمانات الصريحة أو الضمنية بموجب النظام، باستثناء تلك التي لا يمكن استثناؤها بشكل قانوني.",
"liveCareTermsConditions23": "4-3\tلا يوجد في هذا القسم 4 أي نص يُقصد منه استبعاد أو تقييد مسؤوليتنا عن أي مطالبة تتعلق بالإهمال الطبي، إلى الحد الذي لا يسمح لنا فيه النظام المعمول به في المنطقة المسموح بها ذات الصلة بالقيام بذلك.",
"liveCareTermsHeading7": "5.\tالأهلية والتسجيل والاستخدام",
"liveCareTermsConditions24": "5-1\tمن أجل الدخول إلى خدمات الرعاية الصحية عن بُعد، يتعين عليك أن تفي بمتطلبات الحد الأدنى للسن وهو 18 عاماً (يتم احتسابها وفقاً للتقويم الميلادي) وأن تتمتع بالأهلية القانونية الكاملة.",
"liveCareTermsConditions25": "5-2\tيجب أن يحصل أي شخص يقل عمره عن 18 عاماً (يتم احتسابها وفقاً للتقويم الميلادي) يقوم بالدخول إلى خدمات الرعاية الصحية عن بُعد على إذن من أحد الوالدين أو الوصي للقيام بذلك.",
"liveCareTermsConditions26": "5-3\tأنت تضمن وتقر وتتعهد بأن لديك الحق القانوني والقدرة على الدخول إلى التطبيق و/أو موقع الويب وفقاً لهذه الشروط والأحكام و، عند الاقتضاء، إجراء الحجوزات والمدفوعات من خلال التطبيق أو موقع الويب.",
"liveCareTermsConditions27": "5-4\tتتم عملية التسجيل وفق ما ورد في شروط استخدام الخدمات الإلكترونية",
"liveCareTermsConditions28": "5-5\tخدمات الرعاية الصحية عن بُعد مخصصة فقط لاستخدامك الشخصي واستخدام أطفالك تحت إشرافك. يتعين عليك ألا تشارك بيانات تسجيل الدخول الخاصة بك (اسم المستخدم وكلمة المرور وما إلى ذلك) مع أي شخص آخر ويجب أن تتخذ خطوات معقولة للحفاظ على أمان هذه البيانات. يتم تقديم خدماتنا على أساس أن لدينا معلومات معينة حول المستخدم، والتي قد تكون مرتبطة أو تم الحصول عليها من تفاصيل حسابك (العمر والجنس والتاريخ الطبي وما إلى ذلك). نحن لا نتحمل أي مسؤولية من أي نوع تجاهك أو تجاه أي شخص آخر إذا تم تقديم خدماتنا عبر حساب مستخدم إلى شخص آخر غير المستخدم المسجل. هذا مهم بشكل خاص لخدمات الرعاية الصحية عن بعد، حيث سيحتاج الممارس الصحي إلى تقييم المعلومات التي يقدمها المريض أثناء الاستشارة في سياق الملف الطبي للمريض وتاريخه.",
"liveCareTermsConditions29": "5-6\tأنت مسؤول عن التأكد من أن لديك جهازاً متصلاً بالإنترنت وقادراً على إرسال واستقبال الفيديو والصوت. نحن لسنا مسؤولين عن أي انقطاع في جلسة خدمات الرعاية الصحية عن بعد بسبب ناجم عن جهازك أو اتصالك بالإنترنت. أنت مسؤول عن جميع التكاليف المرتبطة باتصالك بالإنترنت واستخدامك لها.",
"liveCareTermsConditions30": "5-7\tقد نقوم من وقت لآخر بإصدار تحديثات لتطبيقنا و/أو موقع الويب الخاص بنا. يجب عليك التأكد من أنك تقوم بتشغيل أحدث إصدار من التطبيق. قد يؤدي استخدام الإصدارات القديمة من التطبيق إلى حدوث أخطاء فنية أثناء استخدامك لخدمات الرعاية الصحية عن بُعد وقد يعرضك ذلك لمخاطر أمنية إضافية.",
"liveCareTermsHeading8": "6.\tخدمات الرعاية الصحية عن بُعد",
"liveCareTermsConditions31": "خدمات الرعاية الصحية عن بُعد الخاصة بنا سوف تكون لتخصصات طبية محددة أو لمواعيد المتابعة أو إعادة صرف الدواء. ",
"liveCareTermsHeading9": "7.\tالأجور والسداد",
"liveCareTermsConditions32": "خدمات الرعاية الصحية عن بُعد الخاصة بنا سوف تكون لتخصصات طبية محددة أو لمواعيد المتابعة أو إعادة صرف الدواء. ",
"liveCareTermsConditions33": "7-1\tستتم الإشارة إلى أجور استشارة خدمات الرعاية الصحية عن بُعد قبل أن تختار المتابعة. بمجرد المتابعة، فإنك توافق على سداد الأجور. لا تشمل تلك الأجور الأولية أي أجور لاحقة مثل أجور الوصفات الطبية والاختبارات المعملية واستشارات المتابعة وما إلى ذلك من أجور وسيتم إبلاغك بها بعد الاستشارة الأولية.",
"liveCareTermsConditions34": "7-2\tيتم تحديد شروط وطرق السداد المعمول بها في شروط استخدام الخدمات عبر الإنترنت الخاصة بنا.",
"liveCareTermsConditions35": "7-3\tقد يكون من الممكن فرض أجور خدمات الرعاية الصحية عن بُعد مباشرة على مزود التأمين الطبي، على الرغم من أننا لا نقدم أي تعهد أو ضمان بأن هذا سيكون ممكناً في أي وقت. تضمنت شروط استخدام الخدمات عبر الإنترنت الخاصة بنا مزيد من التفاصيل حول ذلك. إذا كان هذا التسهيل الخدمي متاحاً واخترت استخدامه، فستحتاج إلى تزويدنا بتفاصيل شركة التأمين الطبي وتغطية وثيقة التأمين، ما لم تكن قد قمت بذلك مسبقاً وربطتها بحسابك. أنت تفوضنا بموجب هذا بالتواصل مع أي شركة تأمين وفق التفاصيل التي تقدمها لنا في وقت الشراء أو المرتبطة بحسابك من أجل الحصول على الموافقة على تكلفة الخدمات المقدمة لك. أنت تقر بأنه قد يُطلب منا تقديم تفاصيل محددة عن الخدمات الطبية التي تطلبها من أجل القيام بذلك وتوافق صراحة على هذا الإفصاح.",
"liveCareTermsHeading10": "8.\tالاتصالات و/أو الاستفسارات",
"liveCareTermsConditions36": "في حال وجود أي أسئلة و/أو استفسارات بخصوص استخدام خدمات الرعاية الصحية عن بُعد، يرجى التواصل معنا على: EServices.HMG@drsulaimanalhabib.com أو الاتصال على الرقم: 9553 525 011",
"liveCareTermsHeading11": "9.\tحدود المسؤولية",
"liveCareTermsConditions37": "9-1\tمع مراعاة أي مسؤوليات ينص عليها النظام والتي لا يمكن استبعادها بموجبه، لا تتحمل المجموعة أو أي من مديرينا أو موظفينا أو وكلائنا أو مقاولينا المسؤولية تجاهك عن أي خسائر وأضرار ومسؤوليات ومطالبات ونفقات (بما في ذلك على سبيل المثال لا الحصر الأتعاب القانونية وتكاليف الدفاع أو التسوية) أيا كانت، سواء كانت مباشرة أو غير مباشرة أو تبعية، ناشئة عن أو متعلقة باستخدامك لخدمات الرعاية الصحية عن بُعد، أياً كان سبب نشوئها، سواء كان ذلك بموجب عقد أو المسؤولية التقصيرية (بما في ذلك الإهمال) أو النظام أو غير ذلك.",
"liveCareTermsConditions38": "9-2\tلن نكون مسؤولين تجاهك أو تجاه أي شخص آخر عن أي خسارة ناتجة عن سبب خارج عن سيطرتنا. يتضمن ذلك تعطل المعدات الإلكترونية أو الميكانيكية أو خطوط الاتصالات (بما في ذلك الهاتف والكابل والإنترنت)، أو الدخول غير المصرح به، أو أفعال أو إغفالات الأطراف الثالثة، أو الفيروسات، أو السرقة، أو أخطاء المشغل، أو الطقس القاسي أو غير العادي (بما في ذلك الفيضانات، أو الزلازل، أو أي من أفعال القضاء والقدر الأخرى)، أو الحرائق والحروب والتمرد والأعمال الإرهابية وأعمال شغب والنزاع العمالي أو المشاكل العمالية الأخرى أو الحوادث أو الطوارئ أو التأخير أو الحجز الزائد أو الإلغاء، أو الزوال الملكي أو أي إجراء حكومي.",
"liveCareTermsHeading12": "10.\tإنهاء الاستخدام",
"liveCareTermsConditions39": "10-1\tيجوز لنا التوقف عن توفير خدمات الرعاية الصحية عن بُعد في أي وقت ولأي سبب. لن نتحمل أي مسؤولية عن أي توقف، بما في ذلك عندما تكون خلال الاستشارات أو دورات العلاج باستخدام خدمات الرعاية الصحية عن بُعد. سنساعدك للتمكن من حجز الاستشارات الشخصية بدلاً من ذلك أو في نقل المعلومات ذات الصلة إلى مزود طبي بديل لتمكينك من مواصلة العلاج (مع مراعاة أنظمة حماية البيانات والسرية والممارسات الطبية والممارسات الطبية الجيدة السائدة).",
"liveCareTermsConditions40": "10-2\tيجوز لنا إنهاء استخدامك ودخولك إلى خدمات الرعاية الصحية عن بُعد لأي سبب أو بدون سبب، في أي وقت، سواء بإشعارك أو بدونه ودون تحمل أي مسؤولية تجاهك، ومع ذلك قد تنشأ هذه المسؤولية (على الرغم من أننا سنأخذ واجباتنا الطبية تجاهك بعين الاعتبار في حالة القيام بذلك).",
"liveCareTermsConditions41": "10-3\tستظل جميع القيود وجميع إخلاءات الطرف من المسؤولية والاستثناءات والقيود الخاصة بمسؤوليتنا سارية بعد أي إنهاء. عند الإنهاء، يتعين عليك عدم الدخول إلى أو استخدام التطبيق و/أو موقع الويب بشكل مباشر أو غير مباشر.",
"liveCareTermsHeading13": "11.\tالقانون الحاكم والاختصاص القضائي",
"liveCareTermsConditions42": "النظام المعمول به على التطبيق و/أو شروط وأحكام مستخدم موقع الويب والنزاعات الناشئة عنها أو المتعلقة بها هي أنظمة المملكة العربية السعودية. وأنت تخضع بشكل لا رجوع فيه للاختصاص القضائي الحصري لمحاكم المملكة العربية السعودية.",
"liveCareTermsHeading14": "12.\tالإقرارات",
"liveCareTermsConditions43": "12-1\tباستثناء ما هو منصوص عليه صراحةً في هذه الشروط والأحكام أو ما يسمح به أي نظام معمول به، فإنك توافق على ما يلي:",
"liveCareTermsConditions43a": "(1) أنك قد قرأت وفهمت هذه الشروط والأحكام والبنود الأخرى التي تشكل جزءاً من اتفاقيتك معنا",
"liveCareTermsConditions43b": "(2) أنك قد قرأت سياسة الخصوصية الخاصة بنا وتوافق بموجبه صراحة على استخدامنا لمعلوماتك الشخصية كما هو موضح فيها. بالإضافة إلى ذلك، أنت تدرك أن رقم الاتصال أو عنوان البريد الإلكتروني الذي زودتنا به عند التسجيل سيتم استخدامه للاتصالات من قبل المجموعة من خلال الرسائل القصيرة أو البريد الإلكتروني أو أي طريقة أخرى فيما يتعلق بخدمات الرعاية الصحية عن بُعد، بما في ذلك إشعارات المواعيد والخدمات الطبية الحالية.",
"liveCareTermsConditions43c": "(3) أنت تدرك أن لديك الحق في حجب أو سحب موافقتك بشأن استخدام التطبيق و/أو موقع الويب في سياق رعايتك في أي وقت، دون التأثير على حقك في تلقي الرعاية أو العلاج في المستقبل؛",
"liveCareTermsConditions43d": "(4) أنت تدرك أنك قد تتوقع الحصول على مزايا من استخدام التطبيق و/أو موقع الويب فيما يتعلق برعايتك الصحية، ولكن لا يمكن ضمان أي نتائج أو تأكيدها؛",
"liveCareTermsConditions43e": "(5) أنت تدرك أنه قد تتم مشاركة معلومات الرعاية الصحية الخاصة بك مع موظفين آخرين في المجموعة لأغراض جدولة المواعيد والفواتير؛",
"liveCareTermsConditions43f": "(6) أنت تدرك أن صور الفيديو والتسجيلات الصوتية الخاصة بك قد يتم التقاطها وتخزينها إلكترونياً. وأنت تدرك كذلك أنه يمكن استخدام هذه التسجيلات لاحقاً فيما يتعلق بالإجراءات النظامية إذا لزم الأمر ولكن لن يتم استخدامها لأي غرض بخلاف توفير خدمات الرعاية الصحية عن بُعد وخدمات المتابعة الطبية لك. أنت تقر وتوافق على استخدام هذه الصور والتسجيلات الصوتية من قبلنا للأغراض الموضحة؛",
"liveCareTermsConditions43g": "(7) أنك تدرك مخاطر الاتصال عبر البريد الإلكتروني والرسائل النصية، ولا سيما مخاطر الخصوصية. أنت تدرك أن المجموعة لا يمكنها ضمان أمان وسرية البريد الإلكتروني أو الاتصالات النصية. لن تكون المجموعة مسؤولة عن الرسائل التي لم يتم استلامها أو تسليمها بسبب عطل فني أو الكشف عن معلومات سرية ما لم يكن ذلك بسبب سوء سلوك متعمد.",
"liveCareTermsHeading15": "13.\tشروط وأحكام عامة",
"liveCareTermsConditions44": "13-1\tيجوز لنا في أي وقت تغيير هذه الشروط والأحكام لأسباب أمنية أو نظامية أو تنظيمية ، أو لتعكس التحديثات أو التغييرات التي تطرأ على خدمات أو وظائف خدمات الرعاية الصحية عن بُعد أو التطبيق، عن طريق نشر الشروط والأحكام المتنوعة على التطبيق. سنخطرك في التطبيق بأن هذه الشروط والأحكام قد تغيرت قبل استخدامك التالي لخدمات الرعاية الصحية عن بُعد وستتاح لك الفرصة للموافقة على الشروط المعدلة قبل استخدام الخدمة مرة أخرى.",
"liveCareTermsConditions45": "13-2\tيجوز لنا أداء أي من التزاماتنا، وممارسة أي من الحقوق الممنوحة لنا بموجب هذه الشروط والأحكام، من خلال طرف ثالث. يجوز لنا التنازل عن أي من حقوقنا والتزاماتنا أو جميعها بموجب هذه الشروط والأحكام إلى أي طرف ثالث.",
"liveCareTermsConditions46": "13-3\tإذا تبين أن أي بند أو جزء من أي بند من هذه الشروط والأحكام باطل أو غير قابل للإنفاذ أو غير صالح، فسيتم فصله عن هذه الشروط والأحكام، تاركاً باقي الشروط سارية المفعول بكامل الأثر والنفاذ، بشرط ألا يغير فصل ذلك البند من الطبيعة الأساسية لهذه الشروط والأحكام.",
"liveCareTermsHeading16": "14.\tالشكاوى",
"liveCareTermsConditions47": "خدمات الرعاية الصحية عن بُعد الخاصة بنا سوف تكون لتخصصات طبية محددة أو لمواعيد المتابعة أو إعادة صرف الدواء. ",
"liveCareTermsConditions48": "إذا كانت لديك أي شكاوى أو مخاوف بشأن التطبيق و/أو موقع الويب أو خدماتنا أو كيفية تعاملنا مع معلوماتك الشخصية، فيرجى التواصل معنا على: EServices.HMG@drsulaimanalhabib.com أو الاتصال على الرقم: 9553 525 011",
"importantNotice": "تنبيه هام",
"appDecommissionedText": "تم إيقاف هذا الإصدار من تطبيق الحبيب الطبي.\nللاستمرار في الاستفادة من الخدمات الصحية والسجلات الطبية، يرجى تحميل التطبيق الجديد.",
"appDecommissionedSubText": "نعتذر بشدة عن الإزعاج الناتج عن هذا الانتقال.",
"downloadApp": "حمل التطبيق",
"unread": "غير مقروء",
"read": "مقروءة",
"pendingMedicalReportRequest": "لديك بالفعل طلب معلّق للحصول على تقرير طبي خاص بهذا الموعد. يرجى الانتظار حتى اكتمال الطلب قبل تقديم طلب جديد.",
"AllergyReactions": "ردود الفعل التحسسية"
}

@ -1526,6 +1526,7 @@
"vatPercent": "VAT (15%)",
"proceedToPayment": "Proceed to Payment",
"supportedSmartWatches": "Supported Smart Watches",
"smartwatchHowItWorks": "How does it work",
"pleaseMakeSureSamsungWatchConnected": "Please make sure that your Samsung Watch is connected to your Phone, is actively synced & updated.",
"beforeSyncingDataFollowInstructions": "Before syncing data, please make sure that you have followed the instructions properly.",
"viewWatchInstructions": "View watch instructions",
@ -1537,6 +1538,18 @@
"seconds": "Seconds",
"secs": "Secs",
"noAllergiesDataFound": "No allergies data found...",
"allHealthData": "All Health Data",
"activityCalories": "Activity Calories",
"activityCaloriesDescription": "Activity rings give you a quick visual reference of how active you are each day.",
"steps": "Steps",
"distanceCovered": "Distance Covered",
"distanceCoveredDescription": "Distance covered throughout the day",
"sleepScore": "Sleep Score",
"sleepScoreDescription": "This keeps track of how many hours you sleep in a day",
"bloodOxygen": "Blood Oxygen",
"bloodOxygenTrackingDescription": "This tracks your blood oxygen to monitor and update your health history",
"bodyTemperature": "Body Temperature",
"bodyTemperatureTrackingDescription": "This tracks your body temperature to monitor and update your health history",
"heartRateDescription": "Your heart rate indicates how many times your heart beats per minute",
"bloodOxygenDescription": "Blood oxygen level indicates how much oxygen your red blood cells are carrying",
"stepsDescription": "Number of steps taken throughout the day",
@ -1978,7 +1991,96 @@
"hide": "Hide",
"viewPatientQR": "View Patient QR Code",
"patientQR": "Patient QR Code",
"forText": "For"
"forText": "For",
"liveCareTermsHeading": "TELEHEALTH SERVICES TERMS OF USE",
"liveCareTermsIntroHeading": "INTRODUCTION",
"liveCareTermsConditions1": "Dr. Sulaiman Al Habib Medical Services Group Company (the “Group”) is one of the leaders in the healthcare sector in the Kingdom of Saudi Arabia with an aim to always improve its services in the region, and as a step to take our services to another level and to facilitate the process of receiving healthcare services we have adopted the approach of providing some of our services remotely to patients. These terms apply to our Telehealth Services, which enable consultations to occur between a doctor and a patient over the internet, using audio or and video conferencing technology (often referred to as “Telehealth Services”).",
"liveCareTermsConditions2": "The purpose of the Telehealth Services is to facilitate communication between healthcare practitioners and patients to provide healthcare services through advanced electronic communication means, which allows healthcare professionals to evaluate, diagnose, treat and follow-up with patients remotely without the need for patients to attend in person.).",
"liveCareTermsHeading2": "AGREEMENT",
"liveCareTermsConditions3": "Telehealth Services is delivered over the Group’s mobile application or and Website. The following terms apply to the Telehealth Services: ",
"liveCareTermsConditions3a": " - Website Terms of Use",
"liveCareTermsConditions3b": " - App User Agreement",
"liveCareTermsConditions3c": " - Online Services Terms of Use",
"liveCareTermsConditions3d": " - These Telehealth Services User Terms of Use",
"liveCareTermsConditions4": "By agreeing to proceed with the Telehealth Services and accepting these terms, you enter into an agreement with The Group incorporating all the above terms (Telehealth Services Agreement).",
"liveCareTermsConditions5": "Our Privacy Policy should also be read. It contains details about how we use your personal information and your rights. By proceeding with the Telehealth Services, you agree to our use of your personal information in accordance with our Privacy Policy and you expressly consent to our use of your personal information for the performance of the Telehealth Services and the discharge of our professional duties as a medical care provider.",
"liveCareTermsConditions6": "Our Privacy Policy should also be read. It contains details about how we use your personal information and your rights. By proceeding with the Telehealth Services, you agree to our use of your personal information in accordance with our Privacy Policy and you expressly consent to our use of your personal information for the performance of the Telehealth Services and the discharge of our professional duties as a medical care provider.",
"liveCareTermsHeading3": "1. DEFINITIONS",
"liveCareTermsConditions7": "Group means Dr. Sulaiman Al Habib Medical Services Group Company and its subsidiaries. ",
"liveCareTermsConditions8": "Telehealth Services means the Group’s telehealth service, enabling remote consultation, diagnosis and follow-up between the patient and doctor, using the Application and or the Website.",
"liveCareTermsConditions9": "Our Services means certain services provided by the Group which covers viewing patients’ medical records and medical test results, providing medical diagnostics in addition to the availability of voice and video Telehealth Service between healthcare practitioners and patients.",
"liveCareTermsConditions10": "Application means Dr. ALHABIB Application which is a platform where Our Services are provided through and accessible by users. ",
"liveCareTermsConditions11": "Website means the Group internet website which is a platform where Our Services are provided through and accessible by users. ",
"liveCareTermsConditions12": "Terms & Conditions means these Telehealth Services Terms of Use. ",
"liveCareTermsConditions13": "Content means any message, data, information, text, sound, photos, video, graphics, code or any other material contained on the Application and or the Website or transmitted via the Application and or the Website. ",
"liveCareTermsHeading4": "2. USER UNDERTAKINGS",
"liveCareTermsConditions14": "2.1 By accessing and using Telehealth Services, you agree to these Terms & Conditions, and you should not attempt to access Our Services if you do not agree. ",
"liveCareTermsConditions15": "2.2 You warrant, represent and undertake that all information you provide about yourself and about anyone else is true and accurate. ",
"liveCareTermsConditions16": "2.3 Telehealth Services is intended for use by patients physically located in the Kingdom Saudi Arabia (Permitted Territory) and should not be used by patients outside the Permitted Territory. By agreeing to these Terms & Conditions and accessing Telehealth Services via the Application and or the Website, you represent and warrant to us that you are physically located in one of the Permitted Territory. ",
"liveCareTermsHeading5": "3. LIMITATIONS OF TELEHEALTH SERVICES AND ASSOCIATED RISKS",
"liveCareTermsConditions17": "3.1 Do not use the Application and or the Website or the Telehealth Services to communicate or treat medical emergencies. Neither the Application nor the Website nor Telehealth Services are intended for the provision of care in an emergency. IF THERE IS AN URGENT MEDICAL EMERGENCY OR A RESPONSE IS NEEDED QUICKLY REGARDING YOUR HEALTH, GO TO A NEARBY EMERGENCY CENTER/HOSPITAL OR CALL IMMEDIATELY ANY EMERGENCY PHONE NUMBER. ",
"liveCareTermsConditions18": "3.2 Telehealth Services is not appropriate for emergency conditions and there may be some treatments or medicines which cannot be provided without follow-up physical consultation. If you believe you have a serious medical condition, you should seek an in-person consultation with a licensed medical professional.",
"liveCareTermsConditions19": "3.3 Telehealth Services is intended to provide benefits including patient convenience. As such, it is most suitable as an alternative to in-person consultation for routine medical matters. However, there are potential risks associated with the use of any telehealth service, including Telehealth Services, and these risks may include but not be limited to the following: ",
"liveCareTermsConditions19a": "(a) information transmitted may not be sufficient (e.g. poor resolution of images) to allow for appropriate medical decision making by healthcare practitioners.",
"liveCareTermsConditions19b": "(b) healthcare practitioners may determine that the transmitted information is of inadequate quality, thus necessitating a face-to-face meeting with the patient, or at least a rescheduled voice and video medical consult. ",
"liveCareTermsConditions19c": "(c) delays in medical care could occur due to deficiencies or failures of the electronic devices. ",
"liveCareTermsConditions19d": "(d) the practitioner is dependent on the patient to provide all relevant information orally and via the appropriate use of the patient’s own camera device. It is possible that information may not be provided to the practitioner or may not be apparent which would have been apparent to the practitioner during an in-person physical examination. ",
"liveCareTermsConditions19e": "(e) security protocols could fail, causing a breach of privacy of personal medical information. Whilst we take reasonable measures to protect the security of the information transmitted over the Application and or the Website, such transmissions can never be guaranteed to be completely secure and information transmitted over public telecommunications networks is outside our control and cannot be secured by us.",
"liveCareTermsConditions20": "3.4 If you use Telehealth Services but are experiencing any ongoing condition or concerns, we recommend you schedule an in-person consultation. ",
"liveCareTermsHeading6": "4. DISCLAIMER OF WARRANTY ",
"liveCareTermsConditions21": "4.1 We do not warrant, represent or undertake that Telehealth Services will meet your needs, or that it will be uninterrupted, timely, secure, error-free or free from viruses. We shall have no liability to you if a Telehealth Services session cannot occur or is interrupted or abandoned due to any unavailability of our online platform, however, where the Telehealth Services session cannot be delivered fully due to the downtime of our own platform, we will not charge you for a replacement consultation.",
"liveCareTermsConditions22": "4.2 All warranties expressed or implied by law, except those that cannot be lawfully excluded, are excluded. ",
"liveCareTermsConditions23": "4.3 Nothing in this section 4 is intended to exclude or limit our liability for any medical negligence claim, to the extent the applicable law in the relevant Permitted Territory does not permit us to do so.",
"liveCareTermsHeading7": "5. ELIGIBILITY, REGISTRATION AND USE",
"liveCareTermsConditions24": "5.1 To access Telehealth Services, you must satisfy the minimum age requirement of 18 years (measured according to the Gregorian calendar) and have full legal capacity. ",
"liveCareTermsConditions25": "5.2 Any person under the age of 18 years (measured according to the Gregorian calendar) accessing Telehealth Services must have permission from their parent or guardian to do so.",
"liveCareTermsConditions26": "5.3 You warrant, represent and undertake that you possess the legal right and ability to access the Application and or the Website in accordance with these Terms & Conditions and, where relevant, to make bookings and payments through the Application and or the Website.",
"liveCareTermsConditions27": "5.4 The registration process is as provided in the Online Services Terms of Use.",
"liveCareTermsConditions28": "5.5 Telehealth Services is intended only for your own personal use and the use of your children under your supervision. You must not share your user access details (log-in name, password etc.) with any other person and must take reasonable steps to maintain the security of such details. Our services are delivered on the basis that we have certain information about the user, which may be connected to or obtained from your account details (age, gender, medical history etc.). We accept no responsibility whatsoever to you or any other person if our services are delivered via a user account to a person other than the registered user. This is particularly important for telehealth services, where the practitioner will need to assess the information, the patient provides during the consultation in the context of the patient’s medical file and history.",
"liveCareTermsConditions29": "5.6 You are responsible for ensuring you have a device connected to the internet and capable of transmitting and receiving video and sound. We are not responsible for any failure of a Telehealth Services session caused by your device or your internet connection. You are responsible for all costs associated with your own internet connection and use.",
"liveCareTermsConditions30": "5.7 From time to time we may release updates to our Application and or the Website. You should ensure that you are running the latest version of the Application. Use of old versions of the Application may lead to technical errors in your use of the Telehealth Services and may expose you to additional security risks.",
"liveCareTermsHeading8": "6. TELEHEALTH SERVICES",
"liveCareTermsConditions31": "Our Telehealth Services will be for specific medical specialties or follow-up or medication refill appointments.",
"liveCareTermsHeading9": "7. CHARGES AND PAYMENT",
"liveCareTermsConditions32": "Our Telehealth Services will be for specific medical specialties or follow-up or medication refill appointments.",
"liveCareTermsConditions33": "7.1 The charges for a Telehealth Services consultation will be indicated before you choose to proceed. By proceeding, you agree to pay the charges. Any subsequent charges, such as prescription charges, lab tests, follow-up consultations etc. are excluded from the initial charge and will be communicated to you following the initial consultation. ",
"liveCareTermsConditions34": "7.2 The applicable payment terms and methods are set out in our Online Services Terms of Use. ",
"liveCareTermsConditions35": "7.3 It may be possible to charge Telehealth Services directly to a provider of medical insurance, although we give no undertaking or warranty that this shall be possible at any given time. Further details are set out in our Online Services Terms of Use. If such facility is made available and you choose to use it, you will need to provide us with details of your medical insurer and policy coverage, unless you have already done so and linked them to your account. You hereby authorise us to contact any such insurer with the details you provide at the time of purchase, or which are linked to your account to seek approval of the cost of your services. You acknowledge that we may be required to provide specific details of the medical services sought by you to do so and you expressly consent to such disclosure.",
"liveCareTermsHeading10": "8. COMMUNICATION AND/OR INQUIRIES",
"liveCareTermsConditions36": "In case there are any questions and/or inquiries regarding the use of Telehealth Services please contact: EServices.HMG@drsulaimanalhabib.com or call 011 525 9553",
"liveCareTermsHeading11": "9. LIMITATION OF LIABILITY ",
"liveCareTermsConditions37": "9.1 Subject to any responsibilities implied by law and which cannot be excluded, neither the Group nor any of our directors, employees, agents or contractors, are liable to you for any losses, damages, liabilities, claims and expenses (including without limitation but not limited to legal costs and defense or settlement costs) whatsoever, whether direct, indirect or consequential, arising out of or referable to your use of Telehealth Services , however caused, whether in contract, tort (including negligence), statute or otherwise. ",
"liveCareTermsConditions38": "9.2 We will not be liable to you or anyone else for any loss resulting from a cause over which we do not have control. This includes failure of electronic or mechanical equipment or communications lines (including telephone, cable and Internet), unauthorized access, acts or omissions of third parties, viruses, theft, operator errors, severe or extraordinary weather (including flood, earthquake, or other act of God), fire, war, insurrection, terrorist act, riot, labor dispute or other labor problems, accident, emergency, delay, overbooking, cancellation, Royal demise or action of government",
"liveCareTermsHeading12": "10. TERMINATION OF USE",
"liveCareTermsConditions39": "10.1 We may discontinue the provision of Telehealth Services at any time and for any reason. We shall have no liability for any discontinuation, including where you are part-way through a series of consultations or courses of treatment using Telehealth Services. We will assist in enabling you to book in-person consultations instead or in transferring relevant information to an alternative medical provider to enable you to continue treatment (subject to data protection, confidentiality and medical practice laws and to prevailing medical good practice).",
"liveCareTermsConditions40": "10.2 We may terminate your use and access to Telehealth Services for any or no reason, at any time, with or without notice to you and without incurring any liability to you, however that liability may arise (although we will consider our medical duties to you, if doing so). ",
"liveCareTermsConditions41": "10.3 All restrictions and all disclaimers and exclusions and limitations of our liability will survive any termination. Upon termination, you must not directly or indirectly access or use the Application and or the Website.",
"liveCareTermsHeading13": "11. GOVERNING LAW AND JURISDICTION ",
"liveCareTermsConditions42": "The law applicable to the Application and or the Website User Terms and Conditions and to disputes arising out of or in connection with them are the laws of The Kingdom of Saudi Arabia. You irrevocably submit to the exclusive jurisdiction of the courts of the Kingdom of Saudi Arabia. ",
"liveCareTermsHeading14": "12. ACKNOWLEDGEMENTS",
"liveCareTermsConditions43": "12.1 Except as expressly set out in these Terms & Conditions or as permitted by any applicable law, you agree on the following: ",
"liveCareTermsConditions43a": "(a) you have read and understand these Terms & Conditions and the other terms forming part of your Agreement with us; ",
"liveCareTermsConditions43b": "(b) you have read our Privacy Policy and hereby expressly consent to our use of your personal information as described. In addition, you understand that the contact number or email address that you have provided on registration will be used for communications by the Group through SMS, email or any other method in connection with the Telehealth Services, including for appointment notifications and current medical services;",
"liveCareTermsConditions43c": "(c) you understand that you have the right to withhold or withdraw your consent to the use of the Application and or the Website in the course of your care at any time, without affecting your right to future care or treatment; ",
"liveCareTermsConditions43d": "(d) you understand that you may expect to receive benefits from the use of Application and or the Website concerning your healthcare, but that no results can be guaranteed or assured; ",
"liveCareTermsConditions43e": "(e) you understand that your healthcare information may be shared with other employees in the Group for scheduling and billing purposes;",
"liveCareTermsConditions43f": "(f) you understand that video images and audio recordings of you may be captured and stored electronically. You understand that these recordings may be later used in connection with legal proceedings if necessary but will not otherwise be used for any purpose other than providing Telehealth Services and follow-up medical services to you. You acknowledge and consent to the use of these images and audio recordings by us for the purposes described; ",
"liveCareTermsConditions43g": "(g) you understand the risks of communicating by email and text messages, particularly the privacy risks. You understand that the Group cannot guarantee the security and confidentiality of email or text communication. The Group will not be responsible for messages that are not received or delivered due to technical failure, or for disclosure of confidential information unless caused by intentional misconduct.",
"liveCareTermsHeading15": "13. GENERAL TERMS AND CONDITIONS ",
"liveCareTermsConditions44": "13.1 We may at any time vary these Terms & Conditions for security, legal or regulatory reasons, or to reflect updates or changes to the services or functionality of Telehealth Services or the Application, by publishing the varied Terms & Conditions on the Application. We will notify you on the Application that these Terms & Conditions have changed before your next use of the Telehealth Services and you will have the opportunity to agree to the revised terms before using the service again. ",
"liveCareTermsConditions45": "13.2 We may perform any of our obligations, and exercise any of the rights granted to us under these Terms & Conditions, through a third party. We may assign any or all our rights and obligations under these Terms & Conditions to any third party.",
"liveCareTermsConditions46": "13.3 If any clause or part of any clause of these Terms & Conditions is found to be void, unenforceable or invalid, then it will be severed from these Terms & Conditions, leaving the remainder in full force and effect, provided that the severance has not altered the basic nature of these Terms & Conditions. ",
"liveCareTermsHeading16": "14. COMPLAINTS",
"liveCareTermsConditions47": "Our Telehealth Services will be for specific medical specialties or follow-up or medication refill appointments.",
"liveCareTermsConditions48": "If you have any complaints or concerns about the Application and or the Website, Our Services, or how we handle your personal information please contact us on: EServices.HMG@drsulaimanalhabib.com or call 011 525 9553",
"importantNotice": "Important Notice",
"appDecommissionedText": "This version of our healthcare application has been officially discontinued. To ensure uninterrupted access to your clinical records, we are transitioning all patients back to our main platform.",
"appDecommissionedSubText": "We sincerely apologize for the inconvenience of this transition.",
"downloadApp": "Download App",
"unread": "Unread",
"read": "Read",
"pendingMedicalReportRequest": "You already have a pending medical report request for this appointment. Please wait for the request to be completed before submitting a new one.",
"allergyReactions": "Allergy Reactions"
}

@ -20,7 +20,5 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
</dict>
</plist>

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt</string>
<key>ANDROID_CLIENT_ID</key>
<string>815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com</string>
<key>API_KEY</key>
@ -11,11 +15,11 @@
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.cloudsolutions.HMGPatientApp</string>
<string>com.HMG.HMG-Smartphone</string>
<key>PROJECT_ID</key>
<string>api-project-815750722565</string>
<key>STORAGE_BUCKET</key>
<string>api-project-815750722565.firebasestorage.app</string>
<string>api-project-815750722565.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
@ -27,7 +31,7 @@
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:815750722565:ios:34ec03c09e02e21f3c186c</string>
<string>1:815750722565:ios:328ec247a81a2ca23c186c</string>
<key>DATABASE_URL</key>
<string>https://api-project-815750722565.firebaseio.com</string>
</dict>

@ -58,8 +58,8 @@ post_install do |installer|
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=1',
]
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386 x86_64'
build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
build_configuration.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
xcconfig_path = build_configuration.base_configuration_reference.real_path
xcconfig = File.read(xcconfig_path)

@ -3,29 +3,39 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
094EF77E011152A3DF3536B2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30E602807D9C203A2FA83417 /* Pods_Runner.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
37D27FAF2C38AC83B852680C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A83C76CFF9D3F92EDE3B22B4 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
478CFA942E638C8E0064F3D7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */; };
61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */; };
61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */; };
61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B452EC5FA3700D46FA0 /* PenguinView.swift */; };
61243B542EC5FA3700D46FA0 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */; };
61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */; };
61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
7676C293308F37EA004CF793 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C291308F37EA004CF793 /* PenguinViewFactory.swift */; };
7676C294308F37EA004CF793 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C290308F37EA004CF793 /* PenguinView.swift */; };
7676C295308F37EA004CF793 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C28D308F37EA004CF793 /* PenguinModel.swift */; };
7676C296308F37EA004CF793 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C28E308F37EA004CF793 /* PenguinNavigator.swift */; };
7676C297308F37EA004CF793 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C28F308F37EA004CF793 /* PenguinPlugin.swift */; };
7676C2A9308F394F004CF793 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */; };
7676C2AA308F394F004CF793 /* HMG_Geofence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A3308F394F004CF793 /* HMG_Geofence.swift */; };
7676C2AB308F394F004CF793 /* LocalizedFromFlutter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */; };
7676C2AC308F394F004CF793 /* GlobalHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A2308F394F004CF793 /* GlobalHelper.swift */; };
7676C2AD308F394F004CF793 /* HMGPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */; };
7676C2AE308F394F004CF793 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C29E308F394F004CF793 /* API.swift */; };
7676C2AF308F394F004CF793 /* FlutterConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A0308F394F004CF793 /* FlutterConstants.swift */; };
7676C2B0308F394F004CF793 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C29F308F394F004CF793 /* Extensions.swift */; };
7676C2B1308F394F004CF793 /* GeoZoneModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A1308F394F004CF793 /* GeoZoneModel.swift */; };
7676C2B2308F394F004CF793 /* OpenTokPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */; };
7676C2C5308F3D02004CF793 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2BF308F3C52004CF793 /* Penguin.xcframework */; };
7676C2C6308F3D02004CF793 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2BF308F3C52004CF793 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7676C2C7308F3D03004CF793 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */; };
7676C2C8308F3D03004CF793 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7676C2C9308F3D04004CF793 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */; };
7676C2CA308F3D04004CF793 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76AA18AE2F3B2A4D00DC8DFC /* ring_30Sec.caf in Resources */ = {isa = PBXBuildFile; fileRef = 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */; };
76B1D2512F91BF8000DBBD1B /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */; };
76B1D2522F91BF8000DBBD1B /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76B1D2532F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */; };
76B1D2542F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76B1D2552F91BF8000DBBD1B /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */; };
76B1D2562F91BF8000DBBD1B /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
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 */; };
@ -48,40 +58,62 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
76B1D2542F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Embed Frameworks */,
76B1D2522F91BF8000DBBD1B /* Penguin.xcframework in Embed Frameworks */,
76B1D2562F91BF8000DBBD1B /* PenNavUI.xcframework in Embed Frameworks */,
7676C2C8308F3D03004CF793 /* PenguinINRenderer.xcframework in Embed Frameworks */,
7676C2C6308F3D02004CF793 /* Penguin.xcframework in Embed Frameworks */,
7676C2CA308F3D04004CF793 /* PenNavUI.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
76B714E4300E58B2004DE37A /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
05E1B2A0E6844572ADA81174 /* 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>"; };
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>"; };
30E602807D9C203A2FA83417 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3EAE1F31D8D0AA94CA6C11EB /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = "<group>"; };
61243B422EC5FA3700D46FA0 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = "<group>"; };
61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = "<group>"; };
61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = "<group>"; };
61243B452EC5FA3700D46FA0 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = "<group>"; };
61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = "<group>"; };
4D6281A38B453C42FAC24BD5 /* 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>"; };
7676C28D308F37EA004CF793 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = "<group>"; };
7676C28E308F37EA004CF793 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = "<group>"; };
7676C28F308F37EA004CF793 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = "<group>"; };
7676C290308F37EA004CF793 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = "<group>"; };
7676C291308F37EA004CF793 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = "<group>"; };
7676C29E308F394F004CF793 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
7676C29F308F394F004CF793 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
7676C2A0308F394F004CF793 /* FlutterConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterConstants.swift; sourceTree = "<group>"; };
7676C2A1308F394F004CF793 /* GeoZoneModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoZoneModel.swift; sourceTree = "<group>"; };
7676C2A2308F394F004CF793 /* GlobalHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalHelper.swift; sourceTree = "<group>"; };
7676C2A3308F394F004CF793 /* HMG_Geofence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMG_Geofence.swift; sourceTree = "<group>"; };
7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = "<group>"; };
7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPlatformBridge.swift; sourceTree = "<group>"; };
7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedFromFlutter.swift; sourceTree = "<group>"; };
7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = "<group>"; };
7676C2BF308F3C52004CF793 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = "<group>"; };
7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = "<group>"; };
7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = "<group>"; };
769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = "<group>"; };
76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ring_30Sec.caf; sourceTree = "<group>"; };
76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = "<group>"; };
76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = "<group>"; };
76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = "<group>"; };
76B714CF300E58B1004DE37A /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
76B714D1300E58B1004DE37A /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7BEF44ABFEF585D64D3F266C /* 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>"; };
8522EA4C54B9CA21B71F91CC /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -89,7 +121,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A83C76CFF9D3F92EDE3B22B4 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9C0E63FC9D84AA7D3BB0A547 /* 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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -97,10 +129,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
76B1D2512F91BF8000DBBD1B /* Penguin.xcframework in Frameworks */,
76B1D2552F91BF8000DBBD1B /* PenNavUI.xcframework in Frameworks */,
76B1D2532F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Frameworks */,
37D27FAF2C38AC83B852680C /* Pods_Runner.framework in Frameworks */,
7676C2C5308F3D02004CF793 /* Penguin.xcframework in Frameworks */,
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
7676C2C7308F3D03004CF793 /* PenguinINRenderer.xcframework in Frameworks */,
7676C2C9308F3D04004CF793 /* PenNavUI.xcframework in Frameworks */,
094EF77E011152A3DF3536B2 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -118,40 +152,58 @@
61243B412EC5FA3700D46FA0 /* Helper */ = {
isa = PBXGroup;
children = (
61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */,
);
path = Helper;
sourceTree = "<group>";
};
61243B472EC5FA3700D46FA0 /* Penguin */ = {
766D8CB22EC60BE600D05E07 /* Frameworks */ = {
isa = PBXGroup;
children = (
61243B422EC5FA3700D46FA0 /* PenguinModel.swift */,
61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */,
61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */,
61243B452EC5FA3700D46FA0 /* PenguinView.swift */,
61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */,
7676C2BF308F3C52004CF793 /* Penguin.xcframework */,
7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */,
7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */,
76B714CF300E58B1004DE37A /* WidgetKit.framework */,
76B714D1300E58B1004DE37A /* SwiftUI.framework */,
30E602807D9C203A2FA83417 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
7676C292308F37EA004CF793 /* Penguin */ = {
isa = PBXGroup;
children = (
7676C28D308F37EA004CF793 /* PenguinModel.swift */,
7676C28E308F37EA004CF793 /* PenguinNavigator.swift */,
7676C28F308F37EA004CF793 /* PenguinPlugin.swift */,
7676C290308F37EA004CF793 /* PenguinView.swift */,
7676C291308F37EA004CF793 /* PenguinViewFactory.swift */,
);
path = Penguin;
sourceTree = "<group>";
};
766D8CB22EC60BE600D05E07 /* Frameworks */ = {
7676C2A8308F394F004CF793 /* Helper */ = {
isa = PBXGroup;
children = (
76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */,
76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */,
76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */,
A83C76CFF9D3F92EDE3B22B4 /* Pods_Runner.framework */,
7676C29E308F394F004CF793 /* API.swift */,
7676C29F308F394F004CF793 /* Extensions.swift */,
7676C2A0308F394F004CF793 /* FlutterConstants.swift */,
7676C2A1308F394F004CF793 /* GeoZoneModel.swift */,
7676C2A2308F394F004CF793 /* GlobalHelper.swift */,
7676C2A3308F394F004CF793 /* HMG_Geofence.swift */,
7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */,
7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */,
7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */,
7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */,
);
name = Frameworks;
path = Helper;
sourceTree = "<group>";
};
79DD2093A1D9674C94359FC8 /* Pods */ = {
isa = PBXGroup;
children = (
3EAE1F31D8D0AA94CA6C11EB /* Pods-Runner.debug.xcconfig */,
05E1B2A0E6844572ADA81174 /* Pods-Runner.release.xcconfig */,
7BEF44ABFEF585D64D3F266C /* Pods-Runner.profile.xcconfig */,
8522EA4C54B9CA21B71F91CC /* Pods-Runner.debug.xcconfig */,
9C0E63FC9D84AA7D3BB0A547 /* Pods-Runner.release.xcconfig */,
4D6281A38B453C42FAC24BD5 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -159,6 +211,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
@ -191,9 +244,10 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7676C2A8308F394F004CF793 /* Helper */,
7676C292308F37EA004CF793 /* Penguin */,
76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */,
61243B412EC5FA3700D46FA0 /* Helper */,
61243B472EC5FA3700D46FA0 /* Penguin */,
769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */,
478CFA952E6E20A60064F3D7 /* Runner.entitlements */,
478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */,
@ -233,21 +287,25 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
EA10FC42B68E41E75A052FAA /* [CP] Check Pods Manifest.lock */,
DE4E6538EB74D09D8F3A8FE7 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
765A5A922F35CD8B0003FF7D /* Embed Frameworks */,
76B714E4300E58B2004DE37A /* Embed Foundation Extensions */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
5D78F615DF2D966539B34DE2 /* [CP] Embed Pods Frameworks */,
4AA9AE39AD56A64A1F16E548 /* [CP] Copy Pods Resources */,
824B1289AE3D15AB765B1BBF /* [CP] Embed Pods Frameworks */,
6F08875CF9A6CF013C44F482 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
@ -259,6 +317,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 2610;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@ -281,6 +340,9 @@
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
@ -329,9 +391,9 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
4AA9AE39AD56A64A1F16E548 /* [CP] Copy Pods Resources */ = {
6F08875CF9A6CF013C44F482 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -352,7 +414,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
5D78F615DF2D966539B34DE2 /* [CP] Embed Pods Frameworks */ = {
824B1289AE3D15AB765B1BBF /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -386,9 +448,9 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
EA10FC42B68E41E75A052FAA /* [CP] Check Pods Manifest.lock */ = {
DE4E6538EB74D09D8F3A8FE7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -426,13 +488,22 @@
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */,
61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */,
61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */,
61243B542EC5FA3700D46FA0 /* PenguinPlugin.swift in Sources */,
61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */,
61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
7676C293308F37EA004CF793 /* PenguinViewFactory.swift in Sources */,
7676C294308F37EA004CF793 /* PenguinView.swift in Sources */,
7676C295308F37EA004CF793 /* PenguinModel.swift in Sources */,
7676C296308F37EA004CF793 /* PenguinNavigator.swift in Sources */,
7676C2A9308F394F004CF793 /* HMGPenguinInPlatformBridge.swift in Sources */,
7676C2AA308F394F004CF793 /* HMG_Geofence.swift in Sources */,
7676C2AB308F394F004CF793 /* LocalizedFromFlutter.swift in Sources */,
7676C2AC308F394F004CF793 /* GlobalHelper.swift in Sources */,
7676C2AD308F394F004CF793 /* HMGPlatformBridge.swift in Sources */,
7676C2AE308F394F004CF793 /* API.swift in Sources */,
7676C2AF308F394F004CF793 /* FlutterConstants.swift in Sources */,
7676C2B0308F394F004CF793 /* Extensions.swift in Sources */,
7676C2B1308F394F004CF793 /* GeoZoneModel.swift in Sources */,
7676C2B2308F394F004CF793 /* OpenTokPlatformBridge.swift in Sources */,
7676C297308F37EA004CF793 /* PenguinPlugin.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -509,7 +580,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -530,6 +601,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
@ -537,8 +609,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.12;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
MARKETING_VERSION = 4.6.050;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -643,7 +715,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -694,7 +766,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -717,6 +789,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
@ -724,8 +797,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.12;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
MARKETING_VERSION = 4.6.050;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -747,6 +820,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
@ -754,8 +828,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.12;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
MARKETING_VERSION = 4.6.050;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -798,6 +872,20 @@
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

@ -0,0 +1,176 @@
{
"pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
"version" : "1.2024072200.0"
}
},
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "97f7d74dd0e8f3d0fe5fc75cc8957aa73bdc948a",
"version" : "11.3.2"
}
},
{
"identity" : "dkcamera",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKCamera",
"state" : {
"branch" : "master",
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
}
},
{
"identity" : "dkimagepickercontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKImagePickerController",
"state" : {
"branch" : "4.3.9",
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
}
},
{
"identity" : "dkphotogallery",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
"state" : {
"branch" : "master",
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "27eaab3918e0bf78711cf1abf240577176326432",
"version" : "12.19.0"
}
},
{
"identity" : "google-ads-on-device-conversion-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
"state" : {
"revision" : "0208e2681ec81f8a9c81084696f60fcce26cb7ee",
"version" : "3.7.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "b8455dd2ff55cc269fda7a4f9eac6c1e3588c53f",
"version" : "12.19.2"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "ba3358d3c3dbae8ef230b58a46b97ad65e84e974",
"version" : "10.1.1"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "cc31f5ed464b111f877ce8554cbef4455d410d91",
"version" : "8.1.4"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
"version" : "1.69.1"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "724a52eea6329b7e12d3ad8300d76ca9f3895fcc",
"version" : "5.3.1"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
"state" : {
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
"version" : "101.0.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
"version" : "1.22.5"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "3851d94a41890dea16dc3db34caf60e585cb4163",
"version" : "2.30910.1"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "f4a19a3c313dc2616c70bb49d29a799fb16be837",
"version" : "2.4.1"
}
},
{
"identity" : "sdwebimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage",
"state" : {
"revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0",
"version" : "5.21.7"
}
},
{
"identity" : "swiftygif",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kirualex/SwiftyGif.git",
"state" : {
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
"version" : "5.4.5"
}
},
{
"identity" : "tocropviewcontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TimOliver/TOCropViewController",
"state" : {
"revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e",
"version" : "2.8.0"
}
}
],
"version" : 2
}

@ -1,10 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "/bin/sh &quot;$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh&quot; prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
@ -73,6 +91,9 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<MetalAPIValidationSettings
isEnabled = "No">
</MetalAPIValidationSettings>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"

@ -0,0 +1,176 @@
{
"pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
"version" : "1.2024072200.0"
}
},
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "3e33dd27dd4c69bd81c7c81fe61d8ccf58846902",
"version" : "11.3.1"
}
},
{
"identity" : "dkcamera",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKCamera",
"state" : {
"branch" : "master",
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
}
},
{
"identity" : "dkimagepickercontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKImagePickerController",
"state" : {
"branch" : "4.3.9",
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
}
},
{
"identity" : "dkphotogallery",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
"state" : {
"branch" : "master",
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "27eaab3918e0bf78711cf1abf240577176326432",
"version" : "12.19.0"
}
},
{
"identity" : "google-ads-on-device-conversion-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
"state" : {
"revision" : "0208e2681ec81f8a9c81084696f60fcce26cb7ee",
"version" : "3.7.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "b8455dd2ff55cc269fda7a4f9eac6c1e3588c53f",
"version" : "12.19.2"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "ba3358d3c3dbae8ef230b58a46b97ad65e84e974",
"version" : "10.1.1"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "cc31f5ed464b111f877ce8554cbef4455d410d91",
"version" : "8.1.4"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
"version" : "1.69.1"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "724a52eea6329b7e12d3ad8300d76ca9f3895fcc",
"version" : "5.3.1"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
"state" : {
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
"version" : "101.0.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
"version" : "1.22.5"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "3851d94a41890dea16dc3db34caf60e585cb4163",
"version" : "2.30910.1"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "f4a19a3c313dc2616c70bb49d29a799fb16be837",
"version" : "2.4.1"
}
},
{
"identity" : "sdwebimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage",
"state" : {
"revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0",
"version" : "5.21.7"
}
},
{
"identity" : "swiftygif",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kirualex/SwiftyGif.git",
"state" : {
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
"version" : "5.4.5"
}
},
{
"identity" : "tocropviewcontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TimOliver/TOCropViewController",
"state" : {
"revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e",
"version" : "2.8.0"
}
}
],
"version" : 2
}

@ -1,25 +1,64 @@
import Flutter
import UIKit
import UserNotifications
import FirebaseCore
import FirebaseMessaging
import GoogleMaps
import firebase_messaging
@main
@objc class AppDelegate: FlutterAppDelegate {
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
func didInitializeImplicitFlutterEngine(_ engineBridge: any FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
// Run AFTER all plugins registered so Firebase sits in front of the VoIP plugin
FLTFirebaseMessagingPlugin.configureNotificationCenterDelegate()
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
FirebaseApp.configure()
application.registerForRemoteNotifications()
GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
initializePlatformChannels()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func initializePlatformChannels(){
if let mainViewController = window?.rootViewController as? FlutterViewController{ // platform initialization suppose to be in foreground
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
// 1. Try accessing window via AppDelegate (legacy/single-window setup)
var controller = self.window?.rootViewController as? FlutterViewController
// 2. Fallback to UIWindowScene active window (modern iOS architecture)
if controller == nil {
controller = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first(where: { $0.isKeyWindow })?
.rootViewController as? FlutterViewController
}
// 3. Perform initialization once FlutterViewController is available
if let mainViewController = controller {
HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController)
} else {
print("⚠️ FlutterViewController not ready yet for initializePlatformChannels.")
}
}
if let mainViewController = window?.rootViewController as? FlutterViewController{ // platform initialization suppose to be in foreground
HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController)
}
}
}
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){
// Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)

@ -1 +1,128 @@
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]}
{
"images" : [
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "Icon-App-20x20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "Icon-App-40x40@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-App-40x40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "Icon-App-60x60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "Icon-App-60x60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "Icon-App-20x20@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon-App-40x40@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "Icon-App-40x40@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-App-76x76@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "Icon-App-76x76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "Icon-App-83.5x83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "icon.jpg",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
},
{
"filename" : "Icon-App-76x76@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "76x76"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt</string>
<key>ANDROID_CLIENT_ID</key>
<string>815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com</string>
<key>API_KEY</key>
@ -11,11 +15,11 @@
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.cloudsolutions.HMGPatientApp</string>
<string>com.HMG.HMG-Smartphone</string>
<key>PROJECT_ID</key>
<string>api-project-815750722565</string>
<key>STORAGE_BUCKET</key>
<string>api-project-815750722565.firebasestorage.app</string>
<string>api-project-815750722565.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
@ -27,7 +31,7 @@
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:815750722565:ios:34ec03c09e02e21f3c186c</string>
<string>1:815750722565:ios:328ec247a81a2ca23c186c</string>
<key>DATABASE_URL</key>
<string>https://api-project-815750722565.firebaseio.com</string>
</dict>

@ -5,32 +5,32 @@
// Created by ZiKambrani on 22/12/2020.
//
import UIKit
class FlutterConstants{
static var LOG_GEOFENCE_URL:String?
static var WIFI_CREDENTIALS_URL:String?
static var DEFAULT_HTTP_PARAMS:[String:Any?]?
class func set(){
// (FiX) Take a start with FlutterMethodChannel (kikstart)
/* First call to flutter method is not returning the correct value (Always returning 'NSObject') then after it wroking fine and returning correct value*/
FlutterText.with(key: "test") { (test) in
flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ (response) in
if let defaultHTTPParams = response as? [String:Any?]{
DEFAULT_HTTP_PARAMS = defaultHTTPParams
}
}
flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments:nil){ (response) in
if let url = response as? String{
LOG_GEOFENCE_URL = url
}
}
}
}
}
//import UIKit
//
//class FlutterConstants{
// static var LOG_GEOFENCE_URL:String?
// static var WIFI_CREDENTIALS_URL:String?
// static var DEFAULT_HTTP_PARAMS:[String:Any?]?
//
// class func set(){
//
// // (FiX) Take a start with FlutterMethodChannel (kikstart)
// /* First call to flutter method is not returning the correct value (Always returning 'NSObject') then after it wroking fine and returning correct value*/
// FlutterText.with(key: "test") { (test) in
//
// flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ (response) in
// if let defaultHTTPParams = response as? [String:Any?]{
// DEFAULT_HTTP_PARAMS = defaultHTTPParams
// }
//
// }
//
// flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments:nil){ (response) in
// if let url = response as? String{
// LOG_GEOFENCE_URL = url
// }
// }
//
// }
// }
//}

@ -5,136 +5,136 @@
// Created by ZiKambrani on 14/12/2020.
//
import UIKit
import NetworkExtension
import SystemConfiguration.CaptiveNetwork
var flutterMethodChannel:FlutterMethodChannel? = nil
fileprivate var mainViewController:MainFlutterVC!
class HMGPlatformBridge{
private let channelName = "HMG-Platform-Bridge"
private static var shared_:HMGPlatformBridge?
class func initialize(flutterViewController:MainFlutterVC){
shared_ = HMGPlatformBridge()
mainViewController = flutterViewController
shared_?.openChannel()
}
func shared() -> HMGPlatformBridge{
assert((HMGPlatformBridge.shared_ != nil), "HMGPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
return HMGPlatformBridge.shared_!
}
private func openChannel(){
flutterMethodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger)
flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
print("Called function \(methodCall.method)")
if methodCall.method == "connectHMGInternetWifi"{
self.connectHMGInternetWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "connectHMGGuestWifi"{
self.connectHMGGuestWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "isHMGNetworkAvailable"{
self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
}else if methodCall.method == "registerHmgGeofences"{
self.registerHmgGeofences(result: result)
}else if methodCall.method == "unRegisterHmgGeofences"{
self.unRegisterHmgGeofences(result: result)
}
print("")
}
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
FlutterConstants.set()
}
}
// Connect HMG Wifi and Internet
func connectHMGInternetWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
guard let pateintId = (methodCall.arguments as? [Any])?.first as? String
else { return assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'") }
HMG_Internet.shared.connect(patientId: pateintId) { (status, message) in
result(status ? 1 : 0)
if status{
self.showMessage(title:"Congratulations", message:message)
}else{
self.showMessage(title:"Ooops,", message:message)
}
}
}
// Connect HMG-Guest for App Access
func connectHMGGuestWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
HMG_GUEST.shared.connect() { (status, message) in
result(status ? 1 : 0)
if status{
self.showMessage(title:"Congratulations", message:message)
}else{
self.showMessage(title:"Ooops,", message:message)
}
}
}
func isHMGNetworkAvailable(methodCall:FlutterMethodCall ,result: @escaping FlutterResult) -> Bool{
guard let ssid = methodCall.arguments as? String else {
assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'")
return false
}
let queue = DispatchQueue.init(label: "com.hmg.wifilist")
NEHotspotHelper.register(options: nil, queue: queue) { (command) in
print(command)
if(command.commandType == NEHotspotHelperCommandType.filterScanList) {
if let networkList = command.networkList{
for network in networkList{
print(network.ssid)
}
}
}
}
return false
}
// Message Dailog
func showMessage(title:String, message:String){
DispatchQueue.main.async {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert )
alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil))
mainViewController.present(alert, animated: true) {
}
}
}
// Register Geofence
func registerHmgGeofences(result: @escaping FlutterResult){
flutterMethodChannel?.invokeMethod("getGeoZones", arguments: nil){ geoFencesJsonString in
if let jsonString = geoFencesJsonString as? String{
let allZones = GeoZoneModel.list(from: jsonString)
HMG_Geofence.shared().register(geoZones: allZones)
result(true)
}else{
}
}
}
// Register Geofence
func unRegisterHmgGeofences(result: @escaping FlutterResult){
HMG_Geofence.shared().unRegisterAll()
result(true)
}
}
//import UIKit
//import NetworkExtension
//import SystemConfiguration.CaptiveNetwork
//
//var flutterMethodChannel:FlutterMethodChannel? = nil
//fileprivate var mainViewController:MainFlutterVC!
//
//class HMGPlatformBridge{
// private let channelName = "HMG-Platform-Bridge"
// private static var shared_:HMGPlatformBridge?
//
// class func initialize(flutterViewController:MainFlutterVC){
// shared_ = HMGPlatformBridge()
// mainViewController = flutterViewController
// shared_?.openChannel()
// }
//
// func shared() -> HMGPlatformBridge{
// assert((HMGPlatformBridge.shared_ != nil), "HMGPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
// return HMGPlatformBridge.shared_!
// }
//
// private func openChannel(){
// flutterMethodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger)
// flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
// print("Called function \(methodCall.method)")
// if methodCall.method == "connectHMGInternetWifi"{
// self.connectHMGInternetWifi(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "connectHMGGuestWifi"{
// self.connectHMGGuestWifi(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "isHMGNetworkAvailable"{
// self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "registerHmgGeofences"{
// self.registerHmgGeofences(result: result)
//
// }else if methodCall.method == "unRegisterHmgGeofences"{
// self.unRegisterHmgGeofences(result: result)
// }
//
// print("")
// }
// Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
// FlutterConstants.set()
// }
// }
//
//
//
// // Connect HMG Wifi and Internet
// func connectHMGInternetWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
//
// guard let pateintId = (methodCall.arguments as? [Any])?.first as? String
// else { return assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'") }
//
//
// HMG_Internet.shared.connect(patientId: pateintId) { (status, message) in
// result(status ? 1 : 0)
// if status{
// self.showMessage(title:"Congratulations", message:message)
// }else{
// self.showMessage(title:"Ooops,", message:message)
// }
// }
// }
//
// // Connect HMG-Guest for App Access
// func connectHMGGuestWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
// HMG_GUEST.shared.connect() { (status, message) in
// result(status ? 1 : 0)
// if status{
// self.showMessage(title:"Congratulations", message:message)
// }else{
// self.showMessage(title:"Ooops,", message:message)
// }
// }
// }
//
// func isHMGNetworkAvailable(methodCall:FlutterMethodCall ,result: @escaping FlutterResult) -> Bool{
// guard let ssid = methodCall.arguments as? String else {
// assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'")
// return false
// }
//
// let queue = DispatchQueue.init(label: "com.hmg.wifilist")
// NEHotspotHelper.register(options: nil, queue: queue) { (command) in
// print(command)
//
// if(command.commandType == NEHotspotHelperCommandType.filterScanList) {
// if let networkList = command.networkList{
// for network in networkList{
// print(network.ssid)
// }
// }
// }
// }
// return false
//
// }
//
//
// // Message Dailog
// func showMessage(title:String, message:String){
// DispatchQueue.main.async {
// let alert = UIAlertController(title: title, message: message, preferredStyle: .alert )
// alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil))
// mainViewController.present(alert, animated: true) {
//
// }
// }
// }
//
// // Register Geofence
// func registerHmgGeofences(result: @escaping FlutterResult){
// flutterMethodChannel?.invokeMethod("getGeoZones", arguments: nil){ geoFencesJsonString in
// if let jsonString = geoFencesJsonString as? String{
// let allZones = GeoZoneModel.list(from: jsonString)
// HMG_Geofence.shared().register(geoZones: allZones)
// result(true)
// }else{
// }
// }
// }
//
// // Register Geofence
// func unRegisterHmgGeofences(result: @escaping FlutterResult){
// HMG_Geofence.shared().unRegisterAll()
// result(true)
// }
//
//}

@ -9,14 +9,14 @@ import UIKit
class FlutterText{
class func with(key:String,completion: @escaping (String)->Void){
flutterMethodChannel?.invokeMethod("localizedValue", arguments: key, result: { (result) in
if let localized = result as? String{
completion(localized)
}else{
completion(key)
}
})
}
// class func with(key:String,completion: @escaping (String)->Void){
// flutterMethodChannel?.invokeMethod("localizedValue", arguments: key, result: { (result) in
// if let localized = result as? String{
// completion(localized)
// }else{
// completion(key)
// }
// })
// }
}

@ -5,57 +5,57 @@
// Created by ZiKambrani on 14/12/2020.
//
import UIKit
import NetworkExtension
import SystemConfiguration.CaptiveNetwork
fileprivate var openTok:OpenTok?
class OpenTokPlatformBridge : NSObject{
private var methodChannel:FlutterMethodChannel? = nil
private var mainViewController:MainFlutterVC!
private static var shared_:OpenTokPlatformBridge?
class func initialize(flutterViewController:MainFlutterVC, registrar:FlutterPluginRegistrar?){
shared_ = OpenTokPlatformBridge()
shared_?.mainViewController = flutterViewController
shared_?.openChannel()
openTok = OpenTok(mainViewController: flutterViewController, registrar: registrar)
}
func shared() -> OpenTokPlatformBridge{
assert((OpenTokPlatformBridge.shared_ != nil), "OpenTokPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
return OpenTokPlatformBridge.shared_!
}
private func openChannel(){
methodChannel = FlutterMethodChannel(name: "OpenTok-Platform-Bridge", binaryMessenger: mainViewController.binaryMessenger)
methodChannel?.setMethodCallHandler { (call, result) in
print("Called function \(call.method)")
switch(call.method) {
case "initSession":
openTok?.initSession(call: call, result: result)
case "swapCamera":
openTok?.swapCamera(call: call, result: result)
case "toggleAudio":
openTok?.toggleAudio(call: call, result: result)
case "toggleVideo":
openTok?.toggleVideo(call: call, result: result)
case "hangupCall":
openTok?.hangupCall(call: call, result: result)
default:
result(FlutterMethodNotImplemented)
}
print("")
}
}
}
//import UIKit
//import NetworkExtension
//import SystemConfiguration.CaptiveNetwork
//
//
//fileprivate var openTok:OpenTok?
//
//class OpenTokPlatformBridge : NSObject{
// private var methodChannel:FlutterMethodChannel? = nil
// private var mainViewController:MainFlutterVC!
// private static var shared_:OpenTokPlatformBridge?
//
// class func initialize(flutterViewController:MainFlutterVC, registrar:FlutterPluginRegistrar?){
// shared_ = OpenTokPlatformBridge()
// shared_?.mainViewController = flutterViewController
//
// shared_?.openChannel()
// openTok = OpenTok(mainViewController: flutterViewController, registrar: registrar)
// }
//
// func shared() -> OpenTokPlatformBridge{
// assert((OpenTokPlatformBridge.shared_ != nil), "OpenTokPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
// return OpenTokPlatformBridge.shared_!
// }
//
// private func openChannel(){
// methodChannel = FlutterMethodChannel(name: "OpenTok-Platform-Bridge", binaryMessenger: mainViewController.binaryMessenger)
// methodChannel?.setMethodCallHandler { (call, result) in
// print("Called function \(call.method)")
//
// switch(call.method) {
// case "initSession":
// openTok?.initSession(call: call, result: result)
//
// case "swapCamera":
// openTok?.swapCamera(call: call, result: result)
//
// case "toggleAudio":
// openTok?.toggleAudio(call: call, result: result)
//
// case "toggleVideo":
// openTok?.toggleVideo(call: call, result: result)
//
// case "hangupCall":
// openTok?.hangupCall(call: call, result: result)
//
// default:
// result(FlutterMethodNotImplemented)
// }
//
// print("")
// }
// }
//}

@ -35,6 +35,7 @@
<string>comgooglemaps</string>
<string>baidumap</string>
<string>iosamap</string>
<string>whatsapp</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
@ -86,17 +87,38 @@
<key>NSMicrophoneUsageDescription</key>
<string>This app requires microphone access to enable virtual consultation between patient &amp; doctor</string>
<key>NSMotionUsageDescription</key>
<string>This app requires access to motion detection to count your daily steps.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app requires photo library access to select image as document &amp; upload it.</string>
<string>This app requires motion detection access to function properly.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app requires photo library access to upload profile picture and documents.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app requires photo library access to select image as document &amp; upload it.</string>
<key>NSRemindersUsageDescription</key>
<string>This app requires calendar access to set reminders for Virtual &amp; Normal Appointments.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app requires speech recognition access to access voice command features.</string>
<key>NSUserActivityTypes</key>
<array/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>

@ -0,0 +1,104 @@
import 'dart:io';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:freerasp/freerasp.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/services/security_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'generated/locale_keys.g.dart';
import 'widgets/buttons/custom_button.dart';
class AppClosedPage extends StatefulWidget {
const AppClosedPage({super.key});
@override
State<AppClosedPage> createState() => _AppClosedPageState();
}
class _AppClosedPageState extends State<AppClosedPage> {
@override
void initState() {
// Clarity.setCurrentScreenName('Unsafe Device Page');
Talsec.instance.detachListener();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.whiteColor,
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo
Utils.buildImgWithAssets(icon: AppAssets.hmgLogo, width: MediaQuery.of(context).size.width * 0.7, height: 90.h, fit: BoxFit.contain),
SizedBox(height: 32.h),
Text(
LocaleKeys.importantNotice.tr(context: context),
style: TextStyle(
fontSize: 28.f,
fontWeight: FontWeight.bold,
color: AppColors.textColor,
),
textAlign: TextAlign.center,
),
SizedBox(height: 16.h),
// Description
Text(
LocaleKeys.appDecommissionedText.tr(context: context),
style: TextStyle(
fontSize: 14.f,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
SizedBox(height: 24.h),
Text(
LocaleKeys.appDecommissionedSubText.tr(context: context),
style: TextStyle(fontSize: 14.f, color: AppColors.textColorLight, fontStyle: FontStyle.italic),
textAlign: TextAlign.center,
),
SizedBox(height: 48.h),
CustomButton(
text: LocaleKeys.downloadApp.tr(context: context),
onPressed: () {
if (Platform.isAndroid) {
Utils.openWebView(
url: "https://play.google.com/store/apps/details?id=com.ejada.hmg",
);
}
if (Platform.isIOS) {
Utils.openWebView(
url: "https://itunes.apple.com/app/id733503978",
);
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h,
height: 56.h,
iconColor: AppColors.primaryRedColor,
),
],
),
),
),
);
}
}

@ -138,8 +138,7 @@ class ApiClientImp implements ApiClient {
} else {}
if (body.containsKey('isDentalAllowedBackend')) {
body['isDentalAllowedBackend'] =
body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
}
if (!body.containsKey('IsPublicRequest')) {
@ -211,16 +210,8 @@ class ApiClientImp implements ApiClient {
}
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 6424682;
// body['PatientID'] = 4772785;
// body['PatientID'] = 4776766;
// body['PatientID'] = 4776370;
// body['PatientID'] = 4776462;
// body['PatientID'] = 4776463;
// body['PatientID'] = 4776359;
// body['PatientID'] = 4776466;
// body['PatientID'] = 4769748;
// body['PatientID'] = 89754444;
// body['PatientID'] = 3310954;
// body['PatientID'] = 53320;
// body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q";
@ -232,9 +223,9 @@ class ApiClientImp implements ApiClient {
// body['PatientID'] = 809289;
}
if (!url.contains("/paymentApi")) {
body['IsNewFlutterApp'] = true;
}
// if (!url.contains("/paymentApi")) {
// body['IsNewFlutterApp'] = true;
// }
body.removeWhere((key, value) => value == null);
}
@ -257,7 +248,7 @@ class ApiClientImp implements ApiClient {
if (kDebugMode) {
debugPrint("uri: ${Uri.parse(url.trim())}");
var requestBodyJSON = json.encode(body);
debugPrint("body: $requestBodyJSON", wrapWidth: 1024);
debugPrint("body: $requestBodyJSON", wrapWidth: 10000);
// log("body: $requestBodyJSON");
}
@ -392,24 +383,19 @@ class ApiClientImp implements ApiClient {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode,
failureType:
UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
);
// logApiEndpointError(endPoint, "session logged out", statusCode);
}
if (isAllowAny) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['IsAuthenticated'] == null) {
if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['MessageStatus'] == 1) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['Result'] == 'OK') {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
@ -419,8 +405,7 @@ class ApiClientImp implements ApiClient {
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
}
} else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
}
// else if (parsed['IsAuthenticated'] == false) {
// onFailure(
@ -432,8 +417,7 @@ class ApiClientImp implements ApiClient {
// }
else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null && parsed['ErrorMessage'] == null) {
if (parsed['ErrorSearchMsg'] == null) {
@ -467,8 +451,7 @@ class ApiClientImp implements ApiClient {
}
} else {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['message'] != null) {
onFailure(

@ -1,6 +1,7 @@
import 'package:amazon_payfort/amazon_payfort.dart';
import 'package:flutter_amazonpaymentservices/environment_type.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
// import 'package:myfatoorah_flutter/myfatoorah_flutter.dart';
class ApiConsts {
static const maxSmallScreen = 660;
@ -44,12 +45,17 @@ class ApiConsts {
// var payFortEnvironment = FortEnvironment.test;
// var applePayMerchantId = "merchant.com.hmgwebservices.uat";
// static var myFatoorahEnvironmentType = MFEnvironment.TEST;
// static var myFatoorahCountry = MFCountry.SAUDIARABIA;
static setBackendURLs() {
switch (appEnvironmentType) {
case AppEnvironmentTypeEnum.prod:
baseUrl = "https://hmgwebservices.com/";
payFortEnvironment = FortEnvironment.production;
payFortEnvironmentType = EnvironmentType.production;
// myFatoorahEnvironmentType = MFEnvironment.LIVE;
// myFatoorahCountry = MFCountry.SAUDIARABIA;
applePayMerchantId = "merchant.com.hmgwebservices";
SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx";
TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout";
@ -66,6 +72,8 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
payFortEnvironmentType = EnvironmentType.sandbox;
// myFatoorahEnvironmentType = MFEnvironment.TEST;
// myFatoorahCountry = MFCountry.KUWAIT;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
@ -77,12 +85,13 @@ class ApiConsts {
symptomsCheckerApi = symptomsCheckerApiUAT;
symptomsCheckerUsername = 'guest_user';
symptomsCheckerPassword = '123456';
break;
case AppEnvironmentTypeEnum.uat:
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
payFortEnvironmentType = EnvironmentType.sandbox;
// myFatoorahEnvironmentType = MFEnvironment.TEST;
// myFatoorahCountry = MFCountry.KUWAIT;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
@ -100,6 +109,8 @@ class ApiConsts {
baseUrl = "https://webservices.hmg.com/";
payFortEnvironment = FortEnvironment.production;
payFortEnvironmentType = EnvironmentType.production;
// myFatoorahEnvironmentType = MFEnvironment.LIVE;
// myFatoorahCountry = MFCountry.SAUDIARABIA;
applePayMerchantId = "merchant.com.hmgwebservices";
SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx";
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
@ -117,6 +128,8 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
payFortEnvironmentType = EnvironmentType.sandbox;
// myFatoorahEnvironmentType = MFEnvironment.TEST;
// myFatoorahCountry = MFCountry.KUWAIT;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
@ -134,6 +147,8 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
payFortEnvironmentType = EnvironmentType.sandbox;
// myFatoorahEnvironmentType = MFEnvironment.TEST;
// myFatoorahCountry = MFCountry.KUWAIT;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
@ -303,12 +318,18 @@ class ApiConsts {
static String googleCloudStorageENTranslationFileBaseURL = "https://storage.googleapis.com/hmg-patientapp-translations";
// ************ static values for Api ****************
static final double appVersionID = 21.8;
static final double appVersionID = 21.7;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";
static final String appGeneralId = "Cs2020@2016\$2958";
static final String sessionID = 'TMRhVmkGhOsvamErw';
// Notification Center GUIDs - Configure these values as per your notification center setup
static final String notificationCenterAppGUID = "SzFwWjI0TjhmSjZreDVsNmc3SDRSdWlxUG1h";
static final String notificationServiceGUID_Login = "D8BD5C76-4B50-4122-81D0-C3AA25DB08A2";
static final String notificationServiceGUID_Registration = "690D3595-A1E1-489A-B9AB-6270E83AD6ED";
static final String notificationServiceGUID_FamilyFile = "318285E4-6221-4A66-8FAF-2265D2B4B24C";
}
// PACKAGES and OFFERS
@ -375,8 +396,6 @@ var DRIVER_LOCATION = 'Services/Patients.svc/REST/PatientER_GetDriverLocation';
//weather
var WEATHER_INDICATOR = 'Services/Weather.svc/REST/GetCityInfo';
var GET_PRIVILEGE = 'Services/Patients.svc/REST/Service_Privilege';
// Wifi Credentials
var WIFI_CREDENTIALS = "Services/Patients.svc/Hmg_SMS_Get_By_ProjectID_And_PatientID";
@ -873,8 +892,7 @@ var GET_CUSTOMER_INFO = "VerifyCustomer";
//Pharmacy
var GET_PHARMACY_CATEGORISE =
'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0';
var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0';
var GET_OFFERS_CATEGORISE = 'discountcategories';
var GET_OFFERS_PRODUCTS = 'offerproducts/';
var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=';

@ -110,6 +110,7 @@ class AppAssets {
static const String report_icon = '$svgBasePath/report_icon.svg';
static const String radiology_icon = '$svgBasePath/radiology_icon.svg';
static const String prescription_item_icon = '$svgBasePath/prescription_item_icon.svg';
static const String vital_sign_item_icon = '$svgBasePath/vital_sign_item_icon.svg';
static const String checkin_location_icon = '$svgBasePath/checkin_location_icon.svg';
static const String checkin_nfc_icon = '$svgBasePath/checkin_nfc_icon.svg';
static const String checkin_qr_icon = '$svgBasePath/checkin_qr_icon.svg';
@ -385,6 +386,7 @@ class AppAssets {
static const String hmg_pharmacy_logo = '$svgBasePath/hmg_pharmacy_logo.svg';
static const String redeem_icon = '$svgBasePath/redeem_icon.svg';
static const String expired_icon = '$svgBasePath/expired_icon.svg';
static const String icon_migrate = '$svgBasePath/Icon-migrate.svg';
//Health Calculators
static const String bodyfatcalc = '$svgBasePath/bfc.svg';

@ -49,12 +49,19 @@ class AppState {
bool isPaytabsEnabled = false;
bool isPayfortHostedPageEnabled = true;
bool isMyFatoorahEnabled = false;
// bool isMyFatoorahEnabled = true;
void setIsPaytabsEnabled(bool value) {
isPaytabsEnabled = value;
isPaytabsEnabled = false;
// isPaytabsEnabled = true;
}
void setIsMyFatoorahEnabled(bool value) {
isMyFatoorahEnabled = false;
// isMyFatoorahEnabled = true;
}
void setIsPayfortHostedPageEnabled(bool value) {
isPayfortHostedPageEnabled = value;
// isPayfortHostedPageEnabled = false;
@ -180,6 +187,14 @@ class AppState {
String get getFamilyFileTokenID => _familyFileTokenID;
bool isSafeDevice = true;
// set setIsSafeDevice(v) => isSafeDevice = v;
set setIsSafeDevice(bool value) {
isSafeDevice = value;
}
set setFamilyFileTokenID(String value) {
_familyFileTokenID = value;
}

@ -44,6 +44,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_rep
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/myfatoorah/myfatoorah_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_repo.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/offers_and_discounts/offers_and_discounts_repo.dart';
@ -84,6 +85,9 @@ import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/services/notification_service.dart';
import 'package:hmg_patient_app_new/services/permission_service.dart';
import 'package:hmg_patient_app_new/services/remote_config_service.dart';
import 'package:hmg_patient_app_new/services/security_service.dart';
import 'package:hmg_patient_app_new/features/occasion_theme/occasion_theme_view_model.dart';
import 'package:hmg_patient_app_new/core/services/turnstile_service.dart';
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_calendar_model.dart';
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart';
@ -157,6 +161,10 @@ class AppDependencies {
getIt.registerLazySingleton<PermissionService>(() => PermissionService());
getIt.registerLazySingleton<TurnstileService>(() => TurnstileService(getIt<LoggerService>()));
getIt.registerLazySingleton<SecurityService>(() => SecurityServiceImpl(
appState: getIt(),
loggerService: getIt(),
));
// Repositories
getIt.registerLazySingleton<CommonRepo>(() => CommonRepoImp(loggerService: getIt()));
@ -375,8 +383,22 @@ class AppDependencies {
errorHandlerService: getIt(),
));
getIt.registerLazySingleton<MyFatoorahViewModel>(() => MyFatoorahViewModel(
appState: getIt(),
errorHandlerService: getIt(),
payfortRepo: getIt(),
));
getIt.registerLazySingleton<ClarityService>(
() => ClarityService(appState: getIt.get<AppState>()),
);
// Remote-config-driven "occasion" theming (National Day, Eid, etc.).
getIt.registerLazySingleton<RemoteConfigService>(() => RemoteConfigServiceImp(loggerService: getIt()));
getIt.registerLazySingleton<OccasionThemeViewModel>(() => OccasionThemeViewModel(
remoteConfigService: getIt(),
cacheService: getIt(),
loggerService: getIt(),
));
}
}

@ -0,0 +1,5 @@
class MyFatoorahConfig {
static const String configAPIKey = "SK_KWT_0auB76h3Frhj7aUBSZa6H5ei792eZoGAPh0bBxKsrgtyjqKgf38MPnZqzGqagErb";
}

@ -3,6 +3,11 @@ class PaymentSdkDefaultConfig {
static const String profileID = "119730";
static const String serverKey = "SWJ9LD22MT-JLJZLBKTLK-WGWTLWGTWR";
static const String clientKey = "C7K2DQ-PDDN6B-69B2K7-P9GB9T";
// static const String profileID = "135577";
// static const String serverKey = "SDJ9LD22LR-J9LRBKZDRD-ZRZKWDWBRR";
// static const String clientKey = "CBK2DQ-PDPN6P-BR2K9D-VPBTB2";
static const String defaultCurrency = "SAR";
static const double defaultAmount = 10.0;
static const String defaultMerchantCountryCode = "SA";

@ -0,0 +1,16 @@
import 'package:freerasp/freerasp.dart';
final talsecConfig = TalsecConfig(
androidConfig: AndroidConfig(
packageName: 'com.ejada.hmg',
signingCertHashes: ['6tvWaoN5coG4SnfxGbdQlcLmM0J4ePQwDjrKIg+QkV0=', 'j6VEqVhrypHMIiXiFdRLDdGwjGaMGWY7KAdBJA+Z4Pc=', 'EKw2Bd3VYz//DYjDnJLxEh3uGqhNDIWubLmpwAx/A7U='], // Must be the release cert hash
supportedStores: ['com.android.vending'], // Google Play Store
),
iosConfig: IOSConfig(
// bundleIds: ['com.cloudsolutions.HMGPatientApp'], // iOS Bundle ID
bundleIds: ['com.HMG.HMG-Smartphone'], // iOS Bundle ID
teamId: '3A359E86ZF', // Found in Apple Developer portal
),
watcherMail: '', // Required to receive security alerts
isProd: true, // Enforces strict checks for release builds
);

@ -28,7 +28,7 @@ class DateUtil {
const end = "+0300)";
final startIndex = date.indexOf(start);
final endIndex = date.indexOf(end, startIndex + start.length);
// if (projectId == 2 || projectId == 3) {
// if (projectId == 2 || projectId == 3 || projectId == 4) {
// return DateTime.fromMillisecondsSinceEpoch(
// int.parse(
// date.substring(startIndex + start.length, endIndex),

@ -12,6 +12,7 @@ class DoctorMapper{
for (var element in doctorList) {
String? region = element.getRegionName(isArabic);
String? regionEng = element.getRegionName(false);
if (region == null) continue;
var regionDoctorList = regionList.registeredDoctorMap?.putIfAbsent(region, () => PatientDoctorAppointmentListByRegion());
@ -33,6 +34,8 @@ class DoctorMapper{
var newAppointment = PatientDoctorAppointmentList(
filterName:
element.getProjectCompleteNameWithLocale(isArabic: isArabic),
filterNameEng:
element.getProjectCompleteNameWithLocale(isArabic: false),
distanceInKMs: element.projectDistanceInKiloMeters.toString(),
projectTopName: element.projectTopName,
projectBottomName: element.projectBottomName,
@ -82,6 +85,7 @@ class DoctorMapper{
regionDoctorList?.hmgSize = regionDoctorList.hmgDoctorList?.length ?? 0;
regionList.registeredDoctorMap?[region] = regionDoctorList;
regionList.regionNameMap?[regionEng??""] = region;
}
return regionList;
@ -110,10 +114,19 @@ class DoctorMapper{
}
List<String>? keys = unsorted.registeredDoctorMap?.keys.toList();
keys?.sort();
final keys = unsorted.registeredDoctorMap?.keys.toList() ?? [];
if (keys.isEmpty) return unsorted;
keys.sort((a, b) {
final priorityA = _getRegionSortPriority(a);
final priorityB = _getRegionSortPriority(b);
if (priorityA != priorityB) return priorityA.compareTo(priorityB);
final aValue = a.toLowerCase();
final bValue = b.toLowerCase();
return aValue.compareTo(bValue);
});
if (keys == null) return unsorted;
Map<String, PatientDoctorAppointmentListByRegion> sortedMap = {};
for (var key in keys) {
sortedMap[key] = unsorted.registeredDoctorMap![key]!;
@ -122,6 +135,25 @@ class DoctorMapper{
return unsorted;
}
static int _getRegionSortPriority(String regionKey) {
final key = regionKey.trim().toLowerCase();
if (key.isEmpty) return 999;
if (key.startsWith('c') || key.contains('وسط') || key.contains('الوسط') || key.contains('المنطقة الوسطى')) {
return 0;
}
if (key.startsWith('w') || key.contains('غرب') || key.contains('الغربي') || key.contains('الغربية')) {
return 1;
}
if (key.startsWith('e') || key.contains('شرق') || key.contains('الشرقي') || key.contains('الشرقية')) {
return 2;
}
if (key.startsWith("u") || key.contains('الإمارات') || key.contains('امارات')) {
return 3;
}
return 999;
}
static Future<RegionList> getMappedHospitals(
List<HospitalsModel> hospitalList, {
bool isArabic = false, double lat = 0.0,double lng = 0.0
@ -129,6 +161,7 @@ class DoctorMapper{
final regionList = RegionList();
for (final hospital in hospitalList) {
final region = hospital.getRegionName(isArabic);
final regionEng = hospital.getRegionName(false);
if (region == null) continue;
final regionData = regionList.registeredDoctorMap?.putIfAbsent(
@ -152,6 +185,7 @@ class DoctorMapper{
} else {
final newEntry = PatientDoctorAppointmentList(
filterName: hospital.name,
filterNameEng: hospital.getName(false),
distanceInKMs: hospital.distanceInKilometers?.toString(),
projectTopName: hospital.name,
projectBottomName: hospital.name,
@ -196,6 +230,7 @@ class DoctorMapper{
regionData?.hmcSize = regionData.hmcDoctorList?.length ?? 0;
regionData?.hmgSize = regionData.hmgDoctorList?.length ?? 0;
regionList.registeredDoctorMap?[region] = regionData;
regionList.regionNameMap?[regionEng??""] = region;
}
return regionList;

@ -15,6 +15,7 @@ import 'package:flutter_callkit_incoming/entities/notification_params.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_ios_voip_kit_karmm/call_state_type.dart';
import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
@ -22,11 +23,17 @@ import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/notifications/models/resp_models/notification_response_model.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/notifications/notification_details_page.dart';
import 'package:hmg_patient_app_new/presentation/onboarding/splash_animation_screen.dart';
import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import 'package:huawei_push/huawei_push.dart' as h_push;
// Global tracking variables for call state
bool _isCallInProgress = false;
@ -310,7 +317,6 @@ class PushNotificationHandler {
final voIPKit = FlutterIOSVoIPKit.instance;
late Timer timeOutTimer;
bool isTalking = false;
var data = {
@ -382,7 +388,8 @@ class PushNotificationHandler {
) async {
try {
log('🎈 example: onDidRejectIncomingCall $uuid - $callerId');
timeOutTimer.cancel();
await voIPKit.endCall();
await FlutterCallkitIncoming.endAllCalls();
// Cleanup on reject with API call
if (_currentCallId != null) {
await _endCallAndCleanup(_currentCallId!, isDeclined: true);
@ -397,6 +404,9 @@ class PushNotificationHandler {
String callerId,
) async {
log('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
String zoomSessionID = callerId.split("_").sublist(0, callerId.split("_").length - 1).join("_");
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected();
@ -405,30 +415,52 @@ class PushNotificationHandler {
_callTimeoutTimer = null;
_isCallInProgress = false;
_currentCallId = null;
await Future.delayed(Duration(seconds: 2)).then((val) async {
await Future.delayed(Duration(milliseconds: 2000)).then((val) async {
await voIPKit.endCall();
await FlutterCallkitIncoming.endAllCalls();
});
// Navigator.pushNamed(
// locator<NavigationService>().navigatorKey.currentContext!,
// "zoom_call_page",
// arguments: CallArguments("hoover-dam", "123", "Patient", "40", "1", false),
// );
// Navigator.pushNamed(navigatorKey.currentContext!, VIDEO_CALL_SCREEN,
// arguments: VideoArgus(
// reservationId: int.parse(callerId), token: null, isVideo: true));
// timeOutTimer.cancel();
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, zoomSessionID);
Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall);
// Navigator.of(GetIt.instance<NavigationService>().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation())));
Navigator.pushReplacementNamed(
// context,
GetIt.instance<NavigationService>().navigatorKey.currentContext!,
AppRoutes.zoomCallPage,
// arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1),
arguments: CallArguments(zoomSessionID, "123", "Patient", "40", "0", true, int.parse("1")),
// arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)),
);
};
}
if (Platform.isAndroid) {
try {
final fcmToken = await FirebaseMessaging.instance.getToken().catchError((err) {
log(err);
});
if (fcmToken != null) onToken(fcmToken);
if (!(await Utils.isGoogleServicesAvailable())) {
h_push.Push.enableLogger();
final result = await h_push.Push.setAutoInitEnabled(true);
h_push.Push.onNotificationOpenedApp.listen((message) {
// newMessage(toFirebaseRemoteMessage(message));
}, onError: (e) => print(e.toString()));
h_push.Push.onMessageReceivedStream.listen((message) {
// newMessage(toFirebaseRemoteMessage(message));
}, onError: (e) => print(e.toString()));
h_push.Push.getTokenStream.listen((token) {
onToken(token);
}, onError: (e) => print(e.toString()));
h_push.Push.getToken('');
h_push.Push.registerBackgroundMessageHandler(backgroundMessageHandler);
} else {
final fcmToken = await FirebaseMessaging.instance.getToken().catchError((err) {
log(err);
});
if (fcmToken != null) onToken(fcmToken);
}
// }
} catch (ex) {
log("Notification Exception: $ex");
@ -587,7 +619,6 @@ class PushNotificationHandler {
// Permission.audio,
// Permission.microphone,
].request();
log("=-=-=-=-=-=-=-=-=-=-");
log(statuses[Permission.notification].toString());
}
} catch (_) {

@ -75,6 +75,12 @@ class RequestUtils {
}
request.isRegister = false;
}
request.notificationCenterAppGUID = ApiConsts.notificationCenterAppGUID;
request.notificationCenterAppServiceGUID = isForRegister
? ApiConsts.notificationServiceGUID_Registration
: ApiConsts.notificationServiceGUID_Login;
return request;
}
@ -148,6 +154,12 @@ class RequestUtils {
}
request.deviceTypeID = request.searchType;
request.notificationCenterAppGUID = ApiConsts.notificationCenterAppGUID;
request.notificationCenterAppServiceGUID = (registeredData != null && registeredData.isRegister == true)
? ApiConsts.notificationServiceGUID_Registration
: ApiConsts.notificationServiceGUID_Login;
return request;
}
@ -220,6 +232,13 @@ class RequestUtils {
request.familyRegionID = zipCode == CountryEnum.saudiArabia.countryCode ? 1 : 2;
}
request.notificationCenterAppGUID = ApiConsts.notificationCenterAppGUID;
request.notificationCenterAppServiceGUID = isFormFamilyFile
? ApiConsts.notificationServiceGUID_FamilyFile
: isForRegister
? ApiConsts.notificationServiceGUID_Registration
: ApiConsts.notificationServiceGUID_Login;
return request;
}

@ -135,7 +135,7 @@ class Utils {
static String convertStringToDateTime(String dateTimeString) {
String timeString = dateTimeString;
// Parse the time string using DateFormat
DateFormat format = DateFormat.Hms(["en-US"]); // 'Hms' = 'HH:mm:ss'
DateFormat format = DateFormat.Hms("en-US"); // 'Hms' = 'HH:mm:ss'
DateTime time = format.parse(timeString);
DateTime now = DateTime.now();
@ -437,8 +437,8 @@ class Utils {
onCancelTap();
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
backgroundColor: AppColors.criticalActionColor,
borderColor: AppColors.criticalActionColor,
textColor: AppColors.whiteColor,
// icon: AppAssets.cancel,
// iconColor: AppColors.whiteColor,
@ -516,8 +516,8 @@ class Utils {
onCancelTap();
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
backgroundColor: AppColors.criticalActionColor,
borderColor: AppColors.criticalActionColor,
textColor: AppColors.whiteColor,
// icon: AppAssets.cancel,
// iconColor: AppColors.whiteColor,
@ -808,8 +808,8 @@ class Utils {
double? border,
double? borderRadius,
}) {
final iconH = height ?? 24.h;
final iconW = width ?? 24.w;
final double? iconW = (width == null && height == null) ? 24.w : width;
final double? iconH = (width == null && height == null) ? 24.h : height;
return PreserveImageColors(
child: Container(
decoration: BoxDecoration(
@ -859,15 +859,15 @@ class Utils {
BoxFit fit = BoxFit.cover,
ImageErrorWidgetBuilder? errorBuilder,
}) {
final double? iconW = (width == null && height == null) ? 24.w : width;
final double? iconH = (width == null && height == null) ? 24.h : height;
if (url == null || url.isEmpty) {
return Utils.buildSvgWithAssets(
width: width ?? 24.w,
height: height ?? 24.h,
width: iconW ?? 24.w,
height: iconH ?? 24.h,
icon: AppAssets.noImageFound,
);
}
final iconH = height ?? 24.h;
final iconW = width ?? 24.w;
return PreserveImageColors(
child: Image.network(
url,
@ -877,7 +877,7 @@ class Utils {
errorBuilder: errorBuilder ??
(_, __, ___) {
//todo_section change the error builder icon that it is returning
return Utils.buildSvgWithAssets(width: iconW, height: iconH, icon: AppAssets.noImageFound);
return Utils.buildSvgWithAssets(width: iconW ?? 24.w, height: iconH ?? 24.h, icon: AppAssets.noImageFound);
},
),
);
@ -1064,9 +1064,42 @@ class Utils {
return isHavePrivilege;
}
static void openWebView({required String url}) {
Uri uri = Uri.parse(url);
launchUrl(uri, mode: LaunchMode.inAppBrowserView);
static Future<void> openWebView({required String url}) async {
try {
Uri uri = Uri.parse(url);
// Validate URL scheme for in-app browser
if (!uri.hasScheme || (!uri.scheme.startsWith('http'))) {
throw 'Invalid URL scheme. In-app browser only supports HTTP/HTTPS URLs';
}
// Check if URL can be launched
if (await canLaunchUrl(uri)) {
final launched = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
if (!launched) {
// Fallback to external browser
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
} else {
// Fallback to external browser
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
} catch (e) {
debugPrint('❌ Failed to open URL: $url - Error: $e');
// Try external browser as last resort
try {
final uri = Uri.parse(url);
await launchUrl(uri, mode: LaunchMode.externalApplication);
} catch (e2) {
debugPrint('❌ Failed to open URL in external browser: $e2');
// Optionally show user-friendly error message
}
}
}
static Color getCardBorderColor(int currentQueueStatus) {

@ -2,3 +2,9 @@ const Map configs = {
'ZOOM_SDK_KEY': 'b9T74nhfTg-ioP9urm970A',
'ZOOM_SDK_SECRET': 'KOzmjBNXQ1f4IPHpnngfL29uZvJMufSy2Fk8',
};
// const Map configs = {
// 'ZOOM_SDK_KEY': 'jYHoRpSUMTTefOwLq94Kyf1Kak513TUHpu78',
// 'ZOOM_SDK_SECRET': 'MOqi1zc18VFOMEaBDshFSHKLB0C2n9M0K48H',
// };

@ -1,5 +1,6 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
@ -486,6 +487,10 @@ extension EmailValidator on String {
: 'Poppins'),
),
);
Widget toText14Markdown() =>
MarkdownBody(
data: this,
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
String upper = "";

@ -222,6 +222,8 @@ class AuthenticationRepoImp implements AuthenticationRepo {
if (isRegister) {
newRequest["activationCode"] = activationCode ?? "0000";
newRequest["isSilentLogin"] = activationCode == null;
newRequest.remove("NotificationCenterAppGUID");
newRequest.remove("NotificationCenterAppSeviceGUID");
} else {
newRequest.activationCode = activationCode ?? "0000";
newRequest.isSilentLogin = activationCode == null;

@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/app_closed_page.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
@ -31,6 +32,7 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
@ -275,6 +277,7 @@ class AuthenticationViewModel extends ChangeNotifier {
// Check if field is empty
if (nationalIdController.text.isEmpty) {
_nationalIdError = LocaleKeys.pleaseEnterAnationalID.tr();
print("the controller is emtpy so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -284,6 +287,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (cleanedId.length == 10) {
if (!Utils.isSAUDIIDValid(cleanedId)) {
_nationalIdError = LocaleKeys.enterValidNationalId.tr();
print("the controller is not valid so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -294,6 +298,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (cleanedId.length == 10) {
if (!ValidationUtils.validateIqama(nationalIdController.text)) {
_nationalIdError = LocaleKeys.pleaseEnterAValidIqamaID.tr();
print("the controller is not valid so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -301,8 +306,9 @@ class AuthenticationViewModel extends ChangeNotifier {
return true;
}
} else if (selectedCountrySignup == CountryEnum.unitedArabEmirates) {
if (!ValidationUtils.validateUaeNationalId(nationalIdController.text)) {
if (!ValidationUtils.validateUaeNationalId(nationalIdController.text) && cleanedId.length == 15) {
_nationalIdError = LocaleKeys.pleaseEnterAValidNationalID.tr();
print("the controller is not valid so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -824,7 +830,11 @@ class AuthenticationViewModel extends ChangeNotifier {
onSuccess: (dynamic respData) async {
try {
if (respData != null) {
dynamic data = await SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
SelectDeviceByImeiRespModelElement data = SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
if (data.mobile == null || data.mobile == "" || data.identificationNo == null || data.identificationNo == "") {
return;
}
_appState.setSelectDeviceByImeiRespModelElement(data);
LoaderBottomSheet.hideLoader();
@ -856,8 +866,6 @@ class AuthenticationViewModel extends ChangeNotifier {
}
Future<void> checkUserAuthentication({required OTPTypeEnum otpTypeEnum, Function(dynamic)? onSuccess, Function(String)? onError}) async {
// TODO: THIS SHOULD BE REMOVED LATER ON AND PASSED FROM APP STATE DIRECTLY INTO API CLIENT. BECAUSE THIS API ONLY NEEDS FEW PARAMS FROM USER
loginTypeEnum = otpTypeEnum == OTPTypeEnum.sms ? LoginTypeEnum.sms : LoginTypeEnum.whatsapp;
// if (phoneNumberController.text.isEmpty) {
@ -1245,6 +1253,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setUserBloodGroup = activation.patientBlodType ?? "N/A";
_appState.setIsPaytabsEnabled(Utils.havePrivilege(120));
_appState.setIsPayfortHostedPageEnabled(Utils.havePrivilege(121));
_appState.setIsMyFatoorahEnabled(Utils.havePrivilege(123));
// Refresh privileges after user switching to ensure correct privileges are loaded
if (isSwitchUser) {
@ -1278,6 +1287,9 @@ class AuthenticationViewModel extends ChangeNotifier {
getIt.get<HabibWalletViewModel>().setIsWalletAmountToBeLoaded(true);
getIt.get<InsuranceViewModel>().setIsInsuranceDataToBeLoaded(true);
getIt.get<HmgServicesViewModel>().setHasVitalSignDataLoaded(false);
getIt.get<MedicalFileViewModel>().setIsSickLeavesDataNeedsReloading(true);
getIt.get<MedicalFileViewModel>().setIsMedicalReportsDataNeedsReloading(true);
getIt.get<PrescriptionsViewModel>().setIsPrescriptionDataNeedsReloading(true);
if (isUserAgreedBefore) {
LoaderBottomSheet.hideLoader();
navigateToHomeScreen();
@ -1413,7 +1425,8 @@ class AuthenticationViewModel extends ChangeNotifier {
if (value) {
LoaderBottomSheet.showLoader();
success();
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
// loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
loginTypeEnum = (Platform.isIOS ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
if (!_appState.isAuthenticated) {
//commenting this api to check either the same flow working or not because this api does not needed further if work fine we will remove this
await getPatientDeviceData(loginTypeEnum.toInt);
@ -1510,7 +1523,9 @@ class AuthenticationViewModel extends ChangeNotifier {
LoaderBottomSheet.hideLoader();
if (apiResponse.data["MessageStatus"] == 1) {
LoaderBottomSheet.showLoader(loadingText: "Your medical file has been created successfully. \nPlease proceed to login.");
//TODO: Here We Need to Show a Dialog Of Something in the case of Success.
// Reset registration payload and clear healthId so subsequent logins hit the login endpoint
_appState.getUserRegistrationPayload.healthId = null;
_appState.setUserRegistrationPayload = RegistrationDataModelPayload();
await clearDefaultInputValues(); // This will Clear All Default Values Of User.
Future.delayed(Duration(seconds: 1), () {
LoaderBottomSheet.hideLoader();
@ -1790,6 +1805,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setProjectsDetailList(projectDetailListModel);
_appState.setIsPaytabsEnabled(Utils.havePrivilege(120));
_appState.setIsPayfortHostedPageEnabled(Utils.havePrivilege(121));
_appState.setIsMyFatoorahEnabled(Utils.havePrivilege(123));
}
},
);
@ -1818,11 +1834,13 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setSelectDeviceByImeiRespModelElement(null);
_appState.setNHICUserData = CheckUserStatusResponseNHIC();
_appState.setUserRegistrationPayload = RegistrationDataModelPayload();
// Clear privilege lists
_appState.setPrivilegeModelList([]);
_appState.setVidaPlusProjectList([]);
_appState.setHMCProjectList([]);
_appState.setProjectsDetailList([]);
// _appState.setPrivilegeModelList([]);
// _appState.setVidaPlusProjectList([]);
// _appState.setHMCProjectList([]);
// _appState.setProjectsDetailList([]);
_appState.clearUserSwitchPayloads();
await clearDefaultInputValues();
_navigationService.pushAndReplace(AppRoutes.landingScreen);

@ -31,6 +31,8 @@ class SendActivationRequest {
int? familyRegionID;
bool? isPatientExcluded;
String? turnstileToken;
String? notificationCenterAppGUID;
String? notificationCenterAppServiceGUID;
SendActivationRequest(
{this.patientMobileNumber,
@ -64,7 +66,10 @@ class SendActivationRequest {
this.status,
this.familyRegionID,
this.isPatientExcluded,
this.turnstileToken});
this.turnstileToken,
this.notificationCenterAppGUID,
this.notificationCenterAppServiceGUID
});
SendActivationRequest.fromJson(Map<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber'];
@ -99,6 +104,8 @@ class SendActivationRequest {
familyRegionID = json['FamilyRegionID'];
isPatientExcluded = json['IsPatientExcluded'];
turnstileToken = json['TurnstileToken'];
notificationCenterAppGUID = json['NotificationCenterAppGUID'];
notificationCenterAppServiceGUID = json['NotificationCenterAppSeviceGUID'];
}
Map<String, dynamic> toJson() {
@ -141,6 +148,8 @@ class SendActivationRequest {
if (turnstileToken != null) {
data['TurnstileToken'] = turnstileToken;
}
data['NotificationCenterAppGUID'] = notificationCenterAppGUID;
data['NotificationCenterAppSeviceGUID'] = notificationCenterAppServiceGUID;
return data;
}
}

@ -1,10 +1,15 @@
import 'dart:io';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/appointment_nearest_gate_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/dental_chief_complaints_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_profile_response_model.dart';
@ -30,12 +35,12 @@ abstract class BookAppointmentsRepo {
Future<Either<Failure, GenericApiModel<DoctorsProfileResponseModel>>> getDoctorProfile(int clinicID, int projectID, int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, int projectID, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare,
{bool continueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel});
Future<Either<Failure, GenericApiModel<dynamic>>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false});
Future<Either<Failure, GenericApiModel<dynamic>>> insertSpecificAppointment(
{required int docID,
@ -181,6 +186,9 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
"IsSearchAppointmnetByClinicID": isContinueDentalPlan ? false : true,
"isDentalAllowedBackend": clinicID == 17 ? true : isContinueDentalPlan,
"IsGetNearAppointment": isNearest,
"gender": getIt.get<AppState>().isAuthenticated ? getIt.get<AppState>().getAuthenticatedUser()!.gender! : 0,
"age": getIt.get<AppState>().isAuthenticated ? getIt.get<AppState>().getAuthenticatedUser()!.age! : 0,
"DateofBirth": getIt.get<AppState>().isAuthenticated ? getIt.get<AppState>().getAuthenticatedUser()!.dateofBirth! : null,
if (isNearest) "SelectedDate": DateUtil.convertDateToString(DateTime.now()),
"License": true
};
@ -309,9 +317,10 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, int projectID, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"DoctorID": doctorId,
"ProjectID": projectID,
"PatientID": 0,
"License": true,
"IsRegistered": true,
@ -477,12 +486,12 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
}
@override
Future<Either<Failure, GenericApiModel>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}) async {
Future<Either<Failure, GenericApiModel>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false}) async {
Map<String, dynamic> requestBody = {
"AppointmentID": patientAppointmentHistoryResponseModel.appointmentNo,
"ClinicID": patientAppointmentHistoryResponseModel.clinicID,
"ProjectID": patientAppointmentHistoryResponseModel.projectID,
"CancelToReschadual": false,
"CancelToReschadual": isReschedule,
"EndTime": patientAppointmentHistoryResponseModel.endTime,
"StartTime": patientAppointmentHistoryResponseModel.startTime,
"DoctorID": patientAppointmentHistoryResponseModel.doctorID,
@ -751,6 +760,10 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
"InitialSlotDuration": initialSlotDuration,
"StrAppointmentDate": selectedDate,
"IsVirtual": false,
"DeviceType": Platform.isIOS ? 'iOS' : 'Android',
"DeviceToken": await Utils.getStringFromPrefs(CacheConst.pushToken),
"VoipToken": await Utils.getStringFromPrefs(CacheConst.voipToken),
"IsVoip": Platform.isIOS ? true : false,
"BookedBy": 102,
"VisitType": 1,
"VisitFor": 1,

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
@ -806,7 +807,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
doctorDetailsList.clear();
notifyListeners();
final result = await bookAppointmentsRepo.getDoctorRatingDetails(selectedDoctor.doctorID ?? 0, onSuccess: onSuccess, onError: onError);
final result = await bookAppointmentsRepo.getDoctorRatingDetails(selectedDoctor.doctorID ?? 0, selectedDoctor.projectID ?? 0, onSuccess: onSuccess, onError: onError);
result.fold(
(failure) async {
@ -842,67 +843,73 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
final DateFormat formatter = DateFormat('HH:mm', "en-US");
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed;
final result = await bookAppointmentsRepo.getDoctorFreeSlots(
selectedDoctor.clinicID ?? 0,
selectedDoctor.projectID ?? 0,
selectedDoctor.doctorID ?? 0,
isBookingForLiveCare,
continueDentalPlan: isContinueDentalPlan,
onError: onError,
);
result.fold(
(failure) async {
print(failure);
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage ?? "Unknown error occurred");
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['FreeTimeSlots'] == null || apiResponse.data['FreeTimeSlots'].isEmpty) {
onError!("No free slots available".tr());
return;
// try {
docFreeSlots.clear();
DateTime date;
final DateFormat formatter = DateFormat('HH:mm', "en-US");
// final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
// Map<DateTime, List> _eventsParsed;
final result = await bookAppointmentsRepo.getDoctorFreeSlots(
selectedDoctor.clinicID ?? 0,
selectedDoctor.projectID ?? 0,
selectedDoctor.doctorID ?? 0,
isBookingForLiveCare,
continueDentalPlan: isContinueDentalPlan,
onError: onError,
);
result.fold(
(failure) async {
print(failure);
if (onError != null) {
onError(failure.message);
}
initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
// isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) {
// date = (isLiveCareSchedule != null && isLiveCareSchedule)
// ? DateUtil.convertStringToDate(element)
// :
date = DateUtil.convertStringToDateSaudiTimezone(element, int.parse(selectedDoctor.projectID.toString()));
slotsList.add(FreeSlot(date, ['slot']));
docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
});
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage ?? "Unknown error occurred");
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['FreeTimeSlots'] == null || apiResponse.data['FreeTimeSlots'].isEmpty) {
onError!("No free slots available".tr());
return;
}
initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
// isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) {
// date = (isLiveCareSchedule != null && isLiveCareSchedule)
// ? DateUtil.convertStringToDate(element)
// :
date = DateUtil.convertStringToDateSaudiTimezone(element, int.parse(selectedDoctor.projectID.toString()));
slotsList.add(FreeSlot(date, ['slot']));
docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
});
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
}
},
);
},
);
// } catch(ex) {
// if (onError != null) {
// onError(ex.toString());
// }
// }
}
Future<void> getLiveCareDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
final DateFormat formatter = DateFormat('HH:mm', "en-US");
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed;
// final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
// Map<DateTime, List> _eventsParsed;
final result = await bookAppointmentsRepo.getLiveCareDoctorFreeSlots(
selectedDoctor.clinicID ?? 0, selectedLiveCareClinic.serviceID ?? 0, selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, isBookingForLiveCare,
@ -941,8 +948,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel);
Future<void> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: isReschedule);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
@ -1004,7 +1011,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
appointmentDate: apiResponse.data["SameClinicApptList"][0]['AppointmentDate'],
);
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: true).then((val) async {
// LoaderBottomSheet.hideLoader();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
// LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr());
@ -1062,7 +1069,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
// loadingText: LocaleKeys.reschedulingAppo.tr(context: navigationService.navigatorKey.currentContext!),
loadingText: LocaleKeys.loadingText.tr(context: navigationService.navigatorKey.currentContext!),
);
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: true).then((val) async {
LoaderBottomSheet.hideLoader();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr());
@ -1167,7 +1174,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
isCloseButtonVisible: false,
isDismissible: false,
isFullScreen: false);
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: true).then((val) async {
navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr());

@ -47,7 +47,7 @@ class FamilyFileRequest {
"SharedPatientIdentificationID": sharedPatientIdentificationId,
"SearchType": searchType,
"SharedPatientMobileNumber": sharedPatientMobileNumber,
"zipCode": zipCode,
"ZipCode": zipCode,
"isRegister": isRegister,
"PatientStatus": patientStatus,
"isDentalAllowedBackend": isDentalAllowedBackend,

@ -32,7 +32,36 @@ class HabibWalletViewModel extends ChangeNotifier {
num habibWalletAmount = 0;
num walletRechargeAmount = 0;
String notesText = "";
bool isWalletAmountToBeLoaded = true;
bool isWalletAmountToBeLoaded = false;
bool isLakumInfoToBeLoaded = false;
// ── Balance visibility (show/hide like a password field) ──────────────────
bool isWalletAmountHidden = true;
bool isLakumPointsHidden = true;
// Track whether data has already been fetched (to avoid re-calling APIs).
bool isWalletAmountFetched = false;
bool isLakumInfoFetched = false;
void toggleWalletAmountVisibility() {
isWalletAmountHidden = !isWalletAmountHidden;
notifyListeners();
// On first unhide, fetch the data if not already fetched.
if (!isWalletAmountHidden && !isWalletAmountFetched) {
isWalletAmountToBeLoaded = true;
getPatientBalanceAmount();
}
}
void toggleLakumPointsVisibility() {
isLakumPointsHidden = !isLakumPointsHidden;
notifyListeners();
// On first unhide, fetch the data if not already fetched.
if (!isLakumPointsHidden && !isLakumInfoFetched) {
isLakumInfoToBeLoaded = true;
getLakumAccountInformation();
}
}
bool isBottomSheetContentLoading = false;
@ -107,6 +136,8 @@ class HabibWalletViewModel extends ChangeNotifier {
bool isLakumAccountInfoLoading = false;
LakumInquiryInformationResponseModel? lakumAccountInfo;
// Get all flattened transactions sorted by date descending
List<PointsDetails> getAllLakumTransactions() {
if (lakumAccountInfo?.gainedPointsAmountPerYear == null) {
@ -406,6 +437,8 @@ class HabibWalletViewModel extends ChangeNotifier {
if (isWalletAmountToBeLoaded) {
isWalletAmountLoading = true;
habibWalletAmount = 0;
}
if (isLakumInfoToBeLoaded) {
isLakumAccountInfoLoading = true;
yahalaAccountNumber = "";
}
@ -482,6 +515,11 @@ class HabibWalletViewModel extends ChangeNotifier {
notifyListeners();
}
setIsLakumInfoToBeLoaded(bool value) {
isLakumInfoToBeLoaded = value;
notifyListeners();
}
String getSelectedRechargeTypeValue() {
switch (selectedRechargeType) {
case 1:
@ -520,6 +558,7 @@ class HabibWalletViewModel extends ChangeNotifier {
isWalletAmountLoading = false;
isWalletAmountToBeLoaded = false;
isWalletAmountFetched = true;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
@ -629,7 +668,7 @@ class HabibWalletViewModel extends ChangeNotifier {
}
Future<void> getLakumAccountInformation({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isWalletAmountToBeLoaded) {
if (!isLakumInfoToBeLoaded) {
return;
}
@ -645,6 +684,8 @@ class HabibWalletViewModel extends ChangeNotifier {
(failure) async {
yahalaAccountNumber = "0";
isLakumAccountInfoLoading = false;
isLakumInfoFetched = true;
isLakumInfoToBeLoaded = false;
notifyListeners(); // 675534
},
(apiResponse) async {
@ -671,6 +712,8 @@ class HabibWalletViewModel extends ChangeNotifier {
);
}
isLakumAccountInfoLoading = false;
isLakumInfoFetched = true;
isLakumInfoToBeLoaded = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);

@ -67,7 +67,7 @@ abstract class HmgServicesRepo {
Future<Either<Failure, GenericApiModel<Covid19GetPaymentInfo>>> getCovidPaymentInfo(String procedureID, int projectID);
Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign();
Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign( num? transID, int? projectID);
}
class HmgServicesRepoImp implements HmgServicesRepo {
@ -917,8 +917,11 @@ class HmgServicesRepoImp implements HmgServicesRepo {
}
@override
Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign() async {
Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign(num? transID, int? projectID) async {
Map<String, dynamic> requestBody = {
"TransID": transID,
"TransNo": transID,
"ProjectID": projectID,
};
try {

@ -895,37 +895,59 @@ class HmgServicesViewModel extends ChangeNotifier {
Future<void> getPatientVitalSign({
Function(dynamic)? onSuccess,
Function(String)? onError,
num? transNo,
int? projectID,
bool forceRefresh = false,
}) async {
if (hasVitalSignDataLoaded) return;
isVitalSignLoading = true;
notifyListeners();
final bool isSpecificQuery = (transNo != null || projectID != null);
if (!isSpecificQuery && hasVitalSignDataLoaded && !forceRefresh) {
if (onSuccess != null) {
onSuccess(GenericApiModel<List<VitalSignResModel>>(
messageStatus: 1,
data: vitalSignList,
));
}
return;
}
final result = await hmgServicesRepo.getPatientVitalSign();
if (!isSpecificQuery) {
isVitalSignLoading = true;
notifyListeners();
}
final result = await hmgServicesRepo.getPatientVitalSign(transNo, projectID);
result.fold(
(failure) async {
isVitalSignLoading = false;
notifyListeners();
if (!isSpecificQuery) {
isVitalSignLoading = false;
notifyListeners();
}
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
isVitalSignLoading = false;
if (apiResponse.messageStatus == 1) {
vitalSignList = apiResponse.data ?? [];
hasVitalSignDataLoaded = true;
if (vitalSignList.isNotEmpty) {
getIt.get<SymptomsCheckerViewModel>().setSelectedHeight(vitalSignList.first.heightCm);
getIt.get<SymptomsCheckerViewModel>().setSelectedWeight(vitalSignList.first.weightKg);
if (!isSpecificQuery) {
isVitalSignLoading = false;
if (apiResponse.messageStatus == 1) {
vitalSignList = apiResponse.data ?? [];
hasVitalSignDataLoaded = true;
if (vitalSignList.isNotEmpty) {
getIt.get<SymptomsCheckerViewModel>().setSelectedHeight(vitalSignList.first.heightCm);
getIt.get<SymptomsCheckerViewModel>().setSelectedWeight(vitalSignList.first.weightKg);
}
}
notifyListeners();
}
if (apiResponse.messageStatus == 1) {
if (onSuccess != null) {
onSuccess(apiResponse);
}
} else {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? 'Unknown error');
}

@ -101,9 +101,7 @@ class ImmediateLiveCareRepoImp implements ImmediateLiveCareRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final respObject = response['GetERAppointmentFeesList'];
final liveCareFeesObj = LiveCareImmediateAppointmentFeesList.fromJson(respObject);
apiResponse = GenericApiModel<LiveCareImmediateAppointmentFeesList>(
messageStatus: messageStatus,
statusCode: statusCode,

@ -59,16 +59,25 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
bool isShowNotEligibleDialog = false;
String notEligibleErrorMsg = "";
bool isTermsAccepted = false;
initImmediateLiveCare() {
_appState = getIt<AppState>();
immediateLiveCareClinicsList = [];
mainLiveCareClinicList = [];
isImmediateLiveCareClinicsLoading = true;
isTermsAccepted = false;
liveCareSelectedCallType = 0; // 1- Video, 2- Audio, 3- Phone
immediateLiveCareSelectedClinic = GetLiveCareClinicListResponseModel();
liveCareImmediateAppointmentFeesList = LiveCareImmediateAppointmentFeesList();
}
onTermsAccepted() {
isTermsAccepted = !isTermsAccepted;
notifyListeners();
}
setLiveCareSelectedCallType(int value) {
liveCareSelectedCallType = value;
notifyListeners();
@ -126,7 +135,9 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
result.fold(
(failure) async {
onError!(failure.message);
if(onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
@ -225,7 +236,7 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
Future<void> addNewCallRequestForImmediateLiveCare(String transID, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await immediateLiveCareRepo.addNewCallRequestForImmediateLiveCare(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!,
immediateLiveCareSelectedClinic.serviceID!, transID, liveCareSelectedCallType, false, _appState.deviceToken, await Utils.getStringFromPrefs(CacheConst.voipToken));
immediateLiveCareSelectedClinic.serviceID!, transID, liveCareSelectedCallType, false, await Utils.getStringFromPrefs(CacheConst.pushToken), await Utils.getStringFromPrefs(CacheConst.voipToken));
result.fold(
(failure) async {

@ -11,7 +11,7 @@ import 'package:hmg_patient_app_new/features/insurance/models/resp_models/upload
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class InsuranceRepo {
Future<Either<Failure, GenericApiModel<List<PatientInsuranceDetailsResponseModel>>>> getPatientInsuranceDetails();
Future<Either<Failure, GenericApiModel<List<PatientInsuranceDetailsResponseModel>>>> getPatientInsuranceDetails({bool isFromHomePage = false});
Future<Either<Failure, GenericApiModel<List<PatientInsuranceCardHistoryResponseModel>>>> getPatientInsuranceCardHistory();
@ -35,8 +35,10 @@ class InsuranceRepoImp implements InsuranceRepo {
InsuranceRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PatientInsuranceDetailsResponseModel>>>> getPatientInsuranceDetails() async {
Map<String, dynamic> mapDevice = {};
Future<Either<Failure, GenericApiModel<List<PatientInsuranceDetailsResponseModel>>>> getPatientInsuranceDetails({bool isFromHomePage = false}) async {
Map<String, dynamic> mapDevice = {
"IsFromHomePage": isFromHomePage
};
try {
GenericApiModel<List<PatientInsuranceDetailsResponseModel>>? apiResponse;

@ -32,11 +32,11 @@ class InsuranceViewModel extends ChangeNotifier {
InsuranceViewModel({required this.insuranceRepo, required this.errorHandlerService});
initInsuranceProvider() {
initInsuranceProvider({bool isFromHomePage = false}) {
if (isInsuranceDataToBeLoaded) {
patientInsuranceList.clear();
isInsuranceLoading = true;
getPatientInsuranceDetails();
getPatientInsuranceDetails(isFromHomePage: isFromHomePage);
}
patientInsuranceCardHistoryList.clear();
isInsuranceHistoryLoading = true;
@ -76,12 +76,12 @@ class InsuranceViewModel extends ChangeNotifier {
notifyListeners();
}
Future<void> getPatientInsuranceDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
Future<void> getPatientInsuranceDetails({bool isFromHomePage = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isInsuranceDataToBeLoaded) {
return;
}
final result = await insuranceRepo.getPatientInsuranceDetails();
final result = await insuranceRepo.getPatientInsuranceDetails(isFromHomePage: isFromHomePage);
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save