diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index d43ca93..a6f033c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -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 post( String endPoint, { required Map 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(); - - 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 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(); String url; if (isExternal) { url = endPoint; @@ -111,39 +106,19 @@ class ApiClientImp implements ApiClient { } } try { - var user = appState.getAuthenticatedUser; + var user = _appState.getAuthenticatedUser; Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; if (!isExternal) { - String? token = appState.appAuthToken; - String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en'); - 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); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 11c44ba..e79a724 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -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 packagesAuthHeader = {}; - -} \ No newline at end of file + 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"; +} diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index eb9315c..a709799 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -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 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; } diff --git a/lib/core/cache_consts.dart b/lib/core/cache_consts.dart new file mode 100644 index 0000000..b793f02 --- /dev/null +++ b/lib/core/cache_consts.dart @@ -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'; +} diff --git a/lib/core/consts.dart b/lib/core/consts.dart deleted file mode 100644 index 216b9a7..0000000 --- a/lib/core/consts.dart +++ /dev/null @@ -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'; -} diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index aa32fa6..a900742 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -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(() => LoggerServiceImp(logger: logger)); + getIt.registerLazySingleton(() => FirebaseServiceImpl( + loggerService: getIt(), + appState: getIt(), + firebaseMessaging: FirebaseMessaging.instance, + )); + getIt.registerLazySingleton(() => NavigationService()); getIt.registerLazySingleton(() => GAnalytics()); getIt.registerLazySingleton(() => AppState(navigationService: getIt())); @@ -56,8 +64,8 @@ class AppDependencies { )); final sharedPreferences = await SharedPreferences.getInstance(); - getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences)); - getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt(), dialogService: getIt(), appState: getIt())); + getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences, loggerService: getIt())); + getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt(), appState: getIt())); // Repositories getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); @@ -103,6 +111,8 @@ class AppDependencies { getIt.registerLazySingleton( () => AuthenticationViewModel( authenticationRepo: getIt(), + cacheService: getIt(), + navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), diff --git a/lib/core/enums.dart b/lib/core/enums.dart index 34aa911..ab5cac1 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -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) { diff --git a/lib/core/exceptions/api_failure.dart b/lib/core/exceptions/api_failure.dart index 4bc5097..c950195 100644 --- a/lib/core/exceptions/api_failure.dart +++ b/lib/core/exceptions/api_failure.dart @@ -13,6 +13,20 @@ class ServerFailure extends Failure { List get props => [message]; } +class UserIntimationFailure extends Failure { + const UserIntimationFailure(super.message); + + @override + List get props => [message]; +} + +class MessageStatusFailure extends Failure { + const MessageStatusFailure(super.message); + + @override + List get props => [message]; +} + class StatusCodeFailure extends Failure { const StatusCodeFailure(super.message); @@ -48,7 +62,6 @@ class UnknownFailure extends Failure { List get props => [message]; } - class DuplicateUsername extends Failure { const DuplicateUsername(String? message) : super(message ?? ''); @@ -62,5 +75,3 @@ class InvalidCredentials extends Failure { @override List get props => [message]; } - - diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index dc6a0d6..d556034 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -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; diff --git a/lib/core/post_params_model.dart b/lib/core/post_params_model.dart index 2f981f6..cf52306 100644 --- a/lib/core/post_params_model.dart +++ b/lib/core/post_params_model.dart @@ -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 json) { versionID = json['VersionID']; diff --git a/lib/core/utils/loading_utils.dart b/lib/core/utils/loading_utils.dart new file mode 100644 index 0000000..7390d56 --- /dev/null +++ b/lib/core/utils/loading_utils.dart @@ -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(); + + 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 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"), + ), + ), + ); + } +} diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index b5a816e..1d2141e 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -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 requestPermissions() async { try { if (Platform.isIOS) { - await flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation() - ?.requestPermissions(alert: true, badge: true, sound: true); + await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); } else if (Platform.isAndroid) { Map statuses = await [ Permission.notification, diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart index 1869923..e83dd46 100644 --- a/lib/core/utils/request_utils.dart +++ b/lib/core/utils/request_utils.dart @@ -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; diff --git a/lib/core/utils/size_config.dart b/lib/core/utils/size_config.dart index 9c09b09..9f9d835 100644 --- a/lib/core/utils/size_config.dart +++ b/lib/core/utils/size_config.dart @@ -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; diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index ed4770d..b539630 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -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 uniqueBy(List 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'', multiLine: true), '\n') - .replaceAll(RegExp(r'<\/p>', multiLine: true), '\n') - .replaceAll(RegExp(r'', multiLine: true), '\n'); + var withLineBreaks = + htmlString.replaceAll(RegExp(r'', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'', multiLine: true), '\n'); // Remove all other HTML tags var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), ''); @@ -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 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(); - - - 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; - } -} - - diff --git a/lib/core/utils/validation_utils.dart b/lib/core/utils/validation_utils.dart new file mode 100644 index 0000000..cb54af5 --- /dev/null +++ b/lib/core/utils/validation_utils.dart @@ -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(); + + 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; + } +} diff --git a/lib/extensions/route_extensions.dart b/lib/extensions/route_extensions.dart index 71f5d2d..0dcc54b 100644 --- a/lib/extensions/route_extensions.dart +++ b/lib/extensions/route_extensions.dart @@ -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)); + } } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 0be6eaf..f8ceff4 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -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>> checkPatientAuthentication({ - required CheckPatientAuthenticationReq checkPatientAuthenticationReq, + Future>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq}); + + Future>> sendActivationCodeRepo({ + required dynamic sendActivationCodeReq, + String? languageID, + bool isRegister = false, }); - Future>> sendActivationCodeRegister({required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}); + Future>> 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( messageStatus: messageStatus, statusCode: statusCode, - errorMessage: null, + errorMessage: errorMessage, data: model, ); } catch (e) { @@ -70,33 +75,26 @@ class AuthenticationRepoImp implements AuthenticationRepo { @override Future>> 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? 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( messageStatus: messageStatus, statusCode: statusCode, - errorMessage: null, + errorMessage: errorMessage, data: response, ); } catch (e) { @@ -113,41 +111,86 @@ class AuthenticationRepoImp implements AuthenticationRepo { } @override - Future>> sendActivationCodeRegister({required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}) async { - int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; - //TODO : We will use all these from AppState directly in the ApiClient - - checkPatientAuthenticationReq.versionID = VERSION_ID; - checkPatientAuthenticationReq.channel = CHANNEL; - checkPatientAuthenticationReq.iPAdress = IP_ADDRESS; - checkPatientAuthenticationReq.generalid = GENERAL_ID; - checkPatientAuthenticationReq.languageID = (languageID == 'ar' ? 1 : 2); - checkPatientAuthenticationReq.deviceTypeID = Platform.isIOS ? 1 : 2; - checkPatientAuthenticationReq.patientOutSA = isOutKsa; - checkPatientAuthenticationReq.isDentalAllowedBackend = false; + Future>> 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? 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( + 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>> 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? 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( 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!); diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index c34c339..e856d3e 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -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? 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 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 selectDeviceImei({Function(dynamic)? onSuccess, Function(String)? onError}) async { - String firebaseToken = "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"; - final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); + Future 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 _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 _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 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 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 checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { -// CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( -// phoneNumber: '0567184134', -// otpTypeEnum: OTPTypeEnum.sms, -// deviceToken: 'dummyDeviceToken123', -// patientOutSA: true, -// loginTokenID: 'dummyLoginToken456', -// registeredData: null, -// patientId: 12345, -// nationIdText: '1234567890', -// countryCode: 'SA', -// ); -// -// final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); -// result.fold( -// (failure) async => await errorHandlerService.handleError(failure: failure), -// (apiResponse) { -// if (apiResponse.data['isSMSSent']) { -// // TODO: set this in AppState -// // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); -// // loginTokenID = value['LogInTokenID'], -// // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), -// sendActivationCode(type); -// } else { -// if (apiResponse.data['IsAuthenticated']) { -// checkActivationCode(onWrongActivationCode: (String? message) {}); -// } -// } -// }, -// ); -// } - -// Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { -// var request = RequestUtils.getCommonRequestAuthProvider( -// otpTypeEnum: otpTypeEnum, -// registeredData: null, -// deviceToken: "dummyLoginToken456", -// mobileNumber: "0567184134", -// zipCode: "SA", -// patientOutSA: true, -// loginTokenID: "dummyLoginToken456", -// selectedOption: selectedOption, -// patientId: 12345, -// ); -// -// request.sMSSignature = await SMSOTP.getSignature(); -// selectedOption = type; -// // GifLoaderDialogUtils.showMyDialog(context); -// if (healthId != null || isDubai) { -// if (!isDubai) { -// request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); -// } -// request.healthId = healthId; -// request.isHijri = isHijri; -// await this.apiClient.sendActivationCodeRegister(request).then((result) { -// // GifLoaderDialogUtils.hideDialog(context); -// if (result != null && result['isSMSSent'] == true) { -// this.startSMSService(type); -// } -// }).catchError((r) { -// GifLoaderDialogUtils.hideDialog(context); -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: r.toString(), -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// )); -// // AppToast.showErrorToast(message: r); -// }); -// } else { -// request.dob = ""; -// request.healthId = ""; -// request.isHijri = 0; -// await this.authService.sendActivationCode(request).then((result) { -// GifLoaderDialogUtils.hideDialog(context); -// if (result != null && result['isSMSSent'] == true) { -// this.startSMSService(type); -// } -// }).catchError((r) { -// GifLoaderDialogUtils.hideDialog(context); -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: r.toString(), -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// )); -// // AppToast.showErrorToast(message: r.toString()); -// }); -// } -// } + Future 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); + 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); + 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 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 onWrongActivationCode({String? message}) async { + // TODO: HANDLE THIS VIA BOTTOM SHEET + } + + @override + void dispose() { + nationalIdController.dispose(); + phoneNumberController.dispose(); + myFocusNode.dispose(); + super.dispose(); + } } diff --git a/lib/features/authentication/models/request_models/check_activation_code_register_request_model.dart b/lib/features/authentication/models/request_models/check_activation_code_register_request_model.dart new file mode 100644 index 0000000..d752a13 --- /dev/null +++ b/lib/features/authentication/models/request_models/check_activation_code_register_request_model.dart @@ -0,0 +1,121 @@ +class CheckActivationCodeRegisterReq { + int? patientMobileNumber; + String? mobileNo; + String? deviceToken; + bool? projectOutSA; + int? loginType; + String? zipCode; + bool? isRegister; + String? logInTokenID; + int? searchType; + int? patientID; + String? nationalID; + String? patientIdentificationID; + String? activationCode; + bool? isSilentLogin; + double? versionID; + int? channel; + int? languageID; + String? iPAdress; + String? generalid; + int? patientOutSA; + dynamic sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + bool? forRegisteration; + String? dob; + int? isHijri; + String? healthId; + + CheckActivationCodeRegisterReq({ + this.patientMobileNumber, + this.mobileNo, + this.deviceToken, + this.projectOutSA, + this.loginType, + this.zipCode, + this.isRegister, + this.logInTokenID, + this.searchType, + this.patientID, + this.nationalID, + this.patientIdentificationID, + this.activationCode, + this.isSilentLogin, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.forRegisteration, + this.dob, + this.isHijri, + this.healthId, + }); + + CheckActivationCodeRegisterReq.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + mobileNo = json['MobileNo']; + deviceToken = json['DeviceToken']; + projectOutSA = json['ProjectOutSA']; + loginType = json['LoginType']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + logInTokenID = json['LogInTokenID']; + searchType = json['SearchType']; + patientID = json['PatientID']; + nationalID = json['NationalID']; + patientIdentificationID = json['PatientIdentificationID']; + activationCode = json['activationCode']; + isSilentLogin = json['IsSilentLogin']; + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + forRegisteration = json['ForRegisteration']; + dob = json['DOB']; + isHijri = json['IsHijri']; + healthId = json['HealthId']; + } + + Map toJson() { + final Map data = {}; + 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; + } +} diff --git a/lib/features/authentication/models/request_models/send_activation_request_model.dart b/lib/features/authentication/models/request_models/send_activation_request_model.dart index dc3d55d..360efd4 100644 --- a/lib/features/authentication/models/request_models/send_activation_request_model.dart +++ b/lib/features/authentication/models/request_models/send_activation_request_model.dart @@ -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 json) { patientMobileNumber = json['PatientMobileNumber']; diff --git a/lib/widgets/otp/otp.dart b/lib/features/authentication/widgets/otp_verification_screen.dart similarity index 92% rename from lib/widgets/otp/otp.dart rename to lib/features/authentication/widgets/otp_verification_screen.dart index 81c375b..9ea1b9e 100644 --- a/lib/widgets/otp/otp.dart +++ b/lib/features/authentication/widgets/otp_verification_screen.dart @@ -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 createState() => _OTPVerificationPageState(); + State createState() => _OTPVerificationScreenState(); } -class _OTPVerificationPageState extends State { +class _OTPVerificationScreenState extends State { final int _otpLength = 4; late final List _controllers; late final List _focusNodes; @@ -41,8 +49,12 @@ class _OTPVerificationPageState extends State { @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(); } diff --git a/lib/features/insurance/insurance_repo.dart b/lib/features/insurance/insurance_repo.dart index a5c624f..cb06724 100644 --- a/lib/features/insurance/insurance_repo.dart +++ b/lib/features/insurance/insurance_repo.dart @@ -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) { diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart index 326379c..d746c69 100644 --- a/lib/features/lab/lab_repo.dart +++ b/lib/features/lab/lab_repo.dart @@ -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) { diff --git a/lib/features/prescriptions/prescriptions_repo.dart b/lib/features/prescriptions/prescriptions_repo.dart index de7bc4b..f584f7b 100644 --- a/lib/features/prescriptions/prescriptions_repo.dart +++ b/lib/features/prescriptions/prescriptions_repo.dart @@ -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) { diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart index d3e4f3d..2917dfd 100644 --- a/lib/features/radiology/radiology_repo.dart +++ b/lib/features/radiology/radiology_repo.dart @@ -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) { diff --git a/lib/main.dart b/lib/main.dart index ce69f5d..53825c8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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 callAppStateInitializations() async { + final String deviceTypeId = (Platform.isIOS + ? "1" + : await Utils.isGoogleServicesAvailable() + ? "2" + : "3"); + AppState appState = getIt.get(); + appState.setDeviceTypeID = deviceTypeId; +} + Future callInitializations() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); @@ -41,6 +53,7 @@ Future 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()), diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index aef877f..f6e725a 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -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 { +class LoginScreenState extends State { @override void initState() { super.initState(); @@ -83,7 +88,7 @@ class _LoginScreen extends State { 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 { ); } - 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 { 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, diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index 4756cba..e51792c 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -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 { 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 { // } else { // registerUser(1); // } - Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => OTPVerificationPage(phoneNumber: '12234567'))); }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedBorderColor, diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart index 483ce5c..151a4c8 100644 --- a/lib/presentation/authentication/register_step2.dart +++ b/lib/presentation/authentication/register_step2.dart @@ -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 { 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 { 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 { ) : 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 { ? Selector? countriesList, NationalityCountries? selectedCountry, bool isArabic})>( selector: (context, authViewModel) { final appState = getIt.get(); - 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) { diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index 8474422..ad524e3 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -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'; diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index e863dab..835fb4e 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.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 { @override Widget build(BuildContext context) { AppState appState = getIt.get(); + NavigationService navigationService = getIt.get(); final AuthenticationViewModel authenticationViewModel = context.read(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -51,8 +52,7 @@ class _LandingPageState extends State { 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 { 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 { ) : 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( diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index d16cc62..4369157 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -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 get routes => { initialRoute: (context) => SplashPage(), - login: (context) => LoginScreen(), + loginScreen: (context) => LoginScreen(), }; } diff --git a/lib/services/cache_service.dart b/lib/services/cache_service.dart index f25409e..8a015d8 100644 --- a/lib/services/cache_service.dart +++ b/lib/services/cache_service.dart @@ -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 saveString({required String key, required String value}); + Future saveInt({required String key, required int value}); + + Future saveDouble({required String key, required double value}); + + Future saveBool({required String key, required bool value}); + + Future saveStringList({required String key, required List value}); + + String? getString({required String key}); + + int? getInt({required String key}); + + double? getDouble({required String key}); + + bool? getBool({required String key}); + + List? getStringList({required String key}); + + Future getObject({required String key}); + + Future saveObject({required String key, required dynamic value}); + + Future remove({required String key}); + + Future clear(); } class CacheServiceImp implements CacheService { - SharedPreferences sharedPreferences; + final SharedPreferences sharedPreferences; + final LoggerService loggerService; + + CacheServiceImp({ + required this.sharedPreferences, + required this.loggerService, + }); + + @override + Future saveString({required String key, required String value}) async { + await sharedPreferences.setString(key, value); + } + + @override + Future saveInt({required String key, required int value}) async { + await sharedPreferences.setInt(key, value); + } + + @override + Future saveDouble({required String key, required double value}) async { + await sharedPreferences.setDouble(key, value); + } + + @override + Future saveBool({required String key, required bool value}) async { + await sharedPreferences.setBool(key, value); + } + + @override + Future saveStringList({required String key, required List 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? getStringList({required String key}) => sharedPreferences.getStringList(key); + + @override + Future remove({required String key}) async { + await sharedPreferences.remove(key); + } - CacheServiceImp({required this.sharedPreferences}); + @override + Future 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 saveObject({required String key, required dynamic value}) async { + try { + await sharedPreferences.setString(key, json.encode(value)); + } catch (ex) { + loggerService.errorLogs(ex.toString()); + } + } + @override + Future clear() async { + await sharedPreferences.clear(); + } } diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index af5af9c..28b77e1 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -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 showErrorDialog({required String message, Function()? onOkPressed}); + Future showErrorBottomSheet({required String message, Function()? onOkPressed}); } class DialogServiceImp implements DialogService { @@ -12,7 +12,7 @@ class DialogServiceImp implements DialogService { DialogServiceImp({required this.navigationService}); @override - Future showErrorDialog({required String message, Function()? onOkPressed}) async { + Future showErrorBottomSheet({required String message, Function()? onOkPressed}) async { final context = navigationService.navigatorKey.currentContext; if (context == null) return; diff --git a/lib/services/error_handler_service.dart b/lib/services/error_handler_service.dart index a26d264..59a0205 100644 --- a/lib/services/error_handler_service.dart +++ b/lib/services/error_handler_service.dart @@ -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 _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); } } diff --git a/lib/services/firebase_service.dart b/lib/services/firebase_service.dart new file mode 100644 index 0000000..f6c712e --- /dev/null +++ b/lib/services/firebase_service.dart @@ -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 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 getDeviceToken() async { + try { + String? deviceToken = await firebaseMessaging.getToken(); + appState.setDeviceToken = deviceToken; + return deviceToken ?? ""; + } catch (e) { + loggerService.logInfo(e.toString()); + return ""; + } + } +} diff --git a/lib/services/logger_service.dart b/lib/services/logger_service.dart index 0b33c52..9df6633 100644 --- a/lib/services/logger_service.dart +++ b/lib/services/logger_service.dart @@ -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); } } diff --git a/lib/services/navigation_service.dart b/lib/services/navigation_service.dart index d814cf5..6dd4a54 100644 --- a/lib/services/navigation_service.dart +++ b/lib/services/navigation_service.dart @@ -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 navigatorKey = GlobalKey(); @@ -12,4 +13,38 @@ class NavigationService { void pop([T? result]) { navigatorKey.currentState!.pop(result); } + + void popUntilNamed(String routeName) { + navigatorKey.currentState?.popUntil(ModalRoute.withName(routeName)); + } + + Future pushToOtpScreen({ + 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 pushPage({ + required Widget page, + bool fullscreenDialog = false, + bool maintainState = true, + }) { + return navigatorKey.currentState!.push( + MaterialPageRoute( + builder: (_) => page, + fullscreenDialog: fullscreenDialog, + maintainState: maintainState, + ), + ); + } } diff --git a/lib/splashPage.dart b/lib/splashPage.dart index 6136d22..b852cd4 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -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'; diff --git a/lib/widgets/bottomsheet/generic_bottom_sheet.dart b/lib/widgets/bottomsheet/generic_bottom_sheet.dart index 08bf849..74062ef 100644 --- a/lib/widgets/bottomsheet/generic_bottom_sheet.dart +++ b/lib/widgets/bottomsheet/generic_bottom_sheet.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 { super.initState(); if (!widget.isForEmail && widget.textController != null) { - widget.textController!.text = widget.initialPhoneNumber!; + widget.textController!.text = widget.initialPhoneNumber ?? ""; } } diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 0f520c6..53a0130 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -34,13 +34,13 @@ class TextInputWidget extends StatelessWidget { final bool hasError; final String? errorMessage; Function(CountryEnum)? onCountryChange; - SelectionTypeEnum? selectionType; + final SelectionTypeEnum? selectionType; // final List 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) { diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index c503e1b..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,1640 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _flutterfire_internals: - dependency: transitive - description: - name: _flutterfire_internals - sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 - url: "https://pub.dev" - source: hosted - version: "1.3.59" - archive: - dependency: transitive - description: - name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.dev" - source: hosted - version: "4.0.7" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" - source: hosted - version: "2.12.0" - audio_session: - dependency: transitive - description: - name: audio_session - sha256: "2b7fff16a552486d078bfc09a8cde19f426dc6d6329262b684182597bec5b1ac" - url: "https://pub.dev" - source: hosted - version: "0.1.25" - auto_size_text: - dependency: "direct main" - description: - name: auto_size_text - sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - cached_network_image: - dependency: "direct main" - description: - name: cached_network_image - sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - cached_network_image_platform_interface: - dependency: transitive - description: - name: cached_network_image_platform_interface - sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - cached_network_image_web: - dependency: transitive - description: - name: cached_network_image_web - sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - carp_serializable: - dependency: transitive - description: - name: carp_serializable - sha256: f039f8ea22e9437aef13fe7e9743c3761c76d401288dcb702eadd273c3e4dcef - url: "https://pub.dev" - source: hosted - version: "2.0.1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - connectivity_plus: - dependency: "direct main" - description: - name: connectivity_plus - sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec - url: "https://pub.dev" - source: hosted - version: "6.1.5" - connectivity_plus_platform_interface: - dependency: transitive - description: - name: connectivity_plus_platform_interface - sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" - url: "https://pub.dev" - source: hosted - version: "0.3.4+2" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - dartz: - dependency: "direct main" - description: - name: dartz - sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - dbus: - dependency: transitive - description: - name: dbus - sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" - url: "https://pub.dev" - source: hosted - version: "0.7.11" - device_calendar: - dependency: "direct main" - description: - path: "." - ref: HEAD - resolved-ref: "5ea5ed9e2bb499c0633383b53103f2920b634755" - url: "https://github.com/bardram/device_calendar" - source: git - version: "4.3.1" - device_info_plus: - dependency: "direct main" - description: - name: device_info_plus - sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" - url: "https://pub.dev" - source: hosted - version: "11.5.0" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.dev" - source: hosted - version: "7.0.3" - dropdown_search: - dependency: "direct main" - description: - name: dropdown_search - sha256: c29b3e5147a82a06a4a08b3b574c51cb48cc17ad89893d53ee72a6f86643622e - url: "https://pub.dev" - source: hosted - version: "6.0.2" - easy_localization: - dependency: "direct main" - description: - name: easy_localization - sha256: "2ccdf9db8fe4d9c5a75c122e6275674508fd0f0d49c827354967b8afcc56bbed" - url: "https://pub.dev" - source: hosted - version: "3.0.8" - easy_logger: - dependency: transitive - description: - name: easy_logger - sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 - url: "https://pub.dev" - source: hosted - version: "0.0.2" - equatable: - dependency: "direct main" - description: - name: equatable - sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" - url: "https://pub.dev" - source: hosted - version: "2.0.7" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - file_picker: - dependency: "direct main" - description: - name: file_picker - sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22 - url: "https://pub.dev" - source: hosted - version: "10.3.2" - file_selector_linux: - dependency: transitive - description: - name: file_selector_linux - sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" - url: "https://pub.dev" - source: hosted - version: "0.9.3+2" - file_selector_macos: - dependency: transitive - description: - name: file_selector_macos - sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c" - url: "https://pub.dev" - source: hosted - version: "0.9.4+4" - file_selector_platform_interface: - dependency: transitive - description: - name: file_selector_platform_interface - sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b - url: "https://pub.dev" - source: hosted - version: "2.6.2" - file_selector_windows: - dependency: transitive - description: - name: file_selector_windows - sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" - url: "https://pub.dev" - source: hosted - version: "0.9.3+4" - firebase_analytics: - dependency: "direct main" - description: - name: firebase_analytics - sha256: "4f85b161772e1d54a66893ef131c0a44bd9e552efa78b33d5f4f60d2caa5c8a3" - url: "https://pub.dev" - source: hosted - version: "11.6.0" - firebase_analytics_platform_interface: - dependency: transitive - description: - name: firebase_analytics_platform_interface - sha256: a44b6d1155ed5cae7641e3de7163111cfd9f6f6c954ca916dc6a3bdfa86bf845 - url: "https://pub.dev" - source: hosted - version: "4.4.3" - firebase_analytics_web: - dependency: transitive - description: - name: firebase_analytics_web - sha256: c7d1ed1f86ae64215757518af5576ff88341c8ce5741988c05cc3b2e07b0b273 - url: "https://pub.dev" - source: hosted - version: "0.5.10+16" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" - url: "https://pub.dev" - source: hosted - version: "3.15.2" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" - url: "https://pub.dev" - source: hosted - version: "2.24.1" - firebase_messaging: - dependency: "direct main" - description: - name: firebase_messaging - sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" - url: "https://pub.dev" - source: hosted - version: "15.2.10" - firebase_messaging_platform_interface: - dependency: transitive - description: - name: firebase_messaging_platform_interface - sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" - url: "https://pub.dev" - source: hosted - version: "4.6.10" - firebase_messaging_web: - dependency: transitive - description: - name: firebase_messaging_web - sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" - url: "https://pub.dev" - source: hosted - version: "3.10.10" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - fl_chart: - dependency: "direct main" - description: - name: fl_chart - sha256: "577aeac8ca414c25333334d7c4bb246775234c0e44b38b10a82b559dd4d764e7" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_cache_manager: - dependency: transitive - description: - name: flutter_cache_manager - sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - flutter_hooks: - dependency: transitive - description: - name: flutter_hooks - sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 - url: "https://pub.dev" - source: hosted - version: "0.20.5" - flutter_inappwebview: - dependency: "direct main" - description: - name: flutter_inappwebview - sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" - source: hosted - version: "6.1.5" - flutter_inappwebview_android: - dependency: transitive - description: - name: flutter_inappwebview_android - sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" - source: hosted - version: "1.1.3" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - name: flutter_inappwebview_internal_annotations - sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - flutter_inappwebview_ios: - dependency: transitive - description: - name: flutter_inappwebview_ios - sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_macos: - dependency: transitive - description: - name: flutter_inappwebview_macos - sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_platform_interface: - dependency: transitive - description: - name: flutter_inappwebview_platform_interface - sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" - source: hosted - version: "1.3.0+1" - flutter_inappwebview_web: - dependency: transitive - description: - name: flutter_inappwebview_web - sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_windows: - dependency: transitive - description: - name: flutter_inappwebview_windows - sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - flutter_ios_voip_kit_karmm: - dependency: "direct main" - description: - name: flutter_ios_voip_kit_karmm - sha256: "31a445d78aacacdf128a0354efb9f4e424285dfe4c0af3ea872e64f03e6f6bfc" - url: "https://pub.dev" - source: hosted - version: "0.8.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - flutter_local_notifications: - dependency: "direct main" - description: - name: flutter_local_notifications - sha256: a9966c850de5e445331b854fa42df96a8020066d67f125a5964cbc6556643f68 - url: "https://pub.dev" - source: hosted - version: "19.4.1" - flutter_local_notifications_linux: - dependency: transitive - description: - name: flutter_local_notifications_linux - sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_local_notifications_platform_interface: - dependency: transitive - description: - name: flutter_local_notifications_platform_interface - sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" - url: "https://pub.dev" - source: hosted - version: "9.1.0" - flutter_local_notifications_windows: - dependency: transitive - description: - name: flutter_local_notifications_windows - sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98 - url: "https://pub.dev" - source: hosted - version: "1.0.2" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31 - url: "https://pub.dev" - source: hosted - version: "2.0.30" - flutter_rating_bar: - dependency: "direct main" - description: - name: flutter_rating_bar - sha256: d2af03469eac832c591a1eba47c91ecc871fe5708e69967073c043b2d775ed93 - url: "https://pub.dev" - source: hosted - version: "4.0.1" - flutter_staggered_animations: - dependency: "direct main" - description: - name: flutter_staggered_animations - sha256: "81d3c816c9bb0dca9e8a5d5454610e21ffb068aedb2bde49d2f8d04f75538351" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845 - url: "https://pub.dev" - source: hosted - version: "2.2.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_zoom_videosdk: - dependency: "direct main" - description: - name: flutter_zoom_videosdk - sha256: "46a4dea664b1c969099328a499c198a1755adf9ac333dea28bea5187910b3bf9" - url: "https://pub.dev" - source: hosted - version: "2.1.10" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" - url: "https://pub.dev" - source: hosted - version: "8.2.12" - geoclue: - dependency: transitive - description: - name: geoclue - sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f - url: "https://pub.dev" - source: hosted - version: "0.1.1" - geolocator: - dependency: "direct main" - description: - name: geolocator - sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" - url: "https://pub.dev" - source: hosted - version: "14.0.2" - geolocator_android: - dependency: transitive - description: - name: geolocator_android - sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" - url: "https://pub.dev" - source: hosted - version: "5.0.2" - geolocator_apple: - dependency: transitive - description: - name: geolocator_apple - sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 - url: "https://pub.dev" - source: hosted - version: "2.3.13" - geolocator_linux: - dependency: transitive - description: - name: geolocator_linux - sha256: c4e966f0a7a87e70049eac7a2617f9e16fd4c585a26e4330bdfc3a71e6a721f3 - url: "https://pub.dev" - source: hosted - version: "0.2.3" - geolocator_platform_interface: - dependency: transitive - description: - name: geolocator_platform_interface - sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" - url: "https://pub.dev" - source: hosted - version: "4.2.6" - geolocator_web: - dependency: transitive - description: - name: geolocator_web - sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 - url: "https://pub.dev" - source: hosted - version: "4.1.3" - geolocator_windows: - dependency: transitive - description: - name: geolocator_windows - sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" - url: "https://pub.dev" - source: hosted - version: "0.2.5" - get_it: - dependency: "direct main" - description: - name: get_it - sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b - url: "https://pub.dev" - source: hosted - version: "8.2.0" - google_api_availability: - dependency: "direct main" - description: - name: google_api_availability - sha256: "2ffdc91e1e0cf4e7974fef6c2988a24cefa81f03526ff04b694df6dc0fcbca03" - url: "https://pub.dev" - source: hosted - version: "5.0.1" - google_api_availability_android: - dependency: transitive - description: - name: google_api_availability_android - sha256: "4794147f43a8f3eee6b514d3ae30dbe6f7b9048cae8cd2a74cb4055cd28d74a8" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - google_api_availability_platform_interface: - dependency: transitive - description: - name: google_api_availability_platform_interface - sha256: "65b7da62fe5b582bb3d508628ad827d36d890710ea274766a992a56fa5420da6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - google_maps: - dependency: transitive - description: - name: google_maps - sha256: "4d6e199c561ca06792c964fa24b2bac7197bf4b401c2e1d23e345e5f9939f531" - url: "https://pub.dev" - source: hosted - version: "8.1.1" - google_maps_flutter: - dependency: "direct main" - description: - name: google_maps_flutter - sha256: e1805e5a5885bd14a1c407c59229f478af169bf4d04388586b19f53145a5db3a - url: "https://pub.dev" - source: hosted - version: "2.12.3" - google_maps_flutter_android: - dependency: transitive - description: - name: google_maps_flutter_android - sha256: a6c9d43f6a944ff4bae5c3deb34817970ac3d591dcd7f5bd2ea450ab9e9c514a - url: "https://pub.dev" - source: hosted - version: "2.18.2" - google_maps_flutter_ios: - dependency: transitive - description: - name: google_maps_flutter_ios - sha256: ca02463b19a9abc7d31fcaf22631d021d647107467f741b917a69fa26659fd75 - url: "https://pub.dev" - source: hosted - version: "2.15.5" - google_maps_flutter_platform_interface: - dependency: transitive - description: - name: google_maps_flutter_platform_interface - sha256: f4b9b44f7b12a1f6707ffc79d082738e0b7e194bf728ee61d2b3cdf5fdf16081 - url: "https://pub.dev" - source: hosted - version: "2.14.0" - google_maps_flutter_web: - dependency: transitive - description: - name: google_maps_flutter_web - sha256: "9d57993ba29b80bb637bb7b9784159ca93071d5940e4d0383ae2358ad371e375" - url: "https://pub.dev" - source: hosted - version: "0.5.13" - gsettings: - dependency: transitive - description: - name: gsettings - sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" - url: "https://pub.dev" - source: hosted - version: "0.2.8" - health: - dependency: "direct main" - description: - name: health - sha256: "996664904194b8e0a09dfe761e168fdbf9ef43c51e7de39cd075de71c7258ada" - url: "https://pub.dev" - source: hosted - version: "13.1.3" - html: - dependency: transitive - description: - name: html - sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.dev" - source: hosted - version: "0.15.6" - http: - dependency: "direct main" - description: - name: http - sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 - url: "https://pub.dev" - source: hosted - version: "1.5.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image_picker: - dependency: "direct main" - description: - name: image_picker - sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - image_picker_android: - dependency: transitive - description: - name: image_picker_android - sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e" - url: "https://pub.dev" - source: hosted - version: "0.8.13+1" - image_picker_for_web: - dependency: transitive - description: - name: image_picker_for_web - sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - image_picker_ios: - dependency: transitive - description: - name: image_picker_ios - sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e - url: "https://pub.dev" - source: hosted - version: "0.8.13" - image_picker_linux: - dependency: transitive - description: - name: image_picker_linux - sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.dev" - source: hosted - version: "0.2.2" - image_picker_macos: - dependency: transitive - description: - name: image_picker_macos - sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 - url: "https://pub.dev" - source: hosted - version: "0.2.2" - image_picker_platform_interface: - dependency: transitive - description: - name: image_picker_platform_interface - sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - image_picker_windows: - dependency: transitive - description: - name: image_picker_windows - sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.dev" - source: hosted - version: "0.2.2" - intl: - dependency: transitive - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - just_audio: - dependency: "direct main" - description: - name: just_audio - sha256: "679637a3ec5b6e00f36472f5a3663667df00ee4822cbf5dafca0f568c710960a" - url: "https://pub.dev" - source: hosted - version: "0.10.4" - just_audio_platform_interface: - dependency: transitive - description: - name: just_audio_platform_interface - sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a" - url: "https://pub.dev" - source: hosted - version: "4.6.0" - just_audio_web: - dependency: transitive - description: - name: just_audio_web - sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663" - url: "https://pub.dev" - source: hosted - version: "0.4.16" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" - url: "https://pub.dev" - source: hosted - version: "11.0.1" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.dev" - source: hosted - version: "5.1.1" - local_auth: - dependency: "direct main" - description: - name: local_auth - sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - local_auth_android: - dependency: transitive - description: - name: local_auth_android - sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3" - url: "https://pub.dev" - source: hosted - version: "1.0.52" - local_auth_darwin: - dependency: transitive - description: - name: local_auth_darwin - sha256: "0e9706a8543a4a2eee60346294d6a633dd7c3ee60fae6b752570457c4ff32055" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - local_auth_platform_interface: - dependency: transitive - description: - name: local_auth_platform_interface - sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a" - url: "https://pub.dev" - source: hosted - version: "1.0.10" - local_auth_windows: - dependency: transitive - description: - name: local_auth_windows - sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5 - url: "https://pub.dev" - source: hosted - version: "1.0.11" - logger: - dependency: "direct main" - description: - name: logger - sha256: "55d6c23a6c15db14920e037fe7e0dc32e7cdaf3b64b4b25df2d541b5b6b81c0c" - url: "https://pub.dev" - source: hosted - version: "2.6.1" - lottie: - dependency: "direct main" - description: - name: lottie - sha256: c5fa04a80a620066c15cf19cc44773e19e9b38e989ff23ea32e5903ef1015950 - url: "https://pub.dev" - source: hosted - version: "3.3.1" - manage_calendar_events: - dependency: "direct main" - description: - name: manage_calendar_events - sha256: f17600fcb7dc7047120c185993045e493d686930237b4e3c2689c26a64513d66 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - nm: - dependency: transitive - description: - name: nm - sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - octo_image: - dependency: transitive - description: - name: octo_image - sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - package_info_plus: - dependency: transitive - description: - name: package_info_plus - sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.dev" - source: hosted - version: "8.3.1" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db" - url: "https://pub.dev" - source: hosted - version: "2.2.18" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 - url: "https://pub.dev" - source: hosted - version: "12.0.1" - permission_handler_android: - dependency: transitive - description: - name: permission_handler_android - sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" - url: "https://pub.dev" - source: hosted - version: "13.0.1" - permission_handler_apple: - dependency: transitive - description: - name: permission_handler_apple - sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.dev" - source: hosted - version: "9.4.7" - permission_handler_html: - dependency: transitive - description: - name: permission_handler_html - sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.dev" - source: hosted - version: "0.1.3+5" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.dev" - source: hosted - version: "4.3.0" - permission_handler_windows: - dependency: transitive - description: - name: permission_handler_windows - sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.dev" - source: hosted - version: "0.2.1" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - posix: - dependency: transitive - description: - name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.dev" - source: hosted - version: "6.0.3" - provider: - dependency: "direct main" - description: - name: provider - sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.dev" - source: hosted - version: "6.1.5+1" - rrule: - dependency: transitive - description: - name: rrule - sha256: b7425410c594d4b6717c9f17ec8ef83c9d1ff2e513c428a135b5924fc2e8e045 - url: "https://pub.dev" - source: hosted - version: "0.2.17" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" - sanitize_html: - dependency: transitive - description: - name: sanitize_html - sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - share_plus: - dependency: "direct main" - description: - name: share_plus - sha256: d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1 - url: "https://pub.dev" - source: hosted - version: "11.1.0" - share_plus_platform_interface: - dependency: transitive - description: - name: share_plus_platform_interface - sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" - url: "https://pub.dev" - source: hosted - version: "2.5.3" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74 - url: "https://pub.dev" - source: hosted - version: "2.4.12" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" - url: "https://pub.dev" - source: hosted - version: "2.5.4" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" - source: hosted - version: "2.4.3" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shimmer: - dependency: "direct main" - description: - name: shimmer - sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sizer: - dependency: "direct main" - description: - name: sizer - sha256: "9963c89e4d30d7c2108de3eafc0a7e6a4a8009799376ea6be5ef0a9ad87cfbad" - url: "https://pub.dev" - source: hosted - version: "3.1.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - smooth_corner: - dependency: "direct main" - description: - name: smooth_corner - sha256: "112d7331f82ead81ec870c5d1eb0624f2e7e367eccd166c2fffe4c11d4f87c4f" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b" - url: "https://pub.dev" - source: hosted - version: "2.5.5" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - syncfusion_flutter_calendar: - dependency: "direct main" - description: - name: syncfusion_flutter_calendar - sha256: "8e8a4eef01d6a82ae2c17e76d497ff289ded274de014c9f471ffabc12d1e2e71" - url: "https://pub.dev" - source: hosted - version: "30.2.7" - syncfusion_flutter_core: - dependency: transitive - description: - name: syncfusion_flutter_core - sha256: bfd026c0f9822b49ff26fed11cd3334519acb6a6ad4b0c81d9cd18df6af1c4c0 - url: "https://pub.dev" - source: hosted - version: "30.2.7" - syncfusion_flutter_datepicker: - dependency: transitive - description: - name: syncfusion_flutter_datepicker - sha256: b5f35cc808e91b229d41613efe71dadab1549a35bfd493f922fc06ccc2fe908c - url: "https://pub.dev" - source: hosted - version: "30.2.7" - syncfusion_localizations: - dependency: transitive - description: - name: syncfusion_localizations - sha256: bb32b07879b4c1dee5d4c8ad1c57343a4fdae55d65a87f492727c11b68f23164 - url: "https://pub.dev" - source: hosted - version: "30.2.7" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6" - url: "https://pub.dev" - source: hosted - version: "3.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" - url: "https://pub.dev" - source: hosted - version: "0.7.6" - time: - dependency: transitive - description: - name: time - sha256: "370572cf5d1e58adcb3e354c47515da3f7469dac3a95b447117e728e7be6f461" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - timezone: - dependency: transitive - description: - name: timezone - sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "69ee86740f2847b9a4ba6cffa74ed12ce500bbe2b07f3dc1e643439da60637b7" - url: "https://pub.dev" - source: hosted - version: "6.3.18" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7 - url: "https://pub.dev" - source: hosted - version: "6.3.4" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f - url: "https://pub.dev" - source: hosted - version: "3.2.3" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" - url: "https://pub.dev" - source: hosted - version: "3.1.4" - uuid: - dependency: "direct main" - description: - name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff - url: "https://pub.dev" - source: hosted - version: "4.5.1" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" - url: "https://pub.dev" - source: hosted - version: "14.3.1" - web: - dependency: "direct main" - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - win32: - dependency: transitive - description: - name: win32 - sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" - url: "https://pub.dev" - source: hosted - version: "5.13.0" - win32_registry: - dependency: transitive - description: - name: win32_registry - sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" -sdks: - dart: ">=3.8.0-0 <4.0.0" - flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index 6bcaa36..7b27343 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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