From d65dc4ea899acf96ae6aef82eb612d743192fd22 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Sun, 31 Aug 2025 14:44:50 +0300 Subject: [PATCH 01/10] initial commit --- android/build.gradle.kts | 14 + ios/Podfile.lock | 401 ----- lib/{services => core/api}/api_client.dart | 10 +- lib/core/enums.dart | 6 +- .../exceptions}/api_exception.dart | 2 +- lib/core/post_params_model.dart | 30 +- lib/extensions/route_extensions.dart | 23 + .../authentication/authentication_repo.dart | 4 + .../authentication_view_model.dart | 0 ...ent_last_login_details_response_model.dart | 0 .../book_appointments_repo.dart | 0 .../book_appointments_view_model.dart | 0 lib/features/common/common_repo.dart | 0 lib/features/common/common_view_model.dart | 0 .../my_appointments/my_appointments_repo.dart | 0 .../my_appointments_view_model.dart | 0 lib/main.dart | 2 +- lib/presentation/home/landing_page.dart | 2 +- lib/routes/app_routes.dart | 1 - .../authentication/authentication_repo.dart | 30 - lib/services/logger_service.dart | 27 + pubspec.lock | 1577 ----------------- 22 files changed, 94 insertions(+), 2035 deletions(-) delete mode 100644 ios/Podfile.lock rename lib/{services => core/api}/api_client.dart (98%) rename lib/{services => core/exceptions}/api_exception.dart (94%) create mode 100644 lib/extensions/route_extensions.dart create mode 100644 lib/features/authentication/authentication_repo.dart rename lib/{providers => features/authentication}/authentication_view_model.dart (100%) rename lib/{services/authentication/models/response_models => features/authentication/models}/get_patient_last_login_details_response_model.dart (100%) create mode 100644 lib/features/book_appointments/book_appointments_repo.dart create mode 100644 lib/features/book_appointments/book_appointments_view_model.dart create mode 100644 lib/features/common/common_repo.dart create mode 100644 lib/features/common/common_view_model.dart create mode 100644 lib/features/my_appointments/my_appointments_repo.dart create mode 100644 lib/features/my_appointments/my_appointments_view_model.dart delete mode 100644 lib/services/authentication/authentication_repo.dart create mode 100644 lib/services/logger_service.dart delete mode 100644 pubspec.lock diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 89176ef..d60f0c0 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,7 +1,21 @@ +buildscript { + repositories { + google() + mavenCentral() + maven { url = uri("https://developer.huawei.com/repo/") } + } + dependencies { + classpath("com.android.tools.build:gradle:7.4.2") + classpath("com.google.gms:google-services:4.4.1") + classpath("com.huawei.agconnect:agcp:1.9.3.302") + } +} + allprojects { repositories { google() mavenCentral() + maven { url = uri("https://developer.huawei.com/repo/") } } } diff --git a/ios/Podfile.lock b/ios/Podfile.lock deleted file mode 100644 index 1c36b55..0000000 --- a/ios/Podfile.lock +++ /dev/null @@ -1,401 +0,0 @@ -PODS: - - audio_session (0.0.1): - - Flutter - - connectivity_plus (0.0.1): - - Flutter - - CryptoSwift (1.8.4) - - device_calendar (0.0.1): - - Flutter - - device_info_plus (0.0.1): - - Flutter - - DKImagePickerController/Core (4.3.9): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.9) - - DKImagePickerController/PhotoGallery (4.3.9): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.9) - - DKPhotoGallery (0.0.19): - - DKPhotoGallery/Core (= 0.0.19) - - DKPhotoGallery/Model (= 0.0.19) - - DKPhotoGallery/Preview (= 0.0.19) - - DKPhotoGallery/Resource (= 0.0.19) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.19): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.19): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Firebase/CoreOnly (11.15.0): - - FirebaseCore (~> 11.15.0) - - Firebase/Messaging (11.15.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 11.15.0) - - firebase_core (3.15.2): - - Firebase/CoreOnly (= 11.15.0) - - Flutter - - firebase_messaging (15.2.10): - - Firebase/Messaging (= 11.15.0) - - firebase_core - - Flutter - - FirebaseCore (11.15.0): - - FirebaseCoreInternal (~> 11.15.0) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/Logger (~> 8.1) - - FirebaseCoreInternal (11.15.0): - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - FirebaseInstallations (11.15.0): - - FirebaseCore (~> 11.15.0) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/UserDefaults (~> 8.1) - - PromisesObjC (~> 2.4) - - FirebaseMessaging (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/Reachability (~> 8.1) - - GoogleUtilities/UserDefaults (~> 8.1) - - nanopb (~> 3.30910.0) - - FLAnimatedImage (1.0.17) - - Flutter (1.0.0) - - flutter_callkit_incoming (0.0.1): - - CryptoSwift - - Flutter - - flutter_inappwebview_ios (0.0.1): - - Flutter - - flutter_inappwebview_ios/Core (= 0.0.1) - - OrderedSet (~> 6.0.3) - - flutter_inappwebview_ios/Core (0.0.1): - - Flutter - - OrderedSet (~> 6.0.3) - - flutter_ios_voip_kit_karmm (0.8.0): - - Flutter - - flutter_local_notifications (0.0.1): - - Flutter - - flutter_zoom_videosdk (0.0.1): - - Flutter - - ZoomVideoSDK/CptShare (= 2.1.10) - - ZoomVideoSDK/zm_annoter_dynamic (= 2.1.10) - - ZoomVideoSDK/zoomcml (= 2.1.10) - - ZoomVideoSDK/ZoomVideoSDK (= 2.1.10) - - fluttertoast (0.0.2): - - Flutter - - geolocator_apple (1.2.0): - - Flutter - - FlutterMacOS - - Google-Maps-iOS-Utils (5.0.0): - - GoogleMaps (~> 8.0) - - google_maps_flutter_ios (0.0.1): - - Flutter - - Google-Maps-iOS-Utils (< 7.0, >= 5.0) - - GoogleMaps (< 10.0, >= 8.4) - - GoogleDataTransport (10.1.0): - - nanopb (~> 3.30910.0) - - PromisesObjC (~> 2.4) - - GoogleMaps (8.4.0): - - GoogleMaps/Maps (= 8.4.0) - - GoogleMaps/Base (8.4.0) - - GoogleMaps/Maps (8.4.0): - - GoogleMaps/Base - - GoogleUtilities/AppDelegateSwizzler (8.1.0): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Privacy - - GoogleUtilities/Environment (8.1.0): - - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.1.0): - - GoogleUtilities/Environment - - GoogleUtilities/Privacy - - GoogleUtilities/Network (8.1.0): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Privacy - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (8.1.0)": - - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.1.0) - - GoogleUtilities/Reachability (8.1.0): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (8.1.0): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - health (13.1.3): - - Flutter - - image_picker_ios (0.0.1): - - Flutter - - just_audio (0.0.1): - - Flutter - - FlutterMacOS - - local_auth_darwin (0.0.1): - - Flutter - - FlutterMacOS - - manage_calendar_events (0.0.1): - - Flutter - - MapboxCommon (23.11.0) - - MapboxCoreMaps (10.19.1): - - MapboxCommon (~> 23.11) - - MapboxCoreNavigation (2.19.0): - - MapboxDirections (~> 2.14) - - MapboxNavigationNative (< 207.0.0, >= 206.0.1) - - MapboxDirections (2.14.2): - - Polyline (~> 5.0) - - Turf (~> 2.8.0) - - MapboxMaps (10.19.0): - - MapboxCommon (= 23.11.0) - - MapboxCoreMaps (= 10.19.1) - - MapboxMobileEvents (= 2.0.0) - - Turf (= 2.8.0) - - MapboxMobileEvents (2.0.0) - - MapboxNavigation (2.19.0): - - MapboxCoreNavigation (= 2.19.0) - - MapboxMaps (~> 10.18) - - MapboxSpeech (~> 2.0) - - Solar-dev (~> 3.0) - - MapboxNavigationNative (206.2.2): - - MapboxCommon (~> 23.10) - - MapboxSpeech (2.1.1) - - nanopb (3.30910.0): - - nanopb/decode (= 3.30910.0) - - nanopb/encode (= 3.30910.0) - - nanopb/decode (3.30910.0) - - nanopb/encode (3.30910.0) - - OrderedSet (6.0.3) - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - permission_handler_apple (9.3.0): - - Flutter - - Polyline (5.1.0) - - PromisesObjC (2.4.0) - - SDWebImage (5.21.2): - - SDWebImage/Core (= 5.21.2) - - SDWebImage/Core (5.21.2) - - share_plus (0.0.1): - - Flutter - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - Solar-dev (3.0.1) - - sqflite_darwin (0.0.4): - - Flutter - - FlutterMacOS - - SwiftyGif (5.4.5) - - Turf (2.8.0) - - url_launcher_ios (0.0.1): - - Flutter - - ZoomVideoSDK/CptShare (2.1.10) - - ZoomVideoSDK/zm_annoter_dynamic (2.1.10) - - ZoomVideoSDK/zoomcml (2.1.10) - - ZoomVideoSDK/ZoomVideoSDK (2.1.10) - -DEPENDENCIES: - - audio_session (from `.symlinks/plugins/audio_session/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - - device_calendar (from `.symlinks/plugins/device_calendar/ios`) - - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - - FLAnimatedImage - - Flutter (from `Flutter`) - - flutter_callkit_incoming (from `.symlinks/plugins/flutter_callkit_incoming/ios`) - - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - - flutter_ios_voip_kit_karmm (from `.symlinks/plugins/flutter_ios_voip_kit_karmm/ios`) - - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - - flutter_zoom_videosdk (from `.symlinks/plugins/flutter_zoom_videosdk/ios`) - - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) - - google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`) - - health (from `.symlinks/plugins/health/ios`) - - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - - just_audio (from `.symlinks/plugins/just_audio/darwin`) - - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - - manage_calendar_events (from `.symlinks/plugins/manage_calendar_events/ios`) - - MapboxMaps (= 10.19.0) - - MapboxNavigation (= 2.19.0) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - share_plus (from `.symlinks/plugins/share_plus/ios`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - -SPEC REPOS: - trunk: - - CryptoSwift - - DKImagePickerController - - DKPhotoGallery - - Firebase - - FirebaseCore - - FirebaseCoreInternal - - FirebaseInstallations - - FirebaseMessaging - - FLAnimatedImage - - Google-Maps-iOS-Utils - - GoogleDataTransport - - GoogleMaps - - GoogleUtilities - - MapboxCommon - - MapboxCoreMaps - - MapboxCoreNavigation - - MapboxDirections - - MapboxMaps - - MapboxMobileEvents - - MapboxNavigation - - MapboxNavigationNative - - MapboxSpeech - - nanopb - - OrderedSet - - Polyline - - PromisesObjC - - SDWebImage - - Solar-dev - - SwiftyGif - - Turf - - ZoomVideoSDK - -EXTERNAL SOURCES: - audio_session: - :path: ".symlinks/plugins/audio_session/ios" - connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" - device_calendar: - :path: ".symlinks/plugins/device_calendar/ios" - device_info_plus: - :path: ".symlinks/plugins/device_info_plus/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - firebase_core: - :path: ".symlinks/plugins/firebase_core/ios" - firebase_messaging: - :path: ".symlinks/plugins/firebase_messaging/ios" - Flutter: - :path: Flutter - flutter_callkit_incoming: - :path: ".symlinks/plugins/flutter_callkit_incoming/ios" - flutter_inappwebview_ios: - :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" - flutter_ios_voip_kit_karmm: - :path: ".symlinks/plugins/flutter_ios_voip_kit_karmm/ios" - flutter_local_notifications: - :path: ".symlinks/plugins/flutter_local_notifications/ios" - flutter_zoom_videosdk: - :path: ".symlinks/plugins/flutter_zoom_videosdk/ios" - fluttertoast: - :path: ".symlinks/plugins/fluttertoast/ios" - geolocator_apple: - :path: ".symlinks/plugins/geolocator_apple/darwin" - google_maps_flutter_ios: - :path: ".symlinks/plugins/google_maps_flutter_ios/ios" - health: - :path: ".symlinks/plugins/health/ios" - image_picker_ios: - :path: ".symlinks/plugins/image_picker_ios/ios" - just_audio: - :path: ".symlinks/plugins/just_audio/darwin" - local_auth_darwin: - :path: ".symlinks/plugins/local_auth_darwin/darwin" - manage_calendar_events: - :path: ".symlinks/plugins/manage_calendar_events/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" - permission_handler_apple: - :path: ".symlinks/plugins/permission_handler_apple/ios" - share_plus: - :path: ".symlinks/plugins/share_plus/ios" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - sqflite_darwin: - :path: ".symlinks/plugins/sqflite_darwin/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - -SPEC CHECKSUMS: - audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe - connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d - CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90 - device_calendar: 9cb33f88a02e19652ec7b8b122ca778f751b1f7b - device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342 - DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c - DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 - Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e - firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c - firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 - FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e - FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 - FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 - FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 - FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_callkit_incoming: 417dd1b46541cdd5d855ad795ccbe97d1c18155e - flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 - flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579 - flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f - flutter_zoom_videosdk: 7ddc97d617b85aeace252165d2b5fc5638678c38 - fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f - geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd - Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 - google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3 - GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d - GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 - health: f1207cccb625fc2e8af263b09c29661bde7b0b7e - image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 - just_audio: a42c63806f16995daf5b219ae1d679deb76e6a79 - local_auth_darwin: fa4b06454df7df8e97c18d7ee55151c57e7af0de - manage_calendar_events: 9b2889799340398027b3e3f5c4891d41599ec257 - MapboxCommon: 119f3759f7dc9457f0695848108ab323eb643cb4 - MapboxCoreMaps: ca17f67baced23f8c952166ac6314c35bad3f66c - MapboxCoreNavigation: 3be9990fae3ed732a101001746d0e3b4234ec023 - MapboxDirections: d4fe7d43cff82aa0c15955d1b4563a5a01e2d4de - MapboxMaps: b7f29ec7c33f7dc6d2947c1148edce6db81db9a7 - MapboxMobileEvents: d044b9edbe0ec7df60f6c2c9634fe9a7f449266b - MapboxNavigation: da9cf3d773ed5b0fa0fb388fccdaa117ee681f31 - MapboxNavigationNative: 629e359f3d2590acd1ebbacaaf99e1a80ee57e42 - MapboxSpeech: cd25ef99c3a3d2e0da72620ff558276ea5991a77 - nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a - share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - Solar-dev: 4612dc9878b9fed2667d23b327f1d4e54e16e8d0 - sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d - SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 - Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - ZoomVideoSDK: 94e939820e57a075c5e712559f927017da0de06a - -PODFILE CHECKSUM: ac23c99fc61c3e92ed1c20a19299a1205568c016 - -COCOAPODS: 1.15.2 diff --git a/lib/services/api_client.dart b/lib/core/api/api_client.dart similarity index 98% rename from lib/services/api_client.dart rename to lib/core/api/api_client.dart index 42ffc58..4e08cd1 100644 --- a/lib/services/api_client.dart +++ b/lib/core/api/api_client.dart @@ -3,14 +3,14 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; -import 'package:hmg_patient_app_new/services/api_exception.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; -import '../core/app_state.dart'; -import '../core/consts.dart'; -import '../core/utils/utils.dart'; -import '../main.dart'; +import '../app_state.dart'; +import '../consts.dart'; +import '../utils/utils.dart'; +import '../../main.dart'; // ignore_for_file: avoid_annotating_with_dynamic diff --git a/lib/core/enums.dart b/lib/core/enums.dart index cf27602..7e65dee 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -23,7 +23,7 @@ enum ViewState { } enum LoginType { - FROM_LOGIN, - SILENT_LOGIN, - SILENT_WITH_OTP, + fromLogin, + silentLogin, + silentWithOTP, } diff --git a/lib/services/api_exception.dart b/lib/core/exceptions/api_exception.dart similarity index 94% rename from lib/services/api_exception.dart rename to lib/core/exceptions/api_exception.dart index f0f1ff9..7d94212 100644 --- a/lib/services/api_exception.dart +++ b/lib/core/exceptions/api_exception.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:hmg_patient_app_new/services/api_client.dart'; +import 'package:hmg_patient_app_new/core/api/api_client.dart'; class APIException implements Exception { static const String BAD_REQUEST = 'api_common_bad_request'; diff --git a/lib/core/post_params_model.dart b/lib/core/post_params_model.dart index 5eed9bb..218f29f 100644 --- a/lib/core/post_params_model.dart +++ b/lib/core/post_params_model.dart @@ -25,32 +25,32 @@ class PostParamsModel { } Map toJson() { - Map data = new Map(); - data['versionID'] = this.versionID; - data['channel'] = this.channel; - data['languageID'] = this.languageID; - data['logInTokenID'] = this.logInTokenID ?? ""; - data['tokenID'] = this.tokenID ?? ""; + Map data = {}; + data['versionID'] = versionID; + data['channel'] = channel; + data['languageID'] = languageID; + data['logInTokenID'] = logInTokenID ?? ""; + data['tokenID'] = tokenID ?? ""; return data; } Map toJsonAfterLogin() { - Map data = new Map(); - data['versionID'] = this.versionID; - data['channel'] = this.channel; - data['languageID'] = this.languageID; - data['logInTokenID'] = this.logInTokenID; - data['tokenID'] = this.tokenID; + Map data = {}; + data['versionID'] = versionID; + data['channel'] = channel; + data['languageID'] = languageID; + data['logInTokenID'] = logInTokenID; + data['tokenID'] = tokenID; return data; } - String? _LogInTokenID; + String? _logInTokenID; - String? get getLogInTokenID => _LogInTokenID ?? logInTokenID; + String? get getLogInTokenID => _logInTokenID ?? logInTokenID; set setLogInTokenID(String? value) { logInTokenID = value; - _LogInTokenID = value; + _logInTokenID = value; } set setTokenID(String? token) => tokenID = token; diff --git a/lib/extensions/route_extensions.dart b/lib/extensions/route_extensions.dart new file mode 100644 index 0000000..71f5d2d --- /dev/null +++ b/lib/extensions/route_extensions.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +extension NavigationExtensions on BuildContext { + void navigateWithName(String routeName, {Object? arguments}) { + Navigator.pushNamed(this, routeName, arguments: arguments); + } + + Future navigateReplaceWithName(String routeName, {Object? arguments}) async { + await Navigator.pushReplacementNamed(this, routeName, arguments: arguments); + } + + void navigateReplaceWithNameUntilRoute(String routeName, {Object? arguments}) { + Navigator.pushNamedAndRemoveUntil(this, routeName, (route) => false); + } + + void pop() { + Navigator.of(this).pop(); + } + + void navigateTo(Widget page) { + Navigator.push(this, MaterialPageRoute(builder: (context) => page)); + } +} diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart new file mode 100644 index 0000000..1755fba --- /dev/null +++ b/lib/features/authentication/authentication_repo.dart @@ -0,0 +1,4 @@ +class AuthenticationRepo { + + +} \ No newline at end of file diff --git a/lib/providers/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart similarity index 100% rename from lib/providers/authentication_view_model.dart rename to lib/features/authentication/authentication_view_model.dart diff --git a/lib/services/authentication/models/response_models/get_patient_last_login_details_response_model.dart b/lib/features/authentication/models/get_patient_last_login_details_response_model.dart similarity index 100% rename from lib/services/authentication/models/response_models/get_patient_last_login_details_response_model.dart rename to lib/features/authentication/models/get_patient_last_login_details_response_model.dart diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/features/common/common_repo.dart b/lib/features/common/common_repo.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/features/common/common_view_model.dart b/lib/features/common/common_view_model.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/main.dart b/lib/main.dart index 48ea6ee..ce601a2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,7 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; -import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/theme/app_theme.dart'; import 'package:logger/logger.dart'; diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index a80c25f..9163a7e 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; -import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; class LandingPage extends StatefulWidget { const LandingPage({super.key}); diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index ce31fb7..732e297 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -3,6 +3,5 @@ import 'package:hmg_patient_app_new/splashPage.dart'; class AppRoutes { static const String initialRoute = '/initialRoute'; - static Map get routes => {initialRoute: (context) => SplashPage()}; } diff --git a/lib/services/authentication/authentication_repo.dart b/lib/services/authentication/authentication_repo.dart deleted file mode 100644 index 353ad59..0000000 --- a/lib/services/authentication/authentication_repo.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'dart:convert'; - -import 'package:hmg_patient_app_new/core/app_state.dart'; -import 'package:http/http.dart'; - -import '../../core/consts.dart'; -import '../api_client.dart'; -import 'models/response_models/get_patient_last_login_details_response_model.dart'; - -class AuthenticationApiClient { - static final AuthenticationApiClient _instance = AuthenticationApiClient._internal(); - - AuthenticationApiClient._internal(); - - factory AuthenticationApiClient() => _instance; - - Future getMultipleLoginUserData(String deviceIMEI) async { - GetPatientLastLoginDetailsResponseModel getPatientLastLoginDetailsResponseModel; - - Map request = {"IMEI": deviceIMEI}; - request.addAll(AppState().postParamsJson); - String url = ApiConsts.baseUrl + ApiConsts.SELECT_DEVICE_IMEI; - Response response = await ApiClient().postJsonForResponse(url, request); - - var json = jsonDecode(response.body); - getPatientLastLoginDetailsResponseModel = GetPatientLastLoginDetailsResponseModel.fromJson(json); - - return getPatientLastLoginDetailsResponseModel; - } -} diff --git a/lib/services/logger_service.dart b/lib/services/logger_service.dart new file mode 100644 index 0000000..833a7d2 --- /dev/null +++ b/lib/services/logger_service.dart @@ -0,0 +1,27 @@ + +import 'package:logger/logger.dart'; + +abstract class LoggerService { + + void logError(String message); + + void logInfo(String message); +} + +class LoggerServiceImp implements LoggerService { + Logger logger; + + LoggerServiceImp({required this.logger}); + + + + @override + void logError(String message) { + logger.e(message); + } + + @override + void logInfo(String message) { + logger.i(message); + } +} diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 6946082..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,1577 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _flutterfire_internals: - dependency: transitive - description: - name: _flutterfire_internals - sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 - url: "https://pub.dev" - source: hosted - version: "1.3.59" - archive: - dependency: transitive - description: - name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.dev" - source: hosted - version: "4.0.7" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - audio_session: - dependency: transitive - description: - name: audio_session - sha256: "2b7fff16a552486d078bfc09a8cde19f426dc6d6329262b684182597bec5b1ac" - url: "https://pub.dev" - source: hosted - version: "0.1.25" - auto_size_text: - dependency: "direct main" - description: - name: auto_size_text - sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - cached_network_image: - dependency: "direct main" - description: - name: cached_network_image - sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - cached_network_image_platform_interface: - dependency: transitive - description: - name: cached_network_image_platform_interface - sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - cached_network_image_web: - dependency: transitive - description: - name: cached_network_image_web - sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - carp_serializable: - dependency: transitive - description: - name: carp_serializable - sha256: f039f8ea22e9437aef13fe7e9743c3761c76d401288dcb702eadd273c3e4dcef - url: "https://pub.dev" - source: hosted - version: "2.0.1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - connectivity_plus: - dependency: "direct main" - description: - name: connectivity_plus - sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec - url: "https://pub.dev" - source: hosted - version: "6.1.5" - connectivity_plus_platform_interface: - dependency: transitive - description: - name: connectivity_plus_platform_interface - sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" - url: "https://pub.dev" - source: hosted - version: "0.3.4+2" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - dbus: - dependency: transitive - description: - name: dbus - sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" - url: "https://pub.dev" - source: hosted - version: "0.7.11" - device_calendar: - dependency: "direct main" - description: - path: "." - ref: HEAD - resolved-ref: "5ea5ed9e2bb499c0633383b53103f2920b634755" - url: "https://github.com/bardram/device_calendar" - source: git - version: "4.3.1" - device_info_plus: - dependency: "direct main" - description: - name: device_info_plus - sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" - url: "https://pub.dev" - source: hosted - version: "11.5.0" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.dev" - source: hosted - version: "7.0.3" - dropdown_search: - dependency: "direct main" - description: - name: dropdown_search - sha256: c29b3e5147a82a06a4a08b3b574c51cb48cc17ad89893d53ee72a6f86643622e - url: "https://pub.dev" - source: hosted - version: "6.0.2" - easy_localization: - dependency: "direct main" - description: - name: easy_localization - sha256: "2ccdf9db8fe4d9c5a75c122e6275674508fd0f0d49c827354967b8afcc56bbed" - url: "https://pub.dev" - source: hosted - version: "3.0.8" - easy_logger: - dependency: transitive - description: - name: easy_logger - sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 - url: "https://pub.dev" - source: hosted - version: "0.0.2" - equatable: - dependency: transitive - description: - name: equatable - sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" - url: "https://pub.dev" - source: hosted - version: "2.0.7" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - file_picker: - dependency: "direct main" - description: - name: file_picker - sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22 - url: "https://pub.dev" - source: hosted - version: "10.3.2" - file_selector_linux: - dependency: transitive - description: - name: file_selector_linux - sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" - url: "https://pub.dev" - source: hosted - version: "0.9.3+2" - file_selector_macos: - dependency: transitive - description: - name: file_selector_macos - sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c" - url: "https://pub.dev" - source: hosted - version: "0.9.4+4" - file_selector_platform_interface: - dependency: transitive - description: - name: file_selector_platform_interface - sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b - url: "https://pub.dev" - source: hosted - version: "2.6.2" - file_selector_windows: - dependency: transitive - description: - name: file_selector_windows - sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" - url: "https://pub.dev" - source: hosted - version: "0.9.3+4" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" - url: "https://pub.dev" - source: hosted - version: "3.15.2" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" - url: "https://pub.dev" - source: hosted - version: "2.24.1" - firebase_messaging: - dependency: "direct main" - description: - name: firebase_messaging - sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" - url: "https://pub.dev" - source: hosted - version: "15.2.10" - firebase_messaging_platform_interface: - dependency: transitive - description: - name: firebase_messaging_platform_interface - sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" - url: "https://pub.dev" - source: hosted - version: "4.6.10" - firebase_messaging_web: - dependency: transitive - description: - name: firebase_messaging_web - sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" - url: "https://pub.dev" - source: hosted - version: "3.10.10" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - fl_chart: - dependency: "direct main" - description: - name: fl_chart - sha256: "577aeac8ca414c25333334d7c4bb246775234c0e44b38b10a82b559dd4d764e7" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_cache_manager: - dependency: transitive - description: - name: flutter_cache_manager - sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - flutter_callkit_incoming: - dependency: "direct main" - description: - path: "." - ref: dev - resolved-ref: "4b5aa9798a77eaba1c1726c314c5de74cd37ad6d" - url: "https://github.com/hiennguyen92/flutter_callkit_incoming.git" - source: git - version: "2.5.8" - flutter_hooks: - dependency: transitive - description: - name: flutter_hooks - sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 - url: "https://pub.dev" - source: hosted - version: "0.20.5" - flutter_inappwebview: - dependency: "direct main" - description: - name: flutter_inappwebview - sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" - source: hosted - version: "6.1.5" - flutter_inappwebview_android: - dependency: transitive - description: - name: flutter_inappwebview_android - sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" - source: hosted - version: "1.1.3" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - name: flutter_inappwebview_internal_annotations - sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - flutter_inappwebview_ios: - dependency: transitive - description: - name: flutter_inappwebview_ios - sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_macos: - dependency: transitive - description: - name: flutter_inappwebview_macos - sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_platform_interface: - dependency: transitive - description: - name: flutter_inappwebview_platform_interface - sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" - source: hosted - version: "1.3.0+1" - flutter_inappwebview_web: - dependency: transitive - description: - name: flutter_inappwebview_web - sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_windows: - dependency: transitive - description: - name: flutter_inappwebview_windows - sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - flutter_ios_voip_kit_karmm: - dependency: "direct main" - description: - name: flutter_ios_voip_kit_karmm - sha256: "31a445d78aacacdf128a0354efb9f4e424285dfe4c0af3ea872e64f03e6f6bfc" - url: "https://pub.dev" - source: hosted - version: "0.8.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - flutter_local_notifications: - dependency: "direct main" - description: - name: flutter_local_notifications - sha256: a9966c850de5e445331b854fa42df96a8020066d67f125a5964cbc6556643f68 - url: "https://pub.dev" - source: hosted - version: "19.4.1" - flutter_local_notifications_linux: - dependency: transitive - description: - name: flutter_local_notifications_linux - sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_local_notifications_platform_interface: - dependency: transitive - description: - name: flutter_local_notifications_platform_interface - sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" - url: "https://pub.dev" - source: hosted - version: "9.1.0" - flutter_local_notifications_windows: - dependency: transitive - description: - name: flutter_local_notifications_windows - sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98 - url: "https://pub.dev" - source: hosted - version: "1.0.2" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31 - url: "https://pub.dev" - source: hosted - version: "2.0.30" - flutter_rating_bar: - dependency: "direct main" - description: - name: flutter_rating_bar - sha256: d2af03469eac832c591a1eba47c91ecc871fe5708e69967073c043b2d775ed93 - url: "https://pub.dev" - source: hosted - version: "4.0.1" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845 - url: "https://pub.dev" - source: hosted - version: "2.2.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_zoom_videosdk: - dependency: "direct main" - description: - name: flutter_zoom_videosdk - sha256: "46a4dea664b1c969099328a499c198a1755adf9ac333dea28bea5187910b3bf9" - url: "https://pub.dev" - source: hosted - version: "2.1.10" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" - url: "https://pub.dev" - source: hosted - version: "8.2.12" - geoclue: - dependency: transitive - description: - name: geoclue - sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f - url: "https://pub.dev" - source: hosted - version: "0.1.1" - geolocator: - dependency: "direct main" - description: - name: geolocator - sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" - url: "https://pub.dev" - source: hosted - version: "14.0.2" - geolocator_android: - dependency: transitive - description: - name: geolocator_android - sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" - url: "https://pub.dev" - source: hosted - version: "5.0.2" - geolocator_apple: - dependency: transitive - description: - name: geolocator_apple - sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 - url: "https://pub.dev" - source: hosted - version: "2.3.13" - geolocator_linux: - dependency: transitive - description: - name: geolocator_linux - sha256: c4e966f0a7a87e70049eac7a2617f9e16fd4c585a26e4330bdfc3a71e6a721f3 - url: "https://pub.dev" - source: hosted - version: "0.2.3" - geolocator_platform_interface: - dependency: transitive - description: - name: geolocator_platform_interface - sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" - url: "https://pub.dev" - source: hosted - version: "4.2.6" - geolocator_web: - dependency: transitive - description: - name: geolocator_web - sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 - url: "https://pub.dev" - source: hosted - version: "4.1.3" - geolocator_windows: - dependency: transitive - description: - name: geolocator_windows - sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" - url: "https://pub.dev" - source: hosted - version: "0.2.5" - google_maps: - dependency: transitive - description: - name: google_maps - sha256: "4d6e199c561ca06792c964fa24b2bac7197bf4b401c2e1d23e345e5f9939f531" - url: "https://pub.dev" - source: hosted - version: "8.1.1" - google_maps_flutter: - dependency: "direct main" - description: - name: google_maps_flutter - sha256: e1805e5a5885bd14a1c407c59229f478af169bf4d04388586b19f53145a5db3a - url: "https://pub.dev" - source: hosted - version: "2.12.3" - google_maps_flutter_android: - dependency: transitive - description: - name: google_maps_flutter_android - sha256: a6c9d43f6a944ff4bae5c3deb34817970ac3d591dcd7f5bd2ea450ab9e9c514a - url: "https://pub.dev" - source: hosted - version: "2.18.2" - google_maps_flutter_ios: - dependency: transitive - description: - name: google_maps_flutter_ios - sha256: ca02463b19a9abc7d31fcaf22631d021d647107467f741b917a69fa26659fd75 - url: "https://pub.dev" - source: hosted - version: "2.15.5" - google_maps_flutter_platform_interface: - dependency: transitive - description: - name: google_maps_flutter_platform_interface - sha256: f4b9b44f7b12a1f6707ffc79d082738e0b7e194bf728ee61d2b3cdf5fdf16081 - url: "https://pub.dev" - source: hosted - version: "2.14.0" - google_maps_flutter_web: - dependency: transitive - description: - name: google_maps_flutter_web - sha256: "9d57993ba29b80bb637bb7b9784159ca93071d5940e4d0383ae2358ad371e375" - url: "https://pub.dev" - source: hosted - version: "0.5.13" - gsettings: - dependency: transitive - description: - name: gsettings - sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" - url: "https://pub.dev" - source: hosted - version: "0.2.8" - health: - dependency: "direct main" - description: - name: health - sha256: "996664904194b8e0a09dfe761e168fdbf9ef43c51e7de39cd075de71c7258ada" - url: "https://pub.dev" - source: hosted - version: "13.1.3" - html: - dependency: transitive - description: - name: html - sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.dev" - source: hosted - version: "0.15.6" - http: - dependency: "direct main" - description: - name: http - sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 - url: "https://pub.dev" - source: hosted - version: "1.5.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image_picker: - dependency: "direct main" - description: - name: image_picker - sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - image_picker_android: - dependency: transitive - description: - name: image_picker_android - sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e" - url: "https://pub.dev" - source: hosted - version: "0.8.13+1" - image_picker_for_web: - dependency: transitive - description: - name: image_picker_for_web - sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - image_picker_ios: - dependency: transitive - description: - name: image_picker_ios - sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e - url: "https://pub.dev" - source: hosted - version: "0.8.13" - image_picker_linux: - dependency: transitive - description: - name: image_picker_linux - sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.dev" - source: hosted - version: "0.2.2" - image_picker_macos: - dependency: transitive - description: - name: image_picker_macos - sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 - url: "https://pub.dev" - source: hosted - version: "0.2.2" - image_picker_platform_interface: - dependency: transitive - description: - name: image_picker_platform_interface - sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - image_picker_windows: - dependency: transitive - description: - name: image_picker_windows - sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.dev" - source: hosted - version: "0.2.2" - injector: - dependency: "direct main" - description: - name: injector - sha256: d692c37788872bfd4bd7c01b864b0712190a25ae5a346431ff69949d5728a2e1 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - intl: - dependency: transitive - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - just_audio: - dependency: "direct main" - description: - name: just_audio - sha256: "679637a3ec5b6e00f36472f5a3663667df00ee4822cbf5dafca0f568c710960a" - url: "https://pub.dev" - source: hosted - version: "0.10.4" - just_audio_platform_interface: - dependency: transitive - description: - name: just_audio_platform_interface - sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a" - url: "https://pub.dev" - source: hosted - version: "4.6.0" - just_audio_web: - dependency: transitive - description: - name: just_audio_web - sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663" - url: "https://pub.dev" - source: hosted - version: "0.4.16" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - lints: - dependency: transitive - description: - name: lints - sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.dev" - source: hosted - version: "5.1.1" - local_auth: - dependency: "direct main" - description: - name: local_auth - sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - local_auth_android: - dependency: transitive - description: - name: local_auth_android - sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3" - url: "https://pub.dev" - source: hosted - version: "1.0.52" - local_auth_darwin: - dependency: transitive - description: - name: local_auth_darwin - sha256: "0e9706a8543a4a2eee60346294d6a633dd7c3ee60fae6b752570457c4ff32055" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - local_auth_platform_interface: - dependency: transitive - description: - name: local_auth_platform_interface - sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a" - url: "https://pub.dev" - source: hosted - version: "1.0.10" - local_auth_windows: - dependency: transitive - description: - name: local_auth_windows - sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5 - url: "https://pub.dev" - source: hosted - version: "1.0.11" - logger: - dependency: "direct main" - description: - name: logger - sha256: "55d6c23a6c15db14920e037fe7e0dc32e7cdaf3b64b4b25df2d541b5b6b81c0c" - url: "https://pub.dev" - source: hosted - version: "2.6.1" - lottie: - dependency: "direct main" - description: - name: lottie - sha256: c5fa04a80a620066c15cf19cc44773e19e9b38e989ff23ea32e5903ef1015950 - url: "https://pub.dev" - source: hosted - version: "3.3.1" - manage_calendar_events: - dependency: "direct main" - description: - name: manage_calendar_events - sha256: f17600fcb7dc7047120c185993045e493d686930237b4e3c2689c26a64513d66 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - nm: - dependency: transitive - description: - name: nm - sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - octo_image: - dependency: transitive - description: - name: octo_image - sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - package_info_plus: - dependency: transitive - description: - name: package_info_plus - sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.dev" - source: hosted - version: "8.3.1" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db" - url: "https://pub.dev" - source: hosted - version: "2.2.18" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 - url: "https://pub.dev" - source: hosted - version: "12.0.1" - permission_handler_android: - dependency: transitive - description: - name: permission_handler_android - sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" - url: "https://pub.dev" - source: hosted - version: "13.0.1" - permission_handler_apple: - dependency: transitive - description: - name: permission_handler_apple - sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.dev" - source: hosted - version: "9.4.7" - permission_handler_html: - dependency: transitive - description: - name: permission_handler_html - sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.dev" - source: hosted - version: "0.1.3+5" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.dev" - source: hosted - version: "4.3.0" - permission_handler_windows: - dependency: transitive - description: - name: permission_handler_windows - sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.dev" - source: hosted - version: "0.2.1" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" - url: "https://pub.dev" - source: hosted - version: "7.0.1" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - posix: - dependency: transitive - description: - name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.dev" - source: hosted - version: "6.0.3" - provider: - dependency: "direct main" - description: - name: provider - sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.dev" - source: hosted - version: "6.1.5+1" - rrule: - dependency: transitive - description: - name: rrule - sha256: b7425410c594d4b6717c9f17ec8ef83c9d1ff2e513c428a135b5924fc2e8e045 - url: "https://pub.dev" - source: hosted - version: "0.2.17" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" - sanitize_html: - dependency: transitive - description: - name: sanitize_html - sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - share_plus: - dependency: "direct main" - description: - name: share_plus - sha256: d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1 - url: "https://pub.dev" - source: hosted - version: "11.1.0" - share_plus_platform_interface: - dependency: transitive - description: - name: share_plus_platform_interface - sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" - url: "https://pub.dev" - source: hosted - version: "2.5.3" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74 - url: "https://pub.dev" - source: hosted - version: "2.4.12" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" - url: "https://pub.dev" - source: hosted - version: "2.5.4" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" - source: hosted - version: "2.4.3" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shimmer: - dependency: "direct main" - description: - name: shimmer - sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sizer: - dependency: "direct main" - description: - name: sizer - sha256: "9963c89e4d30d7c2108de3eafc0a7e6a4a8009799376ea6be5ef0a9ad87cfbad" - url: "https://pub.dev" - source: hosted - version: "3.1.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" - url: "https://pub.dev" - source: hosted - version: "2.5.6" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - syncfusion_flutter_calendar: - dependency: "direct main" - description: - name: syncfusion_flutter_calendar - sha256: "8e8a4eef01d6a82ae2c17e76d497ff289ded274de014c9f471ffabc12d1e2e71" - url: "https://pub.dev" - source: hosted - version: "30.2.7" - syncfusion_flutter_core: - dependency: transitive - description: - name: syncfusion_flutter_core - sha256: bfd026c0f9822b49ff26fed11cd3334519acb6a6ad4b0c81d9cd18df6af1c4c0 - url: "https://pub.dev" - source: hosted - version: "30.2.7" - syncfusion_flutter_datepicker: - dependency: transitive - description: - name: syncfusion_flutter_datepicker - sha256: b5f35cc808e91b229d41613efe71dadab1549a35bfd493f922fc06ccc2fe908c - url: "https://pub.dev" - source: hosted - version: "30.2.7" - syncfusion_localizations: - dependency: transitive - description: - name: syncfusion_localizations - sha256: bb32b07879b4c1dee5d4c8ad1c57343a4fdae55d65a87f492727c11b68f23164 - url: "https://pub.dev" - source: hosted - version: "30.2.7" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 - url: "https://pub.dev" - source: hosted - version: "3.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" - source: hosted - version: "0.7.4" - time: - dependency: transitive - description: - name: time - sha256: "370572cf5d1e58adcb3e354c47515da3f7469dac3a95b447117e728e7be6f461" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - timezone: - dependency: transitive - description: - name: timezone - sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "69ee86740f2847b9a4ba6cffa74ed12ce500bbe2b07f3dc1e643439da60637b7" - url: "https://pub.dev" - source: hosted - version: "6.3.18" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7 - url: "https://pub.dev" - source: hosted - version: "6.3.4" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f - url: "https://pub.dev" - source: hosted - version: "3.2.3" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" - url: "https://pub.dev" - source: hosted - version: "3.1.4" - uuid: - dependency: "direct main" - description: - name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff - url: "https://pub.dev" - source: hosted - version: "4.5.1" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" - source: hosted - version: "15.0.0" - web: - dependency: "direct main" - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - win32: - dependency: transitive - description: - name: win32 - sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" - url: "https://pub.dev" - source: hosted - version: "5.14.0" - win32_registry: - dependency: transitive - description: - name: win32_registry - sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" - source: hosted - version: "6.6.1" -sdks: - dart: ">=3.8.0 <4.0.0" - flutter: ">=3.29.0" From 357cf4392e40d1530504f8b783232f79be4fde6c Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Mon, 1 Sep 2025 12:58:41 +0300 Subject: [PATCH 02/10] Updated architecture --- android/app/build.gradle.kts | 3 +- android/build.gradle.kts | 6 +- ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Podfile | 2 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- lib/core/api/api_client.dart | 58 +++++++------- lib/core/app_state.dart | 8 +- lib/core/dependencies.dart | 30 ++++++- lib/core/exceptions/api_exception.dart | 2 + lib/core/exceptions/api_failure.dart | 42 ++++++++++ .../authentication/authentication_repo.dart | 57 +++++++++++++- .../authentication_view_model.dart | 45 ++++++++++- .../book_appointments_repo.dart | 56 +++++++++++++ lib/features/common/common_repo.dart | 13 ++++ .../my_appointments/my_appointments_repo.dart | 78 +++++++++++++++++++ lib/main.dart | 26 +++---- lib/services/cache_service.dart | 14 ++++ lib/services/logger_service.dart | 4 +- pubspec.yaml | 4 +- 19 files changed, 386 insertions(+), 70 deletions(-) create mode 100644 lib/core/exceptions/api_failure.dart create mode 100644 lib/services/cache_service.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index f531524..432ad2a 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,10 +1,9 @@ plugins { id("com.android.application") id("kotlin-android") - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") id("com.google.gms.google-services") - id("com.huawei.agconnect") +// id("com.huawei.agconnect") } android { diff --git a/android/build.gradle.kts b/android/build.gradle.kts index d60f0c0..71a2e60 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -2,12 +2,12 @@ buildscript { repositories { google() mavenCentral() - maven { url = uri("https://developer.huawei.com/repo/") } +// maven { url = uri("https://developer.huawei.com/repo/") } } dependencies { classpath("com.android.tools.build:gradle:7.4.2") classpath("com.google.gms:google-services:4.4.1") - classpath("com.huawei.agconnect:agcp:1.9.3.302") +// classpath("com.huawei.agconnect:agcp:1.9.3.302") } } @@ -15,7 +15,7 @@ allprojects { repositories { google() mavenCentral() - maven { url = uri("https://developer.huawei.com/repo/") } +// maven { url = uri("https://developer.huawei.com/repo/") } } } diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 7c56964..1dc6cf7 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/ios/Podfile b/ios/Podfile index 6010472..9249e54 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -99,4 +99,4 @@ post_integrate do |installer| end end project.save() -end \ No newline at end of file +end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3f36518..bac2157 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -435,7 +435,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -564,7 +564,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -615,7 +615,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 4e08cd1..ef15c95 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -3,14 +3,15 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/consts.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; -import '../app_state.dart'; -import '../consts.dart'; -import '../utils/utils.dart'; -import '../../main.dart'; // ignore_for_file: avoid_annotating_with_dynamic @@ -31,12 +32,16 @@ class APIError { } APIException _throwAPIException(Response response, Function retryCallBack) { + + +LoggerService loggerService = getIt.get(); + switch (response.statusCode) { case 200: APIError? apiError; if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); - print(jsonError); + loggerService.logInfo(jsonError.toString()); apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']); } return APIException(APIException.BAD_REQUEST, error: apiError); @@ -75,11 +80,9 @@ abstract class IApiClient { } class ApiClient implements IApiClient { - // static final ApiClient _instance = ApiClient._internal(); - - // ApiClient._internal(); + LoggerService loggerService; - // factory ApiClient() => _instance; + ApiClient({required this.loggerService}); @override Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, @@ -89,18 +92,18 @@ class ApiClient implements IApiClient { _headers.addAll(headers); } if (!kReleaseMode) { - print("Url:$url"); + loggerService.logInfo("Url:$url"); var bodyJson = json.encode(jsonObject); - print("body:$bodyJson"); + loggerService.logInfo("body:$bodyJson"); } var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); // try { if (!kReleaseMode) { - logger.i("res: " + response.body); + loggerService.logInfo("res: ${response.body}"); } var jsonData = jsonDecode(response.body); if (jsonData["IsAuthenticated"] != null) { - AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; + getIt.get().setIsAuthenticated = jsonData["IsAuthenticated"]; } if (jsonData["ErrorMessage"] == null) { return factoryConstructor(jsonData); @@ -146,16 +149,16 @@ class ApiClient implements IApiClient { } if (queryParameters != null) { // var queryString = new Uri(queryParameters: queryParameters).query; - var queryString = Uri(queryParameters: queryParameters.map((key, value) => MapEntry(key, value == null ? null : value.toString()))).query; - url = url + '?' + queryString; + var queryString = Uri(queryParameters: queryParameters.map((key, value) => MapEntry(key, value?.toString()))).query; + url = '$url?$queryString'; } // if (!kReleaseMode && url.contains("saned")) { if (!kReleaseMode) { - print("Url: $url"); - print("Headers: $_headers"); + loggerService.logInfo("Url: $url"); + loggerService.logInfo("Headers: $_headers"); // var bodyJson = json.encode(requestBody); - print("body: $requestBody"); + loggerService.logInfo("body: $requestBody"); } var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120)); @@ -170,7 +173,7 @@ class ApiClient implements IApiClient { } } on SocketException catch (e) { if (retryTimes > 0) { - print('will retry after 3 seconds...'); + loggerService.logInfo('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -178,7 +181,7 @@ class ApiClient implements IApiClient { } } on HttpException catch (e) { if (retryTimes > 0) { - print('will retry after 3 seconds...'); + loggerService.logInfo('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -188,7 +191,7 @@ class ApiClient implements IApiClient { throw APIException(APIException.TIMEOUT, arguments: e); } on ClientException catch (e) { if (retryTimes > 0) { - print('will retry after 3 seconds...'); + loggerService.logInfo('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -199,7 +202,7 @@ class ApiClient implements IApiClient { @override Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isAuthAPI = false}) async { - logger.i("Url:$url"); + loggerService.logInfo("Url:$url"); if (headers == null) { headers = {'Content-Type': 'application/json'}; } else { @@ -225,8 +228,8 @@ class ApiClient implements IApiClient { } if (queryParameters != null) { - var queryString = new Uri(queryParameters: queryParameters).query; - url = url + '?' + queryString; + var queryString = Uri(queryParameters: queryParameters).query; + url = '$url?$queryString'; } var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60)); @@ -239,7 +242,7 @@ class ApiClient implements IApiClient { } } on SocketException catch (e) { if (retryTimes > 0) { - print('will retry after 3 seconds...'); + loggerService.logInfo('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -247,7 +250,7 @@ class ApiClient implements IApiClient { } } on HttpException catch (e) { if (retryTimes > 0) { - print('will retry after 3 seconds...'); + loggerService.logInfo('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -257,7 +260,7 @@ class ApiClient implements IApiClient { throw APIException(APIException.TIMEOUT, arguments: e); } on ClientException catch (e) { if (retryTimes > 0) { - print('will retry after 3 seconds...'); + loggerService.logInfo('will retry after 3 seconds...'); await Future.delayed(Duration(seconds: 3)); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -282,7 +285,6 @@ class ApiClient implements IApiClient { Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); - Future _put(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.put(url, headers: headers, body: body, encoding: encoding)); @override void setHomeUrl(String url) { diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index 4bed676..684c600 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -5,14 +5,10 @@ import 'package:hmg_patient_app_new/main.dart'; import 'consts.dart'; class AppState { - static final AppState _instance = AppState._internal(); - - AppState._internal(); - - factory AppState() => _instance; + // Simple constructor - let get_it handle the singleton behavior + AppState(); //Tokens - bool isAuthenticated = false; set setIsAuthenticated(v) => isAuthenticated = v; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 4b3b0d6..82e3fe7 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -1,9 +1,31 @@ +import 'package:get_it/get_it.dart'; +import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; -import 'package:injector/injector.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; +import 'package:hmg_patient_app_new/features/common/common_repo.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; +import 'package:hmg_patient_app_new/services/cache_service.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:logger/web.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +GetIt getIt = GetIt.instance; class AppDependencies { - static void addDependencies() { - Injector injector = Injector.appInstance; - injector.registerSingleton(() => AppState()); + static Future addDependencies() async { + // Services + getIt.registerLazySingleton(() => LoggerServiceImp(logger: Logger(printer: PrettyPrinter(lineLength: 0)))); + final sharedPreferences = await SharedPreferences.getInstance(); + getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences)); + getIt.registerSingleton(AppState()); + getIt.registerLazySingleton(() => ApiClient(loggerService: getIt())); + + // Repositories + getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); + getIt.registerLazySingleton(() => AuthenticationRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => MyAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + } } diff --git a/lib/core/exceptions/api_exception.dart b/lib/core/exceptions/api_exception.dart index 7d94212..5076cc3 100644 --- a/lib/core/exceptions/api_exception.dart +++ b/lib/core/exceptions/api_exception.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:equatable/equatable.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; class APIException implements Exception { @@ -27,3 +28,4 @@ class APIException implements Exception { return jsonEncode(this); } } + diff --git a/lib/core/exceptions/api_failure.dart b/lib/core/exceptions/api_failure.dart new file mode 100644 index 0000000..eaa434e --- /dev/null +++ b/lib/core/exceptions/api_failure.dart @@ -0,0 +1,42 @@ + +import 'package:equatable/equatable.dart'; + +abstract class Failure extends Equatable implements Exception { + final String message; + const Failure(this.message); +} + +class ServerFailure extends Failure { + const ServerFailure(super.message); + + @override + List get props => [message]; +} + +class ConnectivityFailure extends Failure { + const ConnectivityFailure(super.message); + + @override + List get props => [message]; +} + +class LocalStorageFailure extends Failure { + const LocalStorageFailure(super.message); + + @override + List get props => [message]; +} + +class DuplicateUsername extends Failure { + const DuplicateUsername({String? message}) : super(message ?? ''); + + @override + List get props => [message]; +} + +class InvalidCredentials extends Failure { + const InvalidCredentials({String? message}) : super(message ?? ''); + + @override + List get props => [message]; +} diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 1755fba..64bc2ca 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,4 +1,59 @@ -class AuthenticationRepo { + +import 'package:dartz/dartz.dart'; +import 'package:hmg_patient_app_new/core/api/api_client.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; + +abstract class AuthenticationRepo { + Future> signIn({required String phone, required String password}); +} + +class AuthenticationRepoImp implements AuthenticationRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + AuthenticationRepoImp({required this.loggerService, required this.apiClient}); + + @override + Future> signIn({required String phone, required String password}) async { + try { + // Mock API call with delayed response + final result = await Future.delayed( + const Duration(seconds: 2), + () => { + 'success': true, + 'data': [ + { + 'id': '1', + 'name': 'Dr. Ahmed Hassan', + 'specialty': 'Cardiology', + 'experience': '10 years', + 'rating': 4.8, + 'image': 'https://example.com/doctor1.jpg' + }, + ] + } + ); + + if (result != null && result is Map && result['success'] != null && result['success'] != null && result['success'] != false) { + return Right(result); + } else { + loggerService.errorLogs(result.toString()); + return Left(ServerFailure(result.toString())); + } + } on APIException catch (e) { + APIError? apiError; + if (e.error is APIError) { + apiError = e.error as APIError; + } + loggerService.errorLogs(e.toString()); + return Left(ServerFailure(apiError?.errorMessage ?? e.message)); + } catch (e) { + loggerService.errorLogs(e.toString()); + return Left(ServerFailure(e.toString())); + } + } } \ No newline at end of file diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index af542ac..434df16 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1,5 +1,46 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; class AuthenticationViewModel extends ChangeNotifier { - // Add properties and methods related to authentication here -} \ No newline at end of file + AuthenticationRepo authenticationRepo; + + AuthenticationViewModel({required this.authenticationRepo}); + + Future signUp({ + required String phone, + required String password, + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + Utils.showLoading(); + final resultEither = await authenticationRepo.signIn( + phone: phone, + password: password, + ); + + if (resultEither.isLeft()) { + + + } + + if (resultEither.isRight()) { + + + } + + + resultEither.fold( + (failure) { + Utils.hideLoading(); + notifyListeners(); + if (onError != null) onError(failure.message); + }, + (data) { + Utils.hideLoading(); + notifyListeners(); + if (onSuccess != null) onSuccess(data); + }, + ); + } +} diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index e69de29..b994b35 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -0,0 +1,56 @@ +import 'package:dartz/dartz.dart'; +import 'package:hmg_patient_app_new/core/api/api_client.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; + +abstract class BookAppointmentsRepo { + Future> getDoctors(); +} + +class BookAppointmentsRepoImp implements BookAppointmentsRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + BookAppointmentsRepoImp({required this.loggerService, required this.apiClient}); + + @override + Future> getDoctors() async { + try { + // Mock API call with delayed response + final result = await Future.delayed( + const Duration(seconds: 2), + () => { + 'success': true, + 'data': [ + { + 'id': '1', + 'name': 'Dr. Ahmed Hassan', + 'specialty': 'Cardiology', + 'experience': '10 years', + 'rating': 4.8, + 'image': 'https://example.com/doctor1.jpg' + }, + ] + } + ); + + if (result != null && result is Map && result['success'] != null && result['success'] != false) { + return Right(result); + } else { + loggerService.errorLogs(result.toString()); + return Left(ServerFailure(result.toString())); + } + } on APIException catch (e) { + APIError? apiError; + if (e.error is APIError) { + apiError = e.error as APIError; + } + loggerService.errorLogs(e.toString()); + return Left(ServerFailure(apiError?.errorMessage ?? e.message)); + } catch (e) { + loggerService.errorLogs(e.toString()); + return Left(ServerFailure(e.toString())); + } + } +} diff --git a/lib/features/common/common_repo.dart b/lib/features/common/common_repo.dart index e69de29..1d7301c 100644 --- a/lib/features/common/common_repo.dart +++ b/lib/features/common/common_repo.dart @@ -0,0 +1,13 @@ +import 'package:hmg_patient_app_new/services/logger_service.dart'; + +abstract class CommonRepo { + +} + + +class CommonRepoImp implements CommonRepo { + LoggerService loggerService; + + CommonRepoImp({required this.loggerService}); + +} \ No newline at end of file diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index e69de29..7ac0c47 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -0,0 +1,78 @@ +import 'package:dartz/dartz.dart'; +import 'package:hmg_patient_app_new/core/api/api_client.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; + +abstract class MyAppointmentsRepo { + Future> getMyAppointments(); +} + +class MyAppointmentsRepoImp implements MyAppointmentsRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + MyAppointmentsRepoImp({required this.loggerService, required this.apiClient}); + + @override + Future> getMyAppointments() async { + try { + // Mock API call with delayed response + final result = await Future.delayed( + const Duration(seconds: 2), + () => { + 'success': true, + 'data': [ + { + 'id': '1', + 'doctorName': 'Dr. Ahmed Hassan', + 'specialty': 'Cardiology', + 'appointmentDate': '2025-09-05', + 'appointmentTime': '10:00 AM', + 'status': 'confirmed', + 'clinicName': 'HMG Hospital', + 'patientName': 'John Doe' + }, + { + 'id': '2', + 'doctorName': 'Dr. Sarah Johnson', + 'specialty': 'Dermatology', + 'appointmentDate': '2025-09-08', + 'appointmentTime': '2:30 PM', + 'status': 'pending', + 'clinicName': 'HMG Medical Center', + 'patientName': 'John Doe' + }, + { + 'id': '3', + 'doctorName': 'Dr. Mohamed Ali', + 'specialty': 'Pediatrics', + 'appointmentDate': '2025-08-25', + 'appointmentTime': '11:15 AM', + 'status': 'completed', + 'clinicName': 'HMG Children\'s Clinic', + 'patientName': 'John Doe' + } + ] + } + ); + + if (result != null && result is Map && result['success'] != null && result['success'] != false) { + return Right(result); + } else { + loggerService.errorLogs(result.toString()); + return Left(ServerFailure(result.toString())); + } + } on APIException catch (e) { + APIError? apiError; + if (e.error is APIError) { + apiError = e.error as APIError; + } + loggerService.errorLogs(e.toString()); + return Left(ServerFailure(apiError?.errorMessage ?? e.message)); + } catch (e) { + loggerService.errorLogs(e.toString()); + return Left(ServerFailure(e.toString())); + } + } +} diff --git a/lib/main.dart b/lib/main.dart index ce601a2..8adfc4a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,8 +6,10 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/theme/app_theme.dart'; import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; @@ -19,23 +21,11 @@ import 'firebase_options.dart'; var globalMessengerKey = GlobalKey(); final navigatorKey = GlobalKey(); -Logger logger = Logger( - printer: PrettyPrinter( - lineLength: 0, - ), -); - -late AppState appState; @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - print("Firebase backgroundMessageHandler Main!!!"); - // debugPrint('backgroundMessage: message => ${message.notification!.title.toString()}'); - // messagesOpended = message.notification!.title.toString(); - var payload = message.data; - // showCallkitIncoming(payload); - // await backgroundCallHandler(payload); + getIt.get().logInfo("Firebase backgroundMessageHandler Main!!!"); } class MyHttpOverrides extends HttpOverrides { @@ -45,12 +35,17 @@ class MyHttpOverrides extends HttpOverrides { } } -void main() async { +Future callInitializations() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + AppDependencies.addDependencies(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); HttpOverrides.global = MyHttpOverrides(); +} + +void main() async { + callInitializations(); runApp( EasyLocalization( supportedLocales: const [ @@ -61,7 +56,7 @@ void main() async { fallbackLocale: Locale('en', 'US'), child: MultiProvider(providers: [ ChangeNotifierProvider( - create: (_) => AuthenticationViewModel(), + create: (_) => AuthenticationViewModel(authenticationRepo: getIt()), ), ], child: MyApp()), ), @@ -71,7 +66,6 @@ void main() async { class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { return SafeArea( diff --git a/lib/services/cache_service.dart b/lib/services/cache_service.dart new file mode 100644 index 0000000..f25409e --- /dev/null +++ b/lib/services/cache_service.dart @@ -0,0 +1,14 @@ + +import 'package:shared_preferences/shared_preferences.dart'; + +abstract class CacheService { + +} + +class CacheServiceImp implements CacheService { + SharedPreferences sharedPreferences; + + CacheServiceImp({required this.sharedPreferences}); + + +} diff --git a/lib/services/logger_service.dart b/lib/services/logger_service.dart index 833a7d2..0b33c52 100644 --- a/lib/services/logger_service.dart +++ b/lib/services/logger_service.dart @@ -3,7 +3,7 @@ import 'package:logger/logger.dart'; abstract class LoggerService { - void logError(String message); + void errorLogs(String message); void logInfo(String message); } @@ -16,7 +16,7 @@ class LoggerServiceImp implements LoggerService { @override - void logError(String message) { + void errorLogs(String message) { logger.e(message); } diff --git a/pubspec.yaml b/pubspec.yaml index db3d25e..27ba216 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,8 +30,8 @@ dependencies: # firebase_core: ^3.13.1 permission_handler: ^12.0.1 flutter_local_notifications: ^19.4.1 - injector: ^4.0.0 provider: ^6.1.5+1 + get_it: ^8.2.0 just_audio: ^0.10.4 flutter_callkit_incoming: git: @@ -60,6 +60,8 @@ dependencies: dropdown_search: ^6.0.2 google_maps_flutter: ^2.12.3 flutter_zoom_videosdk: ^2.1.10 + dartz: ^0.10.1 + equatable: ^2.0.7 web: any From 45e868adbad8d4c1865b4da1ff978353c6cbb7a2 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Mon, 1 Sep 2025 15:55:21 +0300 Subject: [PATCH 03/10] pushed new API --- ios/Runner.xcodeproj/project.pbxproj | 14 +++- .../authentication/authentication_repo.dart | 37 +++------ .../authentication_view_model.dart | 13 ++-- ...ent_last_login_details_response_model.dart | 30 ++++---- .../models/select_device_by_imei.dart | 77 +++++++++++++++++++ 5 files changed, 121 insertions(+), 50 deletions(-) create mode 100644 lib/features/authentication/models/select_device_by_imei.dart diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index bac2157..dae81f2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -279,10 +279,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -296,10 +300,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -451,7 +459,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = 3A359E86ZF; + DEVELOPMENT_TEAM = ZB3P5B74MA; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; @@ -633,7 +641,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = 3A359E86ZF; + DEVELOPMENT_TEAM = ZB3P5B74MA; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; @@ -658,7 +666,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = 3A359E86ZF; + DEVELOPMENT_TEAM = ZB3P5B74MA; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 64bc2ca..a5e9ae3 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,12 +1,13 @@ - import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:http/http.dart'; abstract class AuthenticationRepo { - Future> signIn({required String phone, required String password}); + Future> selectDeviceByImei({required String deviceIMEI}); } class AuthenticationRepoImp implements AuthenticationRepo { @@ -16,28 +17,14 @@ class AuthenticationRepoImp implements AuthenticationRepo { AuthenticationRepoImp({required this.loggerService, required this.apiClient}); @override - Future> signIn({required String phone, required String password}) async { - try { - // Mock API call with delayed response - final result = await Future.delayed( - const Duration(seconds: 2), - () => { - 'success': true, - 'data': [ - { - 'id': '1', - 'name': 'Dr. Ahmed Hassan', - 'specialty': 'Cardiology', - 'experience': '10 years', - 'rating': 4.8, - 'image': 'https://example.com/doctor1.jpg' - }, - ] - } - ); + Future> selectDeviceByImei({required String deviceIMEI}) async { + final mapDevice = {"": deviceIMEI}; - if (result != null && result is Map && result['success'] != null && result['success'] != null && result['success'] != false) { - return Right(result); + final String apiUrl = "https://hmgwebservices.com/Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI" ; + try { + final Response result = await apiClient.postJsonForResponse(apiUrl, mapDevice); + if (result !=null) { + return Right(null); } else { loggerService.errorLogs(result.toString()); return Left(ServerFailure(result.toString())); @@ -54,6 +41,4 @@ class AuthenticationRepoImp implements AuthenticationRepo { return Left(ServerFailure(e.toString())); } } - - -} \ No newline at end of file +} diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 434df16..5b45790 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -7,6 +7,8 @@ class AuthenticationViewModel extends ChangeNotifier { AuthenticationViewModel({required this.authenticationRepo}); + + Future signUp({ required String phone, required String password, @@ -14,13 +16,12 @@ class AuthenticationViewModel extends ChangeNotifier { Function(String)? onError, }) async { Utils.showLoading(); - final resultEither = await authenticationRepo.signIn( - phone: phone, - password: password, - ); + final String deviceIMEI = + "cIkkB7h7Q7uoFkC4Qv82xG:APA91bEb53Z9XzqymCIctaLxCoMX6bm9fuKlWILQ59uUqfwhCoD42AOP1-jWGB1WYd9BVN5PT2pUUFxrT07vcNg1KH9OH39mrPgCl0m21XVIgWrzNnCkufg"; - if (resultEither.isLeft()) { + final resultEither = await authenticationRepo.selectDeviceByImei(deviceIMEI: deviceIMEI); + if (resultEither.isLeft()) { } @@ -37,7 +38,7 @@ class AuthenticationViewModel extends ChangeNotifier { if (onError != null) onError(failure.message); }, (data) { - Utils.hideLoading(); + notifyListeners(); if (onSuccess != null) onSuccess(data); }, diff --git a/lib/features/authentication/models/get_patient_last_login_details_response_model.dart b/lib/features/authentication/models/get_patient_last_login_details_response_model.dart index a14da5e..ce48dd4 100644 --- a/lib/features/authentication/models/get_patient_last_login_details_response_model.dart +++ b/lib/features/authentication/models/get_patient_last_login_details_response_model.dart @@ -48,21 +48,21 @@ class GetPatientLastLoginDetailsResponseModel { } Map toJson() { - final Map data = new Map(); - data['ID'] = this.iD; - data['IMEI'] = this.iMEI; - data['LogInType'] = this.logInType; - data['PatientID'] = this.patientID; - data['OutSA'] = this.outSA; - data['Mobile'] = this.mobile; - data['IdentificationNo'] = this.identificationNo; - data['Name'] = this.name; - data['NameN'] = this.nameN; - data['CreatedOn'] = this.createdOn; - data['EditedOn'] = this.editedOn; - data['BiometricEnabled'] = this.biometricEnabled; - data['PatientType'] = this.patientType; - data['PreferredLanguage'] = this.preferredLanguage; + final Map data = {}; + data['ID'] = iD; + data['IMEI'] = iMEI; + data['LogInType'] = logInType; + data['PatientID'] = patientID; + data['OutSA'] = outSA; + data['Mobile'] = mobile; + data['IdentificationNo'] = identificationNo; + data['Name'] = name; + data['NameN'] = nameN; + data['CreatedOn'] = createdOn; + data['EditedOn'] = editedOn; + data['BiometricEnabled'] = biometricEnabled; + data['PatientType'] = patientType; + data['PreferredLanguage'] = preferredLanguage; return data; } } diff --git a/lib/features/authentication/models/select_device_by_imei.dart b/lib/features/authentication/models/select_device_by_imei.dart new file mode 100644 index 0000000..2ab669e --- /dev/null +++ b/lib/features/authentication/models/select_device_by_imei.dart @@ -0,0 +1,77 @@ +// To parse this JSON data, do +// +// final selectDeviceByImeiRespModel = selectDeviceByImeiRespModelFromJson(jsonString); + +import 'dart:convert'; + +Map selectDeviceByImeiRespModelFromJson(String str) => Map.from(json.decode(str)).map((k, v) => MapEntry(k, v)); + +String selectDeviceByImeiRespModelToJson(Map data) => json.encode(Map.from(data).map((k, v) => MapEntry(k, v))); + +class SelectDeviceByImeiRespModelElement { + int id; + String imei; + int logInType; + int patientId; + bool outSa; + String mobile; + String identificationNo; + String name; + String nameN; + String createdOn; + String editedOn; + bool biometricEnabled; + int patientType; + int preferredLanguage; + + SelectDeviceByImeiRespModelElement({ + required this.id, + required this.imei, + required this.logInType, + required this.patientId, + required this.outSa, + required this.mobile, + required this.identificationNo, + required this.name, + required this.nameN, + required this.createdOn, + required this.editedOn, + required this.biometricEnabled, + required this.patientType, + required this.preferredLanguage, + }); + + factory SelectDeviceByImeiRespModelElement.fromJson(Map json) => SelectDeviceByImeiRespModelElement( + id: json["ID"], + imei: json["IMEI"], + logInType: json["LogInType"], + patientId: json["PatientID"], + outSa: json["OutSA"], + mobile: json["Mobile"], + identificationNo: json["IdentificationNo"], + name: json["Name"], + nameN: json["NameN"], + createdOn: json["CreatedOn"], + editedOn: json["EditedOn"], + biometricEnabled: json["BiometricEnabled"], + patientType: json["PatientType"], + preferredLanguage: json["PreferredLanguage"], + ); + + Map toJson() => { + "ID": id, + "IMEI": imei, + "LogInType": logInType, + "PatientID": patientId, + "OutSA": outSa, + "Mobile": mobile, + "IdentificationNo": identificationNo, + "Name": name, + "NameN": nameN, + "CreatedOn": createdOn, + "EditedOn": editedOn, + "BiometricEnabled": biometricEnabled, + "PatientType": patientType, + "PreferredLanguage": preferredLanguage, + }; +} From d3aff9f93d9b768ee4f9653265ddb2f9a764ebf1 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Mon, 1 Sep 2025 18:44:35 +0300 Subject: [PATCH 04/10] updating structure --- android/app/build.gradle.kts | 187 +++- android/app/src/main/AndroidManifest.xml | 86 +- .../hmg/hmg_patient_app_new/MainActivity.kt | 5 - android/app/src/main/res/values/styles.xml | 12 +- android/build.gradle.kts | 93 +- ios/Podfile.lock | 58 +- ios/Runner.xcodeproj/project.pbxproj | 8 - lib/core/api/api_client.dart | 795 ++++++++++++------ lib/core/api_consts.dart | 765 +++++++++++++++++ lib/core/app_state.dart | 32 +- lib/core/consts.dart | 19 - lib/core/dependencies.dart | 2 +- lib/core/exceptions/api_exception.dart | 5 +- lib/core/post_params_model.dart | 25 +- lib/core/utils/date_util.dart | 487 +++++++++++ lib/core/utils/size_config.dart | 1 + lib/core/utils/utils.dart | 40 + .../authentication/authentication_repo.dart | 22 +- .../authentication_view_model.dart | 40 +- .../models/authenticated_user_model.dart | 292 +++++++ ...heck_activation_code_request_register.dart | 121 +++ .../book_appointments_repo.dart | 8 - .../my_appointments/my_appointments_repo.dart | 7 - lib/main.dart | 4 +- .../login.dart | 22 +- lib/presentation/home/landing_page.dart | 15 +- lib/routes/app_routes.dart | 3 +- lib/services/analytics/analytics_service.dart | 143 ++++ .../analytics/flows/advance_payments.dart | 91 ++ lib/services/analytics/flows/app_nav.dart | 30 + .../analytics/flows/appointments.dart | 268 ++++++ .../analytics/flows/error_tracking.dart | 16 + .../analytics/flows/hamburger_menu.dart | 16 + .../analytics/flows/hmg_services.dart | 19 + lib/services/analytics/flows/live_care.dart | 102 +++ .../analytics/flows/login_registration.dart | 156 ++++ .../analytics/flows/offers_promotions.dart | 17 + lib/services/analytics/flows/todo_list.dart | 111 +++ lib/splashPage.dart | 35 +- lib/theme/colors.dart | 1 + pubspec.lock | 116 ++- pubspec.yaml | 2 + 42 files changed, 3757 insertions(+), 520 deletions(-) delete mode 100644 android/app/src/main/kotlin/com/ejada/hmg/hmg_patient_app_new/MainActivity.kt create mode 100644 lib/core/api_consts.dart create mode 100644 lib/core/utils/date_util.dart create mode 100644 lib/features/authentication/models/authenticated_user_model.dart create mode 100644 lib/features/authentication/models/check_activation_code_request_register.dart rename lib/presentation/{authantication => authentication}/login.dart (92%) create mode 100644 lib/services/analytics/analytics_service.dart create mode 100644 lib/services/analytics/flows/advance_payments.dart create mode 100644 lib/services/analytics/flows/app_nav.dart create mode 100644 lib/services/analytics/flows/appointments.dart create mode 100644 lib/services/analytics/flows/error_tracking.dart create mode 100644 lib/services/analytics/flows/hamburger_menu.dart create mode 100644 lib/services/analytics/flows/hmg_services.dart create mode 100644 lib/services/analytics/flows/live_care.dart create mode 100644 lib/services/analytics/flows/login_registration.dart create mode 100644 lib/services/analytics/flows/offers_promotions.dart create mode 100644 lib/services/analytics/flows/todo_list.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 432ad2a..226d4dd 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,45 +1,188 @@ +import java.util.Properties +import java.io.FileInputStream + plugins { id("com.android.application") id("kotlin-android") + id("com.google.gms.google-services") version "4.4.1" // Add the version here id("dev.flutter.flutter-gradle-plugin") - id("com.google.gms.google-services") -// id("com.huawei.agconnect") + id("com.huawei.agconnect") + // id("com.mapbox.gradle.application") + // id("com.mapbox.gradle.plugins.ndk") +} + +val keystoreProperties = Properties() +val keystorePropertiesFile = rootProject.file("key.properties") +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) } android { - namespace = "com.ejada.hmg.hmg_patient_app_new" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion + namespace = "com.ejada.hmg" + compileSdk = 36 + ndkVersion = "28.2.13676358" - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + defaultConfig { + applicationId = "com.ejada.hmg" + // minSdk = 24 + minSdk = 26 + targetSdk = 35 + compileSdk = 35 + // targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + multiDexEnabled = true } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + buildFeatures { + viewBinding = true + dataBinding = true } - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.ejada.hmg.hmg_patient_app_new" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName + sourceSets { +// getByName("main") { +// java.srcDirs += "src/main/kotlin" +// jniLibs.srcDir("src/main/libs") +// jni.srcDirs = listOf() // disables automatic ndk-build +// } + getByName("main") { + java.srcDir("src/main/kotlin") + jniLibs.srcDir("src/main/libs") + // To disable automatic ndk-build, do not set jni.srcDirs + // If you need to clear jni.srcDirs: + // set("jni.srcDirs", emptyList()) + } + } + + signingConfigs { + create("release") { + keyAlias = keystoreProperties.getProperty("keyAlias") + keyPassword = keystoreProperties.getProperty("keyPassword") + storeFile = keystoreProperties.getProperty("storeFile")?.let { file(it) } + storePassword = keystoreProperties.getProperty("storePassword") + } } buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. + getByName("debug") { + isDebuggable = true signingConfig = signingConfigs.getByName("debug") + isMinifyEnabled = false + isShrinkResources = false + } + getByName("release") { + isDebuggable = false + signingConfig = signingConfigs.getByName("release") + isMinifyEnabled = true + isShrinkResources = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + create("staging") { + matchingFallbacks += listOf("debug", "qa", "release") } } + + packagingOptions { + jniLibs { + pickFirsts += listOf( + "lib/x86/libc++_shared.so", + "lib/x86_64/libc++_shared.so", + "lib/armeabi-v7a/libc++_shared.so", + "lib/arm64-v8a/libc++_shared.so", + "**/*.so" + ) + useLegacyPackaging = true + } + resources { + excludes += listOf("META-INF/proguard/androidx-annotations.pro") + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + isCoreLibraryDesugaringEnabled = true + } + + // kotlinOptions { + // jvmTarget = "17" + // } + + lint { + disable += "MissingTranslation" + checkReleaseBuilds = false + } } flutter { source = "../.." } + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20") + implementation("com.google.firebase:firebase-messaging:24.1.2") + implementation("pub.devrel:easypermissions:3.0.0") + implementation("com.google.guava:guava:33.4.0-android") + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"), "exclude" to listOf("bcprov-jdk16-1.46.jar")))) + implementation("com.google.code.gson:gson:2.12.0") + + // Zoom SDKs + implementation("us.zoom.videosdk:zoomvideosdk-core:1.12.10") + implementation("us.zoom.videosdk:zoomvideosdk-annotation:1.12.10") + implementation("us.zoom.videosdk:zoomvideosdk-videoeffects:1.12.10") + + // Networking + implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11") + implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.11") + implementation("com.squareup.retrofit2:retrofit:2.11.0") + implementation("com.squareup.retrofit2:converter-gson:2.11.0") + implementation("com.squareup.retrofit2:adapter-java8:2.11.0") + + // Google Services + implementation("com.google.android.gms:play-services-location:21.3.0") + implementation("com.google.android.gms:play-services-basement:18.7.0") + + implementation("com.android.volley:volley:1.2.1") + implementation("androidx.constraintlayout:constraintlayout:2.2.1") + implementation("androidx.navigation:navigation-fragment-ktx:2.9.0") + implementation("androidx.navigation:navigation-ui-ktx:2.9.0") + implementation("androidx.activity:activity-ktx:1.10.1") + +// val room_version = "2.6.1" +// implementation("androidx.room:room-runtime:$room_version") +// annotationProcessor("androidx.room:room-compiler:$room_version") + + implementation("net.zetetic:android-database-sqlcipher:4.5.4") + implementation("com.intuit.ssp:ssp-android:1.1.0") + implementation("com.intuit.sdp:sdp-android:1.1.0") + +// implementation("com.github.bumptech.glide:glide:4.16.0") +// annotationProcessor("com.github.bumptech.glide:compiler:4.16.0") + + implementation("com.mapbox.maps:android:11.5.0") + // implementation("com.mapbox.maps:android:11.4.0") + + // AARs +// implementation(files("libs/PenNavUI.aar")) +// implementation(files("libs/Penguin.aar")) +// implementation(files("libs/PenguinRenderer.aar")) + + implementation("com.github.kittinunf.fuel:fuel:2.3.1") + implementation("com.github.kittinunf.fuel:fuel-android:2.3.1") + +// implementation("com.opentok.android:opentok-android-sdk:2.25.2") + +// implementation("com.facebook.stetho:stetho:1.6.0") +// implementation("com.facebook.stetho:stetho-urlconnection:1.6.0") + + implementation("androidx.core:core-ktx:1.16.0") + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("com.google.android.material:material:1.12.0") + + implementation("pl.droidsonroids.gif:android-gif-drawable:1.2.25") + + androidTestImplementation("androidx.test:core:1.6.1") + implementation("com.whatsapp.otp:whatsapp-otp-android-sdk:0.1.0") + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") + // implementation(project(":vitalSignEngine")) +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9eef101..e07754e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -193,31 +193,31 @@ android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE" /> - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/ejada/hmg/hmg_patient_app_new/MainActivity.kt b/android/app/src/main/kotlin/com/ejada/hmg/hmg_patient_app_new/MainActivity.kt deleted file mode 100644 index 1fd6200..0000000 --- a/android/app/src/main/kotlin/com/ejada/hmg/hmg_patient_app_new/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.ejada.hmg.hmg_patient_app_new - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity : FlutterActivity() diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cb1ef88..1f83a33 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,18 +1,18 @@ - - - diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 71a2e60..4b24dd7 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,13 +1,25 @@ buildscript { repositories { - google() mavenCentral() -// maven { url = uri("https://developer.huawei.com/repo/") } + google() + maven { url = uri("https://developer.huawei.com/repo/") } + maven { + url = uri("https://api.mapbox.com/downloads/v2/releases/maven") + credentials { + username = "mapbox" + password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg" + if (password.isNullOrEmpty()) { + throw GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the environment variables.") + } + } + authentication { + create("basic") + } + } } dependencies { - classpath("com.android.tools.build:gradle:7.4.2") - classpath("com.google.gms:google-services:4.4.1") -// classpath("com.huawei.agconnect:agcp:1.9.3.302") + classpath("com.android.tools.build:gradle:8.1.0") + classpath("com.huawei.agconnect:agcp:1.9.1.304") } } @@ -15,16 +27,73 @@ allprojects { repositories { google() mavenCentral() -// maven { url = uri("https://developer.huawei.com/repo/") } + maven { url = uri("https://developer.huawei.com/repo/") } + maven { url = uri("https://artifactory.ess-dev.com/artifactory/gradle-dev-local") } + maven { + url = uri("https://api.mapbox.com/downloads/v2/releases/maven") + credentials { + username = "mapbox" + password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg" + if (password.isNullOrEmpty()) { + throw GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the environment variables.") + } + } + authentication { + create("basic") + } + } + } + + configurations.all { + exclude(group = "org.bouncycastle", module = "bcprov-jdk16") + } + + tasks.withType().configureEach { + sourceCompatibility = JavaVersion.VERSION_21.toString() + targetCompatibility = JavaVersion.VERSION_21.toString() + } + + tasks.withType().configureEach { + kotlinOptions { + jvmTarget = "21" + } } -} -val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() -rootProject.layout.buildDirectory.value(newBuildDir) + subprojects { + afterEvaluate { + if (project.hasProperty("android")) { + project.extensions.findByName("android")?.let { androidExt -> + val android = androidExt as com.android.build.gradle.BaseExtension + if (android.namespace == null) { + android.namespace = project.group.toString() + } + android.buildFeatures.apply { + if (buildConfig == null) { + buildConfig = true + } + } + android.compileOptions.apply { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + } + } + project.tasks.withType().configureEach { + sourceCompatibility = JavaVersion.VERSION_21.toString() + targetCompatibility = JavaVersion.VERSION_21.toString() + } + project.tasks.withType().configureEach { + kotlinOptions { + jvmTarget = "21" + } + } + } + } +} +rootProject.buildDir = File("../build") subprojects { - val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) - project.layout.buildDirectory.value(newSubprojectBuildDir) + project.buildDir = File("${rootProject.buildDir}/${project.name}") } subprojects { project.evaluationDependsOn(":app") @@ -32,4 +101,4 @@ subprojects { tasks.register("clean") { delete(rootProject.layout.buildDirectory) -} +} \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5728064..db4395f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -336,40 +336,40 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: - audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0 - connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd + audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe + connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90 - device_calendar: b55b2c5406cfba45c95a59f9059156daee1f74ed - device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe + device_calendar: 9cb33f88a02e19652ec7b8b122ca778f751b1f7b + device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342 DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be + file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e - firebase_core: 995454a784ff288be5689b796deb9e9fa3601818 - firebase_messaging: f4a41dd102ac18b840eba3f39d67e77922d3f707 + firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c + firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_callkit_incoming: cb8138af67cda6dd981f7101a5d709003af21502 - flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 - flutter_ios_voip_kit_karmm: 371663476722afb631d5a13a39dee74c56c1abd0 - flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb - flutter_zoom_videosdk: df7353598a3f0ad081055166e12c992ac9218a8c - fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 - geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + flutter_callkit_incoming: 417dd1b46541cdd5d855ad795ccbe97d1c18155e + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 + flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579 + flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f + flutter_zoom_videosdk: 7ddc97d617b85aeace252165d2b5fc5638678c38 + fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f + geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 - google_maps_flutter_ios: 0291eb2aa252298a769b04d075e4a9d747ff7264 + google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 - health: f496ad838f4bd227191f5bc05060b6f6138b44fd - image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a - just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed - local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 - manage_calendar_events: fe1541069431af035ced925ebd9def8b4b271254 + health: f1207cccb625fc2e8af263b09c29661bde7b0b7e + image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 + just_audio: a42c63806f16995daf5b219ae1d679deb76e6a79 + local_auth_darwin: fa4b06454df7df8e97c18d7ee55151c57e7af0de + manage_calendar_events: 9b2889799340398027b3e3f5c4891d41599ec257 MapboxCommon: 119f3759f7dc9457f0695848108ab323eb643cb4 MapboxCoreMaps: ca17f67baced23f8c952166ac6314c35bad3f66c MapboxCoreNavigation: 3be9990fae3ed732a101001746d0e3b4234ec023 @@ -381,21 +381,21 @@ SPEC CHECKSUMS: MapboxSpeech: cd25ef99c3a3d2e0da72620ff558276ea5991a77 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 - permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d + package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a - share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 Solar-dev: 4612dc9878b9fed2667d23b327f1d4e54e16e8d0 - sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 + sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e - url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe ZoomVideoSDK: 94e939820e57a075c5e712559f927017da0de06a -PODFILE CHECKSUM: ac23c99fc61c3e92ed1c20a19299a1205568c016 +PODFILE CHECKSUM: 5df9d8aa8f2c105eacd5ad7a310503d93c68c86b -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index dae81f2..a0241a1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -279,14 +279,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -300,14 +296,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index ef15c95..d8b379d 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -1,293 +1,600 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; +import 'dart:io' show Platform; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; -import 'package:hmg_patient_app_new/core/consts.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; -import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; -import 'package:http/http.dart'; -import 'package:http/io_client.dart'; - - -// ignore_for_file: avoid_annotating_with_dynamic - -typedef FactoryConstructor = U Function(dynamic); - -class APIError { - int? errorCode; - String? errorMessage; - - APIError(this.errorCode, this.errorMessage); - - Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage}; - - @override - String toString() { - return jsonEncode(this); - } -} - -APIException _throwAPIException(Response response, Function retryCallBack) { - - -LoggerService loggerService = getIt.get(); - - switch (response.statusCode) { - case 200: - APIError? apiError; - if (response.body != null && response.body.isNotEmpty) { - var jsonError = jsonDecode(response.body); - loggerService.logInfo(jsonError.toString()); - apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']); - } - return APIException(APIException.BAD_REQUEST, error: apiError); - case 400: - APIError? apiError; - if (response.body != null && response.body.isNotEmpty) { - var jsonError = jsonDecode(response.body); - apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']); - } - return APIException(APIException.BAD_REQUEST, error: apiError); - case 401: - return APIException(APIException.UNAUTHORIZED); - case 403: - return APIException(APIException.FORBIDDEN); - case 404: - return APIException(APIException.NOT_FOUND); - case 500: - return APIException(APIException.INTERNAL_SERVER_ERROR); - case 444: - var downloadUrl = response.headers["location"]; - return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl); - default: - return APIException(APIException.OTHER); - } -} - -abstract class IApiClient { - Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, - {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); - - Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); - - Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}); - - void setHomeUrl(String url); +import 'package:http/http.dart' as http; + + +abstract class ApiClient { + Future post( + String endPoint, { + required Map body, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + bool isAllowAny, + bool isExternal, + bool isRCService, + bool bypassConnectionCheck, + }); + + Future get( + String endPoint, { + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + Map? queryParams, + bool isExternal, + bool isRCService, + }); + + Future simplePost( + String fullUrl, { + required Map body, + required Map headers, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + }); + + Future simpleGet( + String fullUrl, { + Function(dynamic response, int statusCode)? onSuccess, + Function(String error, int statusCode)? onFailure, + Map? queryParams, + Map? headers, + }); + + Future simplePut( + String fullUrl, { + Map? body, + Map? headers, + Function(dynamic response, int statusCode)? onSuccess, + Function(String error, int statusCode)? onFailure, + }); + + Future simpleDelete( + String fullUrl, { + Function(dynamic response, int statusCode)? onSuccess, + Function(String error, int statusCode)? onFailure, + Map? queryParams, + Map? headers, + }); + + Future handleUnauthorized(int statusCode, {required String forUrl}); + + String getSessionId(String id); + + Future generatePackagesToken(); } -class ApiClient implements IApiClient { - LoggerService loggerService; - - ApiClient({required this.loggerService}); - - @override - Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, - {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { - var _headers = {'Accept': 'application/json'}; - if (headers != null && headers.isNotEmpty) { - _headers.addAll(headers); - } - if (!kReleaseMode) { - loggerService.logInfo("Url:$url"); - var bodyJson = json.encode(jsonObject); - loggerService.logInfo("body:$bodyJson"); - } - var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); - // try { - if (!kReleaseMode) { - loggerService.logInfo("res: ${response.body}"); - } - var jsonData = jsonDecode(response.body); - if (jsonData["IsAuthenticated"] != null) { - getIt.get().setIsAuthenticated = jsonData["IsAuthenticated"]; - } - if (jsonData["ErrorMessage"] == null) { - return factoryConstructor(jsonData); +class ApiClientImp implements ApiClient { + final _analytics = getIt(); + + final LoggerService loggerService; + ApiClientImp({required this.loggerService}); + + post(String endPoint, + {required Map body, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isExternal = false, + bool isRCService = false, + bool bypassConnectionCheck = false}) async { + AppState appState = getIt.get(); + String url; + if (isExternal) { + url = endPoint; } else { - APIError? apiError; - apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage']); - throw APIException(APIException.BAD_REQUEST, error: apiError); - } - // } catch (ex) { - // if (ex is APIException) { - // rethrow; - // } else { - // throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); - // } - // } - } - - @override - Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { - String? requestBody; - late Map stringObj; - if (jsonObject != null) { - requestBody = jsonEncode(jsonObject); - if (headers == null) { - headers = {'Content-Type': 'application/json'}; + if (isRCService) { + url = RC_BASE_URL + endPoint; } else { - headers['Content-Type'] = 'application/json'; + url = BASE_URL + endPoint; } } - - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); - } - - Future _postForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { try { - var _headers = {}; - // if (token != null) { - // _headers['Authorization'] = 'Bearer $token'; - // } - - if (headers != null && headers.isNotEmpty) { - _headers.addAll(headers); - } - if (queryParameters != null) { - // var queryString = new Uri(queryParameters: queryParameters).query; - var queryString = Uri(queryParameters: queryParameters.map((key, value) => MapEntry(key, value?.toString()))).query; - url = '$url?$queryString'; + var user = appState.getAuthenticatedUser; + Map headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }; + if (!isExternal) { + String? token = appState.appAuthToken; + String? languageID = + (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en') ?? 'ar'; + if (endPoint == ApiConsts.sendActivationCode) { + languageID = 'en'; + } + if (body.containsKey('SetupID')) { + body['SetupID'] = body.containsKey('SetupID') + ? body['SetupID'] ?? body[''] + : SETUP_ID; + } else {} + + if (body.containsKey('LanguageID')) { + if (body['LanguageID'] != null) { + //change this line because language issue happened on dental + body['LanguageID'] = body['LanguageID'] == 'ar' + ? 1 + : body['LanguageID'] == 'en' + ? 2 + : body['LanguageID']; + } + } + + if (body.containsKey('isDentalAllowedBackend')) { + body['isDentalAllowedBackend'] = + body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; + } + + body['DeviceTypeID'] = Platform.isIOS + ? 1 + : await Utils.isGoogleServicesAvailable() + ? 2 + : 3; + + if (!body.containsKey('IsPublicRequest')) { + // if (!body.containsKey('PatientType')) { + if (user != null && user.patientType != null) { + body['PatientType'] = user.patientType; + } else { + body['PatientType'] = PATIENT_TYPE; + } + // } + + // body['PatientType'] = body.containsKey('PatientType') + // ? body['PatientType'] != null + // ? body['PatientType'] + // : user['PatientType'] != null + // ? user['PatientType'] + // : PATIENT_TYPE + // : PATIENT_TYPE; + + // if (!body.containsKey('PatientTypeID')) { + if (user != null && user.patientType != null) { + body['PatientTypeID'] = user.patientType; + } else { + body['PatientType'] = PATIENT_TYPE_ID; + } + // } + + // body['PatientTypeID'] = body.containsKey('PatientTypeID') + // ? body['PatientTypeID'] != null + // ? body['PatientTypeID'] + // : user['PatientType'] != null + // ? user['PatientType'] + // : PATIENT_TYPE_ID + // : PATIENT_TYPE_ID; + + if (user != null) { + body['TokenID'] = body['TokenID'] ?? token; + body['PatientID'] = body['PatientID'] ?? user.patientID; + + body['PatientOutSA'] = body.containsKey('PatientOutSA') + ? body['PatientOutSA'] ?? user.outSA + : user.outSA; + body['SessionID'] = getSessionId(body['TokenID'] ?? ""); //getSe + } + } } - // if (!kReleaseMode && url.contains("saned")) { - if (!kReleaseMode) { - loggerService.logInfo("Url: $url"); - loggerService.logInfo("Headers: $_headers"); - // var bodyJson = json.encode(requestBody); - loggerService.logInfo("body: $requestBody"); - } + body.removeWhere((key, value) => value == null); - var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120)); - - if (response.statusCode >= 200 && response.statusCode < 300) { - return response; + debugPrint("URL : $url"); + final jsonBody = json.encode(body); + debugPrint(jsonBody); + // } + // return; + if (await Utils.checkConnection( + bypassConnectionCheck: bypassConnectionCheck)) { + final response = await http.post(Uri.parse(url.trim()), + body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; + if (statusCode < 200 || statusCode >= 400) { + onFailure('Error While Fetching data', statusCode); + logApiEndpointError( + endPoint, 'Error While Fetching data', statusCode); + } else { + // var decoded = utf8.decode(response.bodyBytes); + var parsed; + // if (url.contains('Services/NHIC.svc/REST/GetPatientInfo')) { + // parsed = json.decode(sampleNHICResponse); + // } else { + parsed = json.decode(utf8.decode(response.bodyBytes)); + // } + + // print("Response: $parsed"); + + if (isAllowAny) { + onSuccess(parsed, statusCode); + } else { + if (parsed['Response_Message'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['ErrorType'] == 4) { + //TODO : handle app update + logApiEndpointError( + endPoint, + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + } + if (parsed['ErrorType'] == 2) { + // todo: handle Logout + logApiEndpointError(endPoint, "session logged out", statusCode); + } + if (isAllowAny) { + onSuccess(parsed, statusCode); + } else if (parsed['IsAuthenticated'] == null) { + if (parsed['isSMSSent'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode); + } else if (parsed['Result'] == 'OK') { + onSuccess(parsed, statusCode); + } else { + // if (parsed != null) { + // onSuccess(parsed, statusCode); + // } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + logApiEndpointError( + endPoint, + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + // logout(); + // } + } + } else if (parsed['MessageStatus'] == 1 || + parsed['SMSLoginRequired'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 2 && + parsed['IsAuthenticated']) { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] == null && + parsed['ErrorEndUserMessage'] == null) { + if (parsed['ErrorSearchMsg'] == null) { + onFailure("Server Error found with no available message", + statusCode); + logApiEndpointError( + endPoint, + "Server Error found with no available message", + statusCode); + } else { + onFailure(parsed['ErrorSearchMsg'], statusCode); + logApiEndpointError( + endPoint, parsed['ErrorSearchMsg'], statusCode); + } + } else { + onFailure( + parsed['message'] ?? + parsed['ErrorEndUserMessage'] ?? + parsed['ErrorMessage'], + statusCode); + logApiEndpointError(endPoint, + parsed['message'] ?? parsed['message'], statusCode); + } + } + } + // else if (!parsed['IsAuthenticated']) { + // await logout(); + // } + else { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] != null) { + onFailure( + parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, + parsed['message'] ?? parsed['message'], statusCode); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + logApiEndpointError( + endPoint, + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + } + } + } + } + } + } } else { - throw _throwAPIException(response, () { - // _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, isAuthAPI: isAuthAPI); - postJsonForResponse(url, requestBody); - }); + onFailure('Please Check The Internet Connection 1', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); } - } on SocketException catch (e) { - if (retryTimes > 0) { - loggerService.logInfo('will retry after 3 seconds...'); - await Future.delayed(Duration(seconds: 3)); - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } catch (e) { + print(e); + if (e.toString().contains("ClientException")) { + onFailure('Something went wrong, plase try again', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); } else { - throw APIException(APIException.OTHER, arguments: e); + onFailure(e.toString(), -1); } - } on HttpException catch (e) { - if (retryTimes > 0) { - loggerService.logInfo('will retry after 3 seconds...'); - await Future.delayed(Duration(seconds: 3)); - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + _analytics.errorTracking + .log(endPoint, error: "api exception: $e - API Path: $url"); + } + } + + get(String endPoint, + {required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + Map? queryParams, + bool isExternal = false, + bool isRCService = false}) async { + String url; + if (isExternal) { + url = endPoint; + } else { + if (isRCService) { + url = RC_BASE_URL + endPoint; } else { - throw APIException(APIException.OTHER, arguments: e); + url = BASE_URL + endPoint; } - } on TimeoutException catch (e) { - throw APIException(APIException.TIMEOUT, arguments: e); - } on ClientException catch (e) { - if (retryTimes > 0) { - loggerService.logInfo('will retry after 3 seconds...'); - await Future.delayed(Duration(seconds: 3)); - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } + if (queryParams != null) { + String queryString = Uri(queryParameters: queryParams).query; + url += '?$queryString'; + } + + debugPrint("URL : $url"); + // print("Body : ${json.encode(body)}"); + + if (await Utils.checkConnection()) { + final response = await http.get( + Uri.parse(url.trim()), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + ); + final int statusCode = response.statusCode; + // print("statusCode :$statusCode"); + + if (statusCode < 200 || statusCode >= 400) { + onFailure!('Error While Fetching data', statusCode); + logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { - throw APIException(APIException.OTHER, arguments: e); + var parsed = json.decode(utf8.decode(response.bodyBytes)); + onSuccess!(parsed, statusCode); } + } else { + onFailure!('Please Check The Internet Connection', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); } } - @override - Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isAuthAPI = false}) async { - loggerService.logInfo("Url:$url"); - if (headers == null) { - headers = {'Content-Type': 'application/json'}; + simplePost( + String fullUrl, { + required Map body, + required Map headers, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + }) async { + String url = fullUrl; + // print("URL Query String: $url"); + // print("body: $body"); + + if (await Utils.checkConnection()) { + headers!.addAll( + {'Content-Type': 'application/json', 'Accept': 'application/json'}); + final response = await http.post( + Uri.parse(url.trim()), + body: json.encode(body), + headers: headers, + ); + final int statusCode = response.statusCode; + // print("statusCode :$statusCode"); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + simplePost(fullUrl, + onFailure: onFailure, + onSuccess: onSuccess, + body: body, + headers: headers); + + // print(response.body.toString()); + + if (statusCode < 200 || statusCode >= 400) { + onFailure!('Error While Fetching data', statusCode); + logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + } else { + onSuccess!(response.body.toString(), statusCode); + } } else { - headers['Content-Type'] = 'application/json'; + onFailure!('Please Check The Internet Connection', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); } - return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, isAuthAPI: isAuthAPI); } - Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isAuthAPI = false}) async { - try { - var _headers = {}; - if (token != null) { - _headers['Authorization'] = 'Bearer $token'; - } + simpleGet(String fullUrl, + {Function(dynamic response, int statusCode)? onSuccess, + Function(String error, int statusCode)? onFailure, + Map? queryParams, + Map? headers}) async { + headers = headers ?? {}; + String url = fullUrl; + + var haveParams = (queryParams != null); + if (haveParams) { + String queryString = Uri(queryParameters: queryParams).query; + url += '?$queryString'; + // print("URL Query String: $url"); + } - if (headers != null && headers.isNotEmpty) { - _headers.addAll(headers); + if (await Utils.checkConnection()) { + headers.addAll( + {'Content-Type': 'application/json', 'Accept': 'application/json'}); + final response = await http.get( + Uri.parse(url.trim()), + headers: headers, + ); + + final int statusCode = response.statusCode; + // print("statusCode :$statusCode"); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + simpleGet(fullUrl, + onFailure: onFailure, + onSuccess: onSuccess, + headers: headers, + queryParams: queryParams); + + if (statusCode < 200 || statusCode >= 400) { + onFailure!('Error While Fetching data', statusCode); + logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + } else { + onSuccess!(response.body.toString(), statusCode); } + } else { + onFailure!('Please Check The Internet Connection', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); + } + } - if (isAuthAPI) { - String token = await Utils.getStringFromPrefs(SharedPrefsConsts.appAuthToken); - _headers['Authorization'] = "Bearer $token"; + simplePut(String fullUrl, + {Map? body, + Map? headers, + Function(dynamic response, int statusCode)? onSuccess, + Function(String error, int statusCode)? onFailure}) async { + String url = fullUrl; + // print("URL Query String: $url"); + + if (await Utils.checkConnection()) { + headers!.addAll( + {'Content-Type': 'application/json', 'Accept': 'application/json'}); + final response = await http.put( + Uri.parse(url.trim()), + body: json.encode(body), + headers: headers, + ); + + final int statusCode = response.statusCode; + // print("statusCode :$statusCode"); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + simplePut(fullUrl, + onFailure: onFailure, + onSuccess: onSuccess, + headers: headers, + body: body); + + if (statusCode < 200 || statusCode >= 400) { + onFailure!('Error While Fetching data', statusCode); + logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + } else { + onSuccess!(response.body.toString(), statusCode); } + } else { + onFailure!('Please Check The Internet Connection', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); + } + } - if (queryParameters != null) { - var queryString = Uri(queryParameters: queryParameters).query; - url = '$url?$queryString'; - } - var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60)); + simpleDelete(String fullUrl, + {Function(dynamic response, int statusCode)? onSuccess, + Function(String error, int statusCode)? onFailure, + Map? queryParams, + Map? headers}) async { + String url = fullUrl; + // print("URL Query String: $url"); + + var haveParams = (queryParams != null); + if (haveParams) { + String queryString = Uri(queryParameters: queryParams).query; + url += '?$queryString'; + // print("URL Query String: $url"); + } - if (response.statusCode >= 200 && response.statusCode < 300) { - return response; - } else { - throw _throwAPIException(response, () { - _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); - }); - } - } on SocketException catch (e) { - if (retryTimes > 0) { - loggerService.logInfo('will retry after 3 seconds...'); - await Future.delayed(Duration(seconds: 3)); - return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + if (await Utils.checkConnection()) { + headers!.addAll( + {'Content-Type': 'application/json', 'Accept': 'application/json'}); + final response = await http.delete( + Uri.parse(url.trim()), + headers: headers, + ); + + final int statusCode = response.statusCode; + // print("statusCode :$statusCode"); + if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + simpleDelete(fullUrl, + onFailure: onFailure, + onSuccess: onSuccess, + queryParams: queryParams, + headers: headers); + + if (statusCode < 200 || statusCode >= 400) { + onFailure!('Error While Fetching data', statusCode); + logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); } else { - throw APIException(APIException.OTHER, arguments: e); - } - } on HttpException catch (e) { - if (retryTimes > 0) { - loggerService.logInfo('will retry after 3 seconds...'); - await Future.delayed(Duration(seconds: 3)); - return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); - } else { - throw APIException(APIException.OTHER, arguments: e); - } - } on TimeoutException catch (e) { - throw APIException(APIException.TIMEOUT, arguments: e); - } on ClientException catch (e) { - if (retryTimes > 0) { - loggerService.logInfo('will retry after 3 seconds...'); - await Future.delayed(Duration(seconds: 3)); - return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); - } else { - throw APIException(APIException.OTHER, arguments: e); + onSuccess!(response.body.toString(), statusCode); } + } else { + onFailure!('Please Check The Internet Connection', -1); + _analytics.errorTracking + .log("internet_connectivity", error: "no internet available"); } } - Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); - - bool _certificateCheck(X509Certificate cert, String host, int port) => true; - - Future _withClient(Future Function(Client) fn) async { - var httpClient = HttpClient()..badCertificateCallback = _certificateCheck; - var client = IOClient(httpClient); - try { - return await fn(client); - } finally { - client.close(); + Future handleUnauthorized(int statusCode, + {required String forUrl}) async { + if (forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { + final token = await generatePackagesToken(); + ApiConsts.packagesAuthHeader['Authorization'] = 'Bearer $token'; + return (token is String); } + return false; } - Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); + String getSessionId(String id) { + return id.replaceAll(RegExp('/[^a-zA-Z]'), ''); + } + Future generatePackagesToken() async { + var url = EXA_CART_API_BASE_URL + PACKAGES_TOKEN; + var body = { + "api_client": { + "client_id": "a4ab6be4-424f-4836-b032-46caed88e184", + "client_secret": "3c1a3e07-4a40-4510-9fb0-ee5f0a72752c" + } + }; + String? token; + final completer = Completer(); + simplePost(url, body: body, headers: {}, + onSuccess: (dynamic stringResponse, int statusCode) { + if (statusCode == 200) { + var jsonResponse = json.decode(stringResponse); + token = jsonResponse['auth_token']; + completer.complete(); + } + }, onFailure: (String error, int statusCode) { + completer.complete(); + logApiFullUrlError(url, error, statusCode); + }); + await completer.future; + return token!; + } + + logApiFullUrlError(String fullUrl, error, code) { + final endpoint = Uri.parse(fullUrl).pathSegments.last; + logApiEndpointError(endpoint, error, code); + } - @override - void setHomeUrl(String url) { - // TODO: implement setHomeUrl + logApiEndpointError(String endPoint, error, code) { + _analytics.errorTracking.log(endPoint, error: error); } } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart new file mode 100644 index 0000000..dc952bf --- /dev/null +++ b/lib/core/api_consts.dart @@ -0,0 +1,765 @@ +import 'dart:io'; + +var MAX_SMALL_SCREEN = 660; +final OPENTOK_API_KEY = '46209962'; +// final OPENTOK_API_KEY = '47464241'; + +// PACKAGES and OFFERS +var EXA_CART_API_BASE_URL = 'https://mdlaboratories.com/offersdiscounts'; +// var EXA_CART_API_BASE_URL = 'http://10.200.101.75:9000'; +var PACKAGES_CATEGORIES = '/api/categories'; +var PACKAGES_STORES = '/api/stores'; +var PACKAGES_TOKEN = '/api/token'; +var PACKAGES_PRODUCTS = '/api/products'; +var PACKAGES_CUSTOMER = '/api/customers'; +var PACKAGES_SHOPPING_CART = '/api/shopping_cart_items'; +var PACKAGES_ORDERS = '/api/orders'; +var PACKAGES_ORDER_HISTORY = '/api/orders/items'; +var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara'; +// var BASE_URL = 'http://10.50.100.198:2018/'; +var BASE_URL = 'https://uat.hmgwebservices.com/'; +// var BASE_URL = 'https://hmgwebservices.com/'; +// var BASE_URL = 'http://10.201.204.103/'; +// var BASE_URL = 'https://orash.cloudsolutions.com.sa/'; +// var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; +// var BASE_URL = 'https://vidamergeuat.cloudsolutions.com.sa/'; + +// var BASE_URL = 'https://webservices.hmg.com/'; + +// var BASE_URL = 'http://10.50.100.198:4422/'; + +// Pharmacy UAT URLs +// var BASE_PHARMACY_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; +// var PHARMACY_BASE_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; + +// // Pharmacy Production URLs +var BASE_PHARMACY_URL = 'https://mdlaboratories.com/exacartapi/api/'; +var PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapi/api/'; + +var PHARMACY_REDIRECT_URL = 'https://bit.ly/AlhabibPharmacy'; + +// Pharmacy VidaPlus URLs +// var BASE_PHARMACY_URL = 'https://mdlaboratories.com/exacartapitest/api/'; +// var PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapitest/api/'; + +// // Pharmacy Pre-Production URLs +// var BASE_PHARMACY_URL = 'https://mdlaboratories.com/exacartapitest/api/'; +// 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/test/'; + +// var RC_BASE_URL = 'https://ms.hmg.com/rc/'; + +var PING_SERVICE = 'Services/Weather.svc/REST/CheckConnectivity'; + +var GET_PROJECT = 'Services/Lists.svc/REST/GetProject'; + +///Geofencing +var GET_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_GetAllPoints'; +var LOG_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_InsertPatientFileInfo'; + +// Delivery Driver +var DRIVER_LOCATION = 'Services/Patients.svc/REST/PatientER_GetDriverLocation'; + +//weather +var WEATHER_INDICATOR = 'Services/Weather.svc/REST/GetCityInfo'; + +var GET_PRIVILEGE = 'Services/Patients.svc/REST/Service_Privilege'; + +// Wifi Credentials +var WIFI_CREDENTIALS = "Services/Patients.svc/Hmg_SMS_Get_By_ProjectID_And_PatientID"; + +///Doctor +var GET_MY_DOCTOR = 'Services/Doctors.svc/REST/GetPatientDoctorAppointmentResult'; +var GET_DOCTOR_PROFILE = 'Services/Doctors.svc/REST/GetDocProfiles'; +var GET_DOCTOR_PRE_POST_IMAGES = 'Services/Doctors.svc/REST/GetDoctorPrePostImages'; +var GET_DOCTOR_RATING_NOTES = 'Services/Doctors.svc/REST/dr_GetNotesDoctorRating'; +var GET_DOCTOR_RATING_DETAILS = 'Services/Doctors.svc/REST/dr_GetDoctorRatingDetails'; + +var GET_DOCTOR_RATING = 'Services/Doctors.svc/REST/dr_GetAvgDoctorRating'; + +///Prescriptions +// var PRESCRIPTIONS = 'Services/Patients.svc/REST/GetPrescriptionApptList'; +var PRESCRIPTIONS = 'Services/Patients.svc/REST/GetPrescriptionApptList_Async'; + +var GET_PRESCRIPTIONS_ALL_ORDERS = 'Services/Patients.svc/REST/PatientER_GetPatientAllPresOrders'; +var GET_PRESCRIPTION_REPORT = 'Services/Patients.svc/REST/INP_GetPrescriptionReport'; +var SEND_PRESCRIPTION_EMAIL = 'Services/Notifications.svc/REST/SendPrescriptionEmail'; +var GET_PRESCRIPTION_REPORT_ENH = 'Services/Patients.svc/REST/GetPrescriptionReport_enh'; + +///Lab Order +var GET_Patient_LAB_ORDERS = 'Services/Patients.svc/REST/GetPatientLabOrders'; +var GET_Patient_LAB_SPECIAL_RESULT = 'Services/Patients.svc/REST/GetPatientLabSpecialResults'; +var SEND_LAB_RESULT_EMAIL = 'Services/Notifications.svc/REST/SendLabReportEmail'; +var GET_Patient_LAB_RESULT = 'Services/Patients.svc/REST/GetPatientLabResults'; +var GET_Patient_LAB_ORDERS_RESULT = 'Services/Patients.svc/REST/GetPatientLabOrdersResults'; +var SEND_COVID_LAB_RESULT_EMAIL = 'Services/Notifications.svc/REST/GenerateCOVIDReport'; +var COVID_PASSPORT_UPDATE = 'Services/Patients.svc/REST/Covid19_Certificate_PassportUpdate'; +var GET_PATIENT_PASSPORT_NUMBER = 'Services/Patients.svc/REST/Covid19_Certificate_GetPassport'; +var SEND_LAB_RESULT_EMAIL_NEW = 'ReportsAPI/api/reports/labReport'; + +var UPDATE_WORKPLACE_NAME = 'Services/Patients.svc/REST/ActivateSickLeave_FromVida'; +var GET_SICKLEAVE_STATUS_ADMISSION_NO = 'Services/ChatBot_Service.svc/REST/GetSickLeaveStatusByAdmissionNo'; + +/// +var GET_PATIENT_ORDERS = 'Services/Patients.svc/REST/GetPatientRadOrders'; +var GET_PATIENT_LAB_ORDERS_BY_APPOINTMENT = 'Services/Patients.svc/REST/GetPatientLabResultsByAppointmentNo'; + +var GET_PATIENT_ORDERS_DETAILS = 'Services/Patients.svc/REST/Rad_UpdatePatientRadOrdersToRead'; +var GET_RAD_IMAGE_URL = 'Services/Patients.svc/Rest/GetRadImageURL'; +var SEND_RAD_REPORT_EMAIL = 'Services/Notifications.svc/REST/SendRadReportEmail'; + +///Feedback +var SEND_FEEDBACK = 'Services/COCWS.svc/REST/InsertCOCItemInSPList'; +var GET_STATUS_FOR_COCO = 'Services/COCWS.svc/REST/GetStatusforCOC'; +// var GET_PATIENT_AppointmentHistory = 'Services' +// '/Doctors.svc/REST/PateintHasAppoimentHistory'; + +var GET_PATIENT_AppointmentHistory = 'Services' + '/Doctors.svc/REST/PateintHasAppoimentHistory_Async'; + +///VITAL SIGN +var GET_PATIENT_VITAL_SIGN = 'Services/Doctors.svc/REST/Doctor_GetPatientVitalSign'; + +///Er Nearest +var GET_NEAREST_HOSPITAL = 'Services/Patients.svc/REST/Patient_GetProjectAvgERWaitingTime'; + +///ED Online +var ER_GET_VISUAL_TRIAGE_QUESTIONS = "services/Doctors.svc/REST/ER_GetVisualTriageQuestions"; +var ER_SAVE_TRIAGE_INFORMATION = "services/Doctors.svc/REST/ER_SaveTriageInformation"; +var ER_GetPatientPaymentInformationForERClinic = "services/Doctors.svc/REST/ER_GetPatientPaymentInformationForERClinic"; + +///Er Nearest +var GET_AMBULANCE_REQUEST = 'Services/Patients.svc/REST/PatientER_RRT_GetAllTransportationMethod'; +var GET_PATIENT_ALL_PRES_ORDERS = 'Services/Patients.svc/REST/PatientER_GetPatientAllPresOrders'; +var GET_PICK_UP_REQUEST_BY_PRES_ORDER_ID = 'Services/Patients.svc/REST/PatientER_RRT_GetPickUpRequestByPresOrderID'; +var UPDATE_PRESS_ORDER = 'Services/Patients.svc/REST/PatientER_UpdatePresOrder'; +var INSERT_ER_INERT_PRES_ORDER = 'Services/Patients.svc/REST/PatientER_InsertPresOrder'; + +/// ER RRT +var GET_ALL_RC_TRANSPORTATION = 'api/Transportation/getalltransportation'; +var GET_ALL_TRANSPORTATIONS_RC = 'api/Transportation/getalltransportation'; +var GET_ALL_RRT_QUESTIONS = 'Services/Patients.svc/REST/PatientER_RRT_GetAllQuestions'; +var GET_RRT_SERVICE_PRICE = 'Services/Patients.svc/REST/PatientE_RealRRT_GetServicePrice'; + +var GET_ALL_TRANSPORTATIONS_ORDERS = 'api/Transportation/get'; + +var CANCEL_AMBULANCE_REQUEST = "api/Transportation/update"; + +var INSERT_TRANSPORTATION_ORDER_RC = "api/Transportation/add"; + +///FindUs +var GET_FINDUS_REQUEST = 'Services/Lists.svc/REST/Get_HMG_Locations'; + +///LiveChat +var GET_LIVECHAT_REQUEST = 'Services/Patients.svc/REST/GetPatientICProjects'; + +///babyInformation +var GET_BABYINFORMATION_REQUEST = 'Services/Community.svc/REST/GetBabyByUserID'; + +///Get Baby By User ID +var GET_BABY_BY_USER_ID = 'Services/Community.svc/REST/GetBabyByUserID'; + +///userInformation +var GET_USERINFORMATION_REQUEST = 'Services/Community.svc/REST/GetUserInformation_New'; + +///Update email +var UPDATE_PATENT_EMAIL = 'Services/Patients.svc/REST/UpdatePateintEmail'; +var UPDATE_PATENT_INFO = 'Services/Community.svc/REST/UpdateUserInfo_New'; + +///addNewChild +var GET_NEWCHILD_REQUEST = 'Services/Community.svc/REST/CreateNewBaby'; + +///newUserId +var GET_NEW_USER_REQUEST = 'Services/Community.svc/REST/CreateNewUser_New'; + +///delete Child +var DELETE_CHILD_REQUEST = 'Services/Community.svc/REST/DeleteBaby'; + +///addNewTABLE +var GET_TABLE_REQUEST = 'Services/Community.svc/REST/CreateVaccinationTable'; + +///BloodDenote +var GET_CITIES_REQUEST = 'Services/Lists.svc/REST/GetAllCities'; + +///BloodDetails +var GET_BLOOD_REQUEST = 'services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails'; + +var SAVE_BLOOD_REQUEST = 'Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType'; + +var GET_BLOOD_AGREEMENT = 'Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation'; +var SAVE_BLOOD_AGREEMENT = 'Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation'; + +///Reports +var REPORTS = 'Services/Doctors.svc/REST/GetPatientMedicalReportStatusInfo'; +var INSERT_REQUEST_FOR_MEDICAL_REPORT = 'Services/Doctors.svc/REST/InsertRequestForMedicalReport'; +var SEND_MEDICAL_REPORT_EMAIL = 'Services/Notifications.svc/REST/SendMedicalReportEmail'; +var GET_INPATIENT_ADMISSIONS = 'Services/inps.svc/REST/getAdmissionForMedicalReport'; +var GET_MEDICAL_REPORT_PDF = 'Services/inps.svc/REST/getMedicalReportPDF'; + +///Rate +// var IS_LAST_APPOITMENT_RATED = 'Services/Doctors.svc/REST/IsLastAppoitmentRated'; +var IS_LAST_APPOITMENT_RATED = 'Services/Doctors.svc/REST/IsLastAppoitmentRated_Async'; +var GET_APPOINTMENT_DETAILS_BY_NO = 'Services/MobileNotifications.svc/REST/GetAppointmentDetailsByApptNo'; +var NEW_RATE_APPOINTMENT_URL = "Services/Doctors.svc/REST/AppointmentsRating_InsertAppointmentRate"; +var NEW_RATE_DOCTOR_URL = "Services/Doctors.svc/REST/DoctorsRating_InsertDoctorRate"; + +var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID'; + +//URL to get clinic list +var GET_CLINICS_LIST_URL = "Services/lists.svc/REST/GetClinicCentralized"; +var GET_CLINICS_LIST_WRT_HOSPITAL_URL = "Services/Lists.svc/REST/GetClinicFromDoctorSchedule"; + +//URL to get active appointment list +var GET_ACTIVE_APPOINTMENTS_LIST_URL = "Services/Doctors.svc/Rest/Dr_GetAppointmentActiveNumber"; + +//URL to get projects list +var GET_PROJECTS_LIST = 'Services/Lists.svc/REST/GetProject'; + +//URL to get doctors list +var GET_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/SearchDoctorsByTime"; + +//URL to dental doctors list +var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping"; + +//URL to get doctor free slots +var GET_DOCTOR_FREE_SLOTS = "Services/Doctors.svc/REST/GetDoctorFreeSlots"; + +//URL to insert appointment +var INSERT_SPECIFIC_APPOINTMENT = "Services/Doctors.svc/REST/InsertSpecificAppointment"; + +//URL to get patient share +var GET_PATIENT_SHARE = "Services/Doctors.svc/REST/GetCheckinScreenAppointmentDetailsByAppointmentNO"; + +//URL to get patient appointment history +var GET_PATIENT_APPOINTMENT_HISTORY = "Services/Doctors.svc/REST/PateintHasAppoimentHistory"; + +var GET_OBGYNE_ORDERS_LIST = "services/Patients.svc/REST/HIS_OBGYNEProcedureGet"; + +var GET_OBGYNE_DOCTORS_LIST = "services/Doctors.svc/REST/HIS_ObgyneUltrasoundDoctors"; + +var OBGYNE_PROCEDURE_UPDATE = "services/Patients.svc/REST/HIS_OBGYNEProcedure_Update"; + +var GET_RRT_PROCEDURE_LIST = "Services/Patients.svc/REST/GetRRTProcedureDetailsListFromVida"; + +var DOCTOR_SCHEDULE_URL = 'Services/Doctors.svc/REST/GetDoctorWorkingHoursTable'; + +var SEND_REPORT_EYE_EMAIL = "Services/Notifications.svc/REST/SendGlassesPrescriptionEmail"; + +var SEND_CONTACT_LENS_PRESCRIPTION_EMAIL = "Services/Notifications.svc/REST/SendContactLensPrescriptionEmail"; + +//URL to get patient appointment curfew history +// var GET_PATIENT_APPOINTMENT_CURFEW_HISTORY = "Services/Doctors.svc/REST/AppoimentHistoryForCurfew"; +var GET_PATIENT_APPOINTMENT_CURFEW_HISTORY = "Services/Doctors.svc/REST/AppoimentHistoryForCurfew_Async"; + +//URL to confirm appointment +var CONFIRM_APPOINTMENT = "Services/MobileNotifications.svc/REST/ConfirmAppointment"; + +var INSERT_VIDA_REQUEST = "Services/ER_VirtualCall.svc/REST/PatientER_VidaRequestInseart"; + +//URL to cancel appointment +var CANCEL_APPOINTMENT = "Services/Doctors.svc/REST/CancelAppointment"; + +//URL get appointment QR +var GENERATE_QR_APPOINTMENT = "Services/Doctors.svc/REST/GenerateQRAppointmentNo"; + +//URL send email appointment QR +var EMAIL_QR_APPOINTMENT = "Services/Notifications.svc/REST/sendEmailForOnLineCheckin"; + +//URL check payment status +var CHECK_PAYMENT_STATUS = "Services/PayFort_Serv.svc/REST/GetRequestStatusByRequestID"; + +//URL create advance payment +var CREATE_ADVANCE_PAYMENT = "Services/Doctors.svc/REST/CreateAdvancePayment"; + +var HIS_CREATE_ADVANCE_PAYMENT = "Services/Patients.svc/REST/HIS_CreateAdvancePayment"; + +var ER_CREATE_ADVANCE_PAYMENT = "services/Doctors.svc/REST/ER_CreateAdvancePaymentForClinic"; + +var ER_INSERT_ADVANCE_PAYMENT = "services/Doctors.svc/REST/ER_InsertEROnlinePaymentDetails"; + +var ADD_ADVANCE_NUMBER_REQUEST = 'Services/PayFort_Serv.svc/REST/AddAdvancedNumberRequest'; + +var GENERATE_ANCILLARY_ORDERS_INVOICE = 'Services/Doctors.svc/REST/AutoGenerateAncillaryOrderInvoice'; + +var IS_ALLOW_ASK_DOCTOR = 'Services/Doctors.svc/REST/GetPatientDoctorAppointmentResult'; +var GET_CALL_REQUEST_TYPE = 'Services/Doctors.svc/REST/GetCallRequestType_LOV'; +var ADD_VIDA_REQUEST = 'Services/ER_VirtualCall.svc/REST/PatientER_VidaRequestInseart'; + +var SEND_CALL_REQUEST = 'Services/Doctors.svc/REST/InsertCallInfo'; + +var GET_LIVECARE_CLINICS = 'Services/ER_VirtualCall.svc/REST/PatientER_GetClinics'; + +var GET_LIVECARE_SCHEDULE_CLINICS = 'Services/Doctors.svc/REST/PatientER_GetClinicsHaveSchedule'; + +var GET_LIVECARE_SCHEDULE_CLINIC_DOCTOR_LIST = 'Services/Doctors.svc/REST/PatientER_GetDoctorByClinicID'; + +var GET_LIVECARE_SCHEDULE_DOCTOR_TIME_SLOTS = 'Services/Doctors.svc/REST/PatientER_GetDoctorFreeSlots'; + +var INSERT_LIVECARE_SCHEDULE_APPOINTMENT = 'Services/Doctors.svc/REST/InsertSpecificAppoitmentForSchedule'; + +var GET_PATIENT_SHARE_LIVECARE = "Services/Doctors.svc/REST/GetCheckinScreenAppointmentDetailsByAppointmentNOForLiveCare"; + +var SET_ONLINE_CHECKIN_FOR_APPOINTMENT = "Services/Patients.svc/REST/SetOnlineCheckInForAppointment"; + +var GET_LIVECARE_CLINIC_TIMING = 'Services/ER_VirtualCall.svc/REST/PatientER_GetClinicsServiceTimingsSchedule'; + +var GET_ER_APPOINTMENT_FEES = 'Services/DoctorApplication.svc/REST/GetERAppointmentFees'; +var GET_ER_APPOINTMENT_TIME = 'Services/ER_VirtualCall.svc/REST/GetRestTime'; + +var CHECK_PATIENT_DERMA_PACKAGE = 'Services/OUTPs.svc/REST/getPatientPackageComponentsForOnlineCheckIn'; + +var ADD_NEW_CALL_FOR_PATIENT_ER = 'Services/DoctorApplication.svc/REST/NewCallForPatientER'; + +var GET_LIVECARE_HISTORY = 'Services/ER_VirtualCall.svc/REST/GetPatientErVirtualHistory'; +var CANCEL_LIVECARE_REQUEST = 'Services/ER_VirtualCall.svc/REST/DeleteErRequest'; +var SEND_LIVECARE_INVOICE_EMAIL = 'Services/Notifications.svc/REST/SendInvoiceForLiveCare'; + +var CHANGE_PATIENT_ER_SESSION = 'Services/DoctorApplication.svc/REST/ChangePatientERSession'; + +var APPLE_PAY_INSERT_REQUEST = 'Services/PayFort_Serv.svc/REST/PayFort_ApplePayRequestData_Insert'; + +var GET_USER_TERMS = 'Services/Patients.svc/REST/GetUserTermsAndConditions'; + +var TAMARA_REQUEST_INSERT = 'Services/PayFort_Serv.svc/REST/AddTamaraRequest'; + +var UPDATE_HEALTH_TERMS = 'services/Patients.svc/REST/UpdatePateintHealthSummaryReport'; + +var GET_PATIENT_HEALTH_STATS = 'Services/Patients.svc/REST/Med_GetTransactionsSts'; + +var SEND_CHECK_IN_NFC_REQUEST = 'Services/Patients.svc/REST/Patient_CheckAppointmentValidation_ForNFC'; + +var CHECK_SCANNED_NFC_QR_CODE = 'Services/Patients.svc/REST/Patient_ValidationMachine_ForNFC'; + +var HAS_DENTAL_PLAN = 'Services/Doctors.svc/REST/Dental_IsPatientHasOnGoingEstimation'; + +var LASER_BODY_PARTS = 'Services/Patients.svc/REST/Laser_GetBodyPartsByCategory'; + +var INSERT_COVID_QUESTIONNAIRE = 'Services/Doctors.svc/REST/COVID19_Questionnarie_Insert'; + +var UPDATE_COVID_QUESTIONNAIRE = 'Services/Doctors.svc/REST/COVID19_Questionnarie_Update'; + +var GET_PATIENT_SHARE_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/GetCheckinScreenAppointmentDetailsByAppointmentNOForWalkIn'; + +var CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/CanPayForWalkinAppointment'; + +//URL to get medicine and pharmacies list +var CHANNEL = 3; +var GENERAL_ID = 'Cs2020@2016\$2958'; +var IP_ADDRESS = '10.20.10.20'; +var VERSION_ID = 18.7; +var SETUP_ID = '91877'; +var LANGUAGE = 2; +// var PATIENT_OUT_SA = 0; +var SESSION_ID = 'TMRhVmkGhOsvamErw'; +var IS_DENTAL_ALLOWED_BACKEND = false; +var PATIENT_TYPE = 1; +var PATIENT_TYPE_ID = 1; +var DEVICE_TOKEN = ""; +var IS_VOICE_COMMAND_CLOSED = true; +var IS_TEXT_COMPLETED = false; +// var DeviceTypeID = Platform.isIOS ? 1 : 2; +// var LANGUAGE_ID = 2; + +var GET_PHARMCY_ITEMS = "Services/Lists.svc/REST/GetPharmcyItems_Region"; +var GET_PHARMACY_LIST = "Services/Patients.svc/REST/GetPharmcyList"; +var GET_PAtIENTS_INSURANCE = "Services/Patients.svc/REST/Get_PatientInsuranceDetails"; +var GET_PAtIENTS_INSURANCE_UPDATED = "Services/Patients.svc/REST/PatientER_GetPatientInsuranceCardUpdateHistory"; + +var INSURANCE_DETAILS = "Services/Patients.svc/REST/Get_InsuranceCheckList"; +var INSURANCE_SCHEMES = "Services/Patients.svc/REST/PatientER_SchemesOfAactiveCompaniesGet"; +var UPDATE_MANUAL_INSURANCE = "Services/Patients.svc/REST/PatientER_PatientInfoForInsuranceCardUpdate"; +var INSURANCE_COMPANIES = "Services/Patients.svc/REST/PatientER_InsuranceCompanyGet"; +var GET_PATIENT_INSURANCE_DETAILS = "Services/Patients.svc/REST/PatientER_GetPatientInsuranceDetails"; +var UPLOAD_INSURANCE_CARD = 'Services/Patients.svc/REST/PatientER_PatientInfoForInsuranceCardUpdate'; + +var GET_VACCINES = "Services/Patients.svc/REST/GetDoneVaccinesByPatientID"; +var GET_VACCINES_EMAIL = "Services/Notifications.svc/REST/SendVaccinesEmail"; +var GET_PAtIENTS_INSURANCE_APPROVALS = "Services/Patients.svc/REST/GetApprovalStatus_Async"; +// var GET_PAtIENTS_INSURANCE_APPROVALS = "Services/Patients.svc/REST/GetApprovalStatus"; +var SEARCH_BOT = 'HabibiChatBotApi/BotInterface/GetVoiceCommandResponse'; + +var GET_VACCINATIONS_ITEMS = "/Services/ERP.svc/REST/GET_VACCINATIONS_ITEMS"; +var GET_VACCINATION_ONHAND = "/Services/ERP.svc/REST/GET_VACCINATION_ONHAND"; + +var GET_PATIENT_SICK_LEAVE = 'Services/Patients.svc/REST/GetPatientSickLeave'; + +var GET_PATIENT_SICK_LEAVE_STATUS = 'Services/Patients.svc/REST/GetPatientSickLeave_Status'; + +var SendSickLeaveEmail = 'Services/Notifications.svc/REST/SendSickLeaveEmail'; + +var GET_PATIENT_AdVANCE_BALANCE_AMOUNT = 'Services/Patients.svc/REST/GetPatientAdvanceBalanceAmount'; +var GET_PATIENT_INFO_BY_ID = 'Services/Doctors.svc/REST/GetPatientInfoByPatientID'; +var GET_PATIENT_INFO_BY_ID_AND_MOBILE_NUMBER = 'Services/Patients.svc/REST/AP_GetPatientInfoByPatientIDandMobileNumber'; +var SEND_ACTIVATION_CODE_FOR_ADVANCE_PAYMENT = 'Services/Authentication.svc/REST/SendActivationCodeForAdvancePayment'; +var CHECK_ACTIVATION_CODE_FOR_ADVANCE_PAYMENT = 'Services/Authentication.svc/REST/CheckActivationCodeForAdvancePayment'; + +var GET_COVID_DRIVETHRU_PROJECT_LIST = 'Services/Doctors.svc/REST/COVID19_ProjectDriveThroughTestingCenter'; + +var GET_COVID_DRIVETHRU_PAYMENT_INFO = 'Services/Doctors.svc/REST/COVID19_GetPatientPaymentInormation'; + +var GET_COVID_DRIVETHRU_FREE_SLOTS = 'Services/Doctors.svc/REST/COVID19_GetFreeSlots'; + +var GET_COVID_DRIVETHRU_PROCEDURES_LIST = 'Services/Doctors.svc/REST/COVID19_GetTestProcedures'; + +///Smartwatch Integration Services +var GET_PATIENT_LAST_RECORD = 'Services/Patients.svc/REST/Med_GetPatientLastRecord'; +var INSERT_PATIENT_HEALTH_DATA = 'Services/Patients.svc/REST/Med_InsertTransactions'; + +///My Trackers +var GET_DIABETIC_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetDiabeticResultAverage'; +var GET_DIABTEC_RESULT = 'Services/Patients.svc/REST/Patient_GetDiabtecResults'; +var ADD_DIABTEC_RESULT = 'Services/Patients.svc/REST/Patient_AddDiabtecResult'; + +var GET_BLOOD_PRESSURE_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetBloodPressureResultAverage'; +var GET_BLOOD_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_GetBloodPressureResult'; +var ADD_BLOOD_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_AddBloodPressureResult'; + +var GET_WEIGHT_PRESSURE_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResultAverage'; +var GET_WEIGHT_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResult'; +var ADD_WEIGHT_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_AddWeightMeasurementResult'; + +var ADD_ACTIVE_PRESCRIPTIONS_REPORT_BY_PATIENT_ID = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID'; + +var GET_CALL_INFO_HOURS_RESULT = 'Services/Doctors.svc/REST/GetCallInfoHoursResult'; +var GET_CALL_REQUEST_TYPE_LOV = 'Services/Doctors.svc/REST/GetCallRequestType_LOV'; + +var GET_QUESTION_TYPES = 'Services/OUTPs.svc/REST/getQuestionsTypes'; + +var UPDATE_DIABETIC_RESULT = 'Services/Patients.svc/REST/Patient_UpdateDiabeticResult'; + +var SEND_AVERAGE_BLOOD_SUGAR_REPORT = 'Services/Notifications.svc/REST/SendAverageBloodSugarReport'; +var DEACTIVATE_DIABETIC_STATUS = 'services/Patients.svc/REST/Patient_DeactivateDiabeticStatus'; +var DEACTIVATE_BLOOD_PRESSURES_STATUS = 'services/Patients.svc/REST/Patient_DeactivateBloodPressureStatus'; + +var UPDATE_BLOOD_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_UpdateBloodPressureResult'; +var SEND_AVERAGE_BLOOD_WEIGHT_REPORT = 'Services/Notifications.svc/REST/SendAverageBodyWeightReport'; +var SEND_AVERAGE_BLOOD_PRESSURE_REPORT = 'Services/Notifications.svc/REST/SendAverageBloodPressureReport'; + +var UPDATE_WEIGHT_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_UpdateWeightMeasurementResult'; +var DEACTIVATE_WEIGHT_PRESSURE_RESULT = 'services/Patients.svc/REST/Patient_DeactivateWeightMeasurementStatus'; +var GET_DOCTOR_RESPONSE = 'Services/Patients.svc/REST/GetDoctorResponse'; +var UPDATE_READ_STATUS = 'Services/Patients.svc/REST/UpdateReadStatus'; + +var INSERT_CALL_INFO = 'Services/Doctors.svc/REST/InsertCallInfo'; +var INSERT_APPOINTMENT_QUESTION = 'Services/OUTPs.svc/REST/insertAppointmentQuestion'; +var RATE_DOCTOR_RESPONSE = 'Services/OUTPs.svc/REST/insertAppointmentQuestionRating'; + +var GET_PATIENT_ALLERGIES = 'Services/Patients.svc/REST/GetPatientAllergies'; + +// H2O +var H2O_GET_USER_PROGRESS = "Services/H2ORemainder.svc/REST/H2O_GetUserProgress"; +var H2O_INSERT_USER_ACTIVITY = "Services/H2ORemainder.svc/REST/H2O_InsertUserActivity"; +var H2O_GET_USER_DETAIL = "Services/H2ORemainder.svc/REST/H2O_GetUserDetails_New"; +var H2O_UPDATE_USER_DETAIL = "Services/H2ORemainder.svc/REST/H2O_UpdateUserDetails_New"; +var H2O_UNDO_USER_ACTIVITY = "Services/H2ORemainder.svc/REST/H2o_UndoUserActivity"; +//E_Referral Services + +var GET_ALL_RELATIONSHIP_TYPES = "Services/Patients.svc/REST/GetAllRelationshipTypes"; +var SEND_ACTIVATION_CODE_FOR_E_REFERRAL = 'Services/Authentication.svc/REST/SendActivationCodeForEReferral'; +var CHECK_ACTIVATION_CODE_FOR_E_REFERRAL = 'Services/Authentication.svc/REST/CheckActivationCodeForEReferral'; +var GET_ALL_CITIES = 'services/Lists.svc/rest/GetAllCities'; +var CREATE_E_REFERRAL = "Services/Patients.svc/REST/CreateEReferral"; +var GET_E_REFERRALS = "Services/Patients.svc/REST/GetEReferrals"; + +// Encillary Orders + +var GET_ANCILLARY_ORDERS = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList'; + +var GET_ANCILLARY_ORDERS_DETAILS = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderProcList'; + +//Pharmacy wishlist +// var GET_WISHLIST = "http://swd-pharapp-01:7200/api/shopping_cart_items/"; + +var GET_DOCTOR_LIST_BY_TIME = "Services/Doctors.svc/REST/SearchDoctorsByTime"; + +// pharmacy +var PHARMACY_AUTORZIE_CUSTOMER = "AutorizeCustomer"; +var PHARMACY_VERIFY_CUSTOMER = "VerifyCustomer"; +var PHARMACY_GET_COUNTRY = "countries"; +// var PHARMACY_CREATE_CUSTOMER = "epharmacy/api/CreateCustomer"; +var PHARMACY_CREATE_CUSTOMER = "getorcreateCustomer"; +var GET_PHARMACY_BANNER = "promotionbanners"; +var GET_PHARMACY_TOP_MANUFACTURER = "topmanufacturer"; +var GET_PHARMACY_BEST_SELLER_PRODUCT = "bestsellerproducts"; +var GET_PHARMACY_PRODUCTs_BY_IDS = "productsbyids/"; +var GET_PHARMACY_PRODUCTs_BY_SKU = "productbysku/"; +var GET_CUSTOMERS_ADDRESSES = "Customers/"; +var SUBSCRIBE_PRODUCT = "subscribe?"; +var GET_ORDER = "orders?"; +var GET_ORDER_DETAILS = "orders/"; +var ADD_CUSTOMER_ADDRESS = "addcustomeraddress"; +var EDIT_CUSTOMER_ADDRESS = "editcustomeraddress"; +var DELETE_CUSTOMER_ADDRESS = "deletecustomeraddress"; +var GET_ADDRESS = "Customers/"; +var GET_Cancel_ORDER = "cancelorder/"; +var WRITE_REVIEW = "Content-Type" + "text/plain; charset=utf-8"; +var GET_SHOPPING_CART = "shopping_cart_items/"; +var GET_SHIPPING_OPTIONS = "get_shipping_option/"; +var DELETE_SHOPPING_CART = "delete_shopping_cart_items/"; +var DELETE_SHOPPING_CART_ALL = "delete_shopping_cart_item_by_customer/"; +var ORDER_SHOPPING_CART = "orders"; +var GET_LACUM_ACCOUNT_INFORMATION = "Services/Patients.svc/REST/GetLakumAccountInformation"; +var GET_LACUM_GROUP_INFORMATION = "Services/Patients.svc/REST/GetlakumInQueryInfoGrouping"; +var LACUM_ACCOUNT_ACTIVATE = "Services/Patients.svc/REST/LakumAccountActivation"; +var LACUM_ACCOUNT_DEACTIVATE = "Services/Patients.svc/REST/LakumAccountDeactivation"; +var CREATE_LAKUM_ACCOUNT = "Services/Patients.svc/REST/PHR_CreateLakumAccount"; +var TRANSFER_YAHALA_LOYALITY_POINTS = "Services/Patients.svc/REST/TransferYaHalaLoyaltyPoints"; +var LAKUM_GET_USER_TERMS_AND_CONDITIONS = "Services/ERP.svc/REST/GetUserTermsAndConditionsForEPharmcy"; + +// var PRESCRIPTION = 'Services/Patients.svc/REST/GetPrescriptionApptList'; +var PRESCRIPTION = 'Services/Patients.svc/REST/GetPrescriptionApptList_Async'; + +var GET_RECOMMENDED_PRODUCT = 'alsoProduct/'; +var GET_MOST_VIEWED_PRODUCTS = "mostview"; +var GET_NEW_PRODUCTS = "newproducts"; + +// Home Health Care +var HHC_GET_ALL_SERVICES = "Services/Patients.svc/REST/PatientER_HHC_GetAllServices"; +var HHC_GET_ALL_CMC_SERVICES = "Services/Patients.svc/REST/PatientER_CMC_GetAllServices"; +var PATIENT_ER_UPDATE_PRES_ORDER = "Services/Patients.svc/REST/PatientER_UpdatePresOrder"; +var GET_ORDER_DETAIL_BY_ID = "Services/Patients.svc/REST/PatientER_HHC_GetTransactionsForOrder"; +var GET_CMC_ORDER_DETAIL_BY_ID = "Services/Patients.svc/REST/PatientER_CMC_GetTransactionsForOrder"; +var GET_CHECK_UP_ITEMS = "Services/Patients.svc/REST/GetCheckUpItems"; +var PUSH_NOTIFICATION_GET_ALL_NOTIFICATIONS = 'Services/MobileNotifications.svc/REST/PushNotification_GetAllNotifications'; +var PUSH_NOTIFICATION_SET_MESSAGES_FROM_POOL_AS_READ = 'Services/MobileNotifications.svc/REST/PushNotification_SetMessagesFromPoolAsRead'; +var GET_PATIENT_ALL_PRES_ORD = 'Services/Patients.svc/REST/PatientER_GetPatientAllPresOrders'; +var PATIENT_ER_INSERT_PRES_ORDER = 'Services/Patients.svc/REST/PatientER_InsertPresOrder'; +var BLOOD_DONATION_REGISTER_BLOOD_TYPE = 'Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType'; +var ADD_USER_AGREEMENT_FOR_BLOOD_DONATION = 'Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation'; + +// HHC RC SERVICES +var HHC_GET_ALL_SERVICES_RC = "api/HHC/getallhhc"; +var ADD_HHC_ORDER_RC = "api/HHC/add"; +var GET_ALL_HHC_ORDERS_RC = 'api/hhc/list'; +var UPDATE_HHC_ORDER_RC = 'api/hhc/update'; + +// CMC RC SERVICES +var GET_ALL_CMC_SERVICES_RC = 'api/cmc/getallcmc'; +var ADD_CMC_ORDER_RC = 'api/cmc/add'; +var GET_ALL_CMC_ORDERS_RC = 'api/cmc/list'; +var UPDATE_CMC_ORDER_RC = 'api/cmc/update'; + +// RRT RC SERVICES +var ADD_RRT_ORDER_RC = "api/rrt/add"; +var GET_ALL_RRT_ORDERS_RC = "api/rrt/list"; +var UPDATE_RRT_ORDER_RC = 'api/rrt/update'; + +// PRESCRIPTION RC SERVICES +var ADD_PRESCRIPTION_ORDER_RC = "api/prescription/add"; +var GET_ALL_PRESCRIPTION_ORDERS_RC = "api/prescription/list"; +var GET_ALL_PRESCRIPTION_INFO_RC = "api/Prescription/info"; +var UPDATE_PRESCRIPTION_ORDER_RC = 'api/prescription/update'; + +//Pharmacy wishlist +var GET_WISHLIST = "shopping_cart_items/"; +var DELETE_WISHLIST = "delete_shopping_cart_item_by_product?customer_id="; +var GET_REVIEW = "customerreviews/"; +var GET_BRANDS = "manufacturer"; +var GET_TOP_BRANDS = "topmanufacturer?page=1&limit=8"; +var GET_PRODUCT_DETAIL = "products/"; +var GET_LOCATION = "Services/Patients.svc/REST/GetPharmcyListBySKU"; +var GET_SPECIFICATION = "productspecification/"; +var GET_BRAND_ITEMS = "products"; +var PHARMACY_MAKE_REVIEW = 'insertreviews'; + +// External API +var ADD_ADDRESS_INFO = "addcustomeraddress"; +var GET_CUSTOMER_ADDRESSES = "Customers/"; +var GET_CUSTOMER_INFO = "VerifyCustomer"; + +//Pharmacy + +var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; +var GET_OFFERS_CATEGORISE = 'discountcategories'; +var GET_OFFERS_PRODUCTS = 'offerproducts/'; +var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id='; +var GET_PARENT_PRODUCTS = 'products?categoryid='; +var GET_SUB_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id='; +var GET_SUB_PRODUCTS = 'products?categoryid='; +var GET_FINAL_PRODUCTS = + 'products?fields=id,reviews,discount_ids,name,namen,localized_names,display_order,short_description,full_description,full_descriptionn,sku,order_minimum_quantity,order_maximum_quantity,price,old_price,images,is_rx,rx_message,rx_messagen,discount_name,discount_namen,approved_rating_sum,approved_total_reviews,allow_back_in_stock_subscriptions,stock_quantity,stock_availability,stock_availabilityn,discount_percentage&CategoryId='; +var GET_CLINIC_CATEGORY = 'Services/Doctors.svc/REST/DP_GetClinicCategory'; +var GET_DISEASE_BY_CLINIC_ID = 'Services/Doctors.svc/REST/DP_GetDiseasesByClinicID'; +var SEARCH_DOCTOR_BY_TIME = 'Services/Doctors.svc/REST/SearchDoctorsByTime'; + +var TIMER_MIN = 10; + +var GOOGLE_API_KEY = "AIzaSyCmevVlr2Bh-c8W1VUzo8gt8JRY7n5PANw"; + +var GET_BRANDS_LIST = 'categoryManufacturer?categoryids='; + +var GET_SEARCH_PRODUCTS = + 'searchproducts?fields=id,discount_ids,reviews,name,namen,localized_names,display_order,short_description,full_description,full_descriptionn,sku,order_minimum_quantity,order_maximum_quantity,price,old_price,images,is_rx,rx_message,rx_messagen,discount_name,discount_namen,approved_rating_sum,approved_total_reviews,allow_back_in_stock_subscriptions,stock_quantity,stock_availability,stock_availabilityn,discount_percentage&search_key='; + +var SCAN_QR_CODE = 'productbysku/'; + +var FILTERED_PRODUCTS = 'products?categoryids='; + +var GET_DOCTOR_LIST_CALCULATION = "Services/Doctors.svc/REST/GetCallculationDoctors"; + +var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = "Services/Patients.svc/REST/GetDentalAppointments"; + +var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceForDentalByAppointmentNo"; + +var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental"; + +var GET_TAMARA_PLAN = 'https://mdlaboratories.com/tamaralive/Home/GetInstallments'; + +var GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; + +var UPDATE_TAMARA_STATUS = 'Services/PayFort_Serv.svc/REST/Tamara_UpdateRequestStatus'; + +var MARK_APPOINTMENT_TAMARA_STATUS = 'Services/Patients.svc/REST/MarkAppointmentForTamaraPayment_FromVida'; + +var AUTO_GENERATE_INVOICE_TAMARA = 'Services/PayFort_Serv.svc/REST/Tamara_GetinfoByAppointmentNo_AutoGenerateInvoice'; + +var GET_ONESIGNAL_VOIP_TOKEN = 'https://onesignal.com/api/v1/players'; + +var CANCEL_PHARMA_LIVECARE_REQUEST = 'https://vcallapi.hmg.com/api/PharmaLiveCare/SendPaymentStatus'; + +var INSERT_FREE_SLOTS_LOGS = 'Services/Doctors.svc/Rest/InsertDoctorFreeSlotsLogs'; + +var GET_NATIONALITY = 'Services/Lists.svc/REST/GetNationality'; + +var PAYFORT_TEST_URL = 'https://sbpaymentservices.payfort.com/FortAPI/paymentApi'; +var PAYFORT_PROD_URL = 'https://paymentservices.payfort.com/FortAPI/paymentApi'; + +// Check If InPatient API +var CHECK_IF_INPATIENT = 'Services/Patients.svc/REST/GetInPatientAdmissionInfo'; + +var CHECK_IF_PATIENT_ADMITTED = 'Services/Inps.svc/REST/checkIsPatientAdmittedOrAdmissionRequest'; + +// Get General Instructions API +var GET_GENERAL_INSTRUCTIONS = 'Services/INPs.svc/REST/getGeneralInstructions'; + +// Get Medical Instructions API +var GET_MEDICAL_INSTRUCTIONS = 'Services/INPs.svc/REST/getPatientAdmissionRequest'; + +var GET_INPATIENT_ADVANCE_PAYMENT_REQUESTS = 'Services/INPs.svc/REST/getInpatientAdvancePendingPayment'; + +var GET_INPATIENT_PAID_ADVANCE_PAYMENT = 'Services/INPs.svc/REST/getInpatientAdvanceHistory'; + +var GET_INPATIENT_ADVANCE_PAYMENT_LINK = 'Services/PayFort_Serv.svc/REST/InsertInPatientAdvanceDetails'; + +var INSERT_INPATIENT_ORDER = 'Services/INPs.svc/REST/Inpcp_insertOrder'; + +var INPATIENT_DISCHARGE_MEDICATIONS = 'Services/INPs.svc/REST/chekPatientHasDischargeMedicine'; + +var GET_BIRTH_NOTIFICATION = 'Services/INPs.svc/REST/getBirthNotification_bymothermrn'; + +var SAVE_BIRTH_NOTIFICATION = 'Services/INPs.svc/REST/SaveBirthNotification'; + +var INSERT_GENERAL_ADMISSION_CONSENT = 'Services/INPs.svc/REST/Inp_insertAAForGeneralAdmissionConsent'; + +//Meal Plan APIs +var GET_ADMITTED_PATIENTS = 'Services/MOP.svc/REST/GetAdmittedPatients'; +var GET_CURRENT_WEEKID_WEEKDAY = 'Services/MOP.svc/REST/GetCurrentWeekAndDayHMGMP'; +var GET_MEALS_OF_SCHEDULE_ID = 'Services/MOP.svc/REST/GetMealsOfScheduleID_Mobile'; +var GET_MEAL_ITEMS_OF_SCHEDULE_ID = 'Services/MOP.svc/REST/GetDefaultItemsOfScheduleID'; +var PLACE_MEAL_PLAN_ORDER = 'Services/MOP.svc/REST/UpdateOrMakeNewOrder'; + +var CHECK_PATIENT_NPHIES_ELIGIBILITY = 'Services/Doctors.svc/REST/checkPatientInsuranceCompanyValidity'; +var CONVERT_PATIENT_TO_CASH = 'Services/Doctors.svc/REST/deActivateInsuranceCompany'; + +var GET_BLOOD_DONATION_PROJECTS_LIST = 'Services/OUTPs.svc/REST/BD_getProjectsHaveBDClinics'; + +var GET_BLOOD_DONATION_FREE_SLOTS = 'Services/OUTPs.svc/REST/BD_GetFreeSlots'; + +var GET_WE_CARE_TOUR_URL = 'Services/Consent.svc/Rest/Consent_VirtualJurny_Url_GetByProjectID'; + +var GET_DENTAL_INSTRUCTIONS = 'Services/OUTPs.svc/Rest/getProcedureNotification'; + +var INSERT_WALKIN_APPOINTMENT = "Services/Doctors.svc/REST/InsertWalkinAppointment"; + +//Usage Agreement APIs +var CHECK_USAGE_AGREEMENT = "Services/Patients.svc/REST/CheckForUsageAgreement"; +var GET_USAGE_AGREEMENT = "Services/Patients.svc/REST/GetUsageAgreementText"; +var ADD_USAGE_AGREEMENT = "Services/Patients.svc/REST/AddUsageAgreement"; + +var GET_ER_ONLINE_PAYMENT_DETAILS = 'Services/OUTPs.svc/Rest/Outp_GetPatientPaymentInformationForERClinic'; + +var AUTO_GENERATE_INVOICE_ER = 'Services/OUTPs.svc/Rest/Outp_AutoGenerateInvoiceForER'; + +var CHECK_IF_PATIENT_ARRIVED_ER_ONLINE_CHECKIN = 'Services/OUTPs.svc/Rest/IsPatientArrived'; + +var CHECK_PATIENT_ER_ADVANCE_BALANCE = 'Services/OUTPs.svc/Rest/getPatientAdvanceBalanceAmountByClinic'; + +var GET_PROJECT_FROM_NFC = 'Services/OUTPs.svc/Rest/GetProjectByNFC'; + +var GET_PATIENT_OCCUPATION_LIST = 'Services/Authentication.svc/REST/GetPatientOccupation'; + +var IS_DOCTOR_AVAILABLE_BY_CALENDAR_SCHEDULE = 'Services/OUTPs.svc/REST/HIS_IsDoctorAvailableByCalendarSchedule'; + +//PAYFORT +var getPayFortProjectDetails = "Services/PayFort_Serv.svc/REST/GetPayFortProjectDetails"; +var addPayFortApplePayResponse = "Services/PayFort_Serv.svc/REST/AddResponse"; +// var payFortEnvironment = FortEnvironment.production; +var applePayMerchantId = "merchant.com.hmgwebservices"; +// var payFortEnvironment = FortEnvironment.test; +// var applePayMerchantId = "merchant.com.hmgwebservices.uat"; + + + +// Auth Provider Consts + + +const String INSERT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; +const String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; +const String CHECK_PATIENT_AUTH = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; +const GET_MOBILE_INFO = 'Services/Authentication.svc/REST/GetMobileLoginInfo'; +const SEND_ACTIVATION_CODE = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; + +const SEND_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; +const CHECK_ACTIVATION_CODE = 'Services/Authentication.svc/REST/CheckActivationCode'; +const CHECK_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; + +const FORGOT_PASSWORD = 'Services/Authentication.svc/REST/CheckActivationCodeForSendFileNo'; +const CHECK_PATIENT_FOR_REGISTRATION = "Services/Authentication.svc/REST/CheckPatientForRegisteration"; + +const CHECK_USER_STATUS = "Services/NHIC.svc/REST/GetPatientInfo"; +const REGISTER_USER = 'Services/Authentication.svc/REST/PatientRegistration'; +const LOGGED_IN_USER_URL = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; + +const FORGOT_PATIENT_ID = 'Services/Authentication.svc/REST/SendPatientIDSMSByMobileNumber'; +const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard'; +const PROFILE_SETTING = 'Services/Patients.svc/REST/GetPateintInfoForUpdate'; +const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo'; + +const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_InsertUpdate'; + + + +class ApiConsts { + static const maxSmallScreen = 660; + + static bool isDevelopment = true; + + // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT + static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD + + static String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + + static num VERSION_ID = 18.9; + + static final String selectDeviceImei = 'https://hmgwebservices.com/Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + static final String sendActivationCode = 'https://hmgwebservices.com/Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; + + + + static setBackendURLs() { + if (isDevelopment) { + baseUrl = "https://uat.hmgwebservices.com/"; + } else { + baseUrl = "https://hmgwebservices.com/"; + } + } + + + + static final Map packagesAuthHeader = {}; + +} \ No newline at end of file diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index 684c600..71fb6a9 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -1,7 +1,9 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:hmg_patient_app_new/core/post_params_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; import 'package:hmg_patient_app_new/main.dart'; +import 'api_consts.dart' as ApiConsts; import 'consts.dart'; class AppState { @@ -21,8 +23,13 @@ class AppState { set setUserLong(v) => userLong = v; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 3, versionID: ApiConsts.VERSION_ID); - + final PostParamsModel _postParamsInitConfig = PostParamsModel( + channel: 3, + versionID: ApiConsts.VERSION_ID, + ipAddress: '10.20.10.20', + generalId: 'Cs2020@2016\$2958', + deviceTypeID: "2", + sessionID: 'TMRhVmkGhOsvamErw'); void setPostParamsInitConfig() { isAuthenticated = false; @@ -30,8 +37,12 @@ class AppState { } PostParamsModel? _postParams; + PostParamsModel? get postParamsObject => _postParams; - Map get postParamsJson => isAuthenticated ? (_postParams?.toJsonAfterLogin() ?? {}) : (_postParams?.toJson() ?? {}); + + Map get postParamsJson => isAuthenticated + ? (_postParams?.toJsonAfterLogin() ?? {}) + : (_postParams?.toJson() ?? {}); void setPostParamsModel(PostParamsModel _postParams) { this._postParams = _postParams; @@ -40,7 +51,18 @@ class AppState { double userLat = 0.0; double userLong = 0.0; - bool isArabic() => EasyLocalization.of(navigatorKey.currentContext!)?.locale.languageCode == "ar"; + bool isArabic() => + EasyLocalization.of(navigatorKey.currentContext!)?.locale.languageCode == + "ar"; + + int getLanguageID(context) => + EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; + + AuthenticatedUser? _authenticatedUser; + + void setAuthenticatedUser(AuthenticatedUser authenticatedUser) { + _authenticatedUser = authenticatedUser; + } - int getLanguageID(context) => EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; + AuthenticatedUser? get getAuthenticatedUser => _authenticatedUser; } diff --git a/lib/core/consts.dart b/lib/core/consts.dart index 5818b1e..216b9a7 100644 --- a/lib/core/consts.dart +++ b/lib/core/consts.dart @@ -1,23 +1,4 @@ -class ApiConsts { - static const maxSmallScreen = 660; - static bool isDevelopment = true; - - // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT - static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD - - static String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; - - static num VERSION_ID = 18.9; - - static setBackendURLs() { - if (isDevelopment) { - baseUrl = "https://uat.hmgwebservices.com/"; - } else { - baseUrl = "https://hmgwebservices.com/"; - } - } -} class SharedPrefsConsts { static String isRememberMe = "remember_me"; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 82e3fe7..a789da4 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -19,7 +19,7 @@ class AppDependencies { final sharedPreferences = await SharedPreferences.getInstance(); getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences)); getIt.registerSingleton(AppState()); - getIt.registerLazySingleton(() => ApiClient(loggerService: getIt())); + getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt())); // Repositories getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); diff --git a/lib/core/exceptions/api_exception.dart b/lib/core/exceptions/api_exception.dart index 5076cc3..eb11b71 100644 --- a/lib/core/exceptions/api_exception.dart +++ b/lib/core/exceptions/api_exception.dart @@ -16,12 +16,11 @@ class APIException implements Exception { static const String UNKNOWN = 'unexpected_error'; final String message; - final APIError? error; final arguments; - const APIException(this.message, {this.arguments, this.error}); + const APIException(this.message, {this.arguments}); - Map toJson() => {'message': message, 'error': error, 'arguments': '$arguments'}; + Map toJson() => {'message': message, 'arguments': '$arguments'}; @override String toString() { diff --git a/lib/core/post_params_model.dart b/lib/core/post_params_model.dart index 218f29f..2f981f6 100644 --- a/lib/core/post_params_model.dart +++ b/lib/core/post_params_model.dart @@ -14,7 +14,7 @@ class PostParamsModel { String? sessionID; String? setupID; - PostParamsModel({this.versionID, this.channel, this.languageID, this.logInTokenID, this.tokenID, this.language, this.ipAddress, this.generalId, this.latitude, this.longitude, this.deviceTypeID}); + PostParamsModel({this.versionID, this.channel, this.languageID, this.logInTokenID, this.tokenID, this.language, this.ipAddress, this.generalId, this.latitude, this.longitude, this.deviceTypeID, this.sessionID}); PostParamsModel.fromJson(Map json) { versionID = json['VersionID']; @@ -22,25 +22,28 @@ class PostParamsModel { languageID = json['LanguageID']; logInTokenID = json['LogInTokenID']; tokenID = json['TokenID']; + sessionID = json['SessionID']; } Map toJson() { Map data = {}; - data['versionID'] = versionID; - data['channel'] = channel; - data['languageID'] = languageID; - data['logInTokenID'] = logInTokenID ?? ""; - data['tokenID'] = tokenID ?? ""; + data['VersionID'] = versionID; + data['Channel'] = channel; + data['LanguageID'] = languageID; + data['LogInTokenID'] = logInTokenID ?? ""; + data['TokenID'] = tokenID ?? ""; + data['SessionID'] = sessionID ?? ""; return data; } Map toJsonAfterLogin() { Map data = {}; - data['versionID'] = versionID; - data['channel'] = channel; - data['languageID'] = languageID; - data['logInTokenID'] = logInTokenID; - data['tokenID'] = tokenID; + data['VersionID'] = versionID; + data['Channel'] = channel; + data['LanguageID'] = languageID; + data['LogInTokenID'] = logInTokenID; + data['TokenID'] = tokenID; + data['SessionID'] = sessionID; return data; } diff --git a/lib/core/utils/date_util.dart b/lib/core/utils/date_util.dart new file mode 100644 index 0000000..1eb3d9f --- /dev/null +++ b/lib/core/utils/date_util.dart @@ -0,0 +1,487 @@ +import 'package:device_calendar/device_calendar.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class DateUtil { + /// convert String To Date function + /// [date] String we want to convert + static DateTime convertStringToDate(String? date) { + if (date != null) { + const start = "/Date("; + const end = "+0300)"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + return DateTime.fromMillisecondsSinceEpoch(int.parse( + date.substring(startIndex + start.length, endIndex), + )); + } else { + return DateTime.now(); + } + } + + static DateTime convertStringToDateSaudiTimezone(String date, int projectId) { + if (date != null) { + const start = "/Date("; + const end = "+0300)"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + // if (projectId == 2 || projectId == 3) { + // return DateTime.fromMillisecondsSinceEpoch( + // int.parse( + // date.substring(startIndex + start.length, endIndex), + // ), + // isUtc: true) + // .add(Duration(hours: 4)); + // } else { + return DateTime.fromMillisecondsSinceEpoch( + int.parse( + date.substring(startIndex + start.length, endIndex), + ), + isUtc: true) + .add(Duration(hours: 3)); + // } + } else { + return DateTime.now(); + } + } + + static DateTime convertStringToDateNoTimeZone(String date) { + // /Date(1585774800000+0300)/ + if (date != null) { + const start = "/Date("; + const end = ")"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + return DateTime.fromMillisecondsSinceEpoch( + int.parse( + date.substring(startIndex + start.length, endIndex), + ), + ); + } else { + return DateTime.now(); + } + } + + static DateTime convertStringToDateTime(String? date) { + if (date != null) { + try { + var dateT = date.split('/'); + var year = dateT[2].substring(0, 4); + var dateP = DateTime(int.parse(year), int.parse(dateT[1]), int.parse(dateT[0])); + return dateP; + } catch (e) { + print(e); + } + + return DateTime.now(); + } else { + return DateTime.now(); + } + } + + static String convertDateToString(DateTime date) { + const start = "/Date("; + const end = "+0300)/"; + int milliseconds = date.millisecondsSinceEpoch; + + return start + "$milliseconds" + end; + } + + static String convertDateToStringLocation(DateTime date) { + const start = "/Date("; + const end = ")/"; + int milliseconds = date.millisecondsSinceEpoch; + + return start + "$milliseconds" + end; + } + + static String convertTime(String timeStr) { + TimeOfDay time = TimeOfDay(hour: int.parse(timeStr.split(":")[0]), minute: int.parse(timeStr.split(":")[1])); // 24-hour format time + + int hour = time.hourOfPeriod; // get hour in 12-hour format + String meridiem = time.period == DayPeriod.am ? "AM" : "PM"; // get AM/PM + + String convertedTime = '$hour:${time.minute == 0 ? "00" : time.minute} $meridiem'; // create the new time string + + return convertedTime; + } + + static String formatDateToDate(DateTime date, bool isArabic) { + return DateFormat('dd MMM yyy', isArabic ? "ar_SA" : "en_US").format(date); + } + + static String formatDateToTime(DateTime date) { + return DateFormat('hh:mm a').format(date); + } + + static String yearMonthDay(DateTime dateTime) { + String dateFormat = '${dateTime.year}-${dateTime.month}-${dateTime.day}'; + return dateFormat; + } + + static String time(DateTime dateTime) { + String dateFormat = '${dateTime.hour}:${dateTime.minute}:00'; + return dateFormat; + } + + static String convertDateMSToJsonDate(utc) { + var dt = new DateTime.fromMicrosecondsSinceEpoch(utc); + + return "/Date(" + (dt.millisecondsSinceEpoch * 1000).toString() + '+0300' + ")/"; + } + + /// check Date + /// [dateString] String we want to convert + static String checkDate(DateTime checkedTime) { + DateTime currentTime = DateTime.now(); + if ((currentTime.year == checkedTime.year) && (currentTime.month == checkedTime.month) && (currentTime.day == checkedTime.day)) { + return "Today"; + } else if ((currentTime.year == checkedTime.year) && (currentTime.month == checkedTime.month)) { + if ((currentTime.day - checkedTime.day) == 1) { + return "YESTERDAY"; + } else if ((currentTime.day - checkedTime.day) == -1) { + return "Tomorrow"; + } + + if ((currentTime.day - checkedTime.day) <= -2) { + return "Next Week"; + } else { + return "Old Date"; + } + } + return "Old Date"; + } + + static String getDateFormatted(String date) { + DateTime dateObj = DateUtil.convertStringToDate(date); + return DateUtil.getWeekDay(dateObj.weekday) + ", " + dateObj.day.toString() + " " + DateUtil.getMonth(dateObj.month) + " " + dateObj.year.toString(); + } + + static String getISODateFormat(DateTime dateTime) { + // 2020-04-30T00:00:00.000 + return dateTime.toIso8601String(); + } + + /// get month by + /// [month] convert month number in to month name + static getMonth(int month) { + switch (month) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + } + } + + /// get month by + /// [month] convert month number in to month name in Arabic + static getMonthArabic(int month) { + switch (month) { + case 1: + return "يناير"; + case 2: + return " فبراير"; + case 3: + return "مارس"; + case 4: + return "أبريل"; + case 5: + return "مايو"; + case 6: + return "يونيو"; + case 7: + return "يوليو"; + case 8: + return "أغسطس"; + case 9: + return "سبتمبر"; + case 10: + return " اكتوبر"; + case 11: + return " نوفمبر"; + case 12: + return "ديسمبر"; + } + } + + static getMonthByName(String month) { + switch (month.toLowerCase()) { + case 'january': + return 1; + case 'february': + return 2; + case 'march': + return 3; + case 'april': + return 4; + case 'may': + return 5; + case 'june': + return 6; + case 'july': + return 7; + case 'august': + return 8; + case 'september': + return 9; + case 'october': + return 10; + case 'november': + return 11; + case 'december': + return 12; + } + } + + static getMonthDateTime(String month, yearName) { + DateTime? date; + try { + date = DateTime(int.parse(yearName), getMonthByName(month)); + } catch (e) { + print(e); + } + return date ?? DateTime.now(); + } + + /// get month by + /// [weekDay] convert week day in int to week day name + static getWeekDay(int weekDay) { + switch (weekDay) { + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday "; + case 7: + return "Sunday"; + } + } + + /// get month by + /// [weekDay] convert week day in int to week day name arabic + static getWeekDayArabic(int weekDay) { + switch (weekDay) { + case 1: + return "الاثنين"; + case 2: + return "الثلاثاء"; + case 3: + return "الاربعاء"; + case 4: + return "الخميس"; + case 5: + return "الجمعه"; + case 6: + return "السبت "; + case 7: + return "الاحد"; + } + } + + static getWeekDayEnglish(int weekDay) { + switch (weekDay) { + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday "; + case 7: + return "Sunday"; + } + } + + /// get data formatted like Apr 26,2020 + /// [dateTime] convert DateTime to data formatted + static String getMonthDayYearDateFormatted(DateTime dateTime) { + if (dateTime != null) { + return getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); + } else { + return ""; + } + } + + /// get data formatted like Apr 26,2020 + /// [dateTime] convert DateTime to data formatted Arabic + static String getMonthDayYearDateFormattedAr(DateTime dateTime) { + if (dateTime != null) { + return getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); + } else { + return ""; + } + } + + /// get data formatted like Thursday, Apr 26,2020 + /// [dateTime] convert DateTime to date formatted + static String getWeekDayMonthDayYearDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) { + return lang == 'en' + ? getWeekDayEnglish(dateTime.weekday) + ", " + getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString() + : getWeekDayArabic(dateTime.weekday) + ", " + dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + } else { + return ""; + } + } + + static String getMonthDayYearLangDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) { + return lang == 'en' + ? getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString() + : dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + } else { + return ""; + } + } + + /// get data formatted like 26/4/2020 + static String getDayMonthYearLangDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) { + return lang == 'en' + ? dateTime.day.toString() + " " + getMonth(dateTime.month) + " " + dateTime.year.toString() + : dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + } else { + return ""; + } + } + + static String getMonthYearLangDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) { + return lang == 'en' ? getMonth(dateTime.month) + " " + dateTime.year.toString() : getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + } else { + return ""; + } + } + + /// get data formatted like 26/4/2020 + /// [dateTime] convert DateTime to data formatted + static String getDayMonthYearDateFormatted(DateTime dateTime) { + if (dateTime != null) { + return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString(); + } else { + return ""; + } + } + + /// get data formatted like 26/4/2020 + /// [dateTime] convert DateTime to data formatted + static String getDayMonthDateFormatted(DateTime dateTime) { + if (dateTime != null) { + return DateFormat('dd/MM').format(dateTime); + } else { + return ""; + } + } + + /// get data formatted like 26/4/2020 + /// [dateTime] convert DateTime to data formatted according to language + static String getDayMonthYearDateFormattedLang(DateTime dateTime, bool isArabic) { + if (dateTime != null) { + return DateFormat('dd/MM/yyyy', isArabic ? "ar_SA" : "en_US").format(dateTime); + } else { + return ""; + } + } + + /// get data formatted like 10:30 according to lang + static String formatDateToTimeLang(DateTime date, bool isArabic) { + return DateFormat('HH:mm', isArabic ? "ar_SA" : "en_US").format(date); + } + + /// get data formatted like 26/4/2020 10:30 + /// [dateTime] convert DateTime to data formatted + static String getDayMonthYearHourMinuteDateFormatted(DateTime dateTime) { + if (dateTime != null) { + return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString() + " " + DateFormat('HH:mm').format(dateTime); + } else { + return ""; + } + } + + /// get data formatted like 2020-8-13 09:43:00 + /// [dateTime] convert DateTime to data formatted + static String getYearMonthDayHourMinSecDateFormatted(DateTime dateTime) { + if (dateTime != null) { + return dateTime.year.toString() + + "-" + + dateTime.month.toString() + + "-" + + dateTime.day.toString() + + " " + + dateTime.hour.toString() + + ":" + + dateTime.minute.toString() + + ":" + + dateTime.second.toString(); + } else { + return ""; + } + } + + static String getFormattedDate(DateTime dateTime, String formattedString) { + return DateFormat(formattedString).format(dateTime); + } + + static convertISODateToJsonDate(String isoDate) { + return "/Date(" + DateFormat('mm-dd-yyy').parse(isoDate).millisecondsSinceEpoch.toString() + ")/"; + } + + static String getDay(DayOfWeek dayOfWeek) { + switch (dayOfWeek) { + case DayOfWeek.Monday: + return "Monday"; + break; + case DayOfWeek.Tuesday: + return "Tuesday"; + break; + case DayOfWeek.Wednesday: + return "Wednesday"; + break; + case DayOfWeek.Thursday: + return "Thursday"; + break; + case DayOfWeek.Friday: + return "Friday"; + break; + case DayOfWeek.Saturday: + return "Saturday"; + break; + case DayOfWeek.Sunday: + return "Sunday"; + break; + } + return ""; + } +} diff --git a/lib/core/utils/size_config.dart b/lib/core/utils/size_config.dart index 65ff374..9c09b09 100644 --- a/lib/core/utils/size_config.dart +++ b/lib/core/utils/size_config.dart @@ -1,4 +1,5 @@ import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/consts.dart'; class SizeConfig { diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 2df35f1..4f7b398 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -1,3 +1,8 @@ +import 'dart:convert'; + +import 'package:crypto/crypto.dart' as crypto; +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:google_api_availability/google_api_availability.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; @@ -454,4 +459,39 @@ class Utils { } + + + static Future isGoogleServicesAvailable() async { + GooglePlayServicesAvailability availability = await GoogleApiAvailability + .instance + .checkGooglePlayServicesAvailability(); + String status = availability.toString().split('.').last; + if (status == "success") { + return true; + } + return false; + } + + + + + + static Future checkConnection( + {bool bypassConnectionCheck = false}) async { + if (bypassConnectionCheck) return true; + List connectivityResult = + await (Connectivity().checkConnectivity()); + if (connectivityResult.contains(ConnectivityResult.mobile) || + connectivityResult.contains(ConnectivityResult.wifi)) { + return true; + } else { + return false; + } + } + + + static String generateMd5Hash(String input) { + return crypto.md5.convert(utf8.encode(input)).toString(); + } + } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index a5e9ae3..8122a52 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,5 +1,8 @@ +import 'dart:convert'; + import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/features/authentication/models/select_device_by_imei.dart'; @@ -7,7 +10,7 @@ import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:http/http.dart'; abstract class AuthenticationRepo { - Future> selectDeviceByImei({required String deviceIMEI}); + Future> selectDeviceByImei({required String firebaseToken}); } class AuthenticationRepoImp implements AuthenticationRepo { @@ -17,23 +20,22 @@ class AuthenticationRepoImp implements AuthenticationRepo { AuthenticationRepoImp({required this.loggerService, required this.apiClient}); @override - Future> selectDeviceByImei({required String deviceIMEI}) async { - final mapDevice = {"": deviceIMEI}; + Future> selectDeviceByImei({required String firebaseToken}) async { + final mapDevice = {"IMEI": firebaseToken}; - final String apiUrl = "https://hmgwebservices.com/Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI" ; try { - final Response result = await apiClient.postJsonForResponse(apiUrl, mapDevice); + final Response result = await apiClient.postJsonForResponse(ApiConsts.selectDeviceImei, mapDevice); + final SelectDeviceByImeiRespModelElement selectDeviceByImeiRespModelElement = SelectDeviceByImeiRespModelElement.fromJson(jsonDecode(result.body)['Patient_SELECTDeviceIMEIbyIMEIList'][0]); + loggerService.logInfo(result.body); + if (result !=null) { - return Right(null); + return Right(selectDeviceByImeiRespModelElement); } else { loggerService.errorLogs(result.toString()); return Left(ServerFailure(result.toString())); } } on APIException catch (e) { - APIError? apiError; - if (e.error is APIError) { - apiError = e.error as APIError; - } + loggerService.errorLogs(e.toString()); return Left(ServerFailure(apiError?.errorMessage ?? e.message)); } catch (e) { diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 5b45790..8269c72 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1,44 +1,44 @@ +import 'dart:developer'; +import 'dart:io'; + import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/check_activation_code_request_register.dart'; class AuthenticationViewModel extends ChangeNotifier { AuthenticationRepo authenticationRepo; + AppState appState; - AuthenticationViewModel({required this.authenticationRepo}); + AuthenticationViewModel({ + required this.appState, + required this.authenticationRepo, + }); + final TextEditingController nationalIdController = TextEditingController(); + final TextEditingController phoneNumberController = TextEditingController(); - - Future signUp({ - required String phone, - required String password, + Future selectDeviceImei({ Function(dynamic)? onSuccess, - Function(String)? onError, + Function(String)? onError }) async { - Utils.showLoading(); - final String deviceIMEI = + final String firebaseToken = "cIkkB7h7Q7uoFkC4Qv82xG:APA91bEb53Z9XzqymCIctaLxCoMX6bm9fuKlWILQ59uUqfwhCoD42AOP1-jWGB1WYd9BVN5PT2pUUFxrT07vcNg1KH9OH39mrPgCl0m21XVIgWrzNnCkufg"; - final resultEither = await authenticationRepo.selectDeviceByImei(deviceIMEI: deviceIMEI); - - if (resultEither.isLeft()) { - - } - - if (resultEither.isRight()) { - - - } - + final resultEither = + await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); resultEither.fold( (failure) { - Utils.hideLoading(); notifyListeners(); if (onError != null) onError(failure.message); }, (data) { + log("resultEither: ${data.toString()} "); + notifyListeners(); if (onSuccess != null) onSuccess(data); }, diff --git a/lib/features/authentication/models/authenticated_user_model.dart b/lib/features/authentication/models/authenticated_user_model.dart new file mode 100644 index 0000000..49987f3 --- /dev/null +++ b/lib/features/authentication/models/authenticated_user_model.dart @@ -0,0 +1,292 @@ +import 'package:hmg_patient_app/uitl/date_uitl.dart'; + +class AuthenticatedUser { + String? setupID; + int? patientType; + int? patientID; + String? firstName; + String? middleName; + String? lastName; + String? firstNameN; + String? middleNameN; + String? lastNameN; + int? relationshipID; + int? gender; + String? dateofBirth; + DateTime? dateofBirthDataTime; + dynamic dateofBirthN; + String? nationalityID; + dynamic phoneResi; + dynamic phoneOffice; + String? mobileNumber; + dynamic faxNumber; + String? emailAddress; + dynamic bloodGroup; + dynamic rHFactor; + bool? isEmailAlertRequired; + bool? isSMSAlertRequired; + String? preferredLanguage; + bool? isPrivilegedMember; + dynamic memberID; + dynamic expiryDate; + dynamic isHmgEmployee; + dynamic employeeID; + dynamic emergencyContactName; + dynamic emergencyContactNo; + int? patientPayType; + dynamic dHCCPatientRefID; + bool? isPatientDummy; + int? status; + dynamic isStatusCleared; + int? patientIdentificationType; + String? patientIdentificationNo; + int? projectID; + int? infoSourceID; + dynamic address; + int? age; + String? ageDesc; + int? areaID; + int? createdBy; + String? genderDescription; + dynamic iR; + dynamic iSOCityID; + dynamic iSOCountryID; + List? listPrivilege; + dynamic marital; + int? outSA; + dynamic pOBox; + bool? receiveHealthSummaryReport; + int? sourceType; + dynamic strDateofBirth; + dynamic tempAddress; + dynamic zipCode; + dynamic isFamily; + dynamic cRSVerificationStatus; + // dynamic patientPayType; + // dynamic patientType; + // dynamic status; + + AuthenticatedUser( + {this.setupID, + this.patientType, + this.patientID, + this.firstName, + this.middleName, + this.lastName, + this.firstNameN, + this.middleNameN, + this.lastNameN, + this.relationshipID, + this.gender, + this.dateofBirth, + this.dateofBirthN, + this.nationalityID, + this.phoneResi, + this.phoneOffice, + this.mobileNumber, + this.faxNumber, + this.emailAddress, + this.bloodGroup, + this.rHFactor, + this.isEmailAlertRequired, + this.isSMSAlertRequired, + this.preferredLanguage, + this.isPrivilegedMember, + this.memberID, + this.expiryDate, + this.isHmgEmployee, + this.employeeID, + this.emergencyContactName, + this.emergencyContactNo, + this.patientPayType, + this.dHCCPatientRefID, + this.isPatientDummy, + this.status, + this.isStatusCleared, + this.patientIdentificationType, + this.patientIdentificationNo, + this.projectID, + this.infoSourceID, + this.address, + this.age, + this.ageDesc, + this.areaID, + this.createdBy, + this.genderDescription, + this.iR, + this.iSOCityID, + this.iSOCountryID, + this.listPrivilege, + this.marital, + this.outSA, + this.pOBox, + this.receiveHealthSummaryReport, + this.sourceType, + this.strDateofBirth, + this.tempAddress, + this.zipCode, + this.isFamily, + this.cRSVerificationStatus}); + + AuthenticatedUser.fromJson(Map json) { + setupID = json['SetupID']; + patientType = json['PatientType']; + patientID = json['PatientID']; + firstName = json['FirstName']; + middleName = json['MiddleName']; + lastName = json['LastName']; + firstNameN = json['FirstNameN']; + middleNameN = json['MiddleNameN']; + lastNameN = json['LastNameN']; + relationshipID = json['RelationshipID']; + gender = json['Gender']; + dateofBirth = json['DateofBirth']; + dateofBirthDataTime = DateUtil.convertStringToDate(json['DateofBirth']); + dateofBirthN = json['DateofBirthN']; + nationalityID = json['NationalityID']; + phoneResi = json['PhoneResi']; + phoneOffice = json['PhoneOffice']; + mobileNumber = json['MobileNumber']; + faxNumber = json['FaxNumber']; + emailAddress = json['EmailAddress']; + bloodGroup = json['BloodGroup']; + rHFactor = json['RHFactor']; + isEmailAlertRequired = json['IsEmailAlertRequired']; + isSMSAlertRequired = json['IsSMSAlertRequired']; + preferredLanguage = json['PreferredLanguage']; + isPrivilegedMember = json['IsPrivilegedMember']; + memberID = json['MemberID']; + expiryDate = json['ExpiryDate']; + isHmgEmployee = json['IsHmgEmployee']; + employeeID = json['EmployeeID']; + emergencyContactName = json['EmergencyContactName']; + emergencyContactNo = json['EmergencyContactNo']; + patientPayType = json['PatientPayType']; + dHCCPatientRefID = json['DHCCPatientRefID']; + isPatientDummy = json['IsPatientDummy']; + status = json['Status']; + isStatusCleared = json['IsStatusCleared']; + patientIdentificationType = json['PatientIdentificationType']; + patientIdentificationNo = json['PatientIdentificationNo']; + projectID = json['ProjectID']; + infoSourceID = json['InfoSourceID']; + address = json['Address']; + age = json['Age']; + ageDesc = json['AgeDesc']; + areaID = json['AreaID']; + createdBy = json['CreatedBy']; + genderDescription = json['GenderDescription']; + iR = json['IR']; + iSOCityID = json['ISOCityID']; + iSOCountryID = json['ISOCountryID']; + if (json['ListPrivilege'] != null) { + listPrivilege = []; + json['ListPrivilege'].forEach((v) { + listPrivilege!.add(new ListPrivilege.fromJson(v)); + }); + } + marital = json['Marital']; + outSA = json['OutSA']; + pOBox = json['POBox']; + receiveHealthSummaryReport = json['ReceiveHealthSummaryReport']; + sourceType = json['SourceType']; + strDateofBirth = json['StrDateofBirth']; + tempAddress = json['TempAddress']; + zipCode = json['ZipCode']; + isFamily = json['IsFamily']; + cRSVerificationStatus = json['CRSVerificationStatus']; + } + + Map toJson() { + final Map data = new Map(); + data['SetupID'] = this.setupID; + data['PatientType'] = this.patientType; + data['PatientID'] = this.patientID; + data['FirstName'] = this.firstName; + data['MiddleName'] = this.middleName; + data['LastName'] = this.lastName; + data['FirstNameN'] = this.firstNameN; + data['MiddleNameN'] = this.middleNameN; + data['LastNameN'] = this.lastNameN; + data['RelationshipID'] = this.relationshipID; + data['Gender'] = this.gender; + data['DateofBirth'] = this.dateofBirth; + data['DateofBirthN'] = this.dateofBirthN; + data['NationalityID'] = this.nationalityID; + data['PhoneResi'] = this.phoneResi; + data['PhoneOffice'] = this.phoneOffice; + data['MobileNumber'] = this.mobileNumber; + data['FaxNumber'] = this.faxNumber; + data['EmailAddress'] = this.emailAddress; + data['BloodGroup'] = this.bloodGroup; + data['RHFactor'] = this.rHFactor; + data['IsEmailAlertRequired'] = this.isEmailAlertRequired; + data['IsSMSAlertRequired'] = this.isSMSAlertRequired; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsPrivilegedMember'] = this.isPrivilegedMember; + data['MemberID'] = this.memberID; + data['ExpiryDate'] = this.expiryDate; + data['IsHmgEmployee'] = this.isHmgEmployee; + data['EmployeeID'] = this.employeeID; + data['EmergencyContactName'] = this.emergencyContactName; + data['EmergencyContactNo'] = this.emergencyContactNo; + data['PatientPayType'] = this.patientPayType; + data['DHCCPatientRefID'] = this.dHCCPatientRefID; + data['IsPatientDummy'] = this.isPatientDummy; + data['Status'] = this.status; + data['IsStatusCleared'] = this.isStatusCleared; + data['PatientIdentificationType'] = this.patientIdentificationType; + data['PatientIdentificationNo'] = this.patientIdentificationNo; + data['ProjectID'] = this.projectID; + data['InfoSourceID'] = this.infoSourceID; + data['Address'] = this.address; + data['Age'] = this.age; + data['AgeDesc'] = this.ageDesc; + data['AreaID'] = this.areaID; + data['CreatedBy'] = this.createdBy; + data['GenderDescription'] = this.genderDescription; + data['IR'] = this.iR; + data['ISOCityID'] = this.iSOCityID; + data['ISOCountryID'] = this.iSOCountryID; + if (this.listPrivilege != null) { + data['ListPrivilege'] = + this.listPrivilege!.map((v) => v.toJson()).toList(); + } + data['Marital'] = this.marital; + data['OutSA'] = this.outSA; + data['POBox'] = this.pOBox; + data['ReceiveHealthSummaryReport'] = this.receiveHealthSummaryReport; + data['SourceType'] = this.sourceType; + data['StrDateofBirth'] = this.strDateofBirth; + data['TempAddress'] = this.tempAddress; + data['ZipCode'] = this.zipCode; + data['IsFamily'] = this.isFamily; + data['CRSVerificationStatus'] = this.cRSVerificationStatus; + return data; + } +} + +class ListPrivilege { + int? iD; + String? serviceName; + bool? previlege; + dynamic region; + + ListPrivilege({this.iD, this.serviceName, this.previlege, this.region}); + + ListPrivilege.fromJson(Map json) { + iD = json['ID']; + serviceName = json['ServiceName']; + previlege = json['Previlege']; + region = json['Region']; + } + + Map toJson() { + final Map data = new Map(); + data['ID'] = this.iD; + data['ServiceName'] = this.serviceName; + data['Previlege'] = this.previlege; + data['Region'] = this.region; + return data; + } +} diff --git a/lib/features/authentication/models/check_activation_code_request_register.dart b/lib/features/authentication/models/check_activation_code_request_register.dart new file mode 100644 index 0000000..85e1f56 --- /dev/null +++ b/lib/features/authentication/models/check_activation_code_request_register.dart @@ -0,0 +1,121 @@ +class CheckActivationCodeRegisterReq { + int? patientMobileNumber; + String? mobileNo; + String? deviceToken; + bool? projectOutSA; + int? loginType; + String? zipCode; + bool? isRegister; + String? logInTokenID; + int? searchType; + int? patientID; + String? nationalID; + String? patientIdentificationID; + String? activationCode; + bool? isSilentLogin; + double? versionID; + int? channel; + int? languageID; + String? iPAdress; + String? generalid; + int? patientOutSA; + dynamic sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + bool? forRegisteration; + String? dob; + int? isHijri; + String? healthId; + + CheckActivationCodeRegisterReq({ + this.patientMobileNumber, + this.mobileNo, + this.deviceToken, + this.projectOutSA, + this.loginType, + this.zipCode, + this.isRegister, + this.logInTokenID, + this.searchType, + this.patientID, + this.nationalID, + this.patientIdentificationID, + this.activationCode, + this.isSilentLogin, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.forRegisteration, + this.dob, + this.isHijri, + this.healthId, + }); + + CheckActivationCodeRegisterReq.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + mobileNo = json['MobileNo']; + deviceToken = json['DeviceToken']; + projectOutSA = json['ProjectOutSA']; + loginType = json['LoginType']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + logInTokenID = json['LogInTokenID']; + searchType = json['SearchType']; + patientID = json['PatientID']; + nationalID = json['NationalID']; + patientIdentificationID = json['PatientIdentificationID']; + activationCode = json['activationCode']; + isSilentLogin = json['IsSilentLogin']; + 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']; + forRegisteration = json['ForRegisteration']; + dob = json['DOB']; + isHijri = json['IsHijri']; + healthId = json['HealthId']; + } + + Map toJson() { + final Map data = new Map(); + data['PatientMobileNumber'] = this.patientMobileNumber; + data['MobileNo'] = this.mobileNo; + data['DeviceToken'] = this.deviceToken; + data['ProjectOutSA'] = this.projectOutSA; + data['LoginType'] = this.loginType; + data['ZipCode'] = this.zipCode; + data['isRegister'] = this.isRegister; + data['LogInTokenID'] = this.logInTokenID; + data['SearchType'] = this.searchType; + data['PatientID'] = this.patientID; + data['NationalID'] = this.nationalID; + data['PatientIdentificationID'] = this.patientIdentificationID; + data['activationCode'] = this.activationCode; + data['IsSilentLogin'] = this.isSilentLogin; + 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['ForRegisteration'] = this.forRegisteration; + data['DOB'] = dob; + data['IsHijri'] = isHijri; + data['HealthId'] = healthId; + return data; + } +} diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index b994b35..5b0bf10 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -1,6 +1,5 @@ import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; -import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -41,13 +40,6 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { loggerService.errorLogs(result.toString()); return Left(ServerFailure(result.toString())); } - } on APIException catch (e) { - APIError? apiError; - if (e.error is APIError) { - apiError = e.error as APIError; - } - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(apiError?.errorMessage ?? e.message)); } catch (e) { loggerService.errorLogs(e.toString()); return Left(ServerFailure(e.toString())); diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 7ac0c47..28b9b38 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -63,13 +63,6 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { loggerService.errorLogs(result.toString()); return Left(ServerFailure(result.toString())); } - } on APIException catch (e) { - APIError? apiError; - if (e.error is APIError) { - apiError = e.error as APIError; - } - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(apiError?.errorMessage ?? e.message)); } catch (e) { loggerService.errorLogs(e.toString()); return Left(ServerFailure(e.toString())); diff --git a/lib/main.dart b/lib/main.dart index 8d0f7fa..446f8da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -45,7 +45,7 @@ Future callInitializations() async { } void main() async { - callInitializations(); + await callInitializations(); runApp( EasyLocalization( supportedLocales: const [ @@ -56,7 +56,7 @@ void main() async { fallbackLocale: Locale('en', 'US'), child: MultiProvider(providers: [ ChangeNotifierProvider( - create: (_) => AuthenticationViewModel(authenticationRepo: getIt()), + create: (_) => AuthenticationViewModel(authenticationRepo: getIt(), appState: getIt()), ), ], child: MyApp()), ), diff --git a/lib/presentation/authantication/login.dart b/lib/presentation/authentication/login.dart similarity index 92% rename from lib/presentation/authantication/login.dart rename to lib/presentation/authentication/login.dart index 150d446..2699a91 100644 --- a/lib/presentation/authantication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -6,29 +6,16 @@ import 'package:hmg_patient_app_new/core/app_assets.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/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; -import 'package:hmg_patient_app_new/widgets/language_switcher.dart'; -import 'package:sizer/sizer.dart'; // Import sizer +import 'package:sizer/sizer.dart'; -class LoginScreen extends StatefulWidget { - @override - _LoginScreen createState() => _LoginScreen(); -} - -class _LoginScreen extends State { - @override - void initState() { - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } +class LoginScreen extends StatelessWidget { + const LoginScreen({super.key}); @override Widget build(BuildContext context) { @@ -37,7 +24,6 @@ class _LoginScreen extends State { return Scaffold( appBar: CustomAppBar( onBackPressed: () { - // Navigator.of(context).pop(); }, onLanguageChanged: (String value) { print(value); diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 9163a7e..d371213 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.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:provider/provider.dart'; class LandingPage extends StatefulWidget { const LandingPage({super.key}); @@ -10,16 +11,22 @@ class LandingPage extends StatefulWidget { } class _LandingPageState extends State { - late AuthenticationViewModel authenticationViewModel; @override Widget build(BuildContext context) { + AuthenticationViewModel authenticationViewModel = context.read();; + return Scaffold( body: Column( children: [ - Padding( - padding: const EdgeInsets.all(64.0), - child: "Login".toText18(color: Colors.black), + InkWell( + onTap: () { + authenticationViewModel.selectDeviceImei(); + }, + child: Padding( + padding: const EdgeInsets.all(64.0), + child: "Login".toText18(color: Colors.black), + ), ), ], ), diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 8aafc82..d16cc62 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/presentation/authantication/login.dart'; +import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; import 'package:hmg_patient_app_new/splashPage.dart'; class AppRoutes { @@ -10,5 +10,4 @@ class AppRoutes { initialRoute: (context) => SplashPage(), login: (context) => LoginScreen(), }; - static Map get routes => {initialRoute: (context) => SplashPage()}; } diff --git a/lib/services/analytics/analytics_service.dart b/lib/services/analytics/analytics_service.dart new file mode 100644 index 0000000..d4f83a4 --- /dev/null +++ b/lib/services/analytics/analytics_service.dart @@ -0,0 +1,143 @@ + +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/advance_payments.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/app_nav.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/appointments.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/error_tracking.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/hamburger_menu.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/hmg_services.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/live_care.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/login_registration.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/offers_promotions.dart'; +import 'package:hmg_patient_app_new/services/analytics/flows/todo_list.dart'; +import 'package:http/http.dart' as AnalyticEvents; + + +typedef GALogger = Function(String name, {Map parameters}); + +var _analytics = FirebaseAnalytics.instance; + +_logger(String name, {Map? parameters}) async { + // return; + if (name.isNotEmpty) { + if (name.contains(' ')) name = name.replaceAll(' ', '_'); + + // To LowerCase + if (parameters != null && parameters.isNotEmpty) { + parameters = parameters.map((key, value) { + final key_ = key.toLowerCase(); + var value_ = value; + if (value is String) value_ = value.toLowerCase(); + return MapEntry(key_, value_); + }); + } + + try { + final safeParameters = parameters?.map((key, value) => MapEntry(key, value as Object)); + await _analytics.logEvent( + name: name.trim().toLowerCase(), + parameters: safeParameters, + ); + } catch (e) { + print('Error sending analytics event: $e'); + } + + } +} + +class GAnalytics { + static String? TREATMENT_TYPE; + static String? APPOINTMENT_DETAIL_FLOW_TYPE; + static String? PAYMENT_TYPE; + + setUser(AuthenticatedUser user) async { + try { + _analytics.setUserProperty(name: 'user_language', value: user.preferredLanguage == '1' ? 'arabic' : 'english'); + _analytics.setUserProperty(name: 'userid', value: Utils.generateMd5Hash(user.emailAddress!)); + _analytics.setUserProperty(name: 'login_status', value: user == null ? 'guest' : 'loggedin'); + // if (await PermissionService.isLocationEnabled()) { + // final location = await Geolocator.getCurrentPosition(); + // if (location != null && !location.isMocked) { + // final places = await placemarkFromCoordinates(location.latitude, location.longitude,); + // final countryCode = places.first.isoCountryCode; + // _analytics.setUserProperty(name: 'user_country', value: countryCode); + // } + // } else { + // _analytics.setUserProperty(name: 'user_country', value: "N/A"); + // } + } catch (e) {} + } + + // NavObserver navObserver() => NavObserver(); + final hamburgerMenu = HamburgerMenu(_logger); + final bottomTabNavigation = AppNav(_logger); + final hmgServices = HMGServices(_logger); + final loginRegistration = LoginRegistration(_logger); + final appointment = Appointment(_logger); + final liveCare = LiveCare(_logger); + final todoList = TodoList(_logger); + final advancePayments = AdvancePayments(_logger); + final offerPackages = OfferAndPromotion(_logger); + final errorTracking = ErrorTracking(_logger); +} + +// // adb shell setprop debug.firebase.analytics.app com.ejada.hmg -> Android +// class NavObserver extends RouteObserver> { +// _sendScreenView(PageRoute route) async { +// log(String className) { +// var event = AnalyticEvents.get(className); +// if (event.active != null) { +// _analytics.setCurrentScreen(screenName: event.flutterName(), screenClassOverride: className).catchError( +// (Object error) { +// print('$FirebaseAnalyticsObserver: $error'); +// }, +// test: (Object error) { +// return error is PlatformException; +// }, +// ); +// } +// } +// +// if (route.settings.name != null && route.settings.name!.isNotEmpty && route.settings.name != "null") { +// var class_ = routes[route.settings.name]!(0); +// if (class_ != null) log(class_.toStringShort()); +// } else if (route is FadePage) { +// var class_ = route.page; +// if (class_ != null) log(class_.toStringShort()); +// } else if (route is MaterialPageRoute) { +// var class_ = route.builder(route.subtreeContext!); +// log(class_.toStringShort()); +// } else { +// print(""); +// } +// } +// +// @override +// void didPush(Route route, Route? previousRoute) { +// super.didPush(route, previousRoute); +// if (route is PageRoute) { +// _sendScreenView(route); +// } +// } +// +// @override +// void didReplace({Route? newRoute, Route? oldRoute}) { +// super.didReplace(newRoute: newRoute, oldRoute: oldRoute); +// if (newRoute is PageRoute) { +// _sendScreenView(newRoute); +// } +// } +// +// @override +// void didPop(Route route, Route? previousRoute) { +// super.didPop(route, previousRoute); +// // if (previousRoute is PageRoute && route is PageRoute) { +// // _sendScreenView(previousRoute); +// // } +// } +// } diff --git a/lib/services/analytics/flows/advance_payments.dart b/lib/services/analytics/flows/advance_payments.dart new file mode 100644 index 0000000..9c8baa1 --- /dev/null +++ b/lib/services/analytics/flows/advance_payments.dart @@ -0,0 +1,91 @@ +import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class AdvancePayments{ + + final GALogger logger; + AdvancePayments(this.logger); + + // R038 + payment_services({required String service_type}){ + logger('payment_services', parameters: { + 'service_type' : service_type + }); + } + + // R039 + wallet_recharge({required String service_type}){ + logger('wallet_recharge', parameters: { + 'service_type' : service_type + }); + } + + // R040 + wallet_payment_details(){ + logger('wallet_payment_details'); + } + + // R041 + payment_method({required String method,type}){ + logger('payment_method', parameters: { + 'payment_method' : method, + 'payment_type' : type + }); + } + + // R042 + payment_confirm({required String method,type}){ + logger('payment_confirm', parameters: { + 'payment_method' : method, + 'payment_type' : type + }); + } + + // R043 + payment_otp_confirmation({required String method,type}){ + logger('payment_otp_confirmation', parameters: { + 'payment_method' : method, + 'payment_type' : type + }); + } + + // R044 + payment_confirm_card_details({required String method,type}){ + logger('payment_confirm_card_details', parameters: { + 'payment_method' : method, + 'payment_type' : type + }); + } + + // R045 + payment_pay({required String method,type}){ + logger('payment_pay', parameters: { + 'payment_method' : method, + 'payment_type' : type + }); + } + + // R046 + payment_success({required String hospital, payment_method, payment_type, txn_number, txn_amount, txn_currency}){ + logger('payment_success', parameters: { + 'payment_method' : payment_method, + 'payment_type' : payment_type, + 'hospital_name' : hospital, + 'transaction_number' : txn_number, + 'transaction_amount' : txn_amount, + 'transaction_currency' : txn_currency + }); + } + + payment_fail({required String hospital, payment_method, payment_type, txn_amount, txn_currency, error_type}){ + logger('payment_fail', parameters: { + 'payment_method' : payment_method, + 'payment_type' : payment_type, + 'hospital_name' : hospital, + 'transaction_amount' : txn_amount, + 'transaction_currency' : txn_currency, + 'error_type' : error_type + }); + } + +} \ No newline at end of file diff --git a/lib/services/analytics/flows/app_nav.dart b/lib/services/analytics/flows/app_nav.dart new file mode 100644 index 0000000..bd9186c --- /dev/null +++ b/lib/services/analytics/flows/app_nav.dart @@ -0,0 +1,30 @@ +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class AppNav{ + final name = 'app_nav'; + final GALogger logger; + AppNav(this.logger); + + logNavName(String value){ + logger(name, parameters: { + 'nav_name' : value + }); + } + + log({int? tabIndex, bool? isLoggedIn}){ + var nav_name = ""; + if(tabIndex == 1) + nav_name = "medical file"; + if(tabIndex == 3) + nav_name = "my family"; + if(tabIndex == 4) + nav_name = "todo list"; + if(tabIndex == 5) + nav_name = "help"; + + if(nav_name.isNotEmpty) + logger(name, parameters: { + 'nav_name' : nav_name + }); + } +} \ No newline at end of file diff --git a/lib/services/analytics/flows/appointments.dart b/lib/services/analytics/flows/appointments.dart new file mode 100644 index 0000000..57c45e6 --- /dev/null +++ b/lib/services/analytics/flows/appointments.dart @@ -0,0 +1,268 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; +import 'package:intl/intl.dart'; + +class Appointment { + final GALogger logger; + + Appointment(this.logger); + + // R015 + book_appointment() { + logger('book_appointment'); + } + + // R016.1, R017.2 + book_appointment_by_clinic() { + logger('book_appointment_by_clinic'); + } + + // R016.2, R018.2 + book_appointment_by_doctor() { + logger('book_appointment_by_doctor'); + } + +// // R017.1 +// book_appointment_doctor_search({required String query}) { +// // doctor_search_query : value +// logger('book_appointment_doctor_search', parameters: {'doctor_search_query': query}); +// } +// +// // R018.1 +// book_appointment_select_clinic({required String appointment_type, clinic}) { +// // appointment_type: regular | livecare +// // clinic_type : $clinic_type +// logger('book_appointment_select_clinic', parameters: {'appointment_type': appointment_type, 'clinic_type': clinic}); +// } +// +// // R019.1 +// book_appointment_livecare_accept() { +// logger('book_appointment_livecare_accept'); +// } +// +// // R019.2 +// book_appointment_livecare_decline() { +// logger('book_appointment_livecare_decline'); +// } +// +// // R020 +// book_appointment_chief_complaints({ +// required String appointment_type, +// ListClinicCentralized? clinic, +// HospitalsModel? hospital, +// ListDentalChiefComplain? treatment, +// }) { +// GAnalytics.TREATMENT_TYPE = treatment!.name; +// logger('book_appointment_chief_complaints', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': clinic!.clinicDescription, +// 'hospital_name':hospital!=null ? hospital!.name :"", +// 'treatment_type': treatment.name, +// }); +// } +// +// // R021 +// book_appointment_select_doctor({required String appointment_type, required DoctorList doctor}) { +// // appointment_type, clinic_type, hospital_name, treatment_type, doctor_name, doctor_nationality, doctor_gender +// logger('book_appointment_select_doctor', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// }); +// } +// +// // R022 +// book_appointment_schedule({required String appointment_type, required DoctorList doctor}) { +// // appointment_type, clinic_type, hospital_name, treatment_type, doctor_name, doctor_nationality, doctor_gender +// logger('book_appointment_schedule', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// }); +// } +// +// // R023 +// book_appointment_date_selection({required String appointment_type, required day, required DoctorList doctor}) { +// logger('book_appointment_date_selection', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// 'appointment_day': day +// }); +// } +// +// // R024.1 +// book_appointment_time_selection({required String appointment_type, required DateTime? dateTime, required DoctorList doctor}) { +// final day = DateUtil.getWeekDay(dateTime!.weekday); +// final hour = DateFormat('HH').format(dateTime); +// logger('book_appointment_time_selection', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// 'appointment_day': day, +// 'appointment_hour': hour +// }); +// } +// +// // R024.2 +// book_appointment_review({required String appointment_type, required DateTime dateTime, required DoctorList doctor}) { +// final day = DateUtil.getWeekDay(dateTime.weekday); +// final hour = DateFormat('HH').format(dateTime); +// logger('book_appointment_review', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// 'appointment_day': day, +// 'appointment_hour': hour +// }); +// } +// +// // R025 +// book_appointment_click_confirm({required String appointment_type, required DateTime dateTime, required DoctorList doctor}) { +// final day = DateUtil.getWeekDay(dateTime.weekday); +// final hour = DateFormat('HH').format(dateTime); +// logger('book_appointment_click_confirm', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// 'appointment_day': day, +// 'appointment_hour': hour // '5-6' +// }); +// } +// +// // R026 +// book_appointment_confirmation_success({required String appointment_type, required DateTime dateTime, required DoctorList doctor}) { +// final day = DateUtil.getWeekDay(dateTime.weekday); +// final hour = DateFormat('HH').format(dateTime); +// logger('book_appointment_confirmation_success', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctor.clinicName, +// 'hospital_name': doctor.projectName, +// 'treatment_type': GAnalytics.TREATMENT_TYPE ?? '', +// 'doctor_name': doctor.name, +// 'doctor_nationality': doctor.nationalityName, +// 'doctor_gender': doctor.genderDescription, +// 'appointment_day': day, +// 'appointment_hour': hour +// }); +// } +// +// // R049.1 // should be for appointment flow +// appointment_actions(AppoitmentAllHistoryResultList appointment, String action) { +// logger('appointment_actions', parameters: { +// 'action_type': action, +// 'flow_type': GAnalytics.APPOINTMENT_DETAIL_FLOW_TYPE, +// 'appointment_type': appointment.appointmentType, +// 'clinic_type_online': appointment.clinicName, +// 'hospital_name': appointment.projectName, +// 'doctor_name': (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, +// 'payment_type': 'appointment', +// }); +// } +// +// // R027 +// appointment_reminder(bool value) { +// logger('appointment_reminder', parameters: {'reminder': value ? 'yes' : 'no'}); +// } +// +// // R028 +// appointment_reminder_time({required String reminde_before}) { +// logger('appointment_reminder_time', parameters: {'reminder_before': reminde_before}); +// } +// +// // R053 +// // Note : - Payment flow beyond this step are same as listed under ‘Advance Payment’ section of this document +// pay_now_for_appointment({required String appointment_type, required DoctorList doctorDetail, bool payNow = true}) { +// logger('pay_now_for_appointment', parameters: { +// 'appointment_type': appointment_type, +// 'clinic_type': doctorDetail.clinicName, +// 'hospital_name': doctorDetail.projectName, +// 'doctor_name': doctorDetail.name, +// 'payment_type': 'appointment' +// }); +// } +// +// // R033 +// payment_method({required String appointment_type, clinic, payment_method, payment_type}) { +// logger('payment_method', parameters: {'appointment_type': appointment_type, 'clinic_type': clinic, 'payment_method': payment_method, 'payment_type': payment_type}); +// } +// +// // R036 +// payment_success({required String appointment_type, clinic, hospital, payment_method, payment_type, txn_number, txn_amount, txn_currency}) { +// logger('payment_success', parameters: { +// 'appointment_type': appointment_type, +// 'payment_method': payment_method, +// 'payment_type': payment_type, +// 'hospital_name': hospital, +// 'clinic_type_online': clinic, +// 'transaction_number': txn_number, +// 'transaction_amount': txn_amount, +// 'transaction_currency': txn_currency, +// }); +// } +// +// payment_fail({required String appointment_type, clinic, hospital, payment_method, payment_type, txn_amount, txn_currency, error_type}) { +// logger('payment_fail', parameters: { +// 'appointment_type': appointment_type, +// 'payment_method': payment_method, +// 'payment_type': payment_type, +// 'hospital_name': hospital, +// 'clinic_type_online': clinic, +// 'transaction_amount': txn_amount, +// 'transaction_currency': txn_currency, +// 'error_type': error_type +// }); +// } +// +// // Note : - Payment flow beyond this step are same as listed under ‘Advance Payment’ section of this document +// appointment_detail_action({required AppoitmentAllHistoryResultList appointment, required String action}) { +// logger('appointment_detail_action', parameters: { +// 'action_type': action, +// 'flow_type': GAnalytics.APPOINTMENT_DETAIL_FLOW_TYPE, +// }); +// } +// +// // Note : - Payment flow beyond this step are same as listed under ‘Advance Payment’ section of this document +// appointment_details_confirm({required AppoitmentAllHistoryResultList appointment}) { +// logger('appointment_details_confirm', parameters: {}); +// } +// +// // R053 +// // Note : - Payment flow beyond this step are same as listed under ‘Advance Payment’ section of this document +// appointment_details_cancel({required AppoitmentAllHistoryResultList appointment, appointment_type}) { +// logger('cancel_appointment', parameters: { +// 'flow_type': GAnalytics.APPOINTMENT_DETAIL_FLOW_TYPE, +// 'appointment_type': appointment_type, +// 'clinic_type_online': appointment.clinicName, +// 'hospital_name': appointment.projectName, +// 'doctor_name': (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName +// }); +// } +// } +} diff --git a/lib/services/analytics/flows/error_tracking.dart b/lib/services/analytics/flows/error_tracking.dart new file mode 100644 index 0000000..6cc2882 --- /dev/null +++ b/lib/services/analytics/flows/error_tracking.dart @@ -0,0 +1,16 @@ + +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class ErrorTracking{ + + final GALogger logger; + ErrorTracking(this.logger); + + log(String type, {String? error}){ + logger('errors', parameters: { + 'error_type' : type ?? 'unknown', + 'error' : error ?? 'unknown', + }); + } + +} \ No newline at end of file diff --git a/lib/services/analytics/flows/hamburger_menu.dart b/lib/services/analytics/flows/hamburger_menu.dart new file mode 100644 index 0000000..22301a2 --- /dev/null +++ b/lib/services/analytics/flows/hamburger_menu.dart @@ -0,0 +1,16 @@ + +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class HamburgerMenu{ + final hamburger_menu = 'hamburger_menu'; + + final GALogger logger; + HamburgerMenu(this.logger); + + logMenuItemClick(String value){ + logger(hamburger_menu, parameters: { + 'menu_item' : value + }); + } + +} \ No newline at end of file diff --git a/lib/services/analytics/flows/hmg_services.dart b/lib/services/analytics/flows/hmg_services.dart new file mode 100644 index 0000000..1a9a47e --- /dev/null +++ b/lib/services/analytics/flows/hmg_services.dart @@ -0,0 +1,19 @@ + +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class HMGServices{ + final hmg_services = 'hmg_services'; + + final GALogger logger; + HMGServices(this.logger); + logServiceName(String value){ + logger('hmg_services', parameters: { + 'services_name' : value + }); + } + viewAll(){ + logger('hmg_services', parameters: { + 'services_name' : 'view all services' + }); + } +} \ No newline at end of file diff --git a/lib/services/analytics/flows/live_care.dart b/lib/services/analytics/flows/live_care.dart new file mode 100644 index 0000000..5e7f330 --- /dev/null +++ b/lib/services/analytics/flows/live_care.dart @@ -0,0 +1,102 @@ +import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class LiveCare{ + + final GALogger logger; + LiveCare(this.logger); + + // R030.1 + livecare_immediate_consultation(){ + logger('livecare_immediate_consultation'); + } + + // R030.2 + livecare_schedule_video_call(){ + logger('livecare_schedule_video_call'); + } + + // R031.1 + livecare_clinic_schedule({required String clinic}){ + logger('livecare_clinic_schedule', parameters: { + 'clinic_type_online' : clinic + }); + } + + // R031.2 + livecare_immediate_consultation_clinic({required String clinic}){ + logger('livecare_immediate_consultation_clinic', parameters: { + 'clinic_type_online' : clinic + }); + } + + // R031.2 + livecare_schedule_video_call_clinic({required String clinic}){ + logger('livecare_schedule_video_call_clinic', parameters: { + 'clinic_type_online' : clinic + }); + } + + // R032 + livecare_immediate_consultation_TnC({required String clinic}){ + logger('livecare_immediate_consultation_tandc', parameters: { + 'clinic_type_online' : clinic + }); + } + + // R033 + payment_method({required String appointment_type, clinic, payment_method, payment_type}){ + logger('payment_method', parameters: { + 'appointment_type' : appointment_type, + 'clinic_type_online' : clinic, + 'payment_method' : payment_method, + 'payment_type' : payment_type + }); + } + + // R034 + payment_confirm({required String appointment_type, clinic, payment_method, payment_type}){ + logger('payment_confirm', parameters: { + 'appointment_type' : appointment_type, + 'clinic_type_online' : clinic, + 'payment_method' : payment_method, + 'payment_type' : payment_type + }); + } + + // R035 + payment_pay({required String appointment_type, clinic, hospital, payment_method, payment_type}){ + // logger('payment_pay', parameters: { + // 'appointment_type' : appointment_type, + // 'clinic_type_online' : clinic, + // 'payment_method' : payment_method, + // 'payment_type' : payment_type, + // 'hospital_name' : hospital + // }); + } + + // R036 + payment_success({required String appointment_type, clinic, hospital, payment_method, payment_type, txn_number, txn_amount, txn_currency}){ + // appointment_type + // clinic_type_online + // payment_method + // payment_type + // hospital_name + // transaction_number + // transaction_amount + // transaction_currency + } + + // R037 + livecare_immediate_consultation_payment_failed({required String appointment_type, clinic, payment_method, payment_type, txn_amount, txn_currency, error_message}){ + logger('livecare_immediate_consult_payment_fail', parameters: { + 'payment_method' : payment_method, + 'appointment_type' : appointment_type, + 'payment_type' : payment_type, + 'clinic_type_online' : clinic, + 'transaction_amount' : txn_amount, + 'transaction_currency' : txn_currency, + 'error_type' : error_message + }); + } +} \ No newline at end of file diff --git a/lib/services/analytics/flows/login_registration.dart b/lib/services/analytics/flows/login_registration.dart new file mode 100644 index 0000000..9488324 --- /dev/null +++ b/lib/services/analytics/flows/login_registration.dart @@ -0,0 +1,156 @@ +import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class LoginRegistration{ + static int loginMethod = 0; + static int verificationMethod = 0; + + final GALogger logger; + LoginRegistration(this.logger); + // R004.1 + login_register_initiate(){ + logger('login_register_initiate'); + } + + // R005.1 + visited_alhabib_group(bool value){ + // selection_type: yes/no + logger('visited_alhabib_group', parameters: { + 'selection_type' : value ? 'yes' : 'no' + }); + } + + // R006.1, R007.1, R008.1, R009.1 + registration_cancel({required String step}){ + // registration_step : enter details + // registration_step : personal info + // registration_step : patient info + // fourth (verification) + logger('registration_cancel', parameters: { + 'registration_step' : step + }); + } + + // R006.2 + registration_enter_details(){ + logger('registration_enter_details'); + } + + // R007.2 + registration_personal_info(){ + logger('registration_personal_info'); + } + + // R008.2 + registration_patient_info(){ + logger('registration_patient_info'); + } + + // R009.2 + registration_verification_option(){ + logger('registration_verification_option'); + } + + // R010:registration_confirmation + registration_confirmation(){ + // verification_method: by + logger('registration_confirmation'); + } + + registration_fail({required String errorType}){ + // verification_method: by + logger('registration_fail', parameters: { + 'error_type' : errorType + }); + } + + // R011.1 + login_start({required String method}){ + logger('login_start', parameters: { + 'login_method' : method + }); + } + + // R011:login_verify_otp | R009:registration_verification_option + verify_otp_method({bool forRegistration = false}){ + if(forRegistration == false) + logger("login_verify_otp", parameters: { + 'login_method' : _getLoginMethod(), + 'verification_method' : _getVerificationMethod(), + }); + else + logger("registration_verification_option", parameters: { + 'verification_method' : _getVerificationMethod() + }); + } + + // R011:login_verify_otp | R009:registration_verification_option + login_verfication({bool forRegistration = false}){ + if(forRegistration == false) + logger("login_verfication", parameters: { + 'login_method' : _getLoginMethod(), + 'verification_method' : _getVerificationMethod(), + }); + else + logger("login_varification_register", parameters: { + 'login_method' : _getLoginMethod(), + 'verification_method' : _getVerificationMethod(), + }); + } + + // R011.2 + forget_file_number(){ + logger('forget_file_number'); + } + + // R011.3 + register_now(){ + logger('register_now'); + } + + // R012.1, R014.1 + login_successful(){ + logger('login_successful', parameters: { + 'login_method' : _getVerificationMethod() + }); + } + + // R012.4 + login_unsuccessful({required String method, error}){ + logger('login_unsuccessful', parameters: { + 'login_method' : method + }); + } + + login_fail({error}){ + logger('login_unsuccessful', parameters: { + 'login_method' : loginMethod, + 'error': error + }); + } + + // R013 + recover_file_number(){ + logger('recover_file_number'); + } + + // R014.2 + login_with_other_account(){ + logger('login_with_other_account'); + } + + + _getLoginMethod(){ + if(loginMethod == 1) return 'national id'; + if(loginMethod == 2) return 'file number'; + return 'otp'; + } + + String _getVerificationMethod(){ + if(verificationMethod == 1) return 'sms'; + if(verificationMethod == 2) return 'fingerprint'; + if(verificationMethod == 3) return 'face id'; + if(verificationMethod == 4) return 'whatsapp'; + return "unknown"; + } +} \ No newline at end of file diff --git a/lib/services/analytics/flows/offers_promotions.dart b/lib/services/analytics/flows/offers_promotions.dart new file mode 100644 index 0000000..bd2511f --- /dev/null +++ b/lib/services/analytics/flows/offers_promotions.dart @@ -0,0 +1,17 @@ + +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class OfferAndPromotion{ + + final GALogger logger; + OfferAndPromotion(this.logger); + + final offers_and_promotion = 'offers_&_promotion'; + + log(){ + logger('offers_and_promotion', parameters: { + 'promotion_name' : "offer" + }); + } + +} \ No newline at end of file diff --git a/lib/services/analytics/flows/todo_list.dart b/lib/services/analytics/flows/todo_list.dart new file mode 100644 index 0000000..c1c874b --- /dev/null +++ b/lib/services/analytics/flows/todo_list.dart @@ -0,0 +1,111 @@ + + +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; + +class TodoList{ + + final GALogger logger; + TodoList(this.logger); + + // R047.1 + // to_do_list_pay_now(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_pay_now', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + + // // R047.2 + // to_do_list_more_details(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_more_details', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // // R048 + // to_do_list_confirm_payment_details(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_confirm_payment_details', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // // R048 + // to_do_list_cancel_payment_details(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_cancel_payment_details', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // + // + // // R049.2 + // to_do_list_cancel_appointment(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_cancel_appointment', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // // R049.3 + // to_do_list_confirm_appointment(AppoitmentAllHistoryResultList appointment){ + // logger('confirm_appointment', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'flow_type' : 'todo list', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // // R050 + // to_do_list_check_in(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_check_in', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // // R051 + // to_do_list_nfc(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_nfc', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment! ? 'livecare' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } + // + // // R052 + // to_do_list_nfc_cancel(AppoitmentAllHistoryResultList appointment){ + // logger('to_do_list_nfc_cancel', parameters: { + // 'appointment_type' : appointment.isLiveCareAppointment != null ? appointment.isLiveCareAppointment! ? 'livecare' : 'regular' : 'regular', + // 'clinic_type_online' : appointment.clinicName, + // 'hospital_name' : appointment.projectName, + // 'doctor_name' : (appointment.doctorName == null || appointment.doctorName == '') ? appointment.doctorNameObj : appointment.doctorName, + // 'payment_type' : 'appointment', + // }); + // } +} \ No newline at end of file diff --git a/lib/splashPage.dart b/lib/splashPage.dart index 72a9213..85b2e80 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -6,9 +6,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; -import 'package:hmg_patient_app_new/presentation/authantication/login.dart'; +// import 'package:hmg_patient_app_new/presentation/authantication/login.dart'; import 'package:hmg_patient_app_new/presentation/home/landing_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; @@ -24,10 +25,7 @@ class SplashPage extends StatefulWidget { } class _SplashScreenState extends State { - @override - void initState() { - super.initState(); - print("Splash init called............."); + Future initializeStuff() async { Timer( Duration(milliseconds: 500), () async { @@ -39,12 +37,11 @@ class _SplashScreenState extends State { LocalNotification.init(onNotificationClick: (payload) {}); Navigator.of(context).pushReplacement( FadePage( - // page: LandingPage(), - page: LoginScreen(), + page: LandingPage(), + // page: LoginScreen(), ), ); }); - var zoom = ZoomVideoSdk(); InitConfig initConfig = InitConfig( domain: "zoom.us", @@ -53,6 +50,8 @@ class _SplashScreenState extends State { zoom.initSdk(initConfig); } + + /// load the Privilege from service Future loadPrivilege() async { // ProjectViewModel projectProvider = Provider.of(context, listen: false); @@ -71,6 +70,13 @@ class _SplashScreenState extends State { PushNotificationHandler().init(context); // Asyncronously } + + @override + void initState() { + super.initState(); + initializeStuff(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -80,7 +86,8 @@ class _SplashScreenState extends State { children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 53), - child: Image.asset(AppAssets.hmg_logo, fit: BoxFit.fitWidth, width: MediaQuery.of(context).size.width), + child: Image.asset(AppAssets.hmg_logo, + fit: BoxFit.fitWidth, width: MediaQuery.of(context).size.width), ), Align( alignment: Alignment.bottomCenter, @@ -89,12 +96,18 @@ class _SplashScreenState extends State { children: [ Text( "Powered by", - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.textColor, letterSpacing: -0.56, height: 16 / 14), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: AppColors.textColor, + letterSpacing: -0.56, + height: 16 / 14), ), SizedBox( height: 5, ), - Utils.buildSvgWithAssets(icon: AppAssets.cloud_logo, width: 40, height: 40), + Utils.buildSvgWithAssets( + icon: AppAssets.cloud_logo, width: 40, height: 40), SizedBox(height: 7), // Text( // "Version 1.1.0", diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 4987ffe..a537412 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; class AppColors { + static const transparent = Colors.transparent; static const mainPurple = Color(0xFF7954F7); static const purpleBg = Color(0xFFAEA4FC); static const deepPurple = Color(0xFF7C65E7); diff --git a/pubspec.lock b/pubspec.lock index 6ba3395..98b07a4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" audio_session: dependency: transitive description: @@ -161,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dartz: + dependency: "direct main" + description: + name: dartz + sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168 + url: "https://pub.dev" + source: hosted + version: "0.10.1" dbus: dependency: transitive description: @@ -219,7 +227,7 @@ packages: source: hosted version: "0.0.2" equatable: - dependency: transitive + dependency: "direct main" description: name: equatable sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" @@ -230,10 +238,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" ffi: dependency: transitive description: @@ -290,6 +298,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3+4" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: "4f85b161772e1d54a66893ef131c0a44bd9e552efa78b33d5f4f60d2caa5c8a3" + url: "https://pub.dev" + source: hosted + version: "11.6.0" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: a44b6d1155ed5cae7641e3de7163111cfd9f6f6c954ca916dc6a3bdfa86bf845 + url: "https://pub.dev" + source: hosted + version: "4.4.3" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: c7d1ed1f86ae64215757518af5576ff88341c8ce5741988c05cc3b2e07b0b273 + url: "https://pub.dev" + source: hosted + version: "0.5.10+16" firebase_core: dependency: "direct main" description: @@ -615,6 +647,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.5" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b + url: "https://pub.dev" + source: hosted + version: "8.2.0" + google_api_availability: + dependency: "direct main" + description: + name: google_api_availability + sha256: "2ffdc91e1e0cf4e7974fef6c2988a24cefa81f03526ff04b694df6dc0fcbca03" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + google_api_availability_android: + dependency: transitive + description: + name: google_api_availability_android + sha256: "4794147f43a8f3eee6b514d3ae30dbe6f7b9048cae8cd2a74cb4055cd28d74a8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + google_api_availability_platform_interface: + dependency: transitive + description: + name: google_api_availability_platform_interface + sha256: "65b7da62fe5b582bb3d508628ad827d36d890710ea274766a992a56fa5420da6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" google_maps: dependency: transitive description: @@ -767,22 +831,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.2" - injector: - dependency: "direct main" - description: - name: injector - sha256: d692c37788872bfd4bd7c01b864b0712190a25ae5a346431ff69949d5728a2e1 - url: "https://pub.dev" - source: hosted - version: "4.0.0" intl: dependency: transitive description: name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.20.2" + version: "0.19.0" json_annotation: dependency: transitive description: @@ -819,10 +875,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -1099,10 +1155,10 @@ packages: dependency: transitive description: name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "6.1.0" platform: dependency: transitive description: @@ -1296,10 +1352,10 @@ packages: dependency: transitive description: name: sqflite_common - sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b" url: "https://pub.dev" source: hosted - version: "2.5.6" + version: "2.5.5" sqflite_darwin: dependency: transitive description: @@ -1384,10 +1440,10 @@ packages: dependency: transitive description: name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.3.1" term_glyph: dependency: transitive description: @@ -1536,10 +1592,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" web: dependency: "direct main" description: @@ -1552,10 +1608,10 @@ packages: dependency: transitive description: name: win32 - sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" url: "https://pub.dev" source: hosted - version: "5.14.0" + version: "5.13.0" win32_registry: dependency: transitive description: @@ -1576,10 +1632,10 @@ packages: dependency: transitive description: name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.6.1" + version: "6.5.0" sdks: - dart: ">=3.8.0 <4.0.0" + dart: ">=3.7.0 <4.0.0" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index a6e3e49..6c79c92 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -62,6 +62,8 @@ dependencies: flutter_zoom_videosdk: ^2.1.10 dartz: ^0.10.1 equatable: ^2.0.7 + google_api_availability: ^5.0.1 + firebase_analytics: ^11.5.1 web: any smooth_corner: ^1.1.1 From 4e010bb2cf3ea496e8501d4e0095a73efb958323 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Tue, 2 Sep 2025 09:09:38 +0300 Subject: [PATCH 05/10] initial commit --- ios/Podfile.lock | 66 +++++ lib/core/api/api_client.dart | 241 ++++++------------ lib/core/api_consts.dart | 4 +- lib/core/dependencies.dart | 10 +- .../authentication/authentication_repo.dart | 41 +-- .../models/authenticated_user_model.dart | 2 +- 6 files changed, 180 insertions(+), 184 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index db4395f..6794b89 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -42,11 +42,20 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter + - Firebase/Analytics (11.15.0): + - Firebase/Core + - Firebase/Core (11.15.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 11.15.0) - Firebase/CoreOnly (11.15.0): - FirebaseCore (~> 11.15.0) - Firebase/Messaging (11.15.0): - Firebase/CoreOnly - FirebaseMessaging (~> 11.15.0) + - firebase_analytics (11.6.0): + - Firebase/Analytics (= 11.15.0) + - firebase_core + - Flutter - firebase_core (3.15.2): - Firebase/CoreOnly (= 11.15.0) - Flutter @@ -54,6 +63,24 @@ PODS: - Firebase/Messaging (= 11.15.0) - firebase_core - Flutter + - FirebaseAnalytics (11.15.0): + - FirebaseAnalytics/Default (= 11.15.0) + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - FirebaseAnalytics/Default (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleAppMeasurement/Default (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) - FirebaseCore (11.15.0): - FirebaseCoreInternal (~> 11.15.0) - GoogleUtilities/Environment (~> 8.1) @@ -107,6 +134,32 @@ PODS: - Flutter - Google-Maps-iOS-Utils (< 7.0, >= 5.0) - GoogleMaps (< 10.0, >= 8.4) + - GoogleAdsOnDeviceConversion (2.1.0): + - GoogleUtilities/Logger (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/Core (11.15.0): + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/Default (11.15.0): + - GoogleAdsOnDeviceConversion (= 2.1.0) + - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleAppMeasurement/IdentitySupport (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/IdentitySupport (11.15.0): + - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) @@ -125,6 +178,9 @@ PODS: - GoogleUtilities/Logger (8.1.0): - GoogleUtilities/Environment - GoogleUtilities/Privacy + - GoogleUtilities/MethodSwizzler (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy - GoogleUtilities/Network (8.1.0): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" @@ -216,6 +272,7 @@ DEPENDENCIES: - device_calendar (from `.symlinks/plugins/device_calendar/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - FLAnimatedImage @@ -249,12 +306,15 @@ SPEC REPOS: - DKImagePickerController - DKPhotoGallery - Firebase + - FirebaseAnalytics - FirebaseCore - FirebaseCoreInternal - FirebaseInstallations - FirebaseMessaging - FLAnimatedImage - Google-Maps-iOS-Utils + - GoogleAdsOnDeviceConversion + - GoogleAppMeasurement - GoogleDataTransport - GoogleMaps - GoogleUtilities @@ -288,6 +348,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/device_info_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" firebase_messaging: @@ -345,8 +407,10 @@ SPEC CHECKSUMS: DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_analytics: bf93e20703c95030404d6ddbb1adf05bf5c3885b firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 + FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 @@ -362,6 +426,8 @@ SPEC CHECKSUMS: geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3 + GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 + GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index d8b379d..203c6ef 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:io' show Platform; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; @@ -10,7 +11,6 @@ import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:http/http.dart' as http; - abstract class ApiClient { Future post( String endPoint, { @@ -75,8 +75,10 @@ class ApiClientImp implements ApiClient { final _analytics = getIt(); final LoggerService loggerService; + ApiClientImp({required this.loggerService}); + @override post(String endPoint, {required Map body, required Function(dynamic response, int statusCode) onSuccess, @@ -98,21 +100,15 @@ class ApiClientImp implements ApiClient { } try { var user = appState.getAuthenticatedUser; - Map headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }; + Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; if (!isExternal) { String? token = appState.appAuthToken; - String? languageID = - (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en') ?? 'ar'; + String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en') ?? 'ar'; if (endPoint == ApiConsts.sendActivationCode) { languageID = 'en'; } if (body.containsKey('SetupID')) { - body['SetupID'] = body.containsKey('SetupID') - ? body['SetupID'] ?? body[''] - : SETUP_ID; + body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] ?? body[''] : SETUP_ID; } else {} if (body.containsKey('LanguageID')) { @@ -127,90 +123,71 @@ class ApiClientImp implements ApiClient { } if (body.containsKey('isDentalAllowedBackend')) { - body['isDentalAllowedBackend'] = - body.containsKey('isDentalAllowedBackend') - ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND - : IS_DENTAL_ALLOWED_BACKEND; + body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; } + + //Todo: I have converted it to string body['DeviceTypeID'] = Platform.isIOS - ? 1 + ? "1" : await Utils.isGoogleServicesAvailable() - ? 2 - : 3; + ? "2" + : "3"; if (!body.containsKey('IsPublicRequest')) { // if (!body.containsKey('PatientType')) { if (user != null && user.patientType != null) { body['PatientType'] = user.patientType; } else { - body['PatientType'] = PATIENT_TYPE; + body['PatientType'] = PATIENT_TYPE.toString(); } - // } - - // body['PatientType'] = body.containsKey('PatientType') - // ? body['PatientType'] != null - // ? body['PatientType'] - // : user['PatientType'] != null - // ? user['PatientType'] - // : PATIENT_TYPE - // : PATIENT_TYPE; - // if (!body.containsKey('PatientTypeID')) { if (user != null && user.patientType != null) { body['PatientTypeID'] = user.patientType; } else { - body['PatientType'] = PATIENT_TYPE_ID; + body['PatientType'] = PATIENT_TYPE_ID.toString(); } - // } - - // body['PatientTypeID'] = body.containsKey('PatientTypeID') - // ? body['PatientTypeID'] != null - // ? body['PatientTypeID'] - // : user['PatientType'] != null - // ? user['PatientType'] - // : PATIENT_TYPE_ID - // : PATIENT_TYPE_ID; if (user != null) { body['TokenID'] = body['TokenID'] ?? token; body['PatientID'] = body['PatientID'] ?? user.patientID; - body['PatientOutSA'] = body.containsKey('PatientOutSA') - ? body['PatientOutSA'] ?? user.outSA - : user.outSA; + body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] ?? user.outSA : user.outSA; body['SessionID'] = getSessionId(body['TokenID'] ?? ""); //getSe } } } + + body['LanguageID'] = body['LanguageID'] ?? "1"; + body['VersionID'] = body['VersionID'] ?? "18.7"; + body['Channel'] = body['Channel'] ?? "3"; + body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; + body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958"; + body['Latitude'] = body['Latitude'] ?? "0.0"; + body['Longitude'] = body['Longitude'] ?? "0.0"; + body['DeviceTypeID'] = body['DeviceTypeID'] ?? + (Platform.isIOS ? "1" : await Utils.isGoogleServicesAvailable() ? "2" : "3"); + //"LanguageID":1,"VersionID":18.7,"Channel":3,"IPAdress":"10.20.10.20","generalid":"Cs2020@2016$2958","Latitude":0.0,"Longitude":0.0,"DeviceTypeID":2,"PatientType":1} body.removeWhere((key, value) => value == null); - debugPrint("URL : $url"); - final jsonBody = json.encode(body); - debugPrint(jsonBody); - // } - // return; - if (await Utils.checkConnection( - bypassConnectionCheck: bypassConnectionCheck)) { - final response = await http.post(Uri.parse(url.trim()), - body: json.encode(body), headers: headers); + log("bodi: ${json.encode(body)}"); + log("bodi: ${Uri.parse(url.trim())}"); + + if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) { + + final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400) { onFailure('Error While Fetching data', statusCode); - logApiEndpointError( - endPoint, 'Error While Fetching data', statusCode); + logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { - // var decoded = utf8.decode(response.bodyBytes); - var parsed; - // if (url.contains('Services/NHIC.svc/REST/GetPatientInfo')) { - // parsed = json.decode(sampleNHICResponse); - // } else { - parsed = json.decode(utf8.decode(response.bodyBytes)); - // } - - // print("Response: $parsed"); + var parsed = json.decode(utf8.decode(response.bodyBytes)); + log("parsed: ${parsed.toString()}"); if (isAllowAny) { onSuccess(parsed, statusCode); } else { @@ -219,10 +196,7 @@ class ApiClientImp implements ApiClient { } else { if (parsed['ErrorType'] == 4) { //TODO : handle app update - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } if (parsed['ErrorType'] == 2) { // todo: handle Logout @@ -238,72 +212,42 @@ class ApiClientImp implements ApiClient { } else if (parsed['Result'] == 'OK') { onSuccess(parsed, statusCode); } else { - // if (parsed != null) { - // onSuccess(parsed, statusCode); - // } else { - onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - // logout(); - // } + + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + } - } else if (parsed['MessageStatus'] == 1 || - parsed['SMSLoginRequired'] == true) { + } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { onSuccess(parsed, statusCode); - } else if (parsed['MessageStatus'] == 2 && - parsed['IsAuthenticated']) { + } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { if (parsed['SameClinicApptList'] != null) { onSuccess(parsed, statusCode); } else { - if (parsed['message'] == null && - parsed['ErrorEndUserMessage'] == null) { + if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { - onFailure("Server Error found with no available message", - statusCode); - logApiEndpointError( - endPoint, - "Server Error found with no available message", - statusCode); + onFailure("Server Error found with no available message", statusCode); + logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { onFailure(parsed['ErrorSearchMsg'], statusCode); - logApiEndpointError( - endPoint, parsed['ErrorSearchMsg'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } } else { - onFailure( - parsed['message'] ?? - parsed['ErrorEndUserMessage'] ?? - parsed['ErrorMessage'], - statusCode); - logApiEndpointError(endPoint, - parsed['message'] ?? parsed['message'], statusCode); + onFailure(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } } } - // else if (!parsed['IsAuthenticated']) { - // await logout(); - // } + else { if (parsed['SameClinicApptList'] != null) { onSuccess(parsed, statusCode); } else { if (parsed['message'] != null) { - onFailure( - parsed['message'] ?? parsed['message'], statusCode); - logApiEndpointError(endPoint, - parsed['message'] ?? parsed['message'], statusCode); + onFailure(parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } else { - onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); - logApiEndpointError( - endPoint, - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } @@ -312,20 +256,17 @@ class ApiClientImp implements ApiClient { } } else { onFailure('Please Check The Internet Connection 1', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } catch (e) { - print(e); + loggerService.errorLogs(e.toString()); if (e.toString().contains("ClientException")) { onFailure('Something went wrong, plase try again', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } else { onFailure(e.toString(), -1); } - _analytics.errorTracking - .log(endPoint, error: "api exception: $e - API Path: $url"); + _analytics.errorTracking.log(endPoint, error: "api exception: $e - API Path: $url"); } } @@ -356,10 +297,7 @@ class ApiClientImp implements ApiClient { if (await Utils.checkConnection()) { final response = await http.get( Uri.parse(url.trim()), - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, + headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, ); final int statusCode = response.statusCode; // print("statusCode :$statusCode"); @@ -373,8 +311,7 @@ class ApiClientImp implements ApiClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } @@ -390,8 +327,7 @@ class ApiClientImp implements ApiClient { // print("body: $body"); if (await Utils.checkConnection()) { - headers!.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.post( Uri.parse(url.trim()), body: json.encode(body), @@ -400,11 +336,7 @@ class ApiClientImp implements ApiClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePost(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - body: body, - headers: headers); + simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); // print(response.body.toString()); @@ -416,8 +348,7 @@ class ApiClientImp implements ApiClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } @@ -437,8 +368,7 @@ class ApiClientImp implements ApiClient { } if (await Utils.checkConnection()) { - headers.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.get( Uri.parse(url.trim()), headers: headers, @@ -447,11 +377,7 @@ class ApiClientImp implements ApiClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleGet(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - headers: headers, - queryParams: queryParams); + simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); if (statusCode < 200 || statusCode >= 400) { onFailure!('Error While Fetching data', statusCode); @@ -461,8 +387,7 @@ class ApiClientImp implements ApiClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } @@ -475,8 +400,7 @@ class ApiClientImp implements ApiClient { // print("URL Query String: $url"); if (await Utils.checkConnection()) { - headers!.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.put( Uri.parse(url.trim()), body: json.encode(body), @@ -486,11 +410,7 @@ class ApiClientImp implements ApiClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePut(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - headers: headers, - body: body); + simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); if (statusCode < 200 || statusCode >= 400) { onFailure!('Error While Fetching data', statusCode); @@ -500,8 +420,7 @@ class ApiClientImp implements ApiClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } @@ -521,8 +440,7 @@ class ApiClientImp implements ApiClient { } if (await Utils.checkConnection()) { - headers!.addAll( - {'Content-Type': 'application/json', 'Accept': 'application/json'}); + headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.delete( Uri.parse(url.trim()), headers: headers, @@ -531,11 +449,7 @@ class ApiClientImp implements ApiClient { final int statusCode = response.statusCode; // print("statusCode :$statusCode"); if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleDelete(fullUrl, - onFailure: onFailure, - onSuccess: onSuccess, - queryParams: queryParams, - headers: headers); + simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); if (statusCode < 200 || statusCode >= 400) { onFailure!('Error While Fetching data', statusCode); @@ -545,13 +459,11 @@ class ApiClientImp implements ApiClient { } } else { onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking - .log("internet_connectivity", error: "no internet available"); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } - Future handleUnauthorized(int statusCode, - {required String forUrl}) async { + Future handleUnauthorized(int statusCode, {required String forUrl}) async { if (forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { final token = await generatePackagesToken(); ApiConsts.packagesAuthHeader['Authorization'] = 'Bearer $token'; @@ -574,8 +486,7 @@ class ApiClientImp implements ApiClient { }; String? token; final completer = Completer(); - simplePost(url, body: body, headers: {}, - onSuccess: (dynamic stringResponse, int statusCode) { + simplePost(url, body: body, headers: {}, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); token = jsonResponse['auth_token']; diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index dc952bf..6f82e26 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -745,8 +745,8 @@ class ApiConsts { static num VERSION_ID = 18.9; - static final String selectDeviceImei = 'https://hmgwebservices.com/Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; - static final String sendActivationCode = 'https://hmgwebservices.com/Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; + static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index a789da4..440cd26 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_repo. import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/common/common_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; +import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:logger/web.dart'; @@ -15,10 +16,17 @@ GetIt getIt = GetIt.instance; class AppDependencies { static Future addDependencies() async { // Services - getIt.registerLazySingleton(() => LoggerServiceImp(logger: Logger(printer: PrettyPrinter(lineLength: 0)))); + getIt.registerLazySingleton(() => LoggerServiceImp(logger: Logger(printer: PrettyPrinter( + methodCount: 2, // number of stack trace lines + errorMethodCount: 5, // number of stack trace lines for errors + lineLength: 100, // wrap width + colors: true, // colorful logs + printEmojis: true, // include emojis + ),))); final sharedPreferences = await SharedPreferences.getInstance(); getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences)); getIt.registerSingleton(AppState()); + getIt.registerSingleton(GAnalytics()); getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt())); // Repositories diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 8122a52..e544638 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,4 +1,5 @@ -import 'dart:convert'; +import 'dart:async'; +import 'dart:developer'; import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; @@ -7,7 +8,6 @@ import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/features/authentication/models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; -import 'package:http/http.dart'; abstract class AuthenticationRepo { Future> selectDeviceByImei({required String firebaseToken}); @@ -20,24 +20,35 @@ class AuthenticationRepoImp implements AuthenticationRepo { AuthenticationRepoImp({required this.loggerService, required this.apiClient}); @override - Future> selectDeviceByImei({required String firebaseToken}) async { + Future> selectDeviceByImei({ + required String firebaseToken, + }) async { final mapDevice = {"IMEI": firebaseToken}; - try { - final Response result = await apiClient.postJsonForResponse(ApiConsts.selectDeviceImei, mapDevice); - final SelectDeviceByImeiRespModelElement selectDeviceByImeiRespModelElement = SelectDeviceByImeiRespModelElement.fromJson(jsonDecode(result.body)['Patient_SELECTDeviceIMEIbyIMEIList'][0]); - loggerService.logInfo(result.body); - if (result !=null) { - return Right(selectDeviceByImeiRespModelElement); - } else { - loggerService.errorLogs(result.toString()); - return Left(ServerFailure(result.toString())); - } + final completer = Completer>(); + await apiClient.post( + ApiConsts.selectDeviceImei, + body: mapDevice, + onSuccess: (response, statusCode) { + try { + final SelectDeviceByImeiRespModelElement model = + SelectDeviceByImeiRespModelElement.fromJson(response['Patient_SELECTDeviceIMEIbyIMEIList'][0]); + completer.complete(Right(model)); + } catch (e) { + completer.complete(Left(ServerFailure(e.toString()))); + } + }, + onFailure: (error, statusCode) { + loggerService.logInfo(("$error - $statusCode").toString()); + completer.complete(Left(ServerFailure(error))); + }, + ); + + return await completer.future; } on APIException catch (e) { - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(apiError?.errorMessage ?? e.message)); + return Left(ServerFailure(e.message)); } catch (e) { loggerService.errorLogs(e.toString()); return Left(ServerFailure(e.toString())); diff --git a/lib/features/authentication/models/authenticated_user_model.dart b/lib/features/authentication/models/authenticated_user_model.dart index 49987f3..2a071bb 100644 --- a/lib/features/authentication/models/authenticated_user_model.dart +++ b/lib/features/authentication/models/authenticated_user_model.dart @@ -1,4 +1,4 @@ -import 'package:hmg_patient_app/uitl/date_uitl.dart'; +import 'package:hmg_patient_app_new/core/utils/date_util.dart'; class AuthenticatedUser { String? setupID; From c1221e4970b90417532c3b23a7b98aae63ebe4d1 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Tue, 2 Sep 2025 09:35:05 +0300 Subject: [PATCH 06/10] pushed device api --- ios/Podfile.lock | 4 ++-- lib/core/api/api_client.dart | 5 +++-- pubspec.lock | 30 +++++++++++++++--------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6794b89..e5a28a8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -416,7 +416,7 @@ SPEC CHECKSUMS: FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_callkit_incoming: 417dd1b46541cdd5d855ad795ccbe97d1c18155e flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579 @@ -464,4 +464,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 5df9d8aa8f2c105eacd5ad7a310503d93c68c86b -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 203c6ef..fbf63b2 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -161,7 +161,7 @@ class ApiClientImp implements ApiClient { } - body['LanguageID'] = body['LanguageID'] ?? "1"; + body['LanguageID'] = body['LanguageID'] ?? "2"; body['VersionID'] = body['VersionID'] ?? "18.7"; body['Channel'] = body['Channel'] ?? "3"; body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; @@ -169,6 +169,8 @@ class ApiClientImp implements ApiClient { body['Latitude'] = body['Latitude'] ?? "0.0"; body['Longitude'] = body['Longitude'] ?? "0.0"; body['DeviceTypeID'] = body['DeviceTypeID'] ?? + + (Platform.isIOS ? "1" : await Utils.isGoogleServicesAvailable() ? "2" : "3"); //"LanguageID":1,"VersionID":18.7,"Channel":3,"IPAdress":"10.20.10.20","generalid":"Cs2020@2016$2958","Latitude":0.0,"Longitude":0.0,"DeviceTypeID":2,"PatientType":1} body.removeWhere((key, value) => value == null); @@ -186,7 +188,6 @@ class ApiClientImp implements ApiClient { logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { var parsed = json.decode(utf8.decode(response.bodyBytes)); - log("parsed: ${parsed.toString()}"); if (isAllowAny) { onSuccess(parsed, statusCode); diff --git a/pubspec.lock b/pubspec.lock index 98b07a4..0695fc8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -238,10 +238,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -835,10 +835,10 @@ packages: dependency: transitive description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" json_annotation: dependency: transitive description: @@ -875,26 +875,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -1456,10 +1456,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" time: dependency: transitive description: @@ -1584,10 +1584,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1637,5 +1637,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.7.0 <4.0.0" + dart: ">=3.8.0-0 <4.0.0" flutter: ">=3.29.0" From 89e9323d9e389a64c925f8c0823d90252d037a26 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Tue, 2 Sep 2025 09:43:45 +0300 Subject: [PATCH 07/10] merged master and updated structure --- lib/core/app_state.dart | 4 +- lib/main.dart | 4 -- lib/presentation/home/landing_page.dart | 61 ++++++++++++------------- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index e58ba20..91e200a 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -4,14 +4,12 @@ import 'package:hmg_patient_app_new/features/authentication/models/authenticated import 'package:hmg_patient_app_new/main.dart'; import 'api_consts.dart' as ApiConsts; -import 'consts.dart'; + class AppState { // Simple constructor - let get_it handle the singleton behavior AppState(); - //Tokens - bool isAuthenticated = false; bool isAuthenticated = true; diff --git a/lib/main.dart b/lib/main.dart index 7b2e93c..3d25c0a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,18 +5,14 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; -import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/theme/app_theme.dart'; -import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; - import 'core/utils/size_utils.dart'; import 'firebase_options.dart'; diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 0397056..feb7f69 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -1,8 +1,10 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; @@ -10,15 +12,11 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; -import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.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 '../../core/app_assets.dart'; -import '../../core/utils/utils.dart'; -import '../../widgets/buttons/custom_button.dart'; - class LandingPage extends StatefulWidget { const LandingPage({super.key}); @@ -27,7 +25,6 @@ class LandingPage extends StatefulWidget { } class _LandingPageState extends State { - late AuthenticationViewModel authenticationViewModel; @override Widget build(BuildContext context) { @@ -80,33 +77,31 @@ class _LandingPageState extends State { ), child: Padding( padding: EdgeInsets.all(12.h), - child: Container( - child: Column( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - SizedBox(height: 12.h), - "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), - SizedBox(height: 12.h), - CustomButton( - text: LocaleKeys.bookAppo.tr(context: context), - onPressed: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LandingPage()), - ); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40, - icon: AppAssets.add_icon, - iconColor: AppColors.primaryRedColor, - ), - ], - ), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.bookAppo.tr(context: context), + onPressed: () { + Navigator.of(context).pushReplacement( + MaterialPageRoute(builder: (BuildContext context) => LandingPage()), + ); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40, + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + ), + ], ), ), ), From 6bc7af00bc3346d2a7b029e184ce2875687c7616 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Tue, 2 Sep 2025 12:31:05 +0300 Subject: [PATCH 08/10] completed the deviceapi with new architecture --- ios/Podfile.lock | 35 +- lib/core/api/api_client.dart | 532 +++++++++--------- lib/core/app_state.dart | 18 +- lib/core/common_models/generic_api_model.dart | 34 ++ lib/core/dependencies.dart | 62 +- lib/core/exceptions/api_failure.dart | 21 +- lib/core/location_util.dart | 43 +- lib/core/utils/utils.dart | 85 +-- .../authentication/authentication_repo.dart | 62 +- .../authentication_view_model.dart | 45 +- .../models/select_device_by_imei.dart | 124 ++-- lib/main.dart | 15 +- lib/presentation/home/landing_page.dart | 15 +- lib/services/dialog_service.dart | 71 +++ lib/services/error_handler_service.dart | 52 ++ lib/services/navigation_service.dart | 15 + 16 files changed, 735 insertions(+), 494 deletions(-) create mode 100644 lib/core/common_models/generic_api_model.dart create mode 100644 lib/services/dialog_service.dart create mode 100644 lib/services/error_handler_service.dart create mode 100644 lib/services/navigation_service.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5249fe5..c62a44f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -41,11 +41,20 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter + - Firebase/Analytics (11.15.0): + - Firebase/Core + - Firebase/Core (11.15.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 11.15.0) - Firebase/CoreOnly (11.15.0): - FirebaseCore (~> 11.15.0) - Firebase/Messaging (11.15.0): - Firebase/CoreOnly - FirebaseMessaging (~> 11.15.0) + - firebase_analytics (11.6.0): + - Firebase/Analytics (= 11.15.0) + - firebase_core + - Flutter - firebase_core (3.15.2): - Firebase/CoreOnly (= 11.15.0) - Flutter @@ -53,6 +62,24 @@ PODS: - Firebase/Messaging (= 11.15.0) - firebase_core - Flutter + - FirebaseAnalytics (11.15.0): + - FirebaseAnalytics/Default (= 11.15.0) + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - FirebaseAnalytics/Default (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleAppMeasurement/Default (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) - FirebaseCore (11.15.0): - FirebaseCoreInternal (~> 11.15.0) - GoogleUtilities/Environment (~> 8.1) @@ -371,14 +398,16 @@ SPEC CHECKSUMS: DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_analytics: bf93e20703c95030404d6ddbb1adf05bf5c3885b firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 + FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579 flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f @@ -387,6 +416,8 @@ SPEC CHECKSUMS: geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3 + GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 + GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 @@ -423,4 +454,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 5df9d8aa8f2c105eacd5ad7a310503d93c68c86b -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index fbf63b2..c3862e2 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -2,21 +2,25 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io' show Platform; + import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:http/http.dart' as http; +import '../exceptions/api_failure.dart'; + abstract class ApiClient { Future post( String endPoint, { required Map body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, + required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess, + required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, bool isAllowAny, bool isExternal, bool isRCService, @@ -32,61 +36,69 @@ abstract class ApiClient { bool isRCService, }); - Future simplePost( - String fullUrl, { - required Map body, - required Map headers, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - }); - - Future simpleGet( - String fullUrl, { - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers, - }); - - Future simplePut( - String fullUrl, { - Map? body, - Map? headers, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - }); - - Future simpleDelete( - String fullUrl, { - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers, - }); - - Future handleUnauthorized(int statusCode, {required String forUrl}); - String getSessionId(String id); - Future generatePackagesToken(); +// Future simplePost( +// String fullUrl, { +// required Map body, +// required Map headers, +// required Function(dynamic response, int statusCode) onSuccess, +// required Function(String error, int statusCode) onFailure, +// }); + +// +// Future simpleGet( +// String fullUrl, { +// Function(dynamic response, int statusCode)? onSuccess, +// Function(String error, int statusCode)? onFailure, +// Map? queryParams, +// Map? headers, +// }); +// +// Future simplePut( +// String fullUrl, { +// Map? body, +// Map? headers, +// Function(dynamic response, int statusCode)? onSuccess, +// Function(String error, int statusCode)? onFailure, +// }); +// +// Future simpleDelete( +// String fullUrl, { +// Function(dynamic response, int statusCode)? onSuccess, +// Function(String error, int statusCode)? onFailure, +// Map? queryParams, +// Map? headers, +// }); + +// Future handleUnauthorized(int statusCode, {required String forUrl}); +// Future generatePackagesToken(); } class ApiClientImp implements ApiClient { final _analytics = getIt(); final LoggerService loggerService; + final AppState appState; + final DialogService dialogService; - ApiClientImp({required this.loggerService}); + ApiClientImp({ + required this.loggerService, + required this.dialogService, + required this.appState, + }); @override - post(String endPoint, - {required Map body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isExternal = false, - bool isRCService = false, - bool bypassConnectionCheck = false}) async { + post( + String endPoint, { + required Map body, + required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess, + required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, + bool isAllowAny = false, + bool isExternal = false, + bool isRCService = false, + bool bypassConnectionCheck = false, + }) async { AppState appState = getIt.get(); String url; if (isExternal) { @@ -103,7 +115,7 @@ class ApiClientImp implements ApiClient { Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; if (!isExternal) { String? token = appState.appAuthToken; - String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en') ?? 'ar'; + String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en'); if (endPoint == ApiConsts.sendActivationCode) { languageID = 'en'; } @@ -113,7 +125,6 @@ class ApiClientImp implements ApiClient { if (body.containsKey('LanguageID')) { if (body['LanguageID'] != null) { - //change this line because language issue happened on dental body['LanguageID'] = body['LanguageID'] == 'ar' ? 1 : body['LanguageID'] == 'en' @@ -128,7 +139,6 @@ class ApiClientImp implements ApiClient { : IS_DENTAL_ALLOWED_BACKEND; } - //Todo: I have converted it to string body['DeviceTypeID'] = Platform.isIOS ? "1" @@ -160,40 +170,38 @@ class ApiClientImp implements ApiClient { } } - - body['LanguageID'] = body['LanguageID'] ?? "2"; - body['VersionID'] = body['VersionID'] ?? "18.7"; - body['Channel'] = body['Channel'] ?? "3"; - body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; - body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958"; - body['Latitude'] = body['Latitude'] ?? "0.0"; - body['Longitude'] = body['Longitude'] ?? "0.0"; + body['LanguageID'] = body['LanguageID'] ?? "2"; + body['VersionID'] = body['VersionID'] ?? "18.7"; + body['Channel'] = body['Channel'] ?? "3"; + body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; + body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958"; + body['Latitude'] = body['Latitude'] ?? "0.0"; + body['Longitude'] = body['Longitude'] ?? "0.0"; body['DeviceTypeID'] = body['DeviceTypeID'] ?? - - - (Platform.isIOS ? "1" : await Utils.isGoogleServicesAvailable() ? "2" : "3"); - //"LanguageID":1,"VersionID":18.7,"Channel":3,"IPAdress":"10.20.10.20","generalid":"Cs2020@2016$2958","Latitude":0.0,"Longitude":0.0,"DeviceTypeID":2,"PatientType":1} + (Platform.isIOS + ? "1" + : await Utils.isGoogleServicesAvailable() + ? "2" + : "3"); body.removeWhere((key, value) => value == null); - - log("bodi: ${json.encode(body)}"); - log("bodi: ${Uri.parse(url.trim())}"); + log("body: ${json.encode(body)}"); + log("uri: ${Uri.parse(url.trim())}"); if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) { - final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400) { - onFailure('Error While Fetching data', statusCode); + onFailure('Error While Fetching data', statusCode, failureType: ServerFailure("Error While Fetching data")); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { - var parsed = json.decode(utf8.decode(response.bodyBytes)); + var parsed = json.decode(utf8.decode(response.bodyBytes)); log("parsed: ${parsed.toString()}"); if (isAllowAny) { onSuccess(parsed, statusCode); } else { if (parsed['Response_Message'] != null) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else { if (parsed['ErrorType'] == 4) { //TODO : handle app update @@ -204,19 +212,18 @@ class ApiClientImp implements ApiClient { logApiEndpointError(endPoint, "session logged out", statusCode); } if (isAllowAny) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['IsAuthenticated'] == null) { if (parsed['isSMSSent'] == true) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['MessageStatus'] == 1) { onSuccess(parsed, statusCode); } else if (parsed['Result'] == 'OK') { onSuccess(parsed, statusCode); } else { - - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, + failureType: ServerFailure("Error While Fetching data")); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); - } } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { onSuccess(parsed, statusCode); @@ -226,28 +233,46 @@ class ApiClientImp implements ApiClient { } else { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { - onFailure("Server Error found with no available message", statusCode); + onFailure( + "Server Error found with no available message", + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { - onFailure(parsed['ErrorSearchMsg'], statusCode); + onFailure( + parsed['ErrorSearchMsg'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } } else { - onFailure(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + onFailure( + parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } } - } - - else { + } else { if (parsed['SameClinicApptList'] != null) { onSuccess(parsed, statusCode); } else { if (parsed['message'] != null) { - onFailure(parsed['message'] ?? parsed['message'], statusCode); + onFailure( + parsed['message'] ?? parsed['message'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } else { - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } @@ -256,13 +281,17 @@ class ApiClientImp implements ApiClient { } } } else { - onFailure('Please Check The Internet Connection 1', -1); + onFailure( + 'Please Check The Internet Connection 1', + -1, + failureType: ConnectivityFailure("Error While Fetching data"), + ); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } catch (e) { loggerService.errorLogs(e.toString()); if (e.toString().contains("ClientException")) { - onFailure('Something went wrong, plase try again', -1); + onFailure('Something went wrong, plase try again', -1, failureType: InvalidCredentials('Something went wrong, plase try again')); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } else { onFailure(e.toString(), -1); @@ -271,6 +300,7 @@ class ApiClientImp implements ApiClient { } } + @override get(String endPoint, {required Function(dynamic response, int statusCode) onSuccess, required Function(String error, int statusCode) onFailure, @@ -304,203 +334,173 @@ class ApiClientImp implements ApiClient { // print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); + onFailure('Error While Fetching data', statusCode); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { var parsed = json.decode(utf8.decode(response.bodyBytes)); - onSuccess!(parsed, statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - simplePost( - String fullUrl, { - required Map body, - required Map headers, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - }) async { - String url = fullUrl; - // print("URL Query String: $url"); - // print("body: $body"); - - if (await Utils.checkConnection()) { - headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.post( - Uri.parse(url.trim()), - body: json.encode(body), - headers: headers, - ); - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); - - // print(response.body.toString()); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); + onSuccess(parsed, statusCode); } } else { - onFailure!('Please Check The Internet Connection', -1); + onFailure('Please Check The Internet Connection', -1); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } - simpleGet(String fullUrl, - {Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers}) async { - headers = headers ?? {}; - String url = fullUrl; - - var haveParams = (queryParams != null); - if (haveParams) { - String queryString = Uri(queryParameters: queryParams).query; - url += '?$queryString'; - // print("URL Query String: $url"); - } - - if (await Utils.checkConnection()) { - headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.get( - Uri.parse(url.trim()), - headers: headers, - ); - - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - simplePut(String fullUrl, - {Map? body, - Map? headers, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure}) async { - String url = fullUrl; - // print("URL Query String: $url"); - - if (await Utils.checkConnection()) { - headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.put( - Uri.parse(url.trim()), - body: json.encode(body), - headers: headers, - ); - - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - simpleDelete(String fullUrl, - {Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers}) async { - String url = fullUrl; - // print("URL Query String: $url"); - - var haveParams = (queryParams != null); - if (haveParams) { - String queryString = Uri(queryParameters: queryParams).query; - url += '?$queryString'; - // print("URL Query String: $url"); - } - - if (await Utils.checkConnection()) { - headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.delete( - Uri.parse(url.trim()), - headers: headers, - ); - - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - Future handleUnauthorized(int statusCode, {required String forUrl}) async { - if (forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { - final token = await generatePackagesToken(); - ApiConsts.packagesAuthHeader['Authorization'] = 'Bearer $token'; - return (token is String); - } - return false; - } + // @override + // simplePost( + // String fullUrl, { + // required Map body, + // required Map headers, + // required Function(dynamic response, int statusCode) onSuccess, + // required Function(String error, int statusCode) onFailure, + // }) async { + // String url = fullUrl; + // // print("URL Query String: $url"); + // // print("body: $body"); + // + // if (await Utils.checkConnection()) { + // headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.post( + // Uri.parse(url.trim()), + // body: json.encode(body), + // headers: headers, + // ); + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) { + // simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); + // } + // + // // print(response.body.toString()); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + + // simpleGet(String fullUrl, + // {Function(dynamic response, int statusCode)? onSuccess, + // Function(String error, int statusCode)? onFailure, + // Map? queryParams, + // Map? headers}) async { + // headers = headers ?? {}; + // String url = fullUrl; + // + // var haveParams = (queryParams != null); + // if (haveParams) { + // String queryString = Uri(queryParameters: queryParams).query; + // url += '?$queryString'; + // // print("URL Query String: $url"); + // } + // + // if (await Utils.checkConnection()) { + // headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.get( + // Uri.parse(url.trim()), + // headers: headers, + // ); + // + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + // simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + + // simplePut(String fullUrl, + // {Map? body, + // Map? headers, + // Function(dynamic response, int statusCode)? onSuccess, + // Function(String error, int statusCode)? onFailure}) async { + // String url = fullUrl; + // // print("URL Query String: $url"); + // + // if (await Utils.checkConnection()) { + // headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.put( + // Uri.parse(url.trim()), + // body: json.encode(body), + // headers: headers, + // ); + // + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + // simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + // + // simpleDelete(String fullUrl, + // {Function(dynamic response, int statusCode)? onSuccess, + // Function(String error, int statusCode)? onFailure, + // Map? queryParams, + // Map? headers}) async { + // String url = fullUrl; + // // print("URL Query String: $url"); + // + // var haveParams = (queryParams != null); + // if (haveParams) { + // String queryString = Uri(queryParameters: queryParams).query; + // url += '?$queryString'; + // // print("URL Query String: $url"); + // } + // + // if (await Utils.checkConnection()) { + // headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.delete( + // Uri.parse(url.trim()), + // headers: headers, + // ); + // + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + // simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + @override String getSessionId(String id) { return id.replaceAll(RegExp('/[^a-zA-Z]'), ''); } - Future generatePackagesToken() async { - var url = EXA_CART_API_BASE_URL + PACKAGES_TOKEN; - var body = { - "api_client": { - "client_id": "a4ab6be4-424f-4836-b032-46caed88e184", - "client_secret": "3c1a3e07-4a40-4510-9fb0-ee5f0a72752c" - } - }; - String? token; - final completer = Completer(); - simplePost(url, body: body, headers: {}, onSuccess: (dynamic stringResponse, int statusCode) { - if (statusCode == 200) { - var jsonResponse = json.decode(stringResponse); - token = jsonResponse['auth_token']; - completer.complete(); - } - }, onFailure: (String error, int statusCode) { - completer.complete(); - logApiFullUrlError(url, error, statusCode); - }); - await completer.future; - return token!; - } - logApiFullUrlError(String fullUrl, error, code) { final endpoint = Uri.parse(fullUrl).pathSegments.last; logApiEndpointError(endpoint, error, code); diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index 91e200a..bdf8d25 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -1,15 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:hmg_patient_app_new/core/post_params_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; -import 'package:hmg_patient_app_new/main.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'api_consts.dart' as ApiConsts; - class AppState { - // Simple constructor - let get_it handle the singleton behavior - AppState(); + NavigationService navigationService; + AppState({required this.navigationService}); bool isAuthenticated = true; @@ -40,9 +39,7 @@ class AppState { PostParamsModel? get postParamsObject => _postParams; - Map get postParamsJson => isAuthenticated - ? (_postParams?.toJsonAfterLogin() ?? {}) - : (_postParams?.toJson() ?? {}); + Map get postParamsJson => isAuthenticated ? (_postParams?.toJsonAfterLogin() ?? {}) : (_postParams?.toJson() ?? {}); void setPostParamsModel(PostParamsModel _postParams) { this._postParams = _postParams; @@ -51,12 +48,9 @@ class AppState { double userLat = 0.0; double userLong = 0.0; - bool isArabic() => - EasyLocalization.of(navigatorKey.currentContext!)?.locale.languageCode == - "ar"; + bool isArabic() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar"; - int getLanguageID(context) => - EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; + int getLanguageID(context) => EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; AuthenticatedUser? _authenticatedUser; diff --git a/lib/core/common_models/generic_api_model.dart b/lib/core/common_models/generic_api_model.dart new file mode 100644 index 0000000..1ab11db --- /dev/null +++ b/lib/core/common_models/generic_api_model.dart @@ -0,0 +1,34 @@ +class GenericApiModel { + final int? messageStatus; + final String? errorMessage; + final int? statusCode; + final T? data; + + GenericApiModel({ + this.messageStatus, + this.errorMessage, + this.statusCode, + this.data, + }); + + factory GenericApiModel.fromJson( + Map json, + T Function(Object? json)? fromJsonT, + ) { + return GenericApiModel( + messageStatus: json['messageStatus'] as int?, + errorMessage: json['errorMessage'] as String?, + statusCode: json['statusCode'] as int?, + data: fromJsonT != null ? fromJsonT(json['data']) : json['data'] as T?, + ); + } + + Map toJson(Object Function(T value)? toJsonT) { + return { + 'messageStatus': messageStatus, + 'errorMessage': errorMessage, + 'statusCode': statusCode, + 'data': toJsonT != null && data != null ? toJsonT(data as T) : data, + }; + } +} diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 440cd26..5aba3e2 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -1,13 +1,18 @@ import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/location_util.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/common/common_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; +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/logger_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:logger/web.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -15,25 +20,58 @@ GetIt getIt = GetIt.instance; class AppDependencies { static Future addDependencies() async { - // Services - getIt.registerLazySingleton(() => LoggerServiceImp(logger: Logger(printer: PrettyPrinter( - methodCount: 2, // number of stack trace lines - errorMethodCount: 5, // number of stack trace lines for errors - lineLength: 100, // wrap width - colors: true, // colorful logs - printEmojis: true, // include emojis - ),))); + Logger logger = Logger( + printer: PrettyPrinter( + methodCount: 2, + errorMethodCount: 5, + lineLength: 100, + colors: true, + printEmojis: true, + ), + ); + + // Core Services + getIt.registerLazySingleton(() => LoggerServiceImp(logger: logger)); + getIt.registerLazySingleton(() => NavigationService()); + getIt.registerLazySingleton(() => GAnalytics()); + getIt.registerLazySingleton(() => AppState(navigationService: getIt())); + getIt.registerLazySingleton(() => LocationUtils(isShowConfirmDialog: false, navigationService: getIt())); + getIt.registerLazySingleton(() => DialogServiceImp(navigationService: getIt())); + getIt.registerLazySingleton(() => ErrorHandlerServiceImp( + dialogService: getIt(), + loggerService: getIt(), + navigationService: getIt(), + )); + final sharedPreferences = await SharedPreferences.getInstance(); getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences)); - getIt.registerSingleton(AppState()); - getIt.registerSingleton(GAnalytics()); - getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt())); + getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt(), dialogService: getIt(), appState: getIt())); // Repositories getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); getIt.registerLazySingleton(() => AuthenticationRepoImp(loggerService: getIt(), apiClient: getIt())); - getIt.registerLazySingleton(() => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton( + () => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => MyAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + // ViewModels + // Global/shared VMs → LazySingleton + getIt.registerLazySingleton( + () => AuthenticationViewModel( + authenticationRepo: getIt(), + dialogService: getIt(), + appState: getIt(), + errorHandlerService: getIt(), + ), + ); + + // Screen-specific VMs → Factory + // getIt.registerFactory( + // () => BookAppointmentsViewModel( + // bookAppointmentsRepo: getIt(), + // dialogService: getIt(), + // errorHandlerService: getIt(), + // ), + // ); } } diff --git a/lib/core/exceptions/api_failure.dart b/lib/core/exceptions/api_failure.dart index eaa434e..d2a510f 100644 --- a/lib/core/exceptions/api_failure.dart +++ b/lib/core/exceptions/api_failure.dart @@ -1,8 +1,8 @@ - import 'package:equatable/equatable.dart'; abstract class Failure extends Equatable implements Exception { final String message; + const Failure(this.message); } @@ -27,15 +27,30 @@ class LocalStorageFailure extends Failure { List get props => [message]; } +class DataParsingFailure extends Failure { + const DataParsingFailure(super.message); + + @override + List get props => [message]; +} + +class UnknownFailure extends Failure { + const UnknownFailure(super.message); + + @override + List get props => [message]; +} + + class DuplicateUsername extends Failure { - const DuplicateUsername({String? message}) : super(message ?? ''); + const DuplicateUsername(String? message) : super(message ?? ''); @override List get props => [message]; } class InvalidCredentials extends Failure { - const InvalidCredentials({String? message}) : super(message ?? ''); + const InvalidCredentials(String? message) : super(message ?? ''); @override List get props => [message]; diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index d9716a9..c8e69af 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -1,41 +1,40 @@ import 'dart:io'; +import 'package:geolocator/geolocator.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/consts.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; - +import 'package:hmg_patient_app_new/services/navigation_service.dart'; // import 'package:huawei_location/huawei_location.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:provider/provider.dart'; class LocationUtils { + NavigationService navigationService; bool isShowConfirmDialog; bool isShowLocationTimeoutDialog; - BuildContext context; bool isHuawei; final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance; - LocationUtils({required this.isShowConfirmDialog, required this.context, this.isHuawei = false, this.isShowLocationTimeoutDialog = true}); + LocationUtils({ + required this.isShowConfirmDialog, + required this.navigationService, + this.isHuawei = false, + this.isShowLocationTimeoutDialog = true, + }); + AppState appState = getIt.get(); void getCurrentLocation({Function(LatLng)? callBack}) async { Geolocator.isLocationServiceEnabled().then((value) async { if (value) { await Geolocator.checkPermission().then((permission) async { if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) { - // Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) { Geolocator.getLastKnownPosition().then((value) { setLocation(value); if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709)); }).catchError((err) { - print(err); - if (isShowConfirmDialog && isShowLocationTimeoutDialog) { - // showLocationTimeOutDialog(failureCallBack: () { - // Geolocator.openAppSettings(); - // }); - } + if (isShowConfirmDialog && isShowLocationTimeoutDialog) {} }); } @@ -62,15 +61,11 @@ class LocationUtils { } } } - }).catchError((err) { - print(err); - }); + }).catchError((err) {}); } else { if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {}); } - }).catchError((err) { - print(err); - }); + }).catchError((err) {}); } Future checkIfGPSIsEnabled() async { @@ -151,8 +146,8 @@ class LocationUtils { Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.latitude ?? 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.longitude ?? 0.0); - AppState().setUserLat = position?.latitude ?? 0.0; - AppState().setUserLong = position?.longitude ?? 0.0; + appState.setUserLat = position?.latitude ?? 0.0; + appState.setUserLong = position?.longitude ?? 0.0; // projectViewModel.setLatitudeLongitude(position?.latitude ?? 0.0, position?.longitude ?? 0.0); } @@ -161,8 +156,8 @@ class LocationUtils { Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0); - AppState().setUserLat = 0.0; - AppState().setUserLong = 0.0; + appState.setUserLat = 0.0; + appState.setUserLong = 0.0; } Future requestPermissions() async { diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 4f7b398..14e91f8 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -1,24 +1,28 @@ import 'dart:convert'; -import 'package:crypto/crypto.dart' as crypto; import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:crypto/crypto.dart' as crypto; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_api_availability/google_api_availability.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:hmg_patient_app_new/main.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart'; import 'package:hmg_patient_app_new/widgets/loading_dialog.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:lottie/lottie.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Utils { + static AppState appState = getIt.get(); + static NavigationService navigationService = getIt.get(); + static bool _isLoadingVisible = false; static bool get isLoading => _isLoadingVisible; @@ -47,14 +51,16 @@ class Utils { } static String getFreeSlotsTimeText(String startTime, {bool isAddHours = false}) { - // return DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime)!.add( + // return DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime)!.add( // Duration( // hours: isAddHours ? 3 : 0, // ), // )); return !isAddHours - ? DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal()) - : DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( + ? DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US") + .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal()) + : DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US") + .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( Duration( hours: isAddHours ? 3 : 0, ), @@ -82,12 +88,9 @@ class Utils { } static String getMonthDayYearDateFormatted(DateTime dateTime) { - if (dateTime != null) - return AppState().isArabic() - ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString() - : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); - else - return ""; + return appState.isArabic() + ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString() + : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); } /// get month by @@ -200,7 +203,7 @@ class Utils { static void showLoadingDialog() { _isLoadingVisible = true; showDialog( - context: navigatorKey.currentContext!, + context: navigationService.navigatorKey.currentContext!, barrierColor: Colors.black.withOpacity(0.5), builder: (BuildContext context) => LoadingDialog(), ) @@ -217,7 +220,7 @@ class Utils { try { if (_isLoadingVisible) { _isLoadingVisible = false; - Navigator.of(navigatorKey.currentContext!).pop(); + Navigator.of(navigationService.navigatorKey.currentContext!).pop(); } _isLoadingVisible = false; } catch (e) {} @@ -242,9 +245,6 @@ class Utils { static bool isSAUDIIDValid(String id, type) { if (type == 1) { - if (id == null) { - return false; - } try { id = id.toString(); id = id.trim(); @@ -304,13 +304,15 @@ class Utils { } static String removeHtmlTags(String htmlString) { - if (htmlString == null || htmlString.isEmpty) { + if (htmlString.isEmpty) { return ''; } // Replace HTML line breaks with newlines - var withLineBreaks = - htmlString.replaceAll(RegExp(r'', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'', multiLine: true), '\n'); + var withLineBreaks = htmlString + .replaceAll(RegExp(r'', multiLine: true), '\n') + .replaceAll(RegExp(r'<\/p>', multiLine: true), '\n') + .replaceAll(RegExp(r'', multiLine: true), '\n'); // Remove all other HTML tags var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), ''); @@ -376,7 +378,20 @@ class Utils { final year = parts[0]; // Map month number to short month name (Hijri months) - const hijriMonthNames = ['Muharram', 'Safar', 'Rabi I', 'Rabi II', 'Jumada I', 'Jumada II', 'Rajab', 'Sha\'ban', 'Ramadan', 'Shawwal', 'Dhu al-Qi\'dah', 'Dhu al-Hijjah']; + const hijriMonthNames = [ + 'Muharram', + 'Safar', + 'Rabi I', + 'Rabi II', + 'Jumada I', + 'Jumada II', + 'Rajab', + 'Sha\'ban', + 'Ramadan', + 'Shawwal', + 'Dhu al-Qi\'dah', + 'Dhu al-Hijjah' + ]; final monthIndex = int.tryParse(parts[1]) ?? 1; final month = hijriMonthNames[monthIndex - 1]; @@ -458,13 +473,8 @@ class Utils { ); } - - - static Future isGoogleServicesAvailable() async { - GooglePlayServicesAvailability availability = await GoogleApiAvailability - .instance - .checkGooglePlayServicesAvailability(); + GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); String status = availability.toString().split('.').last; if (status == "success") { return true; @@ -472,26 +482,17 @@ class Utils { return false; } - - - - - static Future checkConnection( - {bool bypassConnectionCheck = false}) async { + static Future checkConnection({bool bypassConnectionCheck = false}) async { if (bypassConnectionCheck) return true; - List connectivityResult = - await (Connectivity().checkConnectivity()); - if (connectivityResult.contains(ConnectivityResult.mobile) || - connectivityResult.contains(ConnectivityResult.wifi)) { + List connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult.contains(ConnectivityResult.mobile) || connectivityResult.contains(ConnectivityResult.wifi)) { return true; } else { return false; } } - static String generateMd5Hash(String input) { return crypto.md5.convert(utf8.encode(input)).toString(); } - } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index e544638..04e3a9e 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,16 +1,15 @@ import 'dart:async'; -import 'dart:developer'; import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; -import 'package:hmg_patient_app_new/core/exceptions/api_exception.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/authentication/models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class AuthenticationRepo { - Future> selectDeviceByImei({required String firebaseToken}); + Future>> selectDeviceByImei({required String firebaseToken}); } class AuthenticationRepoImp implements AuthenticationRepo { @@ -20,38 +19,43 @@ class AuthenticationRepoImp implements AuthenticationRepo { AuthenticationRepoImp({required this.loggerService, required this.apiClient}); @override - Future> selectDeviceByImei({ + Future>> selectDeviceByImei({ required String firebaseToken, }) async { final mapDevice = {"IMEI": firebaseToken}; try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + ApiConsts.selectDeviceImei, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + final list = response['Patient_SELECTDeviceIMEIbyIMEIList'] as List?; + if (list == null || list.isEmpty) { + throw Exception("Device list is empty"); + } - final completer = Completer>(); - await apiClient.post( - ApiConsts.selectDeviceImei, - body: mapDevice, - onSuccess: (response, statusCode) { - try { - final SelectDeviceByImeiRespModelElement model = - SelectDeviceByImeiRespModelElement.fromJson(response['Patient_SELECTDeviceIMEIbyIMEIList'][0]); - completer.complete(Right(model)); - } catch (e) { - completer.complete(Left(ServerFailure(e.toString()))); - } - }, - onFailure: (error, statusCode) { - loggerService.logInfo(("$error - $statusCode").toString()); - completer.complete(Left(ServerFailure(error))); - }, - ); - - return await completer.future; - } on APIException catch (e) { - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(e.message)); + final model = SelectDeviceByImeiRespModelElement.fromJson(list[0] as Map); + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: model, + ); + } 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) { - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(e.toString())); + return Left(UnknownFailure(e.toString())); } } } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 8269c72..eaf3c95 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1,46 +1,37 @@ -import 'dart:developer'; -import 'dart:io'; - import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; -import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/check_activation_code_request_register.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; class AuthenticationViewModel extends ChangeNotifier { AuthenticationRepo authenticationRepo; AppState appState; + ErrorHandlerService errorHandlerService; + DialogService dialogService; AuthenticationViewModel({ required this.appState, required this.authenticationRepo, + required this.errorHandlerService, + required this.dialogService, }); final TextEditingController nationalIdController = TextEditingController(); final TextEditingController phoneNumberController = TextEditingController(); - Future selectDeviceImei({ - Function(dynamic)? onSuccess, - Function(String)? onError - }) async { - final String firebaseToken = - "cIkkB7h7Q7uoFkC4Qv82xG:APA91bEb53Z9XzqymCIctaLxCoMX6bm9fuKlWILQ59uUqfwhCoD42AOP1-jWGB1WYd9BVN5PT2pUUFxrT07vcNg1KH9OH39mrPgCl0m21XVIgWrzNnCkufg"; - - final resultEither = - await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); - - resultEither.fold( - (failure) { - notifyListeners(); - if (onError != null) onError(failure.message); - }, - (data) { - - log("resultEither: ${data.toString()} "); - - notifyListeners(); - if (onSuccess != null) onSuccess(data); + Future selectDeviceImei({Function(dynamic)? onSuccess, Function(String)? onError}) async { + String firebaseToken = + "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"; + final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); + result.fold( + (failure) async => await errorHandlerService.handleError(failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + dialogService.showErrorDialog(apiResponse.errorMessage!); + } else if (apiResponse.messageStatus == 1) { + // move to next api call + } }, ); } diff --git a/lib/features/authentication/models/select_device_by_imei.dart b/lib/features/authentication/models/select_device_by_imei.dart index 2ab669e..398f791 100644 --- a/lib/features/authentication/models/select_device_by_imei.dart +++ b/lib/features/authentication/models/select_device_by_imei.dart @@ -1,77 +1,73 @@ -// To parse this JSON data, do -// -// final selectDeviceByImeiRespModel = selectDeviceByImeiRespModelFromJson(jsonString); - import 'dart:convert'; -Map selectDeviceByImeiRespModelFromJson(String str) => Map.from(json.decode(str)).map((k, v) => MapEntry(k, v)); +Map selectDeviceByImeiRespModelFromJson(String str) => Map.from(json.decode(str)); -String selectDeviceByImeiRespModelToJson(Map data) => json.encode(Map.from(data).map((k, v) => MapEntry(k, v))); +String selectDeviceByImeiRespModelToJson(Map data) => json.encode(Map.from(data)); class SelectDeviceByImeiRespModelElement { - int id; - String imei; - int logInType; - int patientId; - bool outSa; - String mobile; - String identificationNo; - String name; - String nameN; - String createdOn; - String editedOn; - bool biometricEnabled; - int patientType; - int preferredLanguage; + int? id; + String? imei; + int? logInType; + int? patientId; + bool? outSa; + String? mobile; + String? identificationNo; + String? name; + String? nameN; + String? createdOn; + String? editedOn; + bool? biometricEnabled; + int? patientType; + int? preferredLanguage; SelectDeviceByImeiRespModelElement({ - required this.id, - required this.imei, - required this.logInType, - required this.patientId, - required this.outSa, - required this.mobile, - required this.identificationNo, - required this.name, - required this.nameN, - required this.createdOn, - required this.editedOn, - required this.biometricEnabled, - required this.patientType, - required this.preferredLanguage, + this.id, + this.imei, + this.logInType, + this.patientId, + this.outSa, + this.mobile, + this.identificationNo, + this.name, + this.nameN, + this.createdOn, + this.editedOn, + this.biometricEnabled, + this.patientType, + this.preferredLanguage, }); factory SelectDeviceByImeiRespModelElement.fromJson(Map json) => SelectDeviceByImeiRespModelElement( - id: json["ID"], - imei: json["IMEI"], - logInType: json["LogInType"], - patientId: json["PatientID"], - outSa: json["OutSA"], - mobile: json["Mobile"], - identificationNo: json["IdentificationNo"], - name: json["Name"], - nameN: json["NameN"], - createdOn: json["CreatedOn"], - editedOn: json["EditedOn"], - biometricEnabled: json["BiometricEnabled"], - patientType: json["PatientType"], - preferredLanguage: json["PreferredLanguage"], - ); + id: json["ID"] as int?, + imei: json["IMEI"] as String?, + logInType: json["LogInType"] as int?, + patientId: json["PatientID"] as int?, + outSa: json["OutSA"] as bool?, + mobile: json["Mobile"] as String?, + identificationNo: json["IdentificationNo"] as String?, + name: json["Name"] as String?, + nameN: json["NameN"] as String?, + createdOn: json["CreatedOn"] as String?, + editedOn: json["EditedOn"] as String?, + biometricEnabled: json["BiometricEnabled"] as bool?, + patientType: json["PatientType"] as int?, + preferredLanguage: json["PreferredLanguage"] as int?, + ); Map toJson() => { - "ID": id, - "IMEI": imei, - "LogInType": logInType, - "PatientID": patientId, - "OutSA": outSa, - "Mobile": mobile, - "IdentificationNo": identificationNo, - "Name": name, - "NameN": nameN, - "CreatedOn": createdOn, - "EditedOn": editedOn, - "BiometricEnabled": biometricEnabled, - "PatientType": patientType, - "PreferredLanguage": preferredLanguage, - }; + "ID": id, + "IMEI": imei, + "LogInType": logInType, + "PatientID": patientId, + "OutSA": outSa, + "Mobile": mobile, + "IdentificationNo": identificationNo, + "Name": name, + "NameN": nameN, + "CreatedOn": createdOn, + "EditedOn": editedOn, + "BiometricEnabled": biometricEnabled, + "PatientType": patientType, + "PreferredLanguage": preferredLanguage, + }; } diff --git a/lib/main.dart b/lib/main.dart index 3d25c0a..bb4332b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,16 +10,14 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_view_ import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/app_theme.dart'; import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; + import 'core/utils/size_utils.dart'; import 'firebase_options.dart'; -var globalMessengerKey = GlobalKey(); -final navigatorKey = GlobalKey(); - - @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); @@ -57,7 +55,12 @@ void main() async { create: (_) => BottomNavigationProvider(), ), ChangeNotifierProvider( - create: (_) => AuthenticationViewModel(authenticationRepo: getIt(), appState: getIt()), + create: (_) => AuthenticationViewModel( + authenticationRepo: getIt(), + appState: getIt(), + dialogService: getIt(), + errorHandlerService: getIt(), + ), ), ], child: MyApp()), ), @@ -94,7 +97,7 @@ class MyApp extends StatelessWidget { initialRoute: AppRoutes.initialRoute, routes: AppRoutes.routes, theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), - navigatorKey: navigatorKey, + navigatorKey: getIt.get().navigatorKey, ); }, ); diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index feb7f69..22355cc 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -3,11 +3,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; @@ -25,9 +27,10 @@ class LandingPage extends StatefulWidget { } class _LandingPageState extends State { - @override Widget build(BuildContext context) { + AppState appState = getIt.get(); + final AuthenticationViewModel authenticationViewModel = context.read(); return Consumer(builder: (context, navigationProvider, child) { return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -43,10 +46,8 @@ class _LandingPageState extends State { children: [ CustomButton( text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LandingPage()), - ); + onPressed: () async { + await authenticationViewModel.selectDeviceImei(); }, backgroundColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA), @@ -66,7 +67,7 @@ class _LandingPageState extends State { ), ), SizedBox(height: 16.h), - AppState().isAuthenticated + appState.isAuthenticated ? Column( children: [ Container( @@ -257,7 +258,7 @@ class _LandingPageState extends State { ), ), SizedBox(height: 16.h), - AppState().isAuthenticated + appState.isAuthenticated ? Column( children: [ Row( diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart new file mode 100644 index 0000000..e931568 --- /dev/null +++ b/lib/services/dialog_service.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; + +abstract class DialogService { + Future showErrorDialog(String message); +} + +class DialogServiceImp implements DialogService { + final NavigationService navigationService; + + DialogServiceImp({required this.navigationService}); + + @override + Future showErrorDialog(String message) async { + final context = navigationService.navigatorKey.currentContext; + if (context == null) return; + + await showModalBottomSheet( + context: context, + isScrollControlled: false, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (_) => _ErrorBottomSheet(message: message), + ); + } +} + +class _ErrorBottomSheet extends StatelessWidget { + final String message; + + const _ErrorBottomSheet({required this.message}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.error_outline, color: Colors.red, size: 40), + const SizedBox(height: 12), + Text( + "Error", + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + message, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () => Navigator.of(context).pop(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text("OK"), + ), + ], + ), + ); + } +} diff --git a/lib/services/error_handler_service.dart b/lib/services/error_handler_service.dart new file mode 100644 index 0000000..d8d473a --- /dev/null +++ b/lib/services/error_handler_service.dart @@ -0,0 +1,52 @@ +import 'dart:io'; + +import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; + +abstract class ErrorHandlerService { + Future handleError(Failure failure); +} + +class ErrorHandlerServiceImp implements ErrorHandlerService { + final DialogService dialogService; + final LoggerService loggerService; + final NavigationService navigationService; + + ErrorHandlerServiceImp({ + required this.dialogService, + required this.loggerService, + required this.navigationService, + }); + + @override + Future handleError(Failure failure) async { + if (failure is APIException) { + loggerService.errorLogs("API Exception: ${failure.message}"); + } else if (failure is ServerFailure) { + loggerService.errorLogs("Server Failure: ${failure.message}"); + await _showDialog(failure); + } else if (failure is DataParsingFailure) { + loggerService.errorLogs("Data Parsing Failure: ${failure.message}"); + await _showDialog(failure, title: "Data Error"); + } else if (failure is HttpException) { + loggerService.errorLogs("Http Exception: ${failure.message}"); + await _showDialog(failure, title: "Network Error"); + } else if (failure is UnknownFailure) { + loggerService.errorLogs("Unknown Failure: ${failure.message}"); + await _showDialog(failure, title: "Unknown Error"); + } else if (failure is InvalidCredentials) { + loggerService.errorLogs("Invalid Credentials : ${failure.message}"); + await _showDialog(failure, title: "Unknown Error"); + } else { + loggerService.errorLogs("Unhandled failure type: $failure"); + await _showDialog(failure, title: "Error"); + } + } + + Future _showDialog(Failure failure, {String title = "Error"}) async { + await dialogService.showErrorDialog(failure.message); + } +} diff --git a/lib/services/navigation_service.dart b/lib/services/navigation_service.dart new file mode 100644 index 0000000..d814cf5 --- /dev/null +++ b/lib/services/navigation_service.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class NavigationService { + final GlobalKey navigatorKey = GlobalKey(); + + BuildContext? get context => navigatorKey.currentContext; + + Future push(Route route) { + return navigatorKey.currentState!.push(route); + } + + void pop([T? result]) { + navigatorKey.currentState!.pop(result); + } +} From 9509d4a1921b9d07f4bed68c77862e9e155ab072 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Tue, 2 Sep 2025 15:15:16 +0300 Subject: [PATCH 09/10] completed the deviceapi with new architecture --- lib/core/api/api_client.dart | 10 +- lib/core/app_state.dart | 2 +- lib/core/dependencies.dart | 6 +- lib/core/enums.dart | 42 +- lib/core/exceptions/api_failure.dart | 9 + lib/core/location_util.dart | 6 +- ...CalendarUtils.dart => calendar_utils.dart} | 0 ...fication.dart => local_notifications.dart} | 0 ...er.dart => push_notification_handler.dart} | 12 +- lib/core/utils/request_utils.dart | 91 +++ lib/extensions/widget_extensions.dart | 22 +- .../authentication/authentication_repo.dart | 111 +++- .../authentication_view_model.dart | 103 +++- ...heck_activation_code_request_register.dart | 121 ---- ...heck_activation_code_request_register.dart | 121 ++++ ..._patient_authentication_request_model.dart | 88 +++ .../send_activation_request_model.dart | 132 +++++ .../authenticated_user_resp_model.dart} | 0 .../check_activation_code_resp_model.dart | 546 ++++++++++++++++++ ...ent_last_login_details_response_model.dart | 0 .../select_device_by_imei.dart | 0 lib/services/analytics/analytics_service.dart | 2 +- lib/services/dialog_service.dart | 18 +- lib/services/error_handler_service.dart | 11 +- lib/splashPage.dart | 4 +- lib/widgets/chip/custom_chip_widget.dart | 6 +- 26 files changed, 1286 insertions(+), 177 deletions(-) rename lib/core/utils/{CalendarUtils.dart => calendar_utils.dart} (100%) rename lib/core/utils/{LocalNotification.dart => local_notifications.dart} (100%) rename lib/core/utils/{push-notification-handler.dart => push_notification_handler.dart} (97%) create mode 100644 lib/core/utils/request_utils.dart delete mode 100644 lib/features/authentication/models/check_activation_code_request_register.dart create mode 100644 lib/features/authentication/models/request_models/check_activation_code_request_register.dart create mode 100644 lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart create mode 100644 lib/features/authentication/models/request_models/send_activation_request_model.dart rename lib/features/authentication/models/{authenticated_user_model.dart => resp_models/authenticated_user_resp_model.dart} (100%) create mode 100644 lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart rename lib/features/authentication/models/{ => resp_models}/get_patient_last_login_details_response_model.dart (100%) rename lib/features/authentication/models/{ => resp_models}/select_device_by_imei.dart (100%) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index c3862e2..92a7e6c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -170,6 +170,14 @@ class ApiClientImp implements ApiClient { } } + // request.versionID = VERSION_ID; + // request.channel = CHANNEL; + // request.iPAdress = IP_ADDRESS; + // request.generalid = GENERAL_ID; + // request.languageID = (languageID == 'ar' ? 1 : 2); + // request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1; + + // TODO : we will use all these from appState body['LanguageID'] = body['LanguageID'] ?? "2"; body['VersionID'] = body['VersionID'] ?? "18.7"; body['Channel'] = body['Channel'] ?? "3"; @@ -192,7 +200,7 @@ class ApiClientImp implements ApiClient { final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400) { - onFailure('Error While Fetching data', statusCode, failureType: ServerFailure("Error While Fetching data")); + onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { var parsed = json.decode(utf8.decode(response.bodyBytes)); diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index bdf8d25..7c42042 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -1,6 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:hmg_patient_app_new/core/post_params_model.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'api_consts.dart' as ApiConsts; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 5aba3e2..549eeed 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -35,7 +35,11 @@ class AppDependencies { getIt.registerLazySingleton(() => NavigationService()); getIt.registerLazySingleton(() => GAnalytics()); getIt.registerLazySingleton(() => AppState(navigationService: getIt())); - getIt.registerLazySingleton(() => LocationUtils(isShowConfirmDialog: false, navigationService: getIt())); + getIt.registerLazySingleton(() => LocationUtils( + isShowConfirmDialog: false, + navigationService: getIt(), + appState: getIt(), + )); getIt.registerLazySingleton(() => DialogServiceImp(navigationService: getIt())); getIt.registerLazySingleton(() => ErrorHandlerServiceImp( dialogService: getIt(), diff --git a/lib/core/enums.dart b/lib/core/enums.dart index db758f3..2fd5867 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -5,7 +5,7 @@ // unverified, // } -enum AuthMethodTypes { +enum AuthMethodTypesEnum { sms, whatsApp, fingerPrint, @@ -13,7 +13,7 @@ enum AuthMethodTypes { moreOptions, } -enum ViewState { +enum ViewStateEnum { hide, idle, busy, @@ -22,20 +22,44 @@ enum ViewState { errorLocal, } -enum LoginType { +enum LoginTypeEnum { fromLogin, silentLogin, silentWithOTP, } -enum OTPType { sms, whatsapp } +enum OTPTypeEnum { sms, whatsapp } -enum Country { saudiArabia, unitedArabEmirates } +enum CountryEnum { saudiArabia, unitedArabEmirates } -enum SelectionType { dropdown, calendar } +enum SelectionTypeEnum { dropdown, calendar } -enum GenderType { male, female } +enum GenderTypeEnum { male, female } -enum MaritalStatusType { single, married, divorced, widowed } +enum MaritalStatusTypeEnum { single, married, divorced, widowed } -enum ChipType { success, error, alert, info, warning } +enum ChipTypeEnum { success, error, alert, info, warning } + +extension OTPTypeEnumExtension on OTPTypeEnum { + /// Convert enum to int + int toInt() { + switch (this) { + case OTPTypeEnum.sms: + return 1; + case OTPTypeEnum.whatsapp: + return 2; + } + } + + /// Convert int to enum + static OTPTypeEnum fromInt(int value) { + switch (value) { + case 1: + return OTPTypeEnum.sms; + case 2: + return OTPTypeEnum.whatsapp; + default: + throw Exception("Invalid OTPTypeEnum value: $value"); + } + } +} diff --git a/lib/core/exceptions/api_failure.dart b/lib/core/exceptions/api_failure.dart index d2a510f..4bc5097 100644 --- a/lib/core/exceptions/api_failure.dart +++ b/lib/core/exceptions/api_failure.dart @@ -13,6 +13,13 @@ class ServerFailure extends Failure { List get props => [message]; } +class StatusCodeFailure extends Failure { + const StatusCodeFailure(super.message); + + @override + List get props => [message]; +} + class ConnectivityFailure extends Failure { const ConnectivityFailure(super.message); @@ -55,3 +62,5 @@ class InvalidCredentials extends Failure { @override List get props => [message]; } + + diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index c8e69af..dc6a0d6 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -4,14 +4,14 @@ import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/consts.dart'; -import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; -// import 'package:huawei_location/huawei_location.dart'; import 'package:permission_handler/permission_handler.dart'; class LocationUtils { NavigationService navigationService; + AppState appState; + bool isShowConfirmDialog; bool isShowLocationTimeoutDialog; bool isHuawei; @@ -20,10 +20,10 @@ class LocationUtils { LocationUtils({ required this.isShowConfirmDialog, required this.navigationService, + required this.appState, this.isHuawei = false, this.isShowLocationTimeoutDialog = true, }); - AppState appState = getIt.get(); void getCurrentLocation({Function(LatLng)? callBack}) async { Geolocator.isLocationServiceEnabled().then((value) async { diff --git a/lib/core/utils/CalendarUtils.dart b/lib/core/utils/calendar_utils.dart similarity index 100% rename from lib/core/utils/CalendarUtils.dart rename to lib/core/utils/calendar_utils.dart diff --git a/lib/core/utils/LocalNotification.dart b/lib/core/utils/local_notifications.dart similarity index 100% rename from lib/core/utils/LocalNotification.dart rename to lib/core/utils/local_notifications.dart diff --git a/lib/core/utils/push-notification-handler.dart b/lib/core/utils/push_notification_handler.dart similarity index 97% rename from lib/core/utils/push-notification-handler.dart rename to lib/core/utils/push_notification_handler.dart index d71bdcf..b5a816e 100644 --- a/lib/core/utils/push-notification-handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -3,19 +3,17 @@ import 'dart:developer'; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:firebase_messaging/firebase_messaging.dart' as fir; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart' as fir; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:hmg_patient_app_new/core/utils/LocalNotification.dart'; +import 'package:hmg_patient_app_new/core/utils/local_notifications.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:uuid/uuid.dart'; import '../consts.dart'; @@ -365,7 +363,9 @@ class PushNotificationHandler { Future requestPermissions() async { try { if (Platform.isIOS) { - await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation() + ?.requestPermissions(alert: true, badge: true, sound: true); } else if (Platform.isAndroid) { Map statuses = await [ Permission.notification, diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart new file mode 100644 index 0000000..1869923 --- /dev/null +++ b/lib/core/utils/request_utils.dart @@ -0,0 +1,91 @@ +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/request_models/send_activation_request_model.dart'; + +class RequestUtils { + static dynamic getCommonRequestWelcome({ + required String phoneNumber, + required OTPTypeEnum otpTypeEnum, + required String? deviceToken, + required bool patientOutSA, + required String? loginTokenID, + required var registeredData, + required int? patientId, + required String nationIdText, + required String countryCode, + }) { + bool fileNo = false; + if (nationIdText.isNotEmpty) { + fileNo = nationIdText.length < 10; + } + var request = SendActivationRequest(); + request.patientMobileNumber = int.parse(phoneNumber); + request.mobileNo = '0$phoneNumber'; + request.deviceToken = deviceToken; + request.projectOutSA = patientOutSA; + request.loginType = otpTypeEnum.toInt(); + request.oTPSendType = otpTypeEnum.toInt(); // could map OTPTypeEnum if needed + request.zipCode = countryCode; // or countryCode if defined elsewhere + request.logInTokenID = loginTokenID ?? ""; + + if (registeredData != null) { + request.searchType = registeredData.searchType ?? 1; + request.patientID = registeredData.patientID ?? 0; + request.patientIdentificationID = request.nationalID = registeredData.patientIdentificationID ?? '0'; + request.dob = registeredData.dob; + request.isRegister = registeredData.isRegister; + } else { + if (fileNo) { + request.patientID = patientId ?? int.parse(nationIdText); + request.patientIdentificationID = request.nationalID = ""; + request.searchType = 2; + } else { + request.patientID = 0; + request.searchType = 1; + request.patientIdentificationID = request.nationalID = nationIdText.isNotEmpty ? nationIdText : '0'; + } + request.isRegister = false; + } + + request.deviceTypeID = request.searchType; + return request; + } + + static getCommonRequestAuthProvider({ + required OTPTypeEnum otpTypeEnum, + required registeredData, + required deviceToken, + required mobileNumber, + required zipCode, + required patientOutSA, + required loginTokenID, + required selectedOption, + required int? patientId, + }) { + var request = SendActivationRequest(); + request.patientMobileNumber = mobileNumber; + request.mobileNo = '0$mobileNumber'; + request.deviceToken = deviceToken; + request.projectOutSA = patientOutSA == true ? true : false; + request.loginType = selectedOption; + request.oTPSendType = otpTypeEnum.toInt(); //this.selectedOption == 1 ? 1 : 2; + request.zipCode = zipCode; + + request.logInTokenID = loginTokenID ?? ""; + + if (registeredData != null) { + request.searchType = registeredData.searchType ?? 1; + request.patientID = registeredData.patientID ?? 0; + request.patientIdentificationID = request.nationalID = registeredData.patientIdentificationID ?? '0'; + request.dob = registeredData.dob; + request.isRegister = registeredData.isRegister; + } else { + request.searchType = request.searchType ?? 2; + request.patientID = patientId ?? 0; + request.nationalID = request.nationalID ?? '0'; + request.patientIdentificationID = request.patientIdentificationID ?? '0'; + request.isRegister = false; + } + request.deviceTypeID = request.searchType; + return request; + } +} diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 8b8c796..e6913d2 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -193,33 +193,33 @@ Widget widthSpacer5per() => SizedBox(height: 5.w); -extension ChipTypeExtension on ChipType { +extension ChipTypeEnumExtension on ChipTypeEnum { Color get color { switch (this) { - case ChipType.success: + case ChipTypeEnum.success: return AppColors.successColor; // Replace with your actual color - case ChipType.error: + case ChipTypeEnum.error: return AppColors.errorColor; // Replace with your actual color - case ChipType.alert: + case ChipTypeEnum.alert: return AppColors.alertColor; // Replace with your actual color - case ChipType.info: + case ChipTypeEnum.info: return AppColors.infoColor; // Replace with your actual color - case ChipType.warning: + case ChipTypeEnum.warning: return AppColors.warningColor; // Replace with your actual color } } Color get backgroundColor { switch (this) { - case ChipType.success: + case ChipTypeEnum.success: return AppColors.successLightColor; // Replace with your actual color - case ChipType.error: + case ChipTypeEnum.error: return AppColors.errorLightColor; // Replace with your actual color - case ChipType.alert: + case ChipTypeEnum.alert: return AppColors.alertLightColor; // Replace with your actual color - case ChipType.info: + case ChipTypeEnum.info: return AppColors.infoLightColor; // Replace with your actual color - case ChipType.warning: + case ChipTypeEnum.warning: return AppColors.warningLightColor; // Replace with your actual color } } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 04e3a9e..7307013 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,15 +1,27 @@ import 'dart:async'; +import 'dart:io'; import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/select_device_by_imei.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_patient_authentication_request_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_activation_code_resp_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class AuthenticationRepo { - Future>> selectDeviceByImei({required String firebaseToken}); + Future>> selectDeviceByImei({ + required String firebaseToken, + }); + + Future>> checkPatientAuthentication({ + required CheckPatientAuthenticationReq checkPatientAuthenticationReq, + }); + + Future>> sendActivationCodeRegister( + {required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}); } class AuthenticationRepoImp implements AuthenticationRepo { @@ -19,9 +31,7 @@ class AuthenticationRepoImp implements AuthenticationRepo { AuthenticationRepoImp({required this.loggerService, required this.apiClient}); @override - Future>> selectDeviceByImei({ - required String firebaseToken, - }) async { + Future>> selectDeviceByImei({required String firebaseToken}) async { final mapDevice = {"IMEI": firebaseToken}; try { GenericApiModel? apiResponse; @@ -34,7 +44,7 @@ class AuthenticationRepoImp implements AuthenticationRepo { }, onSuccess: (response, statusCode, {messageStatus}) { try { - final list = response['Patient_SELECTDeviceIMEIbyIMEIList'] as List?; + final list = response['Patient_SELECTDeviceIMEIbyIMEIList']; if (list == null || list.isEmpty) { throw Exception("Device list is empty"); } @@ -58,4 +68,93 @@ class AuthenticationRepoImp implements AuthenticationRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> checkPatientAuthentication({ + required CheckPatientAuthenticationReq checkPatientAuthenticationReq, + String? languageID, + }) async { + int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; + //TODO : We will use all these from AppState directly in the ApiClient + + checkPatientAuthenticationReq.versionID = VERSION_ID; + checkPatientAuthenticationReq.channel = CHANNEL; + checkPatientAuthenticationReq.iPAdress = IP_ADDRESS; + checkPatientAuthenticationReq.generalid = GENERAL_ID; + checkPatientAuthenticationReq.languageID = (languageID == 'ar' ? 1 : 2); + checkPatientAuthenticationReq.patientOutSA = isOutKsa; + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + ApiConsts.selectDeviceImei, + body: checkPatientAuthenticationReq.toJson(), + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: response, + ); + } 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>> sendActivationCodeRegister( + {required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}) async { + int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; + //TODO : We will use all these from AppState directly in the ApiClient + + checkPatientAuthenticationReq.versionID = VERSION_ID; + checkPatientAuthenticationReq.channel = CHANNEL; + checkPatientAuthenticationReq.iPAdress = IP_ADDRESS; + checkPatientAuthenticationReq.generalid = GENERAL_ID; + checkPatientAuthenticationReq.languageID = (languageID == 'ar' ? 1 : 2); + checkPatientAuthenticationReq.deviceTypeID = Platform.isIOS ? 1 : 2; + checkPatientAuthenticationReq.patientOutSA = isOutKsa; + checkPatientAuthenticationReq.isDentalAllowedBackend = false; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + SEND_ACTIVATION_CODE_REGISTER, + body: checkPatientAuthenticationReq.toJson(), + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: CheckActivationCode.fromJson(response), + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index eaf3c95..573c528 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/request_utils.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_patient_authentication_request_model.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -24,15 +27,109 @@ class AuthenticationViewModel extends ChangeNotifier { String firebaseToken = "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"; final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); + result.fold( - (failure) async => await errorHandlerService.handleError(failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { - dialogService.showErrorDialog(apiResponse.errorMessage!); + dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { - // move to next api call + //todo: move to next api call + } + }, + ); + } + + Future checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { + CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( + phoneNumber: '0567184134', + otpTypeEnum: OTPTypeEnum.sms, + deviceToken: 'dummyDeviceToken123', + patientOutSA: true, + loginTokenID: 'dummyLoginToken456', + registeredData: null, + patientId: 12345, + nationIdText: '1234567890', + countryCode: 'SA', + ); + + final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.data['isSMSSent']) { + // TODO: set this in AppState + // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); + // loginTokenID = value['LogInTokenID'], + // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + sendActivationCode(type); + } else { + if (apiResponse.data['IsAuthenticated']) { + checkActivationCode(onWrongActivationCode: (String? message) {}); + } } }, ); } + + Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { + var request = RequestUtils.getCommonRequestAuthProvider( + otpTypeEnum: otpTypeEnum, + registeredData: null, + deviceToken: "dummyLoginToken456", + mobileNumber: "0567184134", + zipCode: "SA", + patientOutSA: true, + loginTokenID: "dummyLoginToken456", + selectedOption: selectedOption, + patientId: 12345, + ); + + request.sMSSignature = await SMSOTP.getSignature(); + selectedOption = type; + // GifLoaderDialogUtils.showMyDialog(context); + if (healthId != null || isDubai) { + if (!isDubai) { + request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); + } + request.healthId = healthId; + request.isHijri = isHijri; + await this.apiClient.sendActivationCodeRegister(request).then((result) { + // GifLoaderDialogUtils.hideDialog(context); + if (result != null && result['isSMSSent'] == true) { + this.startSMSService(type); + } + }).catchError((r) { + GifLoaderDialogUtils.hideDialog(context); + context.showBottomSheet( + child: ExceptionBottomSheet( + message: r.toString(), + onOkPressed: () { + Navigator.of(context).pop(); + }, + )); + // AppToast.showErrorToast(message: r); + }); + } else { + request.dob = ""; + request.healthId = ""; + request.isHijri = 0; + await this.authService.sendActivationCode(request).then((result) { + GifLoaderDialogUtils.hideDialog(context); + if (result != null && result['isSMSSent'] == true) { + this.startSMSService(type); + } + }).catchError((r) { + GifLoaderDialogUtils.hideDialog(context); + context.showBottomSheet( + child: ExceptionBottomSheet( + message: r.toString(), + onOkPressed: () { + Navigator.of(context).pop(); + }, + )); + // AppToast.showErrorToast(message: r.toString()); + }); + } + } } diff --git a/lib/features/authentication/models/check_activation_code_request_register.dart b/lib/features/authentication/models/check_activation_code_request_register.dart deleted file mode 100644 index 85e1f56..0000000 --- a/lib/features/authentication/models/check_activation_code_request_register.dart +++ /dev/null @@ -1,121 +0,0 @@ -class CheckActivationCodeRegisterReq { - int? patientMobileNumber; - String? mobileNo; - String? deviceToken; - bool? projectOutSA; - int? loginType; - String? zipCode; - bool? isRegister; - String? logInTokenID; - int? searchType; - int? patientID; - String? nationalID; - String? patientIdentificationID; - String? activationCode; - bool? isSilentLogin; - double? versionID; - int? channel; - int? languageID; - String? iPAdress; - String? generalid; - int? patientOutSA; - dynamic sessionID; - bool? isDentalAllowedBackend; - int? deviceTypeID; - bool? forRegisteration; - String? dob; - int? isHijri; - String? healthId; - - CheckActivationCodeRegisterReq({ - this.patientMobileNumber, - this.mobileNo, - this.deviceToken, - this.projectOutSA, - this.loginType, - this.zipCode, - this.isRegister, - this.logInTokenID, - this.searchType, - this.patientID, - this.nationalID, - this.patientIdentificationID, - this.activationCode, - this.isSilentLogin, - this.versionID, - this.channel, - this.languageID, - this.iPAdress, - this.generalid, - this.patientOutSA, - this.sessionID, - this.isDentalAllowedBackend, - this.deviceTypeID, - this.forRegisteration, - this.dob, - this.isHijri, - this.healthId, - }); - - CheckActivationCodeRegisterReq.fromJson(Map json) { - patientMobileNumber = json['PatientMobileNumber']; - mobileNo = json['MobileNo']; - deviceToken = json['DeviceToken']; - projectOutSA = json['ProjectOutSA']; - loginType = json['LoginType']; - zipCode = json['ZipCode']; - isRegister = json['isRegister']; - logInTokenID = json['LogInTokenID']; - searchType = json['SearchType']; - patientID = json['PatientID']; - nationalID = json['NationalID']; - patientIdentificationID = json['PatientIdentificationID']; - activationCode = json['activationCode']; - isSilentLogin = json['IsSilentLogin']; - 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']; - forRegisteration = json['ForRegisteration']; - dob = json['DOB']; - isHijri = json['IsHijri']; - healthId = json['HealthId']; - } - - Map toJson() { - final Map data = new Map(); - data['PatientMobileNumber'] = this.patientMobileNumber; - data['MobileNo'] = this.mobileNo; - data['DeviceToken'] = this.deviceToken; - data['ProjectOutSA'] = this.projectOutSA; - data['LoginType'] = this.loginType; - data['ZipCode'] = this.zipCode; - data['isRegister'] = this.isRegister; - data['LogInTokenID'] = this.logInTokenID; - data['SearchType'] = this.searchType; - data['PatientID'] = this.patientID; - data['NationalID'] = this.nationalID; - data['PatientIdentificationID'] = this.patientIdentificationID; - data['activationCode'] = this.activationCode; - data['IsSilentLogin'] = this.isSilentLogin; - 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['ForRegisteration'] = this.forRegisteration; - data['DOB'] = dob; - data['IsHijri'] = isHijri; - data['HealthId'] = healthId; - return data; - } -} diff --git a/lib/features/authentication/models/request_models/check_activation_code_request_register.dart b/lib/features/authentication/models/request_models/check_activation_code_request_register.dart new file mode 100644 index 0000000..167c8ec --- /dev/null +++ b/lib/features/authentication/models/request_models/check_activation_code_request_register.dart @@ -0,0 +1,121 @@ +// class CheckActivationCodeRegisterReq { +// int? patientMobileNumber; +// String? mobileNo; +// String? deviceToken; +// bool? projectOutSA; +// int? loginType; +// String? zipCode; +// bool? isRegister; +// String? logInTokenID; +// int? searchType; +// int? patientID; +// String? nationalID; +// String? patientIdentificationID; +// String? activationCode; +// bool? isSilentLogin; +// double? versionID; +// int? channel; +// int? languageID; +// String? iPAdress; +// String? generalid; +// int? patientOutSA; +// dynamic sessionID; +// bool? isDentalAllowedBackend; +// int? deviceTypeID; +// bool? forRegisteration; +// String? dob; +// int? isHijri; +// String? healthId; +// +// CheckActivationCodeRegisterReq({ +// this.patientMobileNumber, +// this.mobileNo, +// this.deviceToken, +// this.projectOutSA, +// this.loginType, +// this.zipCode, +// this.isRegister, +// this.logInTokenID, +// this.searchType, +// this.patientID, +// this.nationalID, +// this.patientIdentificationID, +// this.activationCode, +// this.isSilentLogin, +// this.versionID, +// this.channel, +// this.languageID, +// this.iPAdress, +// this.generalid, +// this.patientOutSA, +// this.sessionID, +// this.isDentalAllowedBackend, +// this.deviceTypeID, +// this.forRegisteration, +// this.dob, +// this.isHijri, +// this.healthId, +// }); +// +// CheckActivationCodeRegisterReq.fromJson(Map json) { +// patientMobileNumber = json['PatientMobileNumber']; +// mobileNo = json['MobileNo']; +// deviceToken = json['DeviceToken']; +// projectOutSA = json['ProjectOutSA']; +// loginType = json['LoginType']; +// zipCode = json['ZipCode']; +// isRegister = json['isRegister']; +// logInTokenID = json['LogInTokenID']; +// searchType = json['SearchType']; +// patientID = json['PatientID']; +// nationalID = json['NationalID']; +// patientIdentificationID = json['PatientIdentificationID']; +// activationCode = json['activationCode']; +// isSilentLogin = json['IsSilentLogin']; +// 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']; +// forRegisteration = json['ForRegisteration']; +// dob = json['DOB']; +// isHijri = json['IsHijri']; +// healthId = json['HealthId']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['PatientMobileNumber'] = this.patientMobileNumber; +// data['MobileNo'] = this.mobileNo; +// data['DeviceToken'] = this.deviceToken; +// data['ProjectOutSA'] = this.projectOutSA; +// data['LoginType'] = this.loginType; +// data['ZipCode'] = this.zipCode; +// data['isRegister'] = this.isRegister; +// data['LogInTokenID'] = this.logInTokenID; +// data['SearchType'] = this.searchType; +// data['PatientID'] = this.patientID; +// data['NationalID'] = this.nationalID; +// data['PatientIdentificationID'] = this.patientIdentificationID; +// data['activationCode'] = this.activationCode; +// data['IsSilentLogin'] = this.isSilentLogin; +// 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['ForRegisteration'] = this.forRegisteration; +// data['DOB'] = dob; +// data['IsHijri'] = isHijri; +// data['HealthId'] = healthId; +// return data; +// } +// } diff --git a/lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart b/lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart new file mode 100644 index 0000000..483e416 --- /dev/null +++ b/lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart @@ -0,0 +1,88 @@ +class CheckPatientAuthenticationReq { + int? patientMobileNumber; + String? zipCode; + bool? isRegister; + String? tokenID; + int? searchType; + String? patientIdentificationID; + int? patientID; + double? versionID; + int? channel; + int? languageID; + String? iPAdress; + String? generalid; + int? patientOutSA; + dynamic sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + String? dob; + int? isHijri; + String? healthId; + + CheckPatientAuthenticationReq( + {this.patientMobileNumber, + this.zipCode, + this.isRegister, + this.tokenID, + this.searchType, + this.patientIdentificationID, + this.patientID, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.dob, + this.isHijri, + this.healthId}); + + CheckPatientAuthenticationReq.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + tokenID = json['TokenID']; + searchType = json['SearchType']; + patientIdentificationID = json['PatientIdentificationID']; + patientID = json['PatientID']; + 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']; + dob = json['dob']; + isHijri = json['isHijri']; + healthId = json['HealthId']; + } + + Map toJson() { + final Map data = {}; + data['PatientMobileNumber'] = patientMobileNumber; + data['ZipCode'] = zipCode; + data['isRegister'] = isRegister; + data['TokenID'] = tokenID; + data['SearchType'] = searchType; + data['PatientIdentificationID'] = patientIdentificationID; + data['PatientID'] = patientID; + data['VersionID'] = versionID; + data['Channel'] = channel; + data['LanguageID'] = languageID; + data['IPAdress'] = iPAdress; + data['generalid'] = generalid; + data['PatientOutSA'] = patientOutSA; + data['SessionID'] = sessionID; + data['isDentalAllowedBackend'] = isDentalAllowedBackend; + data['DeviceTypeID'] = deviceTypeID; + data['dob'] = dob; + data['isHijri'] = isHijri; + data['HealthId'] = healthId; + return data; + } +} diff --git a/lib/features/authentication/models/request_models/send_activation_request_model.dart b/lib/features/authentication/models/request_models/send_activation_request_model.dart new file mode 100644 index 0000000..dc3d55d --- /dev/null +++ b/lib/features/authentication/models/request_models/send_activation_request_model.dart @@ -0,0 +1,132 @@ +class SendActivationRequest { + int? patientMobileNumber; + String? mobileNo; + String? deviceToken; + bool? projectOutSA; + int? loginType; + String? zipCode; + bool? isRegister; + String? logInTokenID; + int? searchType; + int? patientID; + String? nationalID; + String? patientIdentificationID; + int? oTPSendType; + int? languageID; + double? versionID; + int? channel; + String? iPAdress; + String? generalid; + int? patientOutSA; + dynamic sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + String? sMSSignature; + String? dob; + int? isHijri; + String? healthId; + int? responseID; + int? status; + int? familyRegionID; + bool? isPatientExcluded; + SendActivationRequest( + {this.patientMobileNumber, + this.mobileNo, + this.deviceToken, + this.projectOutSA, + this.loginType, + this.zipCode, + this.isRegister, + this.logInTokenID, + this.searchType, + this.patientID, + this.nationalID, + this.patientIdentificationID, + this.oTPSendType, + this.languageID, + this.versionID, + this.channel, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.sMSSignature, + this.dob, + this.isHijri, + this.healthId, + this.responseID, + this.status, + this.familyRegionID, + this.isPatientExcluded + }); + + SendActivationRequest.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + mobileNo = json['MobileNo']; + deviceToken = json['DeviceToken']; + projectOutSA = json['ProjectOutSA']; + loginType = json['LoginType']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + logInTokenID = json['LogInTokenID']; + searchType = json['SearchType']; + patientID = json['PatientID']; + nationalID = json['NationalID']; + patientIdentificationID = json['PatientIdentificationID']; + oTPSendType = json['OTP_SendType']; + languageID = json['LanguageID']; + versionID = json['VersionID']; + channel = json['Channel']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + sMSSignature = json['SMSSignature']; + dob = json['DOB']; + isHijri = json['IsHijri']; + healthId = json['HealthId']; + responseID = json['ReponseID']; + status = json['Status']; + familyRegionID = json['FamilyRegionID']; + isPatientExcluded = json['IsPatientExcluded']; + } + + Map toJson() { + final Map data = new Map(); + data['PatientMobileNumber'] = patientMobileNumber; + data['MobileNo'] = mobileNo; + data['DeviceToken'] = deviceToken; + data['ProjectOutSA'] = projectOutSA; + data['LoginType'] = loginType; + data['ZipCode'] = zipCode; + data['isRegister'] = isRegister; + data['LogInTokenID'] = logInTokenID; + data['SearchType'] = searchType; + data['PatientID'] = patientID; + data['NationalID'] = nationalID; + data['PatientIdentificationID'] = patientIdentificationID; + data['OTP_SendType'] = oTPSendType; + data['LanguageID'] = languageID; + data['VersionID'] = versionID; + data['Channel'] = channel; + data['IPAdress'] = iPAdress; + data['generalid'] = generalid; + data['PatientOutSA'] = patientOutSA; + data['SessionID'] = sessionID; + data['isDentalAllowedBackend'] = isDentalAllowedBackend; + data['DeviceTypeID'] = deviceTypeID; + data['SMSSignature'] = sMSSignature; + data['DOB'] = dob; + data['IsHijri'] = isHijri; + data['HealthId'] = healthId; + data['ResponseID'] = responseID; + data['Status'] = status; + data['FamilyRegionID'] = familyRegionID; + data['IsPatientExcluded'] = isPatientExcluded; + return data; + } +} diff --git a/lib/features/authentication/models/authenticated_user_model.dart b/lib/features/authentication/models/resp_models/authenticated_user_resp_model.dart similarity index 100% rename from lib/features/authentication/models/authenticated_user_model.dart rename to lib/features/authentication/models/resp_models/authenticated_user_resp_model.dart diff --git a/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart b/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart new file mode 100644 index 0000000..8610e08 --- /dev/null +++ b/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart @@ -0,0 +1,546 @@ +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; + +class CheckActivationCode { + dynamic date; + int? languageID; + int? serviceName; + dynamic time; + dynamic androidLink; + String? authenticationTokenID; + dynamic data; + bool? dataw; + int? dietType; + dynamic errorCode; + dynamic errorEndUserMessage; + dynamic errorEndUserMessageN; + dynamic errorMessage; + int? errorType; + int? foodCategory; + dynamic iOSLink; + bool? isAuthenticated; + int? mealOrderStatus; + int? mealType; + int? messageStatus; + int? numberOfResultRecords; + dynamic patientBlodType; + dynamic successMsg; + dynamic successMsgN; + dynamic doctorInformationList; + dynamic getAllPendingRecordsList; + dynamic getAllSharedRecordsByStatusList; + dynamic getResponseFileList; + bool? isHMGPatient; + bool? isLoginSuccessfully; + bool? isNeedUpdateIdintificationNo; + bool? kioskSendSMS; + AuthenticatedUser? list; + dynamic listAskHabibMobileLoginInfo; + dynamic listAskHabibPatientFile; + dynamic listMergeFiles; + dynamic listMobileLoginInfo; + dynamic listPatientCount; + dynamic logInTokenID; + dynamic mohemmPrivilegeList; + int? pateintID; + String? patientBloodType; + bool? patientHasFile; + dynamic patientMergedIDs; + bool? patientOutSA; + int? patientShareRequestID; + int? patientType; + int? projectIDOut; + dynamic returnMessage; + bool? sMSLoginRequired; + dynamic servicePrivilegeList; + dynamic sharePatientName; + dynamic verificationCode; + dynamic email; + dynamic errorList; + bool? hasFile; + bool? isActiveCode; + bool? isMerged; + bool? isNeedUserAgreement; + bool? isSMSSent; + dynamic memberList; + dynamic message; + int? statusCode; + + CheckActivationCode( + {this.date, + this.languageID, + this.serviceName, + this.time, + this.androidLink, + this.authenticationTokenID, + this.data, + this.dataw, + this.dietType, + this.errorCode, + this.errorEndUserMessage, + this.errorEndUserMessageN, + this.errorMessage, + this.errorType, + this.foodCategory, + this.iOSLink, + this.isAuthenticated, + this.mealOrderStatus, + this.mealType, + this.messageStatus, + this.numberOfResultRecords, + this.patientBlodType, + this.successMsg, + this.successMsgN, + this.doctorInformationList, + this.getAllPendingRecordsList, + this.getAllSharedRecordsByStatusList, + this.getResponseFileList, + this.isHMGPatient, + this.isLoginSuccessfully, + this.isNeedUpdateIdintificationNo, + this.kioskSendSMS, + this.list, + this.listAskHabibMobileLoginInfo, + this.listAskHabibPatientFile, + this.listMergeFiles, + this.listMobileLoginInfo, + this.listPatientCount, + this.logInTokenID, + this.mohemmPrivilegeList, + this.pateintID, + this.patientBloodType, + this.patientHasFile, + this.patientMergedIDs, + this.patientOutSA, + this.patientShareRequestID, + this.patientType, + this.projectIDOut, + this.returnMessage, + this.sMSLoginRequired, + this.servicePrivilegeList, + this.sharePatientName, + this.verificationCode, + this.email, + this.errorList, + this.hasFile, + this.isActiveCode, + this.isMerged, + this.isNeedUserAgreement, + this.isSMSSent, + this.memberList, + this.message, + this.statusCode}); + + CheckActivationCode.fromJson(Map json) { + date = json['Date']; + languageID = json['LanguageID']; + serviceName = json['ServiceName']; + time = json['Time']; + androidLink = json['AndroidLink']; + authenticationTokenID = json['AuthenticationTokenID']; + data = json['Data']; + dataw = json['Dataw']; + dietType = json['DietType']; + errorCode = json['ErrorCode']; + errorEndUserMessage = json['ErrorEndUserMessage']; + errorEndUserMessageN = json['ErrorEndUserMessageN']; + errorMessage = json['ErrorMessage']; + errorType = json['ErrorType']; + foodCategory = json['FoodCategory']; + iOSLink = json['IOSLink']; + isAuthenticated = json['IsAuthenticated']; + mealOrderStatus = json['MealOrderStatus']; + mealType = json['MealType']; + messageStatus = json['MessageStatus']; + numberOfResultRecords = json['NumberOfResultRecords']; + patientBlodType = json['PatientBlodType']; + successMsg = json['SuccessMsg']; + successMsgN = json['SuccessMsgN']; + doctorInformationList = json['DoctorInformation_List']; + getAllPendingRecordsList = json['GetAllPendingRecordsList']; + getAllSharedRecordsByStatusList = json['GetAllSharedRecordsByStatusList']; + getResponseFileList = json['GetResponseFileList']; + isHMGPatient = json['IsHMGPatient']; + isLoginSuccessfully = json['IsLoginSuccessfully']; + isNeedUpdateIdintificationNo = json['IsNeedUpdateIdintificationNo']; + kioskSendSMS = json['KioskSendSMS']; + if (json['List'] != null) { + list = AuthenticatedUser.fromJson(json['List'][0]); + } + listAskHabibMobileLoginInfo = json['List_AskHabibMobileLoginInfo']; + listAskHabibPatientFile = json['List_AskHabibPatientFile']; + listMergeFiles = json['List_MergeFiles']; + listMobileLoginInfo = json['List_MobileLoginInfo']; + listPatientCount = json['List_PatientCount']; + logInTokenID = json['LogInTokenID']; + mohemmPrivilegeList = json['MohemmPrivilege_List']; + pateintID = json['PateintID']; + patientBloodType = json['PatientBloodType']; + patientHasFile = json['PatientHasFile']; + patientMergedIDs = json['PatientMergedIDs']; + patientOutSA = json['PatientOutSA']; + patientShareRequestID = json['PatientShareRequestID']; + patientType = json['PatientType']; + projectIDOut = json['ProjectIDOut']; + returnMessage = json['ReturnMessage']; + sMSLoginRequired = json['SMSLoginRequired']; + servicePrivilegeList = json['ServicePrivilege_List']; + sharePatientName = json['SharePatientName']; + verificationCode = json['VerificationCode']; + email = json['email']; + errorList = json['errorList']; + hasFile = json['hasFile']; + isActiveCode = json['isActiveCode']; + isMerged = json['isMerged']; + isNeedUserAgreement = json['isNeedUserAgreement']; + isSMSSent = json['isSMSSent']; + memberList = json['memberList']; + message = json['message']; + statusCode = json['statusCode']; + } + + Map toJson() { + final Map data = {}; + data['Date'] = date; + data['LanguageID'] = languageID; + data['ServiceName'] = serviceName; + data['Time'] = time; + data['AndroidLink'] = androidLink; + data['AuthenticationTokenID'] = authenticationTokenID; + data['Data'] = this.data; + data['Dataw'] = dataw; + data['DietType'] = dietType; + data['ErrorCode'] = errorCode; + data['ErrorEndUserMessage'] = errorEndUserMessage; + data['ErrorEndUserMessageN'] = errorEndUserMessageN; + data['ErrorMessage'] = errorMessage; + data['ErrorType'] = errorType; + data['FoodCategory'] = foodCategory; + data['IOSLink'] = iOSLink; + data['IsAuthenticated'] = isAuthenticated; + data['MealOrderStatus'] = mealOrderStatus; + data['MealType'] = mealType; + data['MessageStatus'] = messageStatus; + data['NumberOfResultRecords'] = numberOfResultRecords; + data['PatientBlodType'] = patientBlodType; + data['SuccessMsg'] = successMsg; + data['SuccessMsgN'] = successMsgN; + data['DoctorInformation_List'] = doctorInformationList; + data['GetAllPendingRecordsList'] = getAllPendingRecordsList; + data['GetAllSharedRecordsByStatusList'] = getAllSharedRecordsByStatusList; + data['GetResponseFileList'] = getResponseFileList; + data['IsHMGPatient'] = isHMGPatient; + data['IsLoginSuccessfully'] = isLoginSuccessfully; + data['IsNeedUpdateIdintificationNo'] = isNeedUpdateIdintificationNo; + data['KioskSendSMS'] = kioskSendSMS; + if (list != null) { + data['List'] = list; + } + data['List_AskHabibMobileLoginInfo'] = listAskHabibMobileLoginInfo; + data['List_AskHabibPatientFile'] = listAskHabibPatientFile; + data['List_MergeFiles'] = listMergeFiles; + data['List_MobileLoginInfo'] = listMobileLoginInfo; + data['List_PatientCount'] = listPatientCount; + data['LogInTokenID'] = logInTokenID; + data['MohemmPrivilege_List'] = mohemmPrivilegeList; + data['PateintID'] = pateintID; + data['PatientBloodType'] = patientBloodType; + data['PatientHasFile'] = patientHasFile; + data['PatientMergedIDs'] = patientMergedIDs; + data['PatientOutSA'] = patientOutSA; + data['PatientShareRequestID'] = patientShareRequestID; + data['PatientType'] = patientType; + data['ProjectIDOut'] = projectIDOut; + data['ReturnMessage'] = returnMessage; + data['SMSLoginRequired'] = sMSLoginRequired; + data['ServicePrivilege_List'] = servicePrivilegeList; + data['SharePatientName'] = sharePatientName; + data['VerificationCode'] = verificationCode; + data['email'] = email; + data['errorList'] = errorList; + data['hasFile'] = hasFile; + data['isActiveCode'] = isActiveCode; + data['isMerged'] = isMerged; + data['isNeedUserAgreement'] = isNeedUserAgreement; + data['isSMSSent'] = isSMSSent; + data['memberList'] = memberList; + data['message'] = message; + data['statusCode'] = statusCode; + return data; + } +} + +class List { + String? setupID; + int? patientType; + int? patientID; + String? firstName; + String? middleName; + String? lastName; + String? firstNameN; + String? middleNameN; + String? lastNameN; + int? relationshipID; + int? gender; + String? dateofBirth; + dynamic dateofBirthN; + String? nationalityID; + dynamic phoneResi; + dynamic phoneOffice; + String? mobileNumber; + dynamic faxNumber; + String? emailAddress; + dynamic bloodGroup; + dynamic rHFactor; + bool? isEmailAlertRequired; + bool? isSMSAlertRequired; + String? preferredLanguage; + bool? isPrivilegedMember; + dynamic memberID; + dynamic expiryDate; + dynamic isHmgEmployee; + dynamic employeeID; + dynamic emergencyContactName; + dynamic emergencyContactNo; + int? patientPayType; + dynamic dHCCPatientRefID; + bool? isPatientDummy; + int? status; + dynamic isStatusCleared; + int? patientIdentificationType; + String? patientIdentificationNo; + int? projectID; + int? infoSourceID; + dynamic address; + int? age; + String? ageDesc; + int? areaID; + int? createdBy; + String? genderDescription; + dynamic iR; + dynamic iSOCityID; + dynamic iSOCountryID; + ListPrivilege? listPrivilege; + dynamic marital; + int? outSA; + dynamic pOBox; + bool? receiveHealthSummaryReport; + int? sourceType; + dynamic strDateofBirth; + dynamic tempAddress; + dynamic zipCode; + + List({ + this.setupID, + this.patientType, + this.patientID, + this.firstName, + this.middleName, + this.lastName, + this.firstNameN, + this.middleNameN, + this.lastNameN, + this.relationshipID, + this.gender, + this.dateofBirth, + this.dateofBirthN, + this.nationalityID, + this.phoneResi, + this.phoneOffice, + this.mobileNumber, + this.faxNumber, + this.emailAddress, + this.bloodGroup, + this.rHFactor, + this.isEmailAlertRequired, + this.isSMSAlertRequired, + this.preferredLanguage, + this.isPrivilegedMember, + this.memberID, + this.expiryDate, + this.isHmgEmployee, + this.employeeID, + this.emergencyContactName, + this.emergencyContactNo, + this.patientPayType, + this.dHCCPatientRefID, + this.isPatientDummy, + this.status, + this.isStatusCleared, + this.patientIdentificationType, + this.patientIdentificationNo, + this.projectID, + this.infoSourceID, + this.address, + this.age, + this.ageDesc, + this.areaID, + this.createdBy, + this.genderDescription, + this.iR, + this.iSOCityID, + this.iSOCountryID, + this.listPrivilege, + this.marital, + this.outSA, + this.pOBox, + this.receiveHealthSummaryReport, + this.sourceType, + this.strDateofBirth, + this.tempAddress, + this.zipCode, + }); + + List.fromJson(Map json) { + setupID = json['SetupID']; + patientType = json['PatientType']; + patientID = json['PatientID']; + firstName = json['FirstName']; + middleName = json['MiddleName']; + lastName = json['LastName']; + firstNameN = json['FirstNameN']; + middleNameN = json['MiddleNameN']; + lastNameN = json['LastNameN']; + relationshipID = json['RelationshipID']; + gender = json['Gender']; + dateofBirth = json['DateofBirth']; + dateofBirthN = json['DateofBirthN']; + nationalityID = json['NationalityID']; + phoneResi = json['PhoneResi']; + phoneOffice = json['PhoneOffice']; + mobileNumber = json['MobileNumber']; + faxNumber = json['FaxNumber']; + emailAddress = json['EmailAddress']; + bloodGroup = json['BloodGroup']; + rHFactor = json['RHFactor']; + isEmailAlertRequired = json['IsEmailAlertRequired']; + isSMSAlertRequired = json['IsSMSAlertRequired']; + preferredLanguage = json['PreferredLanguage']; + isPrivilegedMember = json['IsPrivilegedMember']; + memberID = json['MemberID']; + expiryDate = json['ExpiryDate']; + isHmgEmployee = json['IsHmgEmployee']; + employeeID = json['EmployeeID']; + emergencyContactName = json['EmergencyContactName']; + emergencyContactNo = json['EmergencyContactNo']; + patientPayType = json['PatientPayType']; + dHCCPatientRefID = json['DHCCPatientRefID']; + isPatientDummy = json['IsPatientDummy']; + status = json['Status']; + isStatusCleared = json['IsStatusCleared']; + patientIdentificationType = json['PatientIdentificationType']; + patientIdentificationNo = json['PatientIdentificationNo']; + projectID = json['ProjectID']; + infoSourceID = json['InfoSourceID']; + address = json['Address']; + age = json['Age']; + ageDesc = json['AgeDesc']; + areaID = json['AreaID']; + createdBy = json['CreatedBy']; + genderDescription = json['GenderDescription']; + iR = json['IR']; + iSOCityID = json['ISOCityID']; + iSOCountryID = json['ISOCountryID']; + if (json['ListPrivilege'] != null) { + listPrivilege = ListPrivilege.fromJson(json['ListPrivilege']); + } + marital = json['Marital']; + outSA = json['OutSA']; + pOBox = json['POBox']; + receiveHealthSummaryReport = json['ReceiveHealthSummaryReport']; + sourceType = json['SourceType']; + strDateofBirth = json['StrDateofBirth']; + tempAddress = json['TempAddress']; + zipCode = json['ZipCode']; + } + + Map toJson() { + final Map data = {}; + data['SetupID'] = setupID; + data['PatientType'] = patientType; + data['PatientID'] = patientID; + data['FirstName'] = firstName; + data['MiddleName'] = middleName; + data['LastName'] = lastName; + data['FirstNameN'] = firstNameN; + data['MiddleNameN'] = middleNameN; + data['LastNameN'] = lastNameN; + data['RelationshipID'] = relationshipID; + data['Gender'] = gender; + data['DateofBirth'] = dateofBirth; + data['DateofBirthN'] = dateofBirthN; + data['NationalityID'] = nationalityID; + data['PhoneResi'] = phoneResi; + data['PhoneOffice'] = phoneOffice; + data['MobileNumber'] = mobileNumber; + data['FaxNumber'] = faxNumber; + data['EmailAddress'] = emailAddress; + data['BloodGroup'] = bloodGroup; + data['RHFactor'] = rHFactor; + data['IsEmailAlertRequired'] = isEmailAlertRequired; + data['IsSMSAlertRequired'] = isSMSAlertRequired; + data['PreferredLanguage'] = preferredLanguage; + data['IsPrivilegedMember'] = isPrivilegedMember; + data['MemberID'] = memberID; + data['ExpiryDate'] = expiryDate; + data['IsHmgEmployee'] = isHmgEmployee; + data['EmployeeID'] = employeeID; + data['EmergencyContactName'] = emergencyContactName; + data['EmergencyContactNo'] = emergencyContactNo; + data['PatientPayType'] = patientPayType; + data['DHCCPatientRefID'] = dHCCPatientRefID; + data['IsPatientDummy'] = isPatientDummy; + data['Status'] = status; + data['IsStatusCleared'] = isStatusCleared; + data['PatientIdentificationType'] = patientIdentificationType; + data['PatientIdentificationNo'] = patientIdentificationNo; + data['ProjectID'] = projectID; + data['InfoSourceID'] = infoSourceID; + data['Address'] = address; + data['Age'] = age; + data['AgeDesc'] = ageDesc; + data['AreaID'] = areaID; + data['CreatedBy'] = createdBy; + data['GenderDescription'] = genderDescription; + data['IR'] = iR; + data['ISOCityID'] = iSOCityID; + data['ISOCountryID'] = iSOCountryID; + if (listPrivilege != null) { + data['ListPrivilege'] = listPrivilege; + } + data['Marital'] = marital; + data['OutSA'] = outSA; + data['POBox'] = pOBox; + data['ReceiveHealthSummaryReport'] = receiveHealthSummaryReport; + data['SourceType'] = sourceType; + data['StrDateofBirth'] = strDateofBirth; + data['TempAddress'] = tempAddress; + data['ZipCode'] = zipCode; + + return data; + } +} + +class ListPrivilege { + int? iD; + String? serviceName; + bool? previlege; + dynamic region; + + ListPrivilege({this.iD, this.serviceName, this.previlege, this.region}); + + ListPrivilege.fromJson(Map json) { + iD = json['ID']; + serviceName = json['ServiceName']; + previlege = json['Previlege']; + region = json['Region']; + } + + Map toJson() { + final Map data = {}; + data['ID'] = iD; + data['ServiceName'] = serviceName; + data['Previlege'] = previlege; + data['Region'] = region; + return data; + } +} diff --git a/lib/features/authentication/models/get_patient_last_login_details_response_model.dart b/lib/features/authentication/models/resp_models/get_patient_last_login_details_response_model.dart similarity index 100% rename from lib/features/authentication/models/get_patient_last_login_details_response_model.dart rename to lib/features/authentication/models/resp_models/get_patient_last_login_details_response_model.dart diff --git a/lib/features/authentication/models/select_device_by_imei.dart b/lib/features/authentication/models/resp_models/select_device_by_imei.dart similarity index 100% rename from lib/features/authentication/models/select_device_by_imei.dart rename to lib/features/authentication/models/resp_models/select_device_by_imei.dart diff --git a/lib/services/analytics/analytics_service.dart b/lib/services/analytics/analytics_service.dart index d4f83a4..3411157 100644 --- a/lib/services/analytics/analytics_service.dart +++ b/lib/services/analytics/analytics_service.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/services/analytics/flows/advance_payments.dart'; import 'package:hmg_patient_app_new/services/analytics/flows/app_nav.dart'; import 'package:hmg_patient_app_new/services/analytics/flows/appointments.dart'; diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index e931568..af5af9c 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; abstract class DialogService { - Future showErrorDialog(String message); + Future showErrorDialog({required String message, Function()? onOkPressed}); } class DialogServiceImp implements DialogService { @@ -11,7 +12,7 @@ class DialogServiceImp implements DialogService { DialogServiceImp({required this.navigationService}); @override - Future showErrorDialog(String message) async { + Future showErrorDialog({required String message, Function()? onOkPressed}) async { final context = navigationService.navigatorKey.currentContext; if (context == null) return; @@ -21,15 +22,16 @@ class DialogServiceImp implements DialogService { shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), - builder: (_) => _ErrorBottomSheet(message: message), + builder: (_) => _ErrorBottomSheet(message: message, onOkPressed: onOkPressed), ); } } class _ErrorBottomSheet extends StatelessWidget { final String message; + final Function()? onOkPressed; - const _ErrorBottomSheet({required this.message}); + const _ErrorBottomSheet({required this.message, this.onOkPressed}); @override Widget build(BuildContext context) { @@ -55,7 +57,13 @@ class _ErrorBottomSheet extends StatelessWidget { ), const SizedBox(height: 16), ElevatedButton( - onPressed: () => Navigator.of(context).pop(), + onPressed: () { + if (onOkPressed != null) { + onOkPressed!(); + } else { + context.pop(); + } + }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, shape: RoundedRectangleBorder( diff --git a/lib/services/error_handler_service.dart b/lib/services/error_handler_service.dart index d8d473a..a26d264 100644 --- a/lib/services/error_handler_service.dart +++ b/lib/services/error_handler_service.dart @@ -7,7 +7,7 @@ import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; abstract class ErrorHandlerService { - Future handleError(Failure failure); + Future handleError({required Failure failure, Function() onOkPressed}); } class ErrorHandlerServiceImp implements ErrorHandlerService { @@ -22,7 +22,7 @@ class ErrorHandlerServiceImp implements ErrorHandlerService { }); @override - Future handleError(Failure failure) async { + Future handleError({required Failure failure, Function()? onOkPressed}) async { if (failure is APIException) { loggerService.errorLogs("API Exception: ${failure.message}"); } else if (failure is ServerFailure) { @@ -31,6 +31,9 @@ class ErrorHandlerServiceImp implements ErrorHandlerService { } else if (failure is DataParsingFailure) { loggerService.errorLogs("Data Parsing Failure: ${failure.message}"); await _showDialog(failure, title: "Data Error"); + } else if (failure is StatusCodeFailure) { + loggerService.errorLogs("StatusCode Failure: ${failure.message}"); + await _showDialog(failure, title: "Status Code Failure Error"); } else if (failure is HttpException) { loggerService.errorLogs("Http Exception: ${failure.message}"); await _showDialog(failure, title: "Network Error"); @@ -46,7 +49,7 @@ class ErrorHandlerServiceImp implements ErrorHandlerService { } } - Future _showDialog(Failure failure, {String title = "Error"}) async { - await dialogService.showErrorDialog(failure.message); + Future _showDialog(Failure failure, {String title = "Error", Function()? onOkPressed}) async { + await dialogService.showErrorDialog(message: failure.message, onOkPressed: onOkPressed); } } diff --git a/lib/splashPage.dart b/lib/splashPage.dart index 85b2e80..bc3e542 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -16,8 +16,8 @@ import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; import 'core/consts.dart'; -import 'core/utils/LocalNotification.dart'; -import 'core/utils/push-notification-handler.dart'; +import 'core/utils/local_notifications.dart'; +import 'core/utils/push_notification_handler.dart'; class SplashPage extends StatefulWidget { @override diff --git a/lib/widgets/chip/custom_chip_widget.dart b/lib/widgets/chip/custom_chip_widget.dart index 9afb986..6c2f1e3 100644 --- a/lib/widgets/chip/custom_chip_widget.dart +++ b/lib/widgets/chip/custom_chip_widget.dart @@ -5,7 +5,7 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; class CustomChipWidget extends StatelessWidget { - final ChipType chipType; + final ChipTypeEnum chipType; final String chipText; final String? iconAsset; final VoidCallback? onTap; @@ -14,7 +14,7 @@ class CustomChipWidget extends StatelessWidget { final EdgeInsetsGeometry padding; const CustomChipWidget({ - Key? key, + super.key, required this.chipType, required this.chipText, this.iconAsset, @@ -22,7 +22,7 @@ class CustomChipWidget extends StatelessWidget { this.isSelected = false, this.borderRadius = 12, this.padding = const EdgeInsets.all(8), - }) : super(key: key); + }); @override Widget build(BuildContext context) { From c6a95fe7d72737c988be1909a6bd760fb9d6a75c Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Tue, 2 Sep 2025 15:18:03 +0300 Subject: [PATCH 10/10] latest push after master merged --- .../authentication_view_model.dart | 182 +++++++++--------- lib/presentation/home/landing_page.dart | 8 +- 2 files changed, 92 insertions(+), 98 deletions(-) diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 573c528..ed77aca 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -40,96 +40,96 @@ class AuthenticationViewModel extends ChangeNotifier { ); } - Future checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { - CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( - phoneNumber: '0567184134', - otpTypeEnum: OTPTypeEnum.sms, - deviceToken: 'dummyDeviceToken123', - patientOutSA: true, - loginTokenID: 'dummyLoginToken456', - registeredData: null, - patientId: 12345, - nationIdText: '1234567890', - countryCode: 'SA', - ); - - final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); - result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), - (apiResponse) { - if (apiResponse.data['isSMSSent']) { - // TODO: set this in AppState - // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); - // loginTokenID = value['LogInTokenID'], - // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), - sendActivationCode(type); - } else { - if (apiResponse.data['IsAuthenticated']) { - checkActivationCode(onWrongActivationCode: (String? message) {}); - } - } - }, - ); - } - - Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { - var request = RequestUtils.getCommonRequestAuthProvider( - otpTypeEnum: otpTypeEnum, - registeredData: null, - deviceToken: "dummyLoginToken456", - mobileNumber: "0567184134", - zipCode: "SA", - patientOutSA: true, - loginTokenID: "dummyLoginToken456", - selectedOption: selectedOption, - patientId: 12345, - ); + // Future checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { + // CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( + // phoneNumber: '0567184134', + // otpTypeEnum: OTPTypeEnum.sms, + // deviceToken: 'dummyDeviceToken123', + // patientOutSA: true, + // loginTokenID: 'dummyLoginToken456', + // registeredData: null, + // patientId: 12345, + // nationIdText: '1234567890', + // countryCode: 'SA', + // ); + // + // final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); + // result.fold( + // (failure) async => await errorHandlerService.handleError(failure: failure), + // (apiResponse) { + // if (apiResponse.data['isSMSSent']) { + // // TODO: set this in AppState + // // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); + // // loginTokenID = value['LogInTokenID'], + // // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + // sendActivationCode(type); + // } else { + // if (apiResponse.data['IsAuthenticated']) { + // checkActivationCode(onWrongActivationCode: (String? message) {}); + // } + // } + // }, + // ); + // } - request.sMSSignature = await SMSOTP.getSignature(); - selectedOption = type; - // GifLoaderDialogUtils.showMyDialog(context); - if (healthId != null || isDubai) { - if (!isDubai) { - request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); - } - request.healthId = healthId; - request.isHijri = isHijri; - await this.apiClient.sendActivationCodeRegister(request).then((result) { - // GifLoaderDialogUtils.hideDialog(context); - if (result != null && result['isSMSSent'] == true) { - this.startSMSService(type); - } - }).catchError((r) { - GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: r.toString(), - onOkPressed: () { - Navigator.of(context).pop(); - }, - )); - // AppToast.showErrorToast(message: r); - }); - } else { - request.dob = ""; - request.healthId = ""; - request.isHijri = 0; - await this.authService.sendActivationCode(request).then((result) { - GifLoaderDialogUtils.hideDialog(context); - if (result != null && result['isSMSSent'] == true) { - this.startSMSService(type); - } - }).catchError((r) { - GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: r.toString(), - onOkPressed: () { - Navigator.of(context).pop(); - }, - )); - // AppToast.showErrorToast(message: r.toString()); - }); - } - } + // Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { + // var request = RequestUtils.getCommonRequestAuthProvider( + // otpTypeEnum: otpTypeEnum, + // registeredData: null, + // deviceToken: "dummyLoginToken456", + // mobileNumber: "0567184134", + // zipCode: "SA", + // patientOutSA: true, + // loginTokenID: "dummyLoginToken456", + // selectedOption: selectedOption, + // patientId: 12345, + // ); + // + // request.sMSSignature = await SMSOTP.getSignature(); + // selectedOption = type; + // // GifLoaderDialogUtils.showMyDialog(context); + // if (healthId != null || isDubai) { + // if (!isDubai) { + // request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); + // } + // request.healthId = healthId; + // request.isHijri = isHijri; + // await this.apiClient.sendActivationCodeRegister(request).then((result) { + // // GifLoaderDialogUtils.hideDialog(context); + // if (result != null && result['isSMSSent'] == true) { + // this.startSMSService(type); + // } + // }).catchError((r) { + // GifLoaderDialogUtils.hideDialog(context); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: r.toString(), + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // )); + // // AppToast.showErrorToast(message: r); + // }); + // } else { + // request.dob = ""; + // request.healthId = ""; + // request.isHijri = 0; + // await this.authService.sendActivationCode(request).then((result) { + // GifLoaderDialogUtils.hideDialog(context); + // if (result != null && result['isSMSSent'] == true) { + // this.startSMSService(type); + // } + // }).catchError((r) { + // GifLoaderDialogUtils.hideDialog(context); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: r.toString(), + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // )); + // // AppToast.showErrorToast(message: r.toString()); + // }); + // } + // } } diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 27e95de..8421856 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -11,23 +11,17 @@ 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/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:hmg_patient_app_new/presentation/authantication/login.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; -import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.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/transitions/fade_page.dart'; import 'package:provider/provider.dart'; -import '../../core/app_assets.dart'; -import '../../core/utils/utils.dart'; -import '../../widgets/buttons/custom_button.dart'; -import '../../widgets/transitions/fade_page.dart'; - class LandingPage extends StatefulWidget { const LandingPage({super.key});