Merge remote-tracking branch 'origin/master'

CLINIC_ORDER_CHANGE
taha 2 days ago
commit f8dc8dfcb3

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

@ -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.** { *; }

@ -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.
@ -133,7 +133,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 +267,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 ->
@ -83,8 +95,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=true
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=-Xmx4096m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
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

@ -3,4 +3,4 @@ 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.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip

@ -16,14 +16,34 @@ 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
}
include(":app")

@ -1,12 +1 @@
{
"key": "none",
"enabled": false,
"start_date": null,
"end_date": null,
"primary_color": null,
"secondary_color": null,
"background_opacity_image": null,
"background_image_opacity": 0.2,
"header_image": null
}
[]

@ -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": "عدد الخطوات المتخذة على مدار اليوم",
@ -2054,5 +2067,9 @@
"importantNotice": "تنبيه هام",
"appDecommissionedText": "تم إيقاف هذا الإصدار من تطبيق الحبيب الطبي.\nللاستمرار في الاستفادة من الخدمات الصحية والسجلات الطبية، يرجى تحميل التطبيق الجديد.",
"appDecommissionedSubText": "نعتذر بشدة عن الإزعاج الناتج عن هذا الانتقال.",
"downloadApp": "حمل التطبيق"
"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",
@ -2044,7 +2057,11 @@
"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"
"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"
}

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

@ -59,7 +59,7 @@ post_install do |installer|
'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['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,33 +3,21 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
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 */; };
5D5A1F80D389375644C4D0DC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
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 */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -49,40 +37,40 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
76B1D2542F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Embed Frameworks */,
76B1D2522F91BF8000DBBD1B /* Penguin.xcframework in Embed Frameworks */,
76B1D2562F91BF8000DBBD1B /* 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>"; };
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>"; };
56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
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>"; };
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>"; };
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; };
@ -90,8 +78,9 @@
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; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
BCE5BC40273DCC009E2FACB7 /* 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>"; };
C6416282AC56269448D7DA99 /* 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>"; };
C6FD350374F47AFA34911C58 /* 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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -100,9 +89,8 @@
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
76B1D2512F91BF8000DBBD1B /* Penguin.xcframework in Frameworks */,
76B1D2552F91BF8000DBBD1B /* PenNavUI.xcframework in Frameworks */,
76B1D2532F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Frameworks */,
5D5A1F80D389375644C4D0DC /* Pods_Runner.framework in Frameworks */,
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
37D27FAF2C38AC83B852680C /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -121,7 +109,6 @@
61243B412EC5FA3700D46FA0 /* Helper */ = {
isa = PBXGroup;
children = (
61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */,
);
path = Helper;
sourceTree = "<group>";
@ -129,11 +116,6 @@
61243B472EC5FA3700D46FA0 /* Penguin */ = {
isa = PBXGroup;
children = (
61243B422EC5FA3700D46FA0 /* PenguinModel.swift */,
61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */,
61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */,
61243B452EC5FA3700D46FA0 /* PenguinView.swift */,
61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */,
);
path = Penguin;
sourceTree = "<group>";
@ -141,9 +123,9 @@
766D8CB22EC60BE600D05E07 /* Frameworks */ = {
isa = PBXGroup;
children = (
76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */,
76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */,
76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */,
76B714CF300E58B1004DE37A /* WidgetKit.framework */,
76B714D1300E58B1004DE37A /* SwiftUI.framework */,
56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */,
A83C76CFF9D3F92EDE3B22B4 /* Pods_Runner.framework */,
);
name = Frameworks;
@ -152,9 +134,9 @@
79DD2093A1D9674C94359FC8 /* Pods */ = {
isa = PBXGroup;
children = (
3EAE1F31D8D0AA94CA6C11EB /* Pods-Runner.debug.xcconfig */,
05E1B2A0E6844572ADA81174 /* Pods-Runner.release.xcconfig */,
7BEF44ABFEF585D64D3F266C /* Pods-Runner.profile.xcconfig */,
BCE5BC40273DCC009E2FACB7 /* Pods-Runner.debug.xcconfig */,
C6416282AC56269448D7DA99 /* Pods-Runner.release.xcconfig */,
C6FD350374F47AFA34911C58 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -197,7 +179,6 @@
children = (
76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */,
61243B412EC5FA3700D46FA0 /* Helper */,
61243B472EC5FA3700D46FA0 /* Penguin */,
769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */,
478CFA952E6E20A60064F3D7 /* Runner.entitlements */,
478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */,
@ -234,27 +215,28 @@
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
EA10FC42B68E41E75A052FAA /* [CP] Check Pods Manifest.lock */,
511FFA76807DE636962DBF91 /* [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 */,
C7E5B2C65EE0A4D64ECC826B /* [CP] Embed Pods Frameworks */,
DF2C78ED8C8F648520DF8C43 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
@ -263,12 +245,10 @@
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 2610;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@ -291,6 +271,9 @@
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
@ -339,77 +322,78 @@
);
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 */ = {
511FFA76807DE636962DBF91 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
5D78F615DF2D966539B34DE2 /* [CP] Embed Pods Frameworks */ = {
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
C7E5B2C65EE0A4D64ECC826B /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "Run Script";
outputPaths = (
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
EA10FC42B68E41E75A052FAA /* [CP] Check Pods Manifest.lock */ = {
DF2C78ED8C8F648520DF8C43 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -428,12 +412,6 @@
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -511,7 +489,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;
@ -539,8 +517,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.12;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
MARKETING_VERSION = 4.6.044;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -645,7 +623,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;
@ -696,7 +674,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;
@ -726,8 +704,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.12;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
MARKETING_VERSION = 4.6.044;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -756,8 +734,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.12;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp;
MARKETING_VERSION = 4.6.044;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -800,12 +778,14 @@
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;

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

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

@ -4,22 +4,58 @@ import FirebaseCore
import FirebaseMessaging
import GoogleMaps
@main
@objc class AppDelegate: FlutterAppDelegate {
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
func didInitializeImplicitFlutterEngine(_ engineBridge: any FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
// GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
// FirebaseApp.configure()
// initializePlatformChannels()
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
FirebaseApp.configure()
// FirebaseApp.configure()
initializePlatformChannels()
GeneratedPluginRegistrant.register(with: self)
// 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
HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController)
}
}
// 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>

@ -2,6 +2,27 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
@ -35,6 +56,7 @@
<string>comgooglemaps</string>
<string>baidumap</string>
<string>iosamap</string>
<string>whatsapp</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
@ -86,17 +108,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>

@ -209,8 +209,8 @@ class ApiClientImp implements ApiClient {
body['TokenID'] = "@dm!n";
}
body['TokenID'] = "@dm!n";
// body['PatientID'] = 7000792;
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 2101020;
// body['PatientID'] = 53320;
// body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0;
@ -223,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);
}
@ -248,7 +248,7 @@ class ApiClientImp implements ApiClient {
if (kDebugMode) {
debugPrint("uri: ${Uri.parse(url.trim())}");
var requestBodyJSON = json.encode(body);
debugPrint("body: $requestBodyJSON", wrapWidth: 2048);
debugPrint("body: $requestBodyJSON", wrapWidth: 10000);
// log("body: $requestBodyJSON");
}

@ -6,6 +6,7 @@ import 'package:myfatoorah_flutter/myfatoorah_flutter.dart';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.preProd;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -316,13 +317,18 @@ class ApiConsts {
static String googleCloudStorageENTranslationFileBaseURL = "https://storage.googleapis.com/hmg-patientapp-translations";
// ************ static values for Api ****************
static final double appVersionID = 22.3;
static final double appVersionID = 21.6;
// static final double appVersionID = 50.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

@ -52,12 +52,12 @@ class AppState {
// bool isMyFatoorahEnabled = true;
void setIsPaytabsEnabled(bool value) {
isPaytabsEnabled = value;
isPaytabsEnabled = false;
// isPaytabsEnabled = true;
}
void setIsMyFatoorahEnabled(bool value) {
isMyFatoorahEnabled = value;
isMyFatoorahEnabled = false;
// isMyFatoorahEnabled = true;
}
@ -70,7 +70,7 @@ class AppState {
bool isChildLoggedIn = false;
bool isGMSAvailable = true;
bool isAndroid = true;
bool isRatedVisible =false;
bool isRatedVisible = false;
void setAuthenticatedUser(AuthenticatedUser? authenticatedUser, {bool isFamily = false}) {
if (isFamily) {
_authenticatedChildUser = authenticatedUser;

@ -2,12 +2,13 @@ import 'package:freerasp/freerasp.dart';
final talsecConfig = TalsecConfig(
androidConfig: AndroidConfig(
packageName: 'com.cloudsolutions.HMGPatientApp',
signingCertHashes: ['6tvWaoN5coG4SnfxGbdQlcLmM0J4ePQwDjrKIg+QkV0=', 'j6VEqVhrypHMIiXiFdRLDdGwjGaMGWY7KAdBJA+Z4Pc='], // Must be the release cert hash
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.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

@ -27,6 +27,7 @@ import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.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;
@ -425,10 +426,30 @@ class PushNotificationHandler {
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 +608,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;
}

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

@ -277,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;
}
@ -286,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;
}
@ -296,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;
}
@ -303,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;
}
@ -1421,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);
@ -1518,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();

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

@ -37,7 +37,7 @@ abstract class BookAppointmentsRepo {
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,
@ -483,12 +483,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,

@ -948,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),
@ -1011,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());
@ -1069,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());
@ -1174,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,

@ -522,7 +522,7 @@ class LabViewModel extends ChangeNotifier {
labOrderResponseByAi = null;
navigationService.push(
MaterialPageRoute(
builder: (_) => LabResultDetails(recentLabResult: recentResult, testDescription: testDescription),
builder: (_) => LabResultDetails(recentLabResult: recentResult, testDescription: testDescription, labOrder: laborder),
),
);
notifyListeners();
@ -897,6 +897,8 @@ class LabViewModel extends ChangeNotifier {
}
// }
orderData["results"] = testResults;
orderData["clinic_name"] = labOrder.clinicDescription ?? "";
orderData["specialty_name"] = labOrder.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? "";
results.add(orderData);
final result = await labRepo.getPatientAiOverViewLabOrders(payload: results, langId: langId);
@ -927,7 +929,7 @@ class LabViewModel extends ChangeNotifier {
// LoadingUtils.hideFullScreenLoader();
}
Future<void> getAiOverviewSingleLabResult({required int langId, required LabResult recentLabResult, required String loadingText}) async {
Future<void> getAiOverviewSingleLabResult({required int langId, required LabResult recentLabResult, required String loadingText, required PatientLabOrdersResponseModel labOrder}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
@ -942,9 +944,9 @@ class LabViewModel extends ChangeNotifier {
"UOM": recentLabResult.uOM ?? '',
"ReferanceRange": recentLabResult.referanceRange ?? '',
});
var speciality = labOrder.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? "";
// var payload = {"patient_id": currentlySelectedPatientOrder!.patientID, "language_id": langId, "lab_results": results};
var payload = {"patient_id": getIt.get<AppState>().getAuthenticatedUser()!.patientId, "language_id": langId, "lab_results": results};
var payload = {"patient_id": getIt.get<AppState>().getAuthenticatedUser()!.patientId, "language_id": langId, "lab_results": results, "specialty_name": speciality, "clinic_name": labOrder.clinicDescription ?? ""};
final result = await labRepo.getPatientAiOverViewLabOrder(payload);
result.fold(
(failure) async {

@ -35,21 +35,15 @@ class LabOrdersResponseByAi {
class Analysis {
List<AiGeneratedAttribute>? aiGeneratedAttributes;
List<String>? aiPredictions;
List<AiRecommendation>? aiRecommendations;
List<String>? prevention;
String? rawMessage;
List<RiskFactor>? riskFactors;
List<dynamic>? suggestedDoctors;
String? summary;
Analysis({
this.aiGeneratedAttributes,
this.aiPredictions,
this.aiRecommendations,
this.prevention,
this.rawMessage,
this.riskFactors,
this.suggestedDoctors,
this.summary,
});
@ -60,22 +54,16 @@ class Analysis {
factory Analysis.fromJson(Map<String, dynamic> json) => Analysis(
aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List<AiGeneratedAttribute>.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))),
aiPredictions: json["ai_predictions"] == null ? [] : List<String>.from(json["ai_predictions"]!.map((x) => x)),
aiRecommendations: json["ai_recommendations"] == null ? [] : List<AiRecommendation>.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))),
prevention: json["prevention"] == null ? [] : List<String>.from(json["prevention"]!.map((x) => x)),
rawMessage: json["raw_message"],
riskFactors: json["riskFactors"] == null ? [] : List<RiskFactor>.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))),
suggestedDoctors: json["suggested_doctors"] == null ? [] : List<dynamic>.from(json["suggested_doctors"]!.map((x) => x)),
summary: json["summary"],
);
Map<String, dynamic> toJson() => {
"ai_generated_attributes": aiGeneratedAttributes == null ? [] : List<dynamic>.from(aiGeneratedAttributes!.map((x) => x.toJson())),
"ai_predictions": aiPredictions == null ? [] : List<dynamic>.from(aiPredictions!.map((x) => x)),
"ai_recommendations": aiRecommendations == null ? [] : List<dynamic>.from(aiRecommendations!.map((x) => x.toJson())),
"prevention": prevention == null ? [] : List<dynamic>.from(prevention!.map((x) => x)),
"raw_message": rawMessage,
"riskFactors": riskFactors == null ? [] : List<dynamic>.from(riskFactors!.map((x) => x.toJson())),
"suggested_doctors": suggestedDoctors == null ? [] : List<dynamic>.from(suggestedDoctors!.map((x) => x)),
"summary": summary,
};
}

@ -4,20 +4,14 @@ class LabOrderResponseByAi {
String? summary;
List<AiGeneratedAttribute>? aiGeneratedAttributes;
List<String>? aiPredictions;
List<AiRecommendation>? aiRecommendations;
List<RiskFactor>? riskFactors;
List<String>? prevention;
List<dynamic>? suggestedDoctors;
String? rawMessage;
LabOrderResponseByAi({
this.summary,
this.aiGeneratedAttributes,
this.aiPredictions,
this.aiRecommendations,
this.riskFactors,
this.prevention,
this.suggestedDoctors,
this.rawMessage,
});
@ -29,10 +23,7 @@ class LabOrderResponseByAi {
summary: json["summary"],
aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List<AiGeneratedAttribute>.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))),
aiPredictions: json["ai_predictions"] == null ? [] : List<String>.from(json["ai_predictions"]!.map((x) => x)),
aiRecommendations: json["ai_recommendations"] == null ? [] : List<AiRecommendation>.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))),
riskFactors: json["riskFactors"] == null ? [] : List<RiskFactor>.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))),
prevention: json["prevention"] == null ? [] : List<String>.from(json["prevention"]!.map((x) => x)),
suggestedDoctors: json["suggested_doctors"] == null ? [] : List<dynamic>.from(json["suggested_doctors"]!.map((x) => x)),
rawMessage: json["raw_message"],
);
@ -40,10 +31,7 @@ class LabOrderResponseByAi {
"summary": summary,
"ai_generated_attributes": aiGeneratedAttributes == null ? [] : List<dynamic>.from(aiGeneratedAttributes!.map((x) => x.toJson())),
"ai_predictions": aiPredictions == null ? [] : List<dynamic>.from(aiPredictions!.map((x) => x)),
"ai_recommendations": aiRecommendations == null ? [] : List<dynamic>.from(aiRecommendations!.map((x) => x.toJson())),
"riskFactors": riskFactors == null ? [] : List<dynamic>.from(riskFactors!.map((x) => x.toJson())),
"prevention": prevention == null ? [] : List<dynamic>.from(prevention!.map((x) => x)),
"suggested_doctors": suggestedDoctors == null ? [] : List<dynamic>.from(suggestedDoctors!.map((x) => x)),
"raw_message": rawMessage,
};
}

@ -45,7 +45,7 @@ class PatientLabOrdersResponseModel {
dynamic? projectNameN;
String? qR;
String? setupID;
// List<String>? speciality;
List<String>? speciality;
int? status;
String? statusDesc;
String? strOrderDate;
@ -98,7 +98,7 @@ class PatientLabOrdersResponseModel {
this.projectNameN,
this.qR,
this.setupID,
// this.speciality,
this.speciality,
this.status,
this.statusDesc,
this.strOrderDate,
@ -151,7 +151,7 @@ class PatientLabOrdersResponseModel {
projectNameN = json['ProjectNameN'];
qR = json['QR'];
setupID = json['SetupID'];
// speciality = json['Speciality'].cast<String>();
speciality = json['Speciality'] != null ? List<String>.from(json['Speciality']) : null;
status = json['Status'];
statusDesc = json['StatusDesc'];
strOrderDate = json['StrOrderDate'];
@ -211,7 +211,7 @@ class PatientLabOrdersResponseModel {
data['ProjectNameN'] = this.projectNameN;
data['QR'] = this.qR;
data['SetupID'] = this.setupID;
// data['Speciality'] = this.speciality;
data['Speciality'] = this.speciality;
data['Status'] = this.status;
data['StatusDesc'] = this.statusDesc;
data['StrOrderDate'] = this.strOrderDate;

@ -864,4 +864,17 @@ class MedicalFileViewModel extends ChangeNotifier {
print("❌ Error updating family member profile image in cache: $e");
}
}
bool checkExistingMedicalReportStatus(PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel) {
bool hasExistingRequest = false;
for (var report in patientMedicalReportRequestedList) {
if (report.clinicID == patientAppointmentHistoryResponseModel.clinicID && report.doctorID == patientAppointmentHistoryResponseModel.doctorID) {
hasExistingRequest = true;
break;
}
}
return hasExistingRequest;
}
}

@ -44,8 +44,8 @@ class AppointmentRatingViewModel extends ChangeNotifier {
);
}
Future<void> getAppointmentDetails(int appointmentID, int projectID, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.getAppointmentDetails(appointmentID, projectID);
Future<void> getAppointmentDetails(int appointmentID, int projectID, int clinicID, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.getAppointmentDetails(appointmentID, projectID, clinicID);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),

@ -44,7 +44,7 @@ abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> generateAppointmentQR({required int clinicID, required int projectID, required String appointmentNo, required int isFollowUp});
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>>> confirmAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel});
@ -72,7 +72,7 @@ abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<RateAppointmentRespModel>>>> getLastRatingAppointment();
Future<Either<Failure, GenericApiModel<AppointmentDetails>>> getAppointmentDetails(int appointmentID, int projectID);
Future<Either<Failure, GenericApiModel<AppointmentDetails>>> getAppointmentDetails(int appointmentID, int projectID, int clinicID);
Future<Either<Failure, GenericApiModel<void>>> sendAppointmentRate(int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note);
@ -341,12 +341,12 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
}
@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,
@ -915,10 +915,11 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
}
@override
Future<Either<Failure, GenericApiModel<AppointmentDetails>>> getAppointmentDetails(int appointmentID, int projectID) async {
Future<Either<Failure, GenericApiModel<AppointmentDetails>>> getAppointmentDetails(int appointmentID, int projectID, int clinicID) async {
Map<String, dynamic> mapDevice = {
"AppointmentNumber": appointmentID,
"ProjectID": projectID,
"ClinicID":clinicID
};
try {
GenericApiModel<AppointmentDetails>? apiResponse;

@ -639,8 +639,8 @@ class MyAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel);
Future<void> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: isReschedule);
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),

@ -13,11 +13,16 @@ class NotificationsViewModel extends ChangeNotifier {
ErrorHandlerService errorHandlerService;
List<NotificationResponseModel> notificationsList = [];
List<NotificationResponseModel> readdNotificationsList = [];
List<NotificationResponseModel> unreadNotificationsList = [];
List<NotificationResponseModel> allNotificationsList = [];
int currentPage = 0;
int pagingSize = 50;
int notificationStatusID = 2; // Default to status 2 (e.g., unread)
int selectedNotificationsTabIndex = 0;
NotificationsViewModel({
required this.notificationsRepo,
required this.errorHandlerService,
@ -35,6 +40,18 @@ class NotificationsViewModel extends ChangeNotifier {
notifyListeners();
}
void onNotificationTabChange(int index) {
selectedNotificationsTabIndex = index;
if (index == 0) {
notificationsList = allNotificationsList;
} else if (index == 1) {
notificationsList = unreadNotificationsList;
} else if (index == 2) {
notificationsList = readdNotificationsList;
}
notifyListeners();
}
setNotificationStatusID(int statusID) {
notificationStatusID = statusID;
notificationsList.clear();
@ -49,6 +66,9 @@ class NotificationsViewModel extends ChangeNotifier {
}) async {
isNotificationsLoading = true;
unreadNotificationsCount = 0;
notificationsList.clear();
notifyListeners();
final result = await notificationsRepo.getAllNotifications(
@ -80,17 +100,37 @@ class NotificationsViewModel extends ChangeNotifier {
hasMoreNotifications = false;
}
notificationsList.addAll(newNotifications);
for (var notification in notificationsList) {
if (notification.isRead == false) {
unreadNotificationsCount++;
try {
notificationsList.addAll(newNotifications);
// allNotificationsList.clear();
// readdNotificationsList.clear();
// unreadNotificationsList.clear();
// for (var notification in notificationsList) {
// if (notification.isRead == false) {
// unreadNotificationsCount++;
// unreadNotificationsList.add(notification);
// } else {
// readdNotificationsList.add(notification);
// }
// }
// Filter out the items directly without a loop
unreadNotificationsList = notificationsList.where((n) => n.isRead == false).toList();
readdNotificationsList = notificationsList.where((n) => n.isRead == true).toList();
// Calculate count based on the new list length
unreadNotificationsCount = unreadNotificationsList.length;
currentPage++;
allNotificationsList = notificationsList;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
currentPage++;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
} catch (ex) {
print(ex.toString());
}
}
},

@ -17,9 +17,12 @@ class OccasionConfigModel {
/// default/current theme, regardless of any other field below.
final bool enabled;
/// Optional activation window. When both are present, the theme is only
/// considered active if `DateTime.now()` falls within [startDate, endDate].
/// When null, the [enabled] flag alone controls activation.
/// Activation window. Both must be present and `DateTime.now()` must fall
/// within [startDate, endDate] for this occasion to be eligible — a
/// missing date on either side makes the occasion inactive (dates are
/// mandatory, not an optional override of [enabled]). This lets several
/// occasions be scheduled in advance in the same list (see
/// [OccasionConfigModel.resolveActive]) without colliding.
final DateTime? startDate;
final DateTime? endDate;
@ -66,6 +69,7 @@ class OccasionConfigModel {
return OccasionConfigModel(
key: (json['key'] as String?) ?? 'none',
enabled: (json['enabled'] as bool?) ?? false,
// enabled: true,
startDate: _parseDate(json['start_date']),
endDate: _parseDate(json['end_date']),
primaryColorHex: json['primary_color'] as String?,
@ -75,6 +79,25 @@ class OccasionConfigModel {
);
}
/// Parses the remote-config value as a JSON array of occasions — lets
/// several occasions be scheduled in advance (e.g. National Day, Founding
/// Day, Eid), each with its own non-overlapping [startDate]/[endDate]
/// window, all under the same `occasion_config` remote-config key.
static List<OccasionConfigModel> listFromJson(List<dynamic> jsonList) {
return jsonList.map((e) => OccasionConfigModel.fromJson(e as Map<String, dynamic>)).toList();
}
/// Picks whichever scheduled occasion is enabled and whose
/// [startDate]/[endDate] window contains `now` — first match in list
/// order wins, so entries are expected not to overlap. Returns
/// [OccasionConfigModel.disabled] when nothing matches.
static OccasionConfigModel resolveActive(List<OccasionConfigModel> configs, [DateTime? now]) {
for (final config in configs) {
if (config.enabled && config.isWithinActiveWindow(now)) return config;
}
return OccasionConfigModel.disabled();
}
static DateTime? _parseDate(dynamic value) {
if (value == null) return null;
if (value is String && value.isNotEmpty) {
@ -84,11 +107,13 @@ class OccasionConfigModel {
}
/// Whether "now" falls inside the configured activation window.
/// If no window is configured, the [enabled] flag alone decides.
/// Both [startDate] and [endDate] are required — if either is missing,
/// this occasion is never considered active (see field doc above).
bool isWithinActiveWindow([DateTime? now]) {
if (startDate == null || endDate == null) return false;
final current = now ?? DateTime.now();
if (startDate != null && current.isBefore(startDate!)) return false;
if (endDate != null && current.isAfter(endDate!)) return false;
if (current.isBefore(startDate!)) return false;
if (current.isAfter(endDate!)) return false;
return true;
}
@ -120,4 +145,3 @@ class OccasionConfigModel {
'header_image': headerImage,
};
}

@ -35,8 +35,17 @@ class OccasionThemeViewModel extends ChangeNotifier {
OccasionConfigModel _config = OccasionConfigModel.disabled();
OccasionConfigModel get config => _config;
/// Testing-only override for "now" when resolving which scheduled
/// occasion is active — set this instead of changing the device clock to
/// preview each occasion in the list. Only ever takes effect in debug
/// builds (see [_now]); always ignored in profile/release, so it can
/// never leak into production even if accidentally left set.
static DateTime? debugNowOverride;
DateTime? get _now => kDebugMode ? debugNowOverride : null;
/// True only when enabled AND (if a window is configured) within it.
bool get isOccasionActive => _config.enabled && _config.isWithinActiveWindow();
bool get isOccasionActive => _config.enabled && _config.isWithinActiveWindow(_now);
String? get backgroundOpacityImage => isOccasionActive ? _config.backgroundOpacityImage : null;
@ -66,14 +75,20 @@ class OccasionThemeViewModel extends ChangeNotifier {
}
}
/// Fetches the latest occasion config from Firebase Remote Config and
/// applies it. Safe to call again later (e.g. on app resume) to pick up
/// changes without requiring an app update.
/// Fetches the latest occasion schedule from Firebase Remote Config and
/// applies whichever entry is currently active. Safe to call again later
/// (e.g. on app resume) to pick up changes without requiring an app update.
Future<void> refresh() async {
try {
await _remoteConfigService.fetchAndActivate();
final rawJson = _remoteConfigService.occasionConfigRawJson;
_config = OccasionConfigModel.fromJson(json.decode(rawJson) as Map<String, dynamic>);
final configs = OccasionConfigModel.listFromJson(json.decode(rawJson) as List<dynamic>);
_config = OccasionConfigModel.resolveActive(configs, _now);
_loggerService.logInfo('OccasionThemeViewModel: chosen theme = "${_config.key}" (enabled=${_config.enabled}, active=$isOccasionActive)');
_loggerService.logInfo('OccasionThemeViewModel: chosen theme object = ${_config.toJson()}');
// Cache the full schedule (not just the resolved entry) so offline
// restore at next startup re-resolves against that day's date instead
// of replaying whichever occasion happened to be active last time.
await _cacheService.saveString(key: _cachedConfigKey, value: rawJson);
_applyToAppColors();
notifyListeners();
@ -91,7 +106,8 @@ class OccasionThemeViewModel extends ChangeNotifier {
_config = OccasionConfigModel.disabled();
return;
}
_config = OccasionConfigModel.fromJson(json.decode(cachedJson) as Map<String, dynamic>);
final configs = OccasionConfigModel.listFromJson(json.decode(cachedJson) as List<dynamic>);
_config = OccasionConfigModel.resolveActive(configs, _now);
} catch (ex) {
_loggerService.logError('OccasionThemeViewModel._restoreCachedConfig error: $ex');
_config = OccasionConfigModel.disabled();

@ -578,4 +578,27 @@ class PayfortViewModel extends ChangeNotifier {
);
}
Future<void> addApplePayPayfortResponse(dynamic paymentMap) async {
PayfortResponseInsertModel payfortResponseInsertModel = PayfortResponseInsertModel();
payfortResponseInsertModel.fortId = paymentMap['fort_id'] ?? "";
payfortResponseInsertModel.commandType = paymentMap['command'] ?? "";
payfortResponseInsertModel.amount = num.tryParse(paymentMap['amount'] ?? "0") ?? 0;
payfortResponseInsertModel.sadadOLP = "";
payfortResponseInsertModel.paymentOption = paymentMap['payment_option'] ?? "";
payfortResponseInsertModel.customerIP = paymentMap['customer_ip'] ?? "";
payfortResponseInsertModel.eCI = paymentMap['eci'] ?? "";
payfortResponseInsertModel.responseMessage = paymentMap['response_message'] ?? "";
payfortResponseInsertModel.cardNumber = paymentMap['card_number'] ?? "";
payfortResponseInsertModel.cardBin = paymentMap['card_bin'] ?? "";
payfortResponseInsertModel.installmentsNumber = int.tryParse(paymentMap['installments_number'] ?? "0") ?? 0;
payfortResponseInsertModel.status = paymentMap['status'] ?? "";
payfortResponseInsertModel.merchantRef = paymentMap['merchant_reference'] ?? "";
payfortResponseInsertModel.isRefund = false;
payfortResponseInsertModel.remmeberMe = true;
payfortResponseInsertModel.reconciliationReference = "";
payfortResponseInsert(payfortResponseInsertModel: payfortResponseInsertModel);
}
}

@ -36,7 +36,7 @@ class PatientPrescriptionsResponseModel {
int? noOfPatientsRate;
String? qR;
// List<String>? speciality;
List<String>? speciality;
String? strAppointmentDate;
PatientPrescriptionsResponseModel(
@ -76,7 +76,7 @@ class PatientPrescriptionsResponseModel {
this.nationalityFlagURL,
this.noOfPatientsRate,
this.qR,
// this.speciality,
this.speciality,
this.strAppointmentDate});
PatientPrescriptionsResponseModel.fromJson(Map<String, dynamic> json) {
@ -116,7 +116,7 @@ class PatientPrescriptionsResponseModel {
nationalityFlagURL = json['NationalityFlagURL'];
noOfPatientsRate = json['NoOfPatientsRate'];
qR = json['QR'];
// speciality = json['Speciality'].cast<String>();
speciality = json['Speciality'] != null ? List<String>.from(json['Speciality']) : null;
strAppointmentDate = json['StrAppointmentDate'];
}
@ -158,7 +158,7 @@ class PatientPrescriptionsResponseModel {
data['NationalityFlagURL'] = this.nationalityFlagURL;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['QR'] = this.qR;
// data['Speciality'] = this.speciality;
data['Speciality'] = this.speciality;
data['StrAppointmentDate'] = this.strAppointmentDate;
return data;
}

@ -1,17 +1,13 @@
class PrescriptionAnalysisResponse {
String? prescriptionSummary;
List<MedicineAnalysis>? medicinesAnalysis;
List<String>? importantWarnings;
List<String>? medicineInteractions;
String? followUpNeeded;
List<String>? importantNotes;
int? languageId;
PrescriptionAnalysisResponse({
this.prescriptionSummary,
this.medicinesAnalysis,
this.importantWarnings,
this.medicineInteractions,
this.followUpNeeded,
this.importantNotes,
this.languageId,
});
@ -23,9 +19,7 @@ class PrescriptionAnalysisResponse {
medicinesAnalysis!.add(MedicineAnalysis.fromJson(v));
});
}
importantWarnings = json['important_warnings'] != null ? json['important_warnings'].cast<String>() : [];
medicineInteractions = json['medicine_interactions'] != null ? json['medicine_interactions'].cast<String>() : [];
followUpNeeded = json['follow_up_needed'];
importantNotes = json['important_notes'] != null ? json['important_notes'].cast<String>() : [];
languageId = json['language_id'];
}
@ -35,9 +29,7 @@ class PrescriptionAnalysisResponse {
if (medicinesAnalysis != null) {
data['medicines_analysis'] = medicinesAnalysis!.map((v) => v.toJson()).toList();
}
data['important_warnings'] = importantWarnings;
data['medicine_interactions'] = medicineInteractions;
data['follow_up_needed'] = followUpNeeded;
data['important_notes'] = importantNotes;
data['language_id'] = languageId;
return data;
}
@ -46,23 +38,20 @@ class PrescriptionAnalysisResponse {
class MedicineAnalysis {
String? medicineName;
String? benefit;
List<String>? commonSideEffects;
List<String>? seriousWarnings;
List<String>? allergyReactions;
String? storage;
MedicineAnalysis({
this.medicineName,
this.benefit,
this.commonSideEffects,
this.seriousWarnings,
this.allergyReactions,
this.storage,
});
MedicineAnalysis.fromJson(Map<String, dynamic> json) {
medicineName = json['medicine_name'];
benefit = json['benefit'];
commonSideEffects = json['common_side_effects'] != null ? json['common_side_effects'].cast<String>() : [];
seriousWarnings = json['serious_warnings'] != null ? json['serious_warnings'].cast<String>() : [];
allergyReactions = json['allergy_reactions'] != null ? json['allergy_reactions'].cast<String>() : [];
storage = json['storage'];
}
@ -70,8 +59,7 @@ class MedicineAnalysis {
final Map<String, dynamic> data = <String, dynamic>{};
data['medicine_name'] = medicineName;
data['benefit'] = benefit;
data['common_side_effects'] = commonSideEffects;
data['serious_warnings'] = seriousWarnings;
data['allergy_reactions'] = allergyReactions;
data['storage'] = storage;
return data;
}

@ -334,7 +334,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
'X-API-KEY': '9d9d2ac4c1fc302299dbb0fbb1b7fea1',
'accept': 'application/json',
},
body: {"medicines": payload, "language_id": langId},
body: payload,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},

@ -4,6 +4,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_allergies_response_model.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
@ -64,6 +65,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices});
initPrescriptionsViewModel() {
isPrescriptionsDataNeedsReloading = true; // todo remove this
if (isPrescriptionsDataNeedsReloading) {
patientPrescriptionOrders.clear();
patientPrescriptionOrdersByClinic.clear();
@ -413,6 +415,8 @@ class PrescriptionsViewModel extends ChangeNotifier {
required int langId,
required String loadingText,
required Function(dynamic) onNavigate,
required PatientPrescriptionsResponseModel prescriptionResponseModel,
required List<GetAllergiesResponseModel> allergies,
}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
@ -424,6 +428,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
// Prepare medicines payload
List<Map<String, dynamic>> medicines = [];
List<Map<String, dynamic>> allergiesForanalysis = [];
for (var prescription in prescriptions) {
if (prescription.itemDescription != null && prescription.itemDescription!.isNotEmpty) {
medicines.add({
@ -434,8 +439,22 @@ class PrescriptionsViewModel extends ChangeNotifier {
}
}
for (var allergy in allergies) {
allergiesForanalysis.add({
"description": allergy.description ?? "",
"remarks": allergy.remarks ?? "",
});
}
var payload = {
"medicines": medicines,
"patient_allergies": allergiesForanalysis,
"langId": langId,
"clinic_name": prescriptionResponseModel.clinicDescription ?? "",
"specialty_name": prescriptionResponseModel.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? ""
};
final result = await prescriptionsRepo.getPrescriptionAiAnalysis(
payload: medicines,
payload: payload,
langId: langId,
);

@ -56,6 +56,7 @@ class PatientRadiologyResponseModel {
bool? isCVI;
bool? isRadMedicalReport;
dynamic vida3Id;
List<String>? speciality;
PatientRadiologyResponseModel(
{this.setupID,
@ -112,7 +113,9 @@ class PatientRadiologyResponseModel {
this.strOrderDate,
this.isCVI,
this.isRadMedicalReport,
this.vida3Id});
this.vida3Id,
this.speciality,
});
PatientRadiologyResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
@ -170,6 +173,7 @@ class PatientRadiologyResponseModel {
isCVI = json['isCVI'];
isRadMedicalReport = json['isRadMedicalReport'];
vida3Id = json['vida3Id'];
speciality = json['Speciality'] != null ? List<String>.from(json['Speciality']) : [];
}
Map<String, dynamic> toJson() {
@ -229,6 +233,7 @@ class PatientRadiologyResponseModel {
data['isCVI'] = this.isCVI;
data['isRadMedicalReport'] = this.isRadMedicalReport;
data['vida3Id'] = this.vida3Id;
data['Speciality'] = this.speciality;
return data;
}
}

@ -5,7 +5,6 @@ class RadiologyAiAnalysisResponse {
String? labResults;
String? aiPredictions;
String? riskFactors;
String? prevention;
int? languageId;
RadiologyAiAnalysisResponse({
@ -13,7 +12,6 @@ class RadiologyAiAnalysisResponse {
this.labResults,
this.aiPredictions,
this.riskFactors,
this.prevention,
this.languageId,
});
@ -26,7 +24,6 @@ class RadiologyAiAnalysisResponse {
labResults: json["lab_results"],
aiPredictions: json["ai_predictions"],
riskFactors: json["riskFactors"],
prevention: json["prevention"],
languageId: json["language_id"],
);
@ -35,7 +32,6 @@ class RadiologyAiAnalysisResponse {
"lab_results": labResults,
"ai_predictions": aiPredictions,
"riskFactors": riskFactors,
"prevention": prevention,
"language_id": languageId,
};
}

@ -19,7 +19,7 @@ abstract class RadiologyRepo {
Future<Either<Failure, GenericApiModel<List<PatientRadiologyResponseModel>>>> getPatientRadiologyOrderByAppointment({required num appointmentNo, required num projectID});
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required String reportData, required int langId,});
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required int langId,});
}
class RadiologyRepoImp implements RadiologyRepo {
@ -238,10 +238,12 @@ class RadiologyRepoImp implements RadiologyRepo {
}
@override
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required String reportData, required int langId}) async {
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required int langId}) async {
Map<String, dynamic> payload = {
"text": reportData,
"language_id": langId
"text": radiologyData.reportData ?? "",
"language_id": langId,
"clinic_name": radiologyData.clinicDescription ?? "",
"specialty_name":radiologyData.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? ""
};
try {

@ -229,7 +229,7 @@ class RadiologyViewModel extends ChangeNotifier {
}
Future<void> getRadiologyAiAnalysis({required String reportData, required String loadingText, required int langId}) async {
Future<void> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required String loadingText, required int langId}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
@ -237,7 +237,7 @@ class RadiologyViewModel extends ChangeNotifier {
},
);
final result = await radiologyRepo.getRadiologyAiAnalysis(reportData: reportData, langId: langId);
final result = await radiologyRepo.getRadiologyAiAnalysis(radiologyData: radiologyData, langId: langId);
result.fold(
(failure) async {

@ -1,4 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:health/health.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart';
@ -119,15 +120,22 @@ class HealthProvider with ChangeNotifier {
void initDevice() async {
LoaderBottomSheet.showLoader();
notifyListeners();
error = null;
final result = await _healthService.initDevice();
isLoading = false;
LoaderBottomSheet.hideLoader();
// LoaderBottomSheet.hideLoader();
if (result.isError) {
error = 'Error initializing device: ${result.asError}';
LoaderBottomSheet.hideLoader();
final rawError = result.asError?.error;
if (rawError is PlatformException) {
error = 'Error initializing device: ${rawError.message ?? rawError.toString()}';
} else {
error = 'Error initializing device: ${rawError?.toString() ?? 'Unknown error'}';
}
} else {
LoaderBottomSheet.showLoader();
// LoaderBottomSheet.showLoader();
await getVitals();
// LoaderBottomSheet.hideLoader();
LoaderBottomSheet.hideLoader();
// await Future.delayed(Duration(seconds: 5));
getIt.get<NavigationService>().pushPage(page: SmartWatchesHealthDataScreen());
}
@ -286,4 +294,9 @@ class HealthProvider with ChangeNotifier {
}
return formattedString;
}
void clearError(){
error = null;
notifyListeners();
}
}

@ -22,6 +22,7 @@ class Vitals {
if (timestamp.isEmpty) {
timestamp = DateTime.now().toIso8601String();
}
timestamp = DateTime.parse(timestamp).toLocal().toIso8601String();
return Vitals(
value: map['value'] ?? "",
timestamp: timestamp,

@ -0,0 +1 @@
class IllegalWatchTypeException implements Exception {}

@ -6,6 +6,8 @@ import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connec
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/samsung_health.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart';
import 'IllegalWatchTypeException.dart';
class CreateWatchHelper {
static WatchHelper getWatchName(SmartWatchTypes watchType) {
/// if running device is ios
@ -16,7 +18,7 @@ class CreateWatchHelper {
case SmartWatchTypes.huawei:
return HuaweiHealthDataConnector();
default:
return SamsungHealth();
throw IllegalWatchTypeException();
}
}
}

@ -1,86 +1,403 @@
import 'dart:async';
import 'dart:convert';
import 'package:async/src/result/result.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/model/vitals_data_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart';
import 'package:http/http.dart';
import 'package:huawei_health/huawei_health.dart';
class HuaweiHealthDataConnector extends WatchHelper{
final MethodChannel _channel = MethodChannel('huawei_watch');
@override
Future<Result<bool>> initDevice() async{
try{
await _channel.invokeMethod('init');
}catch(e){
DataController? _dataController;
final Map<String, List<Vitals>> mappedData = <String, List<Vitals>>{};
DateTime get _defaultEndDate => DateTime.now();
DateTime get _defaultStartDate => _defaultEndDate.subtract(const Duration(days: 365));
@override
Future<Result<bool>> initDevice() async {
try {
await _channel.invokeMethod('init');
} catch (e) {
debugPrint('Huawei channel init failed: $e');
}
// List of scopes to ask for authorization.
// Note: These scopes should also be authorized on the Huawei Developer Console.
List<Scope> scopes = [
Scope.HEALTHKIT_STEP_READ, Scope.HEALTHKIT_OXYGEN_SATURATION_READ, // View and store height and weight data in Health Service Kit.
Scope.HEALTHKIT_HEARTRATE_READ, Scope.HEALTHKIT_SLEEP_READ,
Scope.HEALTHKIT_BODYTEMPERATURE_READ, Scope.HEALTHKIT_CALORIES_READ
final List<Scope> scopes = <Scope>[
Scope.HEALTHKIT_ACTIVITY_READ,
Scope.HEALTHKIT_ACTIVITY_WRITE,
Scope.HEALTHKIT_BLOODGLUCOSE_READ,
Scope.HEALTHKIT_BLOODGLUCOSE_WRITE,
Scope.HEALTHKIT_CALORIES_READ,
Scope.HEALTHKIT_CALORIES_WRITE,
Scope.HEALTHKIT_DISTANCE_READ,
Scope.HEALTHKIT_DISTANCE_WRITE,
Scope.HEALTHKIT_HEARTRATE_READ,
Scope.HEALTHKIT_HEARTRATE_WRITE,
Scope.HEALTHKIT_HEIGHTWEIGHT_READ,
Scope.HEALTHKIT_HEIGHTWEIGHT_WRITE,
Scope.HEALTHKIT_LOCATION_READ,
Scope.HEALTHKIT_LOCATION_WRITE,
Scope.HEALTHKIT_PULMONARY_READ,
Scope.HEALTHKIT_PULMONARY_WRITE,
Scope.HEALTHKIT_SLEEP_READ,
Scope.HEALTHKIT_SLEEP_WRITE,
Scope.HEALTHKIT_SPEED_READ,
Scope.HEALTHKIT_SPEED_WRITE,
Scope.HEALTHKIT_STEP_READ,
Scope.HEALTHKIT_STEP_WRITE,
Scope.HEALTHKIT_STRENGTH_READ,
Scope.HEALTHKIT_STRENGTH_WRITE,
Scope.HEALTHKIT_BODYFAT_READ,
Scope.HEALTHKIT_BODYFAT_WRITE,
Scope.HEALTHKIT_NUTRITION_READ,
Scope.HEALTHKIT_NUTRITION_WRITE,
Scope.HEALTHKIT_BLOODPRESSURE_READ,
Scope.HEALTHKIT_BLOODPRESSURE_WRITE,
Scope.HEALTHKIT_BODYTEMPERATURE_READ,
Scope.HEALTHKIT_BODYTEMPERATURE_WRITE,
Scope.HEALTHKIT_OXYGENSTATURATION_READ,
Scope.HEALTHKIT_OXYGENSTATURATION_WRITE,
Scope.HEALTHKIT_REPRODUCTIVE_READ,
Scope.HEALTHKIT_REPRODUCTIVE_WRITE,
Scope.HEALTHKIT_ACTIVITY_RECORD_READ,
Scope.HEALTHKIT_ACTIVITY_RECORD_WRITE,
Scope.HEALTHKIT_HEARTRATE_REALTIME,
Scope.HEALTHKIT_STEP_REALTIME,
Scope.HEALTHKIT_HEARTHEALTH_WRITE,
Scope.HEALTHKIT_HEARTHEALTH_READ,
Scope.HEALTHKIT_STRESS_WRITE,
Scope.HEALTHKIT_STRESS_READ,
Scope.HEALTHKIT_OXYGEN_SATURATION_WRITE,
Scope.HEALTHKIT_OXYGEN_SATURATION_READ,
Scope.HEALTHKIT_HISTORYDATA_OPEN_WEEK,
Scope.HEALTHKIT_HISTORYDATA_OPEN_MONTH,
Scope.HEALTHKIT_HISTORYDATA_OPEN_YEAR,
];
try {
bool? result = await SettingController.getHealthAppAuthorization();
debugPrint(
'Granted Scopes for result == is $result}',
);
await HealthAuth.signIn(scopes);
_dataController = await DataController.init();
if (_dataController == null) {
return Result.error(false);
}
return Result.value(true);
} on PlatformException catch (e) {
debugPrint('Error on Huawei authorization: $e');
return Result.error(false);
} catch (e) {
debugPrint('Error on authorization, Error:${e.toString()}');
debugPrint('Unexpected Huawei init error: $e');
return Result.error(false);
}
}
@override
Future<void> getActivity() async {
DataType dataTypeResult = await SettingController.readDataType(
DataType.DT_CONTINUOUS_STEPS_DELTA.name
);
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_CALORIES_BURNT,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('activity', data, preferredKeys: const <String>['calories', 'calories_total']);
} catch (e) {
debugPrint('Error getting activity data: $e');
mappedData['activity'] = <Vitals>[];
}
}
@override
Future getBloodOxygen() {
throw UnimplementedError();
Future<void> getBloodOxygen() async {
try {
final ReadReply? data = await readDataType(
HealthDataTypes.DT_INSTANTANEOUS_SPO2,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap(
'bloodOxygen',
data,
preferredKeys: const <String>['saturation', 'saturation_last', 'saturation_avg'],
transform: _normalizeSpo2,
);
} catch (e) {
debugPrint('Error getting blood oxygen data: $e');
mappedData['bloodOxygen'] = <Vitals>[];
}
}
@override
Future<void> getBodyTemperature() async {
try {
final ReadReply? data = await readDataType(
HealthDataTypes.DT_INSTANTANEOUS_BODY_TEMPERATURE,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('bodyTemperature', data, preferredKeys: const <String>['temperature']);
} catch (e) {
debugPrint('Error getting body temperature data: $e');
mappedData['bodyTemperature'] = <Vitals>[];
}
}
@override
Future getBodyTemperature() {
FutureOr<void> getHeartRate() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_INSTANTANEOUS_HEART_RATE,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('heartRate', data, preferredKeys: const <String>['bpm']);
} catch (e) {
debugPrint('Error getting heart rate data: $e');
mappedData['heartRate'] = <Vitals>[];
}
}
throw UnimplementedError();
@override
FutureOr<void> getSleep() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_SLEEP,
_defaultStartDate,
_defaultEndDate,
);
addSleepDataToMap(data);
} catch (e) {
debugPrint('Error getting sleep data: $e');
mappedData['sleep'] = <Vitals>[];
}
}
@override
FutureOr<void> getHeartRate() {
throw UnimplementedError();
FutureOr<void> getSteps() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_STEPS_DELTA,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('steps', data, preferredKeys: const <String>['steps_delta', 'steps', 'step_rate']);
} catch (e) {
debugPrint('Error getting steps data: $e');
mappedData['steps'] = <Vitals>[];
}
}
@override
FutureOr<void> getSleep() {
throw UnimplementedError();
Future<Result<String>> retrieveData() async {
return Result.value(getMappedData());
}
@override
FutureOr<void> getSteps() {
throw UnimplementedError();
FutureOr<void> getDistance() async {
try {
final ReadReply? data = await readDataType(
DataType.DT_CONTINUOUS_DISTANCE_DELTA,
_defaultStartDate,
_defaultEndDate,
);
addDataToMap('distance', data, preferredKeys: const <String>['distance_delta', 'distance']);
} catch (e) {
debugPrint('Error getting distance data: $e');
mappedData['distance'] = <Vitals>[];
}
}
Future<ReadReply?> readDataType(
DataType dataType,
DateTime startTime,
DateTime endTime,
) async {
final DataCollector dataCollector = DataCollector(
dataType: dataType,
dataGenerateType: DataGenerateType.DATA_TYPE_RAW,
);
@override
Future retrieveData() {
throw UnimplementedError();
final ReadOptions readOptions = ReadOptions(
dataCollectors: <DataCollector>[dataCollector],
startTime: startTime,
endTime: endTime,
allowRemoteInquiry: true,
)..groupByTime(1, timeUnit: TimeUnit.HOURS);
try {
return await _dataController?.read(readOptions);
} on PlatformException catch (e) {
debugPrint('Huawei read error for ${dataType.name}: $e');
return null;
}
}
@override
FutureOr<void> getDistance() {
// TODO: implement getDistance
throw UnimplementedError();
void addDataToMap(
String key,
ReadReply? data, {
List<String> preferredKeys = const <String>[],
double Function(double value)? transform,
}) {
mappedData[key] = <Vitals>[];
if (data == null) {
return;
}
if (data.groups.isNotEmpty) {
for (final Group group in data.groups) {
for (final SampleSet sampleSet in group.sampleSets ?? <SampleSet>[]) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
_addNumericSampleToMappedData(
key: key,
samplePoint: samplePoint,
preferredKeys: preferredKeys,
groupStartTime: group.startTime,
transform: transform,
);
}
}
}
return;
}
for (final SampleSet sampleSet in data.sampleSets) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
_addNumericSampleToMappedData(
key: key,
samplePoint: samplePoint,
preferredKeys: preferredKeys,
transform: transform,
);
}
}
}
void addSleepDataToMap(ReadReply? data) {
mappedData['sleep'] = <Vitals>[];
if (data == null) {
return;
}
void appendSleepPoint(SamplePoint samplePoint, {DateTime? groupStart, DateTime? groupEnd}) {
final DateTime? start = samplePoint.startTime ?? groupStart;
final DateTime? end = samplePoint.endTime ?? groupEnd;
double? value;
if (start != null && end != null && end.isAfter(start)) {
value = end.difference(start).inMinutes / 60;
}
value ??= _extractNumericValue(
samplePoint,
const <String>['sleep_state', 'all_sleep_time', 'deep_sleep_time', 'light_sleep_time'],
);
if (value == null) {
return;
}
final String timestamp =
(start ?? samplePoint.samplingTime ?? DateTime.now()).toIso8601String();
mappedData['sleep']?.add(
Vitals(
value: value.toStringAsFixed(2),
timestamp: timestamp,
),
);
}
if (data.groups.isNotEmpty) {
for (final Group group in data.groups) {
for (final SampleSet sampleSet in group.sampleSets ?? <SampleSet>[]) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
appendSleepPoint(
samplePoint,
groupStart: group.startTime,
groupEnd: group.endTime,
);
}
}
}
return;
}
for (final SampleSet sampleSet in data.sampleSets) {
for (final SamplePoint samplePoint in sampleSet.samplePoints) {
appendSleepPoint(samplePoint);
}
}
}
void _addNumericSampleToMappedData({
required String key,
required SamplePoint samplePoint,
required List<String> preferredKeys,
DateTime? groupStartTime,
double Function(double value)? transform,
}) {
final double? numericValue = _extractNumericValue(samplePoint, preferredKeys);
if (numericValue == null) {
return;
}
final double transformedValue = transform?.call(numericValue) ?? numericValue;
final String timestamp =
(samplePoint.samplingTime ?? samplePoint.startTime ?? groupStartTime ?? DateTime.now())
.toIso8601String();
mappedData[key]?.add(
Vitals(
value: transformedValue.toStringAsFixed(2),
timestamp: timestamp,
),
);
}
double? _extractNumericValue(SamplePoint samplePoint, List<String> preferredKeys) {
final Map<String, dynamic> values = <String, dynamic>{
...samplePoint.pairs,
...?samplePoint.fieldValues,
};
for (final String key in preferredKeys) {
final dynamic value = values[key];
if (value is num) {
return value.toDouble();
}
}
for (final dynamic value in values.values) {
if (value is num) {
return value.toDouble();
}
}
return null;
}
double _normalizeSpo2(double value) {
if (value <= 1) {
return value * 100;
}
return value;
}
String getMappedData() {
return jsonEncode(<String, dynamic>{
'heartRate': (mappedData['heartRate'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'sleep': (mappedData['sleep'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'steps': (mappedData['steps'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'activity': (mappedData['activity'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'bloodOxygen':
(mappedData['bloodOxygen'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'bodyTemperature':
(mappedData['bodyTemperature'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
'distance': (mappedData['distance'] ?? <Vitals>[]).map((Vitals v) => v.toJson()).toList(),
});
}
}
}

@ -57,7 +57,8 @@ class DefaultFirebaseOptions {
databaseURL: 'https://api-project-815750722565.firebaseio.com',
storageBucket: 'api-project-815750722565.firebasestorage.app',
androidClientId: '815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com',
iosBundleId: 'com.cloudsolutions.HMGPatientApp',
// iosBundleId: 'com.cloudsolutions.HMGPatientApp',
iosBundleId: 'com.HMG.HMG-Smartphone',
);
}

@ -2036,5 +2036,10 @@ abstract class LocaleKeys {
static const appDecommissionedText = 'appDecommissionedText';
static const appDecommissionedSubText = 'appDecommissionedSubText';
static const downloadApp = 'downloadApp';
static const unread = 'unread';
static const read = 'read';
static const pendingMedicalReportRequest = 'pendingMedicalReportRequest';
static const viewAttachment = 'viewAttachment';
static const AllergyReactions = 'AllergyReactions';
}

@ -73,7 +73,6 @@ import 'core/utils/size_utils.dart';
import 'features/monthly_reports/terms_conditions_view_model.dart';
import 'firebase_options.dart';
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
@ -132,6 +131,7 @@ Future<void> callInitializations() async {
} catch (e) {
// If it doesn't exist, initialize it.
await Firebase.initializeApp(
name: "api-project-815750722565",
options: DefaultFirebaseOptions.currentPlatform,
);
}
@ -143,7 +143,11 @@ Future<void> callInitializations() async {
// Initialize Security Service early to catch threats before app logic runs
if (kReleaseMode) {
await getIt.get<SecurityService>().initialize();
try {
await getIt.get<SecurityService>().initialize();
} catch (e) {
getIt.get<LoggerService>().logError('SecurityService.initialize failed, continuing app startup: $e');
}
}
// Set up critical threat callback to navigate to unsafe device page
@ -176,6 +180,8 @@ Future<void> callInitializations() async {
// disabled by default — the app looks exactly as it does today until
// Remote Config enables an occasion (e.g. National Day) on the server side.
final occasionThemeViewModel = getIt.get<OccasionThemeViewModel>();
OccasionThemeViewModel.debugNowOverride = DateTime.now();
// OccasionThemeViewModel.debugNowOverride = DateTime.parse('2027-03-09T00:00:00Z');
unawaited(occasionThemeViewModel.initialize());
}

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

Loading…
Cancel
Save