completed the deviceapi with new architecture

pull/3/head
faizatflutter 2 months ago
parent 89e9323d9e
commit 6bc7af00bc

@ -41,11 +41,20 @@ PODS:
- file_picker (0.0.1): - file_picker (0.0.1):
- DKImagePickerController/PhotoGallery - DKImagePickerController/PhotoGallery
- Flutter - Flutter
- Firebase/Analytics (11.15.0):
- Firebase/Core
- Firebase/Core (11.15.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 11.15.0)
- Firebase/CoreOnly (11.15.0): - Firebase/CoreOnly (11.15.0):
- FirebaseCore (~> 11.15.0) - FirebaseCore (~> 11.15.0)
- Firebase/Messaging (11.15.0): - Firebase/Messaging (11.15.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseMessaging (~> 11.15.0) - FirebaseMessaging (~> 11.15.0)
- firebase_analytics (11.6.0):
- Firebase/Analytics (= 11.15.0)
- firebase_core
- Flutter
- firebase_core (3.15.2): - firebase_core (3.15.2):
- Firebase/CoreOnly (= 11.15.0) - Firebase/CoreOnly (= 11.15.0)
- Flutter - Flutter
@ -53,6 +62,24 @@ PODS:
- Firebase/Messaging (= 11.15.0) - Firebase/Messaging (= 11.15.0)
- firebase_core - firebase_core
- Flutter - 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): - FirebaseCore (11.15.0):
- FirebaseCoreInternal (~> 11.15.0) - FirebaseCoreInternal (~> 11.15.0)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
@ -371,14 +398,16 @@ SPEC CHECKSUMS:
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
firebase_analytics: bf93e20703c95030404d6ddbb1adf05bf5c3885b
firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c
firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7
FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae
FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e
FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4
FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09
FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579 flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
@ -387,6 +416,8 @@ SPEC CHECKSUMS:
geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3 google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3
GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64
GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
@ -423,4 +454,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 5df9d8aa8f2c105eacd5ad7a310503d93c68c86b PODFILE CHECKSUM: 5df9d8aa8f2c105eacd5ad7a310503d93c68c86b
COCOAPODS: 1.15.2 COCOAPODS: 1.16.2

@ -2,21 +2,25 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.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/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/core/utils/utils.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.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:hmg_patient_app_new/services/logger_service.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../exceptions/api_failure.dart';
abstract class ApiClient { abstract class ApiClient {
Future<void> post( Future<void> post(
String endPoint, { String endPoint, {
required Map<String, dynamic> body, required Map<String, dynamic> body,
required Function(dynamic response, int statusCode) onSuccess, required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess,
required Function(String error, int statusCode) onFailure, required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
bool isAllowAny, bool isAllowAny,
bool isExternal, bool isExternal,
bool isRCService, bool isRCService,
@ -32,61 +36,69 @@ abstract class ApiClient {
bool isRCService, bool isRCService,
}); });
Future<void> simplePost(
String fullUrl, {
required Map<dynamic, dynamic> body,
required Map<String, String> headers,
required Function(dynamic response, int statusCode) onSuccess,
required Function(String error, int statusCode) onFailure,
});
Future<void> simpleGet(
String fullUrl, {
Function(dynamic response, int statusCode)? onSuccess,
Function(String error, int statusCode)? onFailure,
Map<String, dynamic>? queryParams,
Map<String, String>? headers,
});
Future<void> simplePut(
String fullUrl, {
Map<String, dynamic>? body,
Map<String, String>? headers,
Function(dynamic response, int statusCode)? onSuccess,
Function(String error, int statusCode)? onFailure,
});
Future<void> simpleDelete(
String fullUrl, {
Function(dynamic response, int statusCode)? onSuccess,
Function(String error, int statusCode)? onFailure,
Map<String, String>? queryParams,
Map<String, String>? headers,
});
Future<bool> handleUnauthorized(int statusCode, {required String forUrl});
String getSessionId(String id); String getSessionId(String id);
Future<String> generatePackagesToken(); // Future<void> simplePost(
// String fullUrl, {
// required Map<dynamic, dynamic> body,
// required Map<String, String> headers,
// required Function(dynamic response, int statusCode) onSuccess,
// required Function(String error, int statusCode) onFailure,
// });
//
// Future<void> simpleGet(
// String fullUrl, {
// Function(dynamic response, int statusCode)? onSuccess,
// Function(String error, int statusCode)? onFailure,
// Map<String, dynamic>? queryParams,
// Map<String, String>? headers,
// });
//
// Future<void> simplePut(
// String fullUrl, {
// Map<String, dynamic>? body,
// Map<String, String>? headers,
// Function(dynamic response, int statusCode)? onSuccess,
// Function(String error, int statusCode)? onFailure,
// });
//
// Future<void> simpleDelete(
// String fullUrl, {
// Function(dynamic response, int statusCode)? onSuccess,
// Function(String error, int statusCode)? onFailure,
// Map<String, String>? queryParams,
// Map<String, String>? headers,
// });
// Future<bool> handleUnauthorized(int statusCode, {required String forUrl});
// Future<String> generatePackagesToken();
} }
class ApiClientImp implements ApiClient { class ApiClientImp implements ApiClient {
final _analytics = getIt<GAnalytics>(); final _analytics = getIt<GAnalytics>();
final LoggerService loggerService; final LoggerService loggerService;
final AppState appState;
final DialogService dialogService;
ApiClientImp({required this.loggerService}); ApiClientImp({
required this.loggerService,
required this.dialogService,
required this.appState,
});
@override @override
post(String endPoint, post(
{required Map<String, dynamic> body, String endPoint, {
required Function(dynamic response, int statusCode) onSuccess, required Map<String, dynamic> body,
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 = false, bool isAllowAny = false,
bool isExternal = false, bool isExternal = false,
bool isRCService = false, bool isRCService = false,
bool bypassConnectionCheck = false}) async { bool bypassConnectionCheck = false,
}) async {
AppState appState = getIt.get<AppState>(); AppState appState = getIt.get<AppState>();
String url; String url;
if (isExternal) { if (isExternal) {
@ -103,7 +115,7 @@ class ApiClientImp implements ApiClient {
Map<String, String> headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; Map<String, String> headers = {'Content-Type': 'application/json', 'Accept': 'application/json'};
if (!isExternal) { if (!isExternal) {
String? token = appState.appAuthToken; 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) { if (endPoint == ApiConsts.sendActivationCode) {
languageID = 'en'; languageID = 'en';
} }
@ -113,7 +125,6 @@ class ApiClientImp implements ApiClient {
if (body.containsKey('LanguageID')) { if (body.containsKey('LanguageID')) {
if (body['LanguageID'] != null) { if (body['LanguageID'] != null) {
//change this line because language issue happened on dental
body['LanguageID'] = body['LanguageID'] == 'ar' body['LanguageID'] = body['LanguageID'] == 'ar'
? 1 ? 1
: body['LanguageID'] == 'en' : body['LanguageID'] == 'en'
@ -128,7 +139,6 @@ class ApiClientImp implements ApiClient {
: IS_DENTAL_ALLOWED_BACKEND; : IS_DENTAL_ALLOWED_BACKEND;
} }
//Todo: I have converted it to string //Todo: I have converted it to string
body['DeviceTypeID'] = Platform.isIOS body['DeviceTypeID'] = Platform.isIOS
? "1" ? "1"
@ -160,7 +170,6 @@ class ApiClientImp implements ApiClient {
} }
} }
body['LanguageID'] = body['LanguageID'] ?? "2"; body['LanguageID'] = body['LanguageID'] ?? "2";
body['VersionID'] = body['VersionID'] ?? "18.7"; body['VersionID'] = body['VersionID'] ?? "18.7";
body['Channel'] = body['Channel'] ?? "3"; body['Channel'] = body['Channel'] ?? "3";
@ -169,22 +178,21 @@ class ApiClientImp implements ApiClient {
body['Latitude'] = body['Latitude'] ?? "0.0"; body['Latitude'] = body['Latitude'] ?? "0.0";
body['Longitude'] = body['Longitude'] ?? "0.0"; body['Longitude'] = body['Longitude'] ?? "0.0";
body['DeviceTypeID'] = body['DeviceTypeID'] ?? body['DeviceTypeID'] = body['DeviceTypeID'] ??
(Platform.isIOS
? "1"
(Platform.isIOS ? "1" : await Utils.isGoogleServicesAvailable() ? "2" : "3"); : await Utils.isGoogleServicesAvailable()
//"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} ? "2"
: "3");
body.removeWhere((key, value) => value == null); body.removeWhere((key, value) => value == null);
log("body: ${json.encode(body)}");
log("bodi: ${json.encode(body)}"); log("uri: ${Uri.parse(url.trim())}");
log("bodi: ${Uri.parse(url.trim())}");
if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) { if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) {
final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers);
final int statusCode = response.statusCode; final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode >= 400) { 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); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode);
} else { } else {
var parsed = json.decode(utf8.decode(response.bodyBytes)); var parsed = json.decode(utf8.decode(response.bodyBytes));
@ -193,7 +201,7 @@ class ApiClientImp implements ApiClient {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode);
} else { } else {
if (parsed['Response_Message'] != null) { if (parsed['Response_Message'] != null) {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else { } else {
if (parsed['ErrorType'] == 4) { if (parsed['ErrorType'] == 4) {
//TODO : handle app update //TODO : handle app update
@ -204,19 +212,18 @@ class ApiClientImp implements ApiClient {
logApiEndpointError(endPoint, "session logged out", statusCode); logApiEndpointError(endPoint, "session logged out", statusCode);
} }
if (isAllowAny) { if (isAllowAny) {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else if (parsed['IsAuthenticated'] == null) { } else if (parsed['IsAuthenticated'] == null) {
if (parsed['isSMSSent'] == true) { if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else if (parsed['MessageStatus'] == 1) { } else if (parsed['MessageStatus'] == 1) {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode);
} else if (parsed['Result'] == 'OK') { } else if (parsed['Result'] == 'OK') {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode);
} else { } 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); 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); onSuccess(parsed, statusCode);
@ -226,28 +233,46 @@ class ApiClientImp implements ApiClient {
} else { } else {
if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
if (parsed['ErrorSearchMsg'] == 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); logApiEndpointError(endPoint, "Server Error found with no available message", statusCode);
} else { } else {
onFailure(parsed['ErrorSearchMsg'], statusCode); onFailure(
parsed['ErrorSearchMsg'],
statusCode,
failureType: ServerFailure("Error While Fetching data"),
);
logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode);
} }
} else { } 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); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
} }
} }
} } else {
else {
if (parsed['SameClinicApptList'] != null) { if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode); onSuccess(parsed, statusCode);
} else { } else {
if (parsed['message'] != null) { 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); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
} else { } 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); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
} }
} }
@ -256,13 +281,17 @@ class ApiClientImp implements ApiClient {
} }
} }
} else { } 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"); _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
} }
} catch (e) { } catch (e) {
loggerService.errorLogs(e.toString()); loggerService.errorLogs(e.toString());
if (e.toString().contains("ClientException")) { 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"); _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
} else { } else {
onFailure(e.toString(), -1); onFailure(e.toString(), -1);
@ -271,6 +300,7 @@ class ApiClientImp implements ApiClient {
} }
} }
@override
get(String endPoint, get(String endPoint,
{required Function(dynamic response, int statusCode) onSuccess, {required Function(dynamic response, int statusCode) onSuccess,
required Function(String error, int statusCode) onFailure, required Function(String error, int statusCode) onFailure,
@ -304,203 +334,173 @@ class ApiClientImp implements ApiClient {
// print("statusCode :$statusCode"); // print("statusCode :$statusCode");
if (statusCode < 200 || statusCode >= 400) { if (statusCode < 200 || statusCode >= 400) {
onFailure!('Error While Fetching data', statusCode); onFailure('Error While Fetching data', statusCode);
logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode);
} else { } else {
var parsed = json.decode(utf8.decode(response.bodyBytes)); var parsed = json.decode(utf8.decode(response.bodyBytes));
onSuccess!(parsed, statusCode); 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<dynamic, dynamic> body,
required Map<String, String> 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<String, dynamic>? queryParams,
Map<String, String>? 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<String, dynamic>? body,
Map<String, String>? 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<String, String>? queryParams,
Map<String, String>? 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 { } else {
onFailure!('Please Check The Internet Connection', -1); 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<bool> handleUnauthorized(int statusCode, {required String forUrl}) async { // @override
if (forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { // simplePost(
final token = await generatePackagesToken(); // String fullUrl, {
ApiConsts.packagesAuthHeader['Authorization'] = 'Bearer $token'; // required Map<dynamic, dynamic> body,
return (token is String); // required Map<String, String> headers,
} // required Function(dynamic response, int statusCode) onSuccess,
return false; // 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<String, dynamic>? queryParams,
// Map<String, String>? 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<String, dynamic>? body,
// Map<String, String>? 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<String, String>? queryParams,
// Map<String, String>? 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) { String getSessionId(String id) {
return id.replaceAll(RegExp('/[^a-zA-Z]'), ''); return id.replaceAll(RegExp('/[^a-zA-Z]'), '');
} }
Future<String> 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) { logApiFullUrlError(String fullUrl, error, code) {
final endpoint = Uri.parse(fullUrl).pathSegments.last; final endpoint = Uri.parse(fullUrl).pathSegments.last;
logApiEndpointError(endpoint, error, code); logApiEndpointError(endpoint, error, code);

@ -1,15 +1,14 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:hmg_patient_app_new/core/post_params_model.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/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; import 'api_consts.dart' as ApiConsts;
class AppState { class AppState {
// Simple constructor - let get_it handle the singleton behavior NavigationService navigationService;
AppState();
AppState({required this.navigationService});
bool isAuthenticated = true; bool isAuthenticated = true;
@ -40,9 +39,7 @@ class AppState {
PostParamsModel? get postParamsObject => _postParams; PostParamsModel? get postParamsObject => _postParams;
Map<String, dynamic> get postParamsJson => isAuthenticated Map<String, dynamic> get postParamsJson => isAuthenticated ? (_postParams?.toJsonAfterLogin() ?? {}) : (_postParams?.toJson() ?? {});
? (_postParams?.toJsonAfterLogin() ?? {})
: (_postParams?.toJson() ?? {});
void setPostParamsModel(PostParamsModel _postParams) { void setPostParamsModel(PostParamsModel _postParams) {
this._postParams = _postParams; this._postParams = _postParams;
@ -51,12 +48,9 @@ class AppState {
double userLat = 0.0; double userLat = 0.0;
double userLong = 0.0; double userLong = 0.0;
bool isArabic() => bool isArabic() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar";
EasyLocalization.of(navigatorKey.currentContext!)?.locale.languageCode ==
"ar";
int getLanguageID(context) => int getLanguageID(context) => EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2;
EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2;
AuthenticatedUser? _authenticatedUser; AuthenticatedUser? _authenticatedUser;

@ -0,0 +1,34 @@
class GenericApiModel<T> {
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<String, dynamic> json,
T Function(Object? json)? fromJsonT,
) {
return GenericApiModel<T>(
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<String, dynamic> toJson(Object Function(T value)? toJsonT) {
return {
'messageStatus': messageStatus,
'errorMessage': errorMessage,
'statusCode': statusCode,
'data': toJsonT != null && data != null ? toJsonT(data as T) : data,
};
}
}

@ -1,13 +1,18 @@
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/app_state.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_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/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/common/common_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/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/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/cache_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/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:logger/web.dart'; import 'package:logger/web.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -15,25 +20,58 @@ GetIt getIt = GetIt.instance;
class AppDependencies { class AppDependencies {
static Future<void> addDependencies() async { static Future<void> addDependencies() async {
// Services Logger logger = Logger(
getIt.registerLazySingleton<LoggerService>(() => LoggerServiceImp(logger: Logger(printer: PrettyPrinter( printer: PrettyPrinter(
methodCount: 2, // number of stack trace lines methodCount: 2,
errorMethodCount: 5, // number of stack trace lines for errors errorMethodCount: 5,
lineLength: 100, // wrap width lineLength: 100,
colors: true, // colorful logs colors: true,
printEmojis: true, // include emojis printEmojis: true,
),))); ),
);
// Core Services
getIt.registerLazySingleton<LoggerService>(() => LoggerServiceImp(logger: logger));
getIt.registerLazySingleton<NavigationService>(() => NavigationService());
getIt.registerLazySingleton<GAnalytics>(() => GAnalytics());
getIt.registerLazySingleton<AppState>(() => AppState(navigationService: getIt()));
getIt.registerLazySingleton<LocationUtils>(() => LocationUtils(isShowConfirmDialog: false, navigationService: getIt()));
getIt.registerLazySingleton<DialogService>(() => DialogServiceImp(navigationService: getIt<NavigationService>()));
getIt.registerLazySingleton<ErrorHandlerService>(() => ErrorHandlerServiceImp(
dialogService: getIt(),
loggerService: getIt(),
navigationService: getIt(),
));
final sharedPreferences = await SharedPreferences.getInstance(); final sharedPreferences = await SharedPreferences.getInstance();
getIt.registerLazySingleton<CacheService>(() => CacheServiceImp(sharedPreferences: sharedPreferences)); getIt.registerLazySingleton<CacheService>(() => CacheServiceImp(sharedPreferences: sharedPreferences));
getIt.registerSingleton(AppState()); getIt.registerLazySingleton<ApiClient>(() => ApiClientImp(loggerService: getIt(), dialogService: getIt(), appState: getIt()));
getIt.registerSingleton(GAnalytics());
getIt.registerLazySingleton<ApiClient>(() => ApiClientImp(loggerService: getIt()));
// Repositories // Repositories
getIt.registerLazySingleton<CommonRepo>(() => CommonRepoImp(loggerService: getIt())); getIt.registerLazySingleton<CommonRepo>(() => CommonRepoImp(loggerService: getIt()));
getIt.registerLazySingleton<AuthenticationRepo>(() => AuthenticationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<AuthenticationRepo>(() => AuthenticationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<BookAppointmentsRepo>(() => BookAppointmentsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<BookAppointmentsRepo>(
() => BookAppointmentsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MyAppointmentsRepo>(() => MyAppointmentsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<MyAppointmentsRepo>(() => MyAppointmentsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
dialogService: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
),
);
// Screen-specific VMs Factory
// getIt.registerFactory<BookAppointmentsViewModel>(
// () => BookAppointmentsViewModel(
// bookAppointmentsRepo: getIt(),
// dialogService: getIt(),
// errorHandlerService: getIt(),
// ),
// );
} }
} }

@ -1,8 +1,8 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
abstract class Failure extends Equatable implements Exception { abstract class Failure extends Equatable implements Exception {
final String message; final String message;
const Failure(this.message); const Failure(this.message);
} }
@ -27,15 +27,30 @@ class LocalStorageFailure extends Failure {
List<Object?> get props => [message]; List<Object?> get props => [message];
} }
class DataParsingFailure extends Failure {
const DataParsingFailure(super.message);
@override
List<Object?> get props => [message];
}
class UnknownFailure extends Failure {
const UnknownFailure(super.message);
@override
List<Object?> get props => [message];
}
class DuplicateUsername extends Failure { class DuplicateUsername extends Failure {
const DuplicateUsername({String? message}) : super(message ?? ''); const DuplicateUsername(String? message) : super(message ?? '');
@override @override
List<Object?> get props => [message]; List<Object?> get props => [message];
} }
class InvalidCredentials extends Failure { class InvalidCredentials extends Failure {
const InvalidCredentials({String? message}) : super(message ?? ''); const InvalidCredentials(String? message) : super(message ?? '');
@override @override
List<Object?> get props => [message]; List<Object?> get props => [message];

@ -1,41 +1,40 @@
import 'dart:io'; 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/app_state.dart';
import 'package:hmg_patient_app_new/core/consts.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/core/utils/utils.dart';
import 'package:flutter/cupertino.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
// import 'package:huawei_location/huawei_location.dart'; // import 'package:huawei_location/huawei_location.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
class LocationUtils { class LocationUtils {
NavigationService navigationService;
bool isShowConfirmDialog; bool isShowConfirmDialog;
bool isShowLocationTimeoutDialog; bool isShowLocationTimeoutDialog;
BuildContext context;
bool isHuawei; bool isHuawei;
final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance; 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<AppState>();
void getCurrentLocation({Function(LatLng)? callBack}) async { void getCurrentLocation({Function(LatLng)? callBack}) async {
Geolocator.isLocationServiceEnabled().then((value) async { Geolocator.isLocationServiceEnabled().then((value) async {
if (value) { if (value) {
await Geolocator.checkPermission().then((permission) async { await Geolocator.checkPermission().then((permission) async {
if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) { if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) {
// Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) {
Geolocator.getLastKnownPosition().then((value) { Geolocator.getLastKnownPosition().then((value) {
setLocation(value); setLocation(value);
if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709)); if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709));
}).catchError((err) { }).catchError((err) {
print(err); if (isShowConfirmDialog && isShowLocationTimeoutDialog) {}
if (isShowConfirmDialog && isShowLocationTimeoutDialog) {
// showLocationTimeOutDialog(failureCallBack: () {
// Geolocator.openAppSettings();
// });
}
}); });
} }
@ -62,15 +61,11 @@ class LocationUtils {
} }
} }
} }
}).catchError((err) { }).catchError((err) {});
print(err);
});
} else { } else {
if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {}); if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
} }
}).catchError((err) { }).catchError((err) {});
print(err);
});
} }
Future<bool> checkIfGPSIsEnabled() async { Future<bool> checkIfGPSIsEnabled() async {
@ -151,8 +146,8 @@ class LocationUtils {
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.latitude ?? 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.latitude ?? 0.0);
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.longitude ?? 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.longitude ?? 0.0);
AppState().setUserLat = position?.latitude ?? 0.0; appState.setUserLat = position?.latitude ?? 0.0;
AppState().setUserLong = position?.longitude ?? 0.0; appState.setUserLong = position?.longitude ?? 0.0;
// projectViewModel.setLatitudeLongitude(position?.latitude ?? 0.0, 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);
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0);
AppState().setUserLat = 0.0; appState.setUserLat = 0.0;
AppState().setUserLong = 0.0; appState.setUserLong = 0.0;
} }
Future<bool> requestPermissions() async { Future<bool> requestPermissions() async {

@ -1,24 +1,28 @@
import 'dart:convert'; import 'dart:convert';
import 'package:crypto/crypto.dart' as crypto;
import 'package:connectivity_plus/connectivity_plus.dart'; 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:google_api_availability/google_api_availability.dart';
import 'package:hmg_patient_app_new/core/app_state.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/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_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/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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart'; import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart';
import 'package:hmg_patient_app_new/widgets/loading_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:lottie/lottie.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
class Utils { class Utils {
static AppState appState = getIt.get<AppState>();
static NavigationService navigationService = getIt.get<NavigationService>();
static bool _isLoadingVisible = false; static bool _isLoadingVisible = false;
static bool get isLoading => _isLoadingVisible; static bool get isLoading => _isLoadingVisible;
@ -47,14 +51,16 @@ class Utils {
} }
static String getFreeSlotsTimeText(String startTime, {bool isAddHours = false}) { 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( // Duration(
// hours: isAddHours ? 3 : 0, // hours: isAddHours ? 3 : 0,
// ), // ),
// )); // ));
return !isAddHours 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")
: DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( .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( Duration(
hours: isAddHours ? 3 : 0, hours: isAddHours ? 3 : 0,
), ),
@ -82,12 +88,9 @@ class Utils {
} }
static String getMonthDayYearDateFormatted(DateTime dateTime) { static String getMonthDayYearDateFormatted(DateTime dateTime) {
if (dateTime != null) return appState.isArabic()
return AppState().isArabic()
? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString() ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString()
: getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString();
else
return "";
} }
/// get month by /// get month by
@ -200,7 +203,7 @@ class Utils {
static void showLoadingDialog() { static void showLoadingDialog() {
_isLoadingVisible = true; _isLoadingVisible = true;
showDialog( showDialog(
context: navigatorKey.currentContext!, context: navigationService.navigatorKey.currentContext!,
barrierColor: Colors.black.withOpacity(0.5), barrierColor: Colors.black.withOpacity(0.5),
builder: (BuildContext context) => LoadingDialog(), builder: (BuildContext context) => LoadingDialog(),
) )
@ -217,7 +220,7 @@ class Utils {
try { try {
if (_isLoadingVisible) { if (_isLoadingVisible) {
_isLoadingVisible = false; _isLoadingVisible = false;
Navigator.of(navigatorKey.currentContext!).pop(); Navigator.of(navigationService.navigatorKey.currentContext!).pop();
} }
_isLoadingVisible = false; _isLoadingVisible = false;
} catch (e) {} } catch (e) {}
@ -242,9 +245,6 @@ class Utils {
static bool isSAUDIIDValid(String id, type) { static bool isSAUDIIDValid(String id, type) {
if (type == 1) { if (type == 1) {
if (id == null) {
return false;
}
try { try {
id = id.toString(); id = id.toString();
id = id.trim(); id = id.trim();
@ -304,13 +304,15 @@ class Utils {
} }
static String removeHtmlTags(String htmlString) { static String removeHtmlTags(String htmlString) {
if (htmlString == null || htmlString.isEmpty) { if (htmlString.isEmpty) {
return ''; return '';
} }
// Replace HTML line breaks with newlines // Replace HTML line breaks with newlines
var withLineBreaks = var withLineBreaks = htmlString
htmlString.replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'<divider>', multiLine: true), '\n'); .replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n')
.replaceAll(RegExp(r'<\/p>', multiLine: true), '\n')
.replaceAll(RegExp(r'<divider>', multiLine: true), '\n');
// Remove all other HTML tags // Remove all other HTML tags
var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), ''); var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), '');
@ -376,7 +378,20 @@ class Utils {
final year = parts[0]; final year = parts[0];
// Map month number to short month name (Hijri months) // 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 monthIndex = int.tryParse(parts[1]) ?? 1;
final month = hijriMonthNames[monthIndex - 1]; final month = hijriMonthNames[monthIndex - 1];
@ -458,13 +473,8 @@ class Utils {
); );
} }
static Future<bool> isGoogleServicesAvailable() async { static Future<bool> isGoogleServicesAvailable() async {
GooglePlayServicesAvailability availability = await GoogleApiAvailability GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
.instance
.checkGooglePlayServicesAvailability();
String status = availability.toString().split('.').last; String status = availability.toString().split('.').last;
if (status == "success") { if (status == "success") {
return true; return true;
@ -472,26 +482,17 @@ class Utils {
return false; return false;
} }
static Future<bool> checkConnection({bool bypassConnectionCheck = false}) async {
static Future<bool> checkConnection(
{bool bypassConnectionCheck = false}) async {
if (bypassConnectionCheck) return true; if (bypassConnectionCheck) return true;
List<ConnectivityResult> connectivityResult = List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
await (Connectivity().checkConnectivity()); if (connectivityResult.contains(ConnectivityResult.mobile) || connectivityResult.contains(ConnectivityResult.wifi)) {
if (connectivityResult.contains(ConnectivityResult.mobile) ||
connectivityResult.contains(ConnectivityResult.wifi)) {
return true; return true;
} else { } else {
return false; return false;
} }
} }
static String generateMd5Hash(String input) { static String generateMd5Hash(String input) {
return crypto.md5.convert(utf8.encode(input)).toString(); return crypto.md5.convert(utf8.encode(input)).toString();
} }
} }

@ -1,16 +1,15 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.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/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/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/select_device_by_imei.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class AuthenticationRepo { abstract class AuthenticationRepo {
Future<Either<Failure, SelectDeviceByImeiRespModelElement?>> selectDeviceByImei({required String firebaseToken}); Future<Either<Failure, GenericApiModel<SelectDeviceByImeiRespModelElement>>> selectDeviceByImei({required String firebaseToken});
} }
class AuthenticationRepoImp implements AuthenticationRepo { class AuthenticationRepoImp implements AuthenticationRepo {
@ -20,38 +19,43 @@ class AuthenticationRepoImp implements AuthenticationRepo {
AuthenticationRepoImp({required this.loggerService, required this.apiClient}); AuthenticationRepoImp({required this.loggerService, required this.apiClient});
@override @override
Future<Either<Failure, SelectDeviceByImeiRespModelElement?>> selectDeviceByImei({ Future<Either<Failure, GenericApiModel<SelectDeviceByImeiRespModelElement>>> selectDeviceByImei({
required String firebaseToken, required String firebaseToken,
}) async { }) async {
final mapDevice = {"IMEI": firebaseToken}; final mapDevice = {"IMEI": firebaseToken};
try { try {
GenericApiModel<SelectDeviceByImeiRespModelElement>? apiResponse;
final completer = Completer<Either<Failure, SelectDeviceByImeiRespModelElement?>>(); Failure? failure;
await apiClient.post( await apiClient.post(
ApiConsts.selectDeviceImei, ApiConsts.selectDeviceImei,
body: mapDevice, body: mapDevice,
onSuccess: (response, statusCode) { onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
try { try {
final SelectDeviceByImeiRespModelElement model = final list = response['Patient_SELECTDeviceIMEIbyIMEIList'] as List<dynamic>?;
SelectDeviceByImeiRespModelElement.fromJson(response['Patient_SELECTDeviceIMEIbyIMEIList'][0]); if (list == null || list.isEmpty) {
completer.complete(Right(model)); throw Exception("Device list is empty");
}
final model = SelectDeviceByImeiRespModelElement.fromJson(list[0] as Map<String, dynamic>);
apiResponse = GenericApiModel<SelectDeviceByImeiRespModelElement>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: model,
);
} catch (e) { } catch (e) {
completer.complete(Left(ServerFailure(e.toString()))); failure = DataParsingFailure(e.toString());
} }
}, },
onFailure: (error, statusCode) {
loggerService.logInfo(("$error - $statusCode").toString());
completer.complete(Left(ServerFailure(error)));
},
); );
if (failure != null) return Left(failure!);
return await completer.future; if (apiResponse == null) return Left(ServerFailure("Unknown error"));
} on APIException catch (e) { return Right(apiResponse!);
loggerService.errorLogs(e.toString());
return Left(ServerFailure(e.message));
} catch (e) { } catch (e) {
loggerService.errorLogs(e.toString()); return Left(UnknownFailure(e.toString()));
return Left(ServerFailure(e.toString()));
} }
} }
} }

@ -1,46 +1,37 @@
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart'; 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/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/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 { class AuthenticationViewModel extends ChangeNotifier {
AuthenticationRepo authenticationRepo; AuthenticationRepo authenticationRepo;
AppState appState; AppState appState;
ErrorHandlerService errorHandlerService;
DialogService dialogService;
AuthenticationViewModel({ AuthenticationViewModel({
required this.appState, required this.appState,
required this.authenticationRepo, required this.authenticationRepo,
required this.errorHandlerService,
required this.dialogService,
}); });
final TextEditingController nationalIdController = TextEditingController(); final TextEditingController nationalIdController = TextEditingController();
final TextEditingController phoneNumberController = TextEditingController(); final TextEditingController phoneNumberController = TextEditingController();
Future<void> selectDeviceImei({ Future<void> selectDeviceImei({Function(dynamic)? onSuccess, Function(String)? onError}) async {
Function(dynamic)? onSuccess, String firebaseToken =
Function(String)? onError "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc";
}) async { final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken);
final String firebaseToken = result.fold(
"cIkkB7h7Q7uoFkC4Qv82xG:APA91bEb53Z9XzqymCIctaLxCoMX6bm9fuKlWILQ59uUqfwhCoD42AOP1-jWGB1WYd9BVN5PT2pUUFxrT07vcNg1KH9OH39mrPgCl0m21XVIgWrzNnCkufg"; (failure) async => await errorHandlerService.handleError(failure),
(apiResponse) {
final resultEither = if (apiResponse.messageStatus == 2) {
await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); dialogService.showErrorDialog(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
resultEither.fold( // move to next api call
(failure) { }
notifyListeners();
if (onError != null) onError(failure.message);
},
(data) {
log("resultEither: ${data.toString()} ");
notifyListeners();
if (onSuccess != null) onSuccess(data);
}, },
); );
} }

@ -1,61 +1,57 @@
// To parse this JSON data, do
//
// final selectDeviceByImeiRespModel = selectDeviceByImeiRespModelFromJson(jsonString);
import 'dart:convert'; import 'dart:convert';
Map<String, dynamic> selectDeviceByImeiRespModelFromJson(String str) => Map.from(json.decode(str)).map((k, v) => MapEntry<String, dynamic>(k, v)); Map<String, dynamic> selectDeviceByImeiRespModelFromJson(String str) => Map<String, dynamic>.from(json.decode(str));
String selectDeviceByImeiRespModelToJson(Map<String, dynamic> data) => json.encode(Map.from(data).map((k, v) => MapEntry<String, dynamic>(k, v))); String selectDeviceByImeiRespModelToJson(Map<String, dynamic> data) => json.encode(Map<String, dynamic>.from(data));
class SelectDeviceByImeiRespModelElement { class SelectDeviceByImeiRespModelElement {
int id; int? id;
String imei; String? imei;
int logInType; int? logInType;
int patientId; int? patientId;
bool outSa; bool? outSa;
String mobile; String? mobile;
String identificationNo; String? identificationNo;
String name; String? name;
String nameN; String? nameN;
String createdOn; String? createdOn;
String editedOn; String? editedOn;
bool biometricEnabled; bool? biometricEnabled;
int patientType; int? patientType;
int preferredLanguage; int? preferredLanguage;
SelectDeviceByImeiRespModelElement({ SelectDeviceByImeiRespModelElement({
required this.id, this.id,
required this.imei, this.imei,
required this.logInType, this.logInType,
required this.patientId, this.patientId,
required this.outSa, this.outSa,
required this.mobile, this.mobile,
required this.identificationNo, this.identificationNo,
required this.name, this.name,
required this.nameN, this.nameN,
required this.createdOn, this.createdOn,
required this.editedOn, this.editedOn,
required this.biometricEnabled, this.biometricEnabled,
required this.patientType, this.patientType,
required this.preferredLanguage, this.preferredLanguage,
}); });
factory SelectDeviceByImeiRespModelElement.fromJson(Map<String, dynamic> json) => SelectDeviceByImeiRespModelElement( factory SelectDeviceByImeiRespModelElement.fromJson(Map<String, dynamic> json) => SelectDeviceByImeiRespModelElement(
id: json["ID"], id: json["ID"] as int?,
imei: json["IMEI"], imei: json["IMEI"] as String?,
logInType: json["LogInType"], logInType: json["LogInType"] as int?,
patientId: json["PatientID"], patientId: json["PatientID"] as int?,
outSa: json["OutSA"], outSa: json["OutSA"] as bool?,
mobile: json["Mobile"], mobile: json["Mobile"] as String?,
identificationNo: json["IdentificationNo"], identificationNo: json["IdentificationNo"] as String?,
name: json["Name"], name: json["Name"] as String?,
nameN: json["NameN"], nameN: json["NameN"] as String?,
createdOn: json["CreatedOn"], createdOn: json["CreatedOn"] as String?,
editedOn: json["EditedOn"], editedOn: json["EditedOn"] as String?,
biometricEnabled: json["BiometricEnabled"], biometricEnabled: json["BiometricEnabled"] as bool?,
patientType: json["PatientType"], patientType: json["PatientType"] as int?,
preferredLanguage: json["PreferredLanguage"], preferredLanguage: json["PreferredLanguage"] as int?,
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

@ -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/providers/bottom_navigation_provider.dart';
import 'package:hmg_patient_app_new/routes/app_routes.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/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:hmg_patient_app_new/theme/app_theme.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart'; import 'package:provider/single_child_widget.dart';
import 'core/utils/size_utils.dart'; import 'core/utils/size_utils.dart';
import 'firebase_options.dart'; import 'firebase_options.dart';
var globalMessengerKey = GlobalKey<ScaffoldMessengerState>();
final navigatorKey = GlobalKey<NavigatorState>();
@pragma('vm:entry-point') @pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
@ -57,7 +55,12 @@ void main() async {
create: (_) => BottomNavigationProvider(), create: (_) => BottomNavigationProvider(),
), ),
ChangeNotifierProvider<AuthenticationViewModel>( ChangeNotifierProvider<AuthenticationViewModel>(
create: (_) => AuthenticationViewModel(authenticationRepo: getIt(), appState: getIt()), create: (_) => AuthenticationViewModel(
authenticationRepo: getIt(),
appState: getIt(),
dialogService: getIt(),
errorHandlerService: getIt(),
),
), ),
], child: MyApp()), ], child: MyApp()),
), ),
@ -94,7 +97,7 @@ class MyApp extends StatelessWidget {
initialRoute: AppRoutes.initialRoute, initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes, routes: AppRoutes.routes,
theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"),
navigatorKey: navigatorKey, navigatorKey: getIt.get<NavigationService>().navigatorKey,
); );
}, },
); );

@ -3,11 +3,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.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/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/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/int_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_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/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/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/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/large_service_card.dart';
@ -25,9 +27,10 @@ class LandingPage extends StatefulWidget {
} }
class _LandingPageState extends State<LandingPage> { class _LandingPageState extends State<LandingPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
final AuthenticationViewModel authenticationViewModel = context.read<AuthenticationViewModel>();
return Consumer<BottomNavigationProvider>(builder: (context, navigationProvider, child) { return Consumer<BottomNavigationProvider>(builder: (context, navigationProvider, child) {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
@ -43,10 +46,8 @@ class _LandingPageState extends State<LandingPage> {
children: [ children: [
CustomButton( CustomButton(
text: LocaleKeys.loginOrRegister.tr(context: context), text: LocaleKeys.loginOrRegister.tr(context: context),
onPressed: () { onPressed: () async {
Navigator.of(context).pushReplacement( await authenticationViewModel.selectDeviceImei();
MaterialPageRoute(builder: (BuildContext context) => LandingPage()),
);
}, },
backgroundColor: Color(0xffFEE9EA), backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA),
@ -66,7 +67,7 @@ class _LandingPageState extends State<LandingPage> {
), ),
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
AppState().isAuthenticated appState.isAuthenticated
? Column( ? Column(
children: [ children: [
Container( Container(
@ -257,7 +258,7 @@ class _LandingPageState extends State<LandingPage> {
), ),
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
AppState().isAuthenticated appState.isAuthenticated
? Column( ? Column(
children: [ children: [
Row( Row(

@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
abstract class DialogService {
Future<void> showErrorDialog(String message);
}
class DialogServiceImp implements DialogService {
final NavigationService navigationService;
DialogServiceImp({required this.navigationService});
@override
Future<void> 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"),
),
],
),
);
}
}

@ -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<void> 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<void> 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<void> _showDialog(Failure failure, {String title = "Error"}) async {
await dialogService.showErrorDialog(failure.message);
}
}

@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
BuildContext? get context => navigatorKey.currentContext;
Future<T?> push<T>(Route<T> route) {
return navigatorKey.currentState!.push(route);
}
void pop<T extends Object?>([T? result]) {
navigatorKey.currentState!.pop(result);
}
}
Loading…
Cancel
Save