Merge branch 'master' into dev_aamir

# Conflicts:
#	lib/generated/codegen_loader.g.dart
pull/236/head
aamir-csol 5 days ago
commit 7bf69c52f0

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@ -1,3 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.835 8.71465C29 10.2375 29 12.157 29 14.6057L29 17.393V17.3931C29 19.8418 29 21.7612 28.835 23.284C28.6667 24.8381 28.3169 26.0973 27.5358 27.1724C27.0629 27.8232 26.4905 28.3956 25.8397 28.8685C24.7646 29.6496 23.5054 29.9993 21.9514 30.1677C20.4285 30.3327 18.5091 30.3327 16.0604 30.3327H16.0603H15.9397C13.491 30.3327 11.5715 30.3327 10.0486 30.1677C8.49458 29.9993 7.23541 29.6496 6.16031 28.8685C5.50945 28.3956 4.93708 27.8232 4.4642 27.1724C3.6831 26.0973 3.33334 24.8381 3.16497 23.284C2.99998 21.7612 2.99999 19.8418 3 17.3931V17.393L3 14.6056V14.6056C2.99999 12.1569 2.99998 10.2375 3.16497 8.71465C3.33334 7.1606 3.6831 5.90143 4.4642 4.82633C4.93708 4.17547 5.50945 3.6031 6.16032 3.13022C7.23541 2.34911 8.49459 1.99936 10.0486 1.83099C11.5715 1.666 13.4909 1.666 15.9395 1.66602H15.9396H16.0604H16.0605C18.5091 1.66601 20.4285 1.666 21.9514 1.83099C23.5054 1.99936 24.7646 2.34911 25.8397 3.13022C26.4905 3.6031 27.0629 4.17547 27.5358 4.82633C28.3169 5.90143 28.6667 7.1606 28.835 8.71465ZM16 5.66602C16.7364 5.66602 17.3333 6.26297 17.3333 6.99935V9.24299C17.6276 9.59842 17.8786 9.66602 18 9.66602C18.1485 9.66602 18.4909 9.56487 18.8693 8.95942C19.2595 8.33494 20.0821 8.14507 20.7066 8.53531C21.3311 8.92555 21.521 9.74814 21.1307 10.3726C20.4782 11.4167 19.4088 12.3327 18 12.3327C17.7685 12.3327 17.5462 12.3079 17.3333 12.262L17.3333 13.0409C17.8948 13.4337 18.584 13.666 19.3333 13.666C20.2769 13.666 21.1252 13.2976 21.7432 12.7042C22.2744 12.1942 23.1185 12.2114 23.6285 12.7426C24.1385 13.2738 24.1213 14.1178 23.5901 14.6278C22.49 15.6841 20.9852 16.3327 19.3333 16.3327C18.6338 16.3327 17.9606 16.2163 17.3333 16.002V18.0531C18.0392 17.9934 18.7108 17.8873 19.335 17.7423C21.0296 17.3485 23 18.5587 23 20.5393C23 21.5265 22.4537 22.5524 21.4063 22.9419C20.935 23.1172 20.4345 23.269 19.911 23.3954C19.3839 23.5228 18.9627 23.8554 18.7618 24.3012L18.6199 24.6159C18.1546 25.6483 17.1409 26.3327 16 26.3327C14.8591 26.3327 13.8454 25.6483 13.3801 24.6159L13.2382 24.3012C13.0373 23.8554 12.6161 23.5228 12.089 23.3954C11.5655 23.269 11.065 23.1172 10.5937 22.9419C9.54632 22.5524 9 21.5265 9 20.5393C9 18.5587 10.9704 17.3485 12.665 17.7423C13.2892 17.8873 13.9608 17.9934 14.6667 18.0531V16.002C14.0394 16.2164 13.3662 16.3327 12.6667 16.3327C11.0148 16.3327 9.51001 15.6841 8.4099 14.6278C7.87872 14.1178 7.86154 13.2738 8.37154 12.7426C8.88155 12.2114 9.72559 12.1942 10.2568 12.7042C10.8748 13.2976 11.7231 13.666 12.6667 13.666C13.416 13.666 14.1052 13.4337 14.6667 13.0409V12.262C14.4538 12.3079 14.2315 12.3327 14 12.3327C12.5912 12.3327 11.5218 11.4167 10.8693 10.3726C10.4791 9.74814 10.6689 8.92555 11.2934 8.53531C11.9179 8.14507 12.7405 8.33494 13.1307 8.95942C13.5091 9.56487 13.8515 9.66602 14 9.66602C14.1214 9.66602 14.3724 9.59842 14.6667 9.24299L14.6667 6.99935C14.6667 6.26297 15.2636 5.66602 16 5.66602Z" fill="#2E3039"/>
<svg width="26" height="29" viewBox="0 0 26 29" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 4C13.5523 4 14 4.44772 14 5V7.35861C14.3647 7.84353 14.7315 7.99997 15.0001 7.99997C15.3062 7.99997 15.7395 7.79698 16.1521 7.13669C16.4448 6.66833 17.0617 6.52593 17.5301 6.81861C17.9984 7.11129 18.1408 7.72823 17.8482 8.19659C17.2299 9.18588 16.2514 9.99997 15.0001 9.99997C14.644 9.99997 14.3099 9.93402 14 9.81685V11.2101C14.6402 11.7041 15.4494 12 16.3333 12C17.3655 12 18.2958 11.5965 18.9741 10.9453C19.3725 10.5628 20.0055 10.5757 20.388 10.9741C20.7705 11.3725 20.7576 12.0055 20.3592 12.388C19.3194 13.3864 17.8967 14 16.3333 14C15.5039 14 14.7141 13.8273 14 13.516V16.4116C14.8282 16.3596 15.6132 16.244 16.335 16.0762C18.0296 15.6825 20 16.8927 20 18.8733C20 19.8605 19.4537 20.8864 18.4063 21.2759C17.935 21.4511 17.4345 21.603 16.911 21.7294C16.3839 21.8567 15.9627 22.1893 15.7618 22.6351L15.6199 22.9499C15.1546 23.9822 14.1409 24.6667 13 24.6667C11.8591 24.6667 10.8454 23.9822 10.3801 22.9499L10.2382 22.6351C10.0373 22.1893 9.61608 21.8567 9.08902 21.7294C8.56548 21.603 8.06504 21.4511 7.59375 21.2759C6.54632 20.8864 6 19.8605 6 18.8733C6 16.8927 7.97038 15.6825 9.66501 16.0762C10.3868 16.244 11.1718 16.3596 12 16.4116V13.516C11.2859 13.8273 10.4961 14 9.66667 14C8.1033 14 6.6806 13.3864 5.64076 12.388C5.24237 12.0055 5.22949 11.3725 5.61199 10.9741C5.99449 10.5757 6.62753 10.5628 7.02591 10.9453C7.70416 11.5965 8.63452 12 9.66667 12C10.5506 12 11.3598 11.7041 12 11.2101V9.81695C11.6901 9.93406 11.3562 9.99997 11.0001 9.99997C9.74886 9.99997 8.77033 9.18588 8.1521 8.19659C7.85942 7.72823 8.00183 7.11129 8.47018 6.81861C8.93854 6.52593 9.55548 6.66833 9.84816 7.13669C10.2608 7.79698 10.6941 7.99997 11.0001 7.99997C11.2687 7.99997 11.6354 7.84361 12 7.35897V5C12 4.44772 12.4477 4 13 4Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M26 15.727V12.9397C26 10.491 26 8.57148 25.835 7.04863C25.6667 5.49458 25.3169 4.23541 24.5358 3.16031C24.0629 2.50945 23.4905 1.93708 22.8397 1.4642C21.7646 0.683098 20.5054 0.333341 18.9514 0.16497C17.4285 -1.87904e-05 15.5091 -1.04558e-05 13.0604 1.75524e-07H12.9396C10.491 -1.06751e-05 8.57146 -1.91778e-05 7.04863 0.16497C5.49459 0.33334 4.23541 0.683097 3.16032 1.4642C2.50945 1.93708 1.93708 2.50945 1.4642 3.16031C0.683099 4.23541 0.333342 5.49458 0.164971 7.04863C-1.6585e-05 8.57145 -9.22962e-06 10.4909 1.48706e-07 12.9395V15.727C-9.56553e-06 18.1757 -1.7181e-05 20.0952 0.164971 21.618C0.333341 23.1721 0.683098 24.4313 1.4642 25.5064C1.93708 26.1572 2.50945 26.7296 3.16031 27.2025C4.23541 27.9836 5.49458 28.3333 7.04863 28.5017C8.57148 28.6667 10.491 28.6667 12.9397 28.6667H13.0603C15.509 28.6667 17.4285 28.6667 18.9514 28.5017C20.5054 28.3333 21.7646 27.9836 22.8397 27.2025C23.4905 26.7296 24.0629 26.1572 24.5358 25.5064C25.3169 24.4313 25.6667 23.1721 25.835 21.618C26 20.0952 26 18.1757 26 15.727ZM23.8467 21.4026C23.6967 22.7865 23.4099 23.6534 22.9178 24.3308C22.5682 24.8119 22.1452 25.2349 21.6641 25.5844C20.9868 26.0765 20.1198 26.3634 18.7359 26.5133C17.3333 26.6653 15.5221 26.6667 13 26.6667C10.4779 26.6667 8.66666 26.6653 7.26406 26.5133C5.88018 26.3634 5.01322 26.0765 4.33588 25.5844C3.85481 25.2349 3.43176 24.8119 3.08224 24.3308C2.59012 23.6534 2.30327 22.7865 2.15334 21.4026C2.00137 20 2 18.1888 2 15.6667V13C2 10.4779 2.00137 8.66665 2.15334 7.26406C2.30327 5.88017 2.59012 5.01322 3.08224 4.33588C3.43176 3.85481 3.85481 3.43175 4.33589 3.08224C5.01322 2.59012 5.88018 2.30327 7.26406 2.15333C8.66666 2.00137 10.4779 2 13 2C15.5221 2 17.3333 2.00137 18.7359 2.15334C20.1198 2.30327 20.9868 2.59012 21.6641 3.08224C22.1452 3.43175 22.5682 3.85481 22.9178 4.33588C23.4099 5.01322 23.6967 5.88018 23.8467 7.26406C23.9986 8.66665 24 10.4779 24 13V15.6667C24 18.1888 23.9986 20 23.8467 21.4026Z" fill="#2E3039"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

@ -301,6 +301,12 @@
"medicinesSubtitle": "الوصفات",
"vitalSigns": "علامات حيوية",
"vitalSignsSubTitle": "التقارير",
"vitalSignNormal": "طبيعي",
"vitalSignLow": "منخفض",
"vitalSignHigh": "مرتفع",
"vitalSignObese": "بدين",
"vitalSignOverweight": "زيادة الوزن",
"vitalSignUnderweight": "نقص الوزن",
"myMedical": "نشط",
"myMedicalSubtitle": "الأدوية",
"myDoctor": "أطبائي",
@ -717,6 +723,11 @@
"bloodDonation": "التبرع بالدم",
"bloodDonationInfo": "من خلال هذه الخدمة، يمكنك تسجيل اسمك كمتبرع بالدم حيث سيتواصل معك بنك الدم في مجموعة الحبيب الطبية في حالة الحاجة إلى فصيلة الدم.",
"bloodInstruction": "أدخل المعلومات المطلوبة، من أجل التسجيل في خدمة التبرع بالدم",
"aboutBloodDonation": "عن التبرع بالدم",
"bloodDonationDescription": "التبرع بالدم هو عمل نبيل ينقذ الأرواح. كل تبرع واحد يمكن أن ينقذ ما يصل إلى ثلاثة أشخاص. من خلال التبرع بالدم، فإنك تساعد المرضى الذين يحتاجون إلى عمليات نقل دم، وحالات الطوارئ، والعلاجات الطبية.",
"bloodDonationBenefit1": "عملية آمنة وسريعة (10-15 دقيقة)",
"bloodDonationBenefit2": "يمكنك التبرع كل 8-12 أسبوع",
"bloodDonationBenefit3": "فحص صحي مجاني لدمك",
"viewTerms": "لعرض الشروط والأحكام",
"wantConnectHmgNetwork": "عزيزي العميل، لا يوجد وصول إلى الإنترنت، هل ترغب في الاتصال بشبكة مجموعة الحبيب الطبية لاستخدام تطبيقنا، تأكد من أنك في نطاق شبكة مجموعة الحبيب الطبية",
"failedToAccessHmgServices": "متصل بشبكة مجموعة الحبيب الطبية،\n\nلكن فشل في الوصول إلى خدمات مجموعة الحبيب الطبية",

@ -300,6 +300,12 @@
"medicinesSubtitle": "Prescriptions",
"vitalSigns": "Vital Signs",
"vitalSignsSubTitle": "Reports",
"vitalSignNormal": "Normal",
"vitalSignLow": "Low",
"vitalSignHigh": "High",
"vitalSignObese": "Obese",
"vitalSignOverweight": "Overweight",
"vitalSignUnderweight": "Underweight",
"myMedical": "Active",
"myMedicalSubtitle": "Medications",
"myDoctor": "My Doctors",
@ -710,6 +716,11 @@
"bloodDonation": "Blood Donation",
"bloodDonationInfo": "Through this service, you can register your name as a blood donor where the blood bank in the Habib Medical Group will communicate you in case of need for blood type.",
"bloodInstruction": "Enter the required information, in order to register for Blood Donation Service",
"aboutBloodDonation": "About Blood Donation",
"bloodDonationDescription": "Blood donation is a noble act that saves lives. Every single donation can save up to three people. By donating blood, you help patients in need of transfusions, emergencies, and medical treatments.",
"bloodDonationBenefit1": "Safe and quick process (10-15 minutes)",
"bloodDonationBenefit2": "You can donate every 8-12 weeks",
"bloodDonationBenefit3": "Free health check of your blood",
"viewTerms": "To view the terms and conditions",
"wantConnectHmgNetwork": "Dear customer there is no internet access, do you want to connect with HMG network to use our app, make sure you are in range of HMG network",
"failedToAccessHmgServices": "Connected with HMG Network,\n\nBut failed to access HMG services",

@ -400,6 +400,7 @@ class AppAssets {
static const String fullBodyFrontFemale = '$pngBasePath/full_body_front_female.png';
static const String fullBodyBackFemale = '$pngBasePath/full_body_back_female.png';
static const String bmiFullBody = '$pngBasePath/bmi_image_1.png';
static const String defaultMEP = '$pngBasePath/default_MEP.png';
}
class AppAnimations {

@ -923,7 +923,8 @@ class Utils {
),
TextSpan(
// text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount),
text: " ${habibWalletAmount.toStringAsFixed(2)}",
// text: " ${(NumberFormat.decimalPattern().format(habibWalletAmount)).toStringAsFixed(2)}",
text: " ${(NumberFormat.decimalPattern().format(habibWalletAmount))}",
style: TextStyle(
color: resolvedTextColor,
fontSize: fontSize ?? 32.f,

@ -667,6 +667,11 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setPrivilegeModelList(activation.list!.first.listPrivilege!);
_appState.setUserBloodGroup = activation.patientBlodType ?? "N/A";
// Refresh privileges after user switching to ensure correct privileges are loaded
if (isSwitchUser) {
print("🔄 Switching user - refreshing privileges");
await getServicePrivilege();
}
// Fetch patient blood type from new API
// await getPatientBloodTypeNew();

@ -1,11 +1,14 @@
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_state.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/doctor_response_mapper.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
@ -20,6 +23,7 @@ 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/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
class BloodDonationViewModel extends ChangeNotifier {
@ -263,7 +267,13 @@ class BloodDonationViewModel extends ChangeNotifier {
await bloodDonationRepo.updateBloodGroup(request: payload);
await addUserAgreementForBloodDonation();
LoaderBottomSheet.hideLoader();
dialogService.showSuccessBottomSheetWithoutH(message: "Blood Group Updated Successfully", onOkPressed: () {});
showCommonBottomSheetWithoutHeight(GetIt.instance<NavigationService>().navigatorKey.currentContext!,
child: Utils.getSuccessWidget(loadingText: "Blood Group Updated Successfully").paddingSymmetrical(0.h, 24.h),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true);
// dialogService.showSuccessBottomSheetWithoutH(message: "Blood Group Updated Successfully", onOkPressed: () {});
}
Future<void> addUserAgreementForBloodDonation() async {

@ -183,7 +183,7 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo {
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList() async {
Map<String, dynamic> request = {'IsOnlineCheckIn': false, 'IsAdvancePayment': false, 'IsForER': true};
Map<String, dynamic> request = {'IsOnlineCheckIn': true, 'IsAdvancePayment': false, 'IsForER': true};
try {
GenericApiModel<List<HospitalsModel>>? apiResponse;

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
@ -21,6 +22,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart';
import 'models/req_models/check_activation_e_referral_req_model.dart';
import 'models/resq_models/get_covid_payment_info_resp.dart';
@ -632,6 +634,9 @@ class HmgServicesViewModel extends ChangeNotifier {
Function(GenericApiModel)? onSuccess,
Function(String)? onError,
}) async {
// Get and set the SMS signature for auto-fill
requestModel.sMSSignature = await getSignature();
notifyListeners();
final result = await hmgServicesRepo.sendEReferralActivationCode(requestModel);
@ -660,6 +665,14 @@ class HmgServicesViewModel extends ChangeNotifier {
);
}
Future<String?> getSignature() async {
if (Platform.isAndroid) {
return await SmsVerification.getAppSignature();
} else {
return null;
}
}
Future<void> checkEReferralActivationCode({
required CheckActivationCodeForEReferralRequestModel requestModel,
Function(GenericApiModel)? onSuccess,

@ -10,6 +10,7 @@ class SendActivationCodeForEReferralRequestModel {
dynamic sessionID;
bool? isDentalAllowedBackend;
int? deviceTypeID;
String? sMSSignature;
SendActivationCodeForEReferralRequestModel(
{this.patientMobileNumber,
@ -22,7 +23,8 @@ class SendActivationCodeForEReferralRequestModel {
this.patientOutSA,
this.sessionID,
this.isDentalAllowedBackend,
this.deviceTypeID});
this.deviceTypeID,
this.sMSSignature});
SendActivationCodeForEReferralRequestModel.fromJson(Map<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber'];
@ -36,6 +38,7 @@ class SendActivationCodeForEReferralRequestModel {
sessionID = json['SessionID'];
isDentalAllowedBackend = json['isDentalAllowedBackend'];
deviceTypeID = json['DeviceTypeID'];
sMSSignature = json['SMSSignature'];
}
Map<String, dynamic> toJson() {
@ -51,6 +54,7 @@ class SendActivationCodeForEReferralRequestModel {
data['SessionID'] = this.sessionID;
data['isDentalAllowedBackend'] = this.isDentalAllowedBackend;
data['DeviceTypeID'] = this.deviceTypeID;
data['SMSSignature'] = this.sMSSignature;
return data;
}
}

@ -3,6 +3,16 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
/// Enum for vital sign status to avoid string-based comparisons
enum VitalSignStatus {
normal,
high,
low,
obese,
overweight,
underweight,
}
/// UI-only helper model for Vital Sign cards.
///
/// Keeps presentation logic (chip colors, icon colors, simple status rules)
@ -22,13 +32,12 @@ class VitalSignUiModel {
/// Returns a color scheme for a card based on its [status] and [label].
///
/// Rules (mirrors existing behavior in Medical File page):
/// Rules:
/// - Height is always blue.
/// - High => red scheme.
/// - Low => yellow scheme.
/// - High, Obese, Overweight => red scheme.
/// - Low, Underweight => yellow scheme.
/// - Otherwise => green scheme (Normal).
static VitalSignUiModel scheme({required String? status, required String label}) {
final s = (status ?? '').toLowerCase();
static VitalSignUiModel scheme({required VitalSignStatus? status, required String label}) {
final l = label.toLowerCase();
// Height should always be blue.
@ -41,7 +50,10 @@ class VitalSignUiModel {
);
}
if (s.contains('high')) {
// High, Obese, Overweight => red scheme (health concerns)
if (status == VitalSignStatus.high ||
status == VitalSignStatus.obese ||
status == VitalSignStatus.overweight) {
return VitalSignUiModel(
iconBg: AppColors.chipSecondaryLightRedColor,
iconFg: AppColors.primaryRedColor,
@ -50,8 +62,8 @@ class VitalSignUiModel {
);
}
// Warning for both low and overweight/underweight BMI, since they can indicate potential health issues.
if (s.contains('low') || s.contains("OverWeight") || s.contains("وزن زائد") || s.contains("UnderWeight") || s.contains("وزن ناقص")) {
// Low, Underweight => yellow scheme (warning)
if (status == VitalSignStatus.low || status == VitalSignStatus.underweight) {
final Color yellowBg = AppColors.highAndLow.withValues(alpha: 0.12);
return VitalSignUiModel(
iconBg: yellowBg,
@ -71,19 +83,37 @@ class VitalSignUiModel {
);
}
/// Convert VitalSignStatus enum to localized string
static String statusToString(VitalSignStatus status) {
switch (status) {
case VitalSignStatus.normal:
return LocaleKeys.vitalSignNormal.tr();
case VitalSignStatus.high:
return LocaleKeys.vitalSignHigh.tr();
case VitalSignStatus.low:
return LocaleKeys.vitalSignLow.tr();
case VitalSignStatus.obese:
return LocaleKeys.vitalSignObese.tr();
case VitalSignStatus.overweight:
return LocaleKeys.vitalSignOverweight.tr();
case VitalSignStatus.underweight:
return LocaleKeys.vitalSignUnderweight.tr();
}
}
/// Simple, user-friendly classification:
/// - Low: systolic < 90 OR diastolic < 60
/// - High: systolic >= 140 OR diastolic >= 90
/// - Normal: otherwise
/// Returns null if values are missing/unparseable.
static String? bloodPressureStatus({dynamic systolic, dynamic diastolic}) {
static VitalSignStatus? bloodPressureStatus({dynamic systolic, dynamic diastolic}) {
final int? s = toIntOrNull(systolic);
final int? d = toIntOrNull(diastolic);
if (s == null || d == null) return null;
if (s < 90 || d < 60) return 'Low';
if (s >= 140 || d >= 90) return 'High';
return 'Normal';
if (s < 90 || d < 60) return VitalSignStatus.low;
if (s >= 140 || d >= 90) return VitalSignStatus.high;
return VitalSignStatus.normal;
}
static int? toIntOrNull(dynamic v) {
@ -93,28 +123,47 @@ class VitalSignUiModel {
return int.tryParse(v.toString());
}
static String bmiStatus(dynamic bmi) {
String bmiStatus = 'Normal';
static VitalSignStatus? bmiStatus(dynamic bmi) {
// Return null if BMI is not available or is 0
final double bmiResult = double.tryParse(bmi.toString()) ?? 0;
if (bmiResult >= 30) {
bmiStatus = LocaleKeys.obese.tr();
} else if (bmiResult < 30 && bmiResult >= 25) {
bmiStatus = LocaleKeys.overWeight.tr();
} else if (bmiResult < 25 && bmiResult >= 18.5) {
bmiStatus = LocaleKeys.normal.tr();
} else if (bmiResult < 18.5) {
bmiStatus = LocaleKeys.underWeight.tr();
if (bmiResult == 0 || bmi == null) {
return null;
}
// BMI >= 25 (Overweight or Obese) => High
if (bmiResult >= 25) {
return VitalSignStatus.high;
}
// BMI >= 18.5 and < 25 => Normal
else if (bmiResult >= 18.5) {
return VitalSignStatus.normal;
}
// BMI < 18.5 (Underweight) => Low
else {
return VitalSignStatus.low;
}
}
/// Weight status based on BMI with detailed classification
/// Returns: Obese, Overweight, Normal, Underweight
static VitalSignStatus? weightStatus(dynamic bmi) {
// Return null if BMI is not available or is 0
final double bmiResult = double.tryParse(bmi.toString()) ?? 0;
// if (bmi == null) return 'N/A';
// final double bmiValue = double.tryParse(bmi.toString()) ?? 0;
// if (bmiValue < 18.5) return 'Underweight';
// if (bmiValue < 25) return 'Normal';
// if (bmiValue < 30) return 'Overweight';
// return 'High';
if (bmiResult == 0 || bmi == null) {
return null;
}
return bmiStatus;
if (bmiResult >= 30) {
return VitalSignStatus.obese;
} else if (bmiResult >= 25) {
return VitalSignStatus.overweight;
} else if (bmiResult >= 18.5) {
return VitalSignStatus.normal;
} else {
return VitalSignStatus.underweight;
}
}
}

@ -215,27 +215,40 @@ class MedicalFileViewModel extends ChangeNotifier {
final result = await medicalFileRepo.getPatientVaccinesList();
result.fold(
// (failure) async => await errorHandlerService.handleError(
// failure: failure,
// onOkPressed: () {
// onError!(failure.message);
// },
// ),
(failure) async {
// onError!(failure.message);
print("❌ Vaccine API Failure: ${failure.message}");
isPatientVaccineListLoading = false;
notifyListeners();
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
print("📦 Vaccine API Response - Status: ${apiResponse.messageStatus}, Data: ${apiResponse.data}");
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
print("⚠️ Vaccine API Error: ${apiResponse.errorMessage}");
isPatientVaccineListLoading = false;
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? "Unknown error");
}
} else if (apiResponse.messageStatus == 1) {
patientVaccineList = apiResponse.data!;
if (apiResponse.data != null) {
patientVaccineList = apiResponse.data!;
print("✅ Vaccine data loaded: ${patientVaccineList.length} items");
} else {
print("⚠️ Vaccine API returned success but data is null");
}
isPatientVaccineListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
} else {
print("⚠️ Unexpected messageStatus: ${apiResponse.messageStatus}");
isPatientVaccineListLoading = false;
notifyListeners();
}
},
);

@ -1,160 +1,169 @@
import 'dart:convert';
class PatientVaccineResponseModel {
String? setupID;
int? projectID;
int? patientID;
String? setupId;
int? projectId;
int? patientId;
int? invoiceNo;
String? procedureID;
String? procedureId;
String? vaccineName;
Null? vaccineNameN;
dynamic vaccineNameN;
String? invoiceDate;
int? doctorID;
int? clinicID;
int? doctorId;
int? clinicId;
String? firstName;
String? middleName;
String? lastName;
Null? firstNameN;
Null? middleNameN;
Null? lastNameN;
dynamic firstNameN;
dynamic middleNameN;
dynamic lastNameN;
String? dateofBirth;
int? actualDoctorRate;
String? age;
String? clinicName;
Null? decimalDoctorRate;
Null? doctorImageURL;
double? decimalDoctorRate;
dynamic doctorImageUrl;
String? doctorName;
int? doctorRate;
int? doctorStarsRate;
double? doctorStarsRate;
String? doctorTitle;
int? gender;
Null? genderDescription;
Null? invoiceNoVP;
dynamic genderDescription;
dynamic invoiceNoVp;
bool? isActiveDoctorProfile;
bool? isDoctorAllowVedioCall;
bool? isExecludeDoctor;
int? noOfPatientsRate;
String? patientName;
String? projectName;
String? qR;
String? qr;
List<dynamic>? speciality;
String? vaccinationDate;
PatientVaccineResponseModel(
{this.setupID,
this.projectID,
this.patientID,
this.invoiceNo,
this.procedureID,
this.vaccineName,
this.vaccineNameN,
this.invoiceDate,
this.doctorID,
this.clinicID,
this.firstName,
this.middleName,
this.lastName,
this.firstNameN,
this.middleNameN,
this.lastNameN,
this.dateofBirth,
this.actualDoctorRate,
this.age,
this.clinicName,
this.decimalDoctorRate,
this.doctorImageURL,
this.doctorName,
this.doctorRate,
this.doctorStarsRate,
this.doctorTitle,
this.gender,
this.genderDescription,
this.invoiceNoVP,
this.isActiveDoctorProfile,
this.isDoctorAllowVedioCall,
this.isExecludeDoctor,
this.noOfPatientsRate,
this.patientName,
this.projectName,
this.qR,
this.vaccinationDate});
PatientVaccineResponseModel({
this.setupId,
this.projectId,
this.patientId,
this.invoiceNo,
this.procedureId,
this.vaccineName,
this.vaccineNameN,
this.invoiceDate,
this.doctorId,
this.clinicId,
this.firstName,
this.middleName,
this.lastName,
this.firstNameN,
this.middleNameN,
this.lastNameN,
this.dateofBirth,
this.actualDoctorRate,
this.age,
this.clinicName,
this.decimalDoctorRate,
this.doctorImageUrl,
this.doctorName,
this.doctorRate,
this.doctorStarsRate,
this.doctorTitle,
this.gender,
this.genderDescription,
this.invoiceNoVp,
this.isActiveDoctorProfile,
this.isDoctorAllowVedioCall,
this.isExecludeDoctor,
this.noOfPatientsRate,
this.patientName,
this.projectName,
this.qr,
this.speciality,
this.vaccinationDate,
});
factory PatientVaccineResponseModel.fromRawJson(String str) => PatientVaccineResponseModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
PatientVaccineResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
projectID = json['ProjectID'];
patientID = json['PatientID'];
invoiceNo = json['InvoiceNo'];
procedureID = json['ProcedureID'];
vaccineName = json['VaccineName'];
vaccineNameN = json['VaccineNameN'];
invoiceDate = json['InvoiceDate'];
doctorID = json['DoctorID'];
clinicID = json['ClinicID'];
firstName = json['FirstName'];
middleName = json['MiddleName'];
lastName = json['LastName'];
firstNameN = json['FirstNameN'];
middleNameN = json['MiddleNameN'];
lastNameN = json['LastNameN'];
dateofBirth = json['DateofBirth'];
actualDoctorRate = json['ActualDoctorRate'];
age = json['Age'];
clinicName = json['ClinicName'];
decimalDoctorRate = json['DecimalDoctorRate'];
doctorImageURL = json['DoctorImageURL'];
doctorName = json['DoctorName'];
doctorRate = json['DoctorRate'];
doctorStarsRate = json['DoctorStarsRate'];
doctorTitle = json['DoctorTitle'];
gender = json['Gender'];
genderDescription = json['GenderDescription'];
invoiceNoVP = json['InvoiceNo_VP'];
isActiveDoctorProfile = json['IsActiveDoctorProfile'];
isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
isExecludeDoctor = json['IsExecludeDoctor'];
noOfPatientsRate = json['NoOfPatientsRate'];
patientName = json['PatientName'];
projectName = json['ProjectName'];
qR = json['QR'];
vaccinationDate = json['VaccinationDate'];
}
factory PatientVaccineResponseModel.fromJson(Map<String, dynamic> json) => PatientVaccineResponseModel(
setupId: json["SetupID"],
projectId: json["ProjectID"],
patientId: json["PatientID"],
invoiceNo: json["InvoiceNo"],
procedureId: json["ProcedureID"],
vaccineName: json["VaccineName"],
vaccineNameN: json["VaccineNameN"],
invoiceDate: json["InvoiceDate"],
doctorId: json["DoctorID"],
clinicId: json["ClinicID"],
firstName: json["FirstName"],
middleName: json["MiddleName"],
lastName: json["LastName"],
firstNameN: json["FirstNameN"],
middleNameN: json["MiddleNameN"],
lastNameN: json["LastNameN"],
dateofBirth: json["DateofBirth"],
actualDoctorRate: json["ActualDoctorRate"],
age: json["Age"],
clinicName: json["ClinicName"],
decimalDoctorRate: json["DecimalDoctorRate"]?.toDouble(),
doctorImageUrl: json["DoctorImageURL"],
doctorName: json["DoctorName"],
doctorRate: json["DoctorRate"],
doctorStarsRate: json["DoctorStarsRate"]?.toDouble(),
doctorTitle: json["DoctorTitle"],
gender: json["Gender"],
genderDescription: json["GenderDescription"],
invoiceNoVp: json["InvoiceNo_VP"],
isActiveDoctorProfile: json["IsActiveDoctorProfile"],
isDoctorAllowVedioCall: json["IsDoctorAllowVedioCall"],
isExecludeDoctor: json["IsExecludeDoctor"],
noOfPatientsRate: json["NoOfPatientsRate"],
patientName: json["PatientName"],
projectName: json["ProjectName"],
qr: json["QR"],
speciality: json["Speciality"] == null ? [] : List<dynamic>.from(json["Speciality"]!.map((x) => x)),
vaccinationDate: json["VaccinationDate"],
);
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupID'] = this.setupID;
data['ProjectID'] = this.projectID;
data['PatientID'] = this.patientID;
data['InvoiceNo'] = this.invoiceNo;
data['ProcedureID'] = this.procedureID;
data['VaccineName'] = this.vaccineName;
data['VaccineNameN'] = this.vaccineNameN;
data['InvoiceDate'] = this.invoiceDate;
data['DoctorID'] = this.doctorID;
data['ClinicID'] = this.clinicID;
data['FirstName'] = this.firstName;
data['MiddleName'] = this.middleName;
data['LastName'] = this.lastName;
data['FirstNameN'] = this.firstNameN;
data['MiddleNameN'] = this.middleNameN;
data['LastNameN'] = this.lastNameN;
data['DateofBirth'] = this.dateofBirth;
data['ActualDoctorRate'] = this.actualDoctorRate;
data['Age'] = this.age;
data['ClinicName'] = this.clinicName;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorName'] = this.doctorName;
data['DoctorRate'] = this.doctorRate;
data['DoctorStarsRate'] = this.doctorStarsRate;
data['DoctorTitle'] = this.doctorTitle;
data['Gender'] = this.gender;
data['GenderDescription'] = this.genderDescription;
data['InvoiceNo_VP'] = this.invoiceNoVP;
data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
data['IsExecludeDoctor'] = this.isExecludeDoctor;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['PatientName'] = this.patientName;
data['ProjectName'] = this.projectName;
data['QR'] = this.qR;
data['VaccinationDate'] = this.vaccinationDate;
return data;
}
Map<String, dynamic> toJson() => {
"SetupID": setupId,
"ProjectID": projectId,
"PatientID": patientId,
"InvoiceNo": invoiceNo,
"ProcedureID": procedureId,
"VaccineName": vaccineName,
"VaccineNameN": vaccineNameN,
"InvoiceDate": invoiceDate,
"DoctorID": doctorId,
"ClinicID": clinicId,
"FirstName": firstName,
"MiddleName": middleName,
"LastName": lastName,
"FirstNameN": firstNameN,
"MiddleNameN": middleNameN,
"LastNameN": lastNameN,
"DateofBirth": dateofBirth,
"ActualDoctorRate": actualDoctorRate,
"Age": age,
"ClinicName": clinicName,
"DecimalDoctorRate": decimalDoctorRate,
"DoctorImageURL": doctorImageUrl,
"DoctorName": doctorName,
"DoctorRate": doctorRate,
"DoctorStarsRate": doctorStarsRate,
"DoctorTitle": doctorTitle,
"Gender": gender,
"GenderDescription": genderDescription,
"InvoiceNo_VP": invoiceNoVp,
"IsActiveDoctorProfile": isActiveDoctorProfile,
"IsDoctorAllowVedioCall": isDoctorAllowVedioCall,
"IsExecludeDoctor": isExecludeDoctor,
"NoOfPatientsRate": noOfPatientsRate,
"PatientName": patientName,
"ProjectName": projectName,
"QR": qr,
"Speciality": speciality == null ? [] : List<dynamic>.from(speciality!.map((x) => x)),
"VaccinationDate": vaccinationDate,
};
}

@ -676,9 +676,9 @@ class MyAppointmentsViewModel extends ChangeNotifier {
Future<void> getPatientFavouriteDoctors({bool forceRefresh = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
// If data is already fetched and not forcing refresh, skip API call
if (isFavouriteDoctorsDataFetched && !forceRefresh) {
return;
}
// if (isFavouriteDoctorsDataFetched && !forceRefresh) {
// return;
// }
isPatientFavouriteDoctorsLoading = true;
patientFavouriteDoctorsList.clear();

@ -33,6 +33,7 @@ class PrescriptionDetailResponseModel {
num? scaleOffset;
String? startDate;
bool? hasReminder;
bool? isHomeMedicineDeliverySupported;
PrescriptionDetailResponseModel(
{this.address,
@ -68,7 +69,7 @@ class PrescriptionDetailResponseModel {
this.sKU,
this.scaleOffset,
this.startDate,
this.hasReminder = false});
this.hasReminder = false, this.isHomeMedicineDeliverySupported});
PrescriptionDetailResponseModel.fromJson(Map<String, dynamic> json) {
address = json['Address'];

@ -99,7 +99,11 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
// throw Exception("prescription list is empty");
}
final prescriptionOrders = list.map((item) => PrescriptionDetailResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PrescriptionDetailResponseModel>();
final List<PrescriptionDetailResponseModel> prescriptionOrders =
list.map((item) => PrescriptionDetailResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PrescriptionDetailResponseModel>();
if (prescriptionOrders.isNotEmpty) {
prescriptionOrders.first.isHomeMedicineDeliverySupported = response['IsHomeMedicineDeliverySupported'] ?? false;
}
apiResponse = GenericApiModel<List<PrescriptionDetailResponseModel>>(
messageStatus: messageStatus,

@ -19,6 +19,8 @@ class CodegenLoader extends AssetLoader{
"arabic": "العربية",
"login": "تسجيل الدخول",
"noDataAvailable": "لا توجد بيانات متاحة",
"noRatingAvailable": "لا يوجد تقييم متاح",
"doctorDoesNotHaveRating": "لم يحصل هذا الطبيب على أي تقييمات بعد.",
"confirm": "تأكيد",
"loadingText": "جاري التحميل، يرجى الانتظار...",
"kilometerUnit": "كم",
@ -203,7 +205,7 @@ class CodegenLoader extends AssetLoader{
"lastName": "اسم العائلة",
"female": "أنثى",
"male": "ذكر",
"preferredLanguage": "اللغة المفضلة *",
"preferredLanguage": "اللغة المفضلة",
"locationsRegister": "أين ترغب في إنشاء هذا الملف؟",
"ksa": "السعودية",
"dubai": "دبي",
@ -314,9 +316,15 @@ class CodegenLoader extends AssetLoader{
"medicinesSubtitle": "الوصفات",
"vitalSigns": "علامات حيوية",
"vitalSignsSubTitle": "التقارير",
"vitalSignNormal": "طبيعي",
"vitalSignLow": "منخفض",
"vitalSignHigh": "مرتفع",
"vitalSignObese": "بدين",
"vitalSignOverweight": "زيادة الوزن",
"vitalSignUnderweight": "نقص الوزن",
"myMedical": "نشط",
"myMedicalSubtitle": "الأدوية",
"myDoctor": "طبيبي",
"myDoctor": "أطبائي",
"myDoctorSubtitle": "القائمة",
"eye": "العين",
"eyeSubtitle": "القياس",
@ -378,7 +386,7 @@ class CodegenLoader extends AssetLoader{
"paymentOnline": "الخدمة",
"onlineCheckIn": "تسجيل الوصول عبر الإنترنت",
"myBalances": "رصيدي",
"myWallet": "محف<EFBFBD><EFBFBD>تي",
"myWallet": "محفظتي",
"balanceAmount": "مبلغ المحفظة",
"totalBalance": "إجمالي الرصيد",
"createAdvancedPayment": "إعادة شحن المحفظة",
@ -502,7 +510,7 @@ class CodegenLoader extends AssetLoader{
"services2": "الخدمات",
"cantSeeProfile": "لرؤية ملفك الطبي، يرجى تسجيل الدخول أو التسجيل الآن",
"loginRegisterNow": "تسجيل الدخول أو التسجيل الآن",
"hmgPharmacy": "صيدلية مجموعة الحبيب الطبية",
"hmgPharmacy": "صيدلية الحبيب",
"ecommerceSolution": "حلول التجارة الإلكترونية",
"comprehensive": "شامل",
"onlineConsulting": "استشارات عبر الإنترنت",
@ -705,7 +713,7 @@ class CodegenLoader extends AssetLoader{
"retouch": "روتوش",
"bikini": "بيكيني",
"totalMinutes": "إجمالي الدقائق",
"feedback": "ملاحظات",
"feedback": "رأيك يهمنا",
"likeToHear": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه",
"emptySubject": "يرجى إدخال الموضوع",
"emptyMessage": "يرجى إدخال الرسالة",
@ -713,10 +721,10 @@ class CodegenLoader extends AssetLoader{
"complainAppo": "شكوى بخصوص الموعد",
"complainAppoAlt": "شكوى بدون موعد",
"messageType": "نوع الرسالة",
"feedbackType": "نوع الملاحظات",
"feedbackType": "نوع الرسالة",
"compliment": "تقدير",
"suggestion": "اقتراح",
"yourFeedback": "تم إرسال ملاحظاتك",
"yourFeedback": "تم إرسال رأيك",
"selectPart": "يرجى اختيار الجزء الذي تشتكي منه",
"number": "رقم",
"notClassified": "غير مصنف",
@ -728,6 +736,11 @@ class CodegenLoader extends AssetLoader{
"bloodDonation": "التبرع بالدم",
"bloodDonationInfo": "من خلال هذه الخدمة، يمكنك تسجيل اسمك كمتبرع بالدم حيث سيتواصل معك بنك الدم في مجموعة الحبيب الطبية في حالة الحاجة إلى فصيلة الدم.",
"bloodInstruction": "أدخل المعلومات المطلوبة، من أجل التسجيل في خدمة التبرع بالدم",
"aboutBloodDonation": "عن التبرع بالدم",
"bloodDonationDescription": "التبرع بالدم هو عمل نبيل ينقذ الأرواح. كل تبرع واحد يمكن أن ينقذ ما يصل إلى ثلاثة أشخاص. من خلال التبرع بالدم، فإنك تساعد المرضى الذين يحتاجون إلى عمليات نقل دم، وحالات الطوارئ، والعلاجات الطبية.",
"bloodDonationBenefit1": "عملية آمنة وسريعة (10-15 دقيقة)",
"bloodDonationBenefit2": "يمكنك التبرع كل 8-12 أسبوع",
"bloodDonationBenefit3": "فحص صحي مجاني لدمك",
"viewTerms": "لعرض الشروط والأحكام",
"wantConnectHmgNetwork": "عزيزي العميل، لا يوجد وصول إلى الإنترنت، هل ترغب في الاتصال بشبكة مجموعة الحبيب الطبية لاستخدام تطبيقنا، تأكد من أنك في نطاق شبكة مجموعة الحبيب الطبية",
"failedToAccessHmgServices": "متصل بشبكة مجموعة الحبيب الطبية،\n\nلكن فشل في الوصول إلى خدمات مجموعة الحبيب الطبية",
@ -871,7 +884,7 @@ class CodegenLoader extends AssetLoader{
"onboardingBody1": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره.",
"onboardingHeading2": "الوصول إلى السجل الطبي بين يديك",
"onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها.",
"hmgHospitals": "مستشفيات مجموعة الحبيب الطبية",
"hmgHospitals": "مستشفيات الحبيب",
"hmcMedicalClinic": "مراكز مجموعة الحبيب الطبية",
"applyFilter": "تطبيق الفلتر",
"facilityAndLocation": "المرفق والموقع",
@ -920,6 +933,7 @@ class CodegenLoader extends AssetLoader{
"vat15": "ضريبة القيمة المضافة 15%",
"liveCare": "لايف كير",
"recentVisits": "الزيارات الأخيرة",
"favouriteDoctors": "الأطباء المفضلون",
"searchByClinic": "البحث حسب العيادة",
"tapToSelectClinic": "انقر لاختيار العيادة",
"searchByDoctor": "البحث حسب الطبيب",
@ -945,7 +959,7 @@ class CodegenLoader extends AssetLoader{
"hospitalInformation": "معلومات المستشفى",
"fetchingAppointmentShare": "جاري جلب تفاصيل الموعد...",
"bookingYourAppointment": "جاري حجز موعدك...",
"selectLiveCareClinic": "اختر عيادة لايف كير",
"selectLiveCareClinic": "عيادة لايف كير",
"checkingForExistingDentalPlan": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار...",
"dentalTreatmentPlan": "خطة علاج الأسنان",
"youHaveExistingTreatmentPlan": "لديك خطة علاج حالية: ",
@ -1256,7 +1270,7 @@ class CodegenLoader extends AssetLoader{
"quickLinks": "روابط سريعة",
"viewMedicalFileLandingPage": "عرض الملف الطبي",
"immediateLiveCareRequest": "طلب لايف كير فوري",
"yourTurnIsAfterPatients": "دورك بعد {count} مريض.",
"yourTurnIsAfterPatients": "دورك بعد {count} مريض. يرجى الانتظار حتى يحين دورك، وسيناديك الطبيب قريباً.",
"dontHaveHHCOrders": "ليس لديك أي أوامر رعاية صحية منزلية حتى الآن.",
"hhcOrders": "أوامر الرعاية الصحية المنزلية",
"requestedServices": "الخدمات المطلوبة",
@ -1583,7 +1597,7 @@ class CodegenLoader extends AssetLoader{
"noFreeSlot": "لا توجد مواعيد متاحة في التاريخ المحدد. يرجى اختيار تاريخ آخر أو إعادة المحاولة لاحقاً.",
"noThanksIKnowTheClinic": "لا، شكراً. أنا أعرف العيادة.",
"unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة",
"loadingAIAnalysis": "جارٍ تحليل نتائج المختبر، يرجى التحلي بالصبر والسماح للذكاء الاصطناعي بالقيام بالمهمة، قد يستغرق هذا بعض الوقت.",
"loadingAIAnalysis": "نقوم بتحليل نتائجك، يرجى التحلي بالصبر والسماح للذكاء الاصطناعي بالقيام بالمهمة، قد يستغرق هذا بعض الوقت.",
"symptoms": "أعراض",
"insuranceInActive": "التأمين غير نشط",
"insuranceInActiveContactSupport": "لديك تأمين ساري المفعول، ولكنه غير مُفعّل حاليًا في مجموعة حبيب الطبية. يُرجى التواصل مع خدمة عملاء مجموعة حبيب الطبية.",
@ -1593,9 +1607,24 @@ class CodegenLoader extends AssetLoader{
"invalidEligibility": "لا يمكنك إجراء الدفع عبر الإنترنت لأنك غير مؤهل لاستخدام الخدمة المقدمة.",
"invalidInsurance": "لا يمكنك إجراء الدفع عبر الإنترنت لأنه ليس لديك تأمين صالح.",
"continueCash": "متابعة الدفع نقدًا",
"applewatch": "ساعة آبل",
"applehealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Apple Health على هاتفك",
"unabletodetectapplicationinstalledpleasecomebackonceinstalled": "لا يمكننا اكتشاف التطبيق المثبت على جهازك. يرجى العودة إلى هنا بمجرد تثبيت هذا التطبيق.",
"applewatchshouldbeconnected": "يجب توصيل ساعة آبل",
"samsungwatch": "ساعة سامسونج",
"samsunghealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Samsung Health على هاتفك",
"samsungwatchshouldbeconnected": "يجب توصيل ساعة سامسونج",
"huaweiwatch": "ساعة هواوي",
"huaweihealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Huawei Health على هاتفك",
"huaweiwatchshouldbeconnected": "يجب توصيل ساعة هواوي",
"whoopwatch": "ساعة Whoop",
"whoophealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Whoop Health على هاتفك",
"whoopwatchshouldbeconnected": "يجب توصيل ساعة Whoop",
"updatetheinformation": "سيتيح ذلك جمع أحدث المعلومات من ساعة آبل الخاصة بك",
"timeFor": "الوقت",
"hmgPolicies": "سياسات مجموعة الحبيب الطبية",
"darkMode": "المظهر الداكن",
"featureComingSoonDescription": "هذه الميزة ستتوفر قريباً. نحن نعمل جاهدين لإضافة ميزات أكثر تميزاً إلى التطبيق. انتظرونا لمتابعة التحديثات.",
"generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI",
"ratings": "التقييمات",
"hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية.",
@ -1604,13 +1633,106 @@ class CodegenLoader extends AssetLoader{
"verifyInsurance": "التحقق من التأمين",
"tests": "تحليل",
"calendarPermissionAlert": "يرجى منح إذن الوصول إلى التقويم من إعدادات التطبيق لضبط تذكير تناول الدواء.",
"sortByLocation": "الترتيب حسب الموقع"
"sortByNearestLocation": "فرز حسب الأقرب إلى موقعك",
"giveLocationPermissionForNearestList": "يرجى منح إذن الوصول إلى الموقع من إعدادات التطبيق لعرض أقرب المواقع.",
"sortByLocation": "الترتيب حسب الموقع",
"timeForFirstReminder": "وقت التذكير الأول",
"reminderRemovalNote": "يمكنك إزالتها من التقويم الخاص بك لاحقاً عن طريق إيقاف تشغيل التذكير",
"communicationLanguage": "لغة التواصل",
"cmcServiceHeader": "فحص صحي شامل: تشخيص متقدم، معلومات صحية مفصلة",
"cmcServiceDescription": "احصل على معلومات تفصيلية عن صحتك من خلال خدمات التشخيص المتقدمة لدينا. افهم جسمك بشكل أفضل لمستقبل صحي.",
"eReferralServiceHeader": "نظام الإحالة الإلكترونية في مستشفى حبيب: تبسيط عملية إحالة المرضى",
"eReferralServiceDescription": "نُسهّل عملية نقل المرضى بسلاسة إلى مستشفى حبيب من خلال نظام الإحالة الإلكترونية الآمن لدينا. نضمن استمرارية الرعاية لكل مريض.",
"bloodDonationServiceHeader": "تبرع بالدم، أنقذ الأرواح. تبرعك يُحدث فرقاً.",
"bloodDonationServiceDescription": "تبرّع بالدم، وأنقذ الأرواح. تبرعك يبعث الأمل. انضم لحملة التبرع بالدم وكن شريان حياة للمحتاجين. كل قطرة تُحدث فرقًا!",
"healthTrackersServiceHeader": "تتبّع مؤشراتك الحيوية بسهولة ويسر",
"healthTrackersServiceDescription": "أدخل بياناتك لمراقبة معدل ضربات القلب وضغط الدم بشكل مستمر، بالإضافة إلى ملخصات دقيقة لأنشطتك اليومية. ابقَ على اطلاع وحسّن صحتك بسهولة.",
"waterConsumptionServiceHeader": "حافظ على رطوبتك، حافظ على صحتك. تتبع كمية الماء التي تشربها يومياً بكل سهولة.",
"waterConsumptionServiceDescription": "أروِ عطشك، وتابع صحتك. راقب كمية الماء التي تتناولها يومياً بكل سهولة باستخدام تطبيقنا سهل الاستخدام، مما يضمن لك الترطيب الأمثل والصحة الجيدة.",
"smartWatchServiceHeader": "قم بمزامنة ساعتك الذكية مع تطبيقات الصحة",
"smartWatchServiceDescription": "قم بتوصيل ساعتك الذكية بسلاسة بتطبيقنا الصحي لتتبع البيانات بسهولة والحصول على رؤى شخصية.",
"liveChatServiceHeader": "مساعدة الخبراء على مدار الساعة طوال أيام الأسبوع\n\nمساعدة",
"liveChatServiceDescription": "هل تحتاج إلى مساعدة؟ تتيح لك خدمة الدردشة المباشرة لدينا التواصل مع فريق دعم الخبراء للإجابة على أي أسئلة لديك حول الميزات أو الإعدادات أو استكشاف الأخطاء وإصلاحها.",
"emergencyServiceHeader": "تسجيل الوصول إلى قسم الطوارئ، أسرع من أي وقت مضى. اتصل بالإسعاف / فريق الاستجابة السريعة على الفور",
"emergencyServiceDescription": "هل تواجه حالة طبية طارئة؟ سيارات الإسعاف وفرق الاستجابة السريعة لدينا جاهزة على مدار الساعة. بالإضافة إلى ذلك، يمكنك تسجيل دخولك إلى قسم الطوارئ بسرعة لتلقي رعاية أسرع.",
"homeHealthCareServiceHeader": "صحتك، في أبهى صورها. رعاية فائقة الجودة، تصلك إلى عتبة دارك.",
"homeHealthCareServiceDescription": "نقدم لكم رعاية صحية عالية الجودة تصلكم إلى عتبة منزلكم. ممرضات ذوات خبرة يقدمون رعاية حانية في راحة منزلكم.",
"profileOnlyText": "الملف الشخصي",
"information": "معلومة",
"noFavouriteDoctors": "ليس لديك أي قائمة مفضلة حتى الآن",
"addDoctors": "إضافة الأطباء",
"favouriteList": "قائمة المفضلة",
"later": "لاحقاً",
"cancelAppointmentConfirmMessage": "هل أنت متأكد من رغبتك في إلغاء هذا الموعد؟",
"acknowledged": "معترف به",
"searchLabResults": "بحث نتائج المختبر",
"callForAssistance": "اتصل للحصول على المساعدة الفورية",
"oneWaySubtitle": "نقل من الموقع إلى المستشفى",
"twoWaySubtitle": "نقل من الموقع إلى المستشفى والعودة مرة أخرى",
"toHospitalSubtitle": "نقل من موقعك الحالي إلى المستشفى",
"fromHospitalSubtitle": "نقل من المستشفى إلى منزلك",
"clinicSchedule": "جدول العيادة",
"doctorAddedToFavourite": "تمت إضافة إلى قائمة المفضلة",
"doctorRemovedFromFavourite": "تمت إزالة من قائمة الأطباء المفضلين",
"addNewFavorite": "إضافة مفضلة جديدة",
"favourites": "المفضلة",
"pendingAncillaryOrders": "مدفوعات طلبات الاضافية",
"liveCarePermissions": "يتطلب لايف كير أذونات الكاميرا والميكروفون وإشعارات، يرجى السماح لها بالمتابعة.",
"containsImage": "يحتوي على صورة",
"servicesSelected": "الخدمة (الخدمات) المختارة",
"selectMedicalFileFromFamily": "اختر ملف طبي من عائلتك",
"anyFileFromHMG": "أي ملف طبي نشط من مجموعة حبيب الطبية",
"noDistance": "المسافة غير متوفرة",
"enterAmount": "يرجى إدخال المبلغ للمتابعة.",
"selectHospitalContinue": "يرجى اختيار المستشفى للمتابعة.",
"year": "سنة",
"notifyPrescription": "أبلغني قبل وقت الاستهلاك",
"doctorRatingAppointment": "طبيب\nتصنيف",
"ratingSubmitted": "تم إرسال التقييم",
"rateTheDoctor": "يرجى تقييم الطبيب",
"downloadInvoice": "تحميل الفاتورة",
"approvalDetails": "تفاصيل الموافقة",
"obese": "سمين",
"overWeight": "وزن زائد",
"underWeight": "وزن ناقص",
"nearestGate": "أقرب بوابة",
"RRTDDetails": "فريق الاستجابة السريعة يقوم بتقديم رعاية صحية متكاملة لجميع الحالات الطارئة و المستقرة، الخدمة تشمل جميع الأعمار بما في ذلك حالات الأطفال.",
"normalMapType": "افتراضي",
"satelliteMapType": "قمر صناعي",
"terrainMapType": "تضاريس",
"hybridMapType": "هجين",
"openCamera": "افتح الكاميرا",
"openGallery": "افتح المعرض",
"openFiles": "فتح الملفات",
"generateAiAnalysisRadResult": "بإنشاء تحليل الذكاء الاصطناعي لهذا التقرير",
"grantLocationPermission": "يرجى منح إذن الوصول إلى الموقع من إعدادات التطبيق للحصول على نتائج أفضل.",
"NoBookedAppointments": "لا توجد مواعيد محجوزة",
"aiDisclaimerRad": "سيتم مشاركة بيانات نتائج الأشعة الخاصة بك بشكل آمن مع محلل الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في توفير رؤى صحية مخصصة. هل ترغب في المتابعة؟",
"imageSizeTooLarge": "حجم الصورة كبير جداً. الحد الأقصى للحجم هو 1 ميجابايت",
"profileImageUpdatedSuccessfully": "تم تحديث صورة الملف الشخصي بنجاح",
"failedToProcessImage": "فشل في معالجة الصورة. يرجى المحاولة مرة أخرى",
"cameraGalleryPermissionMessage": "مطلوب إذن الكاميرا والمعرض لتحميل صورة الملف الشخصي. يرجى منح الأذونات من إعدادات التطبيق.",
"cameraGalleryPermissionRequired": "مطلوب أذونات الكاميرا والمعرض",
"cameraPermissionMessage": "مطلوب إذن الكاميرا لالتقاط الصور. يرجى منح الإذن من إعدادات التطبيق.",
"cameraPermissionRequired": "مطلوب إذن الكاميرا",
"galleryPermissionMessage": "مطلوب إذن المعرض لتحديد الصور. يرجى منح الإذن من إعدادات التطبيق.",
"galleryPermissionRequired": "مطلوب إذن المعرض",
"failedToCheckPermissions": "فشل في التحقق من الأذونات. يرجى المحاولة مرة أخرى",
"takePhotoWithCamera": "التقط صورة بالكاميرا",
"selectFromPhotoLibrary": "اختر من مكتبة الصور",
"selectDocumentFiles": "اختر ملفات المستندات",
"profilePicture": "صورة الملف الشخصي",
"sendingAskDrRequest": "جارٍ إرسال الطلب...",
"askDrRequestSentSuccess": "تم إرسال الطلب بنجاح، وسيتواصل معك الطبيب قريباً.",
"onlineCheckIn24HoursOnly": "لا تتوفر خدمة تسجيل الوصول عبر الإنترنت إلا خلال 4 ساعات من موعد الحجز.لا تتوفر خدمة تسجيل الوصول عبر الإنترنت إلا خلال 4 ساعات من موعد الحجز."
};
static const Map<String,dynamic> _en_US = {
"english": "English",
"arabic": "Arabic",
"login": "Login",
"noDataAvailable": "No Data Available",
"noRatingAvailable": "No Rating Available",
"doctorDoesNotHaveRating": "This doctor does not have any ratings yet.",
"confirm": "Confirm",
"loadingText": "Loading, please wait...",
"kilometerUnit": "KM",
@ -1795,7 +1917,7 @@ static const Map<String,dynamic> _en_US = {
"lastName": "Last Name",
"female": "Female",
"male": "Male",
"preferredLanguage": "Preferred Language *",
"preferredLanguage": "Preferred Language",
"locationsRegister": "Where do you want to create this file?",
"ksa": "KSA",
"dubai": "Dubai",
@ -1906,9 +2028,15 @@ static const Map<String,dynamic> _en_US = {
"medicinesSubtitle": "Prescriptions",
"vitalSigns": "Vital Signs",
"vitalSignsSubTitle": "Reports",
"vitalSignNormal": "Normal",
"vitalSignLow": "Low",
"vitalSignHigh": "High",
"vitalSignObese": "Obese",
"vitalSignOverweight": "Overweight",
"vitalSignUnderweight": "Underweight",
"myMedical": "Active",
"myMedicalSubtitle": "Medications",
"myDoctor": "My Doctor",
"myDoctor": "My Doctors",
"myDoctorSubtitle": "List",
"eye": "Eye",
"eyeSubtitle": "Measurement",
@ -2316,6 +2444,11 @@ static const Map<String,dynamic> _en_US = {
"bloodDonation": "Blood Donation",
"bloodDonationInfo": "Through this service, you can register your name as a blood donor where the blood bank in the Habib Medical Group will communicate you in case of need for blood type.",
"bloodInstruction": "Enter the required information, in order to register for Blood Donation Service",
"aboutBloodDonation": "About Blood Donation",
"bloodDonationDescription": "Blood donation is a noble act that saves lives. Every single donation can save up to three people. By donating blood, you help patients in need of transfusions, emergencies, and medical treatments.",
"bloodDonationBenefit1": "Safe and quick process (10-15 minutes)",
"bloodDonationBenefit2": "You can donate every 8-12 weeks",
"bloodDonationBenefit3": "Free health check of your blood",
"viewTerms": "To view the terms and conditions",
"wantConnectHmgNetwork": "Dear customer there is no internet access, do you want to connect with HMG network to use our app, make sure you are in range of HMG network",
"failedToAccessHmgServices": "Connected with HMG Network,\n\nBut failed to access HMG services",
@ -2509,6 +2642,7 @@ static const Map<String,dynamic> _en_US = {
"vat15": "VAT 15%",
"liveCare": "LiveCare",
"recentVisits": "Recent Visits",
"favouriteDoctors": "Favourite Doctors",
"searchByClinic": "Search By Clinic",
"tapToSelectClinic": "Tap to select clinic",
"searchByDoctor": "Search By Doctor",
@ -2534,7 +2668,7 @@ static const Map<String,dynamic> _en_US = {
"hospitalInformation": "Hospital Information",
"fetchingAppointmentShare": "Fetching Appointment Share...",
"bookingYourAppointment": "Booking your appointment...",
"selectLiveCareClinic": "Select LiveCare Clinic",
"selectLiveCareClinic": "LiveCare Clinic",
"checkingForExistingDentalPlan": "Checking for an existing dental plan, Please wait...",
"dentalTreatmentPlan": "Dental treatment plan",
"youHaveExistingTreatmentPlan": "You have an existing treatment plan: ",
@ -2845,7 +2979,7 @@ static const Map<String,dynamic> _en_US = {
"quickLinks": "Quick Links",
"viewMedicalFileLandingPage": "View medical file",
"immediateLiveCareRequest": "Immediate LiveCare Request",
"yourTurnIsAfterPatients": "Your turn is after {count} patients.",
"yourTurnIsAfterPatients": "Your turn is after {count} patients. Please wait for your turn, The doctor will call you shortly.",
"dontHaveHHCOrders": "You don't have any Home Health Care orders yet.",
"hhcOrders": "HHC Orders",
"requestedServices": "Requested Services",
@ -2913,7 +3047,7 @@ static const Map<String,dynamic> _en_US = {
"rejectedYourFamilyMemberRequest": "{status} your family member request",
"notAvailable": "N/A",
"selectAProfile": "Please select a profile",
"switchFamilyFile": "Switch from the below list of medical file",
"switchFamilyFile": "Switch from the below list of medical files",
"medicalFiles": "Medical Files",
"addANewFamilyMember": "Add a new family member",
"viewInvoiceDetails": "View invoice details",
@ -3175,7 +3309,7 @@ static const Map<String,dynamic> _en_US = {
"contextDependent": "Context Dependent",
"calculatedValue": "Calculated Value",
"calculationFormula": "Calculation Formula",
"loadingAIAnalysis": "Analysing your lab results, Please be patient and let the AI do the magic, This might take some time.",
"loadingAIAnalysis": "Analysing your results, Please be patient and let the AI do the magic, This might take some time.",
"symptoms": "Symptoms",
"insuranceInActive": "Insurance Inactive",
"insuranceInActiveContactSupport": "You have a valid insurance but it is currently inactive in HMG. Please contact HMG customer support to activate it.",
@ -3185,8 +3319,23 @@ static const Map<String,dynamic> _en_US = {
"invalidEligibility": "You cannot make online payment because you are not eligible to use the provided service.",
"invalidInsurance": "You cannot make online payment because you do not have a valid insurance.",
"continueCash": "Continue as cash",
"applewatch": "Apple Watch",
"applehealthapplicationshouldbeinstalledinyourphone": "Apple Health application should be installed in your phone",
"unabletodetectapplicationinstalledpleasecomebackonceinstalled": "We are unable to detect the application installed in your device. Please come back here once you have installed this application.",
"applewatchshouldbeconnected": "Apple Watch should be connected",
"samsungwatch": "Samsung Watch",
"samsunghealthapplicationshouldbeinstalledinyourphone": "Samsung Health application should be installed in your phone",
"samsungwatchshouldbeconnected": "Samsung Watch should be connected",
"huaweiwatch": "Huawei Watch",
"huaweihealthapplicationshouldbeinstalledinyourphone": "Huawei Health application should be installed in your phone",
"huaweiwatchshouldbeconnected": "Huawei Watch should be connected",
"whoopwatch": "Whoop Watch",
"whoophealthapplicationshouldbeinstalledinyourphone": "Whoop Health application should be installed in your phone",
"whoopwatchshouldbeconnected": "Whoop Watch should be connected",
"updatetheinformation": "This will allow to gather the most up to date information from your apple watch",
"timeFor": "Time For",
"hmgPolicies": "HMG Policies",
"featureComingSoonDescription": "Feature is coming soon. We are actively working to bring more exciting features into the app. Stay tuned for updates.",
"darkMode": "Dark Mode",
"generateAiAnalysisResult": "Generate AI analysis for this result",
"ratings": "Ratings",
@ -3196,7 +3345,98 @@ static const Map<String,dynamic> _en_US = {
"verifyInsurance": "Verify Insurance",
"tests": "tests",
"calendarPermissionAlert": "Please grant calendar access permission from app settings to set medication reminder.",
"sortByLocation": "Sort by location"
"timeForFirstReminder": "Time for 1st reminder",
"reminderRemovalNote": "You can remove it from your calendar later by switching off the reminder",
"sortByLocation": "Sort by location",
"sortByNearestLocation": "Sort by nearest to your location",
"giveLocationPermissionForNearestList": "Please grant location permission from app settings to see the nearest locations.",
"communicationLanguage": "Communication Language",
"cmcServiceHeader": "Complete Health Checkup: Advanced diagnostics, Detailed Health insights",
"cmcServiceDescription": "Get detailed insights into your health with our advanced diagnostics. Understand your body better for a healthier future.",
"eReferralServiceHeader": "HMG Hospital E-Referral: Streamlined patient referrals",
"eReferralServiceDescription": "Facilitate seamless patient transfers to HMG with our secure e-referral system. Ensure continuity of care for every patient.",
"bloodDonationServiceHeader": "Give Blood, Save Lives. Your donation makes a difference.",
"bloodDonationServiceDescription": "Donate blood, empower lives. Your contribution creates hope. Join our blood drive and be a lifeline for those in need. Every drop counts!",
"healthTrackersServiceHeader": "Track Your Vitals with Ease and effortlessly ",
"healthTrackersServiceDescription": "Input your metrics for continuous heart rate monitoring, blood pressure and precise daily activity summaries. Stay informed and optimize your well-being with ease.",
"waterConsumptionServiceHeader": "Stay Hydrated, Stay Healthy. Track your daily water intake with ease.",
"waterConsumptionServiceDescription": "Quench your thirst, track your health. Effortlessly monitor your daily water intake with our user-friendly app, ensuring optimal hydration and well-being.",
"smartWatchServiceHeader": "Sync Your Smartwatch with Health Apps",
"smartWatchServiceDescription": "Seamlessly connect your smartwatch to our health app for effortless data tracking and personalized insights.",
"liveChatServiceHeader": "24/7 Expert\nAssistance",
"liveChatServiceDescription": "Need help ? Our live chat connects you with expert support for any questions about features, settings, or troubleshooting.",
"emergencyServiceHeader": "ER Check-in, Faster Than Ever. Call ambulance / Rapid Response Team instantly",
"emergencyServiceDescription": "In a medical emergency? Our ambulances and rapid response teams are on standby 24/7. Plus, quick ER check-in for faster care.",
"homeHealthCareServiceHeader": "Your Health, Elevated. Premium care, delivered to your doorstep.",
"homeHealthCareServiceDescription": "We bring quality healthcare to your doorstep. Experienced nurses providing compassionate care in the comfort of your home.",
"profileOnlyText": "Profile",
"information": "Information",
"noFavouriteDoctors": "You don't have any favourite list yet",
"addDoctors": "Add Doctors",
"favouriteList": "Favourite List",
"later": "Later",
"cancelAppointmentConfirmMessage": "Are you sure you want to cancel this appointment?",
"acknowledged": "Acknowledged",
"searchLabResults": "Search lab results",
"callForAssistance": "Call for immediate assistance",
"oneWaySubtitle": "Pickup from location to hospital",
"twoWaySubtitle": "Round trip from location to hospital and back",
"toHospitalSubtitle": "Transfer from your current location to the hospital",
"fromHospitalSubtitle": "Transfer from the hospital back to your home",
"clinicSchedule": "Clinic Schedule",
"doctorAddedToFavourite": "Added to favorites list",
"doctorRemovedFromFavourite": "Removed from favorites list",
"favourites": "Favourites",
"addNewFavorite": "Add new favourite",
"pendingAncillaryOrders": "Pending ancillary orders",
"liveCarePermissions": "LiveCare requires Camera, Microphone & Notifications permissions to enable virtual consultation between patient & doctor, Open app settings to allow them.",
"containsImage": "Contains Image",
"servicesSelected": "Service(s) Selected",
"selectMedicalFileFromFamily": "Select a medical file from your family",
"anyFileFromHMG": "Any active medical file from HMG",
"noDistance": "Distance not available",
"enterAmount": "Please enter amount to continue.",
"selectHospitalContinue": "Please select hospital to continue.",
"year": "Year",
"notifyPrescription": "Notify me before the consumption time",
"doctorRatingAppointment": "Doctor\nRating",
"ratingSubmitted": "Rating Submitted",
"rateTheDoctor": "Please rate the doctor",
"downloadInvoice": "Download Invoice",
"approvalDetails": "Approval Details",
"obese": "Obese",
"overWeight": "OverWeight",
"underWeight": "UnderWeight",
"nearestGate": "Nearest Gate",
"RRTDDetails": "The Rapid response team provides a comprehensive medical service for all sorts of urgent and stable cases of all ages, including adult and paediatric patients.",
"normalMapType": "Default",
"satelliteMapType": "Satellite",
"terrainMapType": "Terrain",
"hybridMapType": "Hybrid",
"openCamera": "Open Camera",
"openGallery": "Open Gallery",
"openFiles": "Open Files",
"generateAiAnalysisRadResult": "Generate AI analysis for this result",
"grantLocationPermission": "Please grant location permission from app settings to see better results.",
"NoBookedAppointments": "No Booked Appointments",
"aiDisclaimerRad": "Your radiology result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?",
"imageSizeTooLarge": "Image size is too large. Maximum size is 1MB",
"profileImageUpdatedSuccessfully": "Profile image updated successfully",
"failedToProcessImage": "Failed to process image. Please try again",
"cameraGalleryPermissionMessage": "Camera and Gallery permissions are required to upload profile picture. Please grant permissions from app settings.",
"cameraGalleryPermissionRequired": "Camera and Gallery permissions are required",
"cameraPermissionMessage": "Camera permission is required to take photos. Please grant permission from app settings.",
"cameraPermissionRequired": "Camera permission is required",
"galleryPermissionMessage": "Gallery permission is required to select photos. Please grant permission from app settings.",
"galleryPermissionRequired": "Gallery permission is required",
"failedToCheckPermissions": "Failed to check permissions. Please try again",
"takePhotoWithCamera": "Take a photo with your camera",
"selectFromPhotoLibrary": "Select from your photo library",
"selectDocumentFiles": "Select document files",
"profilePicture": "Profile Picture",
"sendingAskDrRequest": "Sending Request...",
"askDrRequestSentSuccess": "Request has been sent successfully, The doctor will get back to you soon.",
"onlineCheckIn24HoursOnly": "Online Check-In is only available within 4 hours of the appointment time."
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US};
}

@ -302,6 +302,12 @@ abstract class LocaleKeys {
static const medicinesSubtitle = 'medicinesSubtitle';
static const vitalSigns = 'vitalSigns';
static const vitalSignsSubTitle = 'vitalSignsSubTitle';
static const vitalSignNormal = 'vitalSignNormal';
static const vitalSignLow = 'vitalSignLow';
static const vitalSignHigh = 'vitalSignHigh';
static const vitalSignObese = 'vitalSignObese';
static const vitalSignOverweight = 'vitalSignOverweight';
static const vitalSignUnderweight = 'vitalSignUnderweight';
static const myMedical = 'myMedical';
static const myMedicalSubtitle = 'myMedicalSubtitle';
static const myDoctor = 'myDoctor';
@ -716,6 +722,11 @@ abstract class LocaleKeys {
static const bloodDonation = 'bloodDonation';
static const bloodDonationInfo = 'bloodDonationInfo';
static const bloodInstruction = 'bloodInstruction';
static const aboutBloodDonation = 'aboutBloodDonation';
static const bloodDonationDescription = 'bloodDonationDescription';
static const bloodDonationBenefit1 = 'bloodDonationBenefit1';
static const bloodDonationBenefit2 = 'bloodDonationBenefit2';
static const bloodDonationBenefit3 = 'bloodDonationBenefit3';
static const viewTerms = 'viewTerms';
static const wantConnectHmgNetwork = 'wantConnectHmgNetwork';
static const failedToAccessHmgServices = 'failedToAccessHmgServices';

@ -554,11 +554,15 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
clinicDescription: widget.patientAppointmentHistoryResponseModel.clinicName,
decimalDoctorRate: widget.patientAppointmentHistoryResponseModel.decimalDoctorRate,
name: widget.patientAppointmentHistoryResponseModel.projectName,
isHomeMedicineDeliverySupported: false,
isHomeMedicineDeliverySupported: val.data.first.isHomeMedicineDeliverySupported ?? false,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
setupID: widget.patientAppointmentHistoryResponseModel.setupID,
isInOutPatient: widget.patientAppointmentHistoryResponseModel.isInOutPatient,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
episodeID: widget.patientAppointmentHistoryResponseModel.episodeID,
dischargeNo: 0,
);
Navigator.of(context).push(
CustomPageRoute(
@ -642,6 +646,13 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
);
},
),
callBackFunc: () {
myAppointmentsViewModel.getDoctorsRatingCheck(
doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo);
},
isFullScreen: false,
);
}

@ -154,7 +154,8 @@ class _AppointmentRatingWidgetState extends State<AppointmentRatingWidget> {
Expanded(
child: CustomButton(
text: LocaleKeys.submit.tr(context: context),
onPressed: () async {
isDisabled: rating == 0,
onPressed: rating == 0 ? null : () async {
// Set up clinic rating and show clinic rating view
// appointmentRatingViewModel!.setTitle(LocaleKeys.rateDoctor.tr(context: context),);
// appointmentRatingViewModel!.setSubTitle(LocaleKeys.howWasYourLastVisitWithDoctor.tr(context: context),);
@ -165,7 +166,6 @@ class _AppointmentRatingWidgetState extends State<AppointmentRatingWidget> {
// await appointmentRatingViewModel!.submitClinicRating(clinicRate: rating, clinicNote: note);
LoaderBottomSheet.hideLoader();
Navigator.pop(context);
setState(() {});
},
),

@ -56,11 +56,11 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
child: CollapsingListView(
title: LocaleKeys.bloodDonation.tr(),
trailing: CustomButton(
text: "Book",
text: LocaleKeys.book.tr(context: context),
onPressed: () {
if (bloodDonationVM.isUserAuthanticated()) {
bloodDonationVM.fetchHospitalsList().then((value) {
showCommonBottomSheetWithoutHeight(context, title: "Select Hospital", isDismissible: false, child: Consumer<BloodDonationViewModel>(builder: (_, data, __) {
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.selectHospital.tr(context: context), isDismissible: false, child: Consumer<BloodDonationViewModel>(builder: (_, data, __) {
return HospitalBottomSheetBodySelection(
isHideTitle: true,
onUserHospitalSelection: (BdGetProjectsHaveBdClinic userChoice) {
@ -224,6 +224,109 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
child: SelectBloodGroupWidget(isArabic: appState.isArabic(), bloodDonationViewModel: bloodDonationVM),
callBackFunc: () {});
}),
SizedBox(height: 24.h),
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bgRedLightColor.withValues(alpha: 0.1),
borderRadius: 12.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: EdgeInsets.all(8.h),
decoration: BoxDecoration(
color: AppColors.primaryRedColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8.r),
),
child: Utils.buildSvgWithAssets(
icon: AppAssets.blood_icon,
width: 20.h,
height: 20.h,
iconColor: AppColors.primaryRedColor,
),
),
SizedBox(width: 12.w),
Expanded(
child: LocaleKeys.aboutBloodDonation.tr(context: context).toText16(
color: AppColors.primaryRedColor,
isBold: true,
),
),
],
),
SizedBox(height: 12.h),
LocaleKeys.bloodDonationDescription.tr(context: context).toText14(
color: AppColors.greyTextColor,
isBold: true,
),
SizedBox(height: 12.h),
Row(
children: [
Container(
width: 4.w,
height: 4.h,
decoration: BoxDecoration(
color: AppColors.primaryRedColor,
shape: BoxShape.circle,
),
),
SizedBox(width: 8.w),
Expanded(
child: LocaleKeys.bloodDonationBenefit1.tr(context: context).toText13(
color: AppColors.textColor,
isBold: true,
),
),
],
),
SizedBox(height: 8.h),
Row(
children: [
Container(
width: 4.w,
height: 4.h,
decoration: BoxDecoration(
color: AppColors.primaryRedColor,
shape: BoxShape.circle,
),
),
SizedBox(width: 8.w),
Expanded(
child: LocaleKeys.bloodDonationBenefit2.tr(context: context).toText13(
color: AppColors.textColor,
isBold: true,
),
),
],
),
SizedBox(height: 8.h),
Row(
children: [
Container(
width: 4.w,
height: 4.h,
decoration: BoxDecoration(
color: AppColors.primaryRedColor,
shape: BoxShape.circle,
),
),
SizedBox(width: 8.w),
Expanded(
child: LocaleKeys.bloodDonationBenefit3.tr(context: context).toText13(
color: AppColors.textColor,
isBold: true,
),
),
],
),
],
),
),
],
),
),

@ -117,7 +117,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
SizedBox(height: 24.h),
getSelectedTabData(bookAppointmentsVM.selectedTabIndex),
SizedBox(height: 24.h),
if (appState.isAuthenticated) ...[
if (appState.isAuthenticated && bookAppointmentsVM.selectedTabIndex == 0) ...[
Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return myAppointmentsVM.isPatientMyDoctorsLoading
? SizedBox(

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -73,6 +74,8 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
authVM = Provider.of<AuthenticationViewModel>(context, listen: false);
appState = getIt.get<AppState>();
final isArabic = appState.isArabic();
return Padding(
padding: EdgeInsets.symmetric(horizontal: 0.h),
child: Column(
@ -90,87 +93,93 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
// ),
SizedBox(
height: 350.h,
child: Localizations.override(
context: context,
locale: const Locale('en'),
child: SfCalendar(
controller: _calendarController,
minDate: DateTime.now(),
showNavigationArrow: true,
headerHeight: 60.h,
headerStyle: CalendarHeaderStyle(
backgroundColor: AppColors.transparent,
textAlign: TextAlign.start,
textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor, fontFamily: "Poppins"),
),
viewHeaderStyle: ViewHeaderStyle(
// backgroundColor: AppColors.scaffoldBgColor,
dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor, fontFamily: "Poppins"),
),
view: CalendarView.month,
todayHighlightColor: Colors.transparent,
todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold, fontFamily: "Poppins"),
selectionDecoration: ShapeDecoration(
color: AppColors.transparent,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.circular(10.r),
smoothness: 1,
side: BorderSide(color: AppColors.primaryRedColor, width: 1.5),
child: Directionality(
textDirection: isArabic ? ui.TextDirection.rtl : ui.TextDirection.ltr,
child: Localizations.override(
context: context,
locale: isArabic ? const Locale('ar', 'SA') : const Locale('en'),
child: SfCalendar(
controller: _calendarController,
minDate: DateTime.now(),
showNavigationArrow: true,
headerHeight: 60.h,
headerStyle: CalendarHeaderStyle(
backgroundColor: AppColors.transparent,
textAlign: isArabic ? TextAlign.end : TextAlign.start,
textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor),
),
),
cellBorderColor: AppColors.transparent,
dataSource: MeetingDataSource(_getDataSource()),
monthCellBuilder: (context, details) => Padding(
padding: EdgeInsets.all(12.h),
child: details.date.day.toString().toText14(
isCenter: true,
color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor,
isEnglishOnly: true,
),
),
monthViewSettings: MonthViewSettings(
dayFormat: "EEE",
appointmentDisplayMode: MonthAppointmentDisplayMode.indicator,
showTrailingAndLeadingDates: false,
appointmentDisplayCount: 1,
monthCellStyle: MonthCellStyle(
textStyle: TextStyle(fontSize: 19.f),
viewHeaderStyle: ViewHeaderStyle(
// backgroundColor: AppColors.scaffoldBgColor,
dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor),
),
view: CalendarView.month,
todayHighlightColor: Colors.transparent,
todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold),
selectionDecoration: ShapeDecoration(
color: AppColors.transparent,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.circular(10.r),
smoothness: 1,
side: BorderSide(color: AppColors.primaryRedColor, width: 1.5),
),
),
cellBorderColor: AppColors.transparent,
dataSource: MeetingDataSource(_getDataSource()),
monthCellBuilder: (context, details) => Padding(
padding: EdgeInsets.all(12.h),
child: details.date.day.toString().toText14(
isCenter: true,
color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor,
isEnglishOnly: true,
),
),
monthViewSettings: MonthViewSettings(
dayFormat: "EEE",
appointmentDisplayMode: MonthAppointmentDisplayMode.indicator,
showTrailingAndLeadingDates: false,
appointmentDisplayCount: 1,
monthCellStyle: MonthCellStyle(
textStyle: TextStyle(fontSize: 19.f),
),
),
onTap: (CalendarTapDetails details) {
_calendarController.selectedDate = details.date;
_onDaySelected(details.date!);
},
),
onTap: (CalendarTapDetails details) {
_calendarController.selectedDate = details.date;
_onDaySelected(details.date!);
},
),
),
),
SizedBox(height: 10.h),
Transform.translate(
offset: const Offset(0.0, -10.0),
child: selectedDateDisplay.toText16(isBold: true, isEnglishOnly: true),
child: selectedDateDisplay.toText16(isBold: true, isEnglishOnly: !isArabic),
),
//TODO: Add Next Day Span here
dayEvents.isNotEmpty
? SizedBox(
height: 100.h,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.start,
spacing: 6.h,
runSpacing: 6.h,
children: List.generate(
dayEvents.length, // Generate a large number of items to ensure scrolling
(index) => TimeSlotChip(
label: dayEvents[index].isoTime!,
isSelected: index == selectedButtonIndex,
onTap: () {
setState(() {
selectedButtonIndex = index;
selectedTime = dayEvents[index].isoTime!;
});
},
child: Directionality(
textDirection: isArabic ? ui.TextDirection.rtl : ui.TextDirection.ltr,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.start,
spacing: 6.h,
runSpacing: 6.h,
children: List.generate(
dayEvents.length, // Generate a large number of items to ensure scrolling
(index) => TimeSlotChip(
label: dayEvents[index].isoTime!,
isSelected: index == selectedButtonIndex,
onTap: () {
setState(() {
selectedButtonIndex = index;
selectedTime = dayEvents[index].isoTime!;
});
},
),
),
),
),
@ -322,9 +331,12 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
void _onDaySelected(DateTime day) {
final DateFormat formatter = DateFormat('yyyy-MM-dd', "en-US");
final isArabic = appState.isArabic();
setState(() {
selectedDateDisplay = DateUtil.getMonthDayYearDateFormatted(day);
selectedNextDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day.add(Duration(days: 1)), "en");
selectedDateDisplay = isArabic
? DateUtil.getMonthDayYearDateFormattedAr(day)
: DateUtil.getMonthDayYearDateFormatted(day);
selectedNextDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day.add(Duration(days: 1)), isArabic ? "ar" : "en");
_calendarController.selectedDate = day;
openTimeSlotsPickerForDate(day, bookAppointmentsViewModel.docFreeSlots);
selectedDate = formatter.format(day);

@ -104,10 +104,9 @@ class _NewReferralPageState extends State<NewReferralPage> {
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
// setState(() {
_currentStep++;
// });
// widget.onStepChanged(_currentStep);
setState(() {
_currentStep++;
});
}
void _submitReferral() {
@ -133,8 +132,10 @@ class _NewReferralPageState extends State<NewReferralPage> {
hmgServicesVM.createEReferral(
requestModel: createReferralRequestModel,
onSuccess: (GenericApiModel response) {
showSuccessBottomSheet(int.parse(response.data), hmgServicesVM);
LoaderBottomSheet.hideLoader();
showSuccessBottomSheet(int.parse(response.data), hmgServicesVM);
},
onError: (errorMessage) {
// Handle error (e.g., show error message)
@ -190,7 +191,8 @@ class _NewReferralPageState extends State<NewReferralPage> {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (index) {
if (_currentStep == index) {
// Fill current step and all previous completed steps
if (index <= _currentStep) {
return StepperWidget(widthOfOneState, AppColors.primaryRedColor, true, 4.h);
} else {
return StepperWidget(widthOfOneState, AppColors.greyLightColor, false, 4.h);
@ -200,8 +202,8 @@ class _NewReferralPageState extends State<NewReferralPage> {
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
onPageChanged: (index) => {
// setState(() => _currentStep = index)
onPageChanged: (index) {
setState(() => _currentStep = index);
},
children: [
RequesterFormStep(),

@ -63,28 +63,12 @@ class OTPService {
Navigator.pop(context);
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
LoaderBottomSheet.showLoader();
hmgServicesViewModel.eReferralSendActivationCode(
requestModel: SendActivationCodeForEReferralRequestModel(
patientMobileNumber: int.parse(formManager.formData.requesterPhone),
zipCode: formManager.formData.countryEnum.countryCode,
patientOutSA: formManager.formData.countryEnum.countryCode == '966' ? 0 : 1,
),
onSuccess: (GenericApiModel response) {
LoaderBottomSheet.hideLoader();
hmgServicesViewModel.navigateToOTPScreen(
otpTypeEnum: OTPTypeEnum.sms,
phoneNumber: formManager.formData.requesterPhone,
loginToken: response.data,
onSuccess: () {
Navigator.pop(context);
onSuccess();
});
},
onError: (String errorMessage) {
LoaderBottomSheet.hideLoader();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage)));
},
// Start listening for SMS before sending OTP
_startSmsListener(
context: context,
hmgServicesViewModel: hmgServicesViewModel,
formManager: formManager,
onSuccess: onSuccess,
);
}
},
@ -100,4 +84,37 @@ class OTPService {
)),
);
}
static void _startSmsListener({
required BuildContext context,
required HmgServicesViewModel hmgServicesViewModel,
required ReferralFormManager formManager,
required Function onSuccess,
}) async {
LoaderBottomSheet.showLoader();
// Send OTP after starting listener
hmgServicesViewModel.eReferralSendActivationCode(
requestModel: SendActivationCodeForEReferralRequestModel(
patientMobileNumber: int.parse(formManager.formData.requesterPhone),
zipCode: formManager.formData.countryEnum.countryCode,
patientOutSA: formManager.formData.countryEnum.countryCode == '966' ? 0 : 1,
),
onSuccess: (GenericApiModel response) {
LoaderBottomSheet.hideLoader();
hmgServicesViewModel.navigateToOTPScreen(
otpTypeEnum: OTPTypeEnum.sms,
phoneNumber: formManager.formData.requesterPhone,
loginToken: response.data,
onSuccess: () {
Navigator.pop(context);
onSuccess();
});
},
onError: (String errorMessage) {
LoaderBottomSheet.hideLoader();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage)));
},
);
}
}

@ -159,14 +159,12 @@ class _AddHealthTrackerEntryPageState extends State<AddHealthTrackerEntryPage> {
context,
child: Utils.getSuccessWidget(
loadingText: _getSuccessMessage(),
),
callBackFunc: () {
Navigator.pop(context);
},
).paddingSymmetrical(0.h, 24.h), callBackFunc: () {
// Navigator.pop(context);
},
isCloseButtonVisible: false,
isDismissible: true,
isFullScreen: false,
);
isFullScreen: false, isAutoDismiss: true);
}
// Reusable method to build selection row widget

@ -430,6 +430,7 @@ class ServicesPage extends StatelessWidget {
title: LandingPageData.getServiceCardsList[index].title,
subtitle: LandingPageData.getServiceCardsList[index].subtitle,
icon: LandingPageData.getServiceCardsList[index].largeCardIcon,
isPNG: LandingPageData.getServiceCardsList[index].isPNG,
),
),
),
@ -471,7 +472,7 @@ class ServicesPage extends StatelessWidget {
Spacer(),
getIt.get<AppState>().isAuthenticated
? Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol2(num.parse(NumberFormat.decimalPattern().format(habibWalletVM.habibWalletAmount)), isExpanded: false)
return Utils.getPaymentAmountWithSymbol2(num.parse(NumberFormat.decimalPattern().format(habibWalletVM.habibWalletAmount)), isExpanded: false, letterSpacing: -1)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h);
})
: LocaleKeys.loginToViewWalletBalance.tr().toText12(isBold: true, maxLine: 2),
@ -635,73 +636,73 @@ class ServicesPage extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.virtual_tour_icon,
width: 32.w,
height: 32.h,
fit: BoxFit.contain,
),
SizedBox(width: 8.w),
LocaleKeys.virtualTour.tr().toText14(isBold: true)
],
),
),
).onPress(() {
Utils.openWebView(
url: 'https://hmgwebservices.com/vt_mobile/html/index.html',
);
}),
),
SizedBox(width: 16.w),
Expanded(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.car_parking_icon,
width: 32.w,
height: 32.h,
fit: BoxFit.contain,
),
SizedBox(width: 8.w),
LocaleKeys.carParking.tr().toText14(isBold: true)
],
).onPress(() {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider(
create: (_) => getIt<QrParkingViewModel>(),
child: const ParkingPage(),
),
),
);
}),
),
),
),
],
),
// Row(
// children: [
// // Expanded(
// // child: Container(
// // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// // color: AppColors.whiteColor,
// // borderRadius: 12.h,
// // hasShadow: false,
// // ),
// // child: Padding(
// // padding: EdgeInsets.all(16.h),
// // child: Row(
// // children: [
// // Utils.buildSvgWithAssets(
// // icon: AppAssets.virtual_tour_icon,
// // width: 32.w,
// // height: 32.h,
// // fit: BoxFit.contain,
// // ),
// // SizedBox(width: 8.w),
// // LocaleKeys.virtualTour.tr().toText14(isBold: true)
// // ],
// // ),
// // ),
// // ).onPress(() {
// // Utils.openWebView(
// // url: 'https://hmgwebservices.com/vt_mobile/html/index.html',
// // );
// // }),
// // ),
// SizedBox(width: 16.w),
// Expanded(
// child: Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor,
// borderRadius: 12.h,
// hasShadow: false,
// ),
// child: Padding(
// padding: EdgeInsets.all(16.h),
// child: Row(
// children: [
// Utils.buildSvgWithAssets(
// icon: AppAssets.car_parking_icon,
// width: 32.w,
// height: 32.h,
// fit: BoxFit.contain,
// ),
// SizedBox(width: 8.w),
// LocaleKeys.carParking.tr().toText14(isBold: true)
// ],
// ).onPress(() {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (_) => ChangeNotifierProvider(
// create: (_) => getIt<QrParkingViewModel>(),
// child: const ParkingPage(),
// ),
// ),
// );
// }),
// ),
// ),
// ),
// ],
// ),
SizedBox(height: 16.h),
Row(
children: [

@ -164,6 +164,7 @@ class LandingPageData {
backgroundColor: AppColors.successColor,
iconColor: AppColors.whiteColor,
isBold: false,
isPNG: false
),
// ServiceCardData(
// icon: AppAssets.homeBottom,
@ -182,16 +183,18 @@ class LandingPageData {
backgroundColor: AppColors.primaryRedColor,
iconColor: AppColors.whiteColor,
isBold: false,
isPNG: false
),
ServiceCardData(
serviceName: "pharmacy",
icon: AppAssets.pharmacy_icon, //359846
icon: AppAssets.defaultMEP, //359846
title: LocaleKeys.hmgPharmacy,
subtitle: LocaleKeys.hmgPharmacyText,
largeCardIcon: AppAssets.pharmacyService,
backgroundColor: AppColors.pharmacyBGColor,
iconColor: null,
isBold: true,
isPNG: true
),
];
}

@ -12,6 +12,7 @@ class ServiceCardData {
final Color? backgroundColor;
final bool isBold;
final String largeCardIcon;
final bool isPNG;
ServiceCardData({
this.serviceName = "",
@ -22,6 +23,7 @@ class ServiceCardData {
this.backgroundColor,
this.iconColor,
this.textColor,
this.isBold = false
this.isBold = false,
this.isPNG = false,
});
}

@ -204,7 +204,7 @@ class _LandingPageState extends State<LandingPage> {
// Refresh Appointments Data
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, true);
myAppointmentsViewModel.getPatientAppointments(true, false);
// Refresh Appointments Data
habibWalletVM.initHabibWalletProvider();
@ -703,7 +703,7 @@ class _LandingPageState extends State<LandingPage> {
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
duration: const Duration(milliseconds: 200),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
@ -822,6 +822,7 @@ class _LandingPageState extends State<LandingPage> {
title: LandingPageData.getServiceCardsList[index].title,
subtitle: LandingPageData.getServiceCardsList[index].subtitle,
icon: LandingPageData.getServiceCardsList[index].largeCardIcon,
isPNG: LandingPageData.getServiceCardsList[index].isPNG,
),
),
),

@ -28,6 +28,7 @@ class LargeServiceCard extends StatelessWidget {
final String icon;
final String title;
final String subtitle;
final bool isPNG;
const LargeServiceCard({
super.key,
@ -36,6 +37,7 @@ class LargeServiceCard extends StatelessWidget {
this.icon = "",
this.title = "",
this.subtitle = "",
this.isPNG = false,
});
@override
@ -72,7 +74,7 @@ class LargeServiceCard extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
isPNG ? Image.asset(serviceCardData.icon, width: 35.h, height: 35.h) : Container(
height: 48.h,
width: 48.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
@ -172,6 +174,7 @@ class FadedLargeServiceCard extends StatelessWidget {
final String icon;
final String title;
final String subtitle;
final bool isPNG;
const FadedLargeServiceCard({
super.key,
@ -180,6 +183,7 @@ class FadedLargeServiceCard extends StatelessWidget {
this.icon = "",
this.title = "",
this.subtitle = "",
this.isPNG = false,
});
@override
@ -225,7 +229,7 @@ class FadedLargeServiceCard extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
isPNG ? Image.asset(serviceCardData.icon, width: 32.h, height: 32.h).circle(100.h) : Container(
height: 32.h,
width: 32.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(

@ -34,6 +34,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/active_medication/active_medication_page.dart';
import 'package:hmg_patient_app_new/presentation/allergies/allergies_list_page.dart';
@ -55,6 +56,8 @@ import 'package:hmg_patient_app_new/presentation/medical_file/eye_measurements_a
import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/vaccine_list_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/health_tracker_menu_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/health_tools_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_sick_leave_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_report/medical_reports_page.dart';
@ -524,7 +527,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
],
),
ExpandableListItem(
title: LocaleKeys.healthTrackers.tr(context: context).toText18(isBold: true),
title: LocaleKeys.healthTools.tr(context: context).toText18(isBold: true),
expandedBackgroundColor: Colors.transparent,
children: [
SizedBox(height: 10.h),
@ -979,7 +982,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
),
).paddingSymmetrical(0.w, 0.h)
: SizedBox(
height: 100.h,
height: 110.h,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: myAppointmentsVM.patientMyDoctorsList.length,
@ -1003,7 +1006,8 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: false, radius: 50.r),
SizedBox(height: 8.h),
Expanded(
SizedBox(
width: 80.w,
child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName)
.toString().toText12(isBold: true, isCenter: true, maxLine: 2).toShimmer2(isShow: false),
),
@ -1278,7 +1282,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
width: 62.w,
height: 62.h,
),
).paddingSymmetrical(0.w, 0.h);
).paddingSymmetrical(0.w, 0.h);
}),
SizedBox(height: 16.h),
GridView(
@ -1292,21 +1296,21 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
MedicalFileCard(
label: LocaleKeys.monthlyReports.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.monthly_reports_icon,
isLargeText: true,
iconSize: 36.h,
).onPress(() {
monthlyReportViewModel.setHealthSummaryEnabled(cacheService.getBool(key: CacheConst.isMonthlyReportEnabled) ?? false);
Navigator.of(context).push(
CustomPageRoute(
page: MonthlyReport(),
),
);
}),
// MedicalFileCard(
// label: LocaleKeys.monthlyReports.tr(context: context),
// textColor: AppColors.blackColor,
// backgroundColor: AppColors.whiteColor,
// svgIcon: AppAssets.monthly_reports_icon,
// isLargeText: true,
// iconSize: 36.h,
// ).onPress(() {
// monthlyReportViewModel.setHealthSummaryEnabled(cacheService.getBool(key: CacheConst.isMonthlyReportEnabled) ?? false);
// Navigator.of(context).push(
// CustomPageRoute(
// page: MonthlyReport(),
// ),
// );
// }),
MedicalFileCard(
label: LocaleKeys.medicalReports.tr(context: context),
textColor: AppColors.blackColor,
@ -1343,95 +1347,93 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
],
);
case 3:
// Trackers Tab Data
// Health Tools Tab Data
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Row(
// children: [
// LocaleKeys.healthTrackers.tr(context: context).toText16(isBold: true, color: AppColors.textColor),
// ],
// ),
// SizedBox(height: 16.h),
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.h,
mainAxisSpacing: 16.w,
mainAxisExtent: 115.h,
mainAxisExtent: 120.h,
),
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
padding: EdgeInsets.only(top: 12.h),
shrinkWrap: true,
children: [
MedicalFileCard(
label: LocaleKeys.bloodSugar.tr(context: context),
// Health Trackers
HealthToolsCard(
label: LocaleKeys.healthTrackers.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.blood_sugar_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() => context.navigateWithName(AppRoutes.healthTrackerDetailPage, arguments: HealthTrackerTypeEnum.bloodSugar)),
MedicalFileCard(
label: LocaleKeys.bloodPressure.tr(context: context),
svgIcon: AppAssets.general_health,
iconColor:null,
iconSize: 24.w,
).onPress(() {
if (getIt.get<AppState>().isAuthenticated) {
context.navigateWithName(AppRoutes.healthTrackersPage);
}
}),
// Daily Water Monitor
HealthToolsCard(
label: LocaleKeys.dailyWaterMonitor.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.lab_result_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() => context.navigateWithName(AppRoutes.healthTrackerDetailPage, arguments: HealthTrackerTypeEnum.bloodPressure)),
MedicalFileCard(
label: LocaleKeys.weightTracker.tr(context: context),
svgIcon: AppAssets.daily_water_monitor_icon,
iconColor: AppColors.infoColor,
iconSize: 24.w,
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingYourWaterIntakeDetails.tr());
final waterMonitorVM = getIt.get<WaterMonitorViewModel>();
await waterMonitorVM.fetchUserDetailsForMonitoring(
onSuccess: (userDetail) {
LoaderBottomSheet.hideLoader();
if (userDetail == null) {
waterMonitorVM.populateFromAuthenticatedUser();
context.navigateWithName(AppRoutes.waterMonitorSettingsPage);
} else {
context.navigateWithName(AppRoutes.waterConsumptionPage);
}
},
onError: (error) {
LoaderBottomSheet.hideLoader();
context.navigateWithName(AppRoutes.waterConsumptionPage);
},
);
}
}),
// Health Calculators
HealthToolsCard(
label: LocaleKeys.healthCalculatorsServices.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.weight_tracker_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() => context.navigateWithName(AppRoutes.healthTrackerDetailPage, arguments: HealthTrackerTypeEnum.weightTracker)),
],
).paddingSymmetrical(0.w, 0.0),
SizedBox(height: 16.h),
// Row(
// children: [
// LocaleKeys.others.tr(context: context).toText16(isBold: true, color: AppColors.textColor),
// ],
// ),
SizedBox(height: 16.h),
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.h,
mainAxisSpacing: 16.w,
mainAxisExtent: 115.h,
),
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
// MedicalFileCard(
// label: LocaleKeys.askYourDoctor.tr(context: context),
// textColor: AppColors.blackColor,
// backgroundColor: AppColors.whiteColor,
// svgIcon: AppAssets.ask_doctor_medical_file_icon,
// isLargeText: true,
// iconSize: 36.w,
// ).onPress(() {
// getIt.get<AskDoctorViewModel>().initAskDoctorViewModel();
// Navigator.of(context).push(
// CustomPageRoute(
// page: AskDoctorPage(),
// ),
// );
// }),
// MedicalFileCard(
// label: LocaleKeys.internetPairing.tr(context: context),
// textColor: AppColors.blackColor,
// backgroundColor: AppColors.whiteColor,
// svgIcon: AppAssets.internet_pairing_icon,
// isLargeText: true,
// iconSize: 36.w,
// ).onPress(() {}),
svgIcon: AppAssets.health_calculators_services_icon,
iconColor: AppColors.successColor,
iconSize: 24.w,
).onPress(() {
context.navigateWithName(AppRoutes.healthCalculatorsPage);
}),
// Health Converters
HealthToolsCard(
label: LocaleKeys.healthConvertersServices.tr(context: context),
textColor: AppColors.blackColor,
svgIcon: AppAssets.health_converters_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 24.w,
).onPress(() {
context.navigateWithName(AppRoutes.healthConvertersPage);
}),
// Smart Watches
HealthToolsCard(
label: LocaleKeys.smartWatchesServices.tr(context: context),
textColor: AppColors.blackColor,
svgIcon: AppAssets.smartwatch_icon,
iconColor: AppColors.warningColorYellow,
iconSize: 24.w,
).onPress(() {
if (getIt.get<AppState>().isAuthenticated) {
context.navigateWithName(AppRoutes.smartWatches);
}
}),
],
).paddingSymmetrical(0.w, 0.0),
SizedBox(height: 24.h),
@ -1535,7 +1537,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: _buildVitalSignCard(
icon: AppAssets.bmiVital,
label: LocaleKeys.bmi.tr(context: context),
value: vitalSign.bodyMassIndex?.toString() ?? '--',
value: _formatValue(vitalSign.bodyMassIndex),
unit: '',
status: vitalSign.bodyMassIndex != null ? _getBMIStatus(vitalSign.bodyMassIndex) : null,
// status: "Overweight",
@ -1547,7 +1549,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: _buildVitalSignCard(
icon: AppAssets.heightVital,
label: LocaleKeys.height.tr(context: context),
value: vitalSign.heightCm?.toString() ?? '--',
value: _formatValue(vitalSign.heightCm),
unit: 'cm',
status: null,
onTap: onTap,
@ -1565,7 +1567,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: _buildVitalSignCard(
icon: AppAssets.weightVital,
label: LocaleKeys.weight.tr(context: context),
value: vitalSign.weightKg?.toString() ?? '--',
value: _formatValue(vitalSign.weightKg),
unit: 'kg',
status: vitalSign.weightKg != null ? _getWeightStatus(vitalSign.bodyMassIndex) : null,
onTap: onTap,
@ -1576,12 +1578,18 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: _buildVitalSignCard(
icon: AppAssets.bloodPressure,
label: LocaleKeys.bloodPressure.tr(context: context),
value: vitalSign.bloodPressureLower != null && vitalSign.bloodPressureHigher != null ? "${vitalSign.bloodPressureHigher}/${vitalSign.bloodPressureLower}" : '--',
value: (vitalSign.bloodPressureLower != null && vitalSign.bloodPressureHigher != null &&
vitalSign.bloodPressureLower != 0 && vitalSign.bloodPressureHigher != 0)
? "${vitalSign.bloodPressureHigher}/${vitalSign.bloodPressureLower}"
: '--',
unit: '',
status: _getBloodPressureStatus(
systolic: vitalSign.bloodPressureHigher,
diastolic: vitalSign.bloodPressureLower,
),
status: (vitalSign.bloodPressureLower != null && vitalSign.bloodPressureHigher != null &&
vitalSign.bloodPressureLower != 0 && vitalSign.bloodPressureHigher != 0)
? _getBloodPressureStatus(
systolic: vitalSign.bloodPressureHigher,
diastolic: vitalSign.bloodPressureLower,
)
: null,
onTap: onTap,
),
),
@ -1590,25 +1598,36 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
];
}
String _getBMIStatus(dynamic bmi) {
VitalSignStatus? _getBMIStatus(dynamic bmi) {
return VitalSignUiModel.bmiStatus(bmi);
}
String? _getWeightStatus(dynamic bmi) {
if (bmi == null) return 'Normal';
return VitalSignUiModel.bmiStatus(bmi);
VitalSignStatus? _getWeightStatus(dynamic bmi) {
return VitalSignUiModel.weightStatus(bmi);
}
String? _getBloodPressureStatus({dynamic systolic, dynamic diastolic}) {
VitalSignStatus? _getBloodPressureStatus({dynamic systolic, dynamic diastolic}) {
return VitalSignUiModel.bloodPressureStatus(systolic: systolic, diastolic: diastolic);
}
// Helper function to format vital sign values, showing '--' instead of 0 or null
String _formatValue(dynamic value) {
if (value == null) return '--';
if (value is num && value == 0) return '--';
if (value is String) {
if (value.trim().isEmpty) return '--';
final parsed = double.tryParse(value);
if (parsed == null || parsed == 0) return '--';
}
return value.toString();
}
Widget _buildVitalSignCard({
required String icon,
required String label,
required String value,
required String unit,
required String? status,
required VitalSignStatus? status,
required VoidCallback onTap,
}) {
final VitalSignUiModel scheme = VitalSignUiModel.scheme(status: status, label: label);
@ -1675,7 +1694,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
isEnglishOnly: true
),
),
if (unit.isNotEmpty) ...[
if (unit.isNotEmpty && value != '--' && value != '0') ...[
SizedBox(width: 3.w),
unit.toText12(
color: AppColors.textColor,
@ -1688,7 +1707,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
if (status != null) ...[
SizedBox(width: 4.w),
AppCustomChipWidget(
labelText: status,
labelText: VitalSignUiModel.statusToString(status),
backgroundColor: scheme.chipBg,
textColor: scheme.chipFg,
),

@ -169,8 +169,8 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
richText: Row(
mainAxisSize: MainAxisSize.min,
children: [
"${model.patientSickLeaveList[index].sickLeaveDays} ".toText10(isEnglishOnly: true),
LocaleKeys.days.tr(context: context).toText10()
"${model.patientSickLeaveList[index].sickLeaveDays} ".toText10(isBold: true),
LocaleKeys.days.tr(context: context).toText10(isBold: true)
],
),
// labelText: "${model.patientSickLeaveList[index].sickLeaveDays} ${LocaleKeys.days.tr(context: context)}",

@ -29,11 +29,19 @@ class _VaccineListPageState extends State<VaccineListPage> {
@override
void initState() {
super.initState();
scheduleMicrotask(() {
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
medicalFileViewModel.setIsPatientVaccineListLoading(true);
medicalFileViewModel.getPatientVaccinesList();
medicalFileViewModel.getPatientVaccinesList(
onSuccess: (data) {
// print("✅ Vaccine data received: ${medicalFileViewModel.patientVaccineList.length} items");
},
onError: (error) {
//print("❌ Vaccine error: $error");
},
);
});
super.initState();
}
@override
@ -133,11 +141,18 @@ class _VaccineListPageState extends State<VaccineListPage> {
// height: 63.h,
// fit: BoxFit.fill,
// ).circle(100).toShimmer2(isShow: false),
SizedBox(width: 16.h),
SizedBox(width: 8.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppCustomChipWidget(
backgroundColor: AppColors.lightGreenButtonColor,
textColor: AppColors.textGreenColor,
padding: EdgeInsets.all(0),
labelText: medicalFileVM.patientVaccineList[index].vaccineName).toShimmer2(isShow: false, width: 16.h, ),
SizedBox(height:10.h),
(medicalFileVM.patientVaccineList[index].doctorName).toString().toText16(isBold: true).toShimmer2(isShow: false),
SizedBox(height: 8.h),
Wrap(
@ -148,7 +163,7 @@ class _VaccineListPageState extends State<VaccineListPage> {
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(medicalFileVM.patientVaccineList[index].vaccinationDate), false)),
AppCustomChipWidget(labelText: medicalFileVM.patientVaccineList[index].vaccineName).toShimmer2(isShow: false, width: 16.h),
AppCustomChipWidget(labelText: medicalFileVM.patientVaccineList[index].clinicName).toShimmer2(isShow: false, width: 16.h),
AppCustomChipWidget(labelText: medicalFileVM.patientVaccineList[index].projectName).toShimmer2(isShow: false, width: 16.h),
],

@ -0,0 +1,75 @@
import 'package:flutter/material.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class HealthToolsCard extends StatelessWidget {
final String label;
final Color textColor;
final String svgIcon;
final double? iconSize;
final Color? iconColor;
const HealthToolsCard({
super.key,
required this.label,
required this.textColor,
required this.svgIcon,
this.iconSize,
this.iconColor,
});
@override
Widget build(BuildContext context) {
final iconS = iconSize ?? 24.w;
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
padding: EdgeInsets.all(12.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Icon container with white background and border
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(
color: AppColors.borderOnlyColor.withValues(alpha: 0.1),
width: 1,
),
),
height: 48.w,
width: 48.w,
child: Center(
child: Utils.buildSvgWithAssets(
icon: svgIcon,
width: iconS,
height: iconS,
fit: BoxFit.contain,
applyThemeColor: false,
iconColor: iconColor,
),
),
),
SizedBox(height: 6.h),
label.toText13(color: textColor, isBold: true, maxLine: 2),
],
),
],
),
);
}
}

@ -0,0 +1,86 @@
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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class HealthTrackerMenuCard extends StatelessWidget {
final String label;
final Color textColor;
final Color backgroundColor;
final String svgIcon;
final double? iconSize;
final Color? iconColor;
final Color iconBgColor;
const HealthTrackerMenuCard({
super.key,
required this.label,
required this.textColor,
required this.backgroundColor,
required this.svgIcon,
required this.iconBgColor,
this.iconSize,
this.iconColor,
});
@override
Widget build(BuildContext context) {
final iconS = iconSize ?? 22.w;
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: backgroundColor,
borderRadius: 20.r,
hasShadow: false
),
padding: EdgeInsets.all(16.w),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: iconBgColor,
borderRadius: 10.r
),
height: 40.w,
width: 40.w,
child: Utils.buildSvgWithAssets(
icon: svgIcon,
fit: BoxFit.none,
height: iconS,
width: iconS,
applyThemeColor: false,
iconColor: iconColor,
),
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
label.toText14(color: textColor, isBold: true),
],
),
),
SizedBox(width: 12.w),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrowRight,
width: 24.w,
height: 24.h,
fit: BoxFit.contain,
iconColor: AppColors.textColor,
),
),
],
),
);
}
}

@ -108,7 +108,7 @@ class MedicalFileAppointmentCard extends StatelessWidget {
borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
fontSize: 14.f,
fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
@ -118,8 +118,13 @@ class MedicalFileAppointmentCard extends StatelessWidget {
).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
),
SizedBox(width: 8.w),
Expanded(
flex: 2,
((((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ||
(patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
!Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID ?? 0))) &&
AppointmentType.isArrived(patientAppointmentHistoryResponseModel))
? SizedBox.shrink()
: Expanded(
flex: 2,
child: Container(
height: 40.h,
width: 40.w,
@ -163,40 +168,75 @@ class MedicalFileAppointmentCard extends StatelessWidget {
}
Widget getArrivedAppointmentButton(BuildContext context) {
return DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15
? CustomButton(
text: LocaleKeys.askDoctor.tr(context: context),
onPressed: () {
onAskDoctorTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppAssets.ask_doctor_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
if ((((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ||
(patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
!Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID ?? 0))) &&
AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) {
return CustomButton(
text: LocaleKeys.viewDetails.tr(context: context),
onPressed: () {
Navigator.of(context)
.push(
CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
),
)
: CustomButton(
text: LocaleKeys.rebook.tr(context: context),
onPressed: () {
onRescheduleTap();
},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppAssets.rebook_appointment_icon,
iconColor: AppColors.blackColor,
iconSize: 16.h,
);
.then((_) {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
});
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h,
height: 40.h,
icon: null,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
} else {
return
// DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15
// ? CustomButton(
// text: LocaleKeys.askDoctor.tr(context: context),
// onPressed: () {
// onAskDoctorTap();
// },
// backgroundColor: AppColors.secondaryLightRedColor,
// borderColor: AppColors.secondaryLightRedColor,
// textColor: AppColors.primaryRedColor,
// fontSize: 14.f,
// fontWeight: FontWeight.w600,
// borderRadius: 12.r,
// padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: 40.h,
// icon: AppAssets.ask_doctor_icon,
// iconColor: AppColors.primaryRedColor,
// iconSize: 16.h,
// )
// :
CustomButton(
text: LocaleKeys.rebook.tr(context: context),
onPressed: () {
onRescheduleTap();
},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppAssets.rebook_appointment_icon,
iconColor: AppColors.blackColor,
iconSize: 16.h,
);
}
}
}

@ -64,3 +64,5 @@ class MedicalFileCard extends StatelessWidget {
);
}
}

@ -419,7 +419,7 @@ class _MedicalReportsPageState extends State<MedicalReportsPage> {
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
isAutoDismiss: true
isAutoDismiss: false
);
}
}

@ -251,6 +251,9 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
await prescriptionsViewModel.getPrescriptionDetails(widget.prescriptionsResponseModel, onSuccess: (val) {
LoaderBottomSheet.hideLoader();
prescriptionsViewModel.initiatePrescriptionDelivery();
}, onError: (err) {
LoaderBottomSheet.hideLoader();
print(err);
});
}
},

@ -193,20 +193,15 @@ class _RateAppointmentDoctorState extends State<RateAppointmentDoctor> {
Expanded(
child: CustomButton(
text: LocaleKeys.submit.tr(context: context),
onPressed: () async {
// Set up clinic rating and show clinic rating view
// appointmentRatingViewModel!.setTitle(LocaleKeys.rateDoctor.tr(context: context),);
// appointmentRatingViewModel!.setSubTitle(LocaleKeys.howWasYourLastVisitWithDoctor.tr(context: context),);
// appointmentRatingViewModel!.setClinicOrDoctor(true);
LoaderBottomSheet.showLoader();
await appointmentRatingViewModel!.submitDoctorRating(docRate: rating, docNote: note);
// await appointmentRatingViewModel!.submitClinicRating(clinicRate: rating, clinicNote: note);
LoaderBottomSheet.hideLoader();
Navigator.pop(context);
setState(() {});
},
onPressed: rating > 0
? () {
LoaderBottomSheet.showLoader();
appointmentRatingViewModel!.submitDoctorRating(docRate: rating, docNote: note).then((_) {
LoaderBottomSheet.hideLoader();
Navigator.pop(context);
});
}
: null,
),
),
],

@ -2,7 +2,9 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:fl_chart/fl_chart.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/common_models/data_points.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';
@ -119,7 +121,7 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
required String title,
required String icon,
required String valueText,
required String? status,
required VitalSignStatus? status,
required VitalSignUiModel scheme,
required DateTime? latestDate,
}) {
@ -168,17 +170,20 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
),
SizedBox(width: 4.h),
if (status != null)
Column(
spacing: 6.h,
children: [
status.toText10(isBold: true, color: AppColors.greyTextColor),
Utils.buildSvgWithAssets(
icon: AppAssets.lab_result_indicator,
width: 21,
height: 23,
iconColor: scheme.iconFg,
),
],
Directionality(
textDirection: ui.TextDirection.ltr,
child: Column(
spacing: 6.h,
children: [
VitalSignUiModel.statusToString(status).toText10(isBold: true, color: AppColors.greyTextColor),
Utils.buildSvgWithAssets(
icon: AppAssets.lab_result_indicator,
width: 21,
height: 23,
iconColor: scheme.iconFg,
),
],
),
),
],
),
@ -331,6 +336,7 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
final minY = _minY(history, secondaryHistory: secondaryHistory);
final maxY = _maxY(history, secondaryHistory: secondaryHistory);
final scheme = VitalSignUiModel.scheme(status: _statusForLatest(null), label: args.title);
final isRTL = getIt.get<AppState>().isArabic();
return CustomGraph(
dataPoints: history,
@ -339,6 +345,7 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
leftLabelReservedSize: 40,
showGridLines: true,
showShadow: true,
isRTL: isRTL,
leftLabelInterval: _leftInterval(history, secondaryHistory: secondaryHistory),
maxY: maxY,
minY: minY,
@ -663,7 +670,7 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
}
}
String? _statusForLatest(VitalSignResModel? latest) {
VitalSignStatus? _statusForLatest(VitalSignResModel? latest) {
if (latest == null) return null;
switch (args.metric) {
@ -674,14 +681,15 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
case VitalSignMetric.height:
return null;
case VitalSignMetric.weight:
// return latest.weightKg != null ? 'Normal' : null;
return VitalSignUiModel.bmiStatus(latest.bodyMassIndex);
return VitalSignUiModel.weightStatus(latest.bodyMassIndex);
case VitalSignMetric.temperature:
return null;
case VitalSignMetric.heartRate:
return (latest.heartRate ?? latest.pulseBeatPerMinute) != null ? 'Normal' : null;
final heartRateValue = _toDouble(latest.heartRate ?? latest.pulseBeatPerMinute);
return (heartRateValue != null && heartRateValue > 0) ? VitalSignStatus.normal : null;
case VitalSignMetric.respiratoryRate:
return latest.respirationBeatPerMinute != null ? 'Normal' : null;
final respiratoryValue = _toDouble(latest.respirationBeatPerMinute);
return (respiratoryValue != null && respiratoryValue > 0) ? VitalSignStatus.normal : null;
}
}
@ -756,9 +764,9 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
Widget _bottomLabel(String label, {bool isLast = false}) {
return Padding(
padding: EdgeInsets.only(
padding: EdgeInsetsDirectional.only(
top: 8.0,
right: isLast ? 16.h : 0,
end: isLast ? 16.h : 0,
),
child: label.toText10(isBold: true, isEnglishOnly: true),
);

@ -41,6 +41,18 @@ class _VitalSignPageState extends State<VitalSignPage> {
return false;
}
// Helper function to format vital sign values, showing '--' instead of 0 or null
String _formatValue(dynamic value) {
if (value == null) return '--';
if (value is num && value == 0) return '--';
if (value is String) {
if (value.trim().isEmpty) return '--';
final parsed = double.tryParse(value);
if (parsed == null || parsed == 0) return '--';
}
return value.toString();
}
void _openDetails(VitalSignDetailsArgs args) {
Navigator.of(context).push(
CustomPageRoute(
@ -100,7 +112,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
_buildVitalSignCard(
icon: AppAssets.bmiVital,
label: LocaleKeys.bmi.tr(context: context),
value: latestVitalSign?.bodyMassIndex?.toString() ?? '--',
value: _formatValue(latestVitalSign?.bodyMassIndex),
unit: '',
status: VitalSignUiModel.bmiStatus(latestVitalSign?.bodyMassIndex),
onTap: () => _openDetails(
@ -118,7 +130,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
_buildVitalSignCard(
icon: AppAssets.heightVital,
label: LocaleKeys.height.tr(context: context),
value: latestVitalSign?.heightCm?.toString() ?? '--',
value: _formatValue(latestVitalSign?.heightCm),
unit: 'cm',
status: null,
onTap: () => _openDetails(
@ -136,10 +148,10 @@ class _VitalSignPageState extends State<VitalSignPage> {
_buildVitalSignCard(
icon: AppAssets.weightVital,
label: LocaleKeys.weight.tr(context: context),
value: latestVitalSign?.weightKg?.toString() ?? '--',
value: _formatValue(latestVitalSign?.weightKg),
unit: 'kg',
status: (latestVitalSign?.weightKg != null)
? VitalSignUiModel.bmiStatus(latestVitalSign?.bodyMassIndex)
? VitalSignUiModel.weightStatus(latestVitalSign?.bodyMassIndex)
: null,
onTap: () => _openDetails(
VitalSignDetailsArgs(
@ -162,10 +174,14 @@ class _VitalSignPageState extends State<VitalSignPage> {
? '${latestVitalSign.bloodPressureHigher}/${latestVitalSign.bloodPressureLower}'
: '--',
unit: '',
status: VitalSignUiModel.bloodPressureStatus(
systolic: latestVitalSign?.bloodPressureHigher,
diastolic: latestVitalSign?.bloodPressureLower,
),
status: (latestVitalSign != null &&
_isValidValue(latestVitalSign.bloodPressureHigher) &&
_isValidValue(latestVitalSign.bloodPressureLower))
? VitalSignUiModel.bloodPressureStatus(
systolic: latestVitalSign.bloodPressureHigher,
diastolic: latestVitalSign.bloodPressureLower,
)
: null,
onTap: () => _openDetails(
VitalSignDetailsArgs(
metric: VitalSignMetric.bloodPressure,
@ -183,7 +199,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
_buildVitalSignCard(
icon: AppAssets.temperature,
label: LocaleKeys.temperature.tr(context: context),
value: latestVitalSign?.temperatureCelcius?.toString() ?? '--',
value: _formatValue(latestVitalSign?.temperatureCelcius),
unit: '°C',
status: null,
onTap: () => _openDetails(
@ -258,9 +274,9 @@ class _VitalSignPageState extends State<VitalSignPage> {
child: _buildVitalSignCard(
icon: AppAssets.heart,
label: LocaleKeys.heart.tr(context: context),
value: latestVitalSign?.heartRate?.toString() ?? latestVitalSign?.pulseBeatPerMinute?.toString() ?? '--',
value: _formatValue(latestVitalSign?.heartRate ?? latestVitalSign?.pulseBeatPerMinute),
unit: 'bpm',
status: 'Normal',
status: _isValidValue(latestVitalSign?.heartRate ?? latestVitalSign?.pulseBeatPerMinute) ? VitalSignStatus.normal : null,
onTap: () => _openDetails(
VitalSignDetailsArgs(
metric: VitalSignMetric.heartRate,
@ -282,9 +298,9 @@ class _VitalSignPageState extends State<VitalSignPage> {
_buildVitalSignCard(
icon: AppAssets.respRate,
label: LocaleKeys.respirationRate.tr(context: context),
value: latestVitalSign?.respirationBeatPerMinute?.toString() ?? '--',
value: _formatValue(latestVitalSign?.respirationBeatPerMinute),
unit: 'bpm',
status: 'Normal',
status: _isValidValue(latestVitalSign?.respirationBeatPerMinute) ? VitalSignStatus.normal : null,
onTap: () => _openDetails(
VitalSignDetailsArgs(
metric: VitalSignMetric.respiratoryRate,
@ -318,7 +334,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
required String label,
required String value,
required String unit,
required String? status,
required VitalSignStatus? status,
required VoidCallback onTap,
}) {
final VitalSignUiModel scheme = VitalSignUiModel.scheme(status: status, label: label);
@ -387,7 +403,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
color: AppColors.textColor,
isEnglishOnly: true
),
if (unit.isNotEmpty) ...[
if (unit.isNotEmpty && value != '--' && value != '0') ...[
SizedBox(width: 3.w),
unit.toText12(
color: AppColors.textColor,
@ -398,7 +414,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
),
if (status != null)
AppCustomChipWidget(
labelText: status,
labelText: VitalSignUiModel.statusToString(status),
backgroundColor: scheme.chipBg,
textColor: scheme.chipFg,

@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -82,7 +83,7 @@ class GenericBottomSheetState extends State<GenericBottomSheet> {
FocusScope.of(context).unfocus();
},
child: Directionality(
textDirection: Directionality.of(context),
textDirection: ui.TextDirection.ltr,
child: Container(
padding: EdgeInsets.all(24.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(

@ -8,7 +8,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
class CustomButton extends StatelessWidget {
final String text;
final String? icon;
final VoidCallback onPressed;
final VoidCallback? onPressed;
final Color backgroundColor;
final Color borderColor;
final Color textColor;
@ -58,8 +58,10 @@ class CustomButton extends StatelessWidget {
final radius = borderRadius ?? (12.r);
final iconS = iconSize ?? (24.h);
final fontS = fontSize ?? (16.f);
final isButtonDisabled = isDisabled || onPressed == null;
return GestureDetector(
onTap: isDisabled ? null : onPressed,
onTap: isButtonDisabled ? null : onPressed,
child: Container(
height: height == null
? 56.h
@ -69,10 +71,10 @@ class CustomButton extends StatelessWidget {
width: width,
padding: padding,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: isDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : backgroundColor,
color: isButtonDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : backgroundColor,
borderRadius: radius,
customBorder: BorderRadius.circular(radius),
side: borderSide ?? BorderSide(width: borderWidth.h, color: isDisabled ? Colors.transparent : borderColor)),
side: borderSide ?? BorderSide(width: borderWidth.h, color: isButtonDisabled ? Colors.transparent : borderColor)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
@ -80,9 +82,24 @@ class CustomButton extends StatelessWidget {
if (icon != null)
Padding(
padding: text.isNotEmpty ? EdgeInsets.only(right: 4.w, left: 4.w) : EdgeInsets.zero,
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconS, height: iconS, applyThemeColor: applyThemeColor),
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isButtonDisabled, width: iconS, height: iconS, applyThemeColor: applyThemeColor),
),
if (text.isNotEmpty && icon != null)
Flexible(
child: Text(
text,
overflow: textOverflow ?? TextOverflow.ellipsis,
maxLines: 1,
textAlign: TextAlign.center,
style: context.dynamicTextStyle(
fontSize: fontS,
color: isButtonDisabled ? AppColors.greyTextColor : textColor,
letterSpacing: 0,
fontWeight: isBold ? FontWeight.w700 : fontWeight,
),
),
),
if (text.isNotEmpty)
if (text.isNotEmpty && icon == null)
Text(
text,
overflow: textOverflow ?? TextOverflow.ellipsis,
@ -90,7 +107,7 @@ class CustomButton extends StatelessWidget {
textAlign: TextAlign.center,
style: context.dynamicTextStyle(
fontSize: fontS,
color: isDisabled ? AppColors.greyTextColor : textColor,
color: isButtonDisabled ? AppColors.greyTextColor : textColor,
letterSpacing: 0,
fontWeight: isBold ? FontWeight.w700 : fontWeight,
),

Loading…
Cancel
Save