haroon_dev
haroon amjad 3 days ago
parent d703c382e5
commit d053f58b7d

@ -811,7 +811,7 @@
"awaitingApproval": "انتظر القبول", "awaitingApproval": "انتظر القبول",
"news": "أخبار", "news": "أخبار",
"ready": "جاهز", "ready": "جاهز",
"enterValidNationalId": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح", "enterValidNationalId": "رقم الهوية أو رقم الملف غير صحيح",
"enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح", "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح",
"cannotEnterSaudiOrUAENumber": "لا يمكنك إدخال أرقام هواتف السعودية (00966) أو الإمارات (00971) عند اختيار دولة 'أخرى'", "cannotEnterSaudiOrUAENumber": "لا يمكنك إدخال أرقام هواتف السعودية (00966) أو الإمارات (00971) عند اختيار دولة 'أخرى'",
"medicalCentersWithCount": "{count} مراكز طبية", "medicalCentersWithCount": "{count} مراكز طبية",
@ -1274,7 +1274,7 @@
"noVitalSignsRecordedYet": "لا توجد علامات حيوية مسجلة بعد", "noVitalSignsRecordedYet": "لا توجد علامات حيوية مسجلة بعد",
"appointmentsAndVisits": "المواعيد والزيارات", "appointmentsAndVisits": "المواعيد والزيارات",
"labAndRadiology": "المختبر والأشعة", "labAndRadiology": "المختبر والأشعة",
"activeMedicationsAndPrescriptions": "الأدوية النشطة والوصفات الطبية", "activeMedicationsAndPrescriptions": "الوصفات الطبية",
"allPrescriptions": "جميع الوصفات", "allPrescriptions": "جميع الوصفات",
"allMedications": "جميع الأدوية", "allMedications": "جميع الأدوية",
"youDontHaveAnyPrescriptionsYet": "ليس لديك أي وصفات طبية بعد.", "youDontHaveAnyPrescriptionsYet": "ليس لديك أي وصفات طبية بعد.",
@ -1586,5 +1586,6 @@
"generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI", "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI",
"ratings": "التقييمات", "ratings": "التقييمات",
"hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية.", "hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية.",
"insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء." "insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء.",
"updatingEmailAddress": "جارٍ تحديث عنوان البريد الإلكتروني، يرجى الانتظار..."
} }

@ -802,7 +802,7 @@
"notNow": "Not Now", "notNow": "Not Now",
"pendingActivation": "Pending Activation", "pendingActivation": "Pending Activation",
"awaitingApproval": "Awaiting Approval", "awaitingApproval": "Awaiting Approval",
"enterValidNationalId": "Please enter a valid national ID or file number", "enterValidNationalId": "Invalid Identification or file number",
"enterValidPhoneNumber": "Please enter a valid phone number", "enterValidPhoneNumber": "Please enter a valid phone number",
"cannotEnterSaudiOrUAENumber": "You cannot enter Saudi Arabia (00966) or UAE (00971) phone numbers when 'Others' country is selected", "cannotEnterSaudiOrUAENumber": "You cannot enter Saudi Arabia (00966) or UAE (00971) phone numbers when 'Others' country is selected",
"ready": "Ready", "ready": "Ready",
@ -1266,7 +1266,7 @@
"noVitalSignsRecordedYet": "No vital signs recorded yet", "noVitalSignsRecordedYet": "No vital signs recorded yet",
"appointmentsAndVisits": "Appointments & visits", "appointmentsAndVisits": "Appointments & visits",
"labAndRadiology": "Lab & Radiology", "labAndRadiology": "Lab & Radiology",
"activeMedicationsAndPrescriptions": "Active Medications & Prescriptions", "activeMedicationsAndPrescriptions": "Recent Prescriptions",
"allPrescriptions": "All Prescriptions", "allPrescriptions": "All Prescriptions",
"allMedications": "All Medications", "allMedications": "All Medications",
"youDontHaveAnyPrescriptionsYet": "You don't have any prescriptions yet.", "youDontHaveAnyPrescriptionsYet": "You don't have any prescriptions yet.",
@ -1580,5 +1580,6 @@
"generateAiAnalysisResult": "Generate AI analysis for this result", "generateAiAnalysisResult": "Generate AI analysis for this result",
"ratings": "Ratings", "ratings": "Ratings",
"hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group.", "hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group.",
"insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed." "insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed.",
"updatingEmailAddress": "Updating email address, Please wait..."
} }

@ -343,10 +343,14 @@
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
); );
inputPaths = (
);
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
); );
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@ -360,10 +364,14 @@
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
); );
inputPaths = (
);
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
); );
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
@ -523,7 +531,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 8; CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = 3A359E86ZF; DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -709,7 +717,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 8; CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = 3A359E86ZF; DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -738,7 +746,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 8; CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = 3A359E86ZF; DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;

@ -101,7 +101,6 @@
<array> <array>
<string>audio</string> <string>audio</string>
<string>fetch</string> <string>fetch</string>
<string>location</string>
<string>remote-notification</string> <string>remote-notification</string>
<string>voip</string> <string>voip</string>
</array> </array>

@ -233,7 +233,7 @@ class ApiConsts {
static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
// ************ static values for Api **************** // ************ static values for Api ****************
static final double appVersionID = 20.3; static final double appVersionID = 20.5;
// static final double appVersionID = 50.7; // static final double appVersionID = 50.7;
static final int appChannelId = 3; static final int appChannelId = 3;
@ -920,6 +920,10 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
const SEND_PATIENT_IMMEDIATE_UPDATE_INSURANCE_REQUEST = 'Services/OUTPs.svc/REST/PatientCompanyUpdate'; const SEND_PATIENT_IMMEDIATE_UPDATE_INSURANCE_REQUEST = 'Services/OUTPs.svc/REST/PatientCompanyUpdate';
const PROFILE_SETTING = 'Services/Patients.svc/REST/GetPateintInfoForUpdate';
const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo';
class ApiKeyConstants { class ApiKeyConstants {
static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng'; static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng';
} }

@ -50,6 +50,7 @@ import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_repo.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart'; import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
@ -172,6 +173,7 @@ class AppDependencies {
getIt.registerLazySingleton<NotificationsRepo>(() => NotificationsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<NotificationsRepo>(() => NotificationsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<AskDoctorRepo>(() => AskDoctorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<AskDoctorRepo>(() => AskDoctorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ServicesPriceListRepo>(() => ServicesPriceListRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<ServicesPriceListRepo>(() => ServicesPriceListRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ProfileSettingsRepo>(() => ProfileSettingsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels // ViewModels
// Global/shared VMs LazySingleton // Global/shared VMs LazySingleton
@ -224,7 +226,11 @@ class AppDependencies {
authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()), authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()),
); );
getIt.registerLazySingleton<ProfileSettingsViewModel>(() => ProfileSettingsViewModel(cacheService: getIt<CacheService>())); getIt.registerLazySingleton<ProfileSettingsViewModel>(() => ProfileSettingsViewModel(
cacheService: getIt<CacheService>(),
profileSettingsRepo: getIt<ProfileSettingsRepo>(),
errorHandlerService: getIt<ErrorHandlerService>(),
));
getIt.registerLazySingleton<DateRangeSelectorRangeViewModel>(() => DateRangeSelectorRangeViewModel()); getIt.registerLazySingleton<DateRangeSelectorRangeViewModel>(() => DateRangeSelectorRangeViewModel());

@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.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/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
@ -32,6 +33,13 @@ class ValidationUtils {
isCorrectID = false; isCorrectID = false;
} }
if(nationalId!.length == 10) {
if (Utils.isSAUDIIDValid(nationalId!) == false) {
_dialogService.showExceptionBottomSheet(message: LocaleKeys.enterValidNationalId.tr(), onOkPressed: onOkPress);
isCorrectID = false;
}
}
if (nationalId != null && nationalId.isNotEmpty && selectedCountry != null) { if (nationalId != null && nationalId.isNotEmpty && selectedCountry != null) {
if (selectedCountry == CountryEnum.saudiArabia) { if (selectedCountry == CountryEnum.saudiArabia) {
if (!validateIqama(nationalId)) { if (!validateIqama(nationalId)) {

@ -320,9 +320,9 @@ extension EmailValidator on String {
height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal), height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
); );
Widget toText44({Color? color, bool isBold = false}) => Text( Widget toText44({Color? color, bool isBold = false, bool isEnglishOnly = false,}) => Text(
this, this,
style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),),
); );
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {

@ -28,6 +28,7 @@ import 'package:hmg_patient_app_new/features/authentication/models/resp_models/a
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/check_activation_code_resp_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_user_staus_nhic_response_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_user_staus_nhic_response_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -619,11 +620,12 @@ class AuthenticationViewModel extends ChangeNotifier {
} else { } else {
activation.list!.first.isParentUser = true; activation.list!.first.isParentUser = true;
} }
activation.list!.first.bloodGroup = activation.patientBlodType; activation.list!.first.bloodGroup = activation.patientBloodType;
activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode; activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode;
_appState.setAuthenticatedUser(activation.list!.first); _appState.setAuthenticatedUser(activation.list!.first);
_appState.setPrivilegeModelList(activation.list!.first.listPrivilege!); _appState.setPrivilegeModelList(activation.list!.first.listPrivilege!);
_appState.setUserBloodGroup = activation.patientBlodType ?? "N/A"; // _appState.setUserBloodGroup = activation.patientBlodType ?? "N/A";
_appState.setUserBloodGroup = activation.patientBloodType ?? "N/A";
} }
// _appState.setUserBloodGroup = (activation.patientBlodType ?? ""); // _appState.setUserBloodGroup = (activation.patientBlodType ?? "");
_appState.setAppAuthToken = activation.authenticationTokenId; _appState.setAppAuthToken = activation.authenticationTokenId;
@ -646,6 +648,7 @@ class AuthenticationViewModel extends ChangeNotifier {
await clearDefaultInputValues(); await clearDefaultInputValues();
myAppointmentsVM.setIsAppointmentDataToBeLoaded(true); myAppointmentsVM.setIsAppointmentDataToBeLoaded(true);
getIt.get<InsuranceViewModel>().setIsInsuranceDataToBeLoaded(true); getIt.get<InsuranceViewModel>().setIsInsuranceDataToBeLoaded(true);
getIt.get<HmgServicesViewModel>().setHasVitalSignDataLoaded(false);
if (isUserAgreedBefore) { if (isUserAgreedBefore) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
navigateToHomeScreen(); navigateToHomeScreen();

@ -20,6 +20,8 @@ import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart'; import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart';
import 'dart:ui' as ui;
typedef OnDone = void Function(String text); typedef OnDone = void Function(String text);
class ProvidedPinBoxTextAnimation { class ProvidedPinBoxTextAnimation {
@ -564,6 +566,8 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
Center( Center(
child: Directionality(
textDirection: ui.TextDirection.ltr,
child: OTPWidget( child: OTPWidget(
maxLength: _otpLength, maxLength: _otpLength,
controller: _otpController, controller: _otpController,
@ -581,6 +585,8 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
fontSize: 40.f, fontSize: 40.f,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: AppColors.whiteColor, color: AppColors.whiteColor,
fontFamily: "Poppins"
),
), ),
), ),
), ),
@ -601,7 +607,7 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
children: [ children: [
LocaleKeys.resendIn.tr(context: context).toText16(color: AppColors.inputLabelTextColor), LocaleKeys.resendIn.tr(context: context).toText16(color: AppColors.inputLabelTextColor),
SizedBox(width: 2.h), SizedBox(width: 2.h),
' ($minutes:$seconds). '.toText16(color: AppColors.inputLabelTextColor) ' ($minutes:$seconds). '.toText16(color: AppColors.inputLabelTextColor, isEnglishOnly: true)
], ],
); );
}, },

@ -85,6 +85,11 @@ class HmgServicesViewModel extends ChangeNotifier {
List<Covid19GetTestProceduresResp> covidTestProcedureList = []; List<Covid19GetTestProceduresResp> covidTestProcedureList = [];
Covid19GetPaymentInfo? covidPaymentInfo; Covid19GetPaymentInfo? covidPaymentInfo;
void setHasVitalSignDataLoaded(bool hasVitalSignDataLoaded) {
this.hasVitalSignDataLoaded = hasVitalSignDataLoaded;
notifyListeners();
}
Future<void> getOrdersList() async {} Future<void> getOrdersList() async {}
// HHC multiple services selection // HHC multiple services selection

@ -88,7 +88,7 @@ class InsuranceViewModel extends ChangeNotifier {
(failure) async { (failure) async {
debugPrint("InsuranceViewModel: API call failed - ${failure.toString()}"); debugPrint("InsuranceViewModel: API call failed - ${failure.toString()}");
isInsuranceLoading = false; isInsuranceLoading = false;
isInsuranceDataToBeLoaded = false; isInsuranceDataToBeLoaded = true;
isInsuranceExpired = false; isInsuranceExpired = false;
isInsuranceActive = false; isInsuranceActive = false;
notifyListeners(); notifyListeners();

@ -634,6 +634,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
Future<void> getPatientMyDoctors({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientMyDoctors({Function(dynamic)? onSuccess, Function(String)? onError}) async {
// if (!isAppointmentDataToBeLoaded) return; // if (!isAppointmentDataToBeLoaded) return;
isPatientMyDoctorsLoading = true; isPatientMyDoctorsLoading = true;
patientMyDoctorsList.clear();
notifyListeners(); notifyListeners();
final result = await myAppointmentsRepo.getPatientDoctorsList(); final result = await myAppointmentsRepo.getPatientDoctorsList();

@ -0,0 +1,100 @@
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/services/logger_service.dart';
abstract class ProfileSettingsRepo {
/// Updates general patient info (name, phone, etc.).
Future<Either<Failure, GenericApiModel<dynamic>>> updatePatientInfo({
required Map<String, dynamic> patientInfo,
});
/// Deactivates (deletes) the patient's account.
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateAccount();
}
class ProfileSettingsRepoImp implements ProfileSettingsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
ProfileSettingsRepoImp({
required this.loggerService,
required this.apiClient,
});
@override
Future<Either<Failure, GenericApiModel<dynamic>>> updatePatientInfo({
required Map<String, dynamic> patientInfo,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
SAVE_SETTING,
body: patientInfo,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateAccount() async {
final Map<String, dynamic> body = {};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
// TODO: Replace with actual deactivate-account endpoint once available
'Services/Patients.svc/REST/Patient_DeactivateAccount',
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,18 +1,42 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_repo.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
class ProfileSettingsViewModel extends ChangeNotifier { class ProfileSettingsViewModel extends ChangeNotifier {
static const String _darkModeKey = 'is_dark_mode'; static const String _darkModeKey = 'is_dark_mode';
final CacheService _cacheService; final CacheService _cacheService;
final ProfileSettingsRepo profileSettingsRepo;
final ErrorHandlerService errorHandlerService;
// Dark-mode state
bool _isDarkMode = false; bool _isDarkMode = false;
bool get isDarkMode => _isDarkMode; bool get isDarkMode => _isDarkMode;
ProfileSettingsViewModel({required CacheService cacheService}) // Update email state
: _cacheService = cacheService; bool isUpdateEmailLoading = false;
bool isUpdateEmailSuccess = false;
String? updateEmailError;
// Update patient info state
bool isUpdatePatientInfoLoading = false;
bool isUpdatePatientInfoSuccess = false;
String? updatePatientInfoError;
// Deactivate account state
bool isDeactivateAccountLoading = false;
bool isDeactivateAccountSuccess = false;
String? deactivateAccountError;
ProfileSettingsViewModel({
required CacheService cacheService,
required this.profileSettingsRepo,
required this.errorHandlerService,
}) : _cacheService = cacheService;
// Dark mode
/// Call once at app startup (before the first frame) to restore the /// Call once at app startup (before the first frame) to restore the
/// persisted dark-mode preference. /// persisted dark-mode preference.
@ -30,6 +54,75 @@ class ProfileSettingsViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
// Update patient info
Future<void> updatePatientInfo({
required Map<String, dynamic> patientInfo,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
isUpdatePatientInfoLoading = true;
isUpdatePatientInfoSuccess = false;
updatePatientInfoError = null;
notifyListeners();
final result = await profileSettingsRepo.updatePatientInfo(patientInfo: patientInfo);
result.fold(
(failure) {
isUpdatePatientInfoLoading = false;
updatePatientInfoError = failure.message;
notifyListeners();
if (onError != null) {
onError(failure.message);
} else {
errorHandlerService.handleError(failure: failure);
}
},
(response) {
isUpdatePatientInfoLoading = false;
isUpdatePatientInfoSuccess = true;
notifyListeners();
onSuccess?.call(response.data);
},
);
}
// Deactivate account
Future<void> deactivateAccount({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
isDeactivateAccountLoading = true;
isDeactivateAccountSuccess = false;
deactivateAccountError = null;
notifyListeners();
final result = await profileSettingsRepo.deactivateAccount();
result.fold(
(failure) {
isDeactivateAccountLoading = false;
deactivateAccountError = failure.message;
notifyListeners();
if (onError != null) {
onError(failure.message);
} else {
errorHandlerService.handleError(failure: failure);
}
},
(response) {
isDeactivateAccountLoading = false;
isDeactivateAccountSuccess = true;
notifyListeners();
onSuccess?.call(response.data);
},
);
}
// Helpers
void notify() { void notify() {
notifyListeners(); notifyListeners();
} }

@ -1581,5 +1581,6 @@ abstract class LocaleKeys {
static const ratings = 'ratings'; static const ratings = 'ratings';
static const hmgPharmacyText = 'hmgPharmacyText'; static const hmgPharmacyText = 'hmgPharmacyText';
static const insuranceRequestSubmittedSuccessfully = 'insuranceRequestSubmittedSuccessfully'; static const insuranceRequestSubmittedSuccessfully = 'insuranceRequestSubmittedSuccessfully';
static const updatingEmailAddress = 'updatingEmailAddress';
} }

@ -93,8 +93,6 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
borderRadius: 10, borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h, height: 40.h,
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
CustomButton( CustomButton(
@ -280,7 +278,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
runSpacing: 4.h, runSpacing: 4.h,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: isSortByClinic ? (doctor?.clinicName ?? "") : (doctor?.projectName ?? ""), labelText: isSortByClinic ? (doctor?.projectName ?? "") : (doctor?.clinicName ?? ""),
), ),
], ],
), ),

@ -20,13 +20,20 @@ class DoctorRatingDetails extends StatelessWidget {
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.ceilToDouble().toString().toText44(isBold: true), bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.ceilToDouble().toString().toText44(isBold: true, isEnglishOnly: true),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"${bookAppointmentsVM.doctorsProfileResponseModel.noOfPatientsRate} ${LocaleKeys.reviews.tr(context: context)}" Row(
.toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor), children: [
"${bookAppointmentsVM.doctorsProfileResponseModel.noOfPatientsRate} "
.toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor, isEnglishOnly: true),
LocaleKeys.reviews.tr(context: context)
.toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor,),
],
),
RatingBar( RatingBar(
initialRating: bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.toDouble(), initialRating: bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.toDouble(),
direction: Axis.horizontal, direction: Axis.horizontal,
@ -75,7 +82,7 @@ class DoctorRatingDetails extends StatelessWidget {
), ),
Container( Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${getRatingWidth(bookAppointmentsVM.doctorDetailsList[0].ratio).round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), child: Text("${getRatingWidth(bookAppointmentsVM.doctorDetailsList[0].ratio).round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")),
), ),
], ],
), ),
@ -95,7 +102,7 @@ class DoctorRatingDetails extends StatelessWidget {
), ),
Container( Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[1].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), child: Text("${bookAppointmentsVM.doctorDetailsList[1].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")),
), ),
], ],
), ),
@ -115,7 +122,7 @@ class DoctorRatingDetails extends StatelessWidget {
), ),
Container( Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[2].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), child: Text("${bookAppointmentsVM.doctorDetailsList[2].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")),
), ),
], ],
), ),
@ -135,7 +142,7 @@ class DoctorRatingDetails extends StatelessWidget {
), ),
Container( Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[3].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), child: Text("${bookAppointmentsVM.doctorDetailsList[3].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")),
), ),
], ],
), ),
@ -156,7 +163,7 @@ class DoctorRatingDetails extends StatelessWidget {
), ),
Container( Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[4].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), child: Text("${bookAppointmentsVM.doctorDetailsList[4].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")),
), ),
], ],
), ),

@ -407,10 +407,10 @@ class _LandingPageState extends State<LandingPage> {
? myAppointmentsVM.patientAppointmentsHistoryList.length ? myAppointmentsVM.patientAppointmentsHistoryList.length
: 3, : 3,
layout: SwiperLayout.STACK, layout: SwiperLayout.STACK,
loop: true, loop: false,
itemWidth: MediaQuery.of(context).size.width - 48.h, itemWidth: MediaQuery.of(context).size.width - 48.h,
indicatorLayout: PageIndicatorLayout.COLOR, indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right, axisDirection: getIt.get<AppState>().isArabic() ? AxisDirection.left : AxisDirection.right,
controller: _controller, controller: _controller,
itemHeight: 255.h + 20, itemHeight: 255.h + 20,
// extra space for shadow // extra space for shadow

@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -92,12 +93,12 @@ class LargeServiceCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
serviceCardData.title.tr(context: context).toText14(isBold: true, color: AppColors.textColor), serviceCardData.title.tr(context: context).toText14(isBold: true, color: AppColors.textColor),
serviceCardData.subtitle.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), serviceCardData.subtitle.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight, maxLine: 2),
], ],
), ),
), ),
], ],
).paddingSymmetrical(16.w, 0.h).expanded, ).paddingSymmetrical(8.w, 0.h).expanded,
CustomButton( CustomButton(
text: serviceCardData.isBold ? LocaleKeys.visitPharmacyOnline.tr(context: context) : LocaleKeys.bookNow.tr(context: context), text: serviceCardData.isBold ? LocaleKeys.visitPharmacyOnline.tr(context: context) : LocaleKeys.bookNow.tr(context: context),
onPressed: () { onPressed: () {
@ -177,7 +178,9 @@ class FadedLargeServiceCard extends StatelessWidget {
children: [ children: [
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(24.r), borderRadius: BorderRadius.circular(24.r),
child: Image.asset(serviceCardData.largeCardIcon, fit: BoxFit.cover, width: 520.w, height: 250.h), child: Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Image.asset(serviceCardData.largeCardIcon, fit: BoxFit.cover, width: 520.w, height: 250.h)),
), ),
Positioned( Positioned(
top: 0, top: 0,
@ -216,6 +219,8 @@ class FadedLargeServiceCard extends StatelessWidget {
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(8.h), padding: EdgeInsets.all(8.h),
child: Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets( child: Utils.buildSvgWithAssets(
icon: serviceCardData.icon, icon: serviceCardData.icon,
iconColor: serviceCardData.iconColor, iconColor: serviceCardData.iconColor,
@ -224,6 +229,7 @@ class FadedLargeServiceCard extends StatelessWidget {
), ),
), ),
), ),
),
SizedBox(width: 12.w), SizedBox(width: 12.w),
serviceCardData.title.tr(context: context).toText18(weight: FontWeight.w500, color: AppColors.textColor).expanded, serviceCardData.title.tr(context: context).toText18(weight: FontWeight.w500, color: AppColors.textColor).expanded,
], ],

@ -110,6 +110,7 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
insuranceViewModel.setIsInsuranceDataToBeLoaded(true); insuranceViewModel.setIsInsuranceDataToBeLoaded(true);
insuranceViewModel.initInsuranceProvider(); insuranceViewModel.initInsuranceProvider();
Navigator.pop(context);
}, onError: (err) { }, onError: (err) {
insuranceViewModel.updatePatientInsuranceCard( insuranceViewModel.updatePatientInsuranceCard(
patientID: appState.getAuthenticatedUser()!.patientId!, patientID: appState.getAuthenticatedUser()!.patientId!,
@ -129,9 +130,9 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget {
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: false, isCloseButtonVisible: false,
); );
Future.delayed(Duration(milliseconds: 2000)).then((value) async { // Future.delayed(Duration(milliseconds: 2000)).then((value) async {
Navigator.pop(context); // Navigator.pop(context);
}); // });
}, },
onError: (err) { onError: (err) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();

@ -59,7 +59,7 @@ class LabOrderByTest extends StatelessWidget {
icon: AppAssets.view_report_icon, icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
iconSize: 16.h, iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context), text: LocaleKeys.viewResults.tr(context: context),
onPressed: () { onPressed: () {
onTap(); onTap();
}, },

@ -283,9 +283,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
), ),
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.blood_icon, icon: AppAssets.blood_icon,
labelText: LocaleKeys.bloodGroup.tr(namedArgs: {'bloodType': appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup}, context: context), labelText: appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
), ),
Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) { Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) {
@ -749,7 +749,26 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
], ],
).paddingSymmetrical(0.w, 0.h), ).paddingSymmetrical(0.w, 0.h),
SizedBox(height: 24.h), SizedBox(height: 24.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.activeMedicationsAndPrescriptions.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), LocaleKeys.activeMedicationsAndPrescriptions.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2),
Row(
children: [
LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
SizedBox(width: 2.w),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
],
).onPress(() {
// myAppointmentsViewModel.getPatientMyDoctors();
Navigator.of(context).push(
CustomPageRoute(
page: PrescriptionsListPage(),
),
);
}),
],
),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Consumer<PrescriptionsViewModel>(builder: (context, prescriptionVM, child) { Consumer<PrescriptionsViewModel>(builder: (context, prescriptionVM, child) {
return prescriptionVM.isPrescriptionsOrdersLoading return prescriptionVM.isPrescriptionsOrdersLoading
@ -830,55 +849,55 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Divider(color: AppColors.dividerColor), // Divider(color: AppColors.dividerColor),
SizedBox(height: 16.h), // SizedBox(height: 16.h),
Row( // Row(
children: [ // children: [
Expanded( // Expanded(
child: CustomButton( // child: CustomButton(
text: LocaleKeys.allPrescriptions.tr(context: context), // text: LocaleKeys.allPrescriptions.tr(context: context),
onPressed: () { // onPressed: () {
Navigator.of(context).push( // Navigator.of(context).push(
CustomPageRoute( // CustomPageRoute(
page: PrescriptionsListPage(), // page: PrescriptionsListPage(),
), // ),
); // );
}, // },
backgroundColor: AppColors.secondaryLightRedColor, // backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, // textColor: AppColors.primaryRedColor,
fontSize: 12.f, // fontSize: 12.f,
fontWeight: FontWeight.w500, // fontWeight: FontWeight.w500,
borderRadius: 12.r, // borderRadius: 12.r,
height: 40.h, // height: 40.h,
icon: AppAssets.requests, // icon: AppAssets.requests,
iconColor: AppColors.primaryRedColor, // iconColor: AppColors.primaryRedColor,
iconSize: 16.w, // iconSize: 16.w,
), // ),
), // ),
SizedBox(width: 6.w), // SizedBox(width: 6.w),
Expanded( // Expanded(
child: CustomButton( // child: CustomButton(
text: LocaleKeys.allMedications.tr(context: context), // text: LocaleKeys.allMedications.tr(context: context),
onPressed: () { Navigator.of(context).push( // onPressed: () { Navigator.of(context).push(
CustomPageRoute( // CustomPageRoute(
page: ActiveMedicationPage(), // page: ActiveMedicationPage(),
), // ),
);}, // );},
backgroundColor: AppColors.secondaryLightRedColor, // backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, // textColor: AppColors.primaryRedColor,
fontSize: 12.f, // fontSize: 12.f,
fontWeight: FontWeight.w500, // fontWeight: FontWeight.w500,
borderRadius: 12.h, // borderRadius: 12.h,
height: 40.h, // height: 40.h,
icon: AppAssets.all_medications_icon, // icon: AppAssets.all_medications_icon,
iconColor: AppColors.primaryRedColor, // iconColor: AppColors.primaryRedColor,
iconSize: 16.h, // iconSize: 16.h,
), // ),
), // ),
], // ],
), // ),
], ],
), ),
), ),
@ -911,7 +930,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
], ],
).onPress(() { ).onPress(() {
myAppointmentsViewModel.getPatientMyDoctors(); // myAppointmentsViewModel.getPatientMyDoctors();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: MyDoctorsPage(), page: MyDoctorsPage(),
@ -1210,6 +1229,26 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
// Requests Tab Data // Requests Tab Data
return Column( return Column(
children: [ children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true),
Row(
children: [
LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor),
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
],
),
],
).onPress(() {
Navigator.of(context).push(
CustomPageRoute(
page: PatientSickleavesListPage(),
),
);
}),
SizedBox(height: 16.h),
Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) { Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return medicalFileVM.isPatientSickLeaveListLoading return medicalFileVM.isPatientSickLeaveListLoading
? PatientSickLeaveCard( ? PatientSickLeaveCard(
@ -1279,20 +1318,20 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
), ),
); );
}), }),
MedicalFileCard( // MedicalFileCard(
label: LocaleKeys.sickLeaveReport.tr(context: context), // label: LocaleKeys.sickLeaveReport.tr(context: context),
textColor: AppColors.blackColor, // textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor, // backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.sick_leave_report_icon, // svgIcon: AppAssets.sick_leave_report_icon,
isLargeText: true, // isLargeText: true,
iconSize: 36.h, // iconSize: 36.h,
).onPress(() { // ).onPress(() {
Navigator.of(context).push( // Navigator.of(context).push(
CustomPageRoute( // CustomPageRoute(
page: PatientSickleavesListPage(), // page: PatientSickleavesListPage(),
), // ),
); // );
}), // }),
], ],
).paddingSymmetrical(0.w, 0.0), ).paddingSymmetrical(0.w, 0.0),
SizedBox(height: 24.h), SizedBox(height: 24.h),

@ -40,18 +40,17 @@ class PatientSickLeaveCard extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( // Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ // children: [
"${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true).toShimmer2(isShow: isLoading), // AppCustomChipWidget(
AppCustomChipWidget( // labelText: isLoading ? "" : getStatusText(context),
labelText: isLoading ? "" : getStatusText(context), // backgroundColor: getStatusColor().withOpacity(0.15),
backgroundColor: getStatusColor().withOpacity(0.15), // textColor: getStatusColor(),
textColor: getStatusColor(), // ).toShimmer2(isShow: isLoading, width: 100.h),
).toShimmer2(isShow: isLoading, width: 100.h), // ],
], // ),
), // SizedBox(height: 16.h),
SizedBox(height: 16.h),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [

@ -154,7 +154,7 @@ class _FamilyCardsState extends State<FamilyCards> {
crossAxisCount: 2, crossAxisCount: 2,
crossAxisSpacing: 10.w, crossAxisSpacing: 10.w,
mainAxisSpacing: 10.h, mainAxisSpacing: 10.h,
childAspectRatio: widget.isShowDetails ? 0.56.h : 0.64.h, childAspectRatio: widget.isShowDetails ? 0.56.h : 0.74.h,
), ),
padding: EdgeInsets.only(bottom: 20.h), padding: EdgeInsets.only(bottom: 20.h),
itemBuilder: (context, index) { itemBuilder: (context, index) {
@ -164,7 +164,7 @@ class _FamilyCardsState extends State<FamilyCards> {
final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID);
return Container( return Container(
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h), padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r),
child: Opacity( child: Opacity(
opacity: isActive || profile.status == FamilyFileEnum.pending.toInt || !canSwitch ? 0.4 : 1.0, // Fade all content if active opacity: isActive || profile.status == FamilyFileEnum.pending.toInt || !canSwitch ? 0.4 : 1.0, // Fade all content if active
child: Stack( child: Stack(

@ -24,6 +24,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart'; import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/update_email_widget.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/app_language_change.dart'; import 'package:hmg_patient_app_new/widgets/app_language_change.dart';
@ -115,7 +116,7 @@ class ProfileSettingsState extends State<ProfileSettings> {
// extra space for shadow // extra space for shadow
itemWidth: SizeUtils.width - 30.w, itemWidth: SizeUtils.width - 30.w,
indicatorLayout: PageIndicatorLayout.COLOR, indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right, axisDirection: getIt.get<AppState>().isArabic() ? AxisDirection.left : AxisDirection.right,
controller: _controller, controller: _controller,
pagination: SwiperPagination( pagination: SwiperPagination(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
@ -234,24 +235,24 @@ class ProfileSettingsState extends State<ProfileSettings> {
], ],
), ),
), ),
Container( // Container(
margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h), // margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h),
padding: EdgeInsets.only(top: 4.h, bottom: 4.h), // padding: EdgeInsets.only(top: 4.h, bottom: 4.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column( // child: Column(
children: [ // children: [
actionItem(AppAssets.language_change, LocaleKeys.language.tr(context: context), () { // actionItem(AppAssets.language_change, LocaleKeys.language.tr(context: context), () {
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.language.tr(context: context), child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false); // showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.language.tr(context: context), child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false);
}, trailingLabel: Utils.appState.isArabic() ? "العربية" : "English"), // }, trailingLabel: Utils.appState.isArabic() ? "العربية" : "English"),
1.divider,
actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () {
openAppSettings();
}),
// 1.divider, // 1.divider,
// actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true), // actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () {
], // openAppSettings();
), // }),
), // // 1.divider,
// // actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true),
// ],
// ),
// ),
LocaleKeys.personalInformation.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), LocaleKeys.personalInformation.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w),
Container( Container(
margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h), margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h),
@ -259,7 +260,15 @@ class ProfileSettingsState extends State<ProfileSettings> {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column( child: Column(
children: [ children: [
actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () {}), actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () {
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.updateEmailAddress.tr(context: context),
child: UpdateEmailDialog(),
callBackFunc: () {},
isFullScreen: false,
);
}),
// 1.divider, // 1.divider,
// actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}), // actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}),
// 1.divider, // 1.divider,
@ -385,11 +394,25 @@ class FamilyCardWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
"${profile.patientName}".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1, isEnglishOnly: true), "${profile.patientName}".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1, isEnglishOnly: true),
Wrap(
direction: Axis.horizontal,
spacing: 4.w,
runSpacing: 6.w,
children: [
AppCustomChipWidget( AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
icon: AppAssets.file_icon, icon: AppAssets.file_icon,
labelText: "${LocaleKeys.fileNo.tr(context: context)}: ${profile.responseId}", labelText: "${LocaleKeys.fileno.tr(context: context)}: ${profile.responseId}",
iconSize: 12.w, iconSize: 12.w,
), ),
isActive ? AppCustomChipWidget(
icon: AppAssets.checkmark_icon,
labelText: LocaleKeys.verified.tr(context: context),
iconColor: AppColors.successColor,
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
) : SizedBox.shrink(),
],
),
], ],
).expanded, ).expanded,
// Icon(Icons.qr_code, size: 56.h) // Icon(Icons.qr_code, size: 56.h)
@ -406,11 +429,12 @@ class FamilyCardWidget extends StatelessWidget {
AppCustomChipWidget( AppCustomChipWidget(
labelText: LocaleKeys.ageYearsOld.tr(namedArgs: {'age': profile.age.toString(), 'yearsOld': LocaleKeys.yearsOld.tr(context: context)}), labelText: LocaleKeys.ageYearsOld.tr(namedArgs: {'age': profile.age.toString(), 'yearsOld': LocaleKeys.yearsOld.tr(context: context)}),
), ),
isActive && appState.getAuthenticatedUser()!.bloodGroup != null // isActive && appState.getAuthenticatedUser()!.bloodGroup != null
? AppCustomChipWidget( // ?
isActive ? AppCustomChipWidget(
icon: AppAssets.blood_icon, icon: AppAssets.blood_icon,
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w), labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w),
labelText: "Blood: ${appState.getAuthenticatedUser()!.bloodGroup ?? ""}", labelText: appState.getAuthenticatedUser()!.bloodGroup ?? "N/A",
iconColor: AppColors.primaryRedColor) iconColor: AppColors.primaryRedColor)
: SizedBox(), : SizedBox(),
Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) { Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) {

@ -0,0 +1,106 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart';
class UpdateEmailDialog extends StatefulWidget {
UpdateEmailDialog({super.key});
@override
State<UpdateEmailDialog> createState() => _UpdateEmailDialogState();
}
class _UpdateEmailDialogState extends State<UpdateEmailDialog> {
late FocusNode _textFieldFocusNode;
late TextEditingController? textController;
ProfileSettingsViewModel? profileSettingsViewModel;
@override
void initState() {
_textFieldFocusNode = FocusNode();
textController = TextEditingController();
textController!.text = getIt.get<AppState>().getAuthenticatedUser()!.emailAddress ?? "";
super.initState();
}
@override
void dispose() {
_textFieldFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
profileSettingsViewModel = Provider.of<ProfileSettingsViewModel>(context);
return GestureDetector(
onTap: () {
_textFieldFocusNode.unfocus();
FocusScope.of(context).unfocus();
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Enter the new email address to be updated in your HMG File: ".toText16(textAlign: TextAlign.start, weight: FontWeight.w500),
SizedBox(height: 12.h),
TextInputWidget(
labelText: LocaleKeys.email.tr(),
hintText: "demo@gmail.com",
controller: textController,
focusNode: _textFieldFocusNode,
autoFocus: true,
padding: EdgeInsets.all(8.h),
keyboardType: TextInputType.emailAddress,
isEnable: true,
isReadOnly: false,
prefix: null,
isBorderAllowed: false,
isAllowLeadingIcon: true,
fontSize: 14.f,
isCountryDropDown: false,
leadingIcon: AppAssets.email,
fontFamily: "Poppins",
),
SizedBox(height: 12.h),
CustomButton(
text: LocaleKeys.submit.tr(context: context),
onPressed: () {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.updatingEmailAddress.tr(context: context));
profileSettingsViewModel!.updatePatientInfo(
patientInfo: {"EmailAddress": textController!.text},
onSuccess: (response) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()),
callBackFunc: () async {
Navigator.of(context).pop();
}, isFullScreen: false);
},
onError: (error) {
LoaderBottomSheet.hideLoader();
// Show error message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(error)),
);
},
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: const Color(0xFFffffff),
),
],
),
);
}
}

@ -100,7 +100,7 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
children: [ children: [
title.toText14(weight: FontWeight.w500), title.toText14(weight: FontWeight.w500),
subTitle subTitle
.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) .toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500, isEnglishOnly: true)
.toShimmer2(isShow: (leadingIcon == AppAssets.rulerIcon || leadingIcon == AppAssets.weightScale) && hmgServicesVM.isVitalSignLoading), .toShimmer2(isShow: (leadingIcon == AppAssets.rulerIcon || leadingIcon == AppAssets.weightScale) && hmgServicesVM.isVitalSignLoading),
], ],
), ),

@ -168,7 +168,7 @@ class ConditionCard extends StatelessWidget {
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
for (int i = 0; i < symptoms.length; i++) ...[ for (int i = 0; i < symptoms.length; i++) ...[
"${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), "${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, isEnglishOnly: true),
if (i != symptoms.length - 1) if (i != symptoms.length - 1)
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w), padding: EdgeInsets.symmetric(horizontal: 2.w),
@ -228,7 +228,7 @@ class ConditionCard extends StatelessWidget {
backgroundColor: AppColors.scaffoldBgColor, backgroundColor: AppColors.scaffoldBgColor,
titleWidget: Row( titleWidget: Row(
children: [ children: [
"$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum)), "$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum), isEnglishOnly: true),
], ],
).paddingSymmetrical(0, 4.h), ).paddingSymmetrical(0, 4.h),
), ),

@ -259,7 +259,7 @@ class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
super.dispose(); super.dispose();
} }
double t = 0; double t = 1.0;
void _onScroll() { void _onScroll() {
final double offset = widget.controller.offset; final double offset = widget.controller.offset;

@ -2,8 +2,8 @@ name: hmg_patient_app_new
description: "New HMG Patient App" description: "New HMG Patient App"
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
#version: 0.0.13+10 version: 0.0.15+12
version: 0.0.1+13 #version: 0.0.1+14
environment: environment:
sdk: ">=3.6.0 <4.0.0" sdk: ">=3.6.0 <4.0.0"

Loading…
Cancel
Save