ambulance_listing_and_request #96

Merged
Haroon6138 merged 6 commits from ambulance_listing_and_request into master 4 months ago

@ -1,74 +0,0 @@
{
"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"
}
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -248,9 +248,6 @@
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng" />
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=102857389" />
<!--
Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java

@ -0,0 +1,27 @@
//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)
// }
//}

@ -0,0 +1,6 @@
package com.ejada.hmg
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity : FlutterFragmentActivity()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cloud.diplomaticquarterapp.whatsapp.WhatsAppCodeActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal">
<FrameLayout
android:id="@+id/publisher_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF9800" />
</LinearLayout>

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal">
<FrameLayout
android:id="@+id/subscriber_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#3F51B5" />
<TextView
android:text="Remote"
android:textColor="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/*,@raw/slow_spring_board" />

@ -0,0 +1,23 @@
<resources>
<string name="app_name">HMG Patient App</string>
<string name="geofence_unknown_error">
Unknown error: the Geofence service is not available now.
</string>
<string name="geofence_not_available">
Geofence service is not available now. Go to Settings>Location>Mode and choose High accuracy.
</string>
<string name="geofence_too_many_geofences">
Your app has registered too many geofences.
</string>
<string name="geofence_too_many_pending_intents">
You have provided too many PendingIntents to the addGeofences() call.
</string>
<string name="GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION">
App do not have permission to access location service.
</string>
<string name="GEOFENCE_REQUEST_TOO_FREQUENT">
Geofence requests happened too frequently.
</string>
<string name="mapbox_access_token" translatable="false">sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg</string>
</resources>

File diff suppressed because one or more lines are too long

Binary file not shown.

@ -0,0 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.88966 2.26044H6.1556C6.54339 2.26042 6.87763 2.2604 7.1452 2.29638C7.43199 2.33494 7.7069 2.42189 7.92987 2.64486C8.15285 2.86784 8.2398 3.14275 8.27836 3.42953C8.30096 3.59766 8.30936 3.79206 8.31247 4.00954C8.31248 4.01004 8.31288 4.01044 8.31338 4.01044C8.31369 4.01044 8.31396 4.0106 8.31413 4.01083C8.31413 4.01063 8.31423 4.01098 8.31413 4.01083L8.31429 6.19794C8.31429 6.43957 8.51017 6.63544 8.75179 6.63544C8.99342 6.63544 9.18929 6.43957 9.18929 6.19794V4.20362C9.18929 4.10493 9.2722 4.02578 9.37041 4.03551C9.63863 4.06206 9.88036 4.11895 10.1131 4.2507C10.3443 4.38162 10.5211 4.56074 10.6893 4.77855C10.8614 5.00128 11.0127 5.23986 11.1635 5.47761L11.164 5.4784C11.1889 5.51758 11.2137 5.55673 11.2386 5.59579C11.5034 6.01096 11.8302 6.35342 12.2362 6.63158C12.6288 6.90049 12.9411 7.11434 13.1141 7.46714C13.2034 7.64923 13.24 7.83466 13.2568 8.03171C13.2597 8.06529 13.2329 8.09377 13.1992 8.09377H12.6893C12.4477 8.09377 12.2518 8.28965 12.2518 8.53127C12.2518 8.7729 12.4477 8.96877 12.6893 8.96877H12.9207C13.0883 8.96877 13.1722 8.96877 13.2238 9.02251C13.2755 9.07625 13.2722 9.15762 13.2658 9.32036C13.2616 9.42578 13.2549 9.52356 13.244 9.61307C13.2135 9.86447 13.1447 10.1138 12.9593 10.3235C12.7687 10.5391 12.5059 10.6479 12.2248 10.6872C12.1439 10.6985 12.0789 10.625 12.0886 10.5439C12.0989 10.4578 12.1042 10.3701 12.1042 10.2813C12.1042 9.07315 11.1249 8.09377 9.91675 8.09377C8.71731 8.09377 7.72602 9.09672 7.72928 10.2935C7.73046 10.5082 7.73105 10.6156 7.67973 10.6672C7.62842 10.7188 7.53389 10.7188 7.34482 10.7188H6.65534C6.46628 10.7188 6.37175 10.7188 6.32043 10.6672C6.26912 10.6156 6.26971 10.5082 6.27088 10.2935C6.27415 9.09672 5.28286 8.09377 4.08342 8.09377C2.87529 8.09377 1.89592 9.07315 1.89592 10.2813C1.89592 10.4083 1.90675 10.5328 1.92753 10.6539C1.93036 10.6704 1.9166 10.6851 1.90005 10.6828C1.61327 10.6443 1.33836 10.5573 1.11539 10.3344C0.892408 10.1114 0.805457 9.83647 0.766899 9.54969C0.730924 9.28211 0.73094 8.94798 0.730958 8.56018V4.41914C0.73094 4.03135 0.730924 3.69711 0.766899 3.42953C0.805457 3.14275 0.892408 2.86784 1.11539 2.64486C1.33836 2.42189 1.61327 2.33494 1.90005 2.29638C2.16763 2.2604 2.50187 2.26042 2.88966 2.26044ZM5.10596 4.44794C5.10596 4.20631 4.91008 4.01044 4.66846 4.01044C4.42683 4.01044 4.23096 4.20631 4.23096 4.44794V5.17711H3.50179C3.26017 5.17711 3.06429 5.37298 3.06429 5.61461C3.06429 5.85623 3.26017 6.05211 3.50179 6.05211H4.23096V6.78127C4.23096 7.0229 4.42683 7.21877 4.66846 7.21877C4.91008 7.21877 5.10596 7.0229 5.10596 6.78127V6.05211H5.83513C6.07675 6.05211 6.27263 5.85623 6.27263 5.61461C6.27263 5.37298 6.07675 5.17711 5.83513 5.17711H5.10596V4.44794Z" fill="#2E3039"/>
<path d="M11.3757 10.2813C11.3757 11.0867 10.7227 11.7396 9.91732 11.7396C9.1119 11.7396 8.45898 11.0867 8.45898 10.2813C8.45898 9.47586 9.1119 8.82294 9.91732 8.82294C10.7227 8.82294 11.3757 9.47586 11.3757 10.2813Z" fill="#2E3039"/>
<path d="M4.08399 11.7396C4.8894 11.7396 5.54232 11.0867 5.54232 10.2813C5.54232 9.47586 4.8894 8.82294 4.08399 8.82294C3.27857 8.82294 2.62565 9.47586 2.62565 10.2813C2.62565 11.0867 3.27857 11.7396 4.08399 11.7396Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -0,0 +1,4 @@
<svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 2.85449C3.79188 2.85449 2.8125 3.83387 2.8125 5.04199C2.8125 6.25011 3.79188 7.22949 5 7.22949C6.20812 7.22949 7.1875 6.25011 7.1875 5.04199C7.1875 3.83387 6.20812 2.85449 5 2.85449ZM3.6875 5.04199C3.6875 4.31712 4.27513 3.72949 5 3.72949C5.72487 3.72949 6.3125 4.31712 6.3125 5.04199C6.3125 5.76687 5.72487 6.35449 5 6.35449C4.27513 6.35449 3.6875 5.76687 3.6875 5.04199Z" fill="#ED1C2B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 0.229492C2.38798 0.229492 0.1875 2.42783 0.1875 5.09268C0.1875 7.8228 2.43772 9.64709 4.31579 10.8329L4.32334 10.8377L4.33107 10.8422C4.5346 10.9593 4.76514 11.0212 5 11.0212C5.23486 11.0212 5.4654 10.9593 5.66893 10.8422L5.67567 10.8383L5.68227 10.8342C7.56769 9.65737 9.8125 7.81358 9.8125 5.09268C9.8125 2.42783 7.61202 0.229492 5 0.229492ZM1.0625 5.09268C1.0625 2.90553 2.87676 1.10449 5 1.10449C7.12324 1.10449 8.9375 2.90553 8.9375 5.09268C8.9375 7.29808 7.10717 8.91207 5.22662 10.0871C5.15694 10.1259 5.079 10.1462 5 10.1462C4.92132 10.1462 4.84369 10.1261 4.77422 10.0876C2.89372 8.89884 1.0625 7.30546 1.0625 5.09268Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -455,6 +455,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
@ -467,6 +469,7 @@
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@ -638,6 +641,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
@ -650,6 +655,7 @@
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@ -664,6 +670,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
@ -676,6 +684,7 @@
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@ -693,7 +702,7 @@
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
@ -703,7 +712,7 @@
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
@ -713,7 +722,7 @@
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};

@ -2,13 +2,14 @@ import Flutter
import UIKit
import FirebaseCore
import FirebaseMessaging
import GoogleMaps
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)

@ -44,9 +44,9 @@ var PHARMACY_REDIRECT_URL = 'https://bit.ly/AlhabibPharmacy';
// var PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapitest/api/';
// RC API URL
var RC_BASE_URL = 'https://rc.hmg.com/';
// var RC_BASE_URL = 'https://rc.hmg.com/';
// var RC_BASE_URL = 'https://rc.hmg.com/test/';
var RC_BASE_URL = 'https://rc.hmg.com/uat/';
// var RC_BASE_URL = 'https://ms.hmg.com/rc/';
@ -719,7 +719,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -25,6 +25,7 @@ class AppAssets {
static const String download = '$svgBasePath/download.svg';
static const String language = '$svgBasePath/language.svg';
static const String location = '$svgBasePath/location.svg';
static const String pin_location = '$svgBasePath/pin_location.svg';
static const String whatsapp = '$svgBasePath/whatsapp.svg';
static const String card_user = '$svgBasePath/card_user.svg';
static const String habiblogo = '$svgBasePath/habiblogo.svg';
@ -156,6 +157,7 @@ class AppAssets {
static const String activeCheck = '$svgBasePath/active-check.svg';
static const String deleteIcon = '$svgBasePath/delete_icon.svg';
static const String call_ambulance_icon = '$svgBasePath/call_ambulance_icon.svg';
static const String ambulance = '$svgBasePath/ambulance.svg';
static const String nearest_er_icon = '$svgBasePath/nearest_er_icon.svg';
static const String rrt_icon = '$svgBasePath/rrt_icon.svg';
static const String waiting_time_clock = '$svgBasePath/waiting_time_clock.svg';

@ -56,12 +56,12 @@ class AppState {
}
FutureOr<void> checkIfGMSAvailableOrNot() async {
isGMSAvailable = (await GmsCheck().checkGmsAvailability()) ?? true;
if(Platform.isIOS) {
isGMSAvailable = false;
isGMSAvailable = true;
isAndroid = false;
return;
}
isGMSAvailable = (await GmsCheck().checkGmsAvailability()) ?? true;
}
AuthenticatedUser? getAuthenticatedUser({bool isFamily = false}) {

@ -21,6 +21,8 @@ import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/location/location_repo.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
@ -108,6 +110,8 @@ class AppDependencies {
getIt.registerLazySingleton<ImmediateLiveCareRepo>(() => ImmediateLiveCareRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<EmergencyServicesRepo>(() => EmergencyServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<TodoSectionRepo>(() => TodoSectionRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<LocationRepo>(
() => LocationRepoImpl(apiClient: getIt()));
getIt.registerLazySingleton<ContactUsRepo>(() => ContactUsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
@ -216,6 +220,15 @@ class AppDependencies {
emergencyServicesRepo: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
appointmentRepo: getIt(),
dialogService: getIt()
),
);
getIt.registerLazySingleton<LocationViewModel>(
() => LocationViewModel(
locationRepo: getIt(),
errorHandlerService: getIt(),
),
);

@ -6,7 +6,11 @@ class DateUtil {
/// convert String To Date function
/// [date] String we want to convert
static DateTime convertStringToDate(String? date) {
if (date != null) {
print("the date is $date");
if (date == null) return DateTime.now();
if (date.isEmpty) return DateTime.now();
const start = "/Date(";
const end = "+0300)";
final startIndex = date.indexOf(start);
@ -14,9 +18,7 @@ class DateUtil {
return DateTime.fromMillisecondsSinceEpoch(int.parse(
date.substring(startIndex + start.length, endIndex),
));
} else {
return DateTime.now();
}
}
static DateTime convertStringToDateSaudiTimezone(String date, int projectId) {

@ -102,6 +102,12 @@ class Utils {
? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString()
: getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString();
}
static String getDayMonthYearDateFormatted(DateTime? dateTime) {
if(dateTime == null ) return "";
return appState.isArabic()
? "${dateTime.day.toString()} ${getMonthArabic(dateTime.month)}, ${dateTime.year.toString()}"
: "${dateTime.day.toString()} ${getMonth(dateTime.month)}, ${dateTime.year.toString()}";
}
/// get month by
/// [month] convert month number in to month name
@ -749,10 +755,14 @@ class Utils {
static Widget getPaymentAmountWithSymbol2(num habibWalletAmount,
{double iconSize = 14,
Color iconColor = AppColors.textColor,
double? fontSize,
double? letterSpacing,
FontWeight? fontWeight,
Color iconColor = AppColors.textColor,
Color textColor = AppColors.blackColor,
bool isSaudiCurrency = true,
bool isExpanded = true}) {
bool isExpanded = true,
}) {
return RichText(
maxLines: 1,
text: TextSpan(
@ -763,8 +773,13 @@ class Utils {
child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: iconColor),
),
TextSpan(
text: " $habibWalletAmount",
style: TextStyle(color: textColor, fontSize: 32.f, letterSpacing: -4, fontWeight: FontWeight.w600, height: 1),
text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount),
style: TextStyle(
color: textColor,
fontSize: fontSize ?? 32.f,
letterSpacing: letterSpacing??-4,
fontWeight: fontWeight ?? FontWeight.w600,
height: 1),
),
],
),
@ -838,4 +853,7 @@ class Utils {
}
return isHavePrivilege;
}
}

@ -279,11 +279,11 @@ extension EmailValidator on String {
height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight}) => Text(
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing??-1, fontWeight: isBold ? FontWeight.bold : fontWeight??FontWeight.normal),
);
Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text(

@ -245,6 +245,7 @@ class AuthenticationViewModel extends ChangeNotifier {
}
Future<void> _handleNewImeiRegistration() async {
await selectDeviceImei(onSuccess: (dynamic respData) async {
try {
if (respData != null) {

@ -7,12 +7,16 @@ 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/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'models/resp_model/PatientERTransportationMethod.dart';
abstract class EmergencyServicesRepo {
Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures();
@ -37,6 +41,16 @@ abstract class EmergencyServicesRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getProjectIDFromNFC({required String nfcCode});
Future<Either<Failure, GenericApiModel<dynamic>>> autoGenerateInvoiceERClinic({required int projectID});
Future<Either<Failure, GenericApiModel<List<PatientERTransportationMethod>>>> getTransportationMethods({int? id});
Future<Either<Failure, GenericApiModel<bool>>> submitAmbulanceRequest(PatientER_RC request);
Future<Either<Failure, GenericApiModel<List<AmbulanceRequestOrdersModel>>>> getTransportationOrders({int? id});
Future<Either<Failure, GenericApiModel<bool>>> cancelOrder(int? iD, int patientId);
}
class EmergencyServicesRepoImp implements EmergencyServicesRepo {
@ -121,27 +135,28 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo {
}
@override
Future<Either<Failure, GenericApiModel>> checkPatientERAdvanceBalance() async {
Map<String, dynamic> mapDevice = {"ClinicID": 10};
Future<Either<Failure, GenericApiModel<List<PatientERTransportationMethod>>>> getTransportationMethods({int? id}) async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<dynamic>? apiResponse;
GenericApiModel<List<PatientERTransportationMethod>>? apiResponse;
Failure? failure;
await apiClient.post(
CHECK_PATIENT_ER_ADVANCE_BALANCE,
body: mapDevice,
await apiClient.get(
"$GET_ALL_TRANSPORTATIONS_RC?patientID=$id",
isRCService: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final bool patientHasERBalance = response['BalanceAmount'] > 0;
print(patientHasERBalance);
apiResponse = GenericApiModel<dynamic>(
final list = response['response']['transportationservices'];
final proceduresList = list.map((item) => PatientERTransportationMethod.fromJson(item as Map<String, dynamic>)).toList().cast<PatientERTransportationMethod>();
apiResponse = GenericApiModel<List<PatientERTransportationMethod>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: patientHasERBalance,
data: proceduresList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
@ -194,6 +209,151 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo {
}
}
@override
Future<Either<Failure, GenericApiModel<bool>>> submitAmbulanceRequest(PatientER_RC request) async {
try {
GenericApiModel<bool>? apiResponse;
Failure? failure;
await apiClient.post(
body: request.toJson(),
INSERT_TRANSPORTATION_ORDER_RC,
isRCService: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<bool>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: true,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<AmbulanceRequestOrdersModel>>>> getTransportationOrders({int? id}) async {
try {
GenericApiModel<List<AmbulanceRequestOrdersModel>>? apiResponse;
Failure? failure;
await apiClient.post(
body: {},
"$GET_ALL_TRANSPORTATIONS_ORDERS?patientID=$id",
isRCService: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['response'];
final proceduresList = list.map((item) => AmbulanceRequestOrdersModel.fromJson(item as Map<String, dynamic>)).toList().cast<AmbulanceRequestOrdersModel>();
apiResponse = GenericApiModel<List<AmbulanceRequestOrdersModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: proceduresList,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<bool>>> cancelOrder(int? iD, int patientID) async {
try {
GenericApiModel<bool>? apiResponse;
Map<String, dynamic> request = {};
request['Id'] = iD;
request['StatusId'] = 6;
request['ClickButton'] = 14;
request['PatientID'] = patientID;
Failure? failure;
await apiClient.post(
body: request,
CANCEL_AMBULANCE_REQUEST,
isRCService: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<bool>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: true,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel>> checkPatientERAdvanceBalance() async {
Map<String, dynamic> mapDevice = {"ClinicID": 10};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
CHECK_PATIENT_ER_ADVANCE_BALANCE,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final bool patientHasERBalance = response['BalanceAmount'] > 0;
print(patientHasERBalance);
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: patientHasERBalance,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<EROnlineCheckInPaymentDetailsResponse>>> checkPatientERPaymentInformation({int? projectID}) async {
Map<String, dynamic> mapDevice = {"ClinicID": 10, "ProjectID": projectID ?? 0};

@ -4,32 +4,70 @@ import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/doctor_response_mapper.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart'
show PatientERTransportationMethod;
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart' show PlaceDetails;
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_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/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/requesting_services_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart' show AppRoutes;
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/expandable_bottom_sheet/model/BottomSheetType.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:huawei_map/huawei_map.dart' as HMSCameraServices;
import 'package:url_launcher/url_launcher.dart';
import '../location/GeocodeResponse.dart';
import 'models/ambulance_direction.dart';
class EmergencyServicesViewModel extends ChangeNotifier {
EmergencyServicesRepo emergencyServicesRepo;
MyAppointmentsRepo appointmentRepo;
ErrorHandlerService errorHandlerService;
DialogService dialogService;
Completer<GMSMapServices.GoogleMapController>? gmsController;
Completer<HMSCameraServices.HuaweiMapController>? hmsController;
final NavigationService navServices;
final LocationUtils? locationUtils;
final AppState appState;
TextEditingController searchController = TextEditingController();
//loading variables
bool isERListLoading = false;
bool isTransportationOptionsLoading = false;
List<ProjectAvgERWaitingTime> nearestERList = [];
List<ProjectAvgERWaitingTime> nearestERFilteredList = [];
@ -44,6 +82,14 @@ class EmergencyServicesViewModel extends ChangeNotifier {
int hmgCount = 0;
int hmcCount = 0;
bool pickupFromInsideTheLocation = true;
List<PatientAppointmentHistoryResponseModel>? appointments;
List<AmbulanceRequestOrdersModel>? orders = [];
//ambulance selection data section
List<PatientERTransportationMethod> transportationOptions = [];
PatientERTransportationMethod? selectedTransportOption;
AmbulanceCallingPlace callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL;
AmbulanceDirection ambulanceDirection = AmbulanceDirection.ONE_WAY;
late RRTProceduresResponseModel selectedRRTProcedure;
@ -58,23 +104,34 @@ class EmergencyServicesViewModel extends ChangeNotifier {
notifyListeners();
}
get isGMSAvailable
{
return appState.isGMSAvailable;
}
EmergencyServicesViewModel({
required this.emergencyServicesRepo,
required this.errorHandlerService,
required this.navServices,
required this.locationUtils,
required this.appState,
required this.appointmentRepo,
required this.dialogService,
});
bool get isArabic => appState.isArabic();
get isGMSAvailable => appState.isGMSAvailable;
void setIsERBookAppointment(bool value) {
isERBookAppointment = value;
notifyListeners();
}
bool get isArabic => appState.isArabic();
bool haveAnAppointment = false;
PatientAppointmentHistoryResponseModel? appointment;
bool isMyAppointmentsLoading = false;
Future<void> getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async {
RRTProceduresList.clear();
notifyListeners();
@ -186,84 +243,33 @@ class EmergencyServicesViewModel extends ChangeNotifier {
//todo_section handle the camera moved position for HMS devices
}
FutureOr<void> getProjects() async {
// if (hospitalList.isNotEmpty) return;
var response = await emergencyServicesRepo.getProjectList();
response.fold(
(failure) async {},
(apiResponse) async {
List<HospitalsModel>? data = apiResponse.data;
if (data == null) return;
hospitalList = data;
hmgHospitalList = data.where((e) => e.isHMC == false).toList();
hmcHospitalList = data.where((e) => e.isHMC == true).toList();
hmgCount = hmgHospitalList?.length ?? 0;
hmcCount = hmcHospitalList?.length ?? 0;
notifyListeners();
},
);
}
setSelectedFacility(FacilitySelection selection) {
selectedFacility = selection;
notifyListeners();
}
searchHospitals(String query) {
if (query.isEmpty) {
getDisplayList();
return;
}
List<HospitalsModel>? sourceList;
switch (selectedFacility) {
case FacilitySelection.ALL:
sourceList = hospitalList;
break;
case FacilitySelection.HMG:
sourceList = hmgHospitalList;
break;
case FacilitySelection.HMC:
sourceList = hmcHospitalList;
break;
}
displayList = sourceList?.where((hospital) => hospital.name != null && hospital.name!.toLowerCase().contains(query.toLowerCase())).toList();
notifyListeners();
}
getDisplayList() {
switch (selectedFacility) {
case FacilitySelection.ALL:
displayList = hospitalList;
break;
case FacilitySelection.HMG:
displayList = hmgHospitalList;
break;
case FacilitySelection.HMC:
displayList = hmcHospitalList;
break;
}
notifyListeners();
}
void setSelectedHospital(HospitalsModel? hospital) {
selectedHospital = hospital;
notifyListeners();
}
String? getSelectedHospitalName() {
return selectedHospital?.getName(isArabic);
}
void navigateTOAmbulancePage() {
locationUtils!.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) {
updateBottomSheetState(BottomSheetType.FIXED);
navServices.push(
CustomPageRoute(page: CallAmbulancePage(), direction: AxisDirection.down),
);
});
placeValueInController();
getProjects();
flushData();
selectedFacility = FacilitySelection.ALL;
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated) {
locationUtils!.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) {
updateBottomSheetState(BottomSheetType.FIXED);
navServices.push(
CustomPageRoute(
page: CallAmbulancePage(), direction: AxisDirection.down),
);
});
} else {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
onOkPressed: () {
navServices.pop();
navServices.pushAndReplace(
AppRoutes.loginScreen
);
});
}
}
void navigateToEROnlineCheckIn() {
@ -279,27 +285,33 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
void updateBottomSheetState(BottomSheetType sheetType) {
if (sheetType == BottomSheetType.EXPANDED && selectedHospital == null) {
dialogService.showErrorBottomSheet(message: "Kindly Select Hospital".needTranslation);
return;
}
bottomSheetType = sheetType;
if (sheetType == BottomSheetType.EXPANDED) {
clearAppointmentData();
}
notifyListeners();
}
void setIsGMSAvailable(bool value) {
notifyListeners();
}
Future<void> checkPatientERAdvanceBalance({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.checkPatientERAdvanceBalance();
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
(failure) {
patientHasAdvanceERBalance = false;
isERBookAppointment = true;
if (onSuccess != null) {
onSuccess(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
patientHasAdvanceERBalance = false;
@ -320,12 +332,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
final result = await emergencyServicesRepo.checkPatientERPaymentInformation(projectID: selectedHospital!.iD);
result.fold(
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
@ -347,12 +359,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
paymentReference: paymentReference);
result.fold(
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
// erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
@ -370,8 +382,8 @@ class EmergencyServicesViewModel extends ChangeNotifier {
final result = await emergencyServicesRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@ -389,12 +401,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.errorMessage!);
@ -414,12 +426,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.data["InvoiceResponse"]["Message"]);
@ -434,4 +446,401 @@ class EmergencyServicesViewModel extends ChangeNotifier {
},
);
}
Future<void> getTransportationOption() async {
//handle the cache if the data is present then dont fetch it in the authenticated lifecycle
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated == false) {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
onOkPressed: () {
navServices.pop();
print("inside the ok button");
getIt<AuthenticationViewModel>().onLoginPressed();
});
return;
}
if (transportationOptions.isNotEmpty) return;
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(
loadingText: "Getting Ambulance Transport Option".needTranslation);
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
response.fold(
(failure) async {
LoaderBottomSheet.hideLoader();
},
(apiResponse) {
transportationOptions = apiResponse.data!;
LoaderBottomSheet.hideLoader();
notifyListeners();
},
);
}
Future<void> getTransportationMethods() async {
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(
loadingText: "Getting Ambulance Transport Option".needTranslation);
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
response.fold(
(failure) async {
LoaderBottomSheet.hideLoader();
},
(apiResponse) {
transportationOptions = apiResponse.data!;
LoaderBottomSheet.hideLoader();
notifyListeners();
},
);
}
void setTransportationOption(PatientERTransportationMethod item) {
selectedTransportOption = item;
}
void updateCallingPlace(AmbulanceCallingPlace? value) {
callingPlace = value!;
notifyListeners();
}
void updateDirection(AmbulanceDirection? value) {
ambulanceDirection = value!;
notifyListeners();
}
void placeValueInController() {
if (isGMSAvailable) {
gmsController = Completer<GMSMapServices.GoogleMapController>();
} else {
hmsController = Completer<HMSCameraServices.HuaweiMapController>();
}
}
void moveController(Location location) {
if (isGMSAvailable) {
gmsController?.future.then((controller) {
controller.animateCamera(
GMSMapServices.CameraUpdate.newCameraPosition(
GMSMapServices.CameraPosition(
target: GMSMapServices.LatLng(location.lat, location.lng),
zoom: 18,
),
),
);
});
} else {
hmsController?.future.then((controller) {
controller.animateCamera(
HMSCameraServices.CameraUpdate.newCameraPosition(
HMSCameraServices.CameraPosition(
target: HMSCameraServices.LatLng(location.lat, location.lng),
zoom: 18,
),
),
);
});
}
}
void moveToCurrentLocation() {
moveController(Location(lat: appState.userLat, lng: appState.userLong));
}
FutureOr<void> getProjects() async {
// if (hospitalList.isNotEmpty) return;
var response = await emergencyServicesRepo.getProjectList();
response.fold(
(failure) async {},
(apiResponse) async {
List<HospitalsModel>? data = apiResponse.data;
if (data == null) return;
hospitalList = data;
hmgHospitalList = data.where((e) => e.isHMC == false).toList();
hmcHospitalList = data.where((e) => e.isHMC == true).toList();
hmgCount = hmgHospitalList?.length ?? 0;
hmcCount = hmcHospitalList?.length ?? 0;
getDisplayList();
notifyListeners();
},
);
}
setSelectedFacility(FacilitySelection selection) {
selectedFacility = selection;
notifyListeners();
}
searchHospitals(String query) {
if (query.isEmpty) {
getDisplayList();
return;
}
List<HospitalsModel>? sourceList;
switch (selectedFacility) {
case FacilitySelection.ALL:
sourceList = hospitalList;
break;
case FacilitySelection.HMG:
sourceList = hmgHospitalList;
break;
case FacilitySelection.HMC:
sourceList = hmcHospitalList;
break;
}
displayList = sourceList
?.where((hospital) =>
hospital.name != null &&
hospital.name!.toLowerCase().contains(query.toLowerCase()))
.toList();
notifyListeners();
}
getDisplayList() {
switch (selectedFacility) {
case FacilitySelection.ALL:
displayList = hospitalList;
break;
case FacilitySelection.HMG:
displayList = hmgHospitalList;
break;
case FacilitySelection.HMC:
displayList = hmcHospitalList;
break;
}
notifyListeners();
}
void setSelectedHospital(HospitalsModel? hospital) {
selectedHospital = hospital;
notifyListeners();
}
String? getSelectedHospitalName() {
return selectedHospital?.getName(isArabic);
}
void updateThePickupPlaceFromLocation(bool value) {
pickupFromInsideTheLocation = value;
notifyListeners();
}
void flushData() {
selectedHospital = null;
displayList = hospitalList;
selectedFacility = FacilitySelection.ALL;
pickupFromInsideTheLocation = false;
haveAnAppointment = false;
appointment = null;
notifyListeners();
}
void clearAppointmentData() {
haveAnAppointment = false;
appointment = null;
notifyListeners();
}
void flushPickupInformation() {
ambulanceDirection = AmbulanceDirection.ONE_WAY;
callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL;
notifyListeners();
}
num getTotalPrice() {
print("the ambulance direction is $ambulanceDirection");
switch (ambulanceDirection) {
case AmbulanceDirection.ONE_WAY:
return selectedTransportOption?.priceTotal ?? 0;
case AmbulanceDirection.TWO_WAY:
return (selectedTransportOption?.priceTotal ?? 0) * 2;
}
}
Future<void> updateAppointment(bool value) async {
if (value) {
await getAppointments();
} else {
clearAppointmentData();
}
if(appointments?.isNotEmpty == true) {
haveAnAppointment = value;
}
notifyListeners();
}
Future<void> getAppointments() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Appointment".needTranslation);
var result = await appointmentRepo.getPatientAppointments(isActiveAppointment: true, isArrivedAppointments: false);
LoaderBottomSheet.hideLoader();
result.fold((failure) {
haveAnAppointment = false;
notifyListeners();
errorHandlerService.handleError(failure: failure);
}, (response) {
appointments = response.data;
if (appointments?.isEmpty == true) {
haveAnAppointment = false;
dialogService.showErrorBottomSheet(message: "Unable to Fetch Appointment");
}
notifyListeners();
});
}
void setSelectedAppointment(PatientAppointmentHistoryResponseModel selectedAppointment) {
appointment = selectedAppointment;
notifyListeners();
}
void checkHasAppointment() {
if (appointment == null) {
haveAnAppointment = false;
}
notifyListeners();
}
FutureOr<void> submitAmbulanceRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) async {
PatientER_RC request = createRequest(result, place, placePrediction);
navServices.push(CustomPageRoute(page: RequestingServicesPage()));
var response = await emergencyServicesRepo.submitAmbulanceRequest(request);
response.fold((failure) {
navServices.pushAndRemoveUntil(
CustomPageRoute(
page: TrackingScreen(
state: OrderTrackingState.failed,
)),
ModalRoute.withName("/EmergencyServicesPage"));
}, (success) {
getTransportationOrders(shouldNavigateToTrackingScreen: true);
});
}
Future<void> getTransportationOrders({bool shouldNavigateToTrackingScreen = false, bool showLoader = false}) async {
if(shouldNavigateToTrackingScreen == false && showLoader ) {
LoaderBottomSheet.showLoader(loadingText: "Fetching Orders");
}
int? id = appState.getAuthenticatedUser()?.patientId;
var response = await emergencyServicesRepo.getTransportationOrders(id: id);
if(shouldNavigateToTrackingScreen == false && showLoader ) {
LoaderBottomSheet.hideLoader();}
response.fold(
(failure) async {
if (shouldNavigateToTrackingScreen) {
navServices.pushAndRemoveUntil(CustomPageRoute(page: TrackingScreen(state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage"));
}
},
(apiResponse) {
if (shouldNavigateToTrackingScreen) {
navServices.pushAndRemoveUntil(
CustomPageRoute(
page: TrackingScreen(
state: OrderTrackingState.waitingForCall,
order: apiResponse.data?.firstWhere((element) => element.statusId == 1),
)),
ModalRoute.withName("/EmergencyServicesPage"));
}
orders = apiResponse.data;
notifyListeners();
},
);
}
PatientER_RC createRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) {
PatientER_RC request = PatientER_RC();
TransportationDetails transportationDetails = TransportationDetails();
transportationDetails.requesterIsOutSA = false;
transportationDetails.pickupSpot = pickupFromInsideTheLocation ? 1 : 0;
transportationDetails.tripType = ambulanceDirection == AmbulanceDirection.ONE_WAY ? 0 : 1;
transportationDetails.ambulate = (transportationOptions.indexOf(selectedTransportOption!) + 1);
transportationDetails.transportationType = selectedTransportOption?.iD.toString() ?? "";
request.patientERTransportationMethod = selectedTransportOption;
transportationDetails.pickupUrgency = 1;
switch (callingPlace) {
case AmbulanceCallingPlace.FROM_HOSPITAL:
transportationDetails.dropoffLatitude = selectedHospital!.latitude;
transportationDetails.dropoffLongitude = selectedHospital!.longitude;
transportationDetails.dropoffLocationName = selectedHospital!.name;
transportationDetails.pickupLatitude = ((result?.geometry.location.lat) ?? place?.lat)?.toStringAsFixed(6);
transportationDetails.pickupLongitude = ((result?.geometry.location.lng) ?? place?.lng)?.toStringAsFixed(6);
transportationDetails.pickupLocationName = result?.formattedAddress ?? placePrediction?.description;
transportationDetails.direction = 1;
break;
case AmbulanceCallingPlace.TO_HOSPITAL:
transportationDetails.pickupLatitude = selectedHospital!.latitude;
transportationDetails.pickupLongitude = selectedHospital!.longitude;
transportationDetails.pickupLocationName = selectedHospital!.name;
transportationDetails.dropoffLatitude = ((result?.geometry.location.lat) ?? place?.lat)?.toStringAsFixed(6);
transportationDetails.dropoffLongitude = ((result?.geometry.location.lng) ?? place?.lng)?.toStringAsFixed(6);
transportationDetails.dropoffLocationName = result?.formattedAddress ?? placePrediction?.description;
transportationDetails.direction = 0;
break;
}
AuthenticatedUser? user = appState.getAuthenticatedUser();
if (user == null) throw Exception("Authentication Required to Continue");
request.patientIdentificationID = user.patientIdentificationNo;
request.projectID = user.projectId;
request.patientID = user.patientId;
transportationDetails.requesterIsOutSA = false;
transportationDetails.requesterMobileNo = user.mobileNumber;
transportationDetails.requesterFileNo = user.patientId;
transportationDetails.pickupDateTime = DateUtil.convertDateToStringLocation(DateTime.now());
if (haveAnAppointment) {
transportationDetails.appointmentNo = appointment!.appointmentNo.toString();
transportationDetails.appointmentClinicName = appointment!.clinicName;
transportationDetails.appointmentDoctorName = appointment!.doctorNameObj;
transportationDetails.appointmentBranch = appointment!.projectName;
transportationDetails.appointmentTime = appointment!.appointmentDate;
transportationDetails.haveAppointment = 1;
transportationDetails.dropoffLatitude = appointment!.latitude;
transportationDetails.dropoffLongitude = appointment!.longitude;
transportationDetails.dropoffLocationName = appointment!.projectName;
}
transportationDetails.pickupSpot = pickupFromInsideTheLocation ? 1 : 0;
transportationDetails.ambulate = 3;
transportationDetails.ambulateTitle = "none";
transportationDetails.notes = "";
request.transportationDetails = transportationDetails;
return request;
}
void clearSearchText() {
searchController.clear();
}
Future<void> cancelOrder(AmbulanceRequestOrdersModel? order, {bool shouldPop = false}) async {
dialogService.showCommonBottomSheetWithoutH(
message: "Do you want to cancel the order".needTranslation,
onOkPressed: () async {
navServices.pop();
LoaderBottomSheet.showLoader(loadingText: "Cancelling Order".needTranslation);
var response = await emergencyServicesRepo.cancelOrder(order?.iD, appState.getAuthenticatedUser()?.patientId ?? 0);
LoaderBottomSheet.hideLoader();
response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
getTransportationOrders();
if (shouldPop) navServices.pop();
});
},
onCancelPressed: () {
navServices.pop();
});
}
}

@ -0,0 +1,4 @@
enum AmbulanceCallingPlace{
FROM_HOSPITAL,
TO_HOSPITAL
}

@ -0,0 +1,3 @@
enum AmbulanceDirection{
ONE_WAY, TWO_WAY
}

@ -0,0 +1,205 @@
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart' show PatientERTransportationMethod;
class PatientER_RC {
double? versionID;
int? channel;
int? languageID;
String? iPAdress;
String? generalid;
bool? patientOutSA;
String? sessionID;
bool? isDentalAllowedBackend;
int? deviceTypeID;
int? patientID;
String? tokenID;
int? patientTypeID;
int? patientType;
int? orderServiceID;
String? patientIdentificationID;
dynamic patientOutSa;
int? projectID;
int? lineItemNo;
TransportationDetails? transportationDetails;
PatientERTransportationMethod? patientERTransportationMethod;
PatientER_RC(
{this.versionID,
this.channel,
this.languageID,
this.iPAdress,
this.generalid,
this.patientOutSA,
this.sessionID,
this.isDentalAllowedBackend,
this.deviceTypeID,
this.patientID,
this.tokenID,
this.patientTypeID,
this.patientType,
this.orderServiceID,
this.patientIdentificationID,
this.patientOutSa,
this.projectID,
this.lineItemNo,
this.transportationDetails });
PatientER_RC.fromJson(Map<String, dynamic> json) {
versionID = json['VersionID'];
channel = json['Channel'];
languageID = json['LanguageID'];
iPAdress = json['IPAdress'];
generalid = json['generalid'];
patientOutSA = json['PatientOutSA'];
sessionID = json['SessionID'];
isDentalAllowedBackend = json['isDentalAllowedBackend'];
deviceTypeID = json['DeviceTypeID'];
patientID = json['PatientID'];
tokenID = json['TokenID'];
patientTypeID = json['PatientTypeID'];
patientType = json['PatientType'];
orderServiceID = json['OrderServiceID'];
patientIdentificationID = json['PatientIdentificationID'];
patientOutSa = json['patientOutSa'];
projectID = json['projectID'];
lineItemNo = json['lineItemNo'];
transportationDetails = json['transportationDetails'] != null
? new TransportationDetails.fromJson(json['transportationDetails'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['VersionID'] = this.versionID;
data['Channel'] = this.channel;
data['LanguageID'] = this.languageID;
data['IPAdress'] = this.iPAdress;
data['generalid'] = this.generalid;
data['PatientOutSA'] = this.patientOutSA;
data['SessionID'] = this.sessionID;
data['isDentalAllowedBackend'] = this.isDentalAllowedBackend;
data['DeviceTypeID'] = this.deviceTypeID;
data['PatientID'] = this.patientID;
data['TokenID'] = this.tokenID;
data['PatientTypeID'] = this.patientTypeID;
data['PatientType'] = this.patientType;
data['OrderServiceID'] = this.orderServiceID;
data['PatientIdentificationID'] = this.patientIdentificationID;
data['patientOutSa'] = this.patientOutSa;
data['projectID'] = this.projectID;
data['lineItemNo'] = this.lineItemNo;
if (this.transportationDetails != null) {
data['transportationDetails'] = this.transportationDetails!.toJson();
}
return data;
}
}
class TransportationDetails {
int? direction;
int? haveAppointment;
int? tripType;
int? pickupUrgency;
int? pickupSpot;
String? pickupDateTime;
String? transportationType;
int? ambulate;
String? ambulateTitle;
String? notes;
int? requesterFileNo;
String? requesterMobileNo;
bool? requesterIsOutSA;
String? pickupLocationName;
String? dropoffLocationName;
String? pickupLatitude;
String? pickupLongitude;
String? dropoffLatitude;
String? dropoffLongitude;
String? appointmentNo;
String? appointmentClinicName;
String? appointmentDoctorName;
String? appointmentBranch;
String? appointmentTime;
TransportationDetails(
{this.direction,
this.haveAppointment = 0,
this.tripType,
this.pickupUrgency,
this.pickupSpot,
this.pickupDateTime,
this.transportationType,
this.ambulate,
this.ambulateTitle,
this.notes,
this.requesterFileNo,
this.requesterMobileNo,
this.requesterIsOutSA,
this.pickupLocationName,
this.dropoffLocationName,
this.pickupLatitude,
this.pickupLongitude,
this.dropoffLatitude,
this.dropoffLongitude,
this.appointmentNo = "0",
this.appointmentClinicName = "",
this.appointmentDoctorName = "",
this.appointmentBranch = "",
this.appointmentTime = ""});
TransportationDetails.fromJson(Map<String, dynamic> json) {
direction = json['direction'];
haveAppointment = json['haveAppointment'];
tripType = json['tripType'];
pickupUrgency = json['pickupUrgency'];
pickupSpot = json['pickupSpot'];
pickupDateTime = json['pickupDateTime'];
transportationType = json['transportationType'];
ambulate = json['ambulate'];
ambulateTitle = "";
notes = json['notes'];
requesterFileNo = json['requesterFileNo'];
requesterMobileNo = json['requesterMobileNo'];
requesterIsOutSA = json['requesterIsOutSA'];
pickupLocationName = json['pickupLocationName'];
dropoffLocationName = json['dropoffLocationName'];
pickupLatitude = json['pickup_Latitude'];
pickupLongitude = json['pickup_Longitude'];
dropoffLatitude = json['dropoff_Latitude'];
dropoffLongitude = json['dropoff_Longitude'];
appointmentNo = json['appointmentNo'];
appointmentClinicName = json['appointmentClinicName'];
appointmentDoctorName = json['appointmentDoctorName'];
appointmentBranch = json['appointmentBranch'];
appointmentTime = json['appointmentTime'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['direction'] = this.direction;
data['haveAppointment'] = this.haveAppointment;
data['tripType'] = this.tripType;
data['pickupUrgency'] = this.pickupUrgency;
data['pickupSpot'] = this.pickupSpot;
data['pickupDateTime'] = this.pickupDateTime;
data['transportationType'] = this.transportationType;
data['ambulate'] = this.ambulate;
data['ambulateTitle'] = this.ambulateTitle;
data['notes'] = this.notes;
data['requesterFileNo'] = this.requesterFileNo;
data['requesterMobileNo'] = this.requesterMobileNo;
data['requesterIsOutSA'] = this.requesterIsOutSA;
data['pickupLocationName'] = this.pickupLocationName;
data['dropoffLocationName'] = this.dropoffLocationName;
data['pickup_Latitude'] = this.pickupLatitude;
data['pickup_Longitude'] = this.pickupLongitude;
data['dropoff_Latitude'] = this.dropoffLatitude;
data['dropoff_Longitude'] = this.dropoffLongitude;
data['appointmentNo'] = this.appointmentNo;
data['appointmentClinicName'] = this.appointmentClinicName;
data['appointmentDoctorName'] = this.appointmentDoctorName;
data['appointmentBranch'] = this.appointmentBranch;
data['appointmentTime'] = this.appointmentTime;
return data;
}
}

@ -0,0 +1,346 @@
class AmbulanceRequestOrdersModel {
String? statusText;
num? paymentStatus;
dynamic clientRequestid;
dynamic paymentStatusText;
dynamic projectName;
String? nearestProjectName;
num? paymentAmount;
WFOrder? wFOrder;
String? serviceText;
bool? isSentForApproval;
num? exaCartOrderId;
String? exaCartGUID;
bool? isTimer;
num? timeSeconds;
num? totalPendingSeconds;
num? timeMinute;
num? timeHour;
num? timeTotalSeconds;
num? timeTotalMinute;
num? timeTotalHour;
dynamic approvalStatus;
bool? isActive;
num? clickButton;
dynamic orderHistory;
String? pickupLocation;
String? dropOffLocation;
String? clinicName;
String? doctorName;
String? branch;
String? time;
String? notes;
int? iD;
num? patientId;
num? patientOutSa;
bool? isOutPatient;
num? projectId;
num? nearestProjectId;
dynamic longitude;
dynamic latitude;
dynamic appointmentNo;
dynamic dischargeId;
int? statusId;
num? serviceId;
num? channel;
Orderpayment? orderpayment;
dynamic wforder;
dynamic orderapprovalobj;
String? created;
dynamic createdBy;
dynamic modified;
dynamic modifiedBy;
bool? isDeleted;
AmbulanceRequestOrdersModel(
{this.statusText,
this.paymentStatus,
this.clientRequestid,
this.paymentStatusText,
this.projectName,
this.nearestProjectName,
this.paymentAmount,
this.wFOrder,
this.serviceText,
this.isSentForApproval,
this.exaCartOrderId,
this.exaCartGUID,
this.isTimer,
this.timeSeconds,
this.totalPendingSeconds,
this.timeMinute,
this.timeHour,
this.timeTotalSeconds,
this.timeTotalMinute,
this.timeTotalHour,
this.approvalStatus,
this.isActive,
this.clickButton,
this.orderHistory,
this.pickupLocation,
this.dropOffLocation,
this.clinicName,
this.doctorName,
this.branch,
this.time,
this.notes,
this.iD,
this.patientId,
this.patientOutSa,
this.isOutPatient,
this.projectId,
this.nearestProjectId,
this.longitude,
this.latitude,
this.appointmentNo,
this.dischargeId,
this.statusId,
this.serviceId,
this.channel,
this.orderpayment,
this.wforder,
this.orderapprovalobj,
this.created,
this.createdBy,
this.modified,
this.modifiedBy,
this.isDeleted});
AmbulanceRequestOrdersModel.fromJson(Map<String, dynamic> json) {
statusText = json['StatusText'];
paymentStatus = json['PaymentStatus'];
clientRequestid = json['ClientRequestid'];
paymentStatusText = json['PaymentStatusText'];
projectName = json['ProjectName'];
nearestProjectName = json['NearestProjectName'];
paymentAmount = json['PaymentAmount'];
wFOrder = json['WF_order'] != null
? new WFOrder.fromJson(json['WF_order'])
: null;
serviceText = json['ServiceText'];
isSentForApproval = json['isSentForApproval'];
exaCartOrderId = json['ExaCart_OrderId'];
exaCartGUID = json['ExaCart_GUID'];
isTimer = json['isTimer'];
timeSeconds = json['TimeSeconds'];
totalPendingSeconds = json['TotalPendingSeconds'];
timeMinute = json['TimeMinute'];
timeHour = json['TimeHour'];
timeTotalSeconds = json['TimeTotalSeconds'];
timeTotalMinute = json['TimeTotalMinute'];
timeTotalHour = json['TimeTotalHour'];
approvalStatus = json['ApprovalStatus'];
isActive = json['isActive'];
clickButton = json['ClickButton'];
orderHistory = json['OrderHistory'];
pickupLocation = json['PickupLocation'];
dropOffLocation = json['DropOffLocation'];
clinicName = json['clinicName'];
doctorName = json['DoctorName'];
branch = json['Branch'];
time = json['Time'];
notes = json['Notes'];
iD = json['ID'];
patientId = json['PatientId'];
patientOutSa = json['PatientOutSa'];
isOutPatient = json['IsOutPatient'];
projectId = json['ProjectId'];
nearestProjectId = json['NearestProjectId'];
longitude = json['Longitude'];
latitude = json['Latitude'];
appointmentNo = json['AppointmentNo'];
dischargeId = json['DischargeId'];
statusId = json['StatusId'];
serviceId = json['ServiceId'];
channel = json['Channel'];
orderpayment = json['orderpayment'] != null
? new Orderpayment.fromJson(json['orderpayment'])
: null;
wforder = json['wforder'];
orderapprovalobj = json['orderapprovalobj'];
created = json['Created'];
createdBy = json['CreatedBy'];
modified = json['Modified'];
modifiedBy = json['ModifiedBy'];
isDeleted = json['IsDeleted'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['StatusText'] = this.statusText;
data['PaymentStatus'] = this.paymentStatus;
data['ClientRequestid'] = this.clientRequestid;
data['PaymentStatusText'] = this.paymentStatusText;
data['ProjectName'] = this.projectName;
data['NearestProjectName'] = this.nearestProjectName;
data['PaymentAmount'] = this.paymentAmount;
if (this.wFOrder != null) {
data['WF_order'] = this.wFOrder!.toJson();
}
data['ServiceText'] = this.serviceText;
data['isSentForApproval'] = this.isSentForApproval;
data['ExaCart_OrderId'] = this.exaCartOrderId;
data['ExaCart_GUID'] = this.exaCartGUID;
data['isTimer'] = this.isTimer;
data['TimeSeconds'] = this.timeSeconds;
data['TotalPendingSeconds'] = this.totalPendingSeconds;
data['TimeMinute'] = this.timeMinute;
data['TimeHour'] = this.timeHour;
data['TimeTotalSeconds'] = this.timeTotalSeconds;
data['TimeTotalMinute'] = this.timeTotalMinute;
data['TimeTotalHour'] = this.timeTotalHour;
data['ApprovalStatus'] = this.approvalStatus;
data['isActive'] = this.isActive;
data['ClickButton'] = this.clickButton;
data['OrderHistory'] = this.orderHistory;
data['PickupLocation'] = this.pickupLocation;
data['DropOffLocation'] = this.dropOffLocation;
data['clinicName'] = this.clinicName;
data['DoctorName'] = this.doctorName;
data['Branch'] = this.branch;
data['Time'] = this.time;
data['Notes'] = this.notes;
data['ID'] = this.iD;
data['PatientId'] = this.patientId;
data['PatientOutSa'] = this.patientOutSa;
data['IsOutPatient'] = this.isOutPatient;
data['ProjectId'] = this.projectId;
data['NearestProjectId'] = this.nearestProjectId;
data['Longitude'] = this.longitude;
data['Latitude'] = this.latitude;
data['AppointmentNo'] = this.appointmentNo;
data['DischargeId'] = this.dischargeId;
data['StatusId'] = this.statusId;
data['ServiceId'] = this.serviceId;
data['Channel'] = this.channel;
if (this.orderpayment != null) {
data['orderpayment'] = this.orderpayment!.toJson();
}
data['wforder'] = this.wforder;
data['orderapprovalobj'] = this.orderapprovalobj;
data['Created'] = this.created;
data['CreatedBy'] = this.createdBy;
data['Modified'] = this.modified;
data['ModifiedBy'] = this.modifiedBy;
data['IsDeleted'] = this.isDeleted;
return data;
}
}
class WFOrder {
dynamic wfButtonsDTO;
num? iD;
num? orderId;
num? previousStep;
num? nextStep;
num? serviceId;
dynamic order;
String? created;
dynamic createdBy;
dynamic modified;
dynamic modifiedBy;
bool? isDeleted;
WFOrder(
{this.wfButtonsDTO,
this.iD,
this.orderId,
this.previousStep,
this.nextStep,
this.serviceId,
this.order,
this.created,
this.createdBy,
this.modified,
this.modifiedBy,
this.isDeleted});
WFOrder.fromJson(Map<String, dynamic> json) {
wfButtonsDTO = json['wf_ButtonsDTO'];
iD = json['ID'];
orderId = json['OrderId'];
previousStep = json['PreviousStep'];
nextStep = json['NextStep'];
serviceId = json['ServiceId'];
order = json['Order'];
created = json['Created'];
createdBy = json['CreatedBy'];
modified = json['Modified'];
modifiedBy = json['ModifiedBy'];
isDeleted = json['IsDeleted'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['wf_ButtonsDTO'] = this.wfButtonsDTO;
data['ID'] = this.iD;
data['OrderId'] = this.orderId;
data['PreviousStep'] = this.previousStep;
data['NextStep'] = this.nextStep;
data['ServiceId'] = this.serviceId;
data['Order'] = this.order;
data['Created'] = this.created;
data['CreatedBy'] = this.createdBy;
data['Modified'] = this.modified;
data['ModifiedBy'] = this.modifiedBy;
data['IsDeleted'] = this.isDeleted;
return data;
}
}
class Orderpayment {
num? iD;
num? orderId;
dynamic clientRequestId;
num? totalAmount;
num? paymentStatus;
dynamic order;
String? created;
dynamic createdBy;
dynamic modified;
dynamic modifiedBy;
bool? isDeleted;
Orderpayment(
{this.iD,
this.orderId,
this.clientRequestId,
this.totalAmount,
this.paymentStatus,
this.order,
this.created,
this.createdBy,
this.modified,
this.modifiedBy,
this.isDeleted});
Orderpayment.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
orderId = json['OrderId'];
clientRequestId = json['ClientRequestId'];
totalAmount = json['TotalAmount'];
paymentStatus = json['PaymentStatus'];
order = json['Order'];
created = json['Created'];
createdBy = json['CreatedBy'];
modified = json['Modified'];
modifiedBy = json['ModifiedBy'];
isDeleted = json['IsDeleted'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['OrderId'] = this.orderId;
data['ClientRequestId'] = this.clientRequestId;
data['TotalAmount'] = this.totalAmount;
data['PaymentStatus'] = this.paymentStatus;
data['Order'] = this.order;
data['Created'] = this.created;
data['CreatedBy'] = this.createdBy;
data['Modified'] = this.modified;
data['ModifiedBy'] = this.modifiedBy;
data['IsDeleted'] = this.isDeleted;
return data;
}
}

@ -0,0 +1,56 @@
class PatientERTransportationMethod {
int? iD;
String? serviceID;
int? orderServiceID;
String? text;
String? textN;
dynamic price;
dynamic priceVAT;
dynamic priceTotal;
bool? isEnabled;
int? orderId;
int? quantity;
PatientERTransportationMethod(
{this.iD,
this.serviceID,
this.orderServiceID,
this.text,
this.textN,
this.price,
this.priceVAT,
this.priceTotal,
this.isEnabled,
this.orderId,
this.quantity});
PatientERTransportationMethod.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
serviceID = json['ServiceID'];
orderServiceID = json['OrderServiceID'];
text = json['Text'];
textN = json['TextN'];
price = json['Price'];
priceVAT = json['PriceVAT'];
priceTotal = json['PriceTotal'];
isEnabled = json['IsEnabled'];
orderId = json['OrderId'];
quantity = json['Quantity'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['ServiceID'] = this.serviceID;
data['OrderServiceID'] = this.orderServiceID;
data['Text'] = this.text;
data['TextN'] = this.textN;
data['Price'] = this.price;
data['PriceVAT'] = this.priceVAT;
data['PriceTotal'] = this.priceTotal;
data['IsEnabled'] = this.isEnabled;
data['OrderId'] = this.orderId;
data['Quantity'] = this.quantity;
return data;
}
}

@ -0,0 +1,80 @@
class GeocodeResponse {
final List<GeocodeResult> results;
final String status;
GeocodeResponse({
required this.results,
required this.status,
});
factory GeocodeResponse.fromJson(Map<String, dynamic> json) {
final resultsList = (json['results'] as List<dynamic>? ?? [])
.map((e) => GeocodeResult.fromJson(e as Map<String, dynamic>))
.toList();
return GeocodeResponse(
results: resultsList,
status: json['status'] ?? '',
);
}
@override
String toString() {
return 'GeocodeResponse(status: $status, results: [${results.map((r) => r.toString()).join(', ')}])';
}
}
class GeocodeResult {
final String formattedAddress;
final Geometry geometry;
final String placeId;
GeocodeResult({
required this.formattedAddress,
required this.geometry,
required this.placeId,
});
factory GeocodeResult.fromJson(Map<String, dynamic> json) {
return GeocodeResult(
formattedAddress: json['formatted_address'] ?? '',
geometry: Geometry.fromJson(json['geometry']),
placeId: json['place_id'] ?? '',
);
}
@override
String toString() {
return 'GeocodeResult(formattedAddress: $formattedAddress, placeId: $placeId, geometry: ${geometry.toString()})';
}
}
class Geometry {
final Location location;
Geometry({required this.location});
factory Geometry.fromJson(Map<String, dynamic> json) {
return Geometry(
location: Location.fromJson(json['location']),
);
}
@override
String toString() => 'Geometry(location: ${location.toString()})';
}
class Location {
final double lat;
final double lng;
Location({required this.lat, required this.lng});
factory Location.fromJson(Map<String, dynamic> json) {
return Location(
lat: (json['lat'] as num).toDouble(),
lng: (json['lng'] as num).toDouble(),
);
}
@override
String toString() => 'Location(lat: $lat, lng: $lng)';
}

@ -0,0 +1,14 @@
class PlaceDetails {
final double lat;
final double lng;
PlaceDetails({required this.lat, required this.lng});
factory PlaceDetails.fromJson(Map<String, dynamic> json) {
final loc = json['result']['geometry']['location'];
return PlaceDetails(
lat: (loc['lat'] as num).toDouble(),
lng: (loc['lng'] as num).toDouble(),
);
}
}

@ -0,0 +1,11 @@
class PlacePrediction {
final String description;
final String placeID;
PlacePrediction({required this.description, required this.placeID});
factory PlacePrediction.fromJson(Map<String, dynamic> json) {
return PlacePrediction(
description: json['description'] ?? '',
placeID: json['place_id'] ?? '',
);
}
}

@ -0,0 +1,153 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.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/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import '../../core/api_consts.dart';
import 'PlacePrediction.dart';
abstract class LocationRepo {
Future<Either<Failure, GenericApiModel<List<PlacePrediction>>>>
getPlacePredictionsAsInput(String input);
Future<Either<Failure, GenericApiModel<PlaceDetails>>>
getPlaceDetailsOfSelectedPrediction(String placeId);
Future<Either<Failure, GenericApiModel<GeocodeResponse>>>
getGeoCodeFromLatLng(double lat, double lng);
}
class LocationRepoImpl implements LocationRepo {
final ApiClient apiClient;
LocationRepoImpl({required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PlacePrediction>>>> getPlacePredictionsAsInput(
String input) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$input&region=SA&key=$GOOGLE_API_KEY',
);
GenericApiModel<List<PlacePrediction>>? apiResponse;
Failure? failure;
try {
await apiClient.get(
url.toString(),
isExternal: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['predictions'];
final predictionsList = list
.map((item) =>
PlacePrediction.fromJson(item as Map<String, dynamic>))
.toList()
.cast<PlacePrediction>();
apiResponse = GenericApiModel<List<PlacePrediction>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: predictionsList,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<GeocodeResponse>>> getGeoCodeFromLatLng(double lat, double lng) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=$GOOGLE_API_KEY',
);
GenericApiModel<GeocodeResponse>? apiResponse;
Failure? failure;
try {
await apiClient.get(
url.toString(),
isExternal: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final predictionsList = GeocodeResponse.fromJson(response);
apiResponse = GenericApiModel<GeocodeResponse>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: predictionsList,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<PlaceDetails>>> getPlaceDetailsOfSelectedPrediction(String placeId) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/place/details/json'
'?place_id=$placeId&fields=geometry&key=$GOOGLE_API_KEY',
);
GenericApiModel<PlaceDetails>? apiResponse;
Failure? failure;
try {
await apiClient.get(
url.toString(),
isExternal: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final predictionsList = PlaceDetails.fromJson(response);
apiResponse = GenericApiModel<PlaceDetails>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: predictionsList,
);
} 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()));
}
}
}

@ -0,0 +1,116 @@
import 'dart:async';
import 'package:flutter/foundation.dart' show ChangeNotifier;
import 'package:flutter/material.dart';
import 'package:google_maps_flutter_platform_interface/src/types/camera.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import 'package:hmg_patient_app_new/features/location/location_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:huawei_map/huawei_map.dart' as HMSCameraServices;
import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'PlacePrediction.dart';
class LocationViewModel extends ChangeNotifier {
final LocationRepo locationRepo;
final ErrorHandlerService errorHandlerService;
LocationViewModel({required this.locationRepo, required this.errorHandlerService});
List<PlacePrediction> predictions = [];
PlacePrediction? selectedPrediction;
bool isPredictionLoading = false;
GeocodeResponse? geocodeResponse;
PlaceDetails? placeDetails;
Location? mapCapturedLocation;
FutureOr<void> getPlacesPrediction(String input) async {
predictions = [];
isPredictionLoading= true;
final result = await locationRepo.getPlacePredictionsAsInput(input);
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
},
(apiModel) {
predictions = apiModel.data??[];
},
);
isPredictionLoading = false;
notifyListeners();
}
FutureOr<void> getPlaceEncodedData(double? lat, double? lng) async {
geocodeResponse = null;
final result = await locationRepo.getGeoCodeFromLatLng(lat!, lng!);
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
},
(apiModel) {
print("Geocode Response: ${apiModel.data}");
geocodeResponse = apiModel.data;
},
);
notifyListeners();
}
FutureOr<void> getPlaceDetails(String placeID) async {
placeDetails = null;
final result = await locationRepo.getPlaceDetailsOfSelectedPrediction(placeID);
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
},
(apiModel) {
placeDetails = apiModel.data;
},
);
notifyListeners();
}
handleGMSMapCameraMoved(GMSMapServices.CameraPosition value) {
mapCapturedLocation = Location(lat: value.target.latitude, lng: value.target.longitude);
}
handleHMSMapCameraMoved(HMSCameraServices.CameraPosition value) {
mapCapturedLocation = Location(lat: value.target.lat, lng: value.target.lng);
}
handleOnCameraIdle(){
if(mapCapturedLocation != null) {
getPlaceEncodedData(mapCapturedLocation!.lat, mapCapturedLocation!.lng);
}
}
void updateSearchQuery(String? value) {
if(value == null || value.isEmpty){
predictions = [];
return;
}
getPlacesPrediction(value);
}
void flushSearchPredictions() {
predictions = [];
mapCapturedLocation= null;
placeDetails= null;
geocodeResponse= null;
selectedPrediction= null;
notifyListeners();
}
FutureOr<void> selectPlacePrediction(PlacePrediction placePrediction) async{
selectedPrediction= placePrediction;
await getPlaceDetails(placePrediction.placeID);
}
}

@ -101,4 +101,6 @@ class HospitalsModel {
data['UsingInDoctorApp'] = this.usingInDoctorApp;
return data;
}
}

@ -18,6 +18,7 @@ import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_liveca
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/history/lab_history_viewmodel.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
@ -131,6 +132,8 @@ void main() async {
),
ChangeNotifierProvider<EmergencyServicesViewModel>(
create: (_) => getIt.get<EmergencyServicesViewModel>(),
),ChangeNotifierProvider<LocationViewModel>(
create: (_) => getIt.get<LocationViewModel>(),
),
ChangeNotifierProvider<TodoSectionViewModel>(
create: (_) => getIt.get<TodoSectionViewModel>(),

@ -13,18 +13,18 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class AppointmentDoctorCard extends StatelessWidget {
const AppointmentDoctorCard({
super.key,
required this.patientAppointmentHistoryResponseModel,
required this.onRescheduleTap,
required this.onCancelTap,
required this.onAskDoctorTap,
});
const AppointmentDoctorCard(
{super.key,
required this.patientAppointmentHistoryResponseModel,
required this.onRescheduleTap,
required this.onCancelTap,
required this.onAskDoctorTap, this.renderWidgetForERDisplay = false});
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
final VoidCallback onRescheduleTap;
final VoidCallback onCancelTap;
final VoidCallback onAskDoctorTap;
final bool renderWidgetForERDisplay;
@override
Widget build(BuildContext context) {
@ -99,8 +99,12 @@ class AppointmentDoctorCard extends StatelessWidget {
],
),
SizedBox(height: 16.h),
getAppointmentActionButtons(
AppointmentType.isArrived(patientAppointmentHistoryResponseModel),
Visibility(
visible: renderWidgetForERDisplay == false,
child: getAppointmentActionButtons(
AppointmentType.isArrived(patientAppointmentHistoryResponseModel),
),
),
],
),

@ -72,6 +72,7 @@ class HospitalListItem extends StatelessWidget {
);
Widget get distanceInfo => Row(
spacing: 4.w,
children: [
Visibility(
visible: (hospitalData?.distanceInKMs != "0"),
@ -91,9 +92,9 @@ class HospitalListItem extends StatelessWidget {
labelText: "Distance not available".needTranslation,
textColor: AppColors.blackColor,
),
SizedBox(
width: 8.h,
)
// SizedBox(
// width: 8.h,
// )
],
)),
Visibility(

@ -8,10 +8,19 @@ 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/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/requesting_services_page.dart' show RequestingServicesPage;
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart' show TrackingScreen;
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart' show AppointmentBottomSheet;
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/location_input_bottom_sheet.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/CustomSwitch.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -30,38 +39,79 @@ class CallAmbulancePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
bottomSheet: ExpandableBottomSheet(
bottomSheetType:
context.watch<EmergencyServicesViewModel>().bottomSheetType,
children: {
BottomSheetType.EXPANDED: ExpanedBottomSheet(context),
BottomSheetType.FIXED: FixedBottomSheet(context),
},
floatingActionButton: Visibility(
visible: context.watch<EmergencyServicesViewModel>().bottomSheetType ==
BottomSheetType.FIXED,
child: Padding(
padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h),
child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
.paddingAll(12.h)
.onPress(() {
context
.read<EmergencyServicesViewModel>()
.moveToCurrentLocation();
}),
),
),
),
bottomSheet: Column(
mainAxisSize: MainAxisSize.min,
children: [
ExpandableBottomSheet(
bottomSheetType:
context.watch<EmergencyServicesViewModel>().bottomSheetType,
children: {
BottomSheetType.EXPANDED: ExpanedBottomSheet(context),
BottomSheetType.FIXED: FixedBottomSheet(context),
},
),
],
),
body: Stack(
children: [
if (context.read<EmergencyServicesViewModel>().isGMSAvailable ||
Platform.isIOS)
if (context.read<EmergencyServicesViewModel>().isGMSAvailable )
GMSMap(
currentLocation:
context.read<EmergencyServicesViewModel>().getGMSLocation(),
onCameraMoved: (value) => context
.read<EmergencyServicesViewModel>()
.handleGMSMapCameraMoved(value))
.read<LocationViewModel>()
.handleGMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: true,
inputController:
context.read<EmergencyServicesViewModel>().gmsController,
showCenterMarker: true,
)
else
HMSMap(
currentLocation:
context.read<EmergencyServicesViewModel>().getHMSLocation(),
onCameraMoved: (value) => context
.read<EmergencyServicesViewModel>()
.handleHMSMapCameraMoved(value)),
.read<LocationViewModel>()
.handleHMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: false,
inputController:
context.read<EmergencyServicesViewModel>().hmsController,
showCenterMarker: true,
),
Align(
alignment: AlignmentDirectional.topStart,
child: Utils.buildSvgWithAssets(
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h),
).paddingOnly(top: 51.h, left: 24.h).onPress((){
Navigator.pop(context);
})
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h)
.onPress(() {
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
Navigator.pop(context);
}),
).paddingOnly(top: 51.h, left: 24.h),
],
),
);
@ -70,33 +120,34 @@ class CallAmbulancePage extends StatelessWidget {
Widget FixedBottomSheet(BuildContext context) {
return GestureDetector(
onVerticalDragUpdate: (details){
print("the delta is ${details.delta.dy}");
if(details.delta.dy<0){
context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.EXPANDED);
}
// if(details.delta.dy<0){
//
// context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.EXPANDED);
// }
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: EdgeInsetsDirectional.only(end:24.h, bottom: 24.h),
child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
.paddingAll(12.h),
),
),
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
// Padding(
//
// padding: EdgeInsetsDirectional.only(end:24.h, bottom: 24.h),
// child: DecoratedBox(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor, borderRadius: 12.h),
// child: Utils.buildSvgWithAssets(
// icon: AppAssets.locate_me, width: 24.h, height: 24.h)
// .paddingAll(12.h).onPress((){
// context.read<EmergencyServicesViewModel>().moveToCurrentLocation();
// }),
// ),
// ),
// ],
// ),
// PositionedDirectional(
// end: 1,
// child: Padding(
@ -116,25 +167,7 @@ class CallAmbulancePage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
spacing: 24.h,
children: [
TextInputWidget(
labelText: "Enter Pickup Location Manually".needTranslation,
hintText: "Enter Pickup Location".needTranslation,
leadingIcon: AppAssets.location_pickup,
isAllowLeadingIcon: true,
isEnable: false,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.updateBottomSheetState(BottomSheetType.EXPANDED);
}).paddingOnly(right: 24.h, left: 24.h),
inputFields(context),
SizedBox(
height: 200.h,
child: DecoratedBox(
@ -152,11 +185,11 @@ class CallAmbulancePage extends StatelessWidget {
Column(
spacing: 4.h,
children: [
"Select Pickup Location".needTranslation.toText21(
"Select Pickup Details".needTranslation.toText21(
weight: FontWeight.w600,
color: AppColors.textColor,
),
" Please select the location of pickup"
" Please select the details of pickup"
.needTranslation
.toText12(
fontWeight: FontWeight.w500,
@ -165,7 +198,7 @@ class CallAmbulancePage extends StatelessWidget {
],
),
CustomButton(
text: "Select Location".needTranslation,
text: "Select Details".needTranslation,
onPressed: () {
context
.read<EmergencyServicesViewModel>()
@ -202,21 +235,25 @@ class CallAmbulancePage extends StatelessWidget {
),
child: Column(
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
"Select Pickup Location".needTranslation.toText21(
weight: FontWeight.w600,
color: AppColors.textColor,
),
locationsSections(context),
hospitalAndPickUpSection(context),
],
).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
hospitalAndPickUpSection(context),
if(context.read<EmergencyServicesViewModel>().appointment != null)
AppointmentDoctorCard(
renderWidgetForERDisplay: true,
patientAppointmentHistoryResponseModel: context.read<EmergencyServicesViewModel>().appointment!,
onAskDoctorTap: () {},
onCancelTap: () async {},
onRescheduleTap: () async {},
).onPress((){
openAppointmentList(context);
})
],
).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h),
bottomPriceContent(context)
],
@ -281,44 +318,74 @@ class CallAmbulancePage extends StatelessWidget {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
borderRadius: 24.r,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
// Row(
// children: [
// hospitalAndPickUpItemContent(
// title: "Select Hospital".needTranslation,
// subTitle: "hospital".needTranslation,
// leadingIcon: AppAssets.hospital,
// ),
// Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron,
// width: 24.h, height: 24.h)
// .paddingAll(16.h)
// ],
// ).onPress((){
// showHospitalBottomSheet(context);
// }),
// SizedBox(height: 16.h),
// Divider(
// color: AppColors.bottomNAVBorder,
// height: 1,
// thickness: 1,
// ),
// SizedBox(height: 16.h),
Row(
children: [
hospitalAndPickUpItemContent(
title: "Select Hospital".needTranslation,
subTitle: "hospital".needTranslation,
leadingIcon: AppAssets.hospital,
title: "Pick".needTranslation,
subTitle: "Inside the home".needTranslation,
leadingIcon: AppAssets.pickup_bed,
),
Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron,
width: 24.h, height: 24.h)
.paddingAll(16.h)
CustomSwitch(
value: context
.watch<EmergencyServicesViewModel>()
.pickupFromInsideTheLocation,
onChanged: (value){
context
.read<EmergencyServicesViewModel>()
.updateThePickupPlaceFromLocation(value);
},
)
],
).onPress((){
showHospitalBottomSheet(context);
}),
SizedBox(height: 16.h),
Divider(
color: AppColors.bottomNAVBorder,
height: 1,
thickness: 1,
),
SizedBox(height: 16.h),
Row(
children: [
hospitalAndPickUpItemContent(
title: "Pick".needTranslation,
subTitle: "Inside the home".needTranslation,
leadingIcon: AppAssets.pickup_bed,
title: '',
subTitle: "Have any appointment".needTranslation,
leadingIcon: AppAssets.appointment_checkin_icon,
),
CustomSwitch(
value: context.watch<EmergencyServicesViewModel>().isGMSAvailable,
onChanged: (value){
context.read<EmergencyServicesViewModel>().setIsGMSAvailable( value);
value: context
.watch<EmergencyServicesViewModel>()
.haveAnAppointment,
onChanged: (value) async {
// if (value) {
// openAppointmentList(context);
// }
await context.read<EmergencyServicesViewModel>()
.updateAppointment(value);
if (context.read<EmergencyServicesViewModel>().appointments?.isNotEmpty == true) {
openAppointmentList(context);
}
},
)
],
@ -354,13 +421,22 @@ class CallAmbulancePage extends StatelessWidget {
this.leadingIcon(leadingIcon),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
title.toText12(
color: AppColors.greyTextColor,
fontWeight: FontWeight.w500,
Visibility(
visible: title.isNotEmpty,
child: Column(
children: [
title.toText12(
color: AppColors.greyTextColor,
fontWeight: FontWeight.w500,
),
SizedBox(height: 2.h),
],
),
),
SizedBox(height: 2.h),
subTitle.toText14(
color: AppColors.textColor,
weight: FontWeight.w500,
@ -418,17 +494,30 @@ class CallAmbulancePage extends StatelessWidget {
],
),
),
"\$250".toText24(
fontWeight: FontWeight.w600,
color: AppColors.textColor,
)
],
),
CustomButton(
text: "Submit Request".needTranslation,
onPressed: () {
Navigator.push(context, CustomPageRoute(page: RequestingServicesPage()));
})
Utils.getPaymentAmountWithSymbol(
(Utils.formatNumberToInternationalFormat(context
.read<EmergencyServicesViewModel>()
.getTotalPrice() ??
0))
.toText24(
fontWeight: FontWeight.w600,
color: AppColors.textColor,
letterSpacing: -2),
AppColors.blackColor,
17.h)
// Utils.getPaymentAmountWithSymbol2(context.read<EmergencyServicesViewModel>().selectedTransportOption?.priceTotal??"0", letterSpacing: -2)
],
),
CustomButton(
text: "Submit Request".needTranslation,
onPressed: () {
LocationViewModel locationViewModel = context.read<LocationViewModel>();
GeocodeResponse? response = locationViewModel.geocodeResponse;
PlaceDetails? placeDetails = locationViewModel.placeDetails;
PlacePrediction? placePrediction = locationViewModel.selectedPrediction;
context.read<EmergencyServicesViewModel>().submitAmbulanceRequest(response?.results.first, placeDetails, placePrediction);
})
],
).paddingOnly(top: 24.h, bottom: 12.h, left: 24.h, right: 24.h),
),
@ -443,6 +532,7 @@ class CallAmbulancePage extends StatelessWidget {
context,
child: Consumer<EmergencyServicesViewModel>(
builder:(_,vm,__)=> HospitalBottomSheetBody(
searchText: vm.searchController,
displayList: vm.displayList,
onFacilityClicked: (value) {
vm.setSelectedFacility(value);
@ -465,7 +555,137 @@ class CallAmbulancePage extends StatelessWidget {
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {
context.read<EmergencyServicesViewModel>().clearSearchText();
},
);
}
///it will show the places field first and then hospital field
PlaceFirstThanHospitalField(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
textPlaceInput(context),
hospitalField(context),
],
).paddingOnly(right: 24.h, left: 24.h);
}
HospitalFieldFirstThanPlaces(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [hospitalField(context), textPlaceInput(context)],
).paddingOnly(right: 24.h, left: 24.h);
}
textPlaceInput(context) {
return Consumer<LocationViewModel>(builder: (_, vm, __) {
print(
"the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}");
return SizedBox(
width: MediaQuery.sizeOf(context).width,
child: TextInputWidget(
labelText: "Enter Pickup Location Manually".needTranslation,
hintText: "Enter Pickup Location".needTranslation,
controller: TextEditingController(
text: vm.geocodeResponse?.results.first.formattedAddress ??
vm.selectedPrediction?.description,
),
leadingIcon: AppAssets.location_pickup,
isAllowLeadingIcon: true,
isEnable: false,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
).onPress(() {
openLocationInputBottomSheet(context);
}),
);
});
}
///decide which field to show first based on the selected calling place
inputFields(BuildContext context) {
return context.read<EmergencyServicesViewModel>().callingPlace ==
AmbulanceCallingPlace.FROM_HOSPITAL
? HospitalFieldFirstThanPlaces(context)
: PlaceFirstThanHospitalField(context);
}
openLocationInputBottomSheet(BuildContext context) {
context.read<LocationViewModel>().flushSearchPredictions();
showCommonBottomSheetWithoutHeight(
title: "".needTranslation,
context,
child: SizedBox(
height: MediaQuery.sizeOf(context).height * .8,
child: LocationInputBottomSheet(),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
hospitalField(BuildContext context) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Row(
children: [
hospitalAndPickUpItemContent(
title: "Select Hospital".needTranslation,
subTitle: context
.read<EmergencyServicesViewModel>()
.getSelectedHospitalName() ??
"Select Hospital".needTranslation,
leadingIcon: AppAssets.hospital,
),
Utils.buildSvgWithAssets(
icon: AppAssets.down_cheveron, width: 24.h, height: 24.h)
.paddingAll(16.h)
],
).onPress(() {
print("the item is clicked");
showHospitalBottomSheet(context);
}).paddingSymmetrical(
10.w,
12.h,
),
);
}
void openAppointmentList(BuildContext context) {
showCommonBottomSheetWithoutHeight(
title: "Select Appointment".needTranslation,
context,
child: SizedBox(
height: MediaQuery.sizeOf(context).height * .5,
child: AppointmentBottomSheet(
list: context.read<EmergencyServicesViewModel>().appointments!,
onAppointmentSelection: (appointment) {
Navigator.pop(context);
context.read<EmergencyServicesViewModel>().setSelectedAppointment(appointment);
}),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {
context.read<EmergencyServicesViewModel>().checkHasAppointment();
},
);
// );
}
}

@ -5,27 +5,17 @@ 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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'
show CustomPageRoute;
import 'package:lottie/lottie.dart';
class RequestingServicesPage extends StatefulWidget {
@override
State<RequestingServicesPage> createState() => _RequestingServicesPageState();
}
class RequestingServicesPage extends StatelessWidget {
class _RequestingServicesPageState extends State<RequestingServicesPage> {
@override
void initState() {
Timer(Duration(seconds: 3), () {
Navigator.pushReplacement(
context, CustomPageRoute(page: TrackingScreen()));
});
super.initState();
}
const RequestingServicesPage({super.key,});
@override
Widget build(BuildContext context) {
return Material(

@ -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/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.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/buttons/custom_button.dart';
@ -17,11 +18,33 @@ import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state.
import 'package:hmg_patient_app_new/widgets/order_tracking/request_tracking.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart' show launchUrl;
class TrackingScreen extends StatelessWidget {
final OrderTrackingState state = OrderTrackingState.ended;
OrderTrackingState? state ;
final AmbulanceRequestOrdersModel? order;
const TrackingScreen({super.key});
TrackingScreen({super.key, OrderTrackingState? state, this.order}){
if(state == null){
switch (order?.statusId) {
case 1: //pending
case 2: //processing
this.state = OrderTrackingState.waitingForCall;
break;
case 3: //completed
this.state = OrderTrackingState.dispactched;
break;
case 4: //cancel
case 6:
case 7:
this.state = OrderTrackingState.cancel;
break;
}
}else {
this.state = state;
}
}
@override
Widget build(BuildContext context) {
@ -62,6 +85,10 @@ class TrackingScreen extends StatelessWidget {
return Lottie.asset(AppAnimations.ambulance, repeat: true, reverse: false, width: 260.h, height: 200.h);
case OrderTrackingState.ended:
return Lottie.asset(AppAnimations.checkmark, repeat: true, width: 260.h, height: 200.h);
case OrderTrackingState.failed:
case OrderTrackingState.cancel:
case null:
return Lottie.asset(AppAnimations.errorAnimation, repeat: true, width: 260.h, height: 200.h);
}
}
@ -92,7 +119,11 @@ class TrackingScreen extends StatelessWidget {
}
Widget trackingBottomSection(BuildContext context) {
switch (state) {
if(state == null )
{
return SizedBox.shrink();
}
switch (state!) {
case OrderTrackingState.waitingForCall:
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -102,7 +133,9 @@ class TrackingScreen extends StatelessWidget {
),
CustomButton(
text: "Cancel Request".needTranslation,
onPressed: () async {},
onPressed: () async {
openCancelOrderBottomSheet(context);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
@ -146,6 +179,10 @@ class TrackingScreen extends StatelessWidget {
doctorSection(),
],
);
case OrderTrackingState.failed:
case OrderTrackingState.cancel:
return SizedBox.shrink();
}
}
@ -203,11 +240,17 @@ class TrackingScreen extends StatelessWidget {
if (context.read<EmergencyServicesViewModel>().isGMSAvailable || Platform.isIOS) {
return GMSMap(
myLocationEnabled: false,
onCameraIdle: (){
},
currentLocation: context.read<EmergencyServicesViewModel>().getGMSLocation(),
onCameraMoved: (value) => context.read<EmergencyServicesViewModel>().handleGMSMapCameraMoved(value));
} else {
return HMSMap(
myLocationEnabled: false,
onCameraIdle: (){
},
currentLocation: context.read<EmergencyServicesViewModel>().getHMSLocation(),
onCameraMoved: (value) => context.read<EmergencyServicesViewModel>().handleHMSMapCameraMoved(value));
}
@ -221,7 +264,10 @@ class TrackingScreen extends StatelessWidget {
}
currentStatus() {
switch (state) {
if(state == null){
return SizedBox.shrink();
}
switch (state!) {
case OrderTrackingState.waitingForCall:
case OrderTrackingState.dispactched:
return RichText(
@ -276,10 +322,16 @@ class TrackingScreen extends StatelessWidget {
case OrderTrackingState.ended:
return "Arrived".needTranslation.toText21(color: AppColors.textColor, weight: FontWeight.w600);
case OrderTrackingState.failed:
case OrderTrackingState.cancel:
return SizedBox.shrink();
}
}
orderTrackingId() {
if(state == OrderTrackingState.failed){
return SizedBox.shrink();
}
return Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
@ -291,15 +343,21 @@ class TrackingScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
"Req ID:1234567890".toText16(color: AppColors.textColor, weight: FontWeight.w600),
Visibility(visible:order != null ,child: "Req ID: ${order?.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600)),
Row(
spacing: 8.h,
children: [
chip("location name".needTranslation, AppAssets.location_pickup, AppColors.blackBgColor),
chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor),
Flexible(child:
chip(order?.pickupLocation??"", AppAssets.location_pickup, AppColors.blackBgColor),
),
Flexible(child:
chip(order?.dropOffLocation??"", AppAssets.hospital, AppColors.blackBgColor),
)
],
),
chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor),
],
),
);
@ -330,7 +388,7 @@ class TrackingScreen extends StatelessWidget {
spacing: 4.h,
children: [
"Contact Rapid Response Team (RRT)".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w600),
"1223456789".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
"0115259555".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
SizedBox(height: 8.h),
],
),
@ -348,7 +406,11 @@ class TrackingScreen extends StatelessWidget {
borderColor: Colors.transparent,
height: 36.h,
),
)
).onPress((){
launchUrl(
Uri.parse("tel://0115259555"),
);
})
],
),
);
@ -363,7 +425,10 @@ class TrackingScreen extends StatelessWidget {
// ]
// }
getTitle(OrderTrackingState state) {
getTitle(OrderTrackingState? state) {
if(state == null)
return "Failed".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600);
switch (state) {
case OrderTrackingState.waitingForCall:
return "Confirmation Call".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600);
@ -373,6 +438,11 @@ class TrackingScreen extends StatelessWidget {
return " On The Way To Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600);
case OrderTrackingState.ended:
return "Arrived at Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600);
case OrderTrackingState.failed:
return "Failed".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600);
case OrderTrackingState.cancel:
return "Order Cancel".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600);
}
}
@ -383,4 +453,9 @@ class TrackingScreen extends StatelessWidget {
child: ClipRRect(borderRadius: BorderRadius.circular(20.h), child: mapForRequestedCoordinate(context)),
);
}
openCancelOrderBottomSheet(BuildContext context){
context.read<EmergencyServicesViewModel>().cancelOrder(order, shouldPop: true);
}
}

@ -24,8 +24,8 @@ import 'package:provider/provider.dart';
class HospitalBottomSheetBody extends StatelessWidget {
final TextEditingController searchText = TextEditingController();
final Debouncer debouncer = Debouncer(milliseconds: 500);
final TextEditingController searchText ;
final Debouncer debouncer = Debouncer(milliseconds: 500);
final int hmcCount;
final int hmgCount;
@ -35,15 +35,7 @@ class HospitalBottomSheetBody extends StatelessWidget {
final Function(HospitalsModel) onHospitalClicked;
final Function(String) onHospitalSearch;
HospitalBottomSheetBody(
{super.key,
required this.hmcCount,
required this.hmgCount,
this.displayList,
required this.selectedFacility,
required this.onFacilityClicked,
required this.onHospitalClicked,
required this.onHospitalSearch});
HospitalBottomSheetBody({super.key, required this.hmcCount, required this.hmgCount, this.displayList, required this.selectedFacility, required this.onFacilityClicked, required this.onHospitalClicked, required this.onHospitalSearch, required this.searchText});
@override
Widget build(BuildContext context) {
@ -56,12 +48,13 @@ class HospitalBottomSheetBody extends StatelessWidget {
hintText: LocaleKeys.searchHospital.tr(),
controller: searchText,
onChange: (value) {
debouncer.run(() {
onHospitalSearch(value ?? "");
debouncer.run((){
onHospitalSearch(value??"");
});
},
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
@ -74,7 +67,7 @@ class HospitalBottomSheetBody extends StatelessWidget {
),
SizedBox(height: 24.h),
TypeSelectionWidget(
selectedFacility: selectedFacility,
selectedFacility:selectedFacility ,
hmcCount: hmcCount.toString(),
hmgCount: hmgCount.toString(),
onitemClicked: (selectedValue){
@ -83,16 +76,16 @@ class HospitalBottomSheetBody extends StatelessWidget {
),
SizedBox(height: 21.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index)
{
var hospital = displayList?[index];
return HospitalListItem(
hospitalData: Utils.convertToPatientDoctorAppointmentList(hospital),
isLocationEnabled: true,
).onPress(() {
onHospitalClicked(hospital!);
).onPress(() {
onHospitalClicked(hospital!);
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,

@ -1,10 +1,14 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart' show AppAssets;
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
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/emergency_services/models/resp_model/PatientERTransportationMethod.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/transport_option_Item.dart' show TransportOptionItem;
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';
class AmbulanceOptionSelectionBottomSheet extends StatelessWidget {
final Function onTap;
@ -12,40 +16,36 @@ class AmbulanceOptionSelectionBottomSheet extends StatelessWidget {
const AmbulanceOptionSelectionBottomSheet({super.key, required this.onTap});
@override
Widget build(BuildContext context) {
return Column(
spacing: 16.h,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
return Selector<EmergencyServicesViewModel,
List<PatientERTransportationMethod>>(
selector: (_, model) => model.transportationOptions,
builder: (_, data, __) => Column(
spacing: 16.h,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: ListView.separated(
separatorBuilder: (_,__)=> SizedBox(
height: 16.h,
),
itemCount: data.length??0,
itemBuilder: (_, index) => TransportOptionItem(
title: Utils.getTextWRTCurrentLanguage(data[index].text, data[index].textN),
subTitle: "",
firstIcon: AppAssets.location_pickup,
middleIcon: AppAssets.to_arrow,
lastIcon: AppAssets.hospital,
price: data[index].priceTotal.toString(),
onTap: () {
onTap();
context.read<EmergencyServicesViewModel>().setTransportationOption(data[index]);
},
),
),
),
TransportOptionItem(
title: "Home to Hospital (One Way)",
subTitle: "Pickup from home location to hospital",
firstIcon: AppAssets.location_pickup,
middleIcon:AppAssets.to_arrow,
lastIcon: AppAssets.hospital,
price: "150 AED",
onTap: (){onTap();},
),
TransportOptionItem(
title: "Hospital to Home (One Way)",
subTitle: "Pickup from hospital to home",
lastIcon: AppAssets.location_pickup,
middleIcon:AppAssets.to_arrow,
firstIcon: AppAssets.hospital,
price: "150 AED",
onTap: (){onTap();},
),
TransportOptionItem(
title: "Home to Hospital (Two Way)",
subTitle: "Pick from home to hospital then drop off to home",
firstIcon: AppAssets.location_pickup,
middleIcon:AppAssets.dual_arrow,
lastIcon: AppAssets.hospital,
price: "150 AED",
onTap: (){onTap();},
),
SizedBox(height: 16.h,)
],
],
),
);
}
}

@ -0,0 +1,54 @@
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';
class AppointmentBottomSheet extends StatelessWidget{
final Function(PatientAppointmentHistoryResponseModel) onAppointmentSelection;
final List<PatientAppointmentHistoryResponseModel> list;
const AppointmentBottomSheet({super.key, required this.onAppointmentSelection, required this.list});
@override
Widget build(BuildContext context) => getAppointList(list);
Widget getAppointList( List<PatientAppointmentHistoryResponseModel> list) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: ListView.separated(
padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: list.length,
itemBuilder: (context, index) {
PatientAppointmentHistoryResponseModel item = list[index];
return AppointmentDoctorCard(
renderWidgetForERDisplay: true,
patientAppointmentHistoryResponseModel: item,
onAskDoctorTap: () {},
onCancelTap: () async {},
onRescheduleTap: () async {},
).onPress((){
onAppointmentSelection(item);
});
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
),
SizedBox(height: 24.h),
],
);
}
}

@ -0,0 +1,172 @@
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/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/ambulance_direction.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart';
import '../../../../generated/locale_keys.g.dart' show LocaleKeys;
class PickupLocation extends StatelessWidget {
final VoidCallback onTap;
const PickupLocation({super.key, required this.onTap});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Select Pickup Direction"
.needTranslation
.toText24(color: AppColors.textColor,isBold: true),
SizedBox(
height: 16.h,
),
"Select Direction"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w600),
SizedBox(
height: 12.h,
),
Selector<EmergencyServicesViewModel, AmbulanceCallingPlace>(
selector: (context, viewModel) => viewModel.callingPlace,
builder: (context, value, _) {
return Column(
spacing: 12.h,
children: [
RadioGroup<AmbulanceCallingPlace>(
groupValue: value,
onChanged: (value) {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(value);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Radio(
value: AmbulanceCallingPlace.TO_HOSPITAL,
groupValue: value,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"To Hospital"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.TO_HOSPITAL);
}),
Row(
children: [
Radio(
value: AmbulanceCallingPlace.FROM_HOSPITAL,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"From Hospital"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.FROM_HOSPITAL);
}),
],
),
),
Visibility(
visible: value == AmbulanceCallingPlace.TO_HOSPITAL,
child: Selector<EmergencyServicesViewModel, AmbulanceDirection>(
selector: (context, viewModel) =>
viewModel.ambulanceDirection,
builder: (context, directionValue, _) {
return Column(
spacing: 12.h,
children: [
"Select Way"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w600),
RadioGroup<AmbulanceDirection>(
groupValue: directionValue,
onChanged: (value) {
context
.read<EmergencyServicesViewModel>()
.updateDirection(value);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Radio(
value: AmbulanceDirection.ONE_WAY,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"One Way"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.ONE_WAY);
}),
Row(
children: [
Radio(
value: AmbulanceDirection.TWO_WAY,
// activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"Two Way"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.TWO_WAY);
}),
],
),
),
],
);
}),
)
],
);
}),
SizedBox(
height: 16.h,
),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: onTap,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
iconColor: AppColors.whiteColor,
),
],
);
}
}

@ -48,7 +48,6 @@ class TransportOptionItem extends StatelessWidget {
titleSection() {
return Row(
children: [
Expanded(
child: Column(
@ -56,8 +55,8 @@ class TransportOptionItem extends StatelessWidget {
children: [
title.toText16(
color: AppColors.textColor, weight: FontWeight.w600),
subTitle.toText12(
color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
// subTitle.toText12(
// color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -69,18 +68,23 @@ class TransportOptionItem extends StatelessWidget {
headerSection() {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: Row(
children: [
buildIcon(firstIcon),
Utils.buildSvgWithAssets(
icon: middleIcon, width: 24.h, height: 24.h).paddingAll(8.h),
buildIcon(lastIcon)
],
),
// Expanded(
// child: Row(
// children: [
// buildIcon(firstIcon),
// Utils.buildSvgWithAssets(
// icon: middleIcon, width: 24.h, height: 24.h).paddingAll(8.h),
// buildIcon(lastIcon)
// ],
// ),
// ),
Utils.getPaymentAmountWithSymbol2(
num.tryParse(price) ?? 0.0,
fontSize: 18.f,
letterSpacing:-2
),
price.toText18(color: AppColors.textColor, weight: FontWeight.w600)
],
);
}

@ -17,10 +17,10 @@ class TypeSelectionWidget extends StatelessWidget {
const TypeSelectionWidget(
{super.key,
required this.hmcCount,
required this.hmgCount,
required this.onitemClicked,
required this.selectedFacility});
required this.hmcCount,
required this.hmgCount,
required this.onitemClicked,
required this.selectedFacility});
@override
Widget build(BuildContext context) {

@ -8,10 +8,13 @@ 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/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/ambulance_option_selection_bottomsheet.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/pickup_location.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/history/er_history_listing.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
@ -35,7 +38,9 @@ class EmergencyServicesPage extends StatelessWidget {
locationUtils!.isShowConfirmDialog = true;
return CollapsingListView(
title: LocaleKeys.emergencyServices.tr(),
requests: () {},
requests: () {
Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up));
},
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
@ -65,6 +70,8 @@ class EmergencyServicesPage extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
@ -101,7 +108,8 @@ class EmergencyServicesPage extends StatelessWidget {
height: 120.h,
fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirm.tr().toText28(color: AppColors.whiteColor, isBold: true),
"Confirmation".needTranslation.toText28(
color: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h),
"Are you sure you want to call an ambulance?"
.needTranslation
@ -114,23 +122,8 @@ class EmergencyServicesPage extends StatelessWidget {
onPressed: () async {
//
Navigator.of(context).pop();
showCommonBottomSheetWithoutHeight(
title:
"Transport Options".needTranslation,
context,
child: AmbulanceOptionSelectionBottomSheet(
onTap: () {
Navigator.of(context).pop();
context
.read<EmergencyServicesViewModel>()
.navigateTOAmbulancePage();
}),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
await emergencyServicesViewModel.getTransportationOption();
openTranportationSelectionBottomSheet(context);
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor,
@ -368,4 +361,68 @@ class EmergencyServicesPage extends StatelessWidget {
),
);
}
openPickupDetailsBottomSheet(BuildContext context){
showCommonBottomSheetWithoutHeight(
onCloseClicked: (){
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
},
titleWidget: Transform.flip(
flipX: emergencyServicesViewModel.isArabic ? true : false,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
Navigator.pop(context);
openTranportationSelectionBottomSheet(context);
}),
context,
child: PickupLocation(
onTap: () {
Navigator.of(context).pop();
context.read<LocationViewModel>().flushSearchPredictions();
context
.read<EmergencyServicesViewModel>()
.navigateTOAmbulancePage();
}),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
void openTranportationSelectionBottomSheet(BuildContext context) {
if(emergencyServicesViewModel.transportationOptions.isNotEmpty) {
showCommonBottomSheetWithoutHeight(
title: "Transport Options".needTranslation,
context,
child: SizedBox(
height: 400.h,
child: AmbulanceOptionSelectionBottomSheet(
onTap: () {
Navigator.of(context).pop();
openPickupDetailsBottomSheet(context);
// context
// .read<EmergencyServicesViewModel>()
// .navigateTOAmbulancePage();
}),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
}
}

@ -168,6 +168,7 @@ class ErOnlineCheckinHome extends StatelessWidget {
selectedFacility: vm.selectedFacility,
hmcCount: vm.hmcCount,
hmgCount: vm.hmgCount,
searchText: vm.searchController,
),
),
isFullScreen: false,

@ -0,0 +1,62 @@
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/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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/ambulance_history_item.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:provider/provider.dart';
class ErHistoryListing extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: "History Log".needTranslation,
child: SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Column(
children: [Visibility(
visible: context
.read<EmergencyServicesViewModel>()
.orders
?.isNotEmpty == true,
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: context
.read<EmergencyServicesViewModel>()
.orders
?.length ?? 0,
itemBuilder: (_, index) =>
Consumer<EmergencyServicesViewModel>( builder: (_, vm, __)=>
AmbulanceHistoryItem(order: vm.orders![index]),
)
),
),]
).paddingAll(16.h)
))
),
Visibility(
visible: context
.read<EmergencyServicesViewModel>()
.orders
?.isEmpty == true,
child: Utils.getNoDataWidget(context,
noDataText: "You don't have any history"
.needTranslation)),
],
),
);
}
}

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class RequestStatus extends StatelessWidget {
final int status;
const RequestStatus({super.key, required this.status});
@override
Widget build(BuildContext context) {
return AppCustomChipWidget(
labelText: getTitle(status),
backgroundColor: getBackgroundColor(status),
textColor: getTextColor(status),
);
}
String? getTitle(int status) {
switch (status) {
case 1: //pending
case 2: //processing
return "Under Processing".needTranslation;
case 3: //completed
return "Completed".needTranslation;
break;
case 4: //cancel
case 6:
case 7:
return "Canceled by patient".needTranslation;
break;
}
return null;
}
Color? getBackgroundColor(int status) {
switch (status) {
case 1: //pending
case 2: //processing
case 3: //completed
return AppColors.switchBackgroundColor;
break;
case 4: //cancel
case 6:
case 7:
return AppColors.lightRedButtonColor;
break;
}
return null;
}
Color? getTextColor(int status) {
switch (status) {
case 1: //pending
case 2:
return AppColors.successColor;//processing
case 3: //completed
case 4: //cancel
case 6:
case 7:
return AppColors.errorColor;
break;
}
return null;
}
}

@ -0,0 +1,81 @@
import 'package:flutter/material.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/utils/date_util.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/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/RequestStatus.dart';
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/chip/app_custom_chip_widget.dart';
import 'package:provider/provider.dart';
import '../../../../core/utils/utils.dart';
class AmbulanceHistoryItem extends StatelessWidget {
final AmbulanceRequestOrdersModel order;
const AmbulanceHistoryItem({super.key, required this.order});
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,
hasShadow: true,
customBorder: BorderRadius.all(
Radius.circular(20.h),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
RequestStatus(status: order.statusId ?? 0),
"Req ID: ${order.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600),
Row(
spacing: 4.w,
children: [
chip( Utils.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(order.time)), AppAssets.calendar, AppColors.blackBgColor),
chip("Ambulance".needTranslation, AppAssets.ambulance, AppColors.blackBgColor),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Flexible(child: chip(order?.dropOffLocation ?? "", (order.dropOffLocation?.toLowerCase().contains("hospital") == true)?AppAssets.hospital:AppAssets.location_pickup, AppColors
.blackBgColor),)
],
),
if (order.statusId == 1 || order.statusId == 2)
CustomButton(
text: "Cancel Request".needTranslation,
onPressed: () async {
openCancelOrderBottomSheet(context);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
icon: AppAssets.cancel,
),
],
).paddingAll(16.h),
).paddingOnly(bottom: 16.h);
}
chip(String title, String iconString, Color iconColor) {
return AppCustomChipWidget(
labelText: title,
icon: iconString,
iconColor: iconColor,
iconSize: 14.h,
);
}
openCancelOrderBottomSheet(BuildContext context) {
context.read<EmergencyServicesViewModel>().cancelOrder(order);
}
}

@ -7,7 +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/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/nearestERItem.dart' show NearestERItem;
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';

@ -0,0 +1,118 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'
show AnimationConfiguration, SlideAnimation, FadeInAnimation;
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/enums.dart';
import 'package:hmg_patient_app_new/core/utils/debouncer.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/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
import '../../../theme/colors.dart';
import '../../appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
class LocationInputBottomSheet extends StatelessWidget {
final Debouncer debouncer = Debouncer(milliseconds: 500);
LocationInputBottomSheet({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: "Search Location".needTranslation,
controller: TextEditingController(),
onChange: (value){
debouncer.run(() {
context.read<LocationViewModel>().updateSearchQuery(value);
});
},
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
isAllowLeadingIcon: true,
selectionType: SelectionTypeEnum.search,
padding: EdgeInsets.symmetric(
vertical: 10.h,
horizontal: 15.h,
),
),
SizedBox(height: 24.h),
Selector<LocationViewModel, List<PlacePrediction>>(
selector: (_, vm) => vm.predictions ?? <PlacePrediction>[],
builder: (context, predictions, _) {
if (predictions.isEmpty) return SizedBox.shrink();
return Expanded(
child: ListView.separated(
separatorBuilder: (_,__)=>SizedBox(height: 16.h,),
itemCount: predictions.length,
itemBuilder: (_, index) {
final prediction = predictions[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: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: prediction.description.toText14(
color: AppColors.textColor,
weight: FontWeight.w500),
),
Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 20.h,
height: 15.h,
fit: BoxFit.contain,
),
],
).paddingAll(24.h),),
),
),
).onPress(() async {
await context.read<LocationViewModel>().selectPlacePrediction(prediction);
Navigator.of(context).pop();
var location = context.read<LocationViewModel>().placeDetails;
if(location != null) {
context.read<EmergencyServicesViewModel>().moveController(
Location(lat: location.lat, lng: location.lng));
}
});
},
),
);
},
)
],
);
}
}

@ -5,7 +5,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/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
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/chip/app_custom_chip_widget.dart';

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_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/presentation/appointments/my_doctors_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/emergency_services_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
@ -10,6 +11,7 @@ import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
import '../../../core/utils/utils.dart';
import '../../../theme/colors.dart';
@ -106,9 +108,12 @@ class SmallServiceCard extends StatelessWidget {
);
break;
case "emergency":
context.read<EmergencyServicesViewModel>().flushData();
context.read<EmergencyServicesViewModel>().getTransportationOrders(showLoader: false,);
Navigator.of(context).push(
CustomPageRoute(
page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'),
),
);
break;

@ -62,16 +62,20 @@ class DialogServiceImp implements DialogService {
message: message,
showCancel: onCancelPressed != null ? true : false,
onOkPressed: () {
print('ok button is pressed');
if (onOkPressed != null) {
print('onOkPressed is not null');
onOkPressed();
}else {
Navigator.pop(context);
}
context.pop();
},
onCancelPressed: () {
if (onCancelPressed != null) {
onCancelPressed();
}else {
Navigator.pop(context);
}
context.pop();
},
),
);
@ -211,12 +215,12 @@ Widget exceptionBottomSheetWidget({required BuildContext context, required Strin
Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: CustomButton(
text: LocaleKeys.ok.tr(),
text: LocaleKeys.cancel.tr(),
onPressed: (onCancelPressed == null)
? () {
context.pop();
}
: onOkPressed,
: onCancelPressed,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedBorderColor,
textColor: Colors.white,

@ -13,6 +13,10 @@ class NavigationService {
return navigatorKey.currentState!.push(route);
}
Future<T?> pushAndRemoveUntil<T>(Route<T> route,RoutePredicate predicate) {
return navigatorKey.currentState!.pushAndRemoveUntil(route,predicate);
}
void pop<T extends Object?>([T? result]) {
navigatorKey.currentState!.pop(result);
}
@ -34,6 +38,8 @@ class NavigationService {
navigatorKey.currentState?.pushReplacementNamed(routeName);
}
Future<T?> pushToOtpScreen<T>({required String phoneNumber, required Function(int code) checkActivationCode, required Function(String phoneNumber) onResendOTPPressed, bool isFormFamilyFile = false}) {
return navigatorKey.currentState!.push(
MaterialPageRoute(builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed, isFormFamilyFile : isFormFamilyFile)),

@ -63,6 +63,8 @@ static const Color alertLightColor = Color(0xFFD48D05);
static const Color infoLightColor = Color(0xFF0B85F7);
static const Color warningLightColor = Color(0xFFFFCC00);
static const Color greyLightColor = Color(0xFFEFEFF0);
static const Color thumbColor = Color(0xFF18C273);
static const Color switchBackgroundColor = Color(0x2618C273);
static const Color bottomNAVBorder = Color(0xFFEEEEEE);

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class CustomSwitch extends StatefulWidget {
final bool value;
@ -17,21 +18,21 @@ class _CustomSwitchState extends State<CustomSwitch> {
return GestureDetector(
onTap: () => widget.onChanged(!widget.value),
child: Container(
width: 48.h,
width: 48.w,
height: 30.h,
decoration: BoxDecoration(
color: widget.value ? Color(0xFFE6F7F0) : Color(0xFFE6F7F0),
color: AppColors.switchBackgroundColor ,
borderRadius: BorderRadius.circular(18),
),
child: AnimatedAlign(
duration: Duration(milliseconds: 200),
duration: Duration(milliseconds: 300),
alignment: widget.value ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: EdgeInsets.all(4),
width: 28,
height: 28,
margin: EdgeInsets.all(2.h),
width: 28.w,
height: 28.h,
decoration: BoxDecoration(
color: Color(0xFF5FCB89),
color: AppColors.thumbColor,
shape: BoxShape.circle,
),
),

@ -116,6 +116,7 @@ void showCommonBottomSheetWithoutHeight(
bool useSafeArea = false,
bool hasBottomPadding = true,
Color backgroundColor = AppColors.bottomSheetBgColor,
VoidCallback? onCloseClicked
}) {
showModalBottomSheet<String>(
sheetAnimationStyle: AnimationStyle(
@ -143,12 +144,13 @@ void showCommonBottomSheetWithoutHeight(
),
child: SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Container(
child: isCloseButtonVisible
? Container(
padding: EdgeInsets.only(
left: 24.w,
top: 24.h,
right: 24.w,
bottom: 12.h,
left: 24,
top: 24,
right: 24,
bottom: 12,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bottomSheetBgColor,
@ -171,16 +173,17 @@ void showCommonBottomSheetWithoutHeight(
icon: AppAssets.close_bottom_sheet_icon,
iconColor: Color(0xff2B353E),
).onPress(() {
Navigator.of(context).pop();
}),
],
onCloseClicked?.call();
Navigator.of(context).pop();
}),],
],
),
SizedBox(height: 16.h),
child,
],
),
),
)
: child,
),
),
);

@ -113,7 +113,7 @@ class TextInputWidget extends StatelessWidget {
children: [
Container(
padding: padding,
height: 63.h,
height: 64.h,
alignment: Alignment.center,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,

@ -1,41 +1,63 @@
import 'dart:async';
import 'package:flutter/material.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/utils/utils.dart';
import 'package:huawei_map/huawei_map.dart' ;
class HMSMap extends StatefulWidget{
final CameraPosition currentLocation;
final Function(CameraPosition) onCameraMoved;
final VoidCallback onCameraIdle;
final MapType mapType;
final bool compassEnabled;
final bool myLocationEnabled;
final bool showCenterMarker;
final Completer<HuaweiMapController>? inputController;
HMSMap({super.key, required this.currentLocation ,required this.onCameraMoved, this.mapType = MapType.normal,this.compassEnabled = false, this.myLocationEnabled = true});
HMSMap({super.key, required this.currentLocation ,required this.onCameraMoved,required this.onCameraIdle,
this.mapType = MapType.normal,this.compassEnabled = false,this.showCenterMarker = false,
this.myLocationEnabled = true, this.inputController});
@override
State<HMSMap> createState() => _HMSMapState();
}
class _HMSMapState extends State<HMSMap> {
final Completer<HuaweiMapController> _controller = Completer<HuaweiMapController>();
Completer<HuaweiMapController>? controller;
@override
void initState() {
HuaweiMapInitializer.initializeMap();
controller = widget.inputController ?? Completer<HuaweiMapController>();
super.initState();
}
// @override
@override
Widget build(BuildContext context) =>
HuaweiMap(
mapType: widget.mapType,
zoomControlsEnabled: false,
myLocationEnabled: widget.myLocationEnabled,
compassEnabled: widget.compassEnabled,
initialCameraPosition: widget.currentLocation,
onCameraMove: (value) => widget.onCameraMoved(value),
onMapCreated: (HuaweiMapController controller) {
_controller.complete(controller);
},
);
Stack(
children: [
HuaweiMap(
mapType: widget.mapType,
zoomControlsEnabled: false,
myLocationEnabled: widget.myLocationEnabled,
myLocationButtonEnabled: false,
compassEnabled: widget.compassEnabled,
onCameraIdle:()=> widget.onCameraIdle(),
initialCameraPosition: widget.currentLocation,
onCameraMove: (value) => widget.onCameraMoved(value),
onMapCreated: (HuaweiMapController controller) {
this.controller?.complete(controller);
},
),
Visibility(
visible: widget.showCenterMarker,
child: Align(
alignment: Alignment.center,
child: Utils.buildSvgWithAssets(icon: AppAssets.pin_location, width: 24.w, height: 36.h),
),
)
],
);
}

@ -2,31 +2,52 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
class GMSMap extends StatelessWidget{
final Completer<GoogleMapController> _controller = Completer<GoogleMapController>();
Completer<GoogleMapController>? controller;
final CameraPosition currentLocation;
final Function(CameraPosition) onCameraMoved;
final VoidCallback onCameraIdle;
final MapType mapType;
final bool compassEnabled;
final bool myLocationEnabled;
final bool showCenterMarker;
GMSMap({super.key, required this.currentLocation ,required this.onCameraMoved, this.mapType = MapType.normal,this.compassEnabled = false, this.myLocationEnabled = true});
GMSMap({super.key, required this.currentLocation ,required this.onCameraMoved,required this.onCameraIdle,
this.mapType = MapType.normal,this.compassEnabled = false,this.showCenterMarker = false,
this.myLocationEnabled = true,Completer<GoogleMapController>? inputController}){
controller = inputController ?? Completer<GoogleMapController>();
}
@override
Widget build(BuildContext context) {
return GoogleMap(
mapType: mapType,
zoomControlsEnabled: false,
myLocationEnabled: myLocationEnabled,
compassEnabled: compassEnabled,
initialCameraPosition: currentLocation,
onCameraMove: (value) => onCameraMoved(value),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
return Stack(
children: [
GoogleMap(
mapType: mapType,
zoomControlsEnabled: false,
myLocationEnabled: myLocationEnabled,
myLocationButtonEnabled: false,
compassEnabled: compassEnabled,
initialCameraPosition: currentLocation,
onCameraMove: (value) => onCameraMoved(value),
onCameraIdle: ()=>onCameraIdle(),
onMapCreated: (GoogleMapController controller) {
this.controller?.complete(controller);
},
),
Visibility(
visible: showCenterMarker,
child: Align(
alignment: Alignment.center,
child: Utils.buildSvgWithAssets(icon: AppAssets.pin_location, width: 24.w, height: 36.h),
),
)
],
);
}
}

@ -3,4 +3,6 @@ enum OrderTrackingState {
dispactched,
returning,
ended,
failed,
cancel
}

@ -5,7 +5,7 @@ import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state.
class OrderTrackingWidget extends StatelessWidget {
final double? height;
final OrderTrackingState state;
final OrderTrackingState? state;
final double parentPaddingValue;
const OrderTrackingWidget({super.key, this.height, required this.state, required this.parentPaddingValue});
@ -23,7 +23,7 @@ class OrderTrackingWidget extends StatelessWidget {
);
}
Widget? getBarAndDot(OrderTrackingState state, BuildContext context,
Widget? getBarAndDot(OrderTrackingState? state, BuildContext context,
double width) {
print("the parent padding value is $parentPaddingValue");
print("the parent padding value is ${(parentPaddingValue+24)}");
@ -31,6 +31,16 @@ class OrderTrackingWidget extends StatelessWidget {
double widthOfOneState = (width/4) - (parentPaddingValue+8.h);
print("te width of one state is $widthOfOneState");
print("the value of${width/4}");
if(state == null) {
return Row(
children: List.generate(4, (index) {
if (index == 0) {
return oneProgressBar(widthOfOneState, AppColors.primaryRedColor, true);
} else {
return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
}
}));
}
switch (state) {
case OrderTrackingState.waitingForCall:
return Row(
@ -73,6 +83,26 @@ class OrderTrackingWidget extends StatelessWidget {
// }
})
);
case OrderTrackingState.failed:
return Row(
children: List.generate(4, (index){
// if(index == 3) {
return oneProgressBar(widthOfOneState, AppColors.errorColor, index == 3);
// } else {
// return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
// }
})
);
case OrderTrackingState.cancel:
return Row(
children: List.generate(4, (index){
// if(index == 3) {
return oneProgressBar(widthOfOneState, AppColors.errorColor, index == 3);
// } else {
// return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
// }
})
);
}
}

@ -7,8 +7,10 @@ class CustomPageRoute<T> extends PageRouteBuilder<T> {
final AxisDirection direction;
final bool fullScreenDialog;
CustomPageRoute({required this.page, this.direction = AxisDirection.right, this.fullScreenDialog = false})
CustomPageRoute({required this.page, this.direction = AxisDirection.right, this.fullScreenDialog = false, super.settings})
: super(
transitionDuration: const Duration(milliseconds: 1500),
reverseTransitionDuration: const Duration(milliseconds: 500),
fullscreenDialog: fullScreenDialog,

Loading…
Cancel
Save