diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/100.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/100.png new file mode 100644 index 00000000..c58db45d Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/100.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/1024.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 00000000..4598286b Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/114.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/114.png new file mode 100644 index 00000000..c32a2d52 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/114.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/120.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 00000000..96ebea5e Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/120.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/144.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/144.png new file mode 100644 index 00000000..bc29e159 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/144.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/152.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/152.png new file mode 100644 index 00000000..8412a820 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/152.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/167.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 00000000..8d4dba19 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/180.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 00000000..44b2a86d Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/180.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/20.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/20.png new file mode 100644 index 00000000..26b9d996 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/20.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/29.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 00000000..965753e5 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/29.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/40.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 00000000..8f553ae1 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/40.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/50.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/50.png new file mode 100644 index 00000000..d100f81e Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/50.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/57.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/57.png new file mode 100644 index 00000000..744aa3ba Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/57.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/58.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 00000000..4487359a Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/58.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/60.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 00000000..60de1354 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/60.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/72.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/72.png new file mode 100644 index 00000000..7586d123 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/72.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/76.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 00000000..f5691889 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/80.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/80.png new file mode 100644 index 00000000..340d82bc Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/80.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/87.png b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/87.png new file mode 100644 index 00000000..4e751666 Binary files /dev/null and b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/87.png differ diff --git a/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..65b74d7e --- /dev/null +++ b/AppIcons_NewApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1 @@ +{"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"}]} \ No newline at end of file diff --git a/AppIcons_NewApp/appstore.png b/AppIcons_NewApp/appstore.png new file mode 100644 index 00000000..4598286b Binary files /dev/null and b/AppIcons_NewApp/appstore.png differ diff --git a/AppIcons_NewApp/playstore.png b/AppIcons_NewApp/playstore.png new file mode 100644 index 00000000..a1da25a3 Binary files /dev/null and b/AppIcons_NewApp/playstore.png differ diff --git a/agconnect-services_NewApp.json b/agconnect-services_NewApp.json new file mode 100644 index 00000000..66f04d15 --- /dev/null +++ b/agconnect-services_NewApp.json @@ -0,0 +1 @@ +{"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"}}]} \ No newline at end of file diff --git a/android/app/agconnect-services.json b/android/app/agconnect-services.json index 91aad2c7..66f04d15 100644 --- a/android/app/agconnect-services.json +++ b/android/app/agconnect-services.json @@ -1,74 +1 @@ -{ - "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" - } - } - ] -} +{"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"}}]} \ No newline at end of file diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 5d74c4d0..d9d2f0be 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -18,12 +18,14 @@ if (keystorePropertiesFile.exists()) { } android { - namespace = "com.ejada.hmg" +// namespace = "com.ejada.hmg" + namespace = "com.cloudsolutions.HMGPatientApp" compileSdk = 36 ndkVersion = "28.2.13676358" defaultConfig { - applicationId = "com.ejada.hmg" +// applicationId = "com.ejada.hmg" + applicationId = "com.cloudsolutions.HMGPatientApp" // minSdk = 24 minSdk = 26 targetSdk = 36 diff --git a/android/app/google-services.json b/android/app/google-services.json index 3707617c..49bf1ace 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -3,9 +3,45 @@ "project_number": "815750722565", "firebase_url": "https://api-project-815750722565.firebaseio.com", "project_id": "api-project-815750722565", - "storage_bucket": "api-project-815750722565.appspot.com" + "storage_bucket": "api-project-815750722565.firebasestorage.app" }, "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", diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8c1388b5..54e1a5ee 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="com.cloudsolutions.HMGPatientApp"> + + + + + + + + + --> - + + + + diff --git a/android/app/src/main/kotlin/com/ejada/hmg/Application.kt b/android/app/src/main/kotlin/com/ejada/hmg/Application.kt deleted file mode 100644 index 32eb97cc..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/Application.kt +++ /dev/null @@ -1,27 +0,0 @@ -//package com.cloud.diplomaticquarterapp -package com.ejada.hmg - - -import io.flutter.app.FlutterApplication - -class Application : FlutterApplication() { - override fun onCreate() { - super.onCreate() - } -} - -//import io.flutter.app.FlutterApplication -//import io.flutter.plugin.common.PluginRegistry -//import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback -//import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService -// -//class Application : FlutterApplication(), PluginRegistrantCallback { -// override fun onCreate() { -// super.onCreate() -// FlutterFirebaseMessagingService.setPluginRegistrant(this) -// } -// -// override fun registerWith(registry: PluginRegistry?) { -// FirebaseCloudMessagingPluginRegistrant.registerWith(registry) -// } -//} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt b/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt deleted file mode 100644 index b81a6fb0..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.ejada.hmg - -import android.app.PendingIntent -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build -import android.util.Log -import android.view.WindowManager -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi -import com.ejada.hmg.penguin.PenguinInPlatformBridge -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -import io.flutter.embedding.android.FlutterFragmentActivity - - -class MainActivity: FlutterFragmentActivity() { - @RequiresApi(Build.VERSION_CODES.O) - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - // Create Flutter Platform Bridge - this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) - - PenguinInPlatformBridge(flutterEngine, this).create() - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - - val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } - val intent = Intent("PERMISSION_RESULT_ACTION").apply { - putExtra("PERMISSION_GRANTED", granted) - } - sendBroadcast(intent) - - // Log the request code and permission results - Log.d("PermissionsResult", "Request Code: $requestCode") - Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}") - Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}") - - } - - override fun onResume() { - super.onResume() - } -} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PenguinInPlatformBridge.kt b/android/app/src/main/kotlin/com/ejada/hmg/PenguinInPlatformBridge.kt deleted file mode 100644 index 4df25bc9..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PenguinInPlatformBridge.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.ejada.hmg.penguin - -import com.ejada.hmg.MainActivity -import android.os.Build -import android.util.Log -import androidx.annotation.RequiresApi -import com.ejada.hmg.penguin.PenguinView -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.MethodCall -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( - private var flutterEngine: FlutterEngine, - private var mainActivity: MainActivity -) { - - private lateinit var channel: MethodChannel - - companion object { - private const val CHANNEL = "launch_penguin_ui" - } - - @RequiresApi(Build.VERSION_CODES.O) - fun create() { -// openTok = OpenTok(mainActivity, flutterEngine) - channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) - channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> - when (call.method) { - "launchPenguin" -> { - print("the platform channel is being called") - - if (HostNotificationPermissionManager.isNotificationPermissionGranted(mainActivity)) - else HostNotificationPermissionManager.requestNotificationPermission(mainActivity) - HostBgLocationManager.requestLocationBackgroundPermission(mainActivity) - HostGpsStateManager.requestLocationPermission(mainActivity) - val args = call.arguments as Map? - Log.d("TAG", "configureFlutterEngine: $args") - println("args") - args?.let { - PenguinView( - mainActivity, - 100, - args, - flutterEngine.dartExecutor.binaryMessenger, - activity = mainActivity, - channel - ) - } - } - - else -> { - result.notImplemented() - } - } - } - } - -} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/AppPreferences.java b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/AppPreferences.java deleted file mode 100644 index d0127998..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/AppPreferences.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.ejada.hmg.PermissionManager; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Handler; -import android.os.HandlerThread; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; - - -/** - * This preferences for app level - */ - -public class AppPreferences { - - public static final String PREF_NAME = "PenguinINUI_AppPreferences"; - public static final int MODE = Context.MODE_PRIVATE; - - public static final String campusIdKey = "campusId"; - - public static final String LANG = "Lang"; - - public static final String settingINFO = "SETTING-INFO"; - - public static final String userName = "userName"; - public static final String passWord = "passWord"; - - private static HandlerThread handlerThread; - private static Handler handler; - - static { - handlerThread = new HandlerThread("PreferencesHandlerThread"); - handlerThread.start(); - handler = new Handler(handlerThread.getLooper()); - } - - - - public static SharedPreferences getPreferences(final Context context) { - return context.getSharedPreferences(AppPreferences.PREF_NAME, AppPreferences.MODE); - } - - public static SharedPreferences.Editor getEditor(final Context context) { - return getPreferences(context).edit(); - } - - - public static void writeInt(final Context context, final String key, final int value) { - handler.post(() -> { - SharedPreferences.Editor editor = getEditor(context); - editor.putInt(key, value); - editor.apply(); - }); - } - - - public static int readInt(final Context context, final String key, final int defValue) { - Callable callable = () -> { - SharedPreferences preferences = getPreferences(context); - return preferences.getInt(key, -1); - }; - - Future future = new FutureTask<>(callable); - handler.post((Runnable) future); - - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); // Handle the exception appropriately - } - - return -1; // Return the default value in case of an error - } - - public static int getCampusId(final Context context) { - return readInt(context,campusIdKey,-1); - } - - - - public static void writeString(final Context context, final String key, final String value) { - handler.post(() -> { - SharedPreferences.Editor editor = getEditor(context); - editor.putString(key, value); - editor.apply(); - }); - } - - - public static String readString(final Context context, final String key, final String defValue) { - Callable callable = () -> { - SharedPreferences preferences = getPreferences(context); - return preferences.getString(key, defValue); - }; - - Future future = new FutureTask<>(callable); - handler.post((Runnable) future); - - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); // Handle the exception appropriately - } - - return defValue; // Return the default value in case of an error - } - - - public static void writeBoolean(final Context context, final String key, final boolean value) { - handler.post(() -> { - SharedPreferences.Editor editor = getEditor(context); - editor.putBoolean(key, value); - editor.apply(); - }); - } - - public static boolean readBoolean(final Context context, final String key, final boolean defValue) { - Callable callable = () -> { - SharedPreferences preferences = getPreferences(context); - return preferences.getBoolean(key, defValue); - }; - - Future future = new FutureTask<>(callable); - handler.post((Runnable) future); - - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); // Handle the exception appropriately - } - - return defValue; // Return the default value in case of an error - } - -} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostBgLocationManager.java b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostBgLocationManager.java deleted file mode 100644 index 5bc332dc..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostBgLocationManager.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.ejada.hmg.PermissionManager; - -import android.Manifest; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.provider.Settings; - -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; - -import com.peng.pennavmap.PlugAndPlaySDK; -import com.peng.pennavmap.R; -import com.peng.pennavmap.enums.InitializationErrorType; - -/** - * Manages background location permission requests and handling for the application. - */ -public class HostBgLocationManager { - /** - * Request code for background location permission - */ - public static final int REQUEST_ACCESS_BACKGROUND_LOCATION_CODE = 301; - - /** - * Request code for navigating to app settings - */ - private static final int REQUEST_CODE_SETTINGS = 11234; - - /** - * Alert dialog for denied permissions - */ - private static AlertDialog deniedAlertDialog; - - /** - * Checks if the background location permission has been granted. - * - * @param context the context of the application or activity - * @return true if the permission is granted, false otherwise - */ - - public static boolean isLocationBackgroundGranted(Context context) { - return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) - == PackageManager.PERMISSION_GRANTED; - } - - /** - * Requests the background location permission from the user. - * - * @param activity the activity from which the request is made - */ - public static void requestLocationBackgroundPermission(Activity activity) { - // Check if the ACCESS_BACKGROUND_LOCATION permission is already granted - if (!isLocationBackgroundGranted(activity)) { - // Permission is not granted, so request it - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, - REQUEST_ACCESS_BACKGROUND_LOCATION_CODE); - } - } - - /** - * Displays a dialog prompting the user to grant the background location permission. - * - * @param activity the activity where the dialog is displayed - */ - public static void showLocationBackgroundPermission(Activity activity) { - AlertDialog alertDialog = new AlertDialog.Builder(activity) - .setCancelable(false) - .setMessage(activity.getString(R.string.com_penguin_nav_ui_geofence_alert_msg)) - .setPositiveButton(activity.getString(R.string.com_penguin_nav_ui_go_to_settings), (dialog, which) -> { - if (activity.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { - HostBgLocationManager.requestLocationBackgroundPermission(activity); - } else { - openAppSettings(activity); - } - if (dialog != null) { - dialog.dismiss(); - } - }) - .setNegativeButton(activity.getString(R.string.com_penguin_nav_ui_later), (dialog, which) -> { - dialog.cancel(); - }) - .create(); - - alertDialog.show(); - } - - /** - * Handles the scenario where permissions are denied by the user. - * Displays a dialog to guide the user to app settings or exit the activity. - * - * @param activity the activity where the dialog is displayed - */ - public static synchronized void handlePermissionsDenied(Activity activity) { - if (deniedAlertDialog != null && deniedAlertDialog.isShowing()) { - deniedAlertDialog.dismiss(); - } - - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setCancelable(false) - .setMessage(activity.getString(R.string.com_penguin_nav_ui_permission_denied_dialog_msg)) - .setNegativeButton(activity.getString(R.string.com_penguin_nav_ui_cancel), (dialogInterface, i) -> { - if (PlugAndPlaySDK.externalPenNavUIDelegate != null) { - PlugAndPlaySDK.externalPenNavUIDelegate.onPenNavInitializationError( - InitializationErrorType.permissions.getTypeKey(), - InitializationErrorType.permissions); - } - activity.finish(); - }) - .setPositiveButton(activity.getString(R.string.com_penguin_nav_ui_go_settings), (dialogInterface, i) -> { - dialogInterface.dismiss(); - openAppSettings(activity); - }); - deniedAlertDialog = builder.create(); - deniedAlertDialog.show(); - } - - /** - * Opens the application's settings screen to allow the user to modify permissions. - * - * @param activity the activity from which the settings screen is launched - */ - private static void openAppSettings(Activity activity) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - Uri uri = Uri.fromParts("package", activity.getPackageName(), null); - intent.setData(uri); - - if (intent.resolveActivity(activity.getPackageManager()) != null) { - activity.startActivityForResult(intent, REQUEST_CODE_SETTINGS); - } - } -} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostGpsStateManager.java b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostGpsStateManager.java deleted file mode 100644 index adde1206..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostGpsStateManager.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.ejada.hmg.PermissionManager; - -import android.Manifest; -import android.app.Activity; -import android.content.Context; -import android.content.pm.PackageManager; -import android.location.LocationManager; - -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; - -import com.peng.pennavmap.managers.permissions.managers.BgLocationManager; - -public class HostGpsStateManager { - private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; - - - public boolean checkGPSEnabled(Activity activity) { - LocationManager gpsStateManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); - return gpsStateManager.isProviderEnabled(LocationManager.GPS_PROVIDER); - } - - public static boolean isGpsGranted(Activity activity) { - return BgLocationManager.isLocationBackgroundGranted(activity) - || ContextCompat.checkSelfPermission( - activity, - Manifest.permission.ACCESS_FINE_LOCATION - ) == PackageManager.PERMISSION_GRANTED - && ContextCompat.checkSelfPermission( - activity, - Manifest.permission.ACCESS_COARSE_LOCATION - ) == PackageManager.PERMISSION_GRANTED; - } - - - /** - * Checks if the location permission is granted. - * - * @param activity the Activity context - * @return true if permission is granted, false otherwise - */ - public static boolean isLocationPermissionGranted(Activity activity) { - return ContextCompat.checkSelfPermission( - activity, - Manifest.permission.ACCESS_FINE_LOCATION - ) == PackageManager.PERMISSION_GRANTED && - ContextCompat.checkSelfPermission( - activity, - Manifest.permission.ACCESS_COARSE_LOCATION - ) == PackageManager.PERMISSION_GRANTED; - } - - /** - * Requests the location permission. - * - * @param activity the Activity context - */ - public static void requestLocationPermission(Activity activity) { - ActivityCompat.requestPermissions( - activity, - new String[]{ - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - }, - LOCATION_PERMISSION_REQUEST_CODE - ); - } -} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostNotificationPermissionManager.java b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostNotificationPermissionManager.java deleted file mode 100644 index 5b9f19e6..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/HostNotificationPermissionManager.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ejada.hmg.PermissionManager; - -import android.app.Activity; -import android.content.pm.PackageManager; -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; -import androidx.core.app.NotificationManagerCompat; - -public class HostNotificationPermissionManager { - private static final int REQUEST_NOTIFICATION_PERMISSION = 100; - - - /** - * Checks if the notification permission is granted. - * - * @return true if the notification permission is granted, false otherwise. - */ - public static boolean isNotificationPermissionGranted(Activity activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - try { - return ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.POST_NOTIFICATIONS) - == PackageManager.PERMISSION_GRANTED; - } catch (Exception e) { - // Handle cases where the API is unavailable - e.printStackTrace(); - return NotificationManagerCompat.from(activity).areNotificationsEnabled(); - } - } else { - // Permissions were not required below Android 13 for notifications - return NotificationManagerCompat.from(activity).areNotificationsEnabled(); - } - } - - /** - * Requests the notification permission. - */ - public static void requestNotificationPermission(Activity activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - if (!isNotificationPermissionGranted(activity)) { - ActivityCompat.requestPermissions(activity, - new String[]{android.Manifest.permission.POST_NOTIFICATIONS}, - REQUEST_NOTIFICATION_PERMISSION); - } - } - } - - /** - * Handles the result of the permission request. - * - * @param requestCode The request code passed in requestPermissions(). - * @param permissions The requested permissions. - * @param grantResults The grant results for the corresponding permissions. - */ - public static boolean handlePermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (permissions.length > 0 && - permissions[0].equals(android.Manifest.permission.POST_NOTIFICATIONS) && - grantResults.length > 0 && - grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // Permission granted - System.out.println("Notification permission granted."); - return true; - } else { - // Permission denied - System.out.println("Notification permission denied."); - return false; - } - - } - - -} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionHelper.kt b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionHelper.kt deleted file mode 100644 index 9856a49e..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionHelper.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.ejada.hmg.PermissionManager - -import android.Manifest -import android.os.Build - -object PermissionHelper { - - fun getRequiredPermissions(): Array { - val permissions = mutableListOf( - Manifest.permission.INTERNET, - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.ACCESS_NETWORK_STATE, - Manifest.permission.BLUETOOTH, - Manifest.permission.BLUETOOTH_ADMIN, -// Manifest.permission.ACTIVITY_RECOGNITION - ) - - // For Android 12 (API level 31) and above, add specific permissions -// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above - permissions.add(Manifest.permission.BLUETOOTH_SCAN) - permissions.add(Manifest.permission.BLUETOOTH_CONNECT) - permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS) -// } - - return permissions.toTypedArray() - } -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionManager.kt b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionManager.kt deleted file mode 100644 index d8aea7bd..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionManager.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.ejada.hmg.PermissionManager - -import android.app.Activity -import android.content.Context -import android.content.pm.PackageManager -import android.os.Build -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat - -class PermissionManager( - private val context: Context, - val listener: PermissionListener, - private val requestCode: Int, - vararg permissions: String -) { - - private val permissionsArray = permissions - - interface PermissionListener { - fun onPermissionGranted() - fun onPermissionDenied() - } - - fun arePermissionsGranted(): Boolean { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - permissionsArray.all { - ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED - } - } else { - true - } - } - - fun requestPermissions(activity: Activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - ActivityCompat.requestPermissions(activity, permissionsArray, requestCode) - } - } - - fun handlePermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - if (this.requestCode == requestCode) { - val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } - if (allGranted) { - listener.onPermissionGranted() - } else { - listener.onPermissionDenied() - } - } - } -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionResultReceiver.kt b/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionResultReceiver.kt deleted file mode 100644 index c07d1ded..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/PermissionManager/PermissionResultReceiver.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.ejada.hmg.PermissionManager - -// PermissionResultReceiver.kt -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent - -class PermissionResultReceiver( - private val callback: (Boolean) -> Unit -) : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false - callback(granted) - } -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinMethod.kt b/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinMethod.kt deleted file mode 100644 index 18463d26..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinMethod.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.ejada.hmg.penguin - -enum class PenguinMethod { - // initializePenguin("initializePenguin"), - // configurePenguin("configurePenguin"), - // showPenguinUI("showPenguinUI"), - // onPenNavUIDismiss("onPenNavUIDismiss"), - // onReportIssue("onReportIssue"), - // onPenNavSuccess("onPenNavSuccess"), - onPenNavInitializationError // onLocationOffCampus("onLocationOffCampus"), - // navigateToPOI("navigateToPOI"), - // openSharedLocation("openSharedLocation"); -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinNavigator.kt b/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinNavigator.kt deleted file mode 100644 index 70889d37..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinNavigator.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.ejada.hmg.penguin - -import android.content.Context -import com.google.gson.Gson -import com.peng.pennavmap.PlugAndPlaySDK -import com.peng.pennavmap.connections.ApiController -import com.peng.pennavmap.interfaces.RefIdDelegate -import com.peng.pennavmap.models.TokenModel -import com.peng.pennavmap.models.postmodels.PostToken -import com.peng.pennavmap.utils.AppSharedData -import okhttp3.ResponseBody -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import android.util.Log - - -class PenguinNavigator() { - - fun navigateTo(mContext: Context, refID: String, delegate: RefIdDelegate,clientID : String,clientKey : String ) { - val postToken = PostToken(clientID, clientKey) - getToken(mContext, postToken, object : RefIdDelegate { - override fun onRefByIDSuccess(PoiId: String?) { - Log.e("navigateTo", "PoiId is+++++++ $refID") - - PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate { - override fun onRefByIDSuccess(PoiId: String?) { - Log.e("navigateTo", "PoiId 2is+++++++ $PoiId") - - delegate.onRefByIDSuccess(refID) - - } - - override fun onGetByRefIDError(error: String?) { - delegate.onRefByIDSuccess(error) - } - - }) - - - } - - override fun onGetByRefIDError(error: String?) { - delegate.onRefByIDSuccess(error) - } - - }) - - } - - fun getToken(mContext: Context, postToken: PostToken?, apiTokenCallBack: RefIdDelegate) { - try { - // Create the API call - val purposesCall: Call = ApiController.getInstance(mContext) - .apiMethods - .getToken(postToken) - - // Enqueue the call for asynchronous execution - purposesCall.enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful() && response.body() != null) { - try { - response.body()?.use { responseBody -> - val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content - if (responseBodyString.isNotEmpty()) { - val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java) - if (tokenModel != null && tokenModel.token != null) { - AppSharedData.apiToken = tokenModel.token - apiTokenCallBack.onRefByIDSuccess(tokenModel.token) - } else { - apiTokenCallBack.onGetByRefIDError("Failed to parse token model") - } - } else { - apiTokenCallBack.onGetByRefIDError("Response body is empty") - } - } - } catch (e: Exception) { - apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}") - } - } else { - apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code()) - } - } - - override fun onFailure(call: Call, t: Throwable) { - apiTokenCallBack.onGetByRefIDError(t.message) - } - }) - } catch (error: Exception) { - apiTokenCallBack.onGetByRefIDError("Exception during API call: $error") - } - } - -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt b/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt deleted file mode 100644 index 3925ca56..00000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt +++ /dev/null @@ -1,377 +0,0 @@ -package com.ejada.hmg.penguin - -import android.app.Activity -import android.content.Context -import android.content.Context.RECEIVER_EXPORTED -import android.content.IntentFilter -import android.graphics.Color -import android.os.Build -import android.util.Log -import android.view.View -import android.view.ViewGroup -import android.widget.RelativeLayout -import android.widget.Toast -import androidx.annotation.RequiresApi -import com.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 -import com.peng.pennavmap.interfaces.PenNavUIDelegate -import com.peng.pennavmap.utils.Languages -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.platform.PlatformView -import com.ejada.hmg.penguin.PenguinNavigator -import com.peng.pennavmap.interfaces.PIEventsDelegate -import com.peng.pennavmap.interfaces.PILocationDelegate -import com.peng.pennavmap.interfaces.RefIdDelegate -import com.peng.pennavmap.models.LocationMessage -import com.peng.pennavmap.models.PIReportIssue -import java.util.ArrayList -import penguin.com.pennav.renderer.PIRendererSettings - -/** - * Custom PlatformView for displaying Penguin UI components within a Flutter app. - * Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls, - * and `PenNavUIDelegate` for handling SDK events. - */ -@RequiresApi(Build.VERSION_CODES.O) -internal class PenguinView( - context: Context, - id: Int, - val creationParams: Map, - messenger: BinaryMessenger, - activity: MainActivity, - val channel: MethodChannel -) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate, PIEventsDelegate, - PILocationDelegate { - // The layout for displaying the Penguin UI - private val mapLayout: RelativeLayout = RelativeLayout(context) - private val _context: Context = context - - private val permissionResultReceiver: PermissionResultReceiver - private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION") - - private companion object { - const val PERMISSIONS_REQUEST_CODE = 1 - } - - private lateinit var permissionManager: PermissionManager - - // Reference to the main activity - private var _activity: Activity = activity - - private lateinit var mContext: Context - - lateinit var navigator: PenguinNavigator - - init { - // Set layout parameters for the mapLayout - mapLayout.layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT - ) - - mContext = context - - - permissionResultReceiver = PermissionResultReceiver { granted -> - if (granted) { - onPermissionsGranted() - } else { - onPermissionsDenied() - } - } - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - mContext.registerReceiver( - permissionResultReceiver, - permissionIntentFilter, - RECEIVER_EXPORTED - ) - } else { - mContext.registerReceiver( - permissionResultReceiver, - permissionIntentFilter, - ) - } - - // Set the background color of the layout - mapLayout.setBackgroundColor(Color.RED) - - permissionManager = PermissionManager( - context = mContext, - listener = object : PermissionManager.PermissionListener { - override fun onPermissionGranted() { - // Handle permissions granted - onPermissionsGranted() - } - - override fun onPermissionDenied() { - // Handle permissions denied - onPermissionsDenied() - } - }, - requestCode = PERMISSIONS_REQUEST_CODE, - PermissionHelper.getRequiredPermissions().get(0) - ) - - if (!permissionManager.arePermissionsGranted()) { - permissionManager.requestPermissions(_activity) - } else { - // Permissions already granted - permissionManager.listener.onPermissionGranted() - } - - - } - - private fun onPermissionsGranted() { - // Handle the actions when permissions are granted - Log.d("PermissionsResult", "onPermissionsGranted") - // Register the platform view factory for creating custom views - - // Initialize the Penguin SDK - initPenguin() - - - } - - private fun onPermissionsDenied() { - // Handle the actions when permissions are denied - Log.d("PermissionsResult", "onPermissionsDenied") - - } - - /** - * Returns the view associated with this PlatformView. - * - * @return The main view for this PlatformView. - */ - override fun getView(): View { - return mapLayout - } - - /** - * Cleans up resources associated with this PlatformView. - */ - override fun dispose() { - // Cleanup code if needed - } - - /** - * Handles method calls from Dart code. - * - * @param call The method call from Dart. - * @param result The result callback to send responses back to Dart. - */ - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - // Handle method calls from Dart code here - } - - /** - * Initializes the Penguin SDK with custom configuration and delegates. - */ - private fun initPenguin() { - navigator = PenguinNavigator() - // Configure the PlugAndPlaySDK - val language = when (creationParams["languageCode"] as String) { - "ar" -> Languages.ar - "en" -> Languages.en - else -> { - Languages.en - } - } - - -// PlugAndPlaySDK.configuration = Builder() -// .setClientData(MConstantsDemo.CLIENT_ID, MConstantsDemo.CLIENT_KEY) -// .setLanguageID(selectedLanguage) -// .setBaseUrl(MConstantsDemo.DATA_URL, MConstantsDemo.POSITION_URL) -// .setServiceName(MConstantsDemo.DATA_SERVICE_NAME, MConstantsDemo.POSITION_SERVICE_NAME) -// .setUserName(name) -// .setSimulationModeEnabled(isSimulation) -// .setCustomizeColor(if (MConstantsDemo.APP_COLOR != null) MConstantsDemo.APP_COLOR else "#2CA0AF") -// .setEnableBackButton(MConstantsDemo.SHOW_BACK_BUTTON) -// .setCampusId(MConstantsDemo.selectedCampusId) -// -// .setShowUILoader(true) -// .build() - - PIRendererSettings.styleUri = "mapbox://styles/rwaid/cm3h30b36007v01qz7ik8a0sk" - - PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder() - .setBaseUrl( - creationParams["dataURL"] as String, - creationParams["positionURL"] as String - ) - .setServiceName( - creationParams["dataServiceName"] as String, - creationParams["positionServiceName"] as String - ) - .setClientData( - creationParams["clientID"] as String, - creationParams["clientKey"] as String - ) - .setUserName(creationParams["username"] as String) -// .setLanguageID(Languages.en) - .setLanguageID(language) - .setSimulationModeEnabled(creationParams["isSimulationModeEnabled"] as Boolean) - .setEnableBackButton(true) -// .setDeepLinkData("deeplink") - .setCustomizeColor("#2CA0AF") - .setDeepLinkSchema("", "") - .setIsEnableReportIssue(true) - .setDeepLinkData("") - .setEnableSharedLocationCallBack(false) - .setShowUILoader(true) - .setCampusId(creationParams["projectID"] as Int) - .build() - - - Log.d( - "TAG", - "initPenguin: ${creationParams["projectID"]}" - ) - - Log.d( - "TAG", - "initPenguin: creation param are ${creationParams}" - ) - - // Set location delegate to handle location updates -// PlugAndPlaySDK.setPiLocationDelegate { - // Example code to handle location updates - // Uncomment and modify as needed - // if (location.size() > 0) - // Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show() -// } - - // Set events delegate for reporting issues -// PlugAndPlaySDK.setPiEventsDelegate(new PIEventsDelegate() { -// @Override -// public void onReportIssue(PIReportIssue issue) { -// Log.e("Issue Reported: ", issue.getReportType()); -// } -// // Implement issue reporting logic here } -// @Override -// public void onSharedLocation(String link) { -// // Implement Shared location logic here -// } -// }) - - // Start the Penguin SDK - PlugAndPlaySDK.setPiEventsDelegate(this) - PlugAndPlaySDK.setPiLocationDelegate(this) - PlugAndPlaySDK.start(mContext, this) - } - - - /** - * Navigates to the specified reference ID. - * - * @param refID The reference ID to navigate to. - */ - fun navigateTo(refID: String) { - try { - if (refID.isBlank()) { - Log.e("navigateTo", "Invalid refID: The reference ID is blank.") - } -// referenceId = refID - navigator.navigateTo(mContext, refID,object : RefIdDelegate { - override fun onRefByIDSuccess(PoiId: String?) { - Log.e("navigateTo", "PoiId is penguin view+++++++ $PoiId") - -// channelFlutter.invokeMethod( -// PenguinMethod.navigateToPOI.name, -// "navigateTo Success" -// ) - } - - override fun onGetByRefIDError(error: String?) { - Log.e("navigateTo", "error is penguin view+++++++ $error") - -// channelFlutter.invokeMethod( -// PenguinMethod.navigateToPOI.name, -// "navigateTo Failed: Invalid refID" -// ) - } - } , creationParams["clientID"] as String, creationParams["clientKey"] as String ) - - } catch (e: Exception) { - Log.e("navigateTo", "Exception occurred during navigation: ${e.message}", e) -// channelFlutter.invokeMethod( -// PenguinMethod.navigateToPOI.name, -// "Failed: Exception - ${e.message}" -// ) - } - } - - /** - * Called when Penguin UI setup is successful. - * - * @param warningCode Optional warning code received from the SDK. - */ - override fun onPenNavSuccess(warningCode: String?) { - val clinicId = creationParams["clinicID"] as String - - if(clinicId.isEmpty()) return - - navigateTo(clinicId) -// navigateTo("3-1") - } - - /** - * Called when there is an initialization error with Penguin UI. - * - * @param description Description of the error. - * @param errorType Type of initialization error. - */ - override fun onPenNavInitializationError( - description: String?, - errorType: InitializationErrorType? - ) { - val arguments: Map = mapOf( - "description" to description, - "type" to errorType?.name - ) - Log.d( - "description", - "description : ${description}" - ) - - channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments) - Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show() - } - - /** - * Called when Penguin UI is dismissed. - */ - override fun onPenNavUIDismiss() { - // Handle UI dismissal if needed - try { - mContext.unregisterReceiver(permissionResultReceiver) - dispose(); - } catch (e: IllegalArgumentException) { - Log.e("PenguinView", "Receiver not registered: $e") - } - } - - override fun onReportIssue(issue: PIReportIssue?) { - TODO("Not yet implemented") - } - - override fun onSharedLocation(link: String?) { - TODO("Not yet implemented") - } - - override fun onLocationOffCampus(location: ArrayList?) { - TODO("Not yet implemented") - } - - override fun onLocationMessage(locationMessage: LocationMessage?) { - TODO("Not yet implemented") - } -} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b..00000000 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png index 348b5116..06095ae4 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79..00000000 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png index 410b1b1e..cb15fb64 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d43914..00000000 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png index bb9943af..b5d6eb9a 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d3..00000000 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png index 0b9d9359..3774c262 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372ee..00000000 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png index aaa9808d..a211290c 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png differ diff --git a/android/google-services.json b/android/google-services.json index 3707617c..49bf1ace 100644 --- a/android/google-services.json +++ b/android/google-services.json @@ -3,9 +3,45 @@ "project_number": "815750722565", "firebase_url": "https://api-project-815750722565.firebaseio.com", "project_id": "api-project-815750722565", - "storage_bucket": "api-project-815750722565.appspot.com" + "storage_bucket": "api-project-815750722565.firebasestorage.app" }, "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", diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 6d0842d7..1c91fb7c 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -19,6 +19,9 @@ pluginManagement { 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 } diff --git a/assets/animations/lottie/checkmark.json b/assets/animations/lottie/checkmark.json old mode 100755 new mode 100644 index 998a9155..57b67e2f --- a/assets/animations/lottie/checkmark.json +++ b/assets/animations/lottie/checkmark.json @@ -1,767 +1 @@ -{ - "nm": "HDFC Success", - "h": 512, - "w": 512, - "meta": { - "g": "LottieFiles AE 1.0.0" - }, - "layers": [ - { - "ty": 4, - "nm": "check", - "sr": 1, - "st": 0, - "op": 240, - "ip": 0, - "hasMask": false, - "ao": 0, - "ks": { - "a": { - "a": 0, - "k": [ - 0, - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 100, - 100, - 100 - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 256, - 256, - 0 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - }, - "ef": [], - "shapes": [ - { - "ty": "gr", - "nm": "Shape 1", - "it": [ - { - "ty": "sh", - "nm": "Path 1", - "d": 1, - "ks": { - "a": 0, - "k": { - "c": false, - "i": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 0 - ] - ], - "o": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0, - 0 - ] - ], - "v": [ - [ - -82.5, - 4.5 - ], - [ - -31, - 55 - ], - [ - 73, - -52.5 - ] - ] - } - } - }, - { - "ty": "tm", - "nm": "Trim Paths 1", - "e": { - "a": 1, - "k": [ - { - "o": { - "x": 1, - "y": 0.076 - }, - "i": { - "x": 0.667, - "y": 1 - }, - "s": [ - 0 - ], - "t": 60 - }, - { - "s": [ - 100 - ], - "t": 85 - } - ] - }, - "o": { - "a": 0, - "k": 0 - }, - "s": { - "a": 0, - "k": 0 - }, - "m": 1 - }, - { - "ty": "st", - "nm": "Stroke 1", - "lc": 2, - "lj": 2, - "ml": 1, - "o": { - "a": 0, - "k": 100 - }, - "w": { - "a": 0, - "k": 30 - }, - "c": { - "a": 0, - "k": [ - 1, - 1, - 1 - ] - } - }, - { - "ty": "tr", - "a": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - } - ] - } - ], - "ind": 1 - }, - { - "ty": 4, - "nm": "Shape Layer 2", - "sr": 1, - "st": 0, - "op": 240, - "ip": 0, - "hasMask": false, - "ao": 0, - "ks": { - "a": { - "a": 0, - "k": [ - 0, - 0, - 0 - ] - }, - "s": { - "a": 1, - "k": [ - { - "o": { - "x": 0.656, - "y": 0.872 - }, - "i": { - "x": 0, - "y": 0.98 - }, - "s": [ - 0, - 0, - 100 - ], - "t": 20 - }, - { - "s": [ - 150, - 150, - 100 - ], - "t": 60 - } - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 256, - 257.86, - 0 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - }, - "ef": [], - "shapes": [ - { - "ty": "gr", - "nm": "Ellipse 1", - "it": [ - { - "ty": "el", - "nm": "Ellipse Path 1", - "d": 1, - "p": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 236, - 236 - ] - } - }, - { - "ty": "fl", - "nm": "Fill 1", - "c": { - "a": 0, - "k": [ - 0.094, - 0.761, - 0.451 - ] - }, - "r": 1, - "o": { - "a": 0, - "k": 100 - } - }, - { - "ty": "tr", - "a": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 0, - -3 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - } - ] - } - ], - "ind": 2 - }, - { - "ty": 4, - "nm": "Shape Layer 1", - "sr": 1, - "st": 0, - "op": 240, - "ip": 0, - "hasMask": false, - "ao": 0, - "ks": { - "a": { - "a": 0, - "k": [ - 0, - 0, - 0 - ] - }, - "s": { - "a": 1, - "k": [ - { - "o": { - "x": 0.477, - "y": 0.587 - }, - "i": { - "x": 0, - "y": 0.999 - }, - "s": [ - 0, - 0, - 100 - ], - "t": 10 - }, - { - "o": { - "x": 0.167, - "y": 0.167 - }, - "i": { - "x": 0.833, - "y": 0.833 - }, - "s": [ - 150, - 150, - 100 - ], - "t": 50 - }, - { - "o": { - "x": 0.167, - "y": 0 - }, - "i": { - "x": 0.833, - "y": 1 - }, - "s": [ - 150, - 150, - 100 - ], - "t": 76 - }, - { - "s": [ - 210, - 210, - 100 - ], - "t": 123 - } - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 256, - 257.86, - 0 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 1, - "k": [ - { - "o": { - "x": 0.912, - "y": 0.073 - }, - "i": { - "x": 0.626, - "y": 0.729 - }, - "s": [ - 100 - ], - "t": 76 - }, - { - "s": [ - 0 - ], - "t": 119 - } - ] - } - }, - "ef": [], - "shapes": [ - { - "ty": "gr", - "nm": "Ellipse 1", - "it": [ - { - "ty": "el", - "nm": "Ellipse Path 1", - "d": 1, - "p": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 236, - 236 - ] - } - }, - { - "ty": "st", - "nm": "Stroke 1", - "lc": 1, - "lj": 1, - "ml": 4, - "o": { - "a": 0, - "k": 100 - }, - "w": { - "a": 0, - "k": 2 - }, - "c": { - "a": 0, - "k": [ - 1, - 1, - 1 - ] - } - }, - { - "ty": "fl", - "nm": "Fill 1", - "c": { - "a": 0, - "k": [ - 0.784, - 0.945, - 0.878 - ] - }, - "r": 1, - "o": { - "a": 0, - "k": 100 - } - }, - { - "ty": "tr", - "a": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 0, - -3 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - } - ] - } - ], - "ind": 3 - }, - { - "ty": 4, - "nm": "BG", - "sr": 1, - "st": 0, - "op": 240, - "ip": 0, - "hasMask": false, - "ao": 0, - "ks": { - "a": { - "a": 0, - "k": [ - 0, - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 100, - 100, - 100 - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - 256, - 256, - 0 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - }, - "ef": [], - "shapes": [ - { - "ty": "gr", - "nm": "Rectangle 1", - "it": [ - { - "ty": "rc", - "nm": "Rectangle Path 1", - "d": 1, - "p": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "s": { - "a": 0, - "k": [ - 554, - 556 - ] - } - }, - { - "ty": "fl", - "nm": "Fill 1", - "c": { - "a": 0, - "k": [ - 0.972, - 0.972, - 0.972 - ] - }, - "r": 1, - "o": { - "a": 0, - "k": 100 - } - }, - { - "ty": "tr", - "a": { - "a": 0, - "k": [ - 0, - 0 - ] - }, - "s": { - "a": 0, - "k": [ - 100, - 100 - ] - }, - "sk": { - "a": 0, - "k": 0 - }, - "p": { - "a": 0, - "k": [ - -1, - 6 - ] - }, - "r": { - "a": 0, - "k": 0 - }, - "sa": { - "a": 0, - "k": 0 - }, - "o": { - "a": 0, - "k": 100 - } - } - ] - } - ], - "ind": 4 - } - ], - "v": "4.8.0", - "fr": 60, - "op": 130, - "ip": 0, - "assets": [] -} \ No newline at end of file +{"nm":"Main Scene","ddd":0,"h":512,"w":512,"meta":{"g":"@lottiefiles/creator 1.75.0"},"layers":[{"ty":4,"nm":"check","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,256],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-82.5,4.5],[-31,55],[73,-52.5]]},"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":1,"y":0.076},"i":{"x":0.667,"y":1},"s":[0],"t":60},{"s":[100],"t":85}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":2,"ml":1,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":30,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.656,"y":0.872},"i":{"x":0,"y":0.98},"s":[0,0,100],"t":20},{"s":[150,150,100],"t":60}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,257.86],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[236,236],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.7608,0.451],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,-3],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.477,"y":0.587},"i":{"x":0,"y":0.999},"s":[0,0,100],"t":10},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[150,150,100],"t":50},{"o":{"x":0.167,"y":0},"i":{"x":0.833,"y":1},"s":[150,150,100],"t":76},{"s":[210,210,100],"t":123}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256,257.86],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.912,"y":0.073},"i":{"x":0.626,"y":0.729},"s":[100],"t":76},{"s":[0],"t":119}],"ix":11}},"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[236,236],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.7843,0.9451,0.8784],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,-3],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3}],"v":"5.7.0","fr":60,"op":130,"ip":0,"assets":[]} \ No newline at end of file diff --git a/assets/animations/lottie/checkmark_old.json b/assets/animations/lottie/checkmark_old.json new file mode 100755 index 00000000..998a9155 --- /dev/null +++ b/assets/animations/lottie/checkmark_old.json @@ -0,0 +1,767 @@ +{ + "nm": "HDFC Success", + "h": 512, + "w": 512, + "meta": { + "g": "LottieFiles AE 1.0.0" + }, + "layers": [ + { + "ty": 4, + "nm": "check", + "sr": 1, + "st": 0, + "op": 240, + "ip": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 256, + 256, + 0 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "nm": "Shape 1", + "it": [ + { + "ty": "sh", + "nm": "Path 1", + "d": 1, + "ks": { + "a": 0, + "k": { + "c": false, + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -82.5, + 4.5 + ], + [ + -31, + 55 + ], + [ + 73, + -52.5 + ] + ] + } + } + }, + { + "ty": "tm", + "nm": "Trim Paths 1", + "e": { + "a": 1, + "k": [ + { + "o": { + "x": 1, + "y": 0.076 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 0 + ], + "t": 60 + }, + { + "s": [ + 100 + ], + "t": 85 + } + ] + }, + "o": { + "a": 0, + "k": 0 + }, + "s": { + "a": 0, + "k": 0 + }, + "m": 1 + }, + { + "ty": "st", + "nm": "Stroke 1", + "lc": 2, + "lj": 2, + "ml": 1, + "o": { + "a": 0, + "k": 100 + }, + "w": { + "a": 0, + "k": 30 + }, + "c": { + "a": 0, + "k": [ + 1, + 1, + 1 + ] + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + } + ] + } + ], + "ind": 1 + }, + { + "ty": 4, + "nm": "Shape Layer 2", + "sr": 1, + "st": 0, + "op": 240, + "ip": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ] + }, + "s": { + "a": 1, + "k": [ + { + "o": { + "x": 0.656, + "y": 0.872 + }, + "i": { + "x": 0, + "y": 0.98 + }, + "s": [ + 0, + 0, + 100 + ], + "t": 20 + }, + { + "s": [ + 150, + 150, + 100 + ], + "t": 60 + } + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 256, + 257.86, + 0 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "nm": "Ellipse 1", + "it": [ + { + "ty": "el", + "nm": "Ellipse Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 236, + 236 + ] + } + }, + { + "ty": "fl", + "nm": "Fill 1", + "c": { + "a": 0, + "k": [ + 0.094, + 0.761, + 0.451 + ] + }, + "r": 1, + "o": { + "a": 0, + "k": 100 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 0, + -3 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + } + ] + } + ], + "ind": 2 + }, + { + "ty": 4, + "nm": "Shape Layer 1", + "sr": 1, + "st": 0, + "op": 240, + "ip": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ] + }, + "s": { + "a": 1, + "k": [ + { + "o": { + "x": 0.477, + "y": 0.587 + }, + "i": { + "x": 0, + "y": 0.999 + }, + "s": [ + 0, + 0, + 100 + ], + "t": 10 + }, + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 150, + 150, + 100 + ], + "t": 50 + }, + { + "o": { + "x": 0.167, + "y": 0 + }, + "i": { + "x": 0.833, + "y": 1 + }, + "s": [ + 150, + 150, + 100 + ], + "t": 76 + }, + { + "s": [ + 210, + 210, + 100 + ], + "t": 123 + } + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 256, + 257.86, + 0 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 1, + "k": [ + { + "o": { + "x": 0.912, + "y": 0.073 + }, + "i": { + "x": 0.626, + "y": 0.729 + }, + "s": [ + 100 + ], + "t": 76 + }, + { + "s": [ + 0 + ], + "t": 119 + } + ] + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "nm": "Ellipse 1", + "it": [ + { + "ty": "el", + "nm": "Ellipse Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 236, + 236 + ] + } + }, + { + "ty": "st", + "nm": "Stroke 1", + "lc": 1, + "lj": 1, + "ml": 4, + "o": { + "a": 0, + "k": 100 + }, + "w": { + "a": 0, + "k": 2 + }, + "c": { + "a": 0, + "k": [ + 1, + 1, + 1 + ] + } + }, + { + "ty": "fl", + "nm": "Fill 1", + "c": { + "a": 0, + "k": [ + 0.784, + 0.945, + 0.878 + ] + }, + "r": 1, + "o": { + "a": 0, + "k": 100 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 0, + -3 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + } + ] + } + ], + "ind": 3 + }, + { + "ty": 4, + "nm": "BG", + "sr": 1, + "st": 0, + "op": 240, + "ip": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 256, + 256, + 0 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "nm": "Rectangle 1", + "it": [ + { + "ty": "rc", + "nm": "Rectangle Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "s": { + "a": 0, + "k": [ + 554, + 556 + ] + } + }, + { + "ty": "fl", + "nm": "Fill 1", + "c": { + "a": 0, + "k": [ + 0.972, + 0.972, + 0.972 + ] + }, + "r": 1, + "o": { + "a": 0, + "k": 100 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + -1, + 6 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + } + ] + } + ], + "ind": 4 + } + ], + "v": "4.8.0", + "fr": 60, + "op": 130, + "ip": 0, + "assets": [] +} \ No newline at end of file diff --git a/assets/images/png/full_body_back_female.png b/assets/images/png/full_body_back_female.png new file mode 100644 index 00000000..9b3aa74d Binary files /dev/null and b/assets/images/png/full_body_back_female.png differ diff --git a/assets/images/png/full_body_back.png b/assets/images/png/full_body_back_male.png similarity index 100% rename from assets/images/png/full_body_back.png rename to assets/images/png/full_body_back_male.png diff --git a/assets/images/png/full_body_front_female.png b/assets/images/png/full_body_front_female.png new file mode 100644 index 00000000..c89608b0 Binary files /dev/null and b/assets/images/png/full_body_front_female.png differ diff --git a/assets/images/png/full_body_front.png b/assets/images/png/full_body_front_male.png similarity index 100% rename from assets/images/png/full_body_front.png rename to assets/images/png/full_body_front_male.png diff --git a/assets/images/svg/livecare_audio.svg b/assets/images/svg/livecare_audio.svg new file mode 100644 index 00000000..339d5347 --- /dev/null +++ b/assets/images/svg/livecare_audio.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svg/livecare_phone.svg b/assets/images/svg/livecare_phone.svg new file mode 100644 index 00000000..1722f0fc --- /dev/null +++ b/assets/images/svg/livecare_phone.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svg/livecare_video.svg b/assets/images/svg/livecare_video.svg new file mode 100644 index 00000000..bab506f8 --- /dev/null +++ b/assets/images/svg/livecare_video.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index ba7c12fc..800a9cdb 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -46,7 +46,7 @@ "nationality": "الجنسية", "neverWait": "لا تنتظر في الطابور أبدًا", "reminderTitle": "لديك موعد مع الدكتور.", - "appointmentCalendar": "هل ترغب في ضبط تذكير لهذا الموعد في تقويمك؟", + "appointmentCalendar": "هل ترغب في تعيين تذكير لهذا الموعد في التقويم الخاص بك؟", "appointmentSuccess": "تم حجز الموعد بنجاح", "docQualifications": "مؤهلات الطبيب", "pressAgain": "اضغط مرة أخرى للخروج من التطبيق", @@ -58,7 +58,7 @@ "patientShare": "نسبة المريض", "patientShareWithTax": "نسبة المريض مع الضريبة", "confirmAppo": "تأكيد الموعد", - "confirmLiveCare": "تأكيد الرعاية الحية", + "confirmLiveCare": "تأكيد ال لايف كير", "waitingForDoctor": "في انتظار الطبيب", "appointment": "موعد", "confirmLater": "تأكيد لاحقًا", @@ -70,20 +70,20 @@ "payNow": "ادفع الآن", "viewQR": "عرض رمز الاستجابة السريعة", "instruction": "تعليمات", - "livecare": "الرعاية الحية", - "livecareAppo": "موعد الرعاية الحية", + "livecare": "لايف كير", + "livecareAppo": "موعد لايف كير", "agreeTo": "أوافق على", "termsConditoins": "الشروط والأحكام", "cancelAppoMsg": "هل أنت متأكد أنك تريد إلغاء هذا الموعد؟", "changePayment": "تغيير طريقة الدفع", - "upcomingNoAction": "لا حاجة لإجراء أي إجراء", + "upcomingNoAction": "لا يتطلب أي إجراء", "upcomingConfirm": "يرجى تأكيد الموعد لتجنب الإلغاء", "bookSuccessConfirmMore2412": "ستكون عملية الدفع عبر الإنترنت متاحة قبل 24 ساعة ��ن الموعد.", "upcomingPaymentPending": "سيتم تفعيل الدفع عبر الإنترنت قبل 24 ساعة من موعد الموعد", "upcomingPaymentNow": "ادفع عبر الإنترنت الآن لتجنب الانتظار الطويل", "upcomingQR": "استخدم رمز الاستجابة السريعة لتسجيل الوصول في المستشفى", "upcomingVirtual": "هذا موعد افتراضي، يرجى الالتزام بالتعليمات لتجربة سلسة.", - "upcomingLivecare": "هذا موعد رعاية حية", + "upcomingLivecare": "هذا موعد لايف كير", "upcomingDetails": "المزيد من التفاصيل", "reschedule": "إعادة جدولة", "raise": "رفع", @@ -92,7 +92,7 @@ "reminder": "تذكير", "location": "المواقع", "online": "عبر الإنترنت", - "payment": "الالكتروني", + "payment": "الدفع", "onlinePayment": "عبر الإنترنت", "onlinePaymentSubtitle": "الدفع", "cancelNocaps": "إلغاء", @@ -161,7 +161,7 @@ "passQRAppoAttend": "مرر رمز الاستجابة السريعة عبر أجهزة الحضور المتاحة في المستشفى.", "sitWaitingQR": "اجلس في غرف الانتظار حتى يتم استدعاؤك من قبل الممرضة.", "attendRegisterCode": "رمز تسجيل الحضور", - "scanQRHospital": "اقترب من لوحة التسجيل عبر الإنترنت في المستشفى وامسح عبر NFC أو رمز الاستجابة السريعة لتسجيل الوصول", + "scanQRHospital": "توجّه إلى لوحة تسجيل الوصول الإلكتروني في المستشفى، وقم بالمسح عبر تقنية NFC أو رمز الاستجابة السريعة (QR) لإتمام تسجيل الوصول.", "scanNFC": "امسح NFC لتسجيل الوصول", "sendEmail": "إرسال بريد إلكتروني", "success": "تم بنجاح", @@ -174,7 +174,7 @@ "arrived": "وصل", "payNowBookSuccess": "ادفع الآن عبر تطبيق الحبيب", "payNowBookSuccesstext1": "ادفع الآن باستخدام خدمة الدفع عبر الإنترنت من بوابات الدفع الآمنة", - "payNowBookSuccesstext2": "يمكنك أيضًا الدفع لاحقًا عبر الدفع عبر الإنترنت أو في المستشفى", + "payNowBookSuccesstext2": "يمكنك أيضًا الدفع لاحقًا عبر الدفع الإلكتروني أو في المستشفى.", "payLater": "ادفع لاحقًا", "askDocNotAllowed": "هذه الخدمة ستكون متاحة فقط لزيارة الطبيب قبل 15 يومًا", "moreVerify": "خيارات تحقق إضافية", @@ -246,13 +246,13 @@ "myMedicalFileSubTitle": "جميع سجلاتك الطبية", "viewMore": "عرض المزيد", "homeHealthCareService": "خدمة الرعاية الصحية المنزلية", - "onlinePharmacy": "صيدلية عبر الإنترنت", + "onlinePharmacy": "الصيدلية الإلكترونية", "emergencyService": "خدمة الطوارئ", "onlinePaymentService": "خدمة الدفع عبر الإنترنت", "offersAndPackages": "طلب تحويل عبر الإنترنت", "comprehensiveMedicalCheckup": "فحص طبي شامل", "hmgService": "خدمة HMG", - "viewAllHabibMedicalService": "عرض جميع خدمات حبيب الطبية", + "viewAllHabibMedicalService": "عرض جميع خدمات الحبيب الطبية", "viewAll": "عرض الكل", "view": "عرض", "contactUs": "اتصل بنا", @@ -263,7 +263,7 @@ "consultation": "استشارة", "logs": "السجلات", "textToSpeech": "كيف يمكنني مساعدتك؟", - "locationDialogMessage": "سيساعدك السماح لتطبيق HMG بالوصول إلى موقعك في عرض المستشفيات الأقرب إليك.", + "locationDialogMessage": "السماح لتطبيق HMG بالوصول إلى موقعك سيساعدك في عرض المستشفيات الأقرب إليك.", "userViewRequester": "يريد المستخدم عرض ملفك الطبي", "userView": "يمكن للمستخدم عرض ملفك الطبي", "parking": "موقف السيارات", @@ -288,7 +288,7 @@ "requestA": "طلب", "noBookedAppointments": "لا توجد مواعيد محجوزة", "noConfirmedAppointments": "لا توجد مواعيد مؤكدة", - "noArrivedAppointments": "لا توجد مواعيد وصلت", + "noArrivedAppointments": "لا توجد مواعيد تم تسجيل الوصول إليها", "myAppointmentsList": "المواعيد", "myAppointments": "مواعيدي", "radiology": "الأشعة", @@ -358,11 +358,11 @@ "userAgreement": "اتفاقية المستخدم", "updateSuccessfully": "تم التحديث بنجاح", "checkVaccineAvailability": "تحقق من توفر اللقاح", - "myVaccinesAvailability": "توفر لقاحاتي", + "myVaccinesAvailability": "توفر اللقاحات الخاصة بي", "paymentService": "خدمة الدفع", "paymentOnline": "الخدمة", "onlineCheckIn": "تسجيل الوصول عبر الإنترنت", - "myBalances": "أرصدةي", + "myBalances": "رصيدي", "myWallet": "محف��تي", "balanceAmount": "مبلغ المحفظة", "totalBalance": "إجمالي الرصيد", @@ -383,7 +383,7 @@ "otherAccount": "حساب آخر", "selectBeneficiary": "اختر المستفيد", "confirmThePayment": "تأكيد الدفع", - "depositorName": "اسم الوديع", + "depositorName": "اسم مُقدِّم الإيداع", "mobileNumber": "رقم الجوال", "phoneNumber": "رقم الهاتف", "country": "البلد", @@ -410,7 +410,7 @@ "diameter": "القطر", "remarks": "ملاحظات: ", "activeMedications": "الأدوية النشطة", - "expDate": "تاريخ انتهاء الصلاحية النشط:", + "expDate": "تاريخ انتهاء الصلاحية:", "route": "الطريق", "frequency": "التكرار", "dailyQuantity": "��لكمية اليومية:", @@ -427,7 +427,7 @@ "doctorResponses": "ردود الطبيب", "ne_w": "جديد", "all": "الكل", - "dailyWater": "فحص الماء اليومي", + "dailyWater": "متابعة الماء اليومية", "questionHere": "أدخل السؤال هنا...", "viewDoctorResponses": "عرض ردود الطبيب", "serviceInformationButton": "تسجيل الدخول / التسجيل", @@ -452,7 +452,7 @@ "brands": "العلامات التجارية", "productDetails": "تفاصيل المنتج", "medicationRefill": "إعادة تعبئة الدواء", - "pillReminder": "تذكير بالحبوب", + "pillReminder": "تذكير الأدوية", "shippingAddresses": "عناوين الشحن", "reachUs": "تواصل معنا", "ourLocations": "مواقعنا", @@ -472,7 +472,7 @@ "cancelled": "ملغى", "writeReview": "اكتب تقييمًا", "shareReview": "شارك التقييم", - "review": " تقييمات", + "review": " التقييمات", "viewMedicalFile": "عرض التفاصيل", "viewAllServices": "عرض جميع الخدمات", "medicalFile": "الملف الطبي", @@ -488,7 +488,7 @@ "services2": "الخدمات", "cantSeeProfile": "لرؤية ملفك الطبي، يرجى تسجيل الدخول أو التسجيل الآن", "loginRegisterNow": "تسجيل الدخول أو التسجيل الآن", - "hmgPharmacy": "صيدلية HMG", + "hmgPharmacy": "صيدلية مجموعة الحبيب الطبية", "ecommerceSolution": "حلول التجارة الإلكترونية", "comprehensive": "شامل", "onlineConsulting": "استشارات عبر الإنترنت", @@ -525,7 +525,7 @@ "payOnline": "الدفع عبر الإنترنت", "cancelOrder": "إلغاء الطلب", "confirmAddress": "تأكيد العنوان ", - "confirmLocation": "أكيد الموقع ", + "confirmLocation": "أكد الموقع ", "conditionsHMG": "الشروط والأحكام ", "conditions": "الشروط والأحكام لكوم", "confirmDeleteMsg": "هل أنت متأكد! تريد الحذف ", @@ -635,12 +635,12 @@ "infoInsuranceCards": "تتيح لك هذه الخدمة عرض جميع بطاقات التأمين التي تم تسجيلها خلال زياراتك لمجموعة الحبيب الطبية بالإضافة إلى:", "infoInsuranceCardsPoints": "", "infoAllergies": "تتيح لك هذه الخدمة عرض جميع أنواع الحساسية المسجلة خلال زياراتك لمجموعة الحبيب الطبية.", - "infoSickLeaves": "تتيح لك هذه الخدمة عرض جميع إجازات المرضى التي تم أخذها في مجموعة الحبيب الطبية بالإضافة إلى:", + "infoSickLeaves": "تتيح لك هذه الخدمة عرض جميع الاجازات المرضيه التي تم أخذها في مجموعة الحبيب الطبية بالإضافة إلى:", "infoSickLeavePoints": "", "infoApprovals": "تتيح لك هذه الخدمة عرض جميع طلبات الموافقة التي تم إرسالها إلى شركات التأمين بالإضافة إلى:", "infoApprovalPoints": "", "infoMonthReport": "عند تفعيل هذه الخدمة، سيقوم النظام بإرسال تقرير شهري تلقائيًا إلى البريد الإلكتروني المسجل يتضمن العلامات الحيوية والنتائج لآخر الزيارات التي تمت في مجموعة الحبيب الطبية.", - "languageSetting": "لغة الرسائل القصيرة، واتساب، ومكالمات التأكيد", + "languageSetting": "الرسائل القصيرة، واتساب، لغة مكالمات التأكيد", "alert": "تنبيهات", "emailAlert": "تنبيه عبر البريد الإلكتروني", "smsAlert": "تنبيه عبر الرسائل القصيرة", @@ -648,7 +648,7 @@ "emrgName": "اسم جهة الاتصال في حالات الطوارئ", "emrgNo": "رقم جهة الاتصال في حالات الطوارئ", "modes": "الأوضاع", - "vibration": "اهتزاز ردود الفعل اللمسية", + "vibration": "اهتزاز عند اللمس", "blindModes": "أوضاع للمكفوفين جزئيًا", "invertTheme": "عكس", "offTheme": "إيقاف", @@ -666,7 +666,7 @@ "findUs": "اعثر علينا", "liveChat": "دردشة مباشرة", "service": "خدمة", - "hmgServiceLabel": "خدمة HMG", + "hmgServiceLabel": "خدمة مجموعة الحبيب الطبية", "healthWeatherIndicators": "مؤشرات الطقس الصحية", "healthTipsBasedOnCurrentWeather": "نصائح صحية بناءً على الطقس الحالي", "moreDetails": "المزيد من التفاصيل", @@ -705,7 +705,7 @@ "compliment": "تقدير", "suggestion": "اقتراح", "yourFeedback": "تم إرسال ملاحظاتك", - "selectPart": "يرجى اختيار الجزء الذي تشتك�� منه", + "selectPart": "يرجى اختيار الجزء الذي تشتكي منه", "number": "رقم", "notClassified": "غير مصنف", "selectClinic": "اختر العيادة", @@ -714,13 +714,13 @@ "youCanFind": "يمكنك العثور على ", "itemInSearch": " عنصر في البحث", "bloodDonation": "التبرع بالدم", - "bloodDonationInfo": "من خلال هذه الخدمة، يمكنك تسجيل اسمك كمتبرع بالدم ��يث سيتواصل معك بنك الدم في مجموعة الحبيب الطبية في حالة الحاجة إلى فصيلة الدم.", + "bloodDonationInfo": "من خلال هذه الخدمة، يمكنك تسجيل اسمك كمتبرع بالدم حيث سيتواصل معك بنك الدم في مجموعة الحبيب الطبية في حالة الحاجة إلى فصيلة الدم.", "bloodInstruction": "أدخل المعلومات المطلوبة، من أجل التسجيل في خدمة التبرع بالدم", "viewTerms": "لعرض الشروط والأحكام", - "wantConnectHmgNetwork": "عزيزي العميل، لا يوجد وصول إلى الإنترنت، هل ترغب في الاتصال بشبكة HMG لاستخدام تطبيقنا، تأكد من أنك في نطاق شبكة HMG", - "failedToAccessHmgServices": "متصل بشبكة HMG،\n\nلكن فشل في الوصول إلى خدمات HMG", + "wantConnectHmgNetwork": "عزيزي العميل، لا يوجد وصول إلى الإنترنت، هل ترغب في الاتصال بشبكة مجموعة الحبيب الطبية لاستخدام تطبيقنا، تأكد من أنك في نطاق شبكة مجموعة الحبيب الطبية", + "failedToAccessHmgServices": "متصل بشبكة مجموعة الحبيب الطبية،\n\nلكن فشل في الوصول إلى خدمات مجموعة الحبيب الطبية", "offerAndPackages": "عروض وباقات", - "offerAndPackagesDetails": "تتيح لك هذه الخدمة عرض جميع عروض HMG:", + "offerAndPackagesDetails": "تتيح لك هذه الخدمة عرض جميع عروض مجموعة الحبيب الطبية:", "invoiceNo": "رقم الفاتورة", "invoiceDate": "تاريخ الفاتورة", "specialResult": "نتيجة خاصة", @@ -739,25 +739,25 @@ "excellent": "ممتاز", "average": "متوسط", "infoSigns": "تتيح لك هذه الخدمة عرض جميع العلامات الحيوية التي تم قياسها في مجموعة الحبيب الطبية، مثل (الطول، الوزن، مؤشر كتلة الجسم، معدل ضربات القلب، إلخ.) بالإضافة إلى عرض بعض الرسوم البيانية الإحصائية.", - "infoAdvancePayment": "تم تصميم هذه الخدمة بحيث يمكنك إيداع مبلغ مقدم إما في حسابك أو في حساب شخص آخر في مجموعة الحبيب الطبية.", + "infoAdvancePayment": "تم تصميم هذه الخدمة بحيث يمكنك إيداع مبلغ مقدم إما في حسابك أو في حساب شخص آخر، في مجموعة الحبيب الطبية.", "infoMyBalance": "تتيح لك هذه الخدمة التحقق من رصيدك في جميع الفروع", "erContant": "تظهر هذه الخدمة أقرب فرع من بين جميع فروع مجموعة الحبيب الطبية بناءً على موقعك الحالي.", "infoAmbulance": "من خلال هذه الخدمة، يمكنك طلب الإخلاء بواسطة سيارة إسعاف، سواء من المنزل أو إلى المنزل، بالإضافة إلى مجموعة من الخدمات الأخرى", "infoMyAppointments": "تتيح لك هذه الخدمة رؤية جميع المواعيد التي زرتها في مجموعة الحبيب الطبية، ومن خلال هذه الخدمة:", - "infoTodo": "تم تصميم هذه الخدمة لتمكينك من الحصول على رابط سريع لقائمة المهام التي تحتاج إلى القيام بها", + "infoTodo": "تم تصميم هذه الخدمة لتمكينك من الحصول على رابط سريع لقائمة المهام التي تحتاج القيام بها", "familyInfo": "من خلال هذه الخدمة، ستتمكن من ربط ملفات عائلتك الطبية بملفك الطبي حتى تتمكن من إدارة سجلاتهم عن طريق تسجيل الدخول إلى ملفك الطبي.", "rrtdDetails": "تقدم فريق الاستجابة السريعة خدمة طبية شاملة لجميع أنواع الحالات العاجلة والمستقرة من جميع الأعمار، بما في ذلك البالغين والمرضى الأطفال، وتغطي الخدمة فريق طبي مدرب تدريبًا عاليًا ومجهز تجهيزًا كاملاً قادرًا على تقديم أفضل رعاية طبية في منزل المريض.", "homeHealthCareText": "تقدم هذه الخدمة مجموعة من خدمات الرعاية الصحية المنزلية، والمتابعة المستمرة والشاملة في أماكن إقامتهم لأولئك الذين لا يمكنهم الوصول إلى المرافق الصحية، مثل (تحليلات المختبر - الأشعة - التطعيمات - العلاج الطبيعي)، إلخ.", - "onlineCheckInAgreement": "تسجيل الوصول عبر الإنترنت مخصص للحال��ت التي لا تهدد الحياة. اتصل بالهلال الأحمر (997) أو اذهب إلى أقرب قسم طوارئ إذا كان هناك: \n\nعلامات السكتة الدماغية أو النوبة القلبية \nhالة من النوبات أو الإغماء \nهناك إصابة تهدد الطرف أو الحياة \nصورة لإصابات خطيرة", + "onlineCheckInAgreement": "تسجيل الوصول عبر الإنترنت مخصص للحالات التي لا تهدد الحياة. اتصل بالهلال الأحمر (997) أو اذهب إلى أقرب قسم طوارئ إذا كان هناك: \n\nعلامات السكتة الدماغية أو النوبة القلبية \nhالة من النوبات أو الإغماء \nهناك إصابة تهدد الطرف أو الحياة \nصورة لإصابات خطيرة", "infoEreferral": "تتيح لك هذه الخدمة تقديم طلب إحالة من أي مقدم رعاية صحية سواء داخل أو خارج المملكة العربية السعودية إلى أي من مستشفيات HMG، عن طريق ملء بعض بيانات المريض وإرفاق التقارير الطبية، علاوة على ذلك يمكنك تتبع حالة الطلب (قيد المعالجة، مقبول أو مرفوض)", "erConsultation": "تتيح لك هذه الخدمة إجراء استشارة افتراضية عبر الإنترنت عبر مكالمة فيديو مباشرة مع الطبيب من أي مكان وفي أي وقت.", "myInvoice": "القائمة", "invoiceList": "فواتيري", "thisItemIsNotAvailable": "هذا العنصر غير متوفر", "beforeAfterImages": "صور قبل وبعد", - "clinicAcceptLivecare": "لا حاجة للانتظار أو الزيارة يمكنك الآن الحصول على استشارة طبية عبر مكالمة فيديو (خدمة الرعاية الحية) في اسم العيادة وسيتصل بك الطبيب على الور", - "livecareModalTop": "تقبل هذه العيادة خدمات الرعاية الحية", - "livecarePoint2": "��يتصل بك طبيب متخصص", + "clinicAcceptLivecare": "لا حاجة للانتظار أو الزيارة يمكنك الآن الحصول على استشارة طبية عبر مكالمة فيديو (لايف كير) في اسم العيادة وسيتصل بك الطبيب على الفور", + "livecareModalTop": "تقبل هذه العيادة خدمات ال لايف كير", + "livecarePoint2": "سوف يتصل بك طبيب متخصص", "livecarePoint3": "سيكون لدى الطبيب القدرة على رؤية تاريخ ملفك الطبي الكامل", "livecarePoint4": "تتوفر خدمة توصيل الأدوية المجانية", "livecarePoint5": "لا حاجة للزيارة، الخدمة في مكانك", @@ -787,7 +787,7 @@ "enterEmailDesc": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي", "enterPhoneDesc": "أدخل رقم هاتفك لتلقي رمز التحقق ", "pleaseChooseOption": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP", - "prepareToElevate": "هل أنت مستعد لتحسين صحتك ورفاهتك؟", + "prepareToElevate": "هل أنت مستعد لتحسين صحتك ورفاهيتك؟", "iAcceptTermsConditions": "أوافق على الشروط والأحكام", "alreadyHaveAccount": "هل لديك حساب بالفعل؟", "loginNow": "تسجيل الدخول الآن", @@ -804,7 +804,7 @@ "guest": "زائر", "switchAccount": "تبديل الحساب", "lastLoginBy": "آخر تسجيل دخول بواسطة", - "allSet": "جاهز! الآن يمكنك تسجيل الدخول باستخدام Face ID / Biometric أو البصمة", + "allSet": "جاهز! الآن يمكنك تسجيل الدخول باستخدام Face ID أو البصمة", "enableQuickLogin": "تمكين تسجيل الدخول السريع", "enableMsg": "تمكين تسجيل الدخول السريع سيسمح بالتحقق من خلال Face ID / Biometric الخاص بجهازك الحالي", "notNow": "ليس الآن", @@ -849,12 +849,12 @@ "searchHospital": "بحث في المستشفى", "skip": "تخطي", "getStarted": "ابدأ الآن", - "onboardingHeading1": "حجز المواعيد لم يكن أسهل من قبل", + "onboardingHeading1": "حجز المواعيد لم يكن أسهل من الآن.", "onboardingBody1": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره.", "onboardingHeading2": "الوصول إلى السجل الطبي بين يديك", "onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها.", - "hmgHospitals": "مستشفيات HMG", - "hmcMedicalClinic": "مراكز HMC الطبية", + "hmgHospitals": "مستشفيات مجموعة الحبيب الطبية", + "hmcMedicalClinic": "مراكز مجموعة الحبيب الطبية", "applyFilter": "تطبيق الفلتر", "facilityAndLocation": "المرفق والموقع", "regionAndLocation": "المنطقة والمواقع", @@ -874,7 +874,6 @@ "laserClinic": "عيادة الليزر", "continueString": "يكمل", "covid_info": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة، طوال أيام الأسبوع، وبسرعة ودقة عالية. يمكن للراغبين في الاستفادة من هذه الخدمة زيارة أحد فروع مستشفيات د. سليمان الحبيب وإجراء فحص كورونا خلال بضع دقائق والحصول على النتائج خلال عدة ساعات خدمة فحص فيروس كورونا Covid 19 بتقنية PCR للكشف عن الفيروس وفقاً لأعلى المعايير العالمية وبأحدث أجهزة RT-PCR عالية الدقة (GeneXpert الأمريكي وغيره)، وهي طرق معتمدة من قبل هيئة الغذاء والدواء وكذلك من قبل المركز السعودي للوقاية من الأمراض المُعدية", - "appointmentDetails": "تفاصيل الموعد", "checkingDoctorAvailability": "جاري التحقق من توفر الطبيب...", "cancellingAppointmentPleaseWait": "جاري إلغاء الموعد، يرجى الانتظار...", @@ -924,7 +923,7 @@ "offersFreeMedicineDelivery": "يوفر توصيل مجاني للأدوية لموعد لايف كير", "dentalChiefComplaints": "الشكاوى الرئيسة للأسنان", "viewAvailableAppointments": "عرض المواعيد المتاحة", - "doctorProfile": "الملف للطبيب", + "doctorProfile": " ملف الطبيب", "waitingAppointment": "موعد الانتظار", "hospitalInformation": "معلومات المستشفى", "fetchingAppointmentShare": "جاري جلب تفاصيل الموعد...", @@ -945,6 +944,7 @@ "offline": "غير متصل", "videoCall": "مكالمة فيديو", "liveVideoCallWithHMGDoctors": "مكالمة فيديو مباشرة مع أطباء مجموعة الحبيب الطبية", + "liveAudioCallWithHMGDoctors": "مكالمة صوتية مباشرة مع أطباء مجموعة الحبيب الطبية", "audioCall": "مكالمة صوتية", "phoneCall": "مكالمة هاتفية", "livePhoneCallWithHMGDoctors": "مكالمة هاتفية مباشرة مع أطباء مجموعة الحبيب الطبية", @@ -959,10 +959,10 @@ "visaOrMastercard": "فيزا أو ماستركارد", "tamara": "تمارا", "fetchingApplePayDetails": "جاري جلب تفاصيل Apple Pay، يرجى الانتظار...", - "liveCarePendingRequest": "لايف كير حية معلق", + "liveCarePendingRequest": "طلب لايف كير قيد الانتظار", "callLiveCareSupport": "اتصل بدعم لايف كير", "whatIsWaitingAppointment": "ما هو موعد الانتظار؟", - "waitingAppointmentsFeature": "تتيح لك ميزة مواعيد الانتظار حجز موعد أثناء تواجدك داخل مبنى المستشفى، وفي حال عدم توفر فتحة متاحة في جدول الطبيب.", + "waitingAppointmentsFeature": "تتيح لك ميزة مواعيد الانتظار حجز موعد أثناء تواجدك داخل مبنى المستشفى، وفي حال عدم توفر مواعيد متاحة في جدول الطبيب.", "appointmentWithDoctorConfirmed": "الموعد مع الطبيب مؤكد، ولكن وقت الدخول غير محدد.", "paymentWithinTenMinutes": "ملاحظة: يجب عليك الدفع خلال 10 دقائق من الحجز، وإلا سيتم إلغاء موعدك تلقائياً", "liveLocation": "الموقع المباشر", @@ -1232,7 +1232,7 @@ "invalidWeight": "الوزن غير صالح", "timeToDrinkWater": "حان وقت شرب الماء! 💧", "stayHydratedDrinkWater": "ابق رطبًا! اشرب {amount} مل من الماء.", - "visitPharmacyOnline": "زيارة الصيدلة على الانترنت", + "visitPharmacyOnline": "زيارة الصيدلية على الانترنت", "howAreYouFeelingToday": "كيف حالك اليوم؟", "checkYourSymptomsWithScale": "تحقق من أعراضك باستخدام ذا المقياس", "checkYourSymptoms": "تحقق من أعراضك", @@ -1240,7 +1240,7 @@ "youHaveEROnlineCheckInRequest": "لديك طلب تسجيل وصول عبر الإنترنت للطوارئ", "quickLinks": "روابط سريعة", "viewMedicalFileLandingPage": "عرض الملف الطبي", - "immediateLiveCareRequest": "طلب LiveCare الفوري", + "immediateLiveCareRequest": "طلب لايف كير فوري", "yourTurnIsAfterPatients": "دورك بعد {count} مريض.", "dontHaveHHCOrders": "ليس لديك أي أوامر رعاية صحية منزلية حتى الآن.", "hhcOrders": "أوامر الرعاية الصحية المنزلية", @@ -1256,7 +1256,7 @@ "insuranceActive": "التأمين نشط", "patientCardID": "رقم بطاقة المريض: {id}", "noInsuranceApprovals": "لم تحصل على أي موافقات تأمينية حتى الآن.", - "noInsuranceWithHMG": "ليس لديك تأمين مسجل لدى مجموعة حبيب الطبية.", + "noInsuranceWithHMG": "ليس لديك تأمين مسجل لدى مجموعة الحبيب الطبية.", "referenceRange": "النطاق المرجعي", "downloadReport": "تنزيل التقرير", "generatingReport": "جارٍ إنشاء التقرير، يرجى الانتظار...", @@ -1301,12 +1301,12 @@ "updatingMonthlyReportStatus": "جاري تحديث حالة التقرير الشهري...", "monthlyReportStatusUpdatedSuccessfully": "تم تحديث حالة التقرير الشهري بنجاح", "whoCanViewMyMedicalFile": "من يمكنه عرض ملفي الطبي؟", - "acceptedYourRequestToBeYourFamilyMember": "{status} طلبك لتكون فردًا من عائلتك", + "acceptedYourRequestToBeYourFamilyMember": "{status} طلب الانضمام الى أفراد عائلتك", "canViewYourFile": "يمكنه عرض ملفك", "hasARequestPendingToBeYourFamilyMember": "لديه طلب {status} ليكون فردًا من عائلتك", - "wantsToAddYouAsTheirFamilyMember": "يريد إضافتك كفرد من عائلته", - "rejectedYourRequestToBeYourFamilyMember": "{status} طلبك لتكون فردًا من عائلتك", - "rejectedYourFamilyMemberRequest": "{status} طلب فرد عائلتك", + "wantsToAddYouAsTheirFamilyMember": "يرغب في إضافتك كفرد من أفراد العائلة", + "rejectedYourRequestToBeYourFamilyMember": "{status} طلب الانضمام إلى عائلتك", + "rejectedYourFamilyMemberRequest": "{status} طلب أحد أفراد عائلتك", "notAvailable": "غير متاح", "selectAProfile": "الرجاء تحديد ملف تعريف", "switchFamilyFile": "قم بالتبديل من قائمة الملفات الطبية أدناه", @@ -1385,7 +1385,7 @@ "seekMedicalAdviceDescription": "ليست حالة طوارئ ولكن من الأفضل مراقبة الأعراض.", "emergencyDescription": "تحتاج إلى استشارة الطبيب في أقرب وقت ممكن قبل فوات الأوان.", "colorScience": "دلالات الألوان", - "noNeedToVisitDoctor": "لا حاجة لزيرة الطبيب", + "noNeedToVisitDoctor": "لا حاجة لزيارة الطبيب", "commonSymptom": "الأعراض الشائعة", "bookAppointment": "احجز موعد", "notApplicable": "لا ينطبق", @@ -1422,7 +1422,7 @@ "approved": "موافق عليه", "approvalRejectedPleaseVisitReceptionist": "تم رفض الموافقة - يرجى زيارة موظف الاستقبال", "sentForApproval": "تم إرساله للموافقة", - "ancillaryOrderDetails": "تفاصيل الطلب المساعد", + "ancillaryOrderDetails": "تفاصيل الطلبات المساندة", "noProceduresAvailableForSelectedOrder": "لا توجد إجراءات متاحة للطلب المحدد.", "procedures": "الإجراءات", "totalAmount": "المبلغ الإجمالي", @@ -1491,7 +1491,6 @@ "yourName": "اسمك", "ageYears": "العمر (11-120) سنة", "numberOfRemindersInADay": "عدد التذكيرات في اليوم", - "medications": "الأدوية", "someRemarksAboutPrescription": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية", "notifyMeBeforeConsumptionTime": "أبلغني قبل وقت الاستهلاك", @@ -1528,7 +1527,7 @@ "prediction": "تنبؤ", "prevention": "وقاية", "disclaimer": "تنصل", - "thisAboveInfo": "المعلومات المذكورة أعلاه تم إنشاؤها بواسطة AI", + "thisAboveInfo": "المعلومات المذكورة أعلاه مُولّدة بواسطة AI بناءً على نتائج تحاليلك المخبرية، وهي لأغراض إعلامية فقط. لا ينبغي اعتبارها تشخيصًا طبيًا أو خطة علاجية. استشر طبيبك دائمًا للحصول على نصيحة طبية مُخصصة قبل اتخاذ أي قرارات تتعلق بصحتك.", "aiDisclaimer": "سيتم مشاركة بيانات نتائج تحاليلك المخبرية بشكل آمن مع خدمة الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في تقديم رؤى صحية مُخصصة. هل ترغب في المتابعة؟", "consent": "موافقة", "bmiNormalDescription": "مؤشر كتلة جسمك ضمن المعدل الصحي. استمر في اتباع نظام غذائي متوازن، وممارسة النشاط البدني بانتظام، وإجراء الفحوصات الدورية للحفاظ على صحة جيدة. راقب أي تغييرات ملحوظة مع مرور الوقت.", @@ -1544,19 +1543,19 @@ "bmrNormalDescription": "معدل الأيض الأساسي لديك ضمن النطاق المتوقع لحالتك. معدل الأيض الأساسي هو الطاقة التي يحتاجها جسمك في حالة الراحة للحفاظ على وظائفه الحيوية (التنفس، الدورة الدموية، درجة الحرارة). استخدم هذه القيمة كأساس لتقدير إجمالي احتياجاتك اليومية من الطاقة من خلال تطبيق مُعامل النشاط. حافظ على نظام غذائي متوازن وممارسة النشاط البدني بانتظام لدعم صحة التمثيل الغذائي.", "bmrLowDescription": "معدل الأيض الأساسي لديك أقل من المعدل الطبيعي لحالتك. تشمل الأسباب المحتملة انخفاض كتلة العضلات، أو تراجع التمثيل الغذائي المرتبط بالتقدم في السن، أو التكيف الأيضي الناتج عن تقييد السعرات الحرارية لفترة طويلة. يُنصح بالتركيز على تمارين المقاومة لبناء العضلات والحفاظ عليها، والتأكد من تناول كميات كافية من البروتين والمغذيات الدقيقة، واستشارة أخصائي رعاية صحية إذا كان هذا الأمر غير متوقع.", "bmrHighDescription": "معدل الأيض الأساسي لديك أعلى من المتوسط \u200B\u200Bبالنسبة لحالتك. قد يعكس هذا زيادة في كتلة العضلات، أو صغر السن، أو ارتفاع معدل الأيض لديك بشكل طبيعي، مما يعني أنك تحرق طاقة أكبر أثناء الراحة. استخدم هذه المعلومات لتحديد احتياجاتك من السعرات الحرارية: احتياجات أعلى للحفاظ على الوزن أو بناء العضلات، ونقص معتدل في السعرات الحرارية لإنقاص الوزن. استشر طبيبك إذا لاحظت أي تغيرات سريعة غير مبررة.", - "ibwAtTargetDescription": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.", - "ibwBelowTargetDescription": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.", - "ibwAboveTargetDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.", - "ibwCloseToRangeDescription": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.", - "ibwUnderweightDescription": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.", - "ibwUnderweightGenericDescription": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.", - "ibwOverweightDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.", - "ibwOverweightGenericDescription": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.", - "dietVeryLowCarbsDescription": "Very low‑carb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for long‑term use.", - "dietLowCarbsDescription": "Low‑carb, higher‑protein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.", - "dietModerateCarbsDescription": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.", - "dietUSDAGuidelinesDescription": "USDA‑based balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidence‑based framework for general health, nutrient adequacy, and chronic disease prevention.", - "dietZoneDietDescription": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.", + "ibwAtTargetDescription": "وزنك في النطاق المثالي. حافظ على عاداتك الحالية — نظام غذائي متوازن ونشاط بدني منتظم — للاستمرار على هذا المستوى.", + "ibwBelowTargetDescription": "أنتِ أقل من الوزن المثالي بمقدار {kg} كجم. يُنصح بزيادة الوزن تدريجيًا من خلال فائضٍ بسيط في السعرات الحرارية، وتناول أطعمة غنية بالعناصر الغذائية، مع ممارسة تمارين المقاومة.", + "ibwAboveTargetDescription": "أنتِ أعلى من الوزن المثالي بمقدار {kg} كجم. يُنصح باتباع خفضٍ تدريجي ومستدام للوزن من خلال عجزٍ معتدل في السعرات الحرارية، وزيادة مستوى النشاط البدني، واتباع تغذية متوازنة.", + "ibwCloseToRangeDescription": "وزنك قريب من النطاق المثالي. حافظ على نظام غذائي متوازن ونشاط بدني منتظم، مع اتباع إرشادات شخصية من مختص صحي عند الحاجة.", + "ibwUnderweightDescription": "أنت أقل من الوزن المثالي بمقدار {kg} كجم. ركّز على زيادة السعرات الحرارية من خلال أطعمة غنية بالعناصر الغذائية، وأعط الأولوية للبروتين وتمارين المقاومة لبناء كتلة صحية، مع اتباع إرشادات شخصية من مختص صحي.", + "ibwUnderweightGenericDescription": "يبدو أنكِ أقل من الوزن المثالي. يُنصح بزيادة السعرات الحرارية من خلال أطعمة غنية بالعناصر الغذائية وممارسة تمارين المقاومة؛ مع الحصول على استشارة مختص صحي عند الحاجة.", + "ibwOverweightDescription": "أنت أعلى من الوزن المثالي بمقدار {kg} كجم. يُنصح باتباع استراتيجية تدريجية ومستدامة لفقدان الوزن — من خلال عجزٍ معتدل في السعرات الحرارية، وممارسة نشاط بدني منتظم، وتغذية متوازنة. يُفضّل استشارة مختص صحي قبل إجراء تغييرات كبيرة.", + "ibwOverweightGenericDescription": "يبدو أنك أعلى من الوزن المثالي. يُنصح باتباع عجزٍ تدريجي ومستدام في السعرات الحرارية مع ممارسة النشاط البدني واتباع تغذية متوازنة؛ مع الحصول على استشارة مختص صحي عند الحاجة.", + "dietVeryLowCarbsDescription": "نهج منخفض الكربوهيدرات جدًا (الكيتوني): تقليل الكربوهيدرات إلى الحد الأدنى مع زيادة الدهون وبروتين معتدل. قد يساعد على فقدان الوزن بسرعة وتحسين التحكم في سكر الدم لدى بعض الأشخاص، لكنه قد يكون صعب الاستمرار عليه وقد يسبب نقصًا في بعض العناصر الغذائية. يجب مراقبة الترطيب ، والحصول على استشارة مختص صحي عند استخدامه لفترة طويلة.", + "dietLowCarbsDescription": "خطة منخفضة الكربوهيدرات وعالية البروتين: تقليل الكربوهيدرات مع زيادة البروتين لدعم الشعور بالشبع والحفاظ على الكتلة العضلية. مفيدة لإدارة الوزن وضبط سكر الدم عند موازنتها مع الخضروات والدهون الصحية. احرص على الحصول على كمية كافية من الألياف والعناصر الدقيقة (الفيتامينات والمعادن).", + "dietModerateCarbsDescription": "تناول معتدل للكربوهيدرات مع توازن في البروتين والدهون: يوفر طاقة مستقرة للأنشطة اليومية والتمارين مع قدر من المرونة. مناسب لكثير من الأشخاص الذين يسعون لإدارة وزن مستدامة وتحسين الأداء.", + "dietUSDAGuidelinesDescription": "نمط متوازن مستند إلى (USDA): يركز على الفواكه والخضروات والحبوب الكاملة والبروتينات قليلة الدهن، مع الحد من السكريات المضافة والدهون المشبعة. يُعد إطارًا قائمًا على الأدلة لدعم الصحة العامة، وكفاية العناصر الغذائية، والوقاية من الأمراض المزمنة.", + "dietZoneDietDescription": "حمية الزون (~40٪ كربوهيدرات / 30٪ بروتين / 30٪ دهون): تركز على التوازن الهرموني وضبط الحصص الغذائية. قد تُحسّن تركيب الجسم ومستوى الطاقة لدى بعض الأشخاص، لكنها تتطلب تخطيطًا جيدًا؛ ويُفضّل تخصيصها بالتعاون مع مختص تغذية.", "contextDependent": "يعتمد السياق", "calculatedValue": "القيمة المحسوبة", "calculationFormula": "صيغة الحساب", @@ -1583,4 +1582,18 @@ "whoophealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Whoop Health على هاتفك", "whoopwatchshouldbeconnected": "يجب توصيل ساعة Whoop", "updatetheinformation": "سيتيح ذلك جمع أحدث المعلومات من ساعة آبل الخاصة بك" + "noThanksIKnowTheClinic": "لا، شكراً. أنا أعرف العيادة.", + "unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة", + "loadingAIAnalysis": "جارٍ تحليل نتائج المختبر، يرجى التحلي بالصبر والسماح للذكاء الاصطناعي بالقيام بالمهمة، قد يستغرق هذا بعض الوقت.", + "symptoms": "أعراض", + "insuranceInActive": "التأمين غير نشط", + "insuranceInActiveContactSupport": "لديك تأمين ساري المفعول، ولكنه غير مُفعّل حاليًا في مجموعة حبيب الطبية. يُرجى التواصل مع خدمة عملاء مجموعة حبيب الطبية.", + "updateAppNow": "تحديث التطبيق الآن", + "Dr": "الدكتور.", + "reschedulingAppo": "إعادة جدولة الموعد، يرجى الانتظار...", + "invalidEligibility": "لا يمكنك إجراء الدفع عبر الإنترنت لأنك غير مؤهل لاستخدام الخدمة المقدمة.", + "invalidInsurance": "لا يمكنك إجراء الدفع عبر الإنترنت لأنه ليس لديك تأمين صالح.", + "continueCash": "متابعة الدفع نقدًا", + "timeFor": "الوقت", + "hmgPolicies": "سياسات مجموعة الحبيب الطبية" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 0652be09..212da0ea 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -92,7 +92,7 @@ "reminder": "Reminder", "location": "Locations", "online": "Online", - "payment": "الالكتروني", + "payment": "Payment", "onlinePayment": "Online", "onlinePaymentSubtitle": "Payment", "cancelNocaps": "Cancel", @@ -272,9 +272,9 @@ "appointments": "Appointments", "all2": "All", "checkinOption": "Check-In", - "readBarcode": "قراءة الكود", - "showMyPark": "عرض الموقف", - "clearMyData": "امسح البيانات", + "readBarcode": "Read Barcode", + "showMyPark": "Show My Park", + "clearMyData": "Clear My Data", "floor": "Floor:", "gate": "Gate:", "building": "Building:", @@ -357,7 +357,7 @@ "userAgreement": "User Agreement", "updateSuccessfully": "Update Successfully", "checkVaccineAvailability": "CHECK VACCINE AVAILABILITY", - "myVaccinesAvailability": "MyVaccinesAvailability", + "myVaccinesAvailability": "My Vaccines Availability", "paymentService": "Payment Service", "paymentOnline": "Service", "onlineCheckIn": "Online Check-In", @@ -393,7 +393,7 @@ "theVerificationCodeExpiresIn": "The Verification Code Expires in", "pleaseEnterTheVerificationCode": "Please enter the verification code send to", "eyeMeasurements": "Eye Measurements", - "measurements": "قياسات", + "measurements": "Measurements", "classes": "Glasses", "contactLens": "Contact Lens", "rightEye": "Right Eye", @@ -566,8 +566,8 @@ "transferred": "Transferred", "riyal": "RIYAL", "membersince": "MEMBER SINCE", - "identification": "رقم الهوية", - "lakumMobile": "رقم الجوال", + "identification": "Identification Number", + "lakumMobile": "Mobile Number", "waitinggained": "Waiting gained", "expired": "Expired", "willBeExpired": "Will Be Expired", @@ -616,10 +616,10 @@ "bloodType": "Blood Type", "maritalStatus": "Marital status", "general": "General", - "profile": "ملفي", - "notifications": "إشعارات", + "profile": "My Profile", + "notifications": "Notifications", "notificationDetails": "Notification Details", - "notificationDetailsa": "تفاصيل الاشعار", + "notificationDetailsa": "Notification Details", "infoMyDoctorPoints": "", "infoMyDoctor": "This service allows you to see all the doctors you have visited in Al Habib Medical Group, and through this service:", "infoPrescriptions": "This service allows you to view all the medical prescriptions issued by Al Habib Medical Group, and through this service, you can:", @@ -937,6 +937,7 @@ "offline": "Offline", "videoCall": "Video Call", "liveVideoCallWithHMGDoctors": "Live Video Call with HMG Doctors", + "liveAudioCallWithHMGDoctors": "Live Audio Call with HMG Doctors", "audioCall": "Audio Call", "phoneCall": "Phone Call", "livePhoneCallWithHMGDoctors": "Live Phone Call with HMG Doctors", @@ -1531,8 +1532,8 @@ "prediction": "Prediction", "prevention": "Prevention", "disclaimer": "Disclaimer", - "thisAboveInfo": "The above information is generated by", - "aiDisclaimer": "Your lab result data will be securely shared with our AI service for analysis. This helps provide personalized health insights. Do you want to proceed?", + "thisAboveInfo": "The above information is generated by AI based on your lab results and is intended for informational purposes only. It should not be considered a medical diagnosis or treatment plan. Always consult with your healthcare provider for personalized medical advice and before making any health-related decisions.", + "aiDisclaimer": "Your lab result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?", "consent": "Consent", "bmiNormalDescription": "Your BMI is within the healthy range. Continue a balanced diet, regular physical activity, and routine checkups to maintain good health. Monitor any significant changes over time.", "bmiUnderweightDescription": "BMI suggests you are underweight. Consider increasing calorie intake with nutrient-dense foods, include resistance training to build muscle, and consult a healthcare professional to check for underlying causes.", @@ -1578,4 +1579,16 @@ "whoopwatchshouldbeconnected": "Whoop Watch should be connected", "updatetheinformation": "This will allow to gather the most up to date information from your apple watch" + "loadingAIAnalysis": "Analysing your lab results, Please be patient and let the AI do the magic, This might take some time.", + "symptoms": "Symptoms", + "insuranceInActive": "Insurance Inactive", + "insuranceInActiveContactSupport": "You have a valid insurance but it is currently inactive in HMG. Please contact HMG customer support to activate it.", + "updateAppNow": "Update App Now", + "Dr": "Dr.", + "reschedulingAppo": "Rescheduling Appointment, Please wait...", + "invalidEligibility": "You cannot make online payment because you are not eligible to use the provided service.", + "invalidInsurance": "You cannot make online payment because you do not have a valid insurance.", + "continueCash": "Continue as cash", + "timeFor": "Time For", + "hmgPolicies": "HMG Policies" } diff --git a/assets/sounds/ring_30Sec.caf b/assets/sounds/ring_30Sec.caf new file mode 100644 index 00000000..b5bb4b88 Binary files /dev/null and b/assets/sounds/ring_30Sec.caf differ diff --git a/assets/sounds/ring_30Sec.mp3 b/assets/sounds/ring_30Sec.mp3 new file mode 100644 index 00000000..f647cca8 Binary files /dev/null and b/assets/sounds/ring_30Sec.mp3 differ diff --git a/assets/sounds/ring_60Sec.mp3 b/assets/sounds/ring_60Sec.mp3 new file mode 100644 index 00000000..ac32394e Binary files /dev/null and b/assets/sounds/ring_60Sec.mp3 differ diff --git a/convert_json.dart b/convert_json.dart deleted file mode 100644 index af5c5945..00000000 --- a/convert_json.dart +++ /dev/null @@ -1,73 +0,0 @@ -// import 'dart:convert'; -// import 'dart:io'; -// -// void main() async { -// final file = File('assets/json/body_symptoms_data.json'); -// final content = await file.readAsString(); -// -// print('File size: ${content.length} characters'); -// -// // Split into two parts -// final parts = content.split('export const SymptomsData = ['); -// if (parts.length != 2) { -// print('ERROR: Could not split file properly'); -// exit(1); -// } -// -// print('Split into ${parts.length} parts'); -// -// // Process BodySymptomsData -// var bodyPart = parts[0] -// .replaceAll('export const BodySymptomsData = ', '') -// .trim() -// .replaceAll(RegExp(r';$'), ''); -// -// print('Parsing body symptoms...'); -// Map bodySymptomsData; -// try { -// bodySymptomsData = json.decode(bodyPart); -// print('✅ Body symptoms parsed: ${bodySymptomsData.length} body parts'); -// } catch (e) { -// print('❌ Error parsing body symptoms: $e'); -// exit(1); -// } -// -// // Process SymptomsData -// print('Processing symptoms data...'); -// var symptomsPart = parts[1] -// .trim() -// .replaceAll(RegExp(r'\];$'), '') -// .replaceAllMapped(RegExp(r'\n(\s*)id:'), (m) => '\n${m.group(1)}"id":') -// .replaceAllMapped(RegExp(r'\n(\s*)type:'), (m) => '\n${m.group(1)}"type":') -// .replaceAllMapped(RegExp(r'\n(\s*)name:'), (m) => '\n${m.group(1)}"name":') -// .replaceAllMapped(RegExp(r'\n(\s*)common_name:'), (m) => '\n${m.group(1)}"common_name":'); -// -// print('Parsing symptoms...'); -// List symptomsData; -// try { -// symptomsData = json.decode('[$symptomsPart]'); -// print('✅ Symptoms parsed: ${symptomsData.length} symptoms'); -// } catch (e) { -// print('❌ Error parsing symptoms: $e'); -// print('First 1000 chars:'); -// print('[$symptomsPart]'.substring(0, 1000)); -// exit(1); -// } -// -// // Create final JSON -// print('Creating final JSON structure...'); -// final jsonStructure = { -// 'bodySymptoms': bodySymptomsData, -// 'symptoms': symptomsData, -// }; -// -// // Write to file -// print('Writing to file...'); -// final encoder = JsonEncoder.withIndent(' '); -// await file.writeAsString(encoder.convert(jsonStructure)); -// -// print('\n✅ SUCCESS! File converted to proper JSON'); -// print('✅ Body parts: ${bodySymptomsData.length}'); -// print('✅ Symptoms: ${symptomsData.length}'); -// } -// diff --git a/firebase.json b/firebase.json new file mode 100644 index 00000000..7d1b1fd1 --- /dev/null +++ b/firebase.json @@ -0,0 +1 @@ +{"flutter":{"platforms":{"android":{"default":{"projectId":"api-project-815750722565","appId":"1:815750722565:android:62281cd3e5df4063","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"api-project-815750722565","appId":"1:815750722565:ios:34ec03c09e02e21f3c186c","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"api-project-815750722565","configurations":{"android":"1:815750722565:android:62281cd3e5df4063","ios":"1:815750722565:ios:34ec03c09e02e21f3c186c"}}}}}} \ No newline at end of file diff --git a/google-services_NewApp.json b/google-services_NewApp.json new file mode 100644 index 00000000..49bf1ace --- /dev/null +++ b/google-services_NewApp.json @@ -0,0 +1,83 @@ +{ + "project_info": { + "project_number": "815750722565", + "firebase_url": "https://api-project-815750722565.firebaseio.com", + "project_id": "api-project-815750722565", + "storage_bucket": "api-project-815750722565.firebasestorage.app" + }, + "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", + "android_client_info": { + "package_name": "com.ejada.hmg" + } + }, + "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" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 2a0fec9a..e031a976 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -11,7 +11,21 @@ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 478CFA942E638C8E0064F3D7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */; }; + 61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */; }; + 61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */; }; + 61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B452EC5FA3700D46FA0 /* PenguinView.swift */; }; + 61243B542EC5FA3700D46FA0 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */; }; + 61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */; }; + 61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 765A5A8C2F35CD8B0003FF7D /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A802F35CD730003FF7D /* Penguin.xcframework */; }; + 765A5A8D2F35CD8B0003FF7D /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A802F35CD730003FF7D /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 765A5A8E2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */; }; + 765A5A8F2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 765A5A902F35CD8B0003FF7D /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */; }; + 765A5A912F35CD8B0003FF7D /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 76AA18AE2F3B2A4D00DC8DFC /* ring_30Sec.caf in Resources */ = {isa = PBXBuildFile; fileRef = 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */; }; + 76AA18AF2F3B2A4D00DC8DFC /* ring_30Sec.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 76AA18AD2F3B2A4D00DC8DFC /* ring_30Sec.mp3 */; }; 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 */; }; @@ -29,12 +43,15 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + 765A5A922F35CD8B0003FF7D /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( + 765A5A8F2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Embed Frameworks */, + 765A5A8D2F35CD8B0003FF7D /* Penguin.xcframework in Embed Frameworks */, + 765A5A912F35CD8B0003FF7D /* PenNavUI.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -49,10 +66,21 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = ""; }; + 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; + 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; }; + 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = ""; }; + 61243B452EC5FA3700D46FA0 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = ""; }; + 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7595037DD52211B91157B0F3 /* 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 = ""; }; + 765A5A802F35CD730003FF7D /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = ""; }; + 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = ""; }; + 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = ""; }; 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; }; + 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ring_30Sec.caf; sourceTree = ""; }; + 76AA18AD2F3B2A4D00DC8DFC /* ring_30Sec.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = ring_30Sec.mp3; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 8E12CEEB8E334EE22D5259D7 /* 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; @@ -71,6 +99,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 765A5A8C2F35CD8B0003FF7D /* Penguin.xcframework in Frameworks */, + 765A5A902F35CD8B0003FF7D /* PenNavUI.xcframework in Frameworks */, + 765A5A8E2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Frameworks */, DE1EF78253E64BE86845D2CC /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -86,9 +117,32 @@ path = RunnerTests; sourceTree = ""; }; + 61243B412EC5FA3700D46FA0 /* Helper */ = { + isa = PBXGroup; + children = ( + 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */, + ); + path = Helper; + sourceTree = ""; + }; + 61243B472EC5FA3700D46FA0 /* Penguin */ = { + isa = PBXGroup; + children = ( + 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */, + 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */, + 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */, + 61243B452EC5FA3700D46FA0 /* PenguinView.swift */, + 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */, + ); + path = Penguin; + sourceTree = ""; + }; 766D8CB22EC60BE600D05E07 /* Frameworks */ = { isa = PBXGroup; children = ( + 765A5A802F35CD730003FF7D /* Penguin.xcframework */, + 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */, + 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */, D562310E31D1DDEFA02A6C12 /* Pods_Runner.framework */, ); name = Frameworks; @@ -139,6 +193,10 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */, + 76AA18AD2F3B2A4D00DC8DFC /* ring_30Sec.mp3 */, + 61243B412EC5FA3700D46FA0 /* Helper */, + 61243B472EC5FA3700D46FA0 /* Penguin */, 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */, 478CFA952E6E20A60064F3D7 /* Runner.entitlements */, 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */, @@ -183,10 +241,10 @@ 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 8372B02399CDF54531650AD4 /* [CP] Embed Pods Frameworks */, 81DE7C26F41956799E954FCE /* [CP] Copy Pods Resources */, + 765A5A922F35CD8B0003FF7D /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( ); @@ -248,6 +306,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 76AA18AE2F3B2A4D00DC8DFC /* ring_30Sec.caf in Resources */, + 76AA18AF2F3B2A4D00DC8DFC /* ring_30Sec.mp3 in Resources */, 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 478CFA942E638C8E0064F3D7 /* GoogleService-Info.plist in Resources */, @@ -362,6 +422,12 @@ 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; @@ -457,7 +523,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -466,8 +532,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; + MARKETING_VERSION = 0.0.1; + PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -643,7 +709,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -652,8 +718,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; + MARKETING_VERSION = 0.0.1; + PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -672,7 +738,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -681,8 +747,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; + MARKETING_VERSION = 0.0.1; + PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.HMGPatientApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist index c179ec60..a9b1f53a 100644 --- a/ios/Runner/GoogleService-Info.plist +++ b/ios/Runner/GoogleService-Info.plist @@ -2,10 +2,6 @@ - CLIENT_ID - 815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt ANDROID_CLIENT_ID 815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com API_KEY @@ -15,24 +11,24 @@ PLIST_VERSION 1 BUNDLE_ID - com.HMG.HMG-Smartphone + com.cloudsolutions.HMGPatientApp PROJECT_ID api-project-815750722565 STORAGE_BUCKET - api-project-815750722565.appspot.com + api-project-815750722565.firebasestorage.app IS_ADS_ENABLED - + IS_ANALYTICS_ENABLED - + IS_APPINVITE_ENABLED - + IS_GCM_ENABLED - + IS_SIGNIN_ENABLED - + GOOGLE_APP_ID - 1:815750722565:ios:328ec247a81a2ca23c186c + 1:815750722565:ios:34ec03c09e02e21f3c186c DATABASE_URL https://api-project-815750722565.firebaseio.com - + \ No newline at end of file diff --git a/ios/Runner/ring_30Sec 2.caf b/ios/Runner/ring_30Sec 2.caf new file mode 100644 index 00000000..b5bb4b88 Binary files /dev/null and b/ios/Runner/ring_30Sec 2.caf differ diff --git a/ios/Runner/ring_30Sec.caf b/ios/Runner/ring_30Sec.caf new file mode 100644 index 00000000..b5bb4b88 Binary files /dev/null and b/ios/Runner/ring_30Sec.caf differ diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 231b037b..e706a9d6 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -7,9 +7,11 @@ import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/presentation/home/app_update_page.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:http/http.dart' as http; import '../exceptions/api_failure.dart'; @@ -36,6 +38,7 @@ abstract class ApiClient { required Function(dynamic response, int statusCode) onSuccess, required Function(String error, int statusCode) onFailure, Map? queryParams, + Map apiHeaders, bool isAllowAny, bool isExternal, bool isRCService, @@ -191,11 +194,17 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; } - // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 4768663; + body['TokenID'] = "@dm!n"; + body['PatientID'] = 4773781; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; // body['SessionID'] = "45786230487560q"; + + //VIP Patient: 1181868 + + // body['IdentificationNo'] = "2235558844"; + // body['MobileNo'] = "966533147722"; + // body['PatientID'] = 809289; } if(!url.contains("/paymentApi")) { @@ -220,7 +229,8 @@ class ApiClientImp implements ApiClient { // Handle body encoding based on isBodyPlainText flag final dynamic requestBody = isBodyPlainText ? body : json.encode(body); debugPrint("uri: ${Uri.parse(url.trim())}"); - debugPrint("body: ${json.encode(body)}", wrapWidth: 2048); + var requestBodyJSON = json.encode(body); + debugPrint("body: $requestBodyJSON", wrapWidth: 2048); final response = await http.post(Uri.parse(url.trim()), body: requestBody, headers: headers); final int statusCode = response.statusCode; // log("response.body: ${response.body}"); @@ -245,8 +255,16 @@ class ApiClientImp implements ApiClient { } else { if (parsed['ErrorType'] == 4) { //TODO : handle app update - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, - failureType: AppUpdateFailure("parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']")); + // onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, + // failureType: AppUpdateFailure("parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']")); + + ApiClient._navigationService.pushAndRemoveUntil( + CustomPageRoute( + page: AppUpdatePage( + appUpdateMessage: parsed['ErrorEndUserMessage'], + )), + ModalRoute.withName("/appUpdate") + ); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } if (parsed['ErrorType'] == 2) { @@ -366,6 +384,7 @@ class ApiClientImp implements ApiClient { {required Function(dynamic response, int statusCode) onSuccess, required Function(String error, int statusCode) onFailure, Map? queryParams, + Map? apiHeaders, bool isAllowAny = false, bool isExternal = false, bool isRCService = false}) async { @@ -390,7 +409,7 @@ class ApiClientImp implements ApiClient { if (await Utils.checkConnection(bypassConnectionCheck: true)) { final response = await http.get( Uri.parse(url.trim()), - headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, + headers: apiHeaders ?? {'Content-Type': 'application/json', 'Accept': 'application/json'}, ); final int statusCode = response.statusCode; // print("statusCode :$statusCode"); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index f78c0201..708324eb 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -1,6 +1,242 @@ import 'package:amazon_payfort/amazon_payfort.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; +class ApiConsts { + static const maxSmallScreen = 660; + + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; + + // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT + + static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD + + static String rcBaseUrl = 'https://rc.hmg.com/'; // dRC API URL PROD + static String hmgPharmacyApiBaseUrl = 'https://hmgpharmacyapi.hmg.com/'; // dRC API URL PROD + static String symptomsCheckerApi = '${hmgPharmacyApiBaseUrl}symptomsapi/api/SymptomChecker'; // dRC API URL PROD + + static var payFortEnvironment = FortEnvironment.production; + static var applePayMerchantId = "merchant.com.hmgwebservices"; + + static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE + // static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT + + static String TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; + static String GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments"; + static String GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; + + static String QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + + static String CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; + + // static String GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; + +// var payFortEnvironment = FortEnvironment.test; +// var applePayMerchantId = "merchant.com.hmgwebservices.uat"; + + static setBackendURLs() { + switch (appEnvironmentType) { + case AppEnvironmentTypeEnum.prod: + baseUrl = "https://hmgwebservices.com/"; + payFortEnvironment = FortEnvironment.production; + applePayMerchantId = "merchant.com.hmgwebservices"; + SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; + TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; + GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments"; + GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; + rcBaseUrl = 'https://rc.hmg.com/'; + QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; + break; + case AppEnvironmentTypeEnum.dev: + baseUrl = "https://uat.hmgwebservices.com/"; + payFortEnvironment = FortEnvironment.test; + applePayMerchantId = "merchant.com.hmgwebservices.uat"; + SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; + TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; + GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; + GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; + rcBaseUrl = 'https://rc.hmg.com/uat/'; + QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; + break; + case AppEnvironmentTypeEnum.uat: + baseUrl = "https://uat.hmgwebservices.com/"; + payFortEnvironment = FortEnvironment.test; + applePayMerchantId = "merchant.com.hmgwebservices.uat"; + SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; + TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; + GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; + GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; + rcBaseUrl = 'https://rc.hmg.com/uat/'; + QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; + break; + case AppEnvironmentTypeEnum.preProd: + baseUrl = "https://webservices.hmg.com/"; + payFortEnvironment = FortEnvironment.production; + applePayMerchantId = "merchant.com.hmgwebservices"; + SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; + TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; + GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; + GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; + rcBaseUrl = 'https://rc.hmg.com/'; + QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; + break; + case AppEnvironmentTypeEnum.qa: + baseUrl = "https://uat.hmgwebservices.com/"; + payFortEnvironment = FortEnvironment.test; + applePayMerchantId = "merchant.com.hmgwebservices.uat"; + SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; + TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; + GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; + GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; + rcBaseUrl = 'https://rc.hmg.com/uat/'; + QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; + break; + case AppEnvironmentTypeEnum.staging: + baseUrl = "https://uat.hmgwebservices.com/"; + payFortEnvironment = FortEnvironment.test; + applePayMerchantId = "merchant.com.hmgwebservices.uat"; + SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; + TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; + GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; + GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; + rcBaseUrl = 'https://rc.hmg.com/uat/'; + QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; + break; + } + } + + static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; + + static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; + static final String sendActivationCodeRegister = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; + static final String checkActivationCode = 'Services/Authentication.svc/REST/CheckActivationCode'; + static final String checkActivationCodeRegister = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; + static final String checkUsageAgreement = 'Services/Patients.svc/REST/CheckForUsageAgreement'; + static final String getUserAgreementContent = 'Services/Patients.svc/REST/GetUsageAgreementText'; + + static final String checkPatientForRegistration = 'Services/Authentication.svc/REST/CheckPatientForRegisteration'; + static final String checkUserStatus = 'Services/NHIC.svc/REST/GetPatientInfo'; + + static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; + static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; + static final String getPatientMobileData = '/Services/Authentication.svc/REST/GetMobileLoginInfo'; + static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege'; + static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration'; + + static final String addFamilyFile = 'Services/Patients.svc/REST/ShareFamilyFileService'; + static final String sendFamilyFileActivation = 'Services/Authentication.svc/REST/SendActivationCodeForFamilyFile'; + static final String checkActivationCodeForFamily = 'Services/Authentication.svc/REST/CheckActivationCodeForFamilyFile'; + static final String getAllPendingRecordsByResponseId = 'Services/Authentication.svc/REST/GetAllPendingRecordsByResponseId'; + static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus'; + static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile'; + static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus'; + static final String getActivePrescriptionsDetails = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID'; + static final String getTermsConditions = 'Services/Patients.svc/Rest/GetUserTermsAndConditions'; + static final String getMonthlyReports = 'Services/Patients.svc/Rest/UpdatePateintHealthSummaryReport'; + static final String updatePatientEmail = 'Services/Patients.svc/Rest/UpdatePateintEmail'; + static final String getQrParkingDetails = 'Services/SWP.svc/REST/GetQRParkingByID'; + + // Ancillary Order Apis + static final String getOnlineAncillaryOrderList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList'; + static final String getOnlineAncillaryOrderProcList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderProcList'; + static final String generateAncillaryOrderInvoice = 'Services/Doctors.svc/REST/AutoGenerateAncillaryOrderInvoice'; + static final String autoGenerateAncillaryOrdersInvoice = 'Services/Doctors.svc/REST/AutoGenerateAncillaryOrderInvoice'; + static final String getRequestStatusByRequestID = 'Services/PayFort_Serv.svc/REST/GetRequestStatusByRequestID'; + + //Payment APIs + static final String applePayInsertRequest = "Services/PayFort_Serv.svc/REST/PayFort_ApplePayRequestData_Insert"; + static final String createAdvancePayments = 'Services/Patients.svc/REST/HIS_CreateAdvancePayment'; + static final String addAdvanceNumberRequest = 'Services/PayFort_Serv.svc/REST/AddAdvancedNumberRequest'; + + // RC COMPREHENSIVE MEDICAL CHECKUP ServIces + static final String allCMCOrdersRc = 'api/cmc/list'; + static final String allCMCServicesRc = 'api/cmc/getallcmc'; + static final String updateCMCOrder = 'api/cmc/update'; + static final String addCMCOrder = 'api/cmc/add'; + static final String getHospitalsList = 'Services/Lists.svc/REST/GetProject'; + + // RC HOME HEALTHCARE ServIces + static final String allHHCOrdersRc = 'api/hhc/list'; + static final String allHHCServicesRc = 'api/HHC/getallhhc'; + static final String updateHHCOrder = 'api/hhc/update'; + static final String addHHCOrder = 'api/HHC/add'; + + // SYMPTOMS CHECKER API + static final String symptomsUserLogin = '$symptomsCheckerApi/user_login'; + static final String getBodySymptomsByName = '$symptomsCheckerApi/GetBodySymptomsByName'; + static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors'; + static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion'; + static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis'; + static final String explain = '$symptomsCheckerApi/ExplainDiagnosisResult'; + static final String getClinicFromCondition = '$symptomsCheckerApi/GetClinicsByCondition?condition='; + + //E-REFERRAL SERVICES + static final getAllRelationshipTypes = "Services/Patients.svc/REST/GetAllRelationshipTypes"; + static final sendActivationCodeForEReferral = 'Services/Authentication.svc/REST/SendActivationCodeForEReferral'; + static final checkActivationCodeForEReferral = 'Services/Authentication.svc/REST/CheckActivationCodeForEReferral'; + static final getAllCities = 'services/Lists.svc/rest/GetAllCities'; + static final createEReferral = "Services/Patients.svc/REST/CreateEReferral"; + static final getEReferrals = "Services/Patients.svc/REST/GetEReferrals"; + + //WATER CONSUMPTION + static String h2oGetUserProgress = "Services/H2ORemainder.svc/REST/H2O_GetUserProgress"; + static String h2oInsertUserActivity = "Services/H2ORemainder.svc/REST/H2O_InsertUserActivity"; + static String h2oInsertUserDetailsNew = "Services/H2ORemainder.svc/REST/H2O_InsertUserDetails_New"; + static String h2oGetUserDetail = "Services/H2ORemainder.svc/REST/H2O_GetUserDetails_New"; + static String h2oUpdateUserDetail = "Services/H2ORemainder.svc/REST/H2O_UpdateUserDetails_New"; + static String h2oUndoUserActivity = "Services/H2ORemainder.svc/REST/H2o_UndoUserActivity"; + + // HEALTH TRACKERS + // Blood Sugar (Diabetic) + static String getDiabeticResultAverage = 'Services/Patients.svc/REST/Patient_GetDiabeticResultAverage'; + static String getDiabeticResult = 'Services/Patients.svc/REST/Patient_GetDiabtecResults'; + static String addDiabeticResult = 'Services/Patients.svc/REST/Patient_AddDiabtecResult'; + static String updateDiabeticResult = 'Services/Patients.svc/REST/Patient_UpdateDiabtecResult'; + static String deactivateDiabeticStatus = 'Services/Patients.svc/REST/Patient_DeactivateDiabeticStatus'; + static String sendAverageBloodSugarReport = 'Services/Notifications.svc/REST/SendAverageBloodSugarReport'; + + // Blood Pressure + static String getBloodPressureResultAverage = 'Services/Patients.svc/REST/Patient_GetBloodPressureResultAverage'; + static String getBloodPressureResult = 'Services/Patients.svc/REST/Patient_GetBloodPressureResult'; + static String addBloodPressureResult = 'Services/Patients.svc/REST/Patient_AddBloodPressureResult'; + static String updateBloodPressureResult = 'Services/Patients.svc/REST/Patient_UpdateBloodPressureResult'; + static String deactivateBloodPressureStatus = 'Services/Patients.svc/REST/Patient_DeactivateBloodPressureStatus'; + static String sendAverageBloodPressureReport = 'Services/Notifications.svc/REST/SendAverageBloodPressureReport'; + + // Weight Measurement + static String getWeightMeasurementResultAverage = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResultAverage'; + static String getWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResult'; + static String addWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_AddWeightMeasurementResult'; + static String updateWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_UpdateWeightMeasurementResult'; + static String deactivateWeightMeasurementStatus = 'Services/Patients.svc/REST/Patient_DeactivateWeightMeasurementStatus'; + static String sendAverageBodyWeightReport = 'Services/Notifications.svc/REST/SendAverageBodyWeightReport'; + + //Blood Donation + static String bloodGroupUpdate = "Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType"; + static String userAgreementForBloodGroupUpdate = "Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation"; + static String getProjectsHaveBDClinics = "Services/OUTPs.svc/REST/BD_getProjectsHaveBDClinics"; + static String getClinicsBDFreeSlots = "Services/OUTPs.svc/REST/BD_GetFreeSlots"; + + static String getPatientBloodGroup = "services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails"; + static String getPatientBloodAgreement = "Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation"; + static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API"; + static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; + + // ************ static values for Api **************** + static final double appVersionID = 19.8; + // 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'; +} + // PACKAGES and OFFERS var EXA_CART_API_BASE_URL = 'https://mdlaboratories.com/offersdiscounts'; // var EXA_CART_API_BASE_URL = 'http://10.200.101.75:9000'; @@ -680,241 +916,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard'; -class ApiConsts { - static const maxSmallScreen = 660; - - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; - - // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT - - static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD - - static String rcBaseUrl = 'https://rc.hmg.com/'; // dRC API URL PROD - static String hmgPharmacyApiBaseUrl = 'https://hmgpharmacyapi.hmg.com/'; // dRC API URL PROD - static String symptomsCheckerApi = '${hmgPharmacyApiBaseUrl}symptomsapi/api/SymptomChecker'; // dRC API URL PROD - - static var payFortEnvironment = FortEnvironment.production; - static var applePayMerchantId = "merchant.com.hmgwebservices"; - - static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE - // static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT - - static String TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; - static String GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments"; - static String GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; - - static String QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - - static String CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; - - // static String GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; - -// var payFortEnvironment = FortEnvironment.test; -// var applePayMerchantId = "merchant.com.hmgwebservices.uat"; - - static setBackendURLs() { - switch (appEnvironmentType) { - case AppEnvironmentTypeEnum.prod: - baseUrl = "https://hmgwebservices.com/"; - payFortEnvironment = FortEnvironment.production; - applePayMerchantId = "merchant.com.hmgwebservices"; - SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; - TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; - GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments"; - GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; - rcBaseUrl = 'https://rc.hmg.com/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; - break; - case AppEnvironmentTypeEnum.dev: - baseUrl = "https://uat.hmgwebservices.com/"; - payFortEnvironment = FortEnvironment.test; - applePayMerchantId = "merchant.com.hmgwebservices.uat"; - SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; - TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; - GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; - GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - rcBaseUrl = 'https://rc.hmg.com/uat/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; - break; - case AppEnvironmentTypeEnum.uat: - baseUrl = "https://uat.hmgwebservices.com/"; - payFortEnvironment = FortEnvironment.test; - applePayMerchantId = "merchant.com.hmgwebservices.uat"; - SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; - TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; - GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; - GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - rcBaseUrl = 'https://rc.hmg.com/uat/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; - break; - case AppEnvironmentTypeEnum.preProd: - baseUrl = "https://webservices.hmg.com/"; - payFortEnvironment = FortEnvironment.production; - applePayMerchantId = "merchant.com.hmgwebservices"; - SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; - TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; - GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; - GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - rcBaseUrl = 'https://rc.hmg.com/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; - break; - case AppEnvironmentTypeEnum.qa: - baseUrl = "https://uat.hmgwebservices.com/"; - payFortEnvironment = FortEnvironment.test; - applePayMerchantId = "merchant.com.hmgwebservices.uat"; - SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; - TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; - GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; - GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - rcBaseUrl = 'https://rc.hmg.com/uat/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; - break; - case AppEnvironmentTypeEnum.staging: - baseUrl = "https://uat.hmgwebservices.com/"; - payFortEnvironment = FortEnvironment.test; - applePayMerchantId = "merchant.com.hmgwebservices.uat"; - SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; - TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; - GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; - GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - rcBaseUrl = 'https://rc.hmg.com/uat/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; - CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId"; - break; - } - } - - static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; - static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; - - static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; - static final String sendActivationCodeRegister = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; - static final String checkActivationCode = 'Services/Authentication.svc/REST/CheckActivationCode'; - static final String checkActivationCodeRegister = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; - static final String checkUsageAgreement = 'Services/Patients.svc/REST/CheckForUsageAgreement'; - static final String getUserAgreementContent = 'Services/Patients.svc/REST/GetUsageAgreementText'; - - static final String checkPatientForRegistration = 'Services/Authentication.svc/REST/CheckPatientForRegisteration'; - static final String checkUserStatus = 'Services/NHIC.svc/REST/GetPatientInfo'; - - static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; - static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; - static final String getPatientMobileData = '/Services/Authentication.svc/REST/GetMobileLoginInfo'; - static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege'; - static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration'; - - static final String addFamilyFile = 'Services/Patients.svc/REST/ShareFamilyFileService'; - static final String sendFamilyFileActivation = 'Services/Authentication.svc/REST/SendActivationCodeForFamilyFile'; - static final String checkActivationCodeForFamily = 'Services/Authentication.svc/REST/CheckActivationCodeForFamilyFile'; - static final String getAllPendingRecordsByResponseId = 'Services/Authentication.svc/REST/GetAllPendingRecordsByResponseId'; - static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus'; - static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile'; - static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus'; - static final String getActivePrescriptionsDetails = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID'; - static final String getTermsConditions = 'Services/Patients.svc/Rest/GetUserTermsAndConditions'; - static final String getMonthlyReports = 'Services/Patients.svc/Rest/UpdatePateintHealthSummaryReport'; - static final String updatePatientEmail = 'Services/Patients.svc/Rest/UpdatePateintEmail'; - static final String getQrParkingDetails = 'Services/SWP.svc/REST/GetQRParkingByID'; - - // Ancillary Order Apis - static final String getOnlineAncillaryOrderList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList'; - static final String getOnlineAncillaryOrderProcList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderProcList'; - static final String generateAncillaryOrderInvoice = 'Services/Doctors.svc/REST/AutoGenerateAncillaryOrderInvoice'; - static final String autoGenerateAncillaryOrdersInvoice = 'Services/Doctors.svc/REST/AutoGenerateAncillaryOrderInvoice'; - static final String getRequestStatusByRequestID = 'Services/PayFort_Serv.svc/REST/GetRequestStatusByRequestID'; - - //Payment APIs - static final String applePayInsertRequest = "Services/PayFort_Serv.svc/REST/PayFort_ApplePayRequestData_Insert"; - static final String createAdvancePayments = 'Services/Patients.svc/REST/HIS_CreateAdvancePayment'; - static final String addAdvanceNumberRequest = 'Services/PayFort_Serv.svc/REST/AddAdvancedNumberRequest'; - - // RC COMPREHENSIVE MEDICAL CHECKUP ServIces - static final String allCMCOrdersRc = 'api/cmc/list'; - static final String allCMCServicesRc = 'api/cmc/getallcmc'; - static final String updateCMCOrder = 'api/cmc/update'; - static final String addCMCOrder = 'api/cmc/add'; - static final String getHospitalsList = 'Services/Lists.svc/REST/GetProject'; - - // RC HOME HEALTHCARE ServIces - static final String allHHCOrdersRc = 'api/hhc/list'; - static final String allHHCServicesRc = 'api/HHC/getallhhc'; - static final String updateHHCOrder = 'api/hhc/update'; - static final String addHHCOrder = 'api/HHC/add'; - - // SYMPTOMS CHECKER API - static final String symptomsUserLogin = '$symptomsCheckerApi/user_login'; - static final String getBodySymptomsByName = '$symptomsCheckerApi/GetBodySymptomsByName'; - static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors'; - static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion'; - static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis'; - static final String explain = '$symptomsCheckerApi/ExplainDiagnosisResult'; - - //E-REFERRAL SERVICES - static final getAllRelationshipTypes = "Services/Patients.svc/REST/GetAllRelationshipTypes"; - static final sendActivationCodeForEReferral = 'Services/Authentication.svc/REST/SendActivationCodeForEReferral'; - static final checkActivationCodeForEReferral = 'Services/Authentication.svc/REST/CheckActivationCodeForEReferral'; - static final getAllCities = 'services/Lists.svc/rest/GetAllCities'; - static final createEReferral = "Services/Patients.svc/REST/CreateEReferral"; - static final getEReferrals = "Services/Patients.svc/REST/GetEReferrals"; - - //WATER CONSUMPTION - static String h2oGetUserProgress = "Services/H2ORemainder.svc/REST/H2O_GetUserProgress"; - static String h2oInsertUserActivity = "Services/H2ORemainder.svc/REST/H2O_InsertUserActivity"; - static String h2oInsertUserDetailsNew = "Services/H2ORemainder.svc/REST/H2O_InsertUserDetails_New"; - static String h2oGetUserDetail = "Services/H2ORemainder.svc/REST/H2O_GetUserDetails_New"; - static String h2oUpdateUserDetail = "Services/H2ORemainder.svc/REST/H2O_UpdateUserDetails_New"; - static String h2oUndoUserActivity = "Services/H2ORemainder.svc/REST/H2o_UndoUserActivity"; - - // HEALTH TRACKERS - // Blood Sugar (Diabetic) - static String getDiabeticResultAverage = 'Services/Patients.svc/REST/Patient_GetDiabeticResultAverage'; - static String getDiabeticResult = 'Services/Patients.svc/REST/Patient_GetDiabtecResults'; - static String addDiabeticResult = 'Services/Patients.svc/REST/Patient_AddDiabtecResult'; - static String updateDiabeticResult = 'Services/Patients.svc/REST/Patient_UpdateDiabtecResult'; - static String deactivateDiabeticStatus = 'Services/Patients.svc/REST/Patient_DeactivateDiabeticStatus'; - static String sendAverageBloodSugarReport = 'Services/Notifications.svc/REST/SendAverageBloodSugarReport'; - - // Blood Pressure - static String getBloodPressureResultAverage = 'Services/Patients.svc/REST/Patient_GetBloodPressureResultAverage'; - static String getBloodPressureResult = 'Services/Patients.svc/REST/Patient_GetBloodPressureResult'; - static String addBloodPressureResult = 'Services/Patients.svc/REST/Patient_AddBloodPressureResult'; - static String updateBloodPressureResult = 'Services/Patients.svc/REST/Patient_UpdateBloodPressureResult'; - static String deactivateBloodPressureStatus = 'Services/Patients.svc/REST/Patient_DeactivateBloodPressureStatus'; - static String sendAverageBloodPressureReport = 'Services/Notifications.svc/REST/SendAverageBloodPressureReport'; - - // Weight Measurement - static String getWeightMeasurementResultAverage = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResultAverage'; - static String getWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResult'; - static String addWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_AddWeightMeasurementResult'; - static String updateWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_UpdateWeightMeasurementResult'; - static String deactivateWeightMeasurementStatus = 'Services/Patients.svc/REST/Patient_DeactivateWeightMeasurementStatus'; - static String sendAverageBodyWeightReport = 'Services/Notifications.svc/REST/SendAverageBodyWeightReport'; - - //Blood Donation - static String bloodGroupUpdate = "Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType"; - static String userAgreementForBloodGroupUpdate = "Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation"; - static String getProjectsHaveBDClinics = "Services/OUTPs.svc/REST/BD_getProjectsHaveBDClinics"; - static String getClinicsBDFreeSlots = "Services/OUTPs.svc/REST/BD_GetFreeSlots"; - - - static String getPatientBloodGroup = "services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails"; - static String getPatientBloodAgreement = "Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation"; - static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API"; - static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; - - // ************ static values for Api **************** - // static final double appVersionID = 19.7; - 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'; -} +const SEND_PATIENT_IMMEDIATE_UPDATE_INSURANCE_REQUEST = 'Services/OUTPs.svc/REST/PatientCompanyUpdate'; class ApiKeyConstants { static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng'; diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index c2fd44be..f7fe9f79 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -310,6 +310,10 @@ class AppAssets { static const String bulb = '$svgBasePath/bulb.svg'; static const String switchBtn = '$svgBasePath/switch.svg'; + static const String livecare_video = '$svgBasePath/livecare_video.svg'; + static const String livecare_audio = '$svgBasePath/livecare_audio.svg'; + static const String livecare_phone = '$svgBasePath/livecare_phone.svg'; + //Health Trackers static const String bloodPressureIcon = '$svgBasePath/blood_pressure_icon.svg'; static const String bloodSugarOnlyIcon = '$svgBasePath/blood_sugar_only_icon.svg'; @@ -366,8 +370,10 @@ class AppAssets { static const String maleIcon = '$pngBasePath/male_icon.png'; static const String femaleIcon = '$pngBasePath/female_icon.png'; - static const String fullBodyFront = '$pngBasePath/full_body_front.png'; - static const String fullBodyBack = '$pngBasePath/full_body_back.png'; + static const String fullBodyFrontMale = '$pngBasePath/full_body_front_male.png'; + static const String fullBodyBackMale = '$pngBasePath/full_body_back_male.png'; + static const String fullBodyFrontFemale = '$pngBasePath/full_body_front_female.png'; + static const String fullBodyBackFemale = '$pngBasePath/full_body_back_female.png'; static const String bmiFullBody = '$pngBasePath/bmi_image_1.png'; } diff --git a/lib/core/utils/penguin_method_channel.dart b/lib/core/utils/penguin_method_channel.dart index 69ef4be7..c3da7242 100644 --- a/lib/core/utils/penguin_method_channel.dart +++ b/lib/core/utils/penguin_method_channel.dart @@ -12,13 +12,17 @@ class PenguinMethodChannel { try { await _channel.invokeMethod('launchPenguin', { "storyboardName": storyboardName, - "baseURL": "https://penguinuat.hmg.com", - // "dataURL": "https://hmg.nav.penguinin.com", - // "positionURL": "https://hmg.nav.penguinin.com", - // "dataURL": "https://hmg-v33.local.penguinin.com", - // "positionURL": "https://hmg-v33.local.penguinin.com", - "dataURL": "https://penguinuat.hmg.com", - "positionURL": "https://penguinuat.hmg.com", + + // UAT URLs + // "baseURL": "https://penguinuat.hmg.com", + // "dataURL": "https://penguinuat.hmg.com", + // "positionURL": "https://penguinuat.hmg.com", + + // Prod URLs + "baseURL": "https://eagleiq.hmg.com", + "dataURL": "https://eagleiq.hmg.com", + "positionURL": "https://eagleiq.hmg.com", + "dataServiceName": "api", "positionServiceName": "pe", "clientID": "HMG", diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index aef18f73..8215d570 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -95,7 +95,7 @@ _incomingCall(Map data) async { missedCallNotificationChannelName: "Missed Call", isShowCallID: false), ios: IOSParams( - iconName: 'Meena Health', + iconName: 'CallKitLogo', handleType: 'generic', supportsVideo: true, maximumCallGroups: 2, diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 60925bca..671312d1 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -408,6 +408,8 @@ class Utils { Widget? bodyWidget, Function? onConfirmTap, Function? onCancelTap, + String? cancelText, + String? confirmText, }) { return Column( mainAxisAlignment: MainAxisAlignment.center, @@ -425,7 +427,7 @@ class Utils { children: [ Expanded( child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: cancelText ?? LocaleKeys.cancel.tr(), onPressed: () { if (onCancelTap != null) { onCancelTap(); @@ -434,14 +436,14 @@ class Utils { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, - icon: AppAssets.cancel, - iconColor: AppColors.whiteColor, + // icon: AppAssets.cancel, + // iconColor: AppColors.whiteColor, ), ), SizedBox(width: 8.h), Expanded( child: CustomButton( - text: LocaleKeys.confirm.tr(), + text: confirmText ?? LocaleKeys.confirm.tr(), onPressed: () async { if (onConfirmTap != null) { onConfirmTap(); @@ -450,7 +452,7 @@ class Utils { backgroundColor: AppColors.bgGreenColor, borderColor: AppColors.bgGreenColor, textColor: Colors.white, - icon: AppAssets.confirm, + // icon: AppAssets.confirm, ), ), ], @@ -988,6 +990,12 @@ class Utils { return isAllowed; } + static bool containsArabic(String text) { + // Using Unicode range for Arabic characters + final RegExp arabicRegex = RegExp(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]'); + return arabicRegex.hasMatch(text); + } + static String toEnglishNumbers(String input) { const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index f087f748..792bff50 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -192,6 +192,7 @@ extension EmailValidator on String { int? maxlines, double? letterSpacing = 0, double? height, + String? fontFamily, TextOverflow? textOverflow, }) => Text( @@ -206,7 +207,7 @@ extension EmailValidator on String { height: height, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), decoration: isUnderLine ? TextDecoration.underline : null, - fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', + fontFamily: fontFamily ?? (isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), decorationColor: color ?? AppColors.blackColor), ); @@ -231,12 +232,13 @@ extension EmailValidator on String { TextAlign? textAlign, FontWeight? weight, TextOverflow? textOverflow, + String? fontFamily, double? letterSpacing = -0.4, Color decorationColor = AppColors.errorColor}) => Text( this, maxLines: maxlines, - textAlign: isCenter ? TextAlign.center : null, + textAlign: isCenter ? textAlign ?? TextAlign.center : null, // locale: Locale('en', 'US'), style: TextStyle( color: color ?? AppColors.blackColor, @@ -246,7 +248,7 @@ extension EmailValidator on String { overflow: textOverflow, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), decoration: isUnderLine ? TextDecoration.underline : null, - fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', + fontFamily: fontFamily ?? (isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), decorationColor: decorationColor), ); diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 70f10bbf..58754dc9 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -161,15 +161,17 @@ extension SmoothContainerExtension on ShapeBorder { smoothness: 1, side: side ?? BorderSide.none, ), - shadows: hasShadow - ? [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 32, - offset: const Offset(0, 0), - ) - ] - : [], + shadows: + // hasShadow + // ? [ + // BoxShadow( + // color: const Color(0xff000000).withOpacity(.05), + // blurRadius: 32, + // offset: const Offset(0, 0), + // ) + // ] + // : + [], ); } } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 18147a34..9a3fffc5 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -76,7 +76,6 @@ class AuthenticationViewModel extends ChangeNotifier { nameController = TextEditingController(), emailController = TextEditingController(); - CountryEnum selectedCountrySignup = CountryEnum.saudiArabia; MaritalStatusTypeEnum? maritalStatus; GenderTypeEnum? genderType; @@ -583,8 +582,13 @@ class AuthenticationViewModel extends ChangeNotifier { MedicalFileViewModel medicalVm = getIt(); if (!_appState.getIsChildLoggedIn) { await medicalVm.getFamilyFiles(status: 0); + if (isFormFamilyFile) { + await medicalVm.getAllPendingRecordsByResponseId(); + _navigationService.pushAndReplace(AppRoutes.medicalFilePage); + } else { + _navigationService.replaceAllRoutesAndNavigateToLanding(); + } // await medicalVm.getAllPendingRecordsByResponseId(); - _navigationService.replaceAllRoutesAndNavigateToLanding(); } } else { if (activation.list != null && activation.list!.isNotEmpty) { @@ -744,10 +748,12 @@ class AuthenticationViewModel extends ChangeNotifier { Future onWrongActivationCode({String? message}) async { otpScreenNotifier.value = true; - await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () { - LoaderBottomSheet.hideLoader(); - _navigationService.pushAndReplace(AppRoutes.loginScreen); - }); + await _dialogService.showErrorBottomSheet( + message: message ?? "Something went wrong. ", + onOkPressed: () { + LoaderBottomSheet.hideLoader(); + _navigationService.pushAndReplace(AppRoutes.loginScreen); + }); } loginWithFingerPrintFace(Function success) async { @@ -841,7 +847,7 @@ class AuthenticationViewModel extends ChangeNotifier { } else { LoadingUtils.hideFullScreenLoader(); if (apiResponse.data["MessageStatus"] == 1) { - LoadingUtils.showFullScreenLoader(isSuccessDialog: true); + LoadingUtils.showFullScreenLoader(isSuccessDialog: true, 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. await clearDefaultInputValues(); // This will Clear All Default Values Of User. Future.delayed(Duration(seconds: 1), () { @@ -1058,7 +1064,10 @@ class AuthenticationViewModel extends ChangeNotifier { List projectDetailListModel = []; resultEither.fold( - (failure) async => await _errorHandlerService.handleError(failure: failure), + // (failure) async => await _errorHandlerService.handleError(failure: failure), + (failure) async { + print(failure.message); + }, (apiResponse) async { if (apiResponse.messageStatus == 2) { await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty"); diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index 9b53a133..3132dc8c 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -34,6 +34,7 @@ import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'models/resp_models/get_livecare_clinics_response_model.dart'; @@ -463,7 +464,11 @@ class BookAppointmentsViewModel extends ChangeNotifier { final result = await bookAppointmentsRepo.getLiveCareScheduleClinics(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!); result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + isClinicsListLoading = false; + notifyListeners(); + }, (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -838,16 +843,11 @@ class BookAppointmentsViewModel extends ChangeNotifier { appointmentDate: apiResponse.data["SameClinicApptList"][0]['AppointmentDate'], ); - showCommonBottomSheet(navigationService.navigatorKey.currentContext!, - child: Utils.getLoadingWidget(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr()), - callBackFunc: (str) {}, - title: "", - height: ResponsiveExtension.screenHeight * 0.3, - isCloseButtonVisible: false, - isDismissible: false, - isFullScreen: false); + LoaderBottomSheet.showLoader( + loadingText: LocaleKeys.reschedulingAppo.tr(context: navigationService.navigatorKey.currentContext!), + ); await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async { - navigationService.pop(); + LoaderBottomSheet.hideLoader(); Future.delayed(Duration(milliseconds: 50)).then((value) async {}); LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr()); await insertSpecificAppointment( diff --git a/lib/features/contact_us/contact_us_repo.dart b/lib/features/contact_us/contact_us_repo.dart index 5b9057b0..c7581551 100644 --- a/lib/features/contact_us/contact_us_repo.dart +++ b/lib/features/contact_us/contact_us_repo.dart @@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/req_models/request_insert_coc_item.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_patient_ic_projects.dart'; +import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_status_coc_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -17,6 +18,8 @@ abstract class ContactUsRepo { Future>> getChatRequestID({required String name, required String mobileNo, required String workGroup}); Future>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment}); + + Future>>> getStatusForCOC(String identificationNo, String mobileNo, {Function(dynamic)? onSuccess, Function(String)? onError}); } class ContactUsRepoImp implements ContactUsRepo { @@ -181,4 +184,44 @@ class ContactUsRepoImp implements ContactUsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getStatusForCOC(String identificationNo, String mobileNo, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + Map body = {}; + body['IdentificationNo'] = identificationNo; + body['MobileNo'] = mobileNo; + body['Searching_type'] = 1; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post( + GET_STATUS_FOR_COCO, + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['ListCOCItems']; + final cocItemsList = list.map((item) => COCItem.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: cocItemsList, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/features/contact_us/contact_us_view_model.dart b/lib/features/contact_us/contact_us_view_model.dart index 1029802f..72bcff76 100644 --- a/lib/features/contact_us/contact_us_view_model.dart +++ b/lib/features/contact_us/contact_us_view_model.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dar import 'package:hmg_patient_app_new/features/contact_us/models/req_models/request_insert_coc_item.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_patient_ic_projects.dart'; +import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_status_coc_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -33,6 +34,9 @@ class ContactUsViewModel extends ChangeNotifier { List feedbackAttachmentList = []; + List cocItemsList = []; + bool isCOCItemsListLoading = false; + PatientAppointmentHistoryResponseModel? patientFeedbackSelectedAppointment; List feedbackTypeList = [ @@ -52,10 +56,12 @@ class ContactUsViewModel extends ChangeNotifier { isHMGLocationsListLoading = true; isHMGHospitalsListSelected = true; isLiveChatProjectsListLoading = true; + isCOCItemsListLoading = true; hmgHospitalsLocationsList.clear(); hmgPharmacyLocationsList.clear(); liveChatProjectsList.clear(); feedbackAttachmentList.clear(); + cocItemsList.clear(); selectedFeedbackType = FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'); setPatientFeedbackSelectedAppointment(null); getHMGLocations(); @@ -74,6 +80,9 @@ class ContactUsViewModel extends ChangeNotifier { setIsSendFeedbackTabSelected(bool isSelected) { isSendFeedbackTabSelected = isSelected; + if (!isSelected) { + getStatusForCOC(identificationNo: appState.getAuthenticatedUser()!.patientIdentificationNo!, mobileNo: "966${Utils.getPhoneNumberWithoutZero(appState.getAuthenticatedUser()!.mobileNumber!)}"); + } notifyListeners(); } @@ -223,4 +232,38 @@ class ContactUsViewModel extends ChangeNotifier { }, ); } + + Future getStatusForCOC({required String identificationNo, required String mobileNo, Function(dynamic)? onSuccess, Function(String)? onError}) async { + isCOCItemsListLoading = true; + cocItemsList.clear(); + notifyListeners(); + + final result = await contactUsRepo.getStatusForCOC(identificationNo, mobileNo); + + result.fold( + (failure) async { + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + isCOCItemsListLoading = false; + onError(failure.toString()); + } + }, + (apiResponse) { + if (apiResponse.messageStatus == 2) { + if (onError != null) { + isCOCItemsListLoading = false; + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } else if (apiResponse.messageStatus == 1) { + cocItemsList = apiResponse.data!; + cocItemsList.sort((a, b) => a.date!.compareTo(b.date!)); + isCOCItemsListLoading = false; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } diff --git a/lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart b/lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart new file mode 100644 index 00000000..ed62d8ba --- /dev/null +++ b/lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart @@ -0,0 +1,124 @@ +class COCItem { + dynamic appointment; + String? appointmentClinicName; + String? appointmentDate; + String? appointmentProjectName; + String? cOCID; + String? cOCTitle; + String? channel; + dynamic clinic; + String? clinicID; + String? date; + dynamic detail; + dynamic doctor; + String? doctorID; + String? formType; + int? formTypeID; + dynamic identificationNo; + int? itemID; + dynamic mobileNo; + dynamic naturename; + dynamic patientID; + dynamic patientName; + dynamic project; + dynamic projectID; + String? solution; + String? status; + String? statusAr; + dynamic statusEn; + int? statusId; + + COCItem({ + this.appointment, + this.appointmentClinicName, + this.appointmentDate, + this.appointmentProjectName, + this.cOCID, + this.cOCTitle, + this.channel, + this.clinic, + this.clinicID, + this.date, + this.detail, + this.doctor, + this.doctorID, + this.formType, + this.formTypeID, + this.identificationNo, + this.itemID, + this.mobileNo, + this.naturename, + this.patientID, + this.patientName, + this.project, + this.projectID, + this.solution, + this.status, + this.statusAr, + this.statusEn, + this.statusId, + }); + + COCItem.fromJson(Map json) { + appointment = json['Appointment']; + appointmentClinicName = json['AppointmentClinicName']; + appointmentDate = json['AppointmentDate']; + appointmentProjectName = json['AppointmentProjectName']; + cOCID = json['COCID']; + cOCTitle = json['COCTitle']; + channel = json['Channel']; + clinic = json['Clinic']; + clinicID = json['ClinicID']; + date = json['Date']; + detail = json['Detail']; + doctor = json['Doctor']; + doctorID = json['DoctorID']; + formType = json['FormType']; + formTypeID = json['FormTypeID']; + identificationNo = json['IdentificationNo']; + itemID = json['ItemID']; + mobileNo = json['MobileNo']; + naturename = json['Naturename']; + patientID = json['PatientID']; + patientName = json['PatientName']; + project = json['Project']; + projectID = json['ProjectID']; + solution = json['Solution']; + status = json['Status']; + statusAr = json['StatusAr']; + statusEn = json['StatusEn']; + statusId = json['StatusId']; + } + + Map toJson() { + final Map data = new Map(); + data['Appointment'] = this.appointment; + data['AppointmentClinicName'] = this.appointmentClinicName; + data['AppointmentDate'] = this.appointmentDate; + data['AppointmentProjectName'] = this.appointmentProjectName; + data['COCID'] = this.cOCID; + data['COCTitle'] = this.cOCTitle; + data['Channel'] = this.channel; + data['Clinic'] = this.clinic; + data['ClinicID'] = this.clinicID; + data['Date'] = this.date; + data['Detail'] = this.detail; + data['Doctor'] = this.doctor; + data['DoctorID'] = this.doctorID; + data['FormType'] = this.formType; + data['FormTypeID'] = this.formTypeID; + data['IdentificationNo'] = this.identificationNo; + data['ItemID'] = this.itemID; + data['MobileNo'] = this.mobileNo; + data['Naturename'] = this.naturename; + data['PatientID'] = this.patientID; + data['PatientName'] = this.patientName; + data['Project'] = this.project; + data['ProjectID'] = this.projectID; + data['Solution'] = this.solution; + data['Status'] = this.status; + data['StatusAr'] = this.statusAr; + data['StatusEn'] = this.statusEn; + return data; + } +} diff --git a/lib/features/emergency_services/emergency_services_repo.dart b/lib/features/emergency_services/emergency_services_repo.dart index c63f0ee6..f8eb896f 100644 --- a/lib/features/emergency_services/emergency_services_repo.dart +++ b/lib/features/emergency_services/emergency_services_repo.dart @@ -183,7 +183,7 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { @override Future>>> getProjectList() async { - Map request = {}; + Map request = {'IsOnlineCheckIn': false, 'IsAdvancePayment': false, 'IsForER': true}; try { GenericApiModel>? apiResponse; diff --git a/lib/features/immediate_livecare/immediate_livecare_repo.dart b/lib/features/immediate_livecare/immediate_livecare_repo.dart index eee4adba..cbce4ea2 100644 --- a/lib/features/immediate_livecare/immediate_livecare_repo.dart +++ b/lib/features/immediate_livecare/immediate_livecare_repo.dart @@ -89,7 +89,7 @@ class ImmediateLiveCareRepoImp implements ImmediateLiveCareRepo { body: mapDevice, onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; - onError!(error); + // onError!(error); }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { @@ -142,7 +142,7 @@ class ImmediateLiveCareRepoImp implements ImmediateLiveCareRepo { body: mapDevice, onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; - onError!(error); + // onError!(error); }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { diff --git a/lib/features/immediate_livecare/immediate_livecare_view_model.dart b/lib/features/immediate_livecare/immediate_livecare_view_model.dart index ffa0b00b..46f5a652 100644 --- a/lib/features/immediate_livecare/immediate_livecare_view_model.dart +++ b/lib/features/immediate_livecare/immediate_livecare_view_model.dart @@ -1,16 +1,26 @@ import 'dart:async'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; +import 'package:get_it/get_it.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/cache_consts.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_fees_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import '../../services/navigation_service.dart'; @@ -42,6 +52,9 @@ class ImmediateLiveCareViewModel extends ChangeNotifier { late ValueNotifier durationNotifier; late Timer timer; + bool isShowNotEligibleDialog = false; + String notEligibleErrorMsg = ""; + initImmediateLiveCare() { _appState = getIt(); immediateLiveCareClinicsList = []; @@ -102,8 +115,88 @@ class ImmediateLiveCareViewModel extends ChangeNotifier { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { liveCareImmediateAppointmentFeesList = apiResponse.data!; + + if ((liveCareImmediateAppointmentFeesList.isCash!)) { + isShowNotEligibleDialog = false; + } else { + if (liveCareImmediateAppointmentFeesList.isInsured! && liveCareImmediateAppointmentFeesList.isEligible!) { + isShowNotEligibleDialog = false; + } else { + if (liveCareImmediateAppointmentFeesList.isInsured! && liveCareImmediateAppointmentFeesList.isEligible!) { + isShowNotEligibleDialog = true; + notEligibleErrorMsg = LocaleKeys.invalidEligibility.tr(context: GetIt.instance().navigatorKey.currentContext!); + } else { + isShowNotEligibleDialog = true; + notEligibleErrorMsg = LocaleKeys.invalidInsurance.tr(context: GetIt.instance().navigatorKey.currentContext!); + } + } + } + + if (isShowNotEligibleDialog) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight(GetIt.instance().navigatorKey.currentContext!, + child: Padding( + padding: EdgeInsets.only( + left: 24.w, + top: 24.h, + right: 24.w, + bottom: 12.h, + ), + child: Utils.getWarningWidget( + loadingText: notEligibleErrorMsg, + confirmText: LocaleKeys.updateInsuranceInfo.tr(context: GetIt.instance().navigatorKey.currentContext!), + cancelText: LocaleKeys.continueCash.tr(context: GetIt.instance().navigatorKey.currentContext!), + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + LoaderBottomSheet.showLoader(); + myAppointmentsViewModel.convertPatientToCash( + projectID: ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingFeesPleaseWait.tr()); + getLiveCareImmediateAppointmentFees(); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: GetIt.instance().navigatorKey.currentContext!), + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getErrorWidget(loadingText: err.toString()), + callBackFunc: () { + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }, + onConfirmTap: () async { + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + + //Call the API to attempt updating patient insurance + LoaderBottomSheet.showLoader(); + myAppointmentsViewModel.sendPatientUpdateRequest(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + getLiveCareImmediateAppointmentFees(); + }, onError: (err) { + LoaderBottomSheet.hideLoader(); + Navigator.push( + GetIt.instance().navigatorKey.currentContext!, + CustomPageRoute( + page: InsuranceHomePage(), + ), + ); + }); + }), + ), callBackFunc: () { + // Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + }, isFullScreen: false, isCloseButtonVisible: false, isDismissible: false); + } + notifyListeners(); - if (onSuccess != null) { + if (onSuccess != null && !isShowNotEligibleDialog) { onSuccess(apiResponse); } } diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index 261bda29..fa1ec5de 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -18,6 +18,7 @@ class InsuranceViewModel extends ChangeNotifier { bool isInsuranceApprovalsLoading = false; bool isInsuranceExpired = false; + bool isInsuranceActive = false; InsuranceRepo insuranceRepo; ErrorHandlerService errorHandlerService; @@ -79,6 +80,8 @@ class InsuranceViewModel extends ChangeNotifier { (failure) async { isInsuranceLoading = false; isInsuranceDataToBeLoaded = false; + isInsuranceExpired = false; + isInsuranceActive = false; notifyListeners(); }, (apiResponse) { @@ -94,6 +97,9 @@ class InsuranceViewModel extends ChangeNotifier { DateUtil.convertStringToDate(patientInsuranceList.first.cardValidTo), ); + isInsuranceActive = patientInsuranceList.first.isActive ?? false; + // isInsuranceActive = true; + notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); diff --git a/lib/features/insurance/models/resp_models/patient_insurance_approval_response_model.dart b/lib/features/insurance/models/resp_models/patient_insurance_approval_response_model.dart index f272f2dc..303b6edd 100644 --- a/lib/features/insurance/models/resp_models/patient_insurance_approval_response_model.dart +++ b/lib/features/insurance/models/resp_models/patient_insurance_approval_response_model.dart @@ -52,7 +52,7 @@ class InsuranceApprovalResponseModel { String? eApprovalRemarks; bool? isEmailSentOnDelayApproval; int? eAuthorizationID; - InsuranceApprovalDetails? apporvalDetails; + List? apporvalDetails = []; String? approvalStatusDescption; String? clinicName; String? clinicNameN; @@ -217,7 +217,9 @@ class InsuranceApprovalResponseModel { isEmailSentOnDelayApproval = json['IsEmailSentOnDelayApproval']; eAuthorizationID = json['EAuthorizationID']; if (json['ApporvalDetails'] != null && json['ApporvalDetails'].length != 0) { - apporvalDetails = InsuranceApprovalDetails.fromJson(json['ApporvalDetails'][0]); + json['ApporvalDetails'].forEach((v) { + apporvalDetails!.add(InsuranceApprovalDetails.fromJson(v)); + }); } approvalStatusDescption = json['ApprovalStatusDescption']; clinicName = json['ClinicName']; @@ -302,9 +304,9 @@ class InsuranceApprovalResponseModel { data['EApprovalRemarks'] = this.eApprovalRemarks; data['IsEmailSentOnDelayApproval'] = this.isEmailSentOnDelayApproval; data['EAuthorizationID'] = this.eAuthorizationID; - if (this.apporvalDetails != null) { - data['ApporvalDetails'] = this.apporvalDetails!.toJson; - } + // if (this.apporvalDetails != null) { + // data['ApporvalDetails'] = this.apporvalDetails!.toJson; + // } data['ApprovalStatusDescption'] = this.approvalStatusDescption; data['ClinicName'] = this.clinicName; data['ClinicNameN'] = this.clinicNameN; diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart index a4cdcf1c..285c7322 100644 --- a/lib/features/lab/lab_repo.dart +++ b/lib/features/lab/lab_repo.dart @@ -232,7 +232,7 @@ class LabRepoImp implements LabRepo { "DoctorID": labOrder.doctorID!, "OrderNo": labOrder.orderNo!, "InvoiceType": labOrder.invoiceType!, - "SetupID": labOrder.setupID!, + "SetupID": labOrder.setupID ?? "", "IsDownload": true, 'ClinicName': labOrder.clinicDescription, 'DateofBirth': Utils.appState.getAuthenticatedUser()!.dateofBirth, diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 22e48595..cd062b9e 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -17,7 +17,7 @@ import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_ import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_results/lab_result_details.dart'; -import 'package:hmg_patient_app_new/presentation/labAiAnalysis/lab_ai_analysis_detailed_page.dart'; +import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; @@ -205,14 +205,36 @@ class LabViewModel extends ChangeNotifier { } filterLabReports(String query) { + final clinicMap = >{}; + final hospitalMap = >{}; if (query.isEmpty) { - filteredLabOrders = List.from(patientLabOrders); // reset + // filteredLabOrders = List.from(patientLabOrders); // reset + for (var order in patientLabOrders) { + final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + clinicMap.putIfAbsent(clinicKey, () => []).add(order); + + final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + } + patientLabOrdersByClinic = clinicMap.values.toList(); + patientLabOrdersByHospital = hospitalMap.values.toList(); + patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; } else { filteredLabOrders = patientLabOrders.where((order) { final descriptions = order.testDetails?.map((d) => d.description?.toLowerCase()).toList() ?? []; return descriptions.any((desc) => desc != null && desc.contains(query.toLowerCase())); }).toList(); - patientLabOrders = filteredLabOrders; + // patientLabOrders = filteredLabOrders; + for (var order in filteredLabOrders) { + final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + clinicMap.putIfAbsent(clinicKey, () => []).add(order); + + final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + } + patientLabOrdersByClinic = clinicMap.values.toList(); + patientLabOrdersByHospital = hospitalMap.values.toList(); + patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; } notifyListeners(); } diff --git a/lib/features/lab/models/resp_models/lab_result.dart b/lib/features/lab/models/resp_models/lab_result.dart index 23146849..2808dce9 100644 --- a/lib/features/lab/models/resp_models/lab_result.dart +++ b/lib/features/lab/models/resp_models/lab_result.dart @@ -27,6 +27,7 @@ class LabResult { num? resultTypeID; String? packageShortDescription; int? testId; + String? testShortDescription; LabResult( {this.description, @@ -54,6 +55,7 @@ class LabResult { this.criticalLow, this.referenceLow, this.testId, + this.testShortDescription, }); LabResult.fromJson(Map json) { @@ -85,6 +87,7 @@ class LabResult { packageShortDescription = json['PackageShortDescription']; resultTypeID = json['ResultTypeID']; testId = json['TestID']; + testShortDescription = json['TestShortDescription']; } Map toJson() { @@ -114,6 +117,7 @@ class LabResult { data['CriticalLow'] = this.criticalLow; data['ReferenceLow'] = this.referenceLow; data['TestID'] = this.testId; + data['TestShortDescription'] = this.testShortDescription; return data; } diff --git a/lib/features/medical_file/medical_file_view_model.dart b/lib/features/medical_file/medical_file_view_model.dart index b26a87a1..b93bb62d 100644 --- a/lib/features/medical_file/medical_file_view_model.dart +++ b/lib/features/medical_file/medical_file_view_model.dart @@ -41,7 +41,7 @@ class MedicalFileViewModel extends ChangeNotifier { List patientSickLeavesViewList = []; bool isSickLeavesSortByClinic = true; - bool isSickLeavesDataNeedsReloading = true; + // bool isSickLeavesDataNeedsReloading = true; List patientAllergiesList = []; @@ -164,7 +164,7 @@ class MedicalFileViewModel extends ChangeNotifier { } setIsPatientSickLeaveListLoading(bool val) { - if (val && isSickLeavesDataNeedsReloading) { + // if (val && isSickLeavesDataNeedsReloading) { patientSickLeaveList.clear(); patientSickLeavesByClinic.clear(); patientSickLeavesByHospital.clear(); @@ -172,7 +172,7 @@ class MedicalFileViewModel extends ChangeNotifier { patientSickLeavePDFBase64 = ""; isSickLeavesSortByClinic = true; isPatientSickLeaveListLoading = val; - } + // } notifyListeners(); } @@ -268,11 +268,13 @@ class MedicalFileViewModel extends ChangeNotifier { } Future getPatientSickLeaveList({Function(dynamic)? onSuccess, Function(String)? onError}) async { - if (!isSickLeavesDataNeedsReloading) { - return; - } + // if (!isSickLeavesDataNeedsReloading) { + // return; + // } patientSickLeaveList.clear(); + notifyListeners(); + final result = await medicalFileRepo.getPatientSickLeavesList(); result.fold( @@ -314,7 +316,7 @@ class MedicalFileViewModel extends ChangeNotifier { } } patientSickLeavesViewList = patientSickLeavesByClinic; - isSickLeavesDataNeedsReloading = false; + // isSickLeavesDataNeedsReloading = false; notifyListeners(); if (onSuccess != null) { @@ -353,6 +355,11 @@ class MedicalFileViewModel extends ChangeNotifier { Future getPatientMedicalReportList({Function(dynamic)? onSuccess, Function(String)? onError}) async { patientMedicalReportList.clear(); + patientMedicalReportRequestedList.clear(); + patientMedicalReportReadyList.clear(); + patientMedicalReportCancelledList.clear(); + notifyListeners(); + final result = await medicalFileRepo.getPatientMedicalReportsList(); result.fold( @@ -439,11 +446,10 @@ class MedicalFileViewModel extends ChangeNotifier { ); // Clear and start fresh with current user - patientFamilyFiles.clear(); - patientFamilyFiles.add(currentUserFamilyFile); + final List newPatientFamilyFiles = [currentUserFamilyFile]; final List activeFamilyFiles = []; - final List pendingFamilyFiles = []; + final List newPendingFamilyFiles = []; for (var element in apiResponse.data!) { if (element.status == null) { @@ -484,7 +490,7 @@ class MedicalFileViewModel extends ChangeNotifier { if (isPending) { familyFile.isRequestFromMySide = true; - pendingFamilyFiles.add(familyFile); + newPendingFamilyFiles.add(familyFile); } if (isActive) { activeFamilyFiles.add(familyFile); @@ -492,13 +498,14 @@ class MedicalFileViewModel extends ChangeNotifier { } for (var activeFile in activeFamilyFiles) { - if (!patientFamilyFiles.any((e) => e.responseId == activeFile.responseId)) { - patientFamilyFiles.add(activeFile); + if (!newPatientFamilyFiles.any((e) => e.responseId == activeFile.responseId)) { + newPatientFamilyFiles.add(activeFile); } } - this.pendingFamilyFiles.clear(); - this.pendingFamilyFiles.addAll(pendingFamilyFiles); + // Assign new list instances + patientFamilyFiles = newPatientFamilyFiles; + pendingFamilyFiles = newPendingFamilyFiles; } notifyListeners(); @@ -553,7 +560,9 @@ class MedicalFileViewModel extends ChangeNotifier { } } // pendingFamilyFiles.addAll(tempPendingFamilyFiles.where((element) => !pendingFamilyFiles.any((e) => e.responseId == element.responseId))); - pendingFamilyFiles.addAll(tempPendingFamilyFiles.where((element) => !pendingFamilyFiles.any((e) => e.patientId == element.patientId))); + final existingIds = pendingFamilyFiles.map((e) => e.patientId).toSet(); + final newItems = tempPendingFamilyFiles.where((element) => !existingIds.contains(element.patientId)).toList(); + pendingFamilyFiles = [...pendingFamilyFiles, ...newItems]; } notifyListeners(); } @@ -589,7 +598,7 @@ class MedicalFileViewModel extends ChangeNotifier { onUnHandledFailure: (failure) { LoaderBottomSheet.hideLoader(); _dialogService.showErrorBottomSheet( - message: failure.message!, + message: failure.message, onOkPressed: () { navigationService.pop(); }); @@ -663,7 +672,7 @@ class MedicalFileViewModel extends ChangeNotifier { navigationService.pop(); }); } else if (apiResponse.messageStatus == 1) { - patientFamilyFiles.removeWhere((element) => element.id == id); + patientFamilyFiles = patientFamilyFiles.where((element) => element.id != id).toList(); getFamilyFiles(); getAllPendingRecordsByResponseId(); LoaderBottomSheet.hideLoader(); @@ -741,11 +750,12 @@ class MedicalFileViewModel extends ChangeNotifier { // moveProfile.status = 3; // moveProfile.statusDescription = "Approved"; // patientFamilyFiles.add(moveProfile); - pendingFamilyFiles.removeWhere((element) => element.id == id); + pendingFamilyFiles = pendingFamilyFiles.where((element) => element.id != id).toList(); //TODO: Call Api Here To Load Family Members getFamilyFiles(status: 0); getAllPendingRecordsByResponseId(); LoaderBottomSheet.hideLoader(); + notifyListeners(); // onFamilyFileTabChange(0); } }, diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index ce9e8770..567714c6 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -20,7 +20,8 @@ import 'models/req_model/appointment_rate_req_model.dart'; import 'models/resp_models/appointment_details_resp_model.dart'; abstract class MyAppointmentsRepo { - Future>>> getPatientAppointments({required bool isActiveAppointment, required bool isArrivedAppointments, bool isForEyeMeasurement = false}); + Future>>> getPatientAppointments( + {required bool isActiveAppointment, required bool isArrivedAppointments, bool isForEyeMeasurement = false}); Future>> getPatientShareAppointment( {required int projectID, required int clinicID, required String appointmentNo, required bool isLiveCareAppointment}); @@ -67,12 +68,16 @@ abstract class MyAppointmentsRepo { Future>> getAppointmentDetails(int appointmentID, int projectID); - Future>> sendAppointmentRate(int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note); - Future>> sendDoctorRate(int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note, String appoDate, String docName, String projectName, String clinicName); + Future>> sendDoctorRate( + int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note, String appoDate, String docName, String projectName, String clinicName); Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID}); + + Future>> convertPatientToCash({required int projectID}); + + Future>> sendPatientUpdateRequest(); } class MyAppointmentsRepoImp implements MyAppointmentsRepo { @@ -192,9 +197,7 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { "AppointmentNo": appointmentNo, "PaymentMethodName": paymentMethodName, "PaymentAmount": payedAmount == 0 ? "0" : payedAmount.toString(), - "PaymentDate": payedAmount == 0 ? "" : "/Date(${DateTime - .now() - .millisecondsSinceEpoch})/", + "PaymentDate": payedAmount == 0 ? "" : "/Date(${DateTime.now().millisecondsSinceEpoch})/", "PaymentReferenceNumber": payedAmount == 0 ? "" : paymentReference, "ProjectID": projectID, "PatientID": patientID, @@ -863,10 +866,8 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { } } - @override - Future>> sendAppointmentRate(int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note) async { - + Future>> sendAppointmentRate(int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note) async { AppointmentRate appointmentRate = AppointmentRate(); appointmentRate.rate = rate; appointmentRate.appointmentNo = appointmentNo; @@ -877,7 +878,6 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { appointmentRate.createdBy = 2; appointmentRate.editedBy = 2; - try { GenericApiModel? apiResponse; Failure? failure; @@ -906,7 +906,8 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { } @override - Future>> sendDoctorRate(int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note, String appoDate, String docName, String projectName, String clinicName) async { + Future>> sendDoctorRate( + int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note, String appoDate, String docName, String projectName, String clinicName) async { Map request; request = { @@ -957,4 +958,67 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { } } -} \ No newline at end of file + @override + Future> convertPatientToCash({required int projectID}) async { + Map request; + + request = {"ProjectID": projectID}; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post(CONVERT_PATIENT_TO_CASH, onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = (response['MessageStatus'] == 1); + + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: list, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, body: request); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future> sendPatientUpdateRequest() async { + Map request = {}; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post(SEND_PATIENT_IMMEDIATE_UPDATE_INSURANCE_REQUEST, onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = (response['MessageStatus'] == 1); + + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: list, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, body: request); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } +} diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index ce2b7b91..f8876803 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -1,6 +1,9 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart'; @@ -10,7 +13,13 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; class MyAppointmentsViewModel extends ChangeNotifier { int selectedTabIndex = 0; @@ -45,9 +54,6 @@ class MyAppointmentsViewModel extends ChangeNotifier { List patientQueueDetailsList = []; late PatientQueueDetails currentPatientQueueDetails; - - - List patientAppointmentsHistoryList = []; List filteredAppointmentList = []; @@ -73,6 +79,9 @@ class MyAppointmentsViewModel extends ChangeNotifier { GetTamaraInstallmentsDetailsResponseModel? getTamaraInstallmentsDetailsResponseModel; bool isTamaraDetailsLoading = false; + bool isShowNotEligibleDialog = false; + String notEligibleErrorMsg = ""; + MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState}); void onTabChange(int index) { @@ -141,6 +150,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { isTamaraDetailsLoading = true; isAppointmentPatientShareLoading = true; isEyeMeasurementsAppointmentsLoading = true; + isShowNotEligibleDialog = false; notifyListeners(); } @@ -331,10 +341,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { notifyListeners(); } - Future getPatientShareAppointment(int projectID, int clinicID, String appointmentNo, bool isLiveCareAppointment, - {Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await myAppointmentsRepo.getPatientShareAppointment( - projectID: projectID, clinicID: clinicID, appointmentNo: appointmentNo, isLiveCareAppointment: isLiveCareAppointment); + Future getPatientShareAppointment(int projectID, int clinicID, String appointmentNo, bool isLiveCareAppointment, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.getPatientShareAppointment(projectID: projectID, clinicID: clinicID, appointmentNo: appointmentNo, isLiveCareAppointment: isLiveCareAppointment); result.fold( (failure) async { @@ -349,7 +357,130 @@ class MyAppointmentsViewModel extends ChangeNotifier { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { patientAppointmentShareResponseModel = apiResponse.data!; + + if ((patientAppointmentShareResponseModel!.isCash!)) { + isShowNotEligibleDialog = false; + } else { + if (patientAppointmentShareResponseModel!.isInsured! && patientAppointmentShareResponseModel!.isEligible!) { + isShowNotEligibleDialog = false; + } else { + if (patientAppointmentShareResponseModel!.isInsured! && patientAppointmentShareResponseModel!.isEligible!) { + isShowNotEligibleDialog = true; + notEligibleErrorMsg = LocaleKeys.invalidEligibility.tr(context: GetIt.instance().navigatorKey.currentContext!); + } else { + isShowNotEligibleDialog = true; + notEligibleErrorMsg = LocaleKeys.invalidInsurance.tr(context: GetIt.instance().navigatorKey.currentContext!); + } + } + } isAppointmentPatientShareLoading = false; + + if (isShowNotEligibleDialog) { + showCommonBottomSheetWithoutHeight(GetIt.instance().navigatorKey.currentContext!, + child: Padding( + padding: EdgeInsets.only( + left: 24.w, + top: 24.h, + right: 24.w, + bottom: 12.h, + ), + child: Utils.getWarningWidget( + loadingText: notEligibleErrorMsg, + confirmText: LocaleKeys.updateInsuranceInfo.tr(context: GetIt.instance().navigatorKey.currentContext!), + cancelText: LocaleKeys.continueCash.tr(context: GetIt.instance().navigatorKey.currentContext!), + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + LoaderBottomSheet.showLoader(); + convertPatientToCash( + projectID: projectID, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + setIsPatientAppointmentShareLoading(true); + getPatientShareAppointment(projectID, clinicID, appointmentNo, isLiveCareAppointment); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: GetIt.instance().navigatorKey.currentContext!), + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getErrorWidget(loadingText: err.toString()), + callBackFunc: () { + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }, + onConfirmTap: () async { + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + + //Call the API to attempt updating patient insurance + LoaderBottomSheet.showLoader(); + sendPatientUpdateRequest(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + setIsPatientAppointmentShareLoading(true); + getPatientShareAppointment(projectID, clinicID, appointmentNo, isLiveCareAppointment); + }, onError: (err) { + LoaderBottomSheet.hideLoader(); + Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + Navigator.push( + GetIt.instance().navigatorKey.currentContext!, + CustomPageRoute( + page: InsuranceHomePage(), + ), + ); + }); + }), + ), callBackFunc: () { + // Navigator.pop(GetIt.instance().navigatorKey.currentContext!); + }, isFullScreen: false, isCloseButtonVisible: false, isDismissible: false); + } + + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } + + Future sendPatientUpdateRequest({Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.sendPatientUpdateRequest(); + + result.fold( + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + onError!(failure.message); + }, + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } + + Future convertPatientToCash({required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.convertPatientToCash(projectID: projectID); + + result.fold( + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + onError!(failure.message); + }, + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); @@ -360,13 +491,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future addAdvanceNumberRequest( - {required String advanceNumber, - required String paymentReference, - required String appointmentNo, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = - await myAppointmentsRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo); + {required String advanceNumber, required String paymentReference, required String appointmentNo, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), @@ -384,14 +510,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future generateAppointmentQR( - {required int clinicID, - required int projectID, - required String appointmentNo, - required int isFollowUp, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = - await myAppointmentsRepo.generateAppointmentQR(clinicID: clinicID, projectID: projectID, appointmentNo: appointmentNo, isFollowUp: isFollowUp); + {required int clinicID, required int projectID, required String appointmentNo, required int isFollowUp, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.generateAppointmentQR(clinicID: clinicID, projectID: projectID, appointmentNo: appointmentNo, isFollowUp: isFollowUp); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), @@ -408,12 +528,16 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } - Future cancelAppointment( - {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { + Future cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { final result = await myAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + if (onError != null) { + onError(failure.message); + } + }, (apiResponse) { if (apiResponse.messageStatus == 2) { onError!(apiResponse.errorMessage!); @@ -428,8 +552,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } - Future confirmAppointment( - {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { + Future confirmAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { final result = await myAppointmentsRepo.confirmAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); result.fold( @@ -490,8 +613,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { required int checkInType, Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await myAppointmentsRepo.sendCheckInNfcRequest( - patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, scannedCode: scannedCode, checkInType: checkInType); + final result = await myAppointmentsRepo.sendCheckInNfcRequest(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, scannedCode: scannedCode, checkInType: checkInType); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), @@ -537,12 +659,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future insertLiveCareVIDARequest( - {required clientRequestID, - required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = await myAppointmentsRepo.insertLiveCareVIDARequest( - clientRequestID: clientRequestID, patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); + {required clientRequestID, required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.insertLiveCareVIDARequest(clientRequestID: clientRequestID, patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), @@ -818,5 +936,4 @@ class MyAppointmentsViewModel extends ChangeNotifier { }, ); } - } diff --git a/lib/features/my_invoices/models/get_invoices_list_response_model.dart b/lib/features/my_invoices/models/get_invoices_list_response_model.dart index e8056d91..fe59c045 100644 --- a/lib/features/my_invoices/models/get_invoices_list_response_model.dart +++ b/lib/features/my_invoices/models/get_invoices_list_response_model.dart @@ -13,10 +13,10 @@ class GetInvoicesListResponseModel { String? doctorName; String? doctorNameN; String? clinicName; - double? decimalDoctorRate; + num? decimalDoctorRate; String? doctorImageURL; - int? doctorRate; - int? patientNumber; + num? doctorRate; + num? patientNumber; String? projectName; GetInvoicesListResponseModel( diff --git a/lib/features/prescriptions/prescriptions_repo.dart b/lib/features/prescriptions/prescriptions_repo.dart index dcc9de92..3bfcc7fe 100644 --- a/lib/features/prescriptions/prescriptions_repo.dart +++ b/lib/features/prescriptions/prescriptions_repo.dart @@ -188,7 +188,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo { Map mapDevice = { "AppointmentNo": prescriptionsResponseModel.appointmentNo, "SetupID": prescriptionsResponseModel.setupID, - "EpisodeID": prescriptionsResponseModel.episodeID, + "EpisodeNo": prescriptionsResponseModel.episodeID, "ClinicID": prescriptionsResponseModel.clinicID, "ProjectID": prescriptionsResponseModel.projectID, "DischargeNo": prescriptionsResponseModel.dischargeNo, diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart index 319e5fc1..c0f9c7b5 100644 --- a/lib/features/prescriptions/prescriptions_view_model.dart +++ b/lib/features/prescriptions/prescriptions_view_model.dart @@ -153,7 +153,10 @@ class PrescriptionsViewModel extends ChangeNotifier { final result = await prescriptionsRepo.getPatientPrescriptionDetails(prescriptionsResponseModel: prescriptionsResponseModel); result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + onError!(failure.message); + }, (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart index 2af3e0fa..5847718d 100644 --- a/lib/features/radiology/radiology_repo.dart +++ b/lib/features/radiology/radiology_repo.dart @@ -121,7 +121,7 @@ class RadiologyRepoImp implements RadiologyRepo { Map mapDevice = { "InvoiceNo": Utils.isVidaPlusProject(patientRadiologyResponseModel.projectID!) ? 0 : patientRadiologyResponseModel.invoiceNo, "InvoiceNo_VP": Utils.isVidaPlusProject(patientRadiologyResponseModel.projectID!) ? patientRadiologyResponseModel.invoiceNo : 0, - "LineItemNo": patientRadiologyResponseModel.invoiceLineItemNo, + // "LineItemNo": patientRadiologyResponseModel.invoiceLineItemNo, "InvoiceLineItemNo": patientRadiologyResponseModel.invoiceLineItemNo, "ProjectID": patientRadiologyResponseModel.projectID!, "InvoiceType": patientRadiologyResponseModel.invoiceType!, diff --git a/lib/features/radiology/radiology_view_model.dart b/lib/features/radiology/radiology_view_model.dart index c8150c12..ee5c970f 100644 --- a/lib/features/radiology/radiology_view_model.dart +++ b/lib/features/radiology/radiology_view_model.dart @@ -67,6 +67,19 @@ class RadiologyViewModel extends ChangeNotifier { patientRadiologyOrders = apiResponse.data!; filteredRadiologyOrders = List.from(patientRadiologyOrders); tempRadiologyOrders = [...patientRadiologyOrders]; + + final clinicMap = >{}; + final hospitalMap = >{}; + for (var order in patientRadiologyOrders) { + final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + clinicMap.putIfAbsent(clinicKey, () => []).add(order); + final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + } + patientRadiologyOrdersByClinic = clinicMap.values.toList(); + patientRadiologyOrdersByHospital = hospitalMap.values.toList(); + patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; + isRadiologyOrdersLoading = false; filterSuggestions(); notifyListeners(); @@ -168,9 +181,31 @@ class RadiologyViewModel extends ChangeNotifier { filterRadiologyReports(String query) { if (query.isEmpty) { patientRadiologyOrders = tempRadiologyOrders; // reset + final clinicMap = >{}; + final hospitalMap = >{}; + for (var order in patientRadiologyOrders) { + final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + clinicMap.putIfAbsent(clinicKey, () => []).add(order); + final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + } + patientRadiologyOrdersByClinic = clinicMap.values.toList(); + patientRadiologyOrdersByHospital = hospitalMap.values.toList(); + patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; } else { - filteredRadiologyOrders = filteredRadiologyOrders.where((desc) => desc.description!.toLowerCase().contains(query.toLowerCase())).toList(); - patientRadiologyOrders = filteredRadiologyOrders; + filteredRadiologyOrders = filteredRadiologyOrders.where((desc) => (desc.description ?? "").toLowerCase().contains(query.toLowerCase())).toList(); + + final clinicMap = >{}; + final hospitalMap = >{}; + for (var order in filteredRadiologyOrders) { + final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + clinicMap.putIfAbsent(clinicKey, () => []).add(order); + final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + } + patientRadiologyOrdersByClinic = clinicMap.values.toList(); + patientRadiologyOrdersByHospital = hospitalMap.values.toList(); + patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; } notifyListeners(); } diff --git a/lib/features/symptoms_checker/data/organ_mapping_data.dart b/lib/features/symptoms_checker/data/organ_mapping_data.dart index c338a94e..b0c2ffea 100644 --- a/lib/features/symptoms_checker/data/organ_mapping_data.dart +++ b/lib/features/symptoms_checker/data/organ_mapping_data.dart @@ -1,9 +1,11 @@ +import 'dart:developer'; + import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart'; class OrganData { // ==================== FRONT VIEW ==================== - static const List frontViewOrgans = [ + static const List frontViewOrgansForMale = [ // ========== HEAD & FACE ========== OrganModel( id: 'head', @@ -307,9 +309,313 @@ class OrganData { position: OrganPosition(x: 0.57, y: 0.91), ), ]; + static const List frontViewOrgansForFemale = [ + // ========== HEAD & FACE ========== + OrganModel( + id: 'head', + name: 'whole_head', + nameAr: 'الرأس_كامل', + description: 'Head', + descriptionAr: 'الرأس', + bodyView: BodyView.front, + position: OrganPosition(x: 0.54, y: 0.05), + ), + OrganModel( + id: 'left_eye', + name: 'eyes', + nameAr: 'العيون', + description: 'Left Eye', + descriptionAr: 'العين اليسرى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.49, y: 0.095), + ), + OrganModel( + id: 'right_eye', + name: 'eyes', + nameAr: 'العيون', + description: 'Right Eye', + descriptionAr: 'العين اليمنى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.6, y: 0.095), + ), + OrganModel( + id: 'nose_mouth', + name: 'oral_cavity', + nameAr: 'تجويف_الفم', + description: 'Nose/Mouth', + descriptionAr: 'الأنف/الفم', + bodyView: BodyView.front, + position: OrganPosition(x: 0.54, y: 0.12), + ), + + // ========== NECK ========== + OrganModel( + id: 'throat', + name: 'neck_or_throat', + nameAr: 'الرقبة_أو_الحلق', + description: 'Throat', + descriptionAr: 'الحلق', + bodyView: BodyView.front, + position: OrganPosition(x: 0.54, y: 0.17), + ), + + // ========== SHOULDERS ========== + OrganModel( + id: 'left_shoulder', + name: 'upper_arm', + nameAr: 'الذراع_العلوي', + description: 'Left Shoulder', + descriptionAr: 'الكتف الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.29, y: 0.22), + ), + OrganModel( + id: 'right_shoulder', + name: 'upper_arm', + nameAr: 'الذراع_العلوي', + description: 'Right Shoulder', + descriptionAr: 'الكتف الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.75, y: 0.22), + ), + + // ========== CHEST ========== + OrganModel( + id: 'left_chest', + name: 'chest', + nameAr: 'الصدر', + description: 'Left Chest', + descriptionAr: 'الصدر الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.4, y: 0.22), + ), + OrganModel( + id: 'center_chest', + name: 'chest', + nameAr: 'الصدر', + description: 'Center Chest', + descriptionAr: 'وسط الصدر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.52, y: 0.25), + ), + OrganModel( + id: 'right_chest', + name: 'chest', + nameAr: 'الصدر', + description: 'Right Chest', + descriptionAr: 'الصدر الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.65, y: 0.22), + ), + + // ========== RIBS ========== + OrganModel( + id: 'left_ribs', + name: 'chest', + nameAr: 'الصدر', + description: 'Left Ribs', + descriptionAr: 'الأضلاع اليسرى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.38, y: 0.35), + ), + OrganModel( + id: 'right_ribs', + name: 'chest', + nameAr: 'الصدر', + description: 'Right Ribs', + descriptionAr: 'الأضلاع اليمنى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.64, y: 0.35), + ), + + // ========== ABDOMEN ========== + OrganModel( + id: 'upper_abdomen', + name: 'upper_abdomen', + nameAr: 'البطن_العلوي', + description: 'Upper Abdomen', + descriptionAr: 'أعلى البطن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.51, y: 0.31), + ), + OrganModel( + id: 'navel', + name: 'mid_abdomen', + nameAr: 'البطن_الأوسط', + description: 'Navel', + descriptionAr: 'السرة', + bodyView: BodyView.front, + position: OrganPosition(x: 0.51, y: 0.38), + ), + OrganModel( + id: 'lower_abdomen', + name: 'lower_abdomen', + nameAr: 'البطن_السفلي', + description: 'Lower Abdomen', + descriptionAr: 'أسفل البطن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.51, y: 0.44), + ), + + // ========== PELVIS ========== + OrganModel( + id: 'left_groin', + name: 'sexual_organs', + nameAr: 'الأعضاء_التناسلية', + description: 'Left Groin', + descriptionAr: 'الفخذ الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.42, y: 0.49), + ), + OrganModel( + id: 'right_groin', + name: 'sexual_organs', + nameAr: 'الأعضاء_التناسلية', + description: 'Right Groin', + descriptionAr: 'الفخذ الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.59, y: 0.49), + ), + + // ========== LEFT ARM ========== + + OrganModel( + id: 'left_elbow', + name: 'elbow', + nameAr: 'الكوع', + description: 'Left Elbow', + descriptionAr: 'الكوع الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.24, y: 0.35), + ), + OrganModel( + id: 'left_forearm', + name: 'forearm', + nameAr: 'الساعد', + description: 'Left Forearm', + descriptionAr: 'الساعد الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.24, y: 0.43), + ), + OrganModel( + id: 'left_wrist', + name: 'hand', + nameAr: 'اليد', + description: 'Left Wrist', + descriptionAr: 'المعصم الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.17, y: 0.49), + ), + + // ========== RIGHT ARM ========== + + OrganModel( + id: 'right_elbow', + name: 'elbow', + nameAr: 'الكوع', + description: 'Right Elbow', + descriptionAr: 'الكوع الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.76, y: 0.35), + ), + OrganModel( + id: 'right_forearm', + name: 'forearm', + nameAr: 'الساعد', + description: 'Right Forearm', + descriptionAr: 'الساعد الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.76, y: 0.43), + ), + OrganModel( + id: 'right_wrist', + name: 'hand', + nameAr: 'اليد', + description: 'Right Wrist', + descriptionAr: 'المعصم الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.83, y: 0.5), + ), + + // ========== LEFT LEG ========== + OrganModel( + id: 'left_thigh', + name: 'thigh', + nameAr: 'الفخذ', + description: 'Left Thigh', + descriptionAr: 'الفخذ الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.4, y: 0.60), + ), + OrganModel( + id: 'left_knee', + name: 'knee', + nameAr: 'الركبة', + description: 'Left Knee', + descriptionAr: 'الركبة اليسرى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.4, y: 0.72), + ), + OrganModel( + id: 'left_shin', + name: 'lower_leg', + nameAr: 'الساق_السفلي', + description: 'Left Shin', + descriptionAr: 'الساق اليسرى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.41, y: 0.82), + ), + OrganModel( + id: 'left_ankle', + name: 'foot', + nameAr: 'القدم', + description: 'Left Ankle', + descriptionAr: 'الكاحل الأيسر', + bodyView: BodyView.front, + position: OrganPosition(x: 0.43, y: 0.91), + ), + + // ========== RIGHT LEG ========== + OrganModel( + id: 'right_thigh', + name: 'thigh', + nameAr: 'الفخذ', + description: 'Right Thigh', + descriptionAr: 'الفخذ الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.65, y: 0.60), + ), + OrganModel( + id: 'right_knee', + name: 'knee', + nameAr: 'الركبة', + description: 'Right Knee', + descriptionAr: 'الركبة اليمنى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.6, y: 0.72), + ), + OrganModel( + id: 'right_shin', + name: 'lower_leg', + nameAr: 'الساق_السفلي', + description: 'Right Shin', + descriptionAr: 'الساق اليمنى', + bodyView: BodyView.front, + position: OrganPosition(x: 0.59, y: 0.82), + ), + OrganModel( + id: 'right_ankle', + name: 'foot', + nameAr: 'القدم', + description: 'Right Ankle', + descriptionAr: 'الكاحل الأيمن', + bodyView: BodyView.front, + position: OrganPosition(x: 0.57, y: 0.91), + ), + ]; // ==================== BACK VIEW ==================== - static const List backViewOrgans = [ + static const List backViewOrgansForMale = [ // ========== HEAD & NECK ========== OrganModel( id: 'back_of_head', @@ -504,19 +810,232 @@ class OrganData { position: OrganPosition(x: 0.57, y: 0.79), ), ]; + static const List backViewOrgansForFemale = [ + // ========== HEAD & NECK ========== + OrganModel( + id: 'back_of_head', + name: 'whole_head', + nameAr: 'الرأس_كامل', + description: 'Back of Head', + descriptionAr: 'مؤخرة الرأس', + bodyView: BodyView.back, + position: OrganPosition(x: 0.48, y: 0.055), + ), + OrganModel( + id: 'neck_back', + name: 'nape_of_neck', + nameAr: 'مؤخرة_الرقبة', + description: 'Neck', + descriptionAr: 'الرقبة', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.14), + ), + + // ========== SHOULDERS ========== + OrganModel( + id: 'left_shoulder_back', + name: 'upper_arm', + nameAr: 'الذراع_العلوي', + description: 'Left Shoulder', + descriptionAr: 'الكتف الأيسر', + bodyView: BodyView.back, + position: OrganPosition(x: 0.3, y: 0.2), + ), + OrganModel( + id: 'right_shoulder_back', + name: 'upper_arm', + nameAr: 'الذراع_العلوي', + description: 'Right Shoulder', + descriptionAr: 'الكتف الأيمن', + bodyView: BodyView.back, + position: OrganPosition(x: 0.69, y: 0.2), + ), + + // ========== UPPER BACK ========== + OrganModel( + id: 'upper_spine', + name: 'back', + nameAr: 'الظهر', + description: 'Upper Spine', + descriptionAr: 'العمود الفقري العلوي', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.23), + ), + OrganModel( + id: 'left_upper_back', + name: 'back', + nameAr: 'الظهر', + description: 'Left Upper Back', + descriptionAr: 'أعلى الظهر الأيسر', + bodyView: BodyView.back, + position: OrganPosition(x: 0.38, y: 0.28), + ), + OrganModel( + id: 'right_upper_back', + name: 'back', + nameAr: 'الظهر', + description: 'Right Upper Back', + descriptionAr: 'أعلى الظهر الأيمن', + bodyView: BodyView.back, + position: OrganPosition(x: 0.62, y: 0.28), + ), + + // ========== MID BACK ========== + OrganModel( + id: 'mid_spine', + name: 'back', + nameAr: 'الظهر', + description: 'Mid Spine', + descriptionAr: 'العمود الفقري الأوسط', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.35), + ), + OrganModel( + id: 'left_mid_back', + name: 'back', + nameAr: 'الظهر', + description: 'Left Mid Back', + descriptionAr: 'وسط الظهر الأيسر', + bodyView: BodyView.back, + position: OrganPosition(x: 0.38, y: 0.35), + ), + OrganModel( + id: 'right_mid_back', + name: 'back', + nameAr: 'الظهر', + description: 'Right Mid Back', + descriptionAr: 'وسط الظهر الأيمن', + bodyView: BodyView.back, + position: OrganPosition(x: 0.62, y: 0.35), + ), + + // ========== LOWER BACK ========== + OrganModel( + id: 'lower_spine', + name: 'lower_back', + nameAr: 'أسفل_الظهر', + description: 'Lower Back', + descriptionAr: 'أسفل الظهر', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.43), + ), + OrganModel( + id: 'left_lower_back', + name: 'lower_back', + nameAr: 'أسفل_الظهر', + description: 'Left Lower Back', + descriptionAr: 'أسفل الظهر الأيسر', + bodyView: BodyView.back, + position: OrganPosition(x: 0.36, y: 0.43), + ), + OrganModel( + id: 'right_lower_back', + name: 'lower_back', + nameAr: 'أسفل_الظهر', + description: 'Right Lower Back', + descriptionAr: 'أسفل الظهر الأيمن', + bodyView: BodyView.back, + position: OrganPosition(x: 0.65, y: 0.43), + ), + + // ========== GLUTES ========== + OrganModel( + id: 'sacrum', + name: 'lower_back', + nameAr: 'أسفل_الظهر', + description: 'Sacrum', + descriptionAr: 'العجز', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.5), + ), + OrganModel( + id: 'left_glute', + name: 'buttocks', + nameAr: 'الأرداف', + description: 'Left Glute', + descriptionAr: 'الأرداف اليسرى', + bodyView: BodyView.back, + position: OrganPosition(x: 0.36, y: 0.52), + ), + OrganModel( + id: 'right_glute', + name: 'buttocks', + nameAr: 'الأرداف', + description: 'Right Glute', + descriptionAr: 'الأرداف اليمنى', + bodyView: BodyView.back, + position: OrganPosition(x: 0.61, y: 0.52), + ), + + // ========== LEGS ========== + OrganModel( + id: 'left_hamstring', + name: 'thigh', + nameAr: 'الفخذ', + description: 'Left Hamstring', + descriptionAr: 'عضلة الفخذ الخلفية اليسرى', + bodyView: BodyView.back, + position: OrganPosition(x: 0.41, y: 0.62), + ), + OrganModel( + id: 'right_hamstring', + name: 'thigh', + nameAr: 'الفخذ', + description: 'Right Hamstring', + descriptionAr: 'عضلة الفخذ الخلفية اليمنى', + bodyView: BodyView.back, + position: OrganPosition(x: 0.62, y: 0.62), + ), + OrganModel( + id: 'left_calf', + name: 'lower_leg', + nameAr: 'الساق_السفلي', + description: 'Left Calf', + descriptionAr: 'ربلة الساق اليسرى', + bodyView: BodyView.back, + position: OrganPosition(x: 0.43, y: 0.79), + ), + OrganModel( + id: 'right_calf', + name: 'lower_leg', + nameAr: 'الساق_السفلي', + description: 'Right Calf', + descriptionAr: 'ربلة الساق اليمنى', + bodyView: BodyView.back, + position: OrganPosition(x: 0.57, y: 0.79), + ), + ]; // Helper methods - static List getOrgansForView(BodyView view) { - return view == BodyView.front ? frontViewOrgans : backViewOrgans; + // Accept genderKey (e.g., 'male' / 'female' or Arabic 'ذكر' / 'أنثى') to return gender-specific organ sets + static List getOrgansForView(BodyView view, {String? genderKey}) { + final bool isFemale = genderKey != null && (genderKey.toLowerCase() == 'female' || genderKey == 'أنثى' || genderKey == '2'); + + + if (view == BodyView.front) { + return isFemale ? frontViewOrgansForFemale : frontViewOrgansForMale; + } else { + return isFemale ? backViewOrgansForFemale : backViewOrgansForMale; + } } - static List getAllOrgans() { - return [...frontViewOrgans, ...backViewOrgans]; + /// Return all organs (front + back) for the selected gender. + /// If genderKey is null, default to male to preserve previous behavior. + static List getAllOrgans({String? genderKey}) { + final bool isFemale = genderKey != null && (genderKey.toLowerCase() == 'female' || genderKey == 'أنثى' || genderKey == '2'); + + if (isFemale) { + return [...frontViewOrgansForFemale, ...backViewOrgansForFemale]; + } + + // default: male + return [...frontViewOrgansForMale, ...backViewOrgansForMale]; } - static OrganModel? getOrganById(String id) { + /// Find organ by id within the organs of the selected gender (or male if not specified) + static OrganModel? getOrganById(String id, {String? genderKey}) { try { - return getAllOrgans().firstWhere((organ) => organ.id == id); + return getAllOrgans(genderKey: genderKey).firstWhere((organ) => organ.id == id); } catch (e) { return null; } diff --git a/lib/features/symptoms_checker/models/resp_models/get_clinic_details_response_model.dart b/lib/features/symptoms_checker/models/resp_models/get_clinic_details_response_model.dart new file mode 100644 index 00000000..2d878c13 --- /dev/null +++ b/lib/features/symptoms_checker/models/resp_models/get_clinic_details_response_model.dart @@ -0,0 +1,25 @@ +class GetClinicDetailsResponseModel { + String? category; + int? clinicID; + bool? isActive; + String? categoryAR; + + GetClinicDetailsResponseModel( + {this.category, this.clinicID, this.isActive, this.categoryAR}); + + GetClinicDetailsResponseModel.fromJson(Map json) { + category = json['Category']; + clinicID = json['ClinicID']; + isActive = json['IsActive']; + categoryAR = json['CategoryAR']; + } + + Map toJson() { + final Map data = new Map(); + data['Category'] = this.category; + data['ClinicID'] = this.clinicID; + data['IsActive'] = this.isActive; + data['CategoryAR'] = this.categoryAR; + return data; + } +} diff --git a/lib/features/symptoms_checker/symptoms_checker_repo.dart b/lib/features/symptoms_checker/symptoms_checker_repo.dart index c0214e18..33bcbd8f 100644 --- a/lib/features/symptoms_checker/symptoms_checker_repo.dart +++ b/lib/features/symptoms_checker/symptoms_checker_repo.dart @@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/get_clinic_details_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/symptoms_user_details_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart'; @@ -50,6 +51,11 @@ abstract class SymptomsCheckerRepo { required String userSessionToken, required String sessionId, }); + + Future>>> getClinicDetails({ + required String categoryName, + required String userSessionToken, + }); } class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { @@ -390,4 +396,57 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getClinicDetails({ + required String categoryName, + required String userSessionToken, + }) async { + Map headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userSessionToken', + }; + Map body = {}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + + await apiClient.get( + "${ApiConsts.getClinicFromCondition}$categoryName", + apiHeaders: headers, + isExternal: true, + isAllowAny: true, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType ?? ServerFailure(error); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + final clinicDetails; + try { + final list = response['dataDetails']; + clinicDetails = list.map((item) => GetClinicDetailsResponseModel.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus ?? 1, + statusCode: statusCode, + errorMessage: errorMessage, + data: clinicDetails, + ); + } catch (e, stackTrace) { + loggerService.logError("Error parsing GetClinicsByCondition response: $e"); + loggerService.logError("StackTrace: $stackTrace"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e, stackTrace) { + loggerService.logError("Exception in GetClinicsByCondition: $e"); + loggerService.logError("StackTrace: $stackTrace"); + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/features/symptoms_checker/symptoms_checker_view_model.dart b/lib/features/symptoms_checker/symptoms_checker_view_model.dart index 668b302e..215b6921 100644 --- a/lib/features/symptoms_checker/symptoms_checker_view_model.dart +++ b/lib/features/symptoms_checker/symptoms_checker_view_model.dart @@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/data/organ_mapping_data.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/get_clinic_details_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/symptoms_user_details_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart'; @@ -154,6 +155,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Get the number of triage questions answered int get triageQuestionCount => _triageQuestionCount; + List clinicDetailsList = []; + /// Get choice index for a specific item int? getTriageChoiceForItem(String itemId) { return _selectedTriageChoicesByItemId[itemId]; @@ -175,14 +178,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } /// Get organs for current view - List get currentOrgans => OrganData.getOrgansForView(_currentView); + List get currentOrgans => OrganData.getOrgansForView(_currentView, genderKey: _selectedGender); - /// Get all selected organs from both views + /// Get all selected organs from both views (for the selected gender) List get selectedOrgans { - final allOrgans = [ - ...OrganData.frontViewOrgans, - ...OrganData.backViewOrgans, - ]; + final allOrgans = OrganData.getAllOrgans(genderKey: _selectedGender); return allOrgans.where((organ) => _selectedOrganIds.contains(organ.id)).toList(); } @@ -1069,6 +1069,43 @@ class SymptomsCheckerViewModel extends ChangeNotifier { ); } + Future getClinicConditionsFromCategory({ + required String categoryName, + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + clinicDetailsList.clear(); + notifyListeners(); + + final result = await symptomsCheckerRepo.getClinicDetails( + categoryName: categoryName, + userSessionToken: currentSessionAuthToken, + ); + + result.fold( + (failure) async { + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + if (apiResponse.messageStatus == 1 && apiResponse.data != null) { + clinicDetailsList = apiResponse.data!; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse.data!); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Failed to fetch clinic details'); + } + } + }, + ); + } + @override void dispose() { _tooltipTimer?.cancel(); diff --git a/lib/features/todo_section/todo_section_repo.dart b/lib/features/todo_section/todo_section_repo.dart index 76a44382..6d58d801 100644 --- a/lib/features/todo_section/todo_section_repo.dart +++ b/lib/features/todo_section/todo_section_repo.dart @@ -96,6 +96,8 @@ class TodoSectionRepoImp implements TodoSectionRepo { } } + ancillaryOrders.sort((a, b) => b.orderDate!.compareTo(a.orderDate!)); + apiResponse = GenericApiModel>( messageStatus: messageStatus, statusCode: statusCode, diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart index d1c53a02..9658edbe 100644 --- a/lib/firebase_options.dart +++ b/lib/firebase_options.dart @@ -45,21 +45,19 @@ class DefaultFirebaseOptions { appId: '1:815750722565:android:62281cd3e5df4063', messagingSenderId: '815750722565', projectId: 'api-project-815750722565', - // databaseURL: - // 'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app', - storageBucket: 'api-project-815750722565.appspot.com', + databaseURL: 'https://api-project-815750722565.firebaseio.com', + storageBucket: 'api-project-815750722565.firebasestorage.app', ); static const FirebaseOptions ios = FirebaseOptions( apiKey: 'AIzaSyDiXnCO00li4V7Ioa2YZ_M4ECxRsu_P9tA', - appId: '1:815750722565:ios:328ec247a81a2ca23c186c', + appId: '1:815750722565:ios:34ec03c09e02e21f3c186c', messagingSenderId: '815750722565', projectId: 'api-project-815750722565', - storageBucket: 'api-project-815750722565.appspot.com', - androidClientId: - '815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com', - iosClientId: - '815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com', - iosBundleId: 'com.HMG.HMG-Smartphone', + databaseURL: 'https://api-project-815750722565.firebaseio.com', + storageBucket: 'api-project-815750722565.firebasestorage.app', + androidClientId: '815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com', + iosBundleId: 'com.cloudsolutions.HMGPatientApp', ); -} + +} \ No newline at end of file diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 7bafadf2..78d7f8a3 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -941,6 +941,7 @@ abstract class LocaleKeys { static const offline = 'offline'; static const videoCall = 'videoCall'; static const liveVideoCallWithHMGDoctors = 'liveVideoCallWithHMGDoctors'; + static const liveAudioCallWithHMGDoctors = 'liveAudioCallWithHMGDoctors'; static const audioCall = 'audioCall'; static const phoneCall = 'phoneCall'; static const livePhoneCallWithHMGDoctors = 'livePhoneCallWithHMGDoctors'; @@ -1563,5 +1564,16 @@ abstract class LocaleKeys { static const noThanksIKnowTheClinic = 'noThanksIKnowTheClinic'; static const unableToSendOTP = 'unableToSendOTP'; static const loadingAIAnalysis = 'loadingAIAnalysis'; + static const symptoms = 'symptoms'; + static const insuranceInActive = 'insuranceInActive'; + static const insuranceInActiveContactSupport = 'insuranceInActiveContactSupport'; + static const updateAppNow = 'updateAppNow'; + static const Dr = 'Dr'; + static const reschedulingAppo = 'reschedulingAppo'; + static const invalidEligibility = 'invalidEligibility'; + static const invalidInsurance = 'invalidInsurance'; + static const continueCash = 'continueCash'; + static const hmgPolicies = 'hmgPolicies'; + static const timeFor = 'Time for'; } diff --git a/lib/main.dart b/lib/main.dart index e034cf92..cff0d043 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -76,12 +77,33 @@ Future callAppStateInitializations() async { : "3"); AppState appState = getIt.get(); appState.setDeviceTypeID = deviceTypeId; + + // Pass all uncaught "fatal" errors from the framework to Crashlytics + FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError; + + // Pass all uncaught asynchronous errors that aren't handled by the Flutter framework to Crashlytics + PlatformDispatcher.instance.onError = (error, stack) { + if (!kDebugMode) FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); + return true; + }; } Future callInitializations() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); - await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + + // await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + + try { + // Attempt to get the default app. If it exists, this avoids the error. + await Firebase.app(); + } catch (e) { + // If it doesn't exist, initialize it. + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + } + await AppDependencies.addDependencies(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); HttpOverrides.global = MyHttpOverrides(); @@ -226,9 +248,16 @@ class MyApp extends StatelessWidget { builder: (context, orientation, deviceType) { // SizeConfig().init(constraints, orientation); return MaterialApp( - title: 'Dr. AlHabib', + // title: 'Dr. AlHabib', + title: 'Dr. AlHabib Beta', builder: (context, mchild) { - return MediaQuery(data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling, alwaysUse24HourFormat: true,), child: mchild!, ); + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaler: TextScaler.noScaling, + alwaysUse24HourFormat: true, + ), + child: mchild!, + ); }, showSemanticsDebugger: false, debugShowCheckedModeBanner: false, diff --git a/lib/presentation/active_medication/active_medication_page.dart b/lib/presentation/active_medication/active_medication_page.dart index 14da5b01..be6b82a6 100644 --- a/lib/presentation/active_medication/active_medication_page.dart +++ b/lib/presentation/active_medication/active_medication_page.dart @@ -393,16 +393,16 @@ class _ActiveMedicationPageState extends State { children: [ AppCustomChipWidget( labelText: - LocaleKeys.route.tr(namedArgs: {'route': med.route ?? ''})), + LocaleKeys.route.tr(namedArgs: {LocaleKeys.route.tr(): med.route ?? ''})), AppCustomChipWidget( labelText: - LocaleKeys.frequency.tr(namedArgs: {'frequency': med.frequency ?? ''})), + LocaleKeys.frequency.tr(namedArgs: {LocaleKeys.frequency.tr(): med.frequency ?? ''})), AppCustomChipWidget( labelText: - LocaleKeys.instruction.tr(namedArgs: {'instruction': med.doseDailyQuantity?.toString() ?? ''})), + LocaleKeys.instruction.tr(namedArgs: {LocaleKeys.instruction.tr(): med.doseDailyQuantity?.toString() ?? ''})), AppCustomChipWidget( labelText: - LocaleKeys.duration.tr(namedArgs: {'days': med.days.toString() ?? ''})), + LocaleKeys.duration.tr(namedArgs: {LocaleKeys.days.tr(): med.days.toString() ?? ''})), ], ), ], @@ -813,7 +813,7 @@ class _ReminderTimerDialogState extends State { text: TextSpan( children: [ TextSpan( - text: "Time for ", + text: LocaleKeys.timeFor.tr(), style: TextStyle( fontSize: 18.f, fontWeight: FontWeight.bold, @@ -842,7 +842,7 @@ class _ReminderTimerDialogState extends State { ), ), TextSpan( - text: " reminder", + text: LocaleKeys.reminder.tr(), style: TextStyle( fontSize: 18.f, fontWeight: FontWeight.bold, diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 0e0194b5..e5961e30 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -99,6 +99,7 @@ class _AppointmentDetailsPageState extends State { ? () { contactUsViewModel.setSelectedFeedbackType(FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد')); contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); + contactUsViewModel.setIsSendFeedbackTabSelected(true); Navigator.of(context).push( CustomPageRoute( page: FeedbackPage(), @@ -111,9 +112,9 @@ class _AppointmentDetailsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ AppointmentDoctorCard( - renderWidgetForERDisplay: ((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) || - (widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) || - !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)), + // renderWidgetForERDisplay: ((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) || + renderWidgetForERDisplay: + ((widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) || !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)), patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onAskDoctorTap: () async { LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); @@ -144,8 +145,6 @@ class _AppointmentDetailsPageState extends State { }); }, onCancelTap: () async { - myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr(context: context)); await myAppointmentsViewModel.cancelAppointment( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, @@ -164,6 +163,18 @@ class _AppointmentDetailsPageState extends State { isDismissible: false, isFullScreen: false, ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err.toString()), + callBackFunc: () {}, + title: "", + isCloseButtonVisible: true, + isDismissible: false, + isFullScreen: false, + ); }); var isEventAddedOrRemoved = await CalenderUtilsNew.instance.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", ); setState(() { @@ -532,7 +543,7 @@ class _AppointmentDetailsPageState extends State { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, - child: Utils.getErrorWidget(loadingText: err), + child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr(context: context)), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true, diff --git a/lib/presentation/appointments/my_doctors_page.dart b/lib/presentation/appointments/my_doctors_page.dart index 3795ce1d..fc7798f8 100644 --- a/lib/presentation/appointments/my_doctors_page.dart +++ b/lib/presentation/appointments/my_doctors_page.dart @@ -290,6 +290,12 @@ class _MyDoctorsPageState extends State { clinicID: doctor?.clinicID ?? 0, projectID: doctor?.projectID ?? 0, doctorID: doctor?.doctorID ?? 0, + clinicName: doctor?.clinicName, + projectName: doctor?.projectName, + // nationalityFlagURL: doctor?.nationalityFlagURL, + name: doctor?.doctorName, + doctorImageURL: doctor?.doctorImageURL ?? doctor?.doctorImage, + speciality: doctor?.doctorSpeciality )); LoaderBottomSheet.showLoader(); await bookAppointmentsViewModel.getDoctorProfile(onSuccess: (dynamic respData) { diff --git a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart index f07b9a4f..95fc09b8 100644 --- a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart +++ b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart @@ -155,7 +155,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { myAppointmentsViewModel.getPatientAppointments(true, false); LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () async { - await myAppointmentsViewModel.getPatientAppointmentQueueDetails(); + // await myAppointmentsViewModel.getPatientAppointmentQueueDetails(); Navigator.of(context).pop(); Navigator.pushAndRemoveUntil( context, @@ -163,11 +163,11 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { page: LandingNavigation(), ), (r) => false); - Navigator.of(context).push( - CustomPageRoute( - page: AppointmentQueuePage(), - ), - ); + // Navigator.of(context).push( + // CustomPageRoute( + // page: AppointmentQueuePage(), + // ), + // ); }, isFullScreen: false); }, onError: (error) { diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index 7e430694..9e56053a 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -183,7 +183,7 @@ class AppointmentDoctorCard extends StatelessWidget { ) : SizedBox.shrink(); } else { - return patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false + return patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? CustomButton( text: LocaleKeys.cancel.tr(), onPressed: () { diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index fa239797..03de8332 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -400,30 +400,30 @@ class _BookAppointmentPageState extends State { ), ); }), - SizedBox(height: 16.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h), - SizedBox(width: 12.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.pharmaLiveCare.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), - "".toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), - ], - ), - ], - ), - Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), - ], - ).onPress(() { - openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION); - }), + // SizedBox(height: 16.h), + // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), + // SizedBox(height: 16.h), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Row( + // children: [ + // Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h), + // SizedBox(width: 12.h), + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // LocaleKeys.pharmaLiveCare.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), + // "".toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + // ], + // ), + // ], + // ), + // Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + // ], + // ).onPress(() { + // openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION); + // }), ], ), ), diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart index 4992d850..fb6ebe72 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart @@ -110,7 +110,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget { children: [ Row( children: [ - Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain), + Utils.buildSvgWithAssets(icon: getLiveCareTypeIcon(immediateLiveCareVM.liveCareSelectedCallType), width: 32.h, height: 32.h, fit: BoxFit.contain), SizedBox(width: 8.h), getLiveCareType(context, immediateLiveCareVM.liveCareSelectedCallType).toText16(isBold: true), ], @@ -429,6 +429,19 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget { // // } // } + String getLiveCareTypeIcon(int callType) { + switch (callType) { + case 1: + return AppAssets.livecare_video; + case 2: + return AppAssets.livecare_audio; + case 3: + return AppAssets.livecare_phone; + default: + return AppAssets.livecare_video; + } + } + String getLiveCareType(BuildContext context, int callType) { switch (callType) { case 1: diff --git a/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart b/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart index 594bff0d..a83dfa05 100644 --- a/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart +++ b/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart @@ -116,7 +116,7 @@ class _SelectImmediateLiveCareClinicPageState extends State { Row( children: [ Image.network( - bookAppointmentsViewModel.selectedDoctor.doctorImageURL!, + bookAppointmentsViewModel.selectedDoctor.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png", width: 50.h, height: 50.h, fit: BoxFit.cover, @@ -83,15 +84,14 @@ class _ReviewAppointmentPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: MediaQuery.of(context).size.width * 0.49, - child: "${bookAppointmentsViewModel.selectedDoctor.doctorTitle} ${bookAppointmentsViewModel.selectedDoctor.name}" - .toString() - .toText16(isBold: true, maxlines: 1), - ), + "${bookAppointmentsViewModel.selectedDoctor.doctorTitle ?? LocaleKeys.Dr.tr(context: context)} ${bookAppointmentsViewModel.selectedDoctor.name}" + .toString() + .toText16(isBold: true, maxlines: 1), + SizedBox(width: 12.w), Image.network( - bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL!, + bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png", width: 20.h, height: 15.h, fit: BoxFit.cover, @@ -242,11 +242,16 @@ class _ReviewAppointmentPageState extends State { LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentShare.tr(context: context)); await bookAppointmentsViewModel.getWalkInPatientShareAppointment(onSuccess: (val) { LoaderBottomSheet.hideLoader(); - Navigator.of(context).push( - CustomPageRoute( - page: WaitingAppointmentPaymentPage(), - ), - ); + if (bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax != 0 || + bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax != 0.0) { + Navigator.of(context).push( + CustomPageRoute( + page: WaitingAppointmentPaymentPage(), + ), + ); + } else { + initiateBookAppointmentForWalkInNoPatientShare(); + } }, onError: (err) { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( @@ -259,6 +264,49 @@ class _ReviewAppointmentPageState extends State { }); } + void initiateBookAppointmentForWalkInNoPatientShare() async { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingWaitingAppointment.tr(context: context)); + await bookAppointmentsViewModel.insertSpecificAppointmentForWalkIn(onSuccess: (val) async { + String appointmentNo = val.data['AppointmentNo'].toString(); + LoaderBottomSheet.hideLoader(); + sendCheckInRequest(bookAppointmentsViewModel.waitingAppointmentNFCCode, appointmentNo, context); + }); + } + + void sendCheckInRequest(String scannedCode, String appointmentNo, BuildContext context) async { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.processingCheckIn.tr(context: context)); + PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel = PatientAppointmentHistoryResponseModel( + appointmentNo: appointmentNo, + clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID, + projectID: bookAppointmentsViewModel.selectedDoctor.projectID, + ); + await myAppointmentsViewModel.sendCheckInNfcRequest( + patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, + scannedCode: scannedCode, + checkInType: 2, + onSuccess: (apiResponse) { + LoaderBottomSheet.hideLoader(); + myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); + myAppointmentsViewModel.getPatientAppointments(true, false); + showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: apiResponse.data["SuccessMsg"]), callBackFunc: () { + Navigator.of(context).pop(); + Navigator.pushAndRemoveUntil( + context, + CustomPageRoute( + page: LandingNavigation(), + ), + (r) => false); + }, isFullScreen: false); + }, + onError: (error) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.error.tr(context: context), child: Utils.getErrorWidget(loadingText: error), callBackFunc: () { + Navigator.of(context).pop(); + }, isFullScreen: false); + }, + ); + } + void initiateBookAppointment() async { LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr(context: context)); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); diff --git a/lib/presentation/book_appointment/select_clinic_page.dart b/lib/presentation/book_appointment/select_clinic_page.dart index cad8e2e7..aebb90fd 100644 --- a/lib/presentation/book_appointment/select_clinic_page.dart +++ b/lib/presentation/book_appointment/select_clinic_page.dart @@ -144,7 +144,14 @@ class _SelectClinicPageState extends State { padding: EdgeInsets.only(top: 24.h), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemCount: bookAppointmentsVM.isClinicsListLoading ? 5 : bookAppointmentsVM.liveCareClinicsList.length, + itemCount: bookAppointmentsVM.isClinicsListLoading + ? 5 + : bookAppointmentsVM.liveCareClinicsList.isNotEmpty + ? bookAppointmentsVM.liveCareClinicsList.length + : 1, + + // bookAppointmentsVM.isClinicsListLoading ? 5 : bookAppointmentsVM.liveCareClinicsList.length, + itemBuilder: (context, index) { return bookAppointmentsVM.isClinicsListLoading ? ClinicCard( @@ -163,14 +170,16 @@ class _SelectClinicPageState extends State { duration: Duration(milliseconds: 300), curve: Curves.easeInOut, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), - child: ClinicCard( - bookAppointmentsVM: bookAppointmentsVM, - liveCareClinicsResponseModel: bookAppointmentsVM.liveCareClinicsList[index], - clinicsListResponseModel: GetClinicsListResponseModel(), - isLoading: bookAppointmentsVM.isClinicsListLoading, - ).onPress(() { - onLiveCareClinicSelected(bookAppointmentsVM.liveCareClinicsList[index]); - }), + child: bookAppointmentsVM.liveCareClinicsList.isNotEmpty + ? ClinicCard( + bookAppointmentsVM: bookAppointmentsVM, + liveCareClinicsResponseModel: bookAppointmentsVM.liveCareClinicsList[index], + clinicsListResponseModel: GetClinicsListResponseModel(), + isLoading: bookAppointmentsVM.isClinicsListLoading, + ).onPress(() { + onLiveCareClinicSelected(bookAppointmentsVM.liveCareClinicsList[index]); + }) + : Utils.getNoDataWidget(context), ), ), ), diff --git a/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart b/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart index ca60e9e0..bb347e5b 100644 --- a/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart +++ b/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart @@ -640,6 +640,8 @@ class _WaitingAppointmentPaymentPageState extends State(context, listen: false); medicalFileViewModel = Provider.of(context, listen: false); + appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Consumer(builder: (context, contactUsVM, child) { @@ -67,11 +73,12 @@ class FeedbackPage extends StatelessWidget { ), ), ), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - customBorder: BorderRadius.only( - topLeft: Radius.circular(24.h), + contactUsViewModel.isSendFeedbackTabSelected + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + customBorder: BorderRadius.only( + topLeft: Radius.circular(24.h), topRight: Radius.circular(24.h), ), hasShadow: true, @@ -126,7 +133,8 @@ class FeedbackPage extends StatelessWidget { iconColor: AppColors.whiteColor, iconSize: 20.h, ).paddingSymmetrical(24.h, 24.h), - ), + ) + : SizedBox.shrink(), ], ); }), @@ -389,7 +397,99 @@ class FeedbackPage extends StatelessWidget { ], ); } else { - return Container(); + return getIt.get().isAuthenticated + ? Column( + children: [ + SizedBox(height: 24.h), + ListView.builder( + itemCount: contactUsViewModel.isCOCItemsListLoading + ? 4 + : contactUsViewModel.cocItemsList.isEmpty + ? 1 + : contactUsViewModel.cocItemsList.length, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsetsGeometry.zero, + itemBuilder: (context, index) { + return contactUsViewModel.isCOCItemsListLoading + ? LabResultItemView( + onTap: () {}, + labOrder: null, + index: index, + isLoading: true, + ) + : contactUsViewModel.cocItemsList.isNotEmpty + ? AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + child: Container( + padding: EdgeInsets.all(16.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: true, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppCustomChipWidget( + labelText: appState.isArabic() ? contactUsViewModel.cocItemsList[index].statusAr : contactUsViewModel.cocItemsList[index].status, + // backgroundColor: AppColors.warningColorYellow, + backgroundColor: (contactUsViewModel.cocItemsList[index].statusId == 7 || contactUsViewModel.cocItemsList[index].statusId == 8) + ? AppColors.primaryRedColor + : (contactUsViewModel.cocItemsList[index].statusId == 10 || + contactUsViewModel.cocItemsList[index].statusId == 6 || + contactUsViewModel.cocItemsList[index].statusId == 9) + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: AppColors.whiteColor, + ), + SizedBox(height: 8.h), + "${LocaleKeys.requestID.tr(context: context)} ${contactUsViewModel.cocItemsList[index].itemID}".toText16(weight: FontWeight.bold), + SizedBox(height: 8.h), + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, + children: [ + AppCustomChipWidget( + labelText: contactUsViewModel.cocItemsList[index].date!.split(" ")[0], + icon: AppAssets.calendarGrey, + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), + ), + AppCustomChipWidget( + labelText: contactUsViewModel.cocItemsList[index].formType, + icon: AppAssets.ask_doctor_icon, + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), + ), + ], + ), + SizedBox(height: 8.h), + "${contactUsViewModel.cocItemsList[index].cOCTitle}" + .toText16(weight: FontWeight.bold, fontFamily: Utils.isArabicText(contactUsViewModel.cocItemsList[index].cOCTitle ?? "") ? "GESSTwo" : "Poppins"), + SizedBox(height: 8.h), + "${contactUsViewModel.cocItemsList[index].detail}".toText14( + weight: FontWeight.w500, + color: AppColors.textColorLight, + fontFamily: Utils.isArabicText(contactUsViewModel.cocItemsList[index].detail ?? "") ? "GESSTwo" : "Poppins"), + ], + ), + ).paddingOnly(bottom: 16.h), + ), + ), + ), + ) + : Utils.getNoDataWidget(context); + }), + ], + ) + : Utils.getNoDataWidget(context); } } } diff --git a/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart b/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart index 999a43ee..7f206c17 100644 --- a/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart +++ b/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -24,11 +25,13 @@ class ErOnlineCheckinHome extends StatelessWidget { ErOnlineCheckinHome({super.key}); late EmergencyServicesViewModel emergencyServicesViewModel; + late MyAppointmentsViewModel myAppointmentsViewModel; bool _supportsNFC = false; @override Widget build(BuildContext context) { emergencyServicesViewModel = Provider.of(context, listen: false); + myAppointmentsViewModel = Provider.of(context, listen: false); FlutterNfcKit.nfcAvailability.then((value) { _supportsNFC = (value == NFCAvailability.available); }); @@ -81,6 +84,9 @@ class ErOnlineCheckinHome extends StatelessWidget { await emergencyServicesViewModel.autoGenerateInvoiceERClinic( projectID: value, onSuccess: (value) { + myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); + myAppointmentsViewModel.initAppointmentsViewModel(); + myAppointmentsViewModel.getPatientAppointments(true, false); LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.onlineCheckIn.tr(), @@ -105,7 +111,9 @@ class ErOnlineCheckinHome extends StatelessWidget { ); }); }, - onError: (err) {}); + onError: (err) { + LoaderBottomSheet.hideLoader(); + }); }); }, onCancel: () {}); }); diff --git a/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart b/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart index 35101978..26456794 100644 --- a/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart +++ b/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart @@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/features/emergency_services/emergency_servic import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; @@ -445,7 +446,14 @@ class _ErOnlineCheckinPaymentPageState extends State showCommonBottomSheetWithoutHeight( context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.erAppointmentBookedSuccess.tr(context: context)), - callBackFunc: () {}, + callBackFunc: () { + Navigator.pushAndRemoveUntil( + context, + CustomPageRoute( + page: LandingNavigation(), + ), + (r) => false); + }, isFullScreen: false, isCloseButtonVisible: true, ); @@ -458,7 +466,14 @@ class _ErOnlineCheckinPaymentPageState extends State showCommonBottomSheetWithoutHeight( context, child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)), - callBackFunc: () {}, + callBackFunc: () { + Navigator.pushAndRemoveUntil( + context, + CustomPageRoute( + page: LandingNavigation(), + ), + (r) => false); + }, isFullScreen: false, isCloseButtonVisible: true, ); diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index 9aaf1591..4458b75a 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -53,14 +53,7 @@ class ServicesPage extends StatelessWidget { late MedicalFileViewModel medicalFileViewModel; late final List hmgServices = [ - HmgServicesComponentModel( - 11, - LocaleKeys.emergencyServices.tr(), - "", - AppAssets.emergency_services_icon, - bgColor: AppColors.primaryRedColor, - true, - route: null, onTap: () async { + HmgServicesComponentModel(11, LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, bgColor: AppColors.primaryRedColor, true, route: null, onTap: () async { if (getIt.get().isAuthenticated) { getIt.get().flushData(); getIt.get().getTransportationOrders( @@ -88,8 +81,7 @@ class ServicesPage extends StatelessWidget { true, route: AppRoutes.bookAppointmentPage, ), - HmgServicesComponentModel( - 5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async { + HmgServicesComponentModel(5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async { if (getIt.get().isAuthenticated) { getIt.get().pushPageRoute(AppRoutes.comprehensiveCheckupPage); } else { @@ -141,8 +133,7 @@ class ServicesPage extends StatelessWidget { ); }, ), - HmgServicesComponentModel( - 11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async { + HmgServicesComponentModel(11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async { if (getIt.get().isAuthenticated) { getIt.get().pushPageRoute(AppRoutes.eReferralPage); } else { @@ -415,19 +406,19 @@ class ServicesPage extends StatelessWidget { ? CustomButton( height: 40.h, icon: AppAssets.recharge_icon, - iconSize: 24.w, - iconColor: AppColors.infoColor, - textColor: AppColors.infoColor, - text: LocaleKeys.recharge.tr(), - borderWidth: 0.w, - fontWeight: FontWeight.w500, - borderColor: Colors.transparent, - backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), - padding: EdgeInsets.all(8.w), - fontSize: 14.f, - onPressed: () { - Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); - }, + iconSize: 24.w, + iconColor: AppColors.infoColor, + textColor: AppColors.infoColor, + text: LocaleKeys.recharge.tr(), + borderWidth: 0.w, + fontWeight: FontWeight.w500, + borderColor: Colors.transparent, + backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), + padding: EdgeInsets.all(8.w), + fontSize: 14.f, + onPressed: () { + Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); + }, ) : SizedBox.shrink(), ], @@ -467,60 +458,60 @@ class ServicesPage extends StatelessWidget { getIt.get().isAuthenticated ? Wrap( spacing: -12.h, - // runSpacing: 0.h, - children: [ - Utils.buildImgWithAssets( - icon: AppAssets.babyGirlImg, - height: 32.h, - width: 32.w, - border: 1, - fit: BoxFit.contain, - borderRadius: 50.r, - ), - Utils.buildImgWithAssets( - icon: AppAssets.femaleImg, - height: 32.h, - width: 32.w, - border: 1, - borderRadius: 50.r, - fit: BoxFit.contain, - ), - Utils.buildImgWithAssets( - icon: AppAssets.maleImg, - height: 32.h, - width: 32.w, - border: 1, - borderRadius: 50.r, - fit: BoxFit.contain, - ), - ], + // runSpacing: 0.h, + children: [ + Utils.buildImgWithAssets( + icon: AppAssets.babyGirlImg, + height: 32.h, + width: 32.w, + border: 1, + fit: BoxFit.contain, + borderRadius: 50.r, + ), + Utils.buildImgWithAssets( + icon: AppAssets.femaleImg, + height: 32.h, + width: 32.w, + border: 1, + borderRadius: 50.r, + fit: BoxFit.contain, + ), + Utils.buildImgWithAssets( + icon: AppAssets.maleImg, + height: 32.h, + width: 32.w, + border: 1, + borderRadius: 50.r, + fit: BoxFit.contain, + ), + ], ) : LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2), Spacer(), getIt.get().isAuthenticated ? CustomButton( height: 40.h, - icon: AppAssets.add_icon, - iconSize: 24.h, - iconColor: AppColors.primaryRedColor, - textColor: AppColors.primaryRedColor, - text: LocaleKeys.addMember.tr(), - borderWidth: 0.w, - fontWeight: FontWeight.w500, - borderColor: Colors.transparent, - backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08), - padding: EdgeInsets.all(8.w), - fontSize: 14.f, - onPressed: () { - DialogService dialogService = getIt.get(); - medicalFileViewModel.clearAuthValues(); - dialogService.showAddFamilyFileSheet( - label: LocaleKeys.addFamilyMember.tr(), - message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(), - onVerificationPress: () { - medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); - }); - }, + icon: AppAssets.add_icon, + iconSize: 24.h, + iconColor: AppColors.primaryRedColor, + textColor: AppColors.primaryRedColor, + text: LocaleKeys.addMember.tr(), + borderWidth: 0.w, + fontWeight: FontWeight.w500, + borderColor: Colors.transparent, + backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08), + padding: EdgeInsets.all(8.w), + fontSize: 14.f, + onPressed: () { + DialogService dialogService = getIt.get(); + medicalFileViewModel.clearAuthValues(); + dialogService.showAddFamilyFileSheet( + label: LocaleKeys.addFamilyMember.tr(), + message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(), + onVerificationPress: () { + medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); + }); + }, ) : SizedBox.shrink(), ], @@ -700,6 +691,60 @@ class ServicesPage extends StatelessWidget { }), ) ], + ), + SizedBox(height: 24.h), + LocaleKeys.hmgPolicies.tr().toText18(weight: FontWeight.bold), + SizedBox(height: 16.h), + Row( + children: [ + Expanded( + child: Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 12.h, + hasShadow: false, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.privacy_terms, width: 32.w, height: 32.h, fit: BoxFit.contain, iconColor: AppColors.blackColor), + SizedBox(width: 8.w), + Expanded(child: LocaleKeys.termsConditoins.tr().toText14(weight: FontWeight.w500)) + ], + ), + ), + ).onPress(() { + Utils.openWebView( + url: 'https://hmg.com/en/Pages/Terms.aspx', + ); + }), + ), + SizedBox(width: 16.w), + Expanded( + child: Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 12.h, + hasShadow: false, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.privacy_terms, width: 32.w, height: 32.h, fit: BoxFit.contain, iconColor: AppColors.blackColor), + SizedBox(width: 8.w), + Expanded(child: LocaleKeys.privacyPolicy.tr().toText14(weight: FontWeight.w500)) + ], + ), + ), + ).onPress(() { + Utils.openWebView( + url: 'https://hmg.com/en/Pages/Privacy.aspx', + ); + }), + ) + ], ) ], ).paddingSymmetrical(24.w, 0), diff --git a/lib/presentation/home/app_update_page.dart b/lib/presentation/home/app_update_page.dart new file mode 100644 index 00000000..5e6481bd --- /dev/null +++ b/lib/presentation/home/app_update_page.dart @@ -0,0 +1,96 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.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'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:in_app_update/in_app_update.dart'; +import 'package:lottie/lottie.dart'; + +class AppUpdatePage extends StatelessWidget { + AppUpdatePage({super.key, required this.appUpdateMessage}); + + String appUpdateMessage; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.whiteColor, + body: Column( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.all(24.h), + child: Column( + children: [ + SizedBox(height: 120.h), + Align( + alignment: Alignment.topCenter, + child: Transform.flip( + flipX: getIt.get().isArabic() ? true : false, + child: Lottie.asset(AppAnimations.onboarding_1, + repeat: true, reverse: false, frameRate: FrameRate(60), width: MediaQuery.sizeOf(context).width - 50.w, height: MediaQuery.sizeOf(context).width - 50.w), + ), + ), + SizedBox(height: 50.h), + appUpdateMessage.toText16(weight: FontWeight.w500), + ], + ), + ), + ), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: CustomButton( + text: LocaleKeys.updateAppNow.tr(context: context), + onPressed: () { + openAppUpdateLink(); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 56.h, + ), + ).paddingAll(24.h), + ], + ), + ); + } + + openAppUpdateLink() { + if (Platform.isAndroid) { + // _launchURL("https://play.google.com/store/apps/details?id=com.ejada.hmg"); + InAppUpdate.checkForUpdate().then((info) { + print("checkForUpdate!!!"); + print(info.toString()); + if (info.immediateUpdateAllowed) { + print("Immediate Allowed!!!"); + InAppUpdate.performImmediateUpdate().then((value) {}).catchError((e) => print(e.toString())); + } + }).catchError((e) { + print(e.toString()); + Utils.openWebView( + url: "https://play.google.com/store/apps/details?id=com.ejada.hmg", + ); + }); + } + if (Platform.isIOS) { + Utils.openWebView( + url: "https://itunes.apple.com/app/id733503978", + ); + } + } +} diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index a8a64fa6..e8482bf0 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -460,7 +460,7 @@ class _LandingPageState extends State { return emergencyServicesVM.patientHasAdvanceERBalance ? Column( children: [ - SizedBox(height: 4.h), + SizedBox(height: 16.h), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -490,12 +490,15 @@ class _LandingPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.youHaveEROnlineCheckInRequest.tr(context: context).toText12(isBold: true), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon_small, - iconColor: AppColors.blackColor, - width: 20.h, - height: 15.h, - fit: BoxFit.contain, + Transform.flip( + flipX: getIt.get().isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon_small, + iconColor: AppColors.blackColor, + width: 20.h, + height: 15.h, + fit: BoxFit.contain, + ), ), ], ), @@ -509,10 +512,10 @@ class _LandingPageState extends State { SizedBox(height: 12.h), ], ) - : SizedBox(height: 12.h); + : SizedBox(height: 0.h); }, ), - SizedBox(height: 24.h), + SizedBox(height: 16.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/presentation/home/widgets/habib_wallet_card.dart b/lib/presentation/home/widgets/habib_wallet_card.dart index 01359837..ed48058d 100644 --- a/lib/presentation/home/widgets/habib_wallet_card.dart +++ b/lib/presentation/home/widgets/habib_wallet_card.dart @@ -52,36 +52,36 @@ class HabibWalletCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ LocaleKeys.habibWallet.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), - Container( - height: 40.h, - width: 40.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.textColor, - borderRadius: 8.h, - ), - child: Padding( - padding: EdgeInsets.all(8.h), - child: Utils.buildSvgWithAssets( - icon: AppAssets.show_icon, - width: 12.h, - height: 12.h, - fit: BoxFit.contain, - ), - ), - ), - ], - ), + // Container( + // height: 40.h, + // width: 40.h, + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.textColor, + // borderRadius: 8.h, + // ), + // child: Padding( + // padding: EdgeInsets.all(8.h), + // child: Utils.buildSvgWithAssets( + // icon: AppAssets.show_icon, + // width: 12.h, + // height: 12.h, + // fit: BoxFit.contain, + // ), + // ), + // ), + // ], + // ), SizedBox(height: 4.h), Consumer(builder: (context, habibWalletVM, child) { return Row( children: [ Utils.buildSvgWithAssets( icon: AppAssets.saudi_riyal_icon, - iconColor: AppColors.dividerColor, + iconColor: AppColors.inputLabelTextColor, width: 24.h, height: 24.h, fit: BoxFit.contain, diff --git a/lib/presentation/insurance/insurance_approval_details_page.dart b/lib/presentation/insurance/insurance_approval_details_page.dart index a6d81575..a074a8d8 100644 --- a/lib/presentation/insurance/insurance_approval_details_page.dart +++ b/lib/presentation/insurance/insurance_approval_details_page.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; @@ -122,35 +123,69 @@ class InsuranceApprovalDetailsPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Approval Details".toText16(isBold: true), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LocaleKeys.procedureName.tr(context: context).toText14(isBold: true), - Expanded( - child: (insuranceApprovalResponseModel.apporvalDetails!.procedureName ?? "") - .toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, textAlignment: TextAlign.end, maxLine: 2), - ), - ], - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "${LocaleKeys.status.tr(context: context)}: ".toText14(isBold: true), - insuranceApprovalResponseModel.apporvalDetails!.status!.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), - ], - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "${LocaleKeys.usageStatus.tr(context: context)}: ".toText14(isBold: true), - (insuranceApprovalResponseModel.apporvalDetails!.isInvoicedDesc ?? "").toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), - ], - ), - ], - ) : SizedBox.shrink(), + ListView.separated( + padding: EdgeInsets.only(top: 16.h), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: insuranceApprovalResponseModel.apporvalDetails!.length, + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.procedureName.tr(context: context).toText14(isBold: true), + Expanded( + child: (insuranceApprovalResponseModel.apporvalDetails![index]!.procedureName ?? "") + .toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, textAlignment: TextAlign.end, maxLine: 2), + ), + ], + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "${LocaleKeys.status.tr(context: context)}: ".toText14(isBold: true), + insuranceApprovalResponseModel.apporvalDetails![index]!.status!.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + ], + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "${LocaleKeys.usageStatus.tr(context: context)}: ".toText14(isBold: true), + (insuranceApprovalResponseModel.apporvalDetails![index]!.isInvoicedDesc ?? "").toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + ], + ), + ], + ), + ), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => Column( + children: [ + SizedBox(height: 16.h), + Divider(height: 1, color: AppColors.greyColor), + SizedBox(height: 16.h), + ], + ), + ), + ], + ) + : SizedBox.shrink(), ), ) ], diff --git a/lib/presentation/insurance/widgets/patient_insurance_card.dart b/lib/presentation/insurance/widgets/patient_insurance_card.dart index c9ec7909..531341b5 100644 --- a/lib/presentation/insurance/widgets/patient_insurance_card.dart +++ b/lib/presentation/insurance/widgets/patient_insurance_card.dart @@ -5,6 +5,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/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; @@ -16,6 +17,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class PatientInsuranceCard extends StatelessWidget { PatientInsuranceCard({super.key, required this.insuranceCardDetailsModel, required this.isInsuranceExpired}); @@ -49,19 +51,73 @@ class PatientInsuranceCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( - width: MediaQuery.of(context).size.width * 0.45, child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true)), + width: MediaQuery.of(context).size.width * 0.4, + child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true, textOverflow: TextOverflow.clip)), LocaleKeys.policyNumber.tr(namedArgs: {'number': insuranceCardDetailsModel.insurancePolicyNo ?? ''}, context: context).toText12(isBold: true, color: AppColors.lightGrayColor), ], ), AppCustomChipWidget( - icon: isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon, - labelText: isInsuranceExpired ? LocaleKeys.insuranceExpired.tr(context: context) : LocaleKeys.insuranceActive.tr(context: context), - iconColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, - textColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, - iconSize: 12, - backgroundColor: isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), - labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), - ), + icon: insuranceViewModel.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceViewModel.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceViewModel.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceViewModel.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + iconSize: 12.w, + deleteIcon: insuranceViewModel.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceViewModel.isInsuranceActive) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + confirmText: LocaleKeys.contactUs.tr(context: context), + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(context); + }, + onConfirmTap: () async { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + backgroundColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceViewModel.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceViewModel.isInsuranceLoading), + // AppCustomChipWidget( + // icon: isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon, + // labelText: isInsuranceExpired ? LocaleKeys.insuranceExpired.tr(context: context) : LocaleKeys.insuranceActive.tr(context: context), + // iconColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, + // textColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, + // iconSize: 12, + // backgroundColor: isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), + // labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), + // ), ], ), SizedBox(height: 12.h), diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index a6ee1544..0bcbc364 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; 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/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { final lavVM = Provider.of(context, listen: false); if (lavVM.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; lavVM.filterLabReports(value); } } }, child: Consumer( builder: (context, model, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { model.setIsSortByClinic(true); }, backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { model.setIsSortByClinic(false); }, backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: model.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? CustomChipWidget( chipText: selectedFilterText!, chipType: ChipTypeEnum.alert, isSelected: true, ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available model.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (model.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: model.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = model.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( model.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), ), AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), ), AppCustomChipWidget( labelText: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex: 2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { model.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.length)) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (model.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: model.indexedCharacterForUniqueTest, details: model.uniqueTestsList, labViewModel: model, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; 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/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(true); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(false); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( labViewModel.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), ), AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), ), AppCustomChipWidget( labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex: 2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { labViewModel.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.length)) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/labAiAnalysis/lab_ai_analysis_detailed_page.dart b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart similarity index 97% rename from lib/presentation/labAiAnalysis/lab_ai_analysis_detailed_page.dart rename to lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart index 5d4fe4b0..14ff620b 100644 --- a/lib/presentation/labAiAnalysis/lab_ai_analysis_detailed_page.dart +++ b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart @@ -14,7 +14,7 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/expandable_list_widget.dart'; import 'package:provider/provider.dart'; -import '../../features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart'; +import '../../../features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart'; class LabAiAnalysisDetailedPage extends StatefulWidget { const LabAiAnalysisDetailedPage({super.key}); @@ -314,6 +314,16 @@ class _LabAiAnalysisDetailedPageState extends State { defaultTrailingIcon: Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w, iconColor: AppColors.textColor), ), ).paddingSymmetrical(16.w, 0.0), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.info_outline, color: AppColors.greyTextColor, size: 20.r), + SizedBox(width: 8.w), + Expanded( + child: ("${LocaleKeys.disclaimer.tr()}:${LocaleKeys.thisAboveInfo.tr()}").toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w400), + ), + ], + ).paddingSymmetrical(16.w, 16.h) ], ); }, diff --git a/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart b/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart index ba97731f..cf6ce97b 100644 --- a/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart +++ b/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart @@ -22,7 +22,7 @@ class LabOrderResultItem extends StatelessWidget { final bool isExpanded; final Color iconColor; - const LabOrderResultItem({super.key, required this.onTap, this.tests, required this.index, this.isLoading = false, this.isExpanded = false,required this.iconColor, required this.severityText}); + const LabOrderResultItem({super.key, required this.onTap, this.tests, required this.index, this.isLoading = false, this.isExpanded = false, required this.iconColor, required this.severityText}); @override build(BuildContext context) { @@ -42,7 +42,10 @@ class LabOrderResultItem extends StatelessWidget { padding: EdgeInsets.only(bottom: 8.h), child: '${tests!.description}'.toText14(weight: FontWeight.w500), ), - (tests!.packageShortDescription ?? "").toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), + // (tests!.packageShortDescription ?? "").toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), + + ((tests!.testShortDescription != null && tests!.testShortDescription!.isNotEmpty) ? tests!.testShortDescription : tests!.packageShortDescription)! + .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), SizedBox(height: 12.h), Directionality( textDirection: ui.TextDirection.ltr, @@ -65,28 +68,30 @@ class LabOrderResultItem extends StatelessWidget { ), ), ), - SizedBox(width: 4.h,), + SizedBox( + width: 4.h, + ), Visibility( // visible: tests?.checkIfGraphShouldBeDisplayed() == true, visible: true, child: Expanded( flex: 2, - child: Visibility( - visible: tests?.referanceRange != null, - child: Text( - "(${LocaleKeys.referenceRange.tr(context: context)}: ${tests?.referanceRange})", - style: TextStyle( - fontSize: 12.f, - fontWeight: FontWeight.w500, - fontFamily: 'Poppins', - color: AppColors.greyTextColor, + child: Visibility( + visible: tests?.referanceRange != null, + child: Text( + "(${LocaleKeys.referenceRange.tr(context: context)}: ${tests?.referanceRange})", + style: TextStyle( + fontSize: 12.f, + fontWeight: FontWeight.w500, + fontFamily: 'Poppins', + color: AppColors.greyTextColor, + ), + // overflow: TextOverflow.ellipsis, + // maxLines: 2, + softWrap: true, ), - // overflow: TextOverflow.ellipsis, - // maxLines: 2, - softWrap: true, ), ), - ), ) ], ), @@ -102,14 +107,8 @@ class LabOrderResultItem extends StatelessWidget { spacing: 6.h, crossAxisAlignment: CrossAxisAlignment.start, children: [ - severityText.tr().toText10( - weight: FontWeight.w500, - color: AppColors.greyTextColor), - Utils.buildSvgWithAssets( - icon: AppAssets.lab_result_indicator, - width: 21, - height: 23, - iconColor: iconColor), + severityText.tr().toText10(weight: FontWeight.w500, color: AppColors.greyTextColor), + Utils.buildSvgWithAssets(icon: AppAssets.lab_result_indicator, width: 21, height: 23, iconColor: iconColor), ], ), ), @@ -119,7 +118,7 @@ class LabOrderResultItem extends StatelessWidget { iconSize: 16.h, text: LocaleKeys.viewReport.tr(context: context), onPressed: () { - onTap(); + onTap(); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index ddac1bb8..1a68f224 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -33,6 +33,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; +import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/active_medication/active_medication_page.dart'; import 'package:hmg_patient_app_new/presentation/allergies/allergies_list_page.dart'; @@ -78,6 +79,7 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../features/active_prescriptions/active_prescriptions_view_model.dart'; import '../prescriptions/prescription_detail_page.dart'; @@ -286,14 +288,58 @@ class _MedicalFilePageState extends State { ), Consumer(builder: (context, insuranceVM, child) { return AppCustomChipWidget( - icon: insuranceVM.isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon, - labelText: insuranceVM.isInsuranceExpired ? LocaleKeys.insuranceExpired.tr(context: context) : LocaleKeys.insuranceActive.tr(context: context), - iconColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, - textColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, + icon: insuranceVM.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceVM.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceVM.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceVM.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, iconSize: 12.w, - backgroundColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), - labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), - ); + deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceVM.isInsuranceActive) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), + navigationService.navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + confirmText: LocaleKeys.contactUs.tr(context: context), + isShowActionButtons: true, + onCancelTap: () { + navigationService.pop(); + }, + onConfirmTap: () async { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + backgroundColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceVM.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceVM.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceVM.isInsuranceLoading); }), ], ), @@ -846,7 +892,11 @@ class _MedicalFilePageState extends State { Expanded( child: CustomButton( text: LocaleKeys.allMedications.tr(context: context), - onPressed: () {}, + onPressed: () { Navigator.of(context).push( + CustomPageRoute( + page: ActiveMedicationPage(), + ), + );}, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, @@ -1176,6 +1226,7 @@ class _MedicalFilePageState extends State { isLargeText: true, iconSize: 36.w, ).onPress(() { + getIt.get().setIsAncillaryOrdersNeedReloading(true); Navigator.of(context).push( CustomPageRoute( page: ToDoPage(), diff --git a/lib/presentation/medical_report/medical_reports_page.dart b/lib/presentation/medical_report/medical_reports_page.dart index 87420fd5..02a9bdec 100644 --- a/lib/presentation/medical_report/medical_reports_page.dart +++ b/lib/presentation/medical_report/medical_reports_page.dart @@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/presentation/medical_report/widgets/patient_ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; @@ -251,46 +252,21 @@ class _MedicalReportsPageState extends State { ], ), SizedBox(height: 8.h), - Row( + Wrap( + alignment: WrapAlignment.start, + direction: Axis.horizontal, + spacing: 6.h, + runSpacing: 6.h, children: [ - CustomButton( - text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(report.appointmentDate), false), - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 24.h, + AppCustomChipWidget( + labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(report.appointmentDate), false), ), - SizedBox(width: 8.h), - CustomButton( - text: medicalFileVM.isMedicalReportsSortByClinic ? report.projectName! : report.clinicDescription!, - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 24.h, - ), - SizedBox(width: 8.h), - CustomButton( - text: report.statusDesc!, - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 24.h, + AppCustomChipWidget( + labelText: medicalFileVM.isMedicalReportsSortByClinic ? report.projectName! : report.clinicDescription!, ), + report.statusDesc != null ? AppCustomChipWidget( + labelText: report.statusDesc ?? "test", + ) : SizedBox.shrink(), ], ), SizedBox(height: 8.h), diff --git a/lib/presentation/my_family/my_family.dart b/lib/presentation/my_family/my_family.dart index bac6f778..dca75747 100644 --- a/lib/presentation/my_family/my_family.dart +++ b/lib/presentation/my_family/my_family.dart @@ -1,4 +1,3 @@ - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; @@ -20,14 +19,7 @@ import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:provider/provider.dart'; class FamilyMedicalScreen extends StatefulWidget { - final List profiles; - final Function(FamilyFileResponseModelLists) onSelect; - - const FamilyMedicalScreen({ - super.key, - required this.profiles, - required this.onSelect, - }); + const FamilyMedicalScreen({super.key}); @override State createState() => _FamilyMedicalScreenState(); @@ -43,7 +35,6 @@ class _FamilyMedicalScreenState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { medicalVM?.onFamilyFileTabChange(0); medicalVM?.getAllPendingRecordsByResponseId(); - }); } @@ -55,27 +46,28 @@ class _FamilyMedicalScreenState extends State { title: LocaleKeys.familyTitle.tr(context: context), bottomChild: appState.getAuthenticatedUser()!.isParentUser! ? Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - customBorder: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), - ), - padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 20.h), - child: CustomButton( - text: LocaleKeys.addANewFamilyMember.tr(context: context), - onPressed: () { - DialogService dialogService = getIt.get(); - medicalVM!.clearAuthValues(); - dialogService.showAddFamilyFileSheet( - label: LocaleKeys.addFamilyMember.tr(context: context), - message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), - onVerificationPress: () { - medicalVM!.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); - }); - }, - icon: AppAssets.add_icon, - fontSize: 16.f, - borderRadius: 12.r, - fontWeight: FontWeight.w500)).paddingOnly(bottom: 20.h) + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + customBorder: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), + ), + padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 20.h), + child: CustomButton( + text: LocaleKeys.addANewFamilyMember.tr(context: context), + onPressed: () { + DialogService dialogService = getIt.get(); + medicalVM!.clearAuthValues(); + dialogService.showAddFamilyFileSheet( + label: LocaleKeys.addFamilyMember.tr(context: context), + message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), + onVerificationPress: () { + medicalVM!.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); + }); + }, + icon: AppAssets.add_icon, + fontSize: 16.f, + borderRadius: 12.r, + fontWeight: FontWeight.w500)) + .paddingOnly(bottom: 20.h) : SizedBox(), child: Column( mainAxisSize: MainAxisSize.min, @@ -96,18 +88,28 @@ class _FamilyMedicalScreenState extends State { ), ), appState.isChildLoggedIn ? SizedBox() : SizedBox(height: 25.h), - Selector(selector: (_, model) => model.getSelectedFamilyFileTabIndex, builder: (context, selectedIndex, child) => getFamilyTabs(index: selectedIndex)), + Selector patientFiles, List pendingFiles})>( + selector: (_, model) => (selectedIndex: model.getSelectedFamilyFileTabIndex, patientFiles: model.patientFamilyFiles, pendingFiles: model.pendingFamilyFiles), + shouldRebuild: (previous, next) { + return previous.selectedIndex != next.selectedIndex || previous.patientFiles.length != next.patientFiles.length || previous.pendingFiles.length != next.pendingFiles.length; + }, + builder: (context, data, child) => getFamilyTabs(index: data.selectedIndex, patientFiles: data.patientFiles, pendingFiles: data.pendingFiles), + ), SizedBox(height: 20.h), ], ).paddingSymmetrical(20, 0), ); } - Widget getFamilyTabs({required int index}) { + Widget getFamilyTabs({ + required int index, + required List patientFiles, + required List pendingFiles, + }) { switch (index) { case 0: return FamilyCards( - profiles: medicalVM!.patientFamilyFiles, + profiles: patientFiles, onSelect: (FamilyFileResponseModelLists profile) { medicalVM!.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); }, @@ -120,7 +122,7 @@ class _FamilyMedicalScreenState extends State { ); case 1: return FamilyCards( - profiles: medicalVM!.pendingFamilyFiles, + profiles: pendingFiles, isRequestDesign: medicalVM!.getSelectedFamilyFileTabIndex == 1, onSelect: (FamilyFileResponseModelLists profile) { medicalVM!.acceptRejectFileFromFamilyMembers(id: profile.id, status: 3); diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index ea305b0e..826b1741 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -308,6 +308,7 @@ class _FamilyCardsState extends State { alignment: WrapAlignment.start, children: [ (profile.patientName ?? "").toText14(isBold: false, isCenter: true, maxlines: 1, weight: FontWeight.w600), + SizedBox(width: 2.w,), (getStatusTextByRequest( FamilyFileEnum.values.firstWhere((e) => e.toInt == profile.status), profile.isRequestFromMySide ?? false)) .toText14( diff --git a/lib/presentation/prescriptions/prescription_item_view.dart b/lib/presentation/prescriptions/prescription_item_view.dart index 03a343f7..1369d4ac 100644 --- a/lib/presentation/prescriptions/prescription_item_view.dart +++ b/lib/presentation/prescriptions/prescription_item_view.dart @@ -84,76 +84,77 @@ class PrescriptionItemView extends StatelessWidget { SizedBox(height: 14.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), SizedBox(height: 14.h), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h).toShimmer2(isShow: isLoading), - SizedBox(width: 8.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), - "Notify me before the consumption time".toText10(color: AppColors.textColorLight), - ], - ).toShimmer2(isShow: isLoading).expanded, - Switch( - activeColor: AppColors.successColor, - activeTrackColor: AppColors.successColor.withValues(alpha: .15), - value: isLoading ? false : prescriptionVM.prescriptionDetailsList[index].hasReminder!, - onChanged: (newValue) async { - CalenderUtilsNew calender = CalenderUtilsNew.instance; - - if (prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false) { - LoaderBottomSheet.showLoader(loadingText: "Removing Reminders"); - bool resultValue = await calender.checkAndRemoveMultipleItems(id:prescriptionVM.prescriptionDetailsList[index].itemID.toString()); + Visibility( + visible: (!isLoading && prescriptionVM.prescriptionDetailsList[index].frequencyNumber != 0), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h).toShimmer2(isShow: isLoading), + SizedBox(width: 8.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), + "Notify me before the consumption time".toText10(color: AppColors.textColorLight), + ], + ).toShimmer2(isShow: isLoading).expanded, + Switch( + activeColor: AppColors.successColor, + activeTrackColor: AppColors.successColor.withValues(alpha: .15), + value: isLoading ? false : prescriptionVM.prescriptionDetailsList[index].hasReminder!, + onChanged: (newValue) async { + CalenderUtilsNew calender = CalenderUtilsNew.instance; - prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]); - LoaderBottomSheet.hideLoader(); - return; - } + if (prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false) { + LoaderBottomSheet.showLoader(loadingText: "Removing Reminders"); + bool resultValue = await calender.checkAndRemoveMultipleItems(id: prescriptionVM.prescriptionDetailsList[index].itemID.toString()); - DateTime startDate = DateTime.now(); - DateTime endDate = DateTime(startDate.year, startDate.month, startDate.day + prescriptionVM.prescriptionDetailsList[index].days!.toInt()); - BottomSheetUtils().showReminderBottomSheet( - context, - endDate, - "", - prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - "", - "", - title: "${prescriptionVM.prescriptionDetailsList[index].itemDescription} Prescription Reminder", - description: - "${prescriptionVM.prescriptionDetailsList[index].itemDescription} ${prescriptionVM.prescriptionDetailsList[index].frequency} ${prescriptionVM.prescriptionDetailsList[index].route} ", - onSuccess: () { + prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]); + LoaderBottomSheet.hideLoader(); + return; + } - }, - isMultiAllowed: true, - onMultiDateSuccess: (int selectedIndex) async{ - bool isEventAdded = await calender.createMultipleEvents( + DateTime startDate = DateTime.now(); + DateTime endDate = DateTime(startDate.year, startDate.month, startDate.day + prescriptionVM.prescriptionDetailsList[index].days!.toInt()); + BottomSheetUtils().showReminderBottomSheet( + context, + endDate, + "", + prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + "", + "", + title: "${prescriptionVM.prescriptionDetailsList[index].itemDescription} Prescription Reminder", + description: + "${prescriptionVM.prescriptionDetailsList[index].itemDescription} ${prescriptionVM.prescriptionDetailsList[index].frequency} ${prescriptionVM.prescriptionDetailsList[index].route} ", + onSuccess: () {}, + isMultiAllowed: true, + onMultiDateSuccess: (int selectedIndex) async { + bool isEventAdded = await calender.createMultipleEvents( reminderMinutes: selectedIndex, frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), - days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, route: prescriptionVM.prescriptionDetailsList[index].route!, - onFailure: (errorMessage)=> prescriptionVM.showError(errorMessage), - prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - ); - prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); - // setCalender(context, - // eventId: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - // selectedMinutes: selectedIndex, - // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), - // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), - // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, - // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, - // route: prescriptionVM.prescriptionDetailsList[index].route!); - }, - ); - }, - ).toShimmer2(isShow: isLoading), - ], - ).paddingSymmetrical(16.h, 0.h), + onFailure: (errorMessage) => prescriptionVM.showError(errorMessage), + prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + ); + prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); + // setCalender(context, + // eventId: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + // selectedMinutes: selectedIndex, + // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), + // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, + // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, + // route: prescriptionVM.prescriptionDetailsList[index].route!); + }, + ); + }, + ).toShimmer2(isShow: isLoading), + ], + ).paddingSymmetrical(16.h, 0.h), + ), SizedBox(height: 14.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // Row( diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index a3c2667b..82150ca7 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -30,6 +30,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -197,9 +198,11 @@ class ProfileSettingsState extends State { showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.language.tr(context: context), child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false); }, trailingLabel: Utils.appState.isArabic() ? "العربية" : "English"), 1.divider, - actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () {}), - 1.divider, - actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true), + actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () { + openAppSettings(); + }), + // 1.divider, + // actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true), ], ), ), @@ -228,11 +231,11 @@ class ProfileSettingsState extends State { child: Column( children: [ actionItem(AppAssets.call_fill, LocaleKeys.contactUs.tr(context: context), () { - launchUrl(Uri.parse("tel://" + "+966 11 525 9999")); - }, trailingLabel: "011 525 9999"), - 1.divider, - actionItem(AppAssets.permission, LocaleKeys.permissions.tr(context: context), () {}, trailingLabel: "Location, Camera"), + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }, trailingLabel: "92 006 6666"), 1.divider, + // actionItem(AppAssets.permission, LocaleKeys.permissions.tr(context: context), () {}, trailingLabel: "Location, Camera"), + // 1.divider, actionItem(AppAssets.rate, LocaleKeys.rateApp.tr(context: context), () { if (Platform.isAndroid) { Utils.openWebView( @@ -366,61 +369,66 @@ class FamilyCardWidget extends StatelessWidget { labelText: "Blood: ${appState.getAuthenticatedUser()!.bloodGroup ?? ""}", iconColor: AppColors.primaryRedColor) : SizedBox(), - Selector( - selector: (context, insuranceVM) => ( - isEmpty: insuranceVM.patientInsuranceList.isEmpty, - patientID: insuranceVM.patientInsuranceList.isNotEmpty ? insuranceVM.patientInsuranceList.first.patientID : null, - isLoading: insuranceVM.isInsuranceLoading, - cardValidTo: insuranceVM.patientInsuranceList.isNotEmpty ? insuranceVM.patientInsuranceList.first.cardValidTo : null - ), - builder: (context, data, child) { - if (data.isEmpty) { - return const SizedBox(); - } else if (profile.responseId != data.patientID) { - return SizedBox(); - } - - final isLoading = data.isLoading; - final isExpired = !isLoading && DateTime.now().isAfter(DateUtil.convertStringToDate(data.cardValidTo)); - - final String icon; - final String labelText; - final Color iconColor; - final Color backgroundColor; - - if (isLoading) { - icon = AppAssets.cancel_circle_icon; - labelText = LocaleKeys.insurance.tr(context: context); - iconColor = AppColors.primaryRedColor; - backgroundColor = AppColors.primaryRedColor; - } else if (isExpired) { - icon = AppAssets.cancel_circle_icon; - labelText = LocaleKeys.insuranceExpired.tr(context: context); - iconColor = AppColors.primaryRedColor; - backgroundColor = AppColors.primaryRedColor.withValues(alpha: 0.15); - } else { - icon = AppAssets.insurance_active_icon; - labelText = LocaleKeys.insuranceActive.tr(context: context); - iconColor = AppColors.successColor; - backgroundColor = AppColors.successColor.withValues(alpha: 0.15); - } - - return AppCustomChipWidget( - icon: icon, - labelText: labelText, - iconColor: iconColor, - iconSize: 12.w, - backgroundColor: backgroundColor, - labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w), - // padding: EdgeInsets.zero, - ).toShimmer2(isShow: isLoading); - }, - ) + Consumer(builder: (context, insuranceVM, child) { + return AppCustomChipWidget( + icon: insuranceVM.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceVM.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceVM.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceVM.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + iconSize: 12.w, + deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceVM.isInsuranceActive) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + confirmText: LocaleKeys.contactUs.tr(context: context), + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(context); + }, + onConfirmTap: () async { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + backgroundColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceVM.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceVM.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceVM.isInsuranceLoading); + }), ], ), ), ], - ).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 0.h), + ).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 8.h), 1.divider.paddingSymmetrical(16.w, 0.h), _buildActionButton(appState), ], diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index f9b94e27..a07face1 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -86,19 +86,6 @@ class _RadiologyOrdersPageState extends State { child: Consumer( builder: (context, model, child) { // Build grouping lists if we have data and none constructed yet - if (!model.isRadiologyOrdersLoading && model.patientRadiologyOrders.isNotEmpty && model.patientRadiologyOrdersViewList.isEmpty) { - final clinicMap = >{}; - final hospitalMap = >{}; - for (var order in model.patientRadiologyOrders) { - final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); - clinicMap.putIfAbsent(clinicKey, () => []).add(order); - final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); - hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); - } - model.patientRadiologyOrdersByClinic = clinicMap.values.toList(); - model.patientRadiologyOrdersByHospital = hospitalMap.values.toList(); - model.patientRadiologyOrdersViewList = model.isSortByClinic ? model.patientRadiologyOrdersByClinic : model.patientRadiologyOrdersByHospital; - } return Padding( padding: EdgeInsets.symmetric(horizontal: 24.h), @@ -140,13 +127,12 @@ class _RadiologyOrdersPageState extends State { ), ], ), - SizedBox(height: 8.h), selectedFilterText.isNotEmpty ? AppCustomChipWidget( padding: EdgeInsets.symmetric(horizontal: 5.h), labelText: selectedFilterText, - deleteIcon: 'assets/images/svg/cross_circle.svg', + deleteIcon: AppAssets.close_bottom_sheet_icon, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIconColor: AppColors.whiteColor, @@ -310,8 +296,8 @@ class _RadiologyOrdersPageState extends State { ), ), AppCustomChipWidget( - labelText: model.isSortByClinic ? (order.clinicDescription ?? '') : (order.projectName ?? ''), - ), + labelText: model.isSortByClinic ? (order.projectName ?? '') : (order.clinicDescription ?? ''), + ), ], ), SizedBox(height: 12.h), diff --git a/lib/presentation/symptoms_checker/organ_selector_screen.dart b/lib/presentation/symptoms_checker/organ_selector_screen.dart index 9a4a1d96..253fccdc 100644 --- a/lib/presentation/symptoms_checker/organ_selector_screen.dart +++ b/lib/presentation/symptoms_checker/organ_selector_screen.dart @@ -142,15 +142,27 @@ class _OrganSelectorPageState extends State { transitionBuilder: (child, animation) => _build3DFlipTransition(child, animation), switchInCurve: Curves.easeInOut, switchOutCurve: Curves.easeInOut, - child: InteractiveBodyWidget( + child: Builder( key: ValueKey(viewModel.currentView), - bodyImageAsset: viewModel.currentView == BodyView.front ? AppAssets.fullBodyFront : AppAssets.fullBodyBack, - organs: viewModel.currentOrgans, - selectedOrganIds: viewModel.selectedOrganIds, - onOrganTap: viewModel.toggleOrganSelection, - isBodyHidden: viewModel.isBodyHidden, - tooltipOrganId: viewModel.tooltipOrganId, - isArabic: _appState.isArabic(), + builder: (context) { + // Detect female gender from viewModel; allow Arabic value as fallback + final bool isFemale = + (viewModel.selectedGender != null && (viewModel.selectedGender!.toLowerCase() == 'female' || viewModel.selectedGender == 'أنثى')); + + final String bodyAsset = viewModel.currentView == BodyView.front + ? (isFemale ? AppAssets.fullBodyFrontFemale : AppAssets.fullBodyFrontMale) + : (isFemale ? AppAssets.fullBodyBackFemale : AppAssets.fullBodyBackMale); + + return InteractiveBodyWidget( + bodyImageAsset: bodyAsset, + organs: viewModel.currentOrgans, + selectedOrganIds: viewModel.selectedOrganIds, + onOrganTap: viewModel.toggleOrganSelection, + isBodyHidden: viewModel.isBodyHidden, + tooltipOrganId: viewModel.tooltipOrganId, + isArabic: _appState.isArabic(), + ); + }, ), ), ), diff --git a/lib/presentation/symptoms_checker/possible_conditions_screen.dart b/lib/presentation/symptoms_checker/possible_conditions_screen.dart index 3d288d78..80c70714 100644 --- a/lib/presentation/symptoms_checker/possible_conditions_screen.dart +++ b/lib/presentation/symptoms_checker/possible_conditions_screen.dart @@ -8,20 +8,32 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_type_selection_widget.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/condition_card.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:provider/provider.dart'; import 'package:shimmer/shimmer.dart'; +import '../appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart'; + class PossibleConditionsPage extends StatelessWidget { - const PossibleConditionsPage({super.key}); + PossibleConditionsPage({super.key}); + + late SymptomsCheckerViewModel symptomsCheckerViewModel; + late BookAppointmentsViewModel bookAppointmentsViewModel; + late AppointmentViaRegionViewmodel regionalViewModel; Widget _buildLoadingShimmer() { return ListView.separated( @@ -80,8 +92,20 @@ class PossibleConditionsPage extends StatelessWidget { condition: condition, symptoms: symptoms, onActionPressed: () { - dialogService.showErrorBottomSheet( - message: 'icd10 Code is ${condition.conditionDetails?.icd10Code}. We need to get the clinics mapped against this code.', + LoaderBottomSheet.showLoader(); + symptomsCheckerViewModel.getClinicConditionsFromCategory( + categoryName: (condition.conditionDetails!.category!.name) ?? "Other", + onSuccess: (value) { + LoaderBottomSheet.hideLoader(); + print(symptomsCheckerViewModel.clinicDetailsList.first.clinicID); + initiateBookAppointmentFlow(context); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + dialogService.showErrorBottomSheet( + message: err.toString(), + ); + }, ); }, ); @@ -194,6 +218,9 @@ class PossibleConditionsPage extends StatelessWidget { @override Widget build(BuildContext context) { + symptomsCheckerViewModel = context.read(); + bookAppointmentsViewModel = context.read(); + regionalViewModel = context.read(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( @@ -202,7 +229,6 @@ class PossibleConditionsPage extends StatelessWidget { context: context, onConfirm: () { context.pop(); - final SymptomsCheckerViewModel symptomsCheckerViewModel = context.read(); symptomsCheckerViewModel.reset(); // Clear all symptoms checker data final navigationService = getIt.get(); // navigationService.replaceAllRoutesAndNavigateToLanding(); @@ -230,4 +256,102 @@ class PossibleConditionsPage extends StatelessWidget { ), ); } + + initiateBookAppointmentFlow(BuildContext context) { + bookAppointmentsViewModel.getLocation(); + bookAppointmentsViewModel.setSelectedClinic(GetClinicsListResponseModel( + clinicID: symptomsCheckerViewModel.clinicDetailsList.first.clinicID, + clinicDescription: symptomsCheckerViewModel.clinicDetailsList.first.category, + clinicDescriptionN: symptomsCheckerViewModel.clinicDetailsList.first.categoryAR, + )); + bookAppointmentsViewModel.setIsDoctorsListLoading(true); + + var bottomSheetType = RegionBottomSheetType.FOR_CLINIIC; + openRegionListBottomSheet(context, bottomSheetType); + } + + getTitle(AppointmentViaRegionViewmodel data, BuildContext context) { + if (data.selectedRegionId == null) { + return LocaleKeys.selectRegion.tr(context: context).toText20(weight: FontWeight.w600); + } else { + return Transform.flip( + flipX: data.isArabic ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrow_back, + iconColor: Color(0xff2B353E), + fit: BoxFit.contain, + ), + ).onPress(() { + data.handleBackPress(); + }); + } + } + + void openRegionListBottomSheet(BuildContext context, RegionBottomSheetType type) { + bookAppointmentsViewModel.setProjectID(null); + + regionalViewModel.flush(); + regionalViewModel.setBottomSheetType(type); + // AppointmentViaRegionViewmodel? viewmodel = null; + showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer(builder: (_, data, __) => getTitle(data, context)), isDismissible: false, + child: Consumer(builder: (context, data, __) { + return getRegionalSelectionWidget(data, context); + }), callBackFunc: () {}); + } + + Widget getRegionalSelectionWidget(AppointmentViaRegionViewmodel data, BuildContext context) { + if (data.bottomSheetState == AppointmentViaRegionState.REGION_SELECTION) { + return RegionBottomSheetBody(); + } + if (data.bottomSheetState == AppointmentViaRegionState.TYPE_SELECTION) { + bookAppointmentsViewModel.resetFilterList(); + return FacilityTypeSelectionWidget( + selectedRegion: data.selectedRegionId ?? "", + ); + } + if (data.bottomSheetState == AppointmentViaRegionState.HOSPITAL_SELECTION) { + return HospitalBottomSheetBody( + searchText: data.searchController, + displayList: data.displayList, + onFacilityClicked: (value) { + data.setSelectedFacility(value); + data.getDisplayList(); + }, + onHospitalClicked: (hospital) { + regionalViewModel.setHospitalModel(hospital); + if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION) { + regionalViewModel.setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION); + regionalViewModel.handleLastStepForRegion(); + } else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) { + regionalViewModel.setBottomSheetState(AppointmentViaRegionState.DOCTOR_SELECTION); + regionalViewModel.handleLastStepForClinic(); + } else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) { + var appointmentsViewModel = Provider.of(context, listen: false); + regionalViewModel.setBottomSheetState(AppointmentViaRegionState.DOCTOR_SELECTION); + regionalViewModel.handleLastStepForClinicForDentalAndLaser(appointmentsViewModel.selectedClinic.clinicID ?? -1); + } + }, + onHospitalSearch: (value) { + data.searchHospitals(value ?? ""); + }, + selectedFacility: data.selectedFacility, + hmcCount: data.hmcCount, + hmgCount: data.hmgCount, + ); + } + if (data.bottomSheetState == AppointmentViaRegionState.DOCTOR_SELECTION) { + //if the region screen is opened for the dental clinic then the project id will be in the hospital list as the list is formed form the get project api + var id = ""; + if (data.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) { + id = regionalViewModel.selectedHospital?.hospitalList.first.iD?.toString() ?? ""; + } else { + id = regionalViewModel.selectedHospital?.patientDoctorAppointmentList?.first.projectID?.toString() ?? ""; + } + bookAppointmentsViewModel.setProjectID(id); + return SizedBox.shrink(); + } else { + return SizedBox.shrink(); + } + return SizedBox.shrink(); + } } diff --git a/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart b/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart index f9f2d000..ce8087d4 100644 --- a/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart +++ b/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart @@ -1,9 +1,6 @@ -import 'dart:developer'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; -import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; @@ -154,6 +151,7 @@ class HeightSelectionPage extends StatelessWidget { ), Expanded( child: HeightScale( + key: ValueKey(viewModel.isHeightCm), enableHaptic: true, enableSound: true, minValue: minValue, @@ -161,7 +159,6 @@ class HeightSelectionPage extends StatelessWidget { initialHeight: (viewModel.selectedHeight ?? 100).toDouble(), isCm: viewModel.isHeightCm, onHeightChanged: (newHeight) { - log("height: $newHeight"); viewModel.setHeight(newHeight, viewModel.isHeightCm); }, ), diff --git a/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart b/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart index 29baf646..e09380eb 100644 --- a/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart +++ b/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart @@ -43,10 +43,17 @@ class _HeightScaleState extends State { // Get increment based on unit (CM = 1.0, FT = 0.1) double get _increment => widget.isCm ? 1.0 : 0.1; + late final int _childCount; + @override void initState() { super.initState(); + // prepare child count and initial index using normal order (min at index 0) + _childCount = ((widget.maxValue - widget.minValue) / _increment).round() + 1; + // initialIndex should point to position of initialHeight in normal list int initialIndex = ((widget.initialHeight - widget.minValue) / _increment).round(); + if (initialIndex < 0) initialIndex = 0; + if (initialIndex >= _childCount) initialIndex = _childCount - 1; _scrollController = FixedExtentScrollController(initialItem: initialIndex); } @@ -95,19 +102,21 @@ class _HeightScaleState extends State { perspective: 0.001, physics: const BouncingScrollPhysics(), onSelectedItemChanged: (index) { + // Map index (0..n-1) to value normal: value = min + index*increment final selectedValue = widget.minValue + (index * _increment); widget.onHeightChanged?.call(selectedValue); _scheduleFeedback(); }, childDelegate: ListWheelChildBuilderDelegate( - childCount: ((widget.maxValue - widget.minValue) / _increment).round() + 1, + childCount: _childCount, builder: (context, index) { + // Displayed height value for this index (normal order) final height = widget.minValue + (index * _increment); // For CM: main mark every 10, mid mark every 5 // For FT: main mark every 1.0 (10 ticks), mid mark every 0.5 (5 ticks) - final isMainMark = widget.isCm ? height % 10 == 0 : (height * 10).round() % 10 == 0; - final isMidMark = widget.isCm ? height % 5 == 0 : (height * 10).round() % 5 == 0; + final isMainMark = widget.isCm ? height.round() % 10 == 0 : ((height * 10).round() % 10 == 0); + final isMidMark = widget.isCm ? height.round() % 5 == 0 : ((height * 10).round() % 5 == 0); return SizedBox( width: 100.w, diff --git a/lib/presentation/tele_consultation/zoom/call_screen.dart b/lib/presentation/tele_consultation/zoom/call_screen.dart index 59b5ce4c..59be70e0 100644 --- a/lib/presentation/tele_consultation/zoom/call_screen.dart +++ b/lib/presentation/tele_consultation/zoom/call_screen.dart @@ -352,43 +352,44 @@ class _CallScreenState extends State { ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf(); if (data['status'] == RecordingStatus.Start) { if (mySelf != null && !mySelf.isHost!) { - showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - content: const Text('The session is being recorded.'), - actions: [ - TextButton( - onPressed: () async { - await zoom.acceptRecordingConsent(); - if (context.mounted) { - Navigator.pop(context); - } - ; - }, - child: const Text('accept'), - ), - TextButton( - onPressed: () async { - String currentConsentType = await zoom.getRecordingConsentType(); - if (currentConsentType == ConsentType.ConsentType_Individual) { - await zoom.declineRecordingConsent(); - Navigator.pop(context); - } else { - await zoom.declineRecordingConsent(); - zoom.leaveSession(false); - if (!context.mounted) return; - Navigator.popAndPushNamed( - context, - "Join", - arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role), - ); - } - }, - child: const Text('decline'), - ), - ], - ), - ); + await zoom.acceptRecordingConsent(); + // showDialog( + // context: context, + // builder: (BuildContext context) => AlertDialog( + // content: const Text('The session is being recorded.'), + // actions: [ + // TextButton( + // onPressed: () async { + // await zoom.acceptRecordingConsent(); + // if (context.mounted) { + // Navigator.pop(context); + // } + // ; + // }, + // child: const Text('accept'), + // ), + // TextButton( + // onPressed: () async { + // String currentConsentType = await zoom.getRecordingConsentType(); + // if (currentConsentType == ConsentType.ConsentType_Individual) { + // await zoom.declineRecordingConsent(); + // Navigator.pop(context); + // } else { + // await zoom.declineRecordingConsent(); + // zoom.leaveSession(false); + // if (!context.mounted) return; + // Navigator.popAndPushNamed( + // context, + // "Join", + // arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role), + // ); + // } + // }, + // child: const Text('decline'), + // ), + // ], + // ), + // ); } isRecordingStarted.value = true; } else { @@ -1745,11 +1746,11 @@ class _CallScreenState extends State { iconSize: circleButtonSize, tooltip: isMuted.value == true ? "Unmute" : "Mute", ), - IconButton( - onPressed: onPressShare, - icon: isSharing.value ? Image.asset("assets/images/png/zoom/share-off@2x.png") : Image.asset("assets/images/png/zoom/share-on@2x.png"), - iconSize: circleButtonSize, - ), + // IconButton( + // onPressed: onPressShare, + // icon: isSharing.value ? Image.asset("assets/images/png/zoom/share-off@2x.png") : Image.asset("assets/images/png/zoom/share-on@2x.png"), + // iconSize: circleButtonSize, + // ), IconButton( onPressed: onPressVideo, iconSize: circleButtonSize, @@ -1771,35 +1772,35 @@ class _CallScreenState extends State { ], ), )), - Container( - margin: const EdgeInsets.only(left: 16, right: 16, bottom: 40, top: 10), - alignment: Alignment.bottomCenter, - child: SizedBox( - height: MediaQuery.of(context).viewInsets.bottom == 0 ? 65 : MediaQuery.of(context).viewInsets.bottom + 18, - child: TextField( - maxLines: 1, - textAlign: TextAlign.left, - style: TextStyle(color: chatTextColor), - cursorColor: chatTextColor, - textAlignVertical: TextAlignVertical.center, - controller: chatMessageController, - decoration: InputDecoration( - contentPadding: const EdgeInsets.only(left: 16, top: 10, bottom: 10, right: 16), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: chatTextColor), //<-- SEE HERE - ), - hintText: 'Type your message here...', - hintStyle: TextStyle( - fontSize: 14.0, - color: chatTextColor, - ), - ), - onSubmitted: (String str) { - sendChatMessage(str); - }, - ), - ), - ), + // Container( + // margin: const EdgeInsets.only(left: 16, right: 16, bottom: 40, top: 10), + // alignment: Alignment.bottomCenter, + // child: SizedBox( + // height: MediaQuery.of(context).viewInsets.bottom == 0 ? 65 : MediaQuery.of(context).viewInsets.bottom + 18, + // child: TextField( + // maxLines: 1, + // textAlign: TextAlign.left, + // style: TextStyle(color: chatTextColor), + // cursorColor: chatTextColor, + // textAlignVertical: TextAlignVertical.center, + // controller: chatMessageController, + // decoration: InputDecoration( + // contentPadding: const EdgeInsets.only(left: 16, top: 10, bottom: 10, right: 16), + // enabledBorder: OutlineInputBorder( + // borderSide: BorderSide(width: 1, color: chatTextColor), //<-- SEE HERE + // ), + // hintText: 'Type your message here...', + // hintStyle: TextStyle( + // fontSize: 14.0, + // color: chatTextColor, + // ), + // ), + // onSubmitted: (String str) { + // sendChatMessage(str); + // }, + // ), + // ), + // ), Container( alignment: Alignment.bottomLeft, margin: const EdgeInsets.only(bottom: 120), diff --git a/lib/presentation/todo_section/ancillary_order_payment_page.dart b/lib/presentation/todo_section/ancillary_order_payment_page.dart index fe071867..b34bf212 100644 --- a/lib/presentation/todo_section/ancillary_order_payment_page.dart +++ b/lib/presentation/todo_section/ancillary_order_payment_page.dart @@ -103,7 +103,7 @@ class _AncillaryOrderPaymentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.visaOrMastercard.tr(context: context).toText16(isBold: true).toShimmer2(isShow: todoVM.isProcessingPayment), + Image.asset(AppAssets.mada, width: 50.h, height: 50.h), SizedBox(height: 16.h), LocaleKeys.mada.tr(context: context).toText16(isBold: true).toShimmer2(isShow: todoVM.isProcessingPayment), ], @@ -468,86 +468,43 @@ class _AncillaryOrderPaymentPageState extends State { languageID: appState.isArabic() ? 1 : 2, onSuccess: (response) { LoaderBottomSheet.hideLoader(); - final invoiceNo = response['AncillaryOrderInvoiceList']?[0]?['InvoiceNo']; - _showSuccessDialog(invoiceNo); }, onError: (error) { LoaderBottomSheet.hideLoader(); todoSectionViewModel.setProcessingPayment(false); - Utils.showToast(error); + showCommonBottomSheetWithoutHeight(context, + child: Utils.getErrorWidget(loadingText: error.toString()), isCloseButtonVisible: true, isDismissible: true, isFullScreen: false, callBackFunc: () {}); }, ); } void _showSuccessDialog(dynamic invoiceNo) { todoSectionViewModel.setProcessingPayment(false); - - log("Ancillary order payment successful! Invoice #: $invoiceNo"); - // Show success message and navigate - Utils.showToast("Payment successful! Invoice #: $invoiceNo"); + // Utils.showToast("Payment successful! Invoice #: $invoiceNo"); // Navigate back to home after a short delay - Future.delayed(Duration(seconds: 1), () { - showCommonBottomSheetWithoutHeight( - context, - child: Column( - children: [ - Row( - children: [ - LocaleKeys.hereIsYourInvoiceNumber.tr(context: context).toText14( - color: AppColors.textColorLight, - weight: FontWeight.w500, - ), - SizedBox(width: 4.w), - ("12345").toText16(isBold: true), - ], - ), - SizedBox(height: 24.h), - Row( - children: [ - Expanded( - child: CustomButton( - height: 56.h, - text: LocaleKeys.ok.tr(context: context), - onPressed: () { - Navigator.pushAndRemoveUntil( - context, - CustomPageRoute( - page: LandingNavigation(), - ), - (r) => false); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - ), - ), - ], - ), - ], - ), - // title: LocaleKeys.paymentCompletedSuccessfully.tr(context: context), - titleWidget: Utils.getSuccessWidget(loadingText: LocaleKeys.paymentCompletedSuccessfully.tr(context: context)), - isCloseButtonVisible: false, - isDismissible: false, - isFullScreen: false, - ); + // Future.delayed(Duration(seconds: 1), () { + showCommonBottomSheetWithoutHeight(context, + child: Utils.getSuccessWidget(loadingText: "${LocaleKeys.paymentCompletedSuccessfully.tr(context: context)}, ${LocaleKeys.hereIsYourInvoiceNumber.tr(context: context)}$invoiceNo"), + isCloseButtonVisible: true, + isDismissible: true, + isFullScreen: false, callBackFunc: () { + // Pop until we reach the LandingPage + todoSectionViewModel.setIsAncillaryOrdersNeedReloading(true); + Navigator.pushAndRemoveUntil( + context, + CustomPageRoute( + page: LandingNavigation(), + ), + (r) => false); }); + // }); } _startApplePay() async { - showCommonBottomSheet( - context, - child: Utils.getLoadingWidget(), - callBackFunc: (str) {}, - title: "", - height: ResponsiveExtension.screenHeight * 0.3, - isCloseButtonVisible: false, - isDismissible: false, - isFullScreen: false, - ); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingApplePayDetails.tr(context: context)); final user = appState.getAuthenticatedUser(); transID = Utils.getAdvancePaymentTransID(widget.projectID, user!.patientId!); @@ -604,7 +561,7 @@ class _AncillaryOrderPaymentPageState extends State { await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest); } catch (error) { log("Apple Pay Insert Request Failed: $error"); - Navigator.of(context).pop(); + LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, child: Utils.getErrorWidget(loadingText: LocaleKeys.failedToInitializeApplePay.tr(context: context)), @@ -627,7 +584,7 @@ class _AncillaryOrderPaymentPageState extends State { currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", onFailed: (failureResult) async { log("failureResult: ${failureResult.message.toString()}"); - Navigator.of(context).pop(); + LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, child: Utils.getErrorWidget(loadingText: failureResult.message.toString()), @@ -637,7 +594,7 @@ class _AncillaryOrderPaymentPageState extends State { ); }, onSucceeded: (successResult) async { - Navigator.of(context).pop(); + LoaderBottomSheet.hideLoader(); log("successResult: ${successResult.responseMessage.toString()}"); selectedPaymentMethod = successResult.paymentOption ?? "VISA"; _checkPaymentStatus(); diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index d3fae553..1267dbb2 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts import 'package:hmg_patient_app_new/presentation/health_trackers/add_health_tracker_entry_page.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/health_tracker_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/health_trackers_page.dart'; +import 'package:hmg_patient_app_new/presentation/home/app_update_page.dart'; import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; @@ -62,6 +63,7 @@ class AppRoutes { static const String huaweiHealthExample = '/huaweiHealthExample'; static const String covid19Test = '/covid19Test'; static const String vitalSign = '/vitalSign'; + static const String appUpdate = '/appUpdate'; //appointments static const String bookAppointmentPage = '/bookAppointmentPage'; @@ -124,6 +126,9 @@ class AppRoutes { healthConvertersPage: (context) => HealthCalculatorsPage(type: HealthCalConEnum.converter), healthTrackersPage: (context) => HealthTrackersPage(), vitalSign: (context) => VitalSignPage(), + appUpdate: (context) => AppUpdatePage( + appUpdateMessage: '', + ), emergencyServicesPage: (context) => EmergencyServicesPage(), servicesPriceListPage: (context) => ServicesPriceListPage(), addHealthTrackerEntryPage: (context) { diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index 48f4159e..6347a389 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -101,14 +101,18 @@ class DialogServiceImp implements DialogService { shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), - builder: (_) => ExceptionBottomSheet( - message: message, - showCancel: onCancelPressed != null ? true : false, - onOkPressed: onOkPressed, - onCancelPressed: () { - if (onCancelPressed != null) { - Navigator.of(context).pop(); - } + builder: (_) => StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return ExceptionBottomSheet( + message: message, + showCancel: onCancelPressed != null ? true : false, + onOkPressed: onOkPressed, + onCancelPressed: () { + if (onCancelPressed != null) { + Navigator.of(context).pop(); + } + }, + ); }, ), ); @@ -181,12 +185,8 @@ class DialogServiceImp implements DialogService { textColor: AppColors.primaryRedBorderColor, height: 48.h, onPressed: () { - navigationService.pushPage( - page: FamilyMedicalScreen( - profiles: profiles, - onSelect: (FamilyFileResponseModelLists p1) {}, - ), - ); + navigationService.pop(); + navigationService.pushPage(page: FamilyMedicalScreen()); }) ], ), diff --git a/lib/splashPage.dart b/lib/splashPage.dart index 49680a2a..dc7a7c98 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -47,6 +47,7 @@ class _SplashScreenState extends State { PushNotificationHandler().init(context); // Asyncronously }, ); + // TODO: This next line should be tested. This stops the app at this step, sometimes await authVm.getServicePrivilege(); Timer(Duration(seconds: 2, milliseconds: 500), () async { bool isAppOpenedFromCall = getIt.get().getBool(key: CacheConst.isAppOpenedFromCall) ?? false; diff --git a/lib/widgets/app_language_change.dart b/lib/widgets/app_language_change.dart index e75ff6f6..1200c53b 100644 --- a/lib/widgets/app_language_change.dart +++ b/lib/widgets/app_language_change.dart @@ -103,7 +103,7 @@ class _AppLanguageChangeState extends State { }, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - title.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded, + title.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "ar" ? 'GESSTwo' : 'Poppins').expanded, ], ).paddingOnly(left: 16, right: 16).onPress(() { setState(() { diff --git a/lib/widgets/bottom_navigation/bottom_navigation.dart b/lib/widgets/bottom_navigation/bottom_navigation.dart index bbe8d81f..46067dfe 100644 --- a/lib/widgets/bottom_navigation/bottom_navigation.dart +++ b/lib/widgets/bottom_navigation/bottom_navigation.dart @@ -33,7 +33,7 @@ class BottomNavigation extends StatelessWidget { ), appState.isAuthenticated // ? BottomNavItem(icon: AppAssets.toDoBottom, label: LocaleKeys.todoList.tr(context: context)) - ? BottomNavItem(icon: AppAssets.symptomCheckerBottomIcon, fillIcon: AppAssets.symptomCheckerBottomFillIcon, label: "Symptoms") + ? BottomNavItem(icon: AppAssets.symptomCheckerBottomIcon, fillIcon: AppAssets.symptomCheckerBottomFillIcon, label: LocaleKeys.symptoms.tr(context: context)) : BottomNavItem(icon: AppAssets.news, fillIcon: AppAssets.newsFill, label: LocaleKeys.news.tr()), BottomNavItem(icon: AppAssets.servicesBottom, fillIcon: AppAssets.servicesBottomFill, label: LocaleKeys.services2.tr(context: context)), ]; diff --git a/lib/widgets/bottomsheet/exception_bottom_sheet.dart b/lib/widgets/bottomsheet/exception_bottom_sheet.dart index fe232648..16531bdb 100644 --- a/lib/widgets/bottomsheet/exception_bottom_sheet.dart +++ b/lib/widgets/bottomsheet/exception_bottom_sheet.dart @@ -10,7 +10,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; -class ExceptionBottomSheet extends StatelessWidget { +class ExceptionBottomSheet extends StatefulWidget { final String? title; final String message; final bool showOKButton; @@ -28,6 +28,11 @@ class ExceptionBottomSheet extends StatelessWidget { this.onCancelPressed, }); + @override + State createState() => _ExceptionBottomSheetState(); +} + +class _ExceptionBottomSheetState extends State { @override Widget build(BuildContext context) { return SafeArea( @@ -53,7 +58,7 @@ class ExceptionBottomSheet extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - (title ?? LocaleKeys.notice.tr()).toText28(), + (widget.title ?? LocaleKeys.notice.tr()).toText28(), InkWell( onTap: () { Navigator.of(context).pop(); @@ -66,18 +71,18 @@ class ExceptionBottomSheet extends StatelessWidget { ], ), SizedBox(height: 10.h), - (message).toText16(isBold: false, color: AppColors.textColor), + (widget.message).toText16(isBold: false, color: AppColors.textColor), SizedBox(height: 10.h), SizedBox(height: 24.h), - if (showOKButton && showCancel) + if (widget.showOKButton && widget.showCancel) Row( children: [ Expanded( child: CustomButton( height: 56.h, text: LocaleKeys.cancel.tr(), - onPressed: onCancelPressed != null - ? onCancelPressed! + onPressed: widget.onCancelPressed != null + ? widget.onCancelPressed! : () { Navigator.of(context).pop(); }, @@ -92,8 +97,8 @@ class ExceptionBottomSheet extends StatelessWidget { Expanded( child: CustomButton( height: 56.h, - text: showCancel ? LocaleKeys.confirm.tr() : LocaleKeys.ok.tr(), - onPressed: onOkPressed, + text: widget.showCancel ? LocaleKeys.confirm.tr() : LocaleKeys.ok.tr(), + onPressed: widget.onOkPressed, backgroundColor: AppColors.bgGreenColor, borderColor: AppColors.bgGreenColor, textColor: Colors.white, @@ -102,13 +107,13 @@ class ExceptionBottomSheet extends StatelessWidget { ), ], ), - if (showOKButton && !showCancel) + if (widget.showOKButton && !widget.showCancel) Padding( padding: EdgeInsets.only(bottom: 10.h), child: CustomButton( height: 56.h, text: LocaleKeys.ok.tr(), - onPressed: onOkPressed, + onPressed: widget.onOkPressed, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedBorderColor, textColor: Colors.white, diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart index fb51f28e..515d1f72 100644 --- a/lib/widgets/common_bottom_sheet.dart +++ b/lib/widgets/common_bottom_sheet.dart @@ -183,6 +183,7 @@ void showCommonBottomSheetWithoutHeight( isScrollControlled: true, showDragHandle: false, isDismissible: isDismissible, + enableDrag: isDismissible, backgroundColor: backgroundColor, useSafeArea: useSafeArea, builder: (BuildContext context) { diff --git a/lib/widgets/family_files/family_file_add_widget.dart b/lib/widgets/family_files/family_file_add_widget.dart index cd20c5f0..15751e93 100644 --- a/lib/widgets/family_files/family_file_add_widget.dart +++ b/lib/widgets/family_files/family_file_add_widget.dart @@ -14,24 +14,29 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; -class FamilyFileAddWidget extends StatelessWidget { +class FamilyFileAddWidget extends StatefulWidget { final Function()? onVerificationPress; final String message; const FamilyFileAddWidget(this.onVerificationPress, this.message, {super.key}); + @override + State createState() => _FamilyFileAddWidgetState(); +} + +class _FamilyFileAddWidgetState extends State { @override Widget build(BuildContext context) { AuthenticationViewModel authVm = getIt.get(); - MedicalFileViewModel? medicalVM = getIt.get(); // TODO: implement build return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - message.toText16(color: AppColors.textColor, weight: FontWeight.w500), + widget.message.toText16(color: AppColors.textColor, weight: FontWeight.w500), SizedBox(height: 20.h), Container( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), @@ -59,21 +64,26 @@ class FamilyFileAddWidget extends StatelessWidget { leadingIcon: AppAssets.student_card, ).paddingOnly(top: 8.h, bottom: 8.h), Divider(height: 1.h, color: AppColors.spacerLineColor), - TextInputWidget( - labelText: LocaleKeys.phoneNumber.tr(), - hintText: "", - controller: authVm.phoneNumberController, - isEnable: true, - prefix: authVm.selectedCountrySignup.countryCode, - isAllowRadius: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - autoFocus: true, - keyboardType: TextInputType.number, - fontFamily: "Poppins", - padding: EdgeInsets.symmetric(vertical: 8.h), - leadingIcon: AppAssets.smart_phone, - ).paddingOnly(top: 8.h, bottom: 4.h), + Selector( + selector: (_, model) => model.selectedCountrySignup.countryCode, + builder: (context, countryCode, child) { + return TextInputWidget( + labelText: LocaleKeys.phoneNumber.tr(), + hintText: "", + controller: authVm.phoneNumberController, + isEnable: true, + prefix: countryCode, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + autoFocus: true, + keyboardType: TextInputType.number, + fontFamily: "Poppins", + padding: EdgeInsets.symmetric(vertical: 8.h), + leadingIcon: AppAssets.smart_phone, + ).paddingOnly(top: 8.h, bottom: 4.h); + }, + ), ], ), ), @@ -91,8 +101,8 @@ class FamilyFileAddWidget extends StatelessWidget { }, )) { // authVm.addFamilyMember(otpTypeEnum: OTPTypeEnum.sms, isExcludedUser: true); - if (onVerificationPress != null) { - onVerificationPress!(); + if (widget.onVerificationPress != null) { + widget.onVerificationPress!(); } } }, diff --git a/pubspec.yaml b/pubspec.yaml index 19acdf31..01c155b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.0+1 +version: 0.0.1+3 environment: sdk: ">=3.6.0 <4.0.0" @@ -67,6 +67,7 @@ dependencies: equatable: ^2.0.7 google_api_availability: ^5.0.1 firebase_analytics: ^11.5.1 + firebase_crashlytics: ^4.3.8 jiffy: ^6.4.3 hijri_gregorian_calendar: ^0.1.1 sms_otp_auto_verify: ^2.2.0 @@ -83,6 +84,7 @@ dependencies: open_filex: ^4.7.0 flutter_swiper_view: ^1.1.8 flutter_callkit_incoming: ^3.0.0 + in_app_update: ^4.2.5 # device_preview: ^1.3.1 location: ^8.0.1