faiz_dev1 #12

Merged
Haroon6138 merged 13 commits from faiz_dev1 into master 2 months ago

@ -1,7 +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';
@ -9,7 +8,6 @@ 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;
@ -19,7 +17,7 @@ abstract class ApiClient {
Future<void> post(
String endPoint, {
required Map<String, dynamic> body,
required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess,
required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess,
required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
bool isAllowAny,
bool isExternal,
@ -77,29 +75,26 @@ abstract class ApiClient {
class ApiClientImp implements ApiClient {
final _analytics = getIt<GAnalytics>();
final LoggerService loggerService;
final AppState appState;
final DialogService dialogService;
final LoggerService _loggerService;
final AppState _appState;
ApiClientImp({
required this.loggerService,
required this.dialogService,
required this.appState,
});
required LoggerService loggerService,
required AppState appState,
}) : _appState = appState,
_loggerService = loggerService;
@override
post(
String endPoint, {
required Map<String, dynamic> body,
required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess,
required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess,
required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
bool isAllowAny = false,
bool isAllowAny = true,
bool isExternal = false,
bool isRCService = false,
bool bypassConnectionCheck = false,
}) async {
AppState appState = getIt.get<AppState>();
String url;
if (isExternal) {
url = endPoint;
@ -111,39 +106,19 @@ class ApiClientImp implements ApiClient {
}
}
try {
var user = appState.getAuthenticatedUser;
var user = _appState.getAuthenticatedUser;
Map<String, String> headers = {'Content-Type': 'application/json', 'Accept': 'application/json'};
if (!isExternal) {
String? token = appState.appAuthToken;
String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en');
if (endPoint == ApiConsts.sendActivationCode) {
languageID = 'en';
}
String? token = _appState.appAuthToken;
if (body.containsKey('SetupID')) {
body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] ?? body[''] : SETUP_ID;
} else {}
if (body.containsKey('LanguageID')) {
if (body['LanguageID'] != null) {
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;
}
//Todo: I have converted it to string
body['DeviceTypeID'] = Platform.isIOS
? "1"
: await Utils.isGoogleServicesAvailable()
? "2"
: "3";
if (!body.containsKey('IsPublicRequest')) {
// if (!body.containsKey('PatientType')) {
if (user != null && user.patientType != null) {
@ -158,6 +133,7 @@ class ApiClientImp implements ApiClient {
body['PatientType'] = PATIENT_TYPE_ID.toString();
}
// TODO : These should be from the appState
if (user != null) {
body['TokenID'] = body['TokenID'] ?? token;
body['PatientID'] = body['PatientID'] ?? user.patientID;
@ -175,129 +151,134 @@ class ApiClientImp implements ApiClient {
// 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'] ?? "50.0";
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");
body['TokenID'] = "@dm!n";
body['VersionID'] = ApiConsts.appVersionID.toString();
body['Channel'] = ApiConsts.appChannelId.toString();
body['IPAdress'] = ApiConsts.appIpAddress;
body['generalid'] = ApiConsts.appGeneralId;
body['LanguageID'] = _appState.getLanguageID().toString();
body['Latitude'] = _appState.userLat.toString();
body['Longitude'] = _appState.userLong.toString();
body['DeviceTypeID'] = _appState.deviceTypeID;
if (_appState.appLoginTokenID.isNotEmpty) {
body['LogInTokenID'] = _appState.appLoginTokenID;
}
body.removeWhere((key, value) => value == null);
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 bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck);
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode >= 400) {
onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data"));
logApiEndpointError(endPoint, 'Error While Fetching data', statusCode);
if (!networkStatus) {
onFailure(
'Please Check The Internet Connection 1',
-1,
failureType: ConnectivityFailure("Please Check The Internet Connection 1"),
);
_analytics.errorTracking.log("internet_connectivity", error: "no internet available");
return;
}
final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers);
final int statusCode = response.statusCode;
log("response.body: ${response.body}");
if (statusCode < 200 || statusCode >= 400) {
var parsed = json.decode(utf8.decode(response.bodyBytes));
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));
if (isAllowAny) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
var parsed = json.decode(utf8.decode(response.bodyBytes));
log("parsed: ${parsed.toString()}");
if (isAllowAny) {
onSuccess(parsed, statusCode);
if (parsed['Response_Message'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['Response_Message'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else {
if (parsed['ErrorType'] == 4) {
//TODO : handle app update
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, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['IsAuthenticated'] == null) {
if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['MessageStatus'] == 1) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['Result'] == 'OK') {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode,
failureType: MessageStatusFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']),
);
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, messageStatus: parsed['MessageStatus']);
} else if (parsed['IsAuthenticated'] == null) {
if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else if (parsed['MessageStatus'] == 1) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else if (parsed['Result'] == 'OK') {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else {
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, messageStatus: parsed['MessageStatus']);
} else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else {
if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
if (parsed['ErrorSearchMsg'] == null) {
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,
failureType: ServerFailure("Error While Fetching data"),
);
logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode);
}
} else {
onFailure(
parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode,
failureType: ServerFailure("Error While Fetching data"),
);
logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
}
}
} else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']);
} else {
if (parsed['message'] != null) {
if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
if (parsed['ErrorSearchMsg'] == null) {
onFailure(
parsed['message'] ?? parsed['message'],
"Server Error found with no available message",
statusCode,
failureType: ServerFailure("Error While Fetching data"),
);
logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
logApiEndpointError(endPoint, "Server Error found with no available message", statusCode);
} else {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
parsed['ErrorSearchMsg'],
statusCode,
failureType: ServerFailure("Error While Fetching data"),
);
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode);
}
} else {
onFailure(
parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode,
failureType: UserIntimationFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']),
);
logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
}
}
} else {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['message'] != null) {
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,
failureType: ServerFailure("Error While Fetching data"),
);
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
}
}
}
}
}
} else {
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());
} catch (e, stackTrace) {
_loggerService.errorLogs(stackTrace.toString());
if (e.toString().contains("ClientException")) {
onFailure('Something went wrong, plase try again', -1, failureType: InvalidCredentials('Something went wrong, plase try again'));
onFailure('ClientException: Something went wrong, Please try again', -1, failureType: InvalidCredentials('ClientException: Something went wrong, plase try again'));
_analytics.errorTracking.log("internet_connectivity", error: "no internet available");
} else {
onFailure(e.toString(), -1);

@ -1,4 +1,4 @@
import 'dart:io';
import 'package:hmg_patient_app_new/core/enums.dart';
var MAX_SMALL_SCREEN = 660;
final OPENTOK_API_KEY = '46209962';
@ -350,7 +350,6 @@ var CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/CanPayForWal
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;
@ -702,20 +701,12 @@ 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";
@ -731,34 +722,53 @@ 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 AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD
static String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI';
static num VERSION_ID = 18.9;
static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI';
static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
static setBackendURLs() {
if (isDevelopment) {
baseUrl = "https://uat.hmgwebservices.com/";
} else {
baseUrl = "https://hmgwebservices.com/";
switch (appEnvironmentType) {
case AppEnvironmentTypeEnum.prod:
baseUrl = "https://hmgwebservices.com/";
break;
case AppEnvironmentTypeEnum.dev:
baseUrl = "https://uat.hmgwebservices.com/";
break;
case AppEnvironmentTypeEnum.uat:
baseUrl = "https://uat.hmgwebservices.com/";
break;
case AppEnvironmentTypeEnum.preProd:
baseUrl = "https://uat.hmgwebservices.com/";
break;
case AppEnvironmentTypeEnum.qa:
baseUrl = "https://uat.hmgwebservices.com/";
break;
case AppEnvironmentTypeEnum.staging:
baseUrl = "https://uat.hmgwebservices.com/";
break;
}
}
static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI';
static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication';
static final Map<String, String> packagesAuthHeader = {};
}
static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
static final String sendActivationCodeRegister = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration';
static final String checkActivationCode = 'Services/Authentication.svc/REST/CheckActivationCode';
static final String checkActivationCodeRegister = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration';
// static values for Api
static final double appVersionID = 18.7;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";
static final String appGeneralId = "Cs2020@2016\$2958";
}

@ -1,59 +1,64 @@
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/resp_models/authenticated_user_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/navigation_service.dart';
import 'api_consts.dart' as ApiConsts;
class AppState {
NavigationService navigationService;
AppState({required this.navigationService});
bool isAuthenticated = true;
double userLat = 0.0;
set setIsAuthenticated(v) => isAuthenticated = v;
set setUserLat(v) => userLat = v;
set setAppAuthToken(v) => appAuthToken = v;
double userLong = 0.0;
String appAuthToken = "";
set setUserLong(v) => userLong = v;
set setUserLat(v) => userLat = v;
bool isArabic() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar";
set setUserLong(v) => userLong = v;
int getLanguageID() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar" ? 1 : 2;
final PostParamsModel _postParamsInitConfig =
PostParamsModel(channel: 3, versionID: ApiConsts.VERSION_ID, ipAddress: '10.20.10.20', generalId: 'Cs2020@2016\$2958', deviceTypeID: "2", sessionID: 'TMRhVmkGhOsvamErw');
String? getLanguageCode() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode;
void setPostParamsInitConfig() {
isAuthenticated = false;
_postParams = _postParamsInitConfig;
}
AuthenticatedUser? _authenticatedUser;
PostParamsModel? _postParams;
void setAuthenticatedUser(AuthenticatedUser authenticatedUser) {
_authenticatedUser = authenticatedUser;
}
PostParamsModel? get postParamsObject => _postParams;
AuthenticatedUser? get getAuthenticatedUser => _authenticatedUser;
Map<String, dynamic> get postParamsJson => isAuthenticated ? (_postParams?.toJsonAfterLogin() ?? {}) : (_postParams?.toJson() ?? {});
SelectDeviceByImeiRespModelElement? _selectDeviceByImeiRespModelElement;
void setPostParamsModel(PostParamsModel _postParams) {
this._postParams = _postParams;
void setSelectDeviceByImeiRespModelElement(SelectDeviceByImeiRespModelElement value) {
_selectDeviceByImeiRespModelElement = value;
}
double userLat = 0.0;
double userLong = 0.0;
SelectDeviceByImeiRespModelElement? get getSelectDeviceByImeiRespModelElement => _selectDeviceByImeiRespModelElement;
bool isArabic() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar";
String appLoginTokenID = "";
int getLanguageID() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar" ? 1 : 2;
set setAppLoginTokenID(v) => appLoginTokenID = v;
String? getLanguageCode() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode;
String deviceToken = "";
AuthenticatedUser? _authenticatedUser;
set setDeviceToken(v) => deviceToken = v;
void setAuthenticatedUser(AuthenticatedUser authenticatedUser) {
_authenticatedUser = authenticatedUser;
}
String appAuthToken = "";
AuthenticatedUser? get getAuthenticatedUser => _authenticatedUser;
set setAppAuthToken(v) => appAuthToken = v;
String sessionId = "";
set setSessionId(v) => sessionId = v;
bool isAuthenticated = false;
set setIsAuthenticated(v) => isAuthenticated = v;
String deviceTypeID = "";
set setDeviceTypeID(v) => deviceTypeID = v;
}

@ -0,0 +1,75 @@
class CacheConst {
static const String isRememberMe = "remember_me";
static const String username = "doctorId";
static const String password = "password";
static const String logInTokenId = "logInTokenID";
static const String vidaAuthTokenId = "vidaAuthTokenID";
static const String vidaRefreshTokenId = "vidaRefreshTokenID";
static const String authenticationTokenId = "authenticationTokenID";
static const String projectId = "projectID";
static const String clinicId = "clinicId";
static const String lastLoginDate = "lastLoginDate";
static const String lastLoginTime = "lastLoginTime";
static const String memberModel = "memberModel";
static const String isShowOnboarding = "is_show_onboarding";
static const String appAuthToken = "app_auth_token";
static const String appUserId = "app_user_id";
static const String loggedInUserObj = "logged_in_user_obj";
static const String pushToken = "push_token";
static const String apnsToken = "apns_token";
static const String voipToken = "voip_token";
static const String patientMrn = "patient_mrn";
static const String loggedInUserId = "logged_in_user_id";
static const String loggedInUserPassword = "logged_in_user_password";
static const String userLat = 'user-lat';
static const String userLong = 'user-long';
static const String token = 'token';
static const String appLanguage = 'language';
static const String userProfile = 'user-profile';
static const String oneSignalApnsToken = 'onesignal-apns-token';
static const String registerDataForRegister = 'register-data-for-register';
static const String loginTokenIdDuplicate = 'register-data-for-register';
static const String registerDataForLogin = 'register-data-for-login';
static const String lastLogin = 'last-login';
static const String erCheckinRiskScore = 'er-checkin-risk-score';
static const String onlySms = 'only-sms';
static const String authData = 'auth-data';
static const String imeiUserData = 'imei-user-data';
static const String nhicData = 'nhic-data';
static const String familyFile = 'family-file';
static const String isGoToParking = 'IS_GO_TO_PARKING';
static const String isSearchAppo = 'is-search-appo';
static const String isLivecareAppointment = 'is_livecare_appointment';
static const String isVibration = 'is_vibration';
static const String themeValue = 'is_vibration';
static const String mainUser = 'main-user';
static const String pharmacyLastVisitedProducts = 'last-visited';
static const String pharmacyCustomerId = 'costumer-id';
static const String pharmacyCustomerGuid = 'customer-guid';
static const String pharmacyCustomerObject = 'pharmacy-customer-object';
static const String isRobotVisible = 'robot-visible';
static const String isRobotInit = 'robot-init';
static const String hmgGeofences = 'hmg-geo-fences';
static const String weather = 'weather';
static const String bloodType = 'blood-type';
static const String notificationCount = 'notification-count';
static const String pharmacySelectedAddress = 'selected-address';
static const String pharmacyAutorzieToken = 'PHARMACY_AUTORZIE_TOKEN';
static const String h2oUnit = 'H2O_UNIT';
static const String h2oReminder = 'H2O_REMINDER';
static const String livecareClinicData = 'LIVECARE_CLINIC_DATA';
static const String doctorScheduleDateSel = 'DOCTOR_SCHEDULE_DATE_SEL';
static const String appointmentHistoryMedical = 'APPOINTMENT_HISTORY_MEDICAL';
static const String clinicsList = 'CLINICS_LIST';
static const String covidQaList = 'COVID_QA_LIST';
static const String isCovidConsentShown = 'IS_COVID_CONSENT_SHOWN';
static const String registerInfoDubai = 'register-info-dubai';
static const String isLastAppointmentRateShown = 'is-last-appointment-rate-shown';
static const String patientOccupationList = 'patient-occupation-list';
static const String hasEnabledQuickLogin = 'has-enabled-quick-login';
}

@ -1,32 +0,0 @@
class SharedPrefsConsts {
static String isRememberMe = "remember_me";
static String username = "doctorId";
static String password = "password";
static String logInTokenID = "logInTokenID";
static String vidaAuthTokenID = "vidaAuthTokenID";
static String vidaRefreshTokenID = "vidaRefreshTokenID";
static String authenticationTokenID = "authenticationTokenID";
static String projectID = "projectID";
static String clinicId = "clinicId";
static String lastLoginDate = "lastLoginDate";
static String lastLoginTime = "lastLoginTime";
static String memberModel = "memberModel";
static String isShowOnboarding = "is_show_onboarding";
static String appAuthToken = "app_auth_token";
static String appUserID = "app_user_id";
static String loggedInUserObj = "logged_in_user_obj";
static String PUSH_TOKEN = "push_token";
static String APNS_TOKEN = "apns_token";
static String VOIP_TOKEN = "voip_token";
static String PATIENT_MRN = "patient_mrn";
static String loggedInUserID = "logged_in_user_id";
static String loggedInUserPassword = "logged_in_user_password";
static String user_lat = 'user-lat';
static String user_long = 'user-long';
}

@ -1,3 +1,4 @@
import 'package:firebase_messaging/firebase_messaging.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/app_state.dart';
@ -19,6 +20,7 @@ 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/firebase_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';
@ -32,7 +34,7 @@ class AppDependencies {
printer: PrettyPrinter(
methodCount: 2,
errorMethodCount: 5,
lineLength: 100,
lineLength: 1000,
colors: true,
printEmojis: true,
),
@ -40,6 +42,12 @@ class AppDependencies {
// Core Services
getIt.registerLazySingleton<LoggerService>(() => LoggerServiceImp(logger: logger));
getIt.registerLazySingleton<FirebaseService>(() => FirebaseServiceImpl(
loggerService: getIt(),
appState: getIt(),
firebaseMessaging: FirebaseMessaging.instance,
));
getIt.registerLazySingleton<NavigationService>(() => NavigationService());
getIt.registerLazySingleton<GAnalytics>(() => GAnalytics());
getIt.registerLazySingleton<AppState>(() => AppState(navigationService: getIt()));
@ -56,8 +64,8 @@ class AppDependencies {
));
final sharedPreferences = await SharedPreferences.getInstance();
getIt.registerLazySingleton<CacheService>(() => CacheServiceImp(sharedPreferences: sharedPreferences));
getIt.registerLazySingleton<ApiClient>(() => ApiClientImp(loggerService: getIt(), dialogService: getIt(), appState: getIt()));
getIt.registerLazySingleton<CacheService>(() => CacheServiceImp(sharedPreferences: sharedPreferences, loggerService: getIt()));
getIt.registerLazySingleton<ApiClient>(() => ApiClientImp(loggerService: getIt(), appState: getIt()));
// Repositories
getIt.registerLazySingleton<CommonRepo>(() => CommonRepoImp(loggerService: getIt()));
@ -103,6 +111,8 @@ class AppDependencies {
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
cacheService: getIt(),
navigationService: getIt(),
dialogService: getIt(),
appState: getIt(),
errorHandlerService: getIt(),

@ -22,8 +22,6 @@ enum ViewStateEnum {
errorLocal,
}
enum OTPTypeEnum { sms, whatsapp }
enum CountryEnum { saudiArabia, unitedArabEmirates }
enum SelectionTypeEnum { dropdown, calendar }
@ -34,8 +32,12 @@ enum MaritalStatusTypeEnum { single, married, divorced, widowed }
enum ChipTypeEnum { success, error, alert, info, warning }
enum OTPTypeEnum { sms, whatsapp }
enum LoginTypeEnum { sms, whatsapp, face, fingerprint }
enum AppEnvironmentTypeEnum { dev, uat, preProd, qa, staging, prod }
extension LoginTypeExtension on LoginTypeEnum {
int get toInt {
switch (this) {

@ -13,6 +13,20 @@ class ServerFailure extends Failure {
List<Object?> get props => [message];
}
class UserIntimationFailure extends Failure {
const UserIntimationFailure(super.message);
@override
List<Object?> get props => [message];
}
class MessageStatusFailure extends Failure {
const MessageStatusFailure(super.message);
@override
List<Object?> get props => [message];
}
class StatusCodeFailure extends Failure {
const StatusCodeFailure(super.message);
@ -48,7 +62,6 @@ class UnknownFailure extends Failure {
List<Object?> get props => [message];
}
class DuplicateUsername extends Failure {
const DuplicateUsername(String? message) : super(message ?? '');
@ -62,5 +75,3 @@ class InvalidCredentials extends Failure {
@override
List<Object?> get props => [message];
}

@ -3,7 +3,7 @@ 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/cache_consts.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:permission_handler/permission_handler.dart';
@ -143,8 +143,8 @@ class LocationUtils {
}
void setLocation(Position? position) {
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.latitude ?? 0.0);
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.longitude ?? 0.0);
Utils.saveNumFromPrefs(CacheConst.userLat, position?.latitude ?? 0.0);
Utils.saveNumFromPrefs(CacheConst.userLong, position?.longitude ?? 0.0);
appState.setUserLat = position?.latitude ?? 0.0;
appState.setUserLong = position?.longitude ?? 0.0;
@ -153,8 +153,8 @@ class LocationUtils {
}
void setZeroLocation() {
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0);
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0);
Utils.saveNumFromPrefs(CacheConst.userLat, 0.0);
Utils.saveNumFromPrefs(CacheConst.userLong, 0.0);
appState.setUserLat = 0.0;
appState.setUserLong = 0.0;

@ -14,7 +14,19 @@ 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, this.sessionID});
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<String, dynamic> json) {
versionID = json['VersionID'];

@ -0,0 +1,87 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:gif_view/gif_view.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class LoadingUtils {
static final NavigationService _navigationService = getIt.get<NavigationService>();
static bool _isLoadingVisible = false;
static bool get isLoading => _isLoadingVisible;
static showFullScreenLoader({bool barrierDismissible = true}) {
if (!_isLoadingVisible) {
_isLoadingVisible = true;
final context = _navigationService.navigatorKey.currentContext;
log("got the context in showFullScreenLoading");
if (context == null) return;
showDialog(
barrierDismissible: barrierDismissible,
context: context,
barrierColor: AppColors.blackColor.withOpacity(0.5),
useRootNavigator: false,
builder: (BuildContext context) => Center(
child: CircularProgressIndicator(
color: AppColors.primaryRedColor,
)),
).then((value) {
_isLoadingVisible = false;
});
}
}
static hideFullScreenLoader() {
if (!_isLoadingVisible) return;
final context = _navigationService.navigatorKey.currentContext;
if (context != null) {
try {
Navigator.of(context).pop();
} catch (_) {}
}
_isLoadingVisible = false;
}
}
class GifLoaderContainer extends StatefulWidget {
final bool barrierDismissible;
const GifLoaderContainer({super.key, this.barrierDismissible = true});
@override
GifLoaderContainerState createState() => GifLoaderContainerState();
}
class GifLoaderContainerState extends State<GifLoaderContainer> with TickerProviderStateMixin {
late GifController controller;
@override
void initState() {
super.initState();
controller = GifController();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: widget.barrierDismissible,
child: Center(
child: GifView(
controller: controller,
image: AssetImage("assets/images/progress-loading-red.gif"),
),
),
);
}
}

@ -15,7 +15,7 @@ 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 '../consts.dart';
import '../cache_consts.dart';
// |--> Push Notification Background
@pragma('vm:entry-point')
@ -256,7 +256,7 @@ class PushNotificationHandler {
final permission = await FirebaseMessaging.instance.requestPermission();
await FirebaseMessaging.instance.getAPNSToken().then((value) async {
log("APNS token: " + value.toString());
await Utils.saveStringFromPrefs(SharedPrefsConsts.APNS_TOKEN, value.toString());
await Utils.saveStringFromPrefs(CacheConst.apnsToken, value.toString());
});
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
@ -269,11 +269,11 @@ class PushNotificationHandler {
try {
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) async {
if (message != null) {
if (Platform.isIOS)
if (Platform.isIOS) {
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
if (message != null) newMessage(message);
});
else if (message != null) newMessage(message);
} else if (message != null) newMessage(message);
}
});
} catch (ex) {}
@ -281,22 +281,24 @@ class PushNotificationHandler {
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print("Firebase onMessage!!!");
// showCallkitIncoming();
if (Platform.isIOS)
if (Platform.isIOS) {
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
newMessage(message);
});
else
} else {
newMessage(message);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
print("Firebase onMessageOpenedApp!!!");
if (Platform.isIOS)
if (Platform.isIOS) {
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
newMessage(message);
});
else
} else {
newMessage(message);
}
});
FirebaseMessaging.instance.getToken().then((String? token) {
@ -350,7 +352,7 @@ class PushNotificationHandler {
onToken(String token) async {
print("Push Notification Token: " + token);
await Utils.saveStringFromPrefs(SharedPrefsConsts.PUSH_TOKEN, token);
await Utils.saveStringFromPrefs(CacheConst.pushToken, token);
}
onResume() async {
@ -363,9 +365,7 @@ class PushNotificationHandler {
Future<void> requestPermissions() async {
try {
if (Platform.isIOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(alert: true, badge: true, sound: true);
await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()?.requestPermissions(alert: true, badge: true, sound: true);
} else if (Platform.isAndroid) {
Map<Permission, PermissionStatus> statuses = await [
Permission.notification,

@ -2,6 +2,47 @@ 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 getPatientAuthenticationRequest({
required String phoneNumber,
required String nationId,
required OTPTypeEnum otpTypeEnum,
required bool patientOutSA,
required bool isForRegister,
required int? patientId,
required String zipCode,
}) {
bool fileNo = false;
if (nationId.isNotEmpty) {
fileNo = nationId.length < 10;
}
var request = SendActivationRequest();
if (phoneNumber.isNotEmpty) {
request.patientMobileNumber = int.parse(phoneNumber);
}
request.oTPSendType = otpTypeEnum.toInt(); // could map OTPTypeEnum if needed
request.zipCode = zipCode; // or countryCode if defined elsewhere
if (isForRegister) {
// 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(nationId);
request.patientIdentificationID = request.nationalID = "";
request.searchType = 2;
} else {
request.patientID = 0;
request.searchType = 1;
request.patientIdentificationID = request.nationalID = nationId.isNotEmpty ? nationId : '0';
}
request.isRegister = false;
}
return request;
}
static dynamic getCommonRequestWelcome({
required String phoneNumber,
required OTPTypeEnum otpTypeEnum,
@ -50,39 +91,38 @@ class RequestUtils {
return request;
}
static getCommonRequestAuthProvider({
static getCommonRequestSendActivationCode({
required OTPTypeEnum otpTypeEnum,
required registeredData,
required deviceToken,
required mobileNumber,
required zipCode,
required patientOutSA,
required loginTokenID,
required selectedOption,
required String mobileNumber,
required String zipCode,
required int? patientId,
required String? nationalId,
required bool patientOutSA,
required int selectedLoginType,
required bool isForRegister,
required bool isFileNo,
}) {
var request = SendActivationRequest();
request.patientMobileNumber = mobileNumber;
if (mobileNumber.isNotEmpty) {
request.patientMobileNumber = int.parse(mobileNumber);
}
request.mobileNo = '0$mobileNumber';
request.deviceToken = deviceToken;
request.projectOutSA = patientOutSA == true ? true : false;
request.loginType = selectedOption;
request.projectOutSA = patientOutSA;
request.loginType = selectedLoginType;
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;
if (isForRegister) {
// 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.searchType = isFileNo ? 2 : 1;
request.patientID = patientId ?? 0;
request.nationalID = request.nationalID ?? '0';
request.patientIdentificationID = request.patientIdentificationID ?? '0';
request.nationalID = nationalId ?? '0';
request.patientIdentificationID = nationalId ?? '0';
request.isRegister = false;
}
request.deviceTypeID = request.searchType;

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/consts.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
class SizeConfig {
static double _blockWidth = 0;

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:crypto/crypto.dart' as crypto;
@ -13,7 +14,6 @@ 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/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart';
@ -59,14 +59,12 @@ class Utils {
// ),
// ));
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(
Duration(
hours: isAddHours ? 3 : 0,
),
));
? 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,
),
));
}
static String convertStringToDateTime(String dateTimeString) {
@ -205,16 +203,16 @@ class Utils {
_isLoadingVisible = true;
showDialog(
context: navigationService.navigatorKey.currentContext!,
barrierColor: Colors.black.withOpacity(0.5),
barrierColor: AppColors.blackColor,
builder: (BuildContext context) => LoadingDialog(),
)
.then((value) {
_isLoadingVisible = false;
})
_isLoadingVisible = false;
})
.catchError((e) {})
.onError(
(error, stackTrace) {},
);
);
}
static void hideLoading() {
@ -224,7 +222,9 @@ class Utils {
Navigator.of(navigationService.navigatorKey.currentContext!).pop();
}
_isLoadingVisible = false;
} catch (e) {}
} catch (e) {
log("errr: ${e.toString()}");
}
}
static List<T> uniqueBy<T, K>(List<T> list, K Function(T) keySelector) {
@ -236,12 +236,11 @@ class Utils {
showDialog(
barrierDismissible: false,
context: context,
builder: (cxt) =>
ConfirmDialog(
title: title!,
message: message!,
onTap: onTap,
),
builder: (cxt) => ConfirmDialog(
title: title!,
message: message!,
onTap: onTap,
),
);
}
@ -268,7 +267,7 @@ class Utils {
var x = int.parse(a) * 2;
var b = x.toString();
if (b.length == 1) {
b = "0" + b;
b = "0$b";
}
sum += int.parse(b[0]) + int.parse(b[1]);
} else {
@ -277,7 +276,9 @@ class Utils {
}
return sum % 10 == 0;
}
} catch (err) {}
} catch (err) {
log("errr: ${err.toString()}");
}
return false;
} else {
return true;
@ -311,10 +312,8 @@ class Utils {
}
// Replace HTML line breaks with newlines
var withLineBreaks = htmlString
.replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n')
.replaceAll(RegExp(r'<\/p>', multiLine: true), '\n')
.replaceAll(RegExp(r'<divider>', multiLine: true), '\n');
var withLineBreaks =
htmlString.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
var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), '');
@ -362,9 +361,8 @@ class Utils {
final month = monthNames[dateTime.month - 1];
return '$day $month, $year';
return '$day $month, $year';
} catch (e) {
print("Error formatting date: $e");
log("Error formatting date: $e");
return "";
}
}
@ -372,9 +370,7 @@ class Utils {
static String formatHijriDateToDisplay(String hijriDateString) {
try {
// Assuming hijriDateString is in the format yyyy-MM-dd
final datePart = hijriDateString
.split("T")
.first;
final datePart = hijriDateString.split("T").first;
final parts = datePart.split('-');
if (parts.length != 3) return "";
@ -382,26 +378,13 @@ 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];
return '$day $month, $year';
} catch (e) {
print("Error formatting hijri date: $e");
log("Error formatting hijri date: $e");
return "";
}
}
@ -415,7 +398,7 @@ class Utils {
return '$day-$month-$year';
} catch (e) {
print("Error formatting date: $e");
log("Error formatting date: $e");
return "";
}
}
@ -432,14 +415,8 @@ class Utils {
void Function(LottieComposition)? onLoaded,
}) {
return Lottie.asset(assetPath,
height: height ?? MediaQuery
.of(context)
.size
.height * 0.26,
width: width ?? MediaQuery
.of(context)
.size
.width,
height: height ?? MediaQuery.of(context).size.height * 0.26,
width: width ?? MediaQuery.of(context).size.width,
fit: fit,
alignment: alignment,
repeat: repeat,
@ -499,10 +476,7 @@ class Utils {
static Future<bool> isGoogleServicesAvailable() async {
GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
String status = availability
.toString()
.split('.')
.last;
String status = availability.toString().split('.').last;
if (status == "success") {
return true;
}
@ -523,26 +497,3 @@ class Utils {
return crypto.md5.convert(utf8.encode(input)).toString();
}
}
class ValidationUtils {
static DialogService dialogService = getIt.get<DialogService>();
static bool isValidatePhoneAndId({
String? nationalId,
String? phoneNumber
}) {
if (nationalId == null || nationalId.isEmpty) {
dialogService.showErrorDialog(message: "Please enter a valid national ID or file number", onOkPressed: () {});
return false;
}
if (phoneNumber == null || phoneNumber.isEmpty) {
dialogService.showErrorDialog(message: "Please enter a valid phone number", onOkPressed: () {});
return false;
}
return true;
}
}

@ -0,0 +1,23 @@
import 'dart:developer';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
class ValidationUtils {
static final DialogService _dialogService = getIt.get<DialogService>();
static bool isValidatePhoneAndId({String? nationalId, String? phoneNumber}) {
log("phoneNumber: $phoneNumber");
log("nationalId: $nationalId");
if (nationalId == null || nationalId.isEmpty) {
_dialogService.showErrorBottomSheet(message: "Please enter a valid national ID or file number", onOkPressed: () {});
return false;
}
if (phoneNumber == null || phoneNumber.isEmpty) {
_dialogService.showErrorBottomSheet(message: "Please enter a valid phone number", onOkPressed: () {});
return false;
}
return true;
}
}

@ -20,4 +20,8 @@ extension NavigationExtensions on BuildContext {
void navigateTo(Widget page) {
Navigator.push(this, MaterialPageRoute(builder: (context) => page));
}
void popUntilNamed(String routeName) {
Navigator.popUntil(this, ModalRoute.withName(routeName));
}
}

@ -1,13 +1,10 @@
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/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';
@ -16,11 +13,19 @@ abstract class AuthenticationRepo {
required String firebaseToken,
});
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({
required CheckPatientAuthenticationReq checkPatientAuthenticationReq,
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq});
Future<Either<Failure, GenericApiModel<dynamic>>> sendActivationCodeRepo({
required dynamic sendActivationCodeReq,
String? languageID,
bool isRegister = false,
});
Future<Either<Failure, GenericApiModel<dynamic>>> sendActivationCodeRegister({required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID});
Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo({
required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
required String? activationCode,
required bool isRegister,
});
}
class AuthenticationRepoImp implements AuthenticationRepo {
@ -41,7 +46,7 @@ class AuthenticationRepoImp implements AuthenticationRepo {
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['Patient_SELECTDeviceIMEIbyIMEIList'];
if (list == null || list.isEmpty) {
@ -52,7 +57,7 @@ class AuthenticationRepoImp implements AuthenticationRepo {
apiResponse = GenericApiModel<SelectDeviceByImeiRespModelElement>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
errorMessage: errorMessage,
data: model,
);
} catch (e) {
@ -70,33 +75,26 @@ class AuthenticationRepoImp implements AuthenticationRepo {
@override
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({
required CheckPatientAuthenticationReq checkPatientAuthenticationReq,
required dynamic 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<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.selectDeviceImei,
ApiConsts.checkPatientAuth,
body: checkPatientAuthenticationReq.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
errorMessage: errorMessage,
data: response,
);
} catch (e) {
@ -113,41 +111,86 @@ class AuthenticationRepoImp implements AuthenticationRepo {
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> 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;
Future<Either<Failure, GenericApiModel<dynamic>>> sendActivationCodeRepo({
required dynamic sendActivationCodeReq,
String? languageID,
bool isRegister = false,
}) async {
int isOutKsa = (sendActivationCodeReq.zipCode == '966' || sendActivationCodeReq.zipCode == '+966') ? 0 : 1;
sendActivationCodeReq.patientOutSA = isOutKsa;
sendActivationCodeReq.isDentalAllowedBackend = false;
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
SEND_ACTIVATION_CODE_REGISTER,
body: checkPatientAuthenticationReq.toJson(),
isRegister ? ApiConsts.sendActivationCodeRegister : ApiConsts.sendActivationCode,
body: sendActivationCodeReq.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
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<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo({
required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
required String? activationCode,
required bool isRegister,
}) async {
newRequest.activationCode = activationCode ?? "0000";
newRequest.isSilentLogin = activationCode != null ? false : true;
newRequest.projectOutSA = newRequest.zipCode == '966' ? false : true;
newRequest.isDentalAllowedBackend = false;
newRequest.forRegisteration = newRequest.isRegister ?? false;
newRequest.isRegister = false;
final endpoint = isRegister ? ApiConsts.checkActivationCodeRegister : ApiConsts.checkActivationCode;
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
endpoint,
body: newRequest.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: CheckActivationCode.fromJson(response),
errorMessage: errorMessage,
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!);

@ -1,29 +1,43 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/request_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.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/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/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/routes/app_routes.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/navigation_service.dart';
class AuthenticationViewModel extends ChangeNotifier {
AuthenticationRepo authenticationRepo;
AppState appState;
ErrorHandlerService errorHandlerService;
DialogService dialogService;
final AuthenticationRepo _authenticationRepo;
final AppState _appState;
final ErrorHandlerService _errorHandlerService;
final DialogService _dialogService;
final NavigationService _navigationService;
AuthenticationViewModel({
required this.appState,
required this.authenticationRepo,
required this.errorHandlerService,
required this.dialogService,
});
required AppState appState,
required AuthenticationRepo authenticationRepo,
required ErrorHandlerService errorHandlerService,
required DialogService dialogService,
required NavigationService navigationService,
required CacheService cacheService,
}) : _navigationService = navigationService,
_dialogService = dialogService,
_errorHandlerService = errorHandlerService,
_appState = appState,
_authenticationRepo = authenticationRepo;
final TextEditingController nationalIdController = TextEditingController(), phoneNumberController = TextEditingController(), dobController = TextEditingController();
CountryEnum selectedCountrySignup = CountryEnum.saudiArabia;
@ -31,11 +45,46 @@ class AuthenticationViewModel extends ChangeNotifier {
GenderTypeEnum? genderType;
bool isTermsAccepted = false;
List<NationalityCountries>? countriesList;
NationalityCountries? pickedCountryByUAEUser;
void login() {
if (ValidationUtils.isValidatePhoneAndId(nationalId: nationalIdController.text, phoneNumber: phoneNumberController.text)) {
} else {}
bool isDubai = false;
bool authenticated = false;
late int mobileNumber;
String errorMsg = '';
var registerd_data;
bool isMoreOption = false;
var zipCode;
var patientOutSA;
var loginTokenID;
var loginType;
var deviceToken;
var lastLogin;
final FocusNode myFocusNode = FocusNode();
late int selectedOption = 1;
bool onlySMSBox = false;
int fingrePrintBefore = 0;
var dob;
late int isHijri;
var healthId;
Future<void> onLoginPressed() async {
try {
LoadingUtils.showFullScreenLoader();
//TODO: We will remove this delay
await Future.delayed(Duration(seconds: 3));
var data = _appState.getSelectDeviceByImeiRespModelElement;
log("Cached IMEI data: ${data?.toJson()}");
if (data != null) {
await _handleExistingImeiData(data);
} else {
await _handleNewImeiRegistration();
}
} catch (e) {
log("Error in onLoginPressed: $e");
LoadingUtils.hideFullScreenLoader();
_dialogService.showErrorBottomSheet(message: "An unexpected error occurred. Please try again.", onOkPressed: () {});
}
}
void clearDefaults() {
@ -84,112 +133,285 @@ class AuthenticationViewModel extends ChangeNotifier {
notifyListeners();
}
Future<void> selectDeviceImei({Function(dynamic)? onSuccess, Function(String)? onError}) async {
String firebaseToken = "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc";
final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken);
Future<void> selectDeviceImei({required Function(dynamic data) onSuccess, Function(String)? onError}) async {
// LoadingUtils.showFullScreenLoading();
String firebaseToken = _appState.deviceToken == ""
? "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"
: _appState.deviceToken;
final result = await _authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
// LoadingUtils.hideFullScreenLoader();
await _errorHandlerService.handleError(failure: failure);
},
(apiResponse) {
// LoadingUtils.hideFullScreenLoader();
log("apiResponse: ${apiResponse.data.toString()}");
log("messageStatus: ${apiResponse.messageStatus.toString()}");
if (apiResponse.messageStatus == 1) {
onSuccess(apiResponse.data);
} else if (apiResponse.messageStatus == 2) {
_dialogService.showErrorBottomSheet(message: "Message Status = 2", onOkPressed: () {});
}
},
);
}
Future<void> _handleExistingImeiData(dynamic data) async {
try {
SelectDeviceByImeiRespModelElement? savedData = _appState.getSelectDeviceByImeiRespModelElement;
LoadingUtils.hideFullScreenLoader();
if (savedData != null) {
// TODO: Navigate to SavedLogin when available
_navigationService.pushPage(page: LoginScreen());
// navigationService.pushPage(page: SavedLogin(savedData));
}
} catch (e) {
log("Error handling existing IMEI data: $e");
LoadingUtils.hideFullScreenLoader();
_navigationService.pushPage(page: LoginScreen());
}
}
Future<void> _handleNewImeiRegistration() async {
await selectDeviceImei(onSuccess: (dynamic respData) async {
try {
if (respData != null) {
dynamic data = SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
_appState.setSelectDeviceByImeiRespModelElement(data);
LoadingUtils.hideFullScreenLoader();
// TODO: Navigate to SavedLogin when available
// SelectDeviceByImeiRespModelElement savedData =
// SelectDeviceByImeiRespModelElement.fromJson(respData);
// navigationService.pushPage(page: SavedLogin(savedData));
_navigationService.pushPage(page: LoginScreen());
} else {
LoadingUtils.hideFullScreenLoader();
_navigationService.pushPage(page: LoginScreen());
}
} catch (e) {
log("Error processing IMEI registration response: $e");
LoadingUtils.hideFullScreenLoader();
_navigationService.pushPage(page: LoginScreen());
}
}, onError: (String error) {
LoadingUtils.hideFullScreenLoader();
_dialogService.showErrorBottomSheet(message: error, onOkPressed: () {});
});
}
Future<void> checkUserAuthentication({required OTPTypeEnum otpTypeEnum, Function(dynamic)? onSuccess, Function(String)? onError}) async {
// TODO: THIS SHOULD BE REMOVED LATER ON AND PASSED FROM APP STATE DIRECTLY INTO API CLIENT. BECAUSE THIS API ONLY NEEDS FEW PARAMS FROM USER
if (phoneNumberController.text.isEmpty) {
phoneNumberController.text = "504278212";
}
bool isValidated = ValidationUtils.isValidatePhoneAndId(
phoneNumber: phoneNumberController.text,
nationalId: nationalIdController.text,
);
if (!isValidated) {
return;
}
LoadingUtils.showFullScreenLoader();
dynamic checkPatientAuthenticationReq = RequestUtils.getPatientAuthenticationRequest(
phoneNumber: phoneNumberController.text,
nationId: nationalIdController.text,
isForRegister: false,
patientOutSA: false,
otpTypeEnum: otpTypeEnum,
patientId: 0,
zipCode: '966',
);
final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq);
LoadingUtils.hideFullScreenLoader();
result.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
//todo: move to next api call
if (apiResponse.data['isSMSSent']) {
_appState.setAppLoginTokenID = apiResponse.data['LogInTokenID'];
sendActivationCode(
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text,
);
} else {
if (apiResponse.data['IsAuthenticated']) {
await checkActivationCode(
onWrongActivationCode: (String? message) {},
activationCode: 0000,
);
}
}
}
},
);
}
Future<void> sendActivationCode({
required OTPTypeEnum otpTypeEnum,
required String nationalIdOrFileNumber,
required String phoneNumber,
}) async {
var request = RequestUtils.getCommonRequestSendActivationCode(
otpTypeEnum: otpTypeEnum,
mobileNumber: phoneNumber,
selectedLoginType: otpTypeEnum.toInt(),
zipCode: "966",
nationalId: nationalIdOrFileNumber,
isFileNo: false,
patientId: 0,
isForRegister: false,
patientOutSA: false,
);
// TODO: GET APP SMS SIGNATURE HERE
request.sMSSignature = "enKTDcqbOVd";
// GifLoaderDialogUtils.showMyDialog(context);
bool isForRegister = healthId != null || isDubai;
if (isForRegister) {
if (!isDubai) {
request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob));
}
request.healthId = healthId;
request.isHijri = isHijri;
} else {
// request.dob = "";
// request.healthId = "";
// request.isHijri = 0;
}
final resultEither = await _authenticationRepo.sendActivationCodeRepo(
sendActivationCodeReq: request,
isRegister: isForRegister,
languageID: 'er',
);
resultEither.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty");
} else {
if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) {
navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
} else {
// TODO: Handle isSMSSent false
// navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
}
}
},
);
}
// Future<void> 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<void> 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());
// });
// }
// }
Future<void> checkActivationCode({
required int activationCode,
required Function(String? message) onWrongActivationCode,
}) async {
final request = RequestUtils.getCommonRequestWelcome(
phoneNumber: '0567184134',
otpTypeEnum: OTPTypeEnum.sms,
deviceToken: 'dummyDeviceToken123',
patientOutSA: true,
loginTokenID: 'dummyLoginToken456',
registeredData: null,
patientId: 12345,
nationIdText: '1234567890',
countryCode: 'SA',
).toJson();
bool isForRegister = healthId != null || isDubai;
if (isForRegister) {
if (isDubai) request['DOB'] = dob;
request['HealthId'] = healthId;
request['IsHijri'] = isHijri;
final resultEither = await _authenticationRepo.checkActivationCodeRepo(
newRequest: request,
activationCode: activationCode.toString(),
isRegister: true,
);
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) {
final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
if (registerd_data?.isRegister == true) {
_navigationService.popUntilNamed(AppRoutes.registerNewScreen);
// Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
return;
}
});
} else {
final resultEither = await _authenticationRepo.checkActivationCodeRepo(
newRequest: request,
activationCode: activationCode.toString(),
isRegister: false,
);
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) {
final activation = CheckActivationCode.fromJson(resultEither as Map<String, dynamic>);
if (activation.errorCode == '699') {
// Todo: Hide Loader
// GifLoaderDialogUtils.hideDialog(context);
onWrongActivationCode(activation.errorEndUserMessage);
return;
} else if (registerd_data?.isRegister == true) {
_navigationService.popUntilNamed(AppRoutes.registerNewScreen);
// Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
return;
} else {
// TODO: setPreferences and stuff
// sharedPref.remove(FAMILY_FILE);
// activation.list!.isFamily = false;
// userData = activation.list;
// sharedPref.setString(BLOOD_TYPE, activation.patientBloodType ?? "");
// authenticatedUserObject.user = activation.list!;
// projectViewModel.setPrivilege(privilegeList: res);
// await sharedPref.setObject(MAIN_USER, activation.list);
// await sharedPref.setObject(USER_PROFILE, activation.list);
// loginTokenID = activation.logInTokenID;
// await sharedPref.setObject(LOGIN_TOKEN_ID, activation.logInTokenID);
// await sharedPref.setString(TOKEN, activation.authenticationTokenID!);
// checkIfUserAgreedBefore(activation);
// projectViewModel.analytics.loginRegistration.login_successful();
}
});
}
}
Future<void> navigateToOTPScreen({required OTPTypeEnum otpTypeEnum, required String phoneNumber}) async {
_navigationService.pushToOtpScreen(
phoneNumber: phoneNumber,
checkActivationCode: (int activationCode) async {
await checkActivationCode(
activationCode: activationCode,
onWrongActivationCode: (String? value) {
onWrongActivationCode(message: value);
});
},
onResendOTPPressed: (String phoneNumber) {},
);
}
Future<void> onWrongActivationCode({String? message}) async {
// TODO: HANDLE THIS VIA BOTTOM SHEET
}
@override
void dispose() {
nationalIdController.dispose();
phoneNumberController.dispose();
myFocusNode.dispose();
super.dispose();
}
}

@ -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<String, dynamic> 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<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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['activationCode'] = activationCode;
data['IsSilentLogin'] = isSilentLogin;
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['ForRegisteration'] = forRegisteration;
data['DOB'] = dob;
data['IsHijri'] = isHijri;
data['HealthId'] = healthId;
return data;
}
}

@ -29,38 +29,38 @@ class SendActivationRequest {
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
});
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<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber'];

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
@ -6,16 +7,23 @@ import 'package:hmg_patient_app_new/presentation/authentication/register_step2.d
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
class OTPVerificationPage extends StatefulWidget {
class OTPVerificationScreen extends StatefulWidget {
final String phoneNumber;
final Function(int code) checkActivationCode;
final Function(String phoneNumber) onResendOTPPressed;
const OTPVerificationPage({Key? key, required this.phoneNumber}) : super(key: key);
const OTPVerificationScreen({
super.key,
required this.phoneNumber,
required this.checkActivationCode,
required this.onResendOTPPressed,
});
@override
State<OTPVerificationPage> createState() => _OTPVerificationPageState();
State<OTPVerificationScreen> createState() => _OTPVerificationScreenState();
}
class _OTPVerificationPageState extends State<OTPVerificationPage> {
class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
final int _otpLength = 4;
late final List<TextEditingController> _controllers;
late final List<FocusNode> _focusNodes;
@ -41,8 +49,12 @@ class _OTPVerificationPageState extends State<OTPVerificationPage> {
@override
void dispose() {
for (final c in _controllers) c.dispose();
for (final f in _focusNodes) f.dispose();
for (final c in _controllers) {
c.dispose();
}
for (final f in _focusNodes) {
f.dispose();
}
_resendTimer?.cancel();
super.dispose();
}

@ -45,7 +45,7 @@ class InsuranceRepoImp implements InsuranceRepo {
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_PatientInsuranceCard'];
if (list == null || list.isEmpty) {

@ -45,7 +45,7 @@ class LabRepoImp implements LabRepo {
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListPLO'];
if (list == null || list.isEmpty) {

@ -48,7 +48,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['PatientPrescriptionList'];
if (list == null || list.isEmpty) {
@ -111,7 +111,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = prescriptionsResponseModel.isInOutPatient! ? response['ListPRM'] : response['INP_GetPrescriptionReport_List'];
if (list == null || list.isEmpty) {

@ -1,8 +1,8 @@
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_failure.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
@ -45,7 +45,7 @@ class RadiologyRepoImp implements RadiologyRepo {
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus}) {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
final radOrders;
try {
if (response['FinalRadiologyList'] != null && response['FinalRadiologyList'].length != 0) {

@ -5,7 +5,9 @@ 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/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
@ -34,6 +36,16 @@ class MyHttpOverrides extends HttpOverrides {
}
}
Future<void> callAppStateInitializations() async {
final String deviceTypeId = (Platform.isIOS
? "1"
: await Utils.isGoogleServicesAvailable()
? "2"
: "3");
AppState appState = getIt.get<AppState>();
appState.setDeviceTypeID = deviceTypeId;
}
Future<void> callInitializations() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
@ -41,6 +53,7 @@ Future<void> callInitializations() async {
AppDependencies.addDependencies();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
HttpOverrides.global = MyHttpOverrides();
await callAppStateInitializations();
}
void main() async {
@ -84,6 +97,8 @@ void main() async {
appState: getIt(),
dialogService: getIt(),
errorHandlerService: getIt(),
navigationService: getIt(),
cacheService: getIt(),
),
),
], child: MyApp()),

@ -1,7 +1,10 @@
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/context_extensions.dart';
@ -18,11 +21,13 @@ import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
_LoginScreen createState() => _LoginScreen();
LoginScreenState createState() => LoginScreenState();
}
class _LoginScreen extends State<LoginScreen> {
class LoginScreenState extends State<LoginScreen> {
@override
void initState() {
super.initState();
@ -83,7 +88,7 @@ class _LoginScreen extends State<LoginScreen> {
icon: AppAssets.login1,
iconColor: Colors.white,
onPressed: () {
showLoginModel(context: context, authVM: authVm);
showLoginModelSheet(context: context, phoneNumberController: authVm.phoneNumberController, authViewModel: authVm);
// if (nationIdController.text.isNotEmpty) {
// } else {
@ -140,29 +145,35 @@ class _LoginScreen extends State<LoginScreen> {
);
}
void showLoginModel({required BuildContext context, required AuthenticationViewModel authVM}) {
void showLoginModelSheet({
required BuildContext context,
required TextEditingController? phoneNumberController,
required AuthenticationViewModel authViewModel,
}) {
context.showBottomSheet(
isScrollControlled: true,
isDismissible: false,
useSafeArea: true,
backgroundColor: Colors.transparent,
backgroundColor: AppColors.transparent,
child: StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) {
return Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: SingleChildScrollView(
child: GenericBottomSheet(
countryCode: authVM.selectedCountrySignup.countryCode,
countryCode: authViewModel.selectedCountrySignup.countryCode,
initialPhoneNumber: "",
textController: authVM.phoneNumberController,
textController: phoneNumberController,
isEnableCountryDropdown: true,
onCountryChange: authVM.onCountryChange,
onChange: authVM.onPhoneNumberChange,
onCountryChange: authViewModel.onCountryChange,
onChange: authViewModel.onPhoneNumberChange,
buttons: [
Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: CustomButton(
text: LocaleKeys.sendOTPSMS.tr(),
onPressed: () {},
onPressed: () async {
await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedBorderColor,
textColor: AppColors.whiteColor,
@ -183,7 +194,11 @@ class _LoginScreen extends State<LoginScreen> {
padding: EdgeInsets.only(bottom: 10.h, top: 10.h),
child: CustomButton(
text: LocaleKeys.sendOTPWHATSAPP.tr(),
onPressed: () {},
onPressed: () async {
log("phoneNumberController: ${phoneNumberController == null}");
log("phoneNumberControllerVa: ${phoneNumberController?.text}");
await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp);
},
backgroundColor: Colors.white,
borderColor: AppColors.borderOnlyColor,
textColor: AppColors.textColor,

@ -10,15 +10,14 @@ 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/features/authentication/widgets/otp_verification_screen.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/bottomsheet/generic_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart' show CustomButton;
import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart';
import 'package:hmg_patient_app_new/widgets/dropdown/dropdown_widget.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/otp/otp.dart';
import 'package:provider/provider.dart';
class RegisterNew extends StatefulWidget {
@ -225,9 +224,12 @@ class _RegisterNew extends State<RegisterNew> {
text: LocaleKeys.sendOTPSMS.tr(),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => OTPVerificationPage(
phoneNumber: '12234567',
)));
builder: (BuildContext context) => OTPVerificationScreen(
phoneNumber: '504278212',
checkActivationCode: (int code) {},
onResendOTPPressed: (String phone) {},
),
));
// if (mobileNo.isEmpty) {
// context.showBottomSheet(
@ -252,7 +254,6 @@ class _RegisterNew extends State<RegisterNew> {
// } else {
// registerUser(1);
// }
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => OTPVerificationPage(phoneNumber: '12234567')));
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedBorderColor,

@ -1,15 +1,11 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/context_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';
@ -112,8 +108,8 @@ class _RegisterNew extends State<RegisterNewStep2> {
labelText: LocaleKeys.gender.tr(),
hintText: LocaleKeys.malE.tr(),
isEnable: true,
dropdownItems: GenderTypeEnum.values.map((e) => appState!.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: genderType != null ? (appState!.isArabic() ? genderType!.typeAr : genderType!.type) : "",
dropdownItems: GenderTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: genderType != null ? (appState.isArabic() ? genderType.typeAr : genderType.type) : "",
onChange: authVM.onGenderChange,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
@ -147,8 +143,8 @@ class _RegisterNew extends State<RegisterNewStep2> {
labelText: LocaleKeys.maritalStatus.tr(),
hintText: LocaleKeys.married.tr(),
isEnable: true,
dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState!.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: maritalStatus != null ? (appState!.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "",
dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: maritalStatus != null ? (appState.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "",
onChange: authVM.onMaritalStatusChange,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
@ -161,7 +157,7 @@ class _RegisterNew extends State<RegisterNewStep2> {
)
: TextInputWidget(
labelText: LocaleKeys.maritalStatus.tr(),
hintText: appState!.isArabic()
hintText: appState.isArabic()
? (MaritalStatusTypeExtension.fromValue(widget.nHICData!.maritalStatusCode)!.typeAr)
: (MaritalStatusTypeExtension.fromValue(widget.nHICData!.maritalStatusCode)!.type),
isEnable: true,
@ -178,7 +174,11 @@ class _RegisterNew extends State<RegisterNewStep2> {
? Selector<AuthenticationViewModel, ({List<NationalityCountries>? countriesList, NationalityCountries? selectedCountry, bool isArabic})>(
selector: (context, authViewModel) {
final appState = getIt.get<AppState>();
return (countriesList: authViewModel.countriesList, selectedCountry: authViewModel.pickedCountryByUAEUser, isArabic: appState.isArabic());
return (
countriesList: authViewModel.countriesList,
selectedCountry: authViewModel.pickedCountryByUAEUser,
isArabic: appState.isArabic(),
);
},
shouldRebuild: (previous, next) => previous.countriesList != next.countriesList || previous.selectedCountry != next.selectedCountry || previous.isArabic != next.isArabic,
builder: (context, data, child) {

@ -1,5 +1,3 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/presentation/home/data/service_card_data.dart';

@ -11,12 +11,12 @@ 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/authentication/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/services/navigation_service.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/custom_tab_bar.dart' show CustomTabBar;
@ -35,6 +35,7 @@ class _LandingPageState extends State<LandingPage> {
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
NavigationService navigationService = getIt.get<NavigationService>();
final AuthenticationViewModel authenticationViewModel = context.read<AuthenticationViewModel>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
@ -51,8 +52,7 @@ class _LandingPageState extends State<LandingPage> {
CustomButton(
text: LocaleKeys.loginOrRegister.tr(context: context),
onPressed: () async {
// await authenticationViewModel.selectDeviceImei();
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => LoginScreen()));
await authenticationViewModel.onLoginPressed();
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
@ -157,7 +157,6 @@ class _LandingPageState extends State<LandingPage> {
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName,
icon: LandingPageData.getLoggedInServiceCardsList[index].icon,
title: LandingPageData.getLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle,
@ -181,7 +180,10 @@ class _LandingPageState extends State<LandingPage> {
)
: Container(
height: 127.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(

@ -4,10 +4,11 @@ import 'package:hmg_patient_app_new/splashPage.dart';
class AppRoutes {
static const String initialRoute = '/initialRoute';
static const String login = '/login';
static const String loginScreen = '/loginScreen';
static const String registerNewScreen = '/registerNewScreen';
static Map<String, WidgetBuilder> get routes => {
initialRoute: (context) => SplashPage(),
login: (context) => LoginScreen(),
loginScreen: (context) => LoginScreen(),
};
}

@ -1,14 +1,116 @@
import 'dart:convert';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
abstract class CacheService {
Future<void> saveString({required String key, required String value});
Future<void> saveInt({required String key, required int value});
Future<void> saveDouble({required String key, required double value});
Future<void> saveBool({required String key, required bool value});
Future<void> saveStringList({required String key, required List<String> value});
String? getString({required String key});
int? getInt({required String key});
double? getDouble({required String key});
bool? getBool({required String key});
List<String>? getStringList({required String key});
Future<dynamic> getObject({required String key});
Future<void> saveObject({required String key, required dynamic value});
Future<void> remove({required String key});
Future<void> clear();
}
class CacheServiceImp implements CacheService {
SharedPreferences sharedPreferences;
final SharedPreferences sharedPreferences;
final LoggerService loggerService;
CacheServiceImp({
required this.sharedPreferences,
required this.loggerService,
});
@override
Future<void> saveString({required String key, required String value}) async {
await sharedPreferences.setString(key, value);
}
@override
Future<void> saveInt({required String key, required int value}) async {
await sharedPreferences.setInt(key, value);
}
@override
Future<void> saveDouble({required String key, required double value}) async {
await sharedPreferences.setDouble(key, value);
}
@override
Future<void> saveBool({required String key, required bool value}) async {
await sharedPreferences.setBool(key, value);
}
@override
Future<void> saveStringList({required String key, required List<String> value}) async {
await sharedPreferences.setStringList(key, value);
}
@override
String? getString({required String key}) => sharedPreferences.getString(key);
@override
int? getInt({required String key}) => sharedPreferences.getInt(key);
@override
double? getDouble({required String key}) => sharedPreferences.getDouble(key);
@override
bool? getBool({required String key}) => sharedPreferences.getBool(key);
@override
List<String>? getStringList({required String key}) => sharedPreferences.getStringList(key);
@override
Future<void> remove({required String key}) async {
await sharedPreferences.remove(key);
}
CacheServiceImp({required this.sharedPreferences});
@override
Future<dynamic> getObject({required String key}) async {
try {
await sharedPreferences.reload();
var string = sharedPreferences.getString(key);
if (string == null) return null;
return json.decode(string);
} catch (ex) {
loggerService.errorLogs(ex.toString());
return null;
}
}
@override
Future<void> saveObject({required String key, required dynamic value}) async {
try {
await sharedPreferences.setString(key, json.encode(value));
} catch (ex) {
loggerService.errorLogs(ex.toString());
}
}
@override
Future<void> clear() async {
await sharedPreferences.clear();
}
}

@ -3,7 +3,7 @@ import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
abstract class DialogService {
Future<void> showErrorDialog({required String message, Function()? onOkPressed});
Future<void> showErrorBottomSheet({required String message, Function()? onOkPressed});
}
class DialogServiceImp implements DialogService {
@ -12,7 +12,7 @@ class DialogServiceImp implements DialogService {
DialogServiceImp({required this.navigationService});
@override
Future<void> showErrorDialog({required String message, Function()? onOkPressed}) async {
Future<void> showErrorBottomSheet({required String message, Function()? onOkPressed}) async {
final context = navigationService.navigatorKey.currentContext;
if (context == null) return;

@ -2,6 +2,7 @@ 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/core/utils/loading_utils.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';
@ -45,11 +46,15 @@ class ErrorHandlerServiceImp implements ErrorHandlerService {
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", Function()? onOkPressed}) async {
await dialogService.showErrorDialog(message: failure.message, onOkPressed: onOkPressed);
if (LoadingUtils.isLoading) {
LoadingUtils.hideFullScreenLoader();
}
await dialogService.showErrorBottomSheet(message: failure.message, onOkPressed: onOkPressed);
}
}

@ -0,0 +1,31 @@
import 'package:firebase_messaging/firebase_messaging.dart' show FirebaseMessaging;
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class FirebaseService {
Future<String?> getDeviceToken();
}
class FirebaseServiceImpl implements FirebaseService {
final FirebaseMessaging firebaseMessaging;
final LoggerService loggerService;
final AppState appState;
FirebaseServiceImpl({
required this.firebaseMessaging,
required this.loggerService,
required this.appState,
});
@override
Future<String> getDeviceToken() async {
try {
String? deviceToken = await firebaseMessaging.getToken();
appState.setDeviceToken = deviceToken;
return deviceToken ?? "";
} catch (e) {
loggerService.logInfo(e.toString());
return "";
}
}
}

@ -1,8 +1,6 @@
import 'package:logger/logger.dart';
abstract class LoggerService {
void errorLogs(String message);
void logInfo(String message);
@ -13,8 +11,6 @@ class LoggerServiceImp implements LoggerService {
LoggerServiceImp({required this.logger});
@override
void errorLogs(String message) {
logger.e(message);
@ -22,6 +18,6 @@ class LoggerServiceImp implements LoggerService {
@override
void logInfo(String message) {
logger.i(message);
logger.d(message);
}
}

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/authentication/widgets/otp_verification_screen.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@ -12,4 +13,38 @@ class NavigationService {
void pop<T extends Object?>([T? result]) {
navigatorKey.currentState!.pop(result);
}
void popUntilNamed(String routeName) {
navigatorKey.currentState?.popUntil(ModalRoute.withName(routeName));
}
Future<T?> pushToOtpScreen<T>({
required String phoneNumber,
required Function(int code) checkActivationCode,
required Function(String phoneNumber) onResendOTPPressed,
}) {
return navigatorKey.currentState!.push(
MaterialPageRoute(
builder: (_) => OTPVerificationScreen(
phoneNumber: phoneNumber,
checkActivationCode: checkActivationCode,
onResendOTPPressed: onResendOTPPressed,
),
),
);
}
Future<T?> pushPage<T>({
required Widget page,
bool fullscreenDialog = false,
bool maintainState = true,
}) {
return navigatorKey.currentState!.push<T>(
MaterialPageRoute(
builder: (_) => page,
fullscreenDialog: fullscreenDialog,
maintainState: maintainState,
),
);
}
}

@ -16,7 +16,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
import 'core/consts.dart';
import 'core/cache_consts.dart';
import 'core/utils/local_notifications.dart';
import 'core/utils/push_notification_handler.dart';

@ -1,4 +1,5 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -25,6 +26,7 @@ class GenericBottomSheet extends StatefulWidget {
// FocusNode myFocusNode;
GenericBottomSheet({
super.key,
this.countryCode = "",
this.initialPhoneNumber = "",
required this.buttons,
@ -47,7 +49,7 @@ class _GenericBottomSheetState extends State<GenericBottomSheet> {
super.initState();
if (!widget.isForEmail && widget.textController != null) {
widget.textController!.text = widget.initialPhoneNumber!;
widget.textController!.text = widget.initialPhoneNumber ?? "";
}
}

@ -34,13 +34,13 @@ class TextInputWidget extends StatelessWidget {
final bool hasError;
final String? errorMessage;
Function(CountryEnum)? onCountryChange;
SelectionTypeEnum? selectionType;
final SelectionTypeEnum? selectionType;
// final List<Country> countryList;
// final Function(Country)? onCountryChange;
TextInputWidget({
Key? key,
super.key,
required this.labelText,
required this.hintText,
this.controller,
@ -63,7 +63,7 @@ class TextInputWidget extends StatelessWidget {
this.selectionType,
// this.countryList = const [],
// this.onCountryChange,
}) : super(key: key);
});
@override
Widget build(BuildContext context) {

File diff suppressed because it is too large Load Diff

@ -33,10 +33,10 @@ dependencies:
provider: ^6.1.5+1
get_it: ^8.2.0
just_audio: ^0.10.4
# flutter_callkit_incoming:
# git:
# url: https://github.com/hiennguyen92/flutter_callkit_incoming.git
# ref: dev
# flutter_callkit_incoming:
# git:
# url: https://github.com/hiennguyen92/flutter_callkit_incoming.git
# ref: dev
url_launcher: ^6.3.2
logger: ^2.6.1
lottie: ^3.3.1
@ -64,6 +64,7 @@ dependencies:
equatable: ^2.0.7
google_api_availability: ^5.0.1
firebase_analytics: ^11.5.1
gif_view: ^1.0.3
jiffy: ^6.4.3
hijri_gregorian_calendar: ^0.0.4
@ -92,24 +93,24 @@ flutter:
fonts:
- family: Poppins
fonts:
# - asset: assets/fonts/poppins/Poppins-Black.ttf
# weight: 900
# - asset: assets/fonts/poppins/Poppins-ExtraBold.ttf
# weight: 800
# - asset: assets/fonts/poppins/Poppins-Bold.ttf
# weight: 700
# - asset: assets/fonts/poppins/Poppins-Black.ttf
# weight: 900
# - asset: assets/fonts/poppins/Poppins-ExtraBold.ttf
# weight: 800
# - asset: assets/fonts/poppins/Poppins-Bold.ttf
# weight: 700
- asset: assets/fonts/poppins/Poppins-SemiBold.ttf
weight: 600
- asset: assets/fonts/poppins/Poppins-Medium.ttf
weight: 500
- asset: assets/fonts/poppins/Poppins-Regular.ttf
weight: 400
# - asset: assets/fonts/poppins/Poppins-Light.ttf
# weight: 300
# - asset: assets/fonts/poppins/Poppins-ExtraLight.ttf
# weight: 200
# - asset: assets/fonts/poppins/Poppins-Thin.ttf
# weight: 100
# - asset: assets/fonts/poppins/Poppins-Light.ttf
# weight: 300
# - asset: assets/fonts/poppins/Poppins-ExtraLight.ttf
# weight: 200
# - asset: assets/fonts/poppins/Poppins-Thin.ttf
# weight: 100
- family: GESSTwo

Loading…
Cancel
Save