Merge pull request 'Localization' (#261) from dev_aamir into master

Reviewed-on: #261
master
khansultan1 6 hours ago
commit a651e2a650

@ -303,7 +303,7 @@
"labSubtitle": "نتائج",
"medicines": "الأدوية",
"medicinesSubtitle": "الوصفات",
"vitalSigns": "علامات حيوية",
"vitalSigns": "العلامات الحيوية",
"vitalSignsSubTitle": "التقارير",
"vitalSignNormal": "طبيعي",
"vitalSignLow": "منخفض",
@ -335,7 +335,7 @@
"monthly": "شهري",
"monthlySubtitle": "التقرير",
"sick": "مريض",
"sick2": "المريضة",
"sick2": "المرضية",
"sickSubtitle": "الإجازات",
"myBalance": "رصيدي",
"myBalanceSubtitle": "الرصيد",
@ -349,7 +349,7 @@
"askYourSubtitle": "طبيبك",
"internet": "الإنترنت",
"internetSubtitle": "الاقتران",
"chatbot": "الدرد<EFBFBD><EFBFBD>ة الآلية",
"chatbot": "الدردشة الآلية",
"chatbotSubtitle": "",
"timeLine": "الخط الزمني",
"labOrders": "طلبات المختبر",
@ -835,7 +835,7 @@
"allSet": "الآن يمكنك تسجيل الدخول باستخدام بصمة الوجه أو البصمة",
"quickLogin": "الدخول السريع",
"enableQuickLogin": "تسجيل الدخول السريع",
"enableQuickLoginBtn": "الدخول السريع",
"enableQuickLoginBtn": " تفعيل الدخول السريع",
"enableMsg": "تمكين تسجيل الدخول السريع سيسمح بالتحقق من خلال Face ID / Biometric الخاص بجهازك الحالي",
"notNow": "ليس الآن",
"pendingActivation": "في انتظار التنشيط",
@ -946,7 +946,7 @@
"scheduledConsultation": "استشارة مجدولة",
"pharmaLiveCare": "لايف كير الصيدلية",
"notSureHelpMeChooseClinic": "هل تريد مساعدة في اختيار العياة؟",
"mentionYourSymptomsAndFindDoctors": "اذكر أعراضك واعثر على قائمة الأطباء وفقاً لذلك",
"mentionYourSymptomsAndFindDoctors": "أدخل حالتك الصحية للحصول على قائمة الأطباء",
"immediateService": "خدمة فورية",
"noNeedToWaitGetMedicalConsultation": "لا حاجة للانتظار، ستحصل على استشارة طبية فورية عبر مكالمة فيديو",
"noVisitRequired": "لا حاجة للزيارة",
@ -1031,7 +1031,7 @@
"upcoming": "القادمة",
"completed": "المكتملة",
"noAppointmentsYet": "ليس لديك أي مواعيد بعد.",
"viewProfile": "عرض الملف الشخصي",
"viewProfile": "الملف الشخصي",
"choosePreferredHospitalForService": "اختر المستشفى المفضل لديك للخدمة",
"noHospitalsFound": "لم يتم العثور على مستشفيات",
"cancelOrderConfirmation": "هل أنت متأكد أنك تريد إلغاء هذا الطلب؟",
@ -1111,16 +1111,16 @@
"selectDetails": "اختر التفاصيل",
"work": "العمل",
"pick": "استلام",
"insideTheHome": "داخل المنزل",
"insideTheHome": "من المنزل",
"haveAnyAppointment": "هل لديك أي موعد",
"amountPaidAtHospital": "الدفع عند الوصول للمستشفى",
"submitRequest": "تأكيد الطلب",
"enterPickupLocationManually": "تحديد موقع الاستلام",
"enterPickupLocation": "أدخل موقع الاستلام",
"trackingDetails": "تفاصيل التتبع",
"trackingDetails": "استدعاء سيارة إسعاف",
"cancelRequest": "إلغاء الطلب",
"shareLocationWhatsapp": "مشاركة موقعك المباشر على واتساب",
"pleaseWaitForCall": تتلقى مكالمة لتأكيد طلبك قريباً.",
"pleaseWaitForCall": نتصل بك قريبًا لتأكيد الطلب",
"toHospitalLower": "إلى المستشفى",
"contact": "اتصال",
"failed": "فشل",
@ -1129,7 +1129,7 @@
"onTheWayToHospital": " في الطريق إلى المستشفى",
"arrivedAtHospital": "وصل إلى المستشفى",
"orderCancel": "إلغاء الطلب",
"emergencyCheckIn": "تسجيل الطوارئ الإلكتروني",
"emergencyCheckIn": "تسجيل الوصول في الطواريء",
"erOnlineCheckInDescription": "تتيح هذه الخدمة للمرضى تسجيل موعد الطوارئ قبل الوصول.",
"erOnlineCheckInSuccess": "تم تسجيل وصول الطوارئ بنجاح. الرجاء التوجه إلى منطقة الانتظار.",
"erOnlineCheckInError": "حدث خطأ غير متوقع أثناء عملية التسجيل. يرجى التواصل مع الدعم.",
@ -1157,7 +1157,7 @@
"checkingYourERAppointmentStatus": "يرجى الانتظار…",
"transportOptions": "خيارات النقل",
"selectHospitalForAdvancePayment": "يرجى تحديد المستشفى أولاً.",
"recharge": "اضافة رصيد",
"recharge": "شحن المحفظة",
"activityLevel": "مستوى النشاط",
"selectActivityLevel": "حدد مستوى النشاط",
"almostInactive": "غير نشط تقريبًا (بدون تمارين)",
@ -1245,14 +1245,13 @@
"healthCalculatorsServices": "حاسبات\nالصحة",
"healthConvertersServices": "محولات\nالصحة",
"smartWatchesServices": "الساعات\nالذكية",
"exploreServices": "تصفح الخدمات",
"exploreServices": "قائمة الخدمات",
"medicalAndCareServices": "خدمات الرعاية الطبية",
"hmgServices": "خدمات مجموعة الحبيب الطبية",
"personalServices": "الخدمات الشخصية",
"habibWallet": "محفظة الحبيب",
"habibWallet2": "المحفظة",
"loginToViewWalletBalance": "سجل الدخول لعرض رصيد محفظتك",
"recharge": "إعادة الشحن",
"loginToViewMedicalFile": "سجل الدخول لعرض ملفك الطبي",
"addMember": "إضافة عضو",
"addFamilyMember": "إضافة فرد من العائلة",
@ -1307,7 +1306,7 @@
"noInsuranceApprovals": "لم تحصل على أي موافقات تأمينية حتى الآن.",
"noInsuranceWithHMG": "ليس لديك تأمين مسجل لدى مجموعة الحبيب الطبية.",
"referenceRange": "النطاق المرجعي",
"downloadReport": "تحميل التقارير",
"downloadReport": "تحميل",
"generatingReport": "جارٍ إنشاء التقرير، يرجى الانتظار...",
"noLabResults": "لا يوجد نتائج",
"labResultDetails": "تفاصيل نتائج المختبر",
@ -1319,22 +1318,22 @@
"results": "نتائج",
"viewResults": "عرض النتائج",
"rebook": "إعادة الحجز",
"noOphthalmologyAppointments": "لم يتم العثور على أي مواعيد في قسم طب العيون...",
"noVitalSignsRecordedYet": "لا توجد علامات حيوية مسجلة بعد",
"noOphthalmologyAppointments": "لم يتم العثور على أي مواعيد",
"noVitalSignsRecordedYet": "لا توجد علامات حيوية",
"appointmentsAndVisits": "المواعيد",
"labAndRadiology": "المختبر والأشعة",
"activeMedicationsAndPrescriptions": "الوصفات الطبية",
"allPrescriptions": "جميع الوصفات",
"allMedications": "جميع الأدوية",
"youDontHaveAnyPrescriptionsYet": "ليس لديك أي وصفات طبية بعد.",
"youDontHaveAnyCompletedVisitsYet": "ليس لديك أي زيارات مكتملة بعد",
"others": "سجلات أخرى",
"youDontHaveAnyPrescriptionsYet": "ليس لديك أي وصفات طبية",
"youDontHaveAnyCompletedVisitsYet": "ليس لديك أي زيارات مكتملة",
"others": "خدمات أخرى",
"allergyInfo": "معلومات الحساسية",
"vaccineInfo": "معلومات اللقاحات",
"updateInsuranceInfo": "تحديث التأمين",
"myInvoicesList": "قائمة فواتيري",
"ancillaryOrdersList": "قائمة الطلبات المساعدة",
"youDontHaveAnySickLeavesYet": "ليس لديك أي إجازات مرضية بعد.",
"myInvoicesList": "و الفواتير",
"ancillaryOrdersList": "الخدمات الطبية المساندة",
"youDontHaveAnySickLeavesYet": "ليس لديك أي إجازات مرضية",
"medicalReports": "التقارير الطبية",
"sickLeaveReport": "تقرير الإجازة المرضية",
"weightTracker": "متتبع الوزن",
@ -1342,7 +1341,7 @@
"internetPairing": "الاقتران بالإنترنت",
"requested": "مطلوب",
"readyToDownload": "جاهز للتحميل",
"youDontHaveAnyMedicalReportsYet": "ليس لديك أي تقارير طبية بعد.",
"youDontHaveAnyMedicalReportsYet": "ليس لديك أي تقارير طبية",
"requestMedicalReport": "طلب تقرير طبي",
"youDoNotHaveAnyAppointmentsToRequestMedicalReport": "ليس لديك أي مواعيد لطلب تقرير طبي.",
"areYouSureYouWantToRequestMedicalReport": "هل أنت متأكد أنك تريد طلب تقرير طبي لهذا الموعد؟",
@ -1377,7 +1376,7 @@
"parkingDate": "التاريخ: {date}",
"parkedSince": "متوقف منذ: {time}",
"resetDirection": "إعادة تعيين الاتجاه",
"noPrescriptionOrdersYet": "ليس لديك أي طلبات وصفات طبية حتى الآن.",
"noPrescriptionOrdersYet": "ليس لديك أي طلبات.",
"fetchingPrescriptionPDFPleaseWait": "جاري جلب ملف الوصفة الطبية، يرجى الانتظار...",
"ratingValue": "التقييم: {rating}",
"downloadPrescription": "تحميل الوصفة الطبية",
@ -1570,7 +1569,7 @@
"liveCareServiceDesc": "احصل على استشارة طبية من طبيب مختص عبر مكالمة فيديو",
"bloodGroup": "فصيلة الدم: {bloodType}",
"medicalServices": "الخدمات الطبية",
"insuranceAndPayments": "التأمين والمدفوعات",
"insuranceAndPayments": "التأمين و الفواتير",
"trackerAndOthers": "المتتبع وأخرى",
"bmi": "مؤشر كتلة الجسم",
"yesPleaseINeedHelp": "نعم، احتاج مساعدة",
@ -1582,7 +1581,7 @@
"disclaimer": "إخلاء مسؤولية",
"thisAboveInfo": "تم تحليل نتائج المختبرهذه بواسطة الذكاء الاصطناعي، وهي لا تُعدّ نصيحة طبية. استشر طبيبك المختص للتشخيص والعلاج.",
"aiDisclaimer": "سيتم مشاركة بيانات نتائج تحاليلك المخبرية بشكل آمن مع خدمة الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في تقديم رؤى صحية مُخصصة. هل ترغب في المتابعة؟",
"consent": "نتائج المختبر",
"consent": "تحليل الذكاء الاصطناعي",
"bmiNormalDescription": "مؤشر كتلة جسمك ضمن المعدل الصحي. استمر في اتباع نظام غذائي متوازن، وممارسة النشاط البدني بانتظام، وإجراء الفحوصات الدورية للحفاظ على صحة جيدة. راقب أي تغييرات ملحوظة مع مرور الوقت.",
"bmiUnderweightDescription": "يشير مؤشر كتلة الجسم إلى أنك تعاني من نقص الوزن. لذا، يُنصح بزيادة السعرات الحرارية المتناولة من خلال تناول الأطعمة الغنية بالعناصر الغذائية، وممارسة تمارين المقاومة لبناء العضلات، واستشارة أخصائي رعاية صحية للتحقق من وجود أسباب كامنة.",
"bmiOverweightDescription": "يشير مؤشر كتلة الجسم إلى زيادة الوزن. لذا، يُنصح بالسعي إلى إنقاص الوزن تدريجياً وبشكل مستدام من خلال تقليل السعرات الحرارية بشكل معتدل، وممارسة النشاط البدني بانتظام، واختيار الأطعمة الصحية. استشر طبيبك قبل إجراء أي تغييرات جذرية في نمط حياتك.",
@ -1717,7 +1716,7 @@
"doctorRatingAppointment": "طبيب\nتصنيف",
"ratingSubmitted": "تم إرسال التقييم",
"rateTheDoctor": "يرجى تقييم الطبيب",
"downloadInvoice": نزيل الفاتورة",
"downloadInvoice": حميل",
"approvalDetails": "تفاصيل الموافقة",
"obese": "سمين",
"overWeight": "وزن زائد",
@ -1764,7 +1763,7 @@
"errorFetchingData": "حدث خطأ أثناء تحميل البيانات",
"negative": "سلبي",
"calculateCaloriesBasedOnFactors": "حساب السعرات الحرارية اليومية بناءً على عدة عوامل مثل الطول، الوزن، العمر، الجنس، والنشاط البدني اليومي.",
"conformationCall": تتلقى مكالمة لتأكيد طلبك قريباً.",
"conformationCall": نتصل بك قريبًا لتأكيد الطلب",
"radiologyLabResults": "نتائج الأشعة",
"disclaimerRadiology": "تم تحليل نتائج الأشعة هذه بواسطة الذكاء الاصطناعي، وهي لا تُعدّ نصيحة طبية. استشر طبيبك المختص للتشخيص والعلاج.",
"enterIdentificationNumberWithNoStar": "أدخل رقم الهوية",
@ -1776,6 +1775,11 @@
"locationServicesDisabled": "حالة الطقس غير متوفرة لتعطيل خدمات الموقع. يرجى تفعيل خدمات الموقع لتتمكن من رؤية معلومات الطقس.",
"selectDateTimeKey": "اختيار",
"medicalKey": "الطبية",
"doctors2": "أطباء",
"illurgyInfomation": "الحساسية",
"vaccineInfomation": "التطعيمات",
"approvals1": "موافقات",
"convertBloodcholesterolInfo":"حول قيمة كوليسترول الدم بين ملجم/ديسيلتر و مليمول/لتر",
"carbsAlert": "حساب نسب المغذيات (الكربوهيدرات ،البروتين والدهون) بالسعرات الحرارية والقرامات وفقا لنسب محددة مسبقا",
"bodyFatAlert": "يحسب بناءً على الحجم",
"ibwAlert": "حساب الوزن المثالي بناءً على الطول، الوزن، وبنية الجسم",
@ -1783,8 +1787,7 @@
"selectBloodGroup": "اختر الفصيلة",
"routePrescription": "طريقة الاستخدام",
"noNearestER": "لا يوجد طوارئ قريب منك",
"loginToUseServiceLiveCare": "تحتاج إلى تسجيل الدخول لاستخدام هذه الخدمة"
"convertBloodcholesterolInfo":"حول قيمة كوليسترول الدم بين ملجم/ديسيلتر و مليمول/لتر",
"loginToUseServiceLiveCare": "تحتاج إلى تسجيل الدخول لاستخدام هذه الخدمة",
"mldl": "مليجرام لكل ديسيلتر",
"mmol": "ملي مول لكل لتر",
"triglycerideInfo": "تغيير وحدات القياس بين مليجرام لكل ديسيلتر و ملي مول لكل لتر",

@ -825,7 +825,7 @@
"allSet": "Now you can login with Face ID or Biometric",
"quickLogin": "Quick Login",
"enableQuickLogin": "Enable Quick Login",
"enableQuickLoginBtn": "Quick Login",
"enableQuickLoginBtn": "Enable Quick Login",
"enableMsg": "Enabling the quick login will verify through your existing device Face ID / Biometric",
"notNow": "Not Now",
"pendingActivation": "Pending Activation",
@ -1320,7 +1320,7 @@
"others": "Others",
"allergyInfo": "Allergy Info",
"vaccineInfo": "Vaccine Info",
"updateInsuranceInfo": "Update Insurance",
"updateInsuranceInfo": "Insurance Update",
"myInvoicesList": "My Invoices List",
"ancillaryOrdersList": "Ancillary Orders List",
"youDontHaveAnySickLeavesYet": "You don't have any sick leaves yet.",
@ -1540,7 +1540,7 @@
"route": "Route",
"frequency": "Frequency",
"reminders": "Reminders",
"reminderAddedToCalendar": "Reminder added to calendar",
"reminderAddedToCalendar": "Reminder added to calendar",
"errorWhileSettingCalendar": "Error while setting calendar: {error}",
"instructions": "Instructions",
"requests": "Requests",
@ -1780,7 +1780,11 @@
"selectSmartWatch": "Select",
"selectBloodDonationCity": "Select City",
"selectBloodDonationGender": "Select Gender",
"selectBloodType": "Select Blood Type"
"selectBloodType": "Select Blood Type",
"doctors2": "Doctor",
"illurgyInfomation": "Allergy",
"vaccineInfomation": "Vaccine",
"approvals1": "Approvals"
}

@ -1120,7 +1120,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_dialogService.showPhoneNumberPickerSheet(
// label: "Where would you like to receive OTP?",
label: LocaleKeys.receiveOtpToast.tr(),
message: "Please select from the below options to receive OTP.",
message: _appState.isArabic() ? "يرجى الاختيار من الخيارات أدناه لاستلام رمز التحقق." "Please select from the below options to receive OTP.",
onSMSPress: () {
checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms);
},

@ -34,13 +34,25 @@ class HealthTrackersViewModel extends ChangeNotifier {
String? get errorMessage => _errorMessage;
List<String> get durationFilters => ["Week", "Month", "Year"];
final List<String> durationFiltersEn = ["Week", "Month", "Year"];
final List<String> durationFiltersAr = ["أسبوع", "شهر", "سنة"];
List<String> get durationFilters => getIt.get<AppState>().isArabic() ? durationFiltersAr : durationFiltersEn;
String _selectedDuration = "Week";
bool _isGraphView = true;
String get selectedDurationFilter => _selectedDuration;
// Get the localized display value for the selected duration
String get selectedDurationFilterDisplay {
final index = durationFiltersEn.indexOf(_selectedDuration);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? durationFiltersAr[index] : durationFiltersEn[index];
}
return _selectedDuration;
}
bool get isGraphView => _isGraphView;
final List<String> bloodSugarUnit = ['mg/dlt', 'mol/L'];
@ -90,7 +102,15 @@ class HealthTrackersViewModel extends ChangeNotifier {
// Setters with notification
void setFilterDuration(String duration) async {
_selectedDuration = duration;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = durationFiltersAr.indexOf(duration);
if (index >= 0 && index < durationFiltersEn.length) {
_selectedDuration = durationFiltersEn[index];
}
} else {
_selectedDuration = duration;
}
notifyListeners();
}
@ -107,26 +127,73 @@ class HealthTrackersViewModel extends ChangeNotifier {
// ==================== WEIGHT FORM FIELDS ====================
final List<String> weightUnits = ['kg', 'lb'];
final List<String> weightUnitsEn = ['kg', 'lb'];
final List<String> weightUnitsAr = ['كجم', 'رطل'];
String _selectedWeightUnit = 'kg';
String get selectedWeightUnit => _selectedWeightUnit;
List<String> getWeightUnitsList() {
return getIt.get<AppState>().isArabic() ? weightUnitsAr : weightUnitsEn;
}
void setWeightUnit(String unit) {
_selectedWeightUnit = unit;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = weightUnitsAr.indexOf(unit);
if (index >= 0 && index < weightUnitsEn.length) {
_selectedWeightUnit = weightUnitsEn[index];
}
} else {
_selectedWeightUnit = unit;
}
notifyListeners();
}
// Get the localized display value for the selected weight unit
String get selectedWeightUnitDisplay {
final index = weightUnitsEn.indexOf(_selectedWeightUnit);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? weightUnitsAr[index] : weightUnitsEn[index];
}
return _selectedWeightUnit;
}
// ==================== BLOOD PRESSURE FORM FIELDS ====================
final List<String> measuredArmList = ['Left Arm', 'Right Arm'];
final List<String> measuredArmListEn = ['Left Arm', 'Right Arm'];
final List<String> measuredArmListAr = ['الذراع الأيسر', 'الذراع الأيمن'];
String _selectedMeasuredArm = '';
String get selectedMeasuredArm => _selectedMeasuredArm;
List<String> getMeasuredArmList() {
return getIt.get<AppState>().isArabic() ? measuredArmListAr : measuredArmListEn;
}
void setMeasuredArm(String arm) {
_selectedMeasuredArm = arm;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = measuredArmListAr.indexOf(arm);
if (index >= 0 && index < measuredArmListEn.length) {
_selectedMeasuredArm = measuredArmListEn[index];
}
} else {
_selectedMeasuredArm = arm;
}
notifyListeners();
}
// Get the localized display value for the selected measured arm
String get selectedMeasuredArmDisplay {
final index = measuredArmListEn.indexOf(_selectedMeasuredArm);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? measuredArmListAr[index] : measuredArmListEn[index];
}
return _selectedMeasuredArm;
}
// Text Controllers
TextEditingController weightController = TextEditingController();
TextEditingController bloodSugarController = TextEditingController();
@ -952,33 +1019,35 @@ class HealthTrackersViewModel extends ChangeNotifier {
// Validation method
String? _validateBloodSugarEntry(String dateTime) {
final isArabic = getIt.get<AppState>().isArabic();
// Validate blood sugar value
if (bloodSugarController.text.trim().isEmpty) {
return "Please enter blood sugar value";
return isArabic ? "الرجاء إدخال مستوى سكر الدم" : "Please enter blood sugar value";
}
final bloodSugarValue = double.tryParse(bloodSugarController.text.trim());
if (bloodSugarValue == null) {
return "Please enter a valid number";
return isArabic ? "الرجاء إدخال رقم صحيح" : "Please enter a valid number";
}
if (bloodSugarValue <= 0) {
return "Blood sugar value must be greater than 0";
return isArabic ? "يجب أن يكون مستوى سكر الدم أكبر من 0" : "Blood sugar value must be greater than 0";
}
// Validate reasonable range (typical ranges)
if (bloodSugarValue > 1000) {
return "Blood sugar value seems too high. Please check and enter again";
return isArabic ? "مستوى سكر الدم يبدو مرتفع جداً. يرجى التحقق وإدخالها مرة أخرى" : "Blood sugar value seems too high. Please check and enter again";
}
// Validate date time
if (dateTime.trim().isEmpty) {
return "Please select date and time";
return isArabic ? "الرجاء اختيار التاريخ والوقت" : "Please select date and time";
}
// Validate measure time
if (_selectedBloodSugarMeasureTime.isEmpty) {
return "Please select when the measurement was taken";
return isArabic ? "الرجاء اختيار وقت القياس" : "Please select when the measurement was taken";
}
return null; // No errors
@ -991,6 +1060,8 @@ class HealthTrackersViewModel extends ChangeNotifier {
Function()? onSuccess,
Function(String error)? onFailure,
}) async {
final isArabic = getIt.get<AppState>().isArabic();
// Validate
final validationError = _validateBloodSugarEntry(dateTime);
if (validationError != null) {
@ -1025,13 +1096,13 @@ class HealthTrackersViewModel extends ChangeNotifier {
notifyListeners();
if (onSuccess != null) onSuccess();
} else {
_errorMessage = "Failed to save blood sugar entry. Please try again";
_errorMessage = isArabic ? "فشل حفظ قراءة سكر الدم. يرجى المحاولة مرة أخرى" : "Failed to save blood sugar entry. Please try again";
notifyListeners();
if (onFailure != null) onFailure(_errorMessage!);
}
} catch (e) {
log('Error in saveBloodSugarEntry: $e');
_errorMessage = "An error occurred. Please try again";
_errorMessage = isArabic ? "حدث خطأ. يرجى المحاولة مرة أخرى" : "An error occurred. Please try again";
isLoading = false;
notifyListeners();
if (onFailure != null) onFailure(_errorMessage!);
@ -1042,21 +1113,23 @@ class HealthTrackersViewModel extends ChangeNotifier {
// Validate weight entry before saving
String? _validateWeightEntry(String dateTime) {
final isArabic = getIt.get<AppState>().isArabic();
// Validate weight value
final weightValue = weightController.text.trim();
if (weightValue.isEmpty) {
return "Please enter weight value";
return isArabic ? "الرجاء إدخال قيمة الوزن" : "Please enter weight value";
}
// Check if it's a valid number
final parsedValue = double.tryParse(weightValue);
if (parsedValue == null || parsedValue <= 0) {
return "Please enter a valid weight value";
return isArabic ? "الرجاء إدخال قيمة وزن صحيحة" : "Please enter a valid weight value";
}
// Validate date time
if (dateTime.trim().isEmpty) {
return "Please select date and time";
return isArabic ? "الرجاء تحديد التاريخ والوقت" : "Please select date and time";
}
return null; // No errors
@ -1068,6 +1141,8 @@ class HealthTrackersViewModel extends ChangeNotifier {
Function()? onSuccess,
Function(String error)? onFailure,
}) async {
final isArabic = getIt.get<AppState>().isArabic();
// Validate
final validationError = _validateWeightEntry(dateTime);
if (validationError != null) {
@ -1100,13 +1175,13 @@ class HealthTrackersViewModel extends ChangeNotifier {
notifyListeners();
if (onSuccess != null) onSuccess();
} else {
_errorMessage = "Failed to save weight entry. Please try again";
_errorMessage = isArabic ? "فشل حفظ قراءة الوزن. يرجى المحاولة مرة أخرى" : "Failed to save weight entry. Please try again";
notifyListeners();
if (onFailure != null) onFailure(_errorMessage!);
}
} catch (e) {
log('Error in saveWeightEntry: $e');
_errorMessage = "An error occurred. Please try again";
_errorMessage = isArabic ? "حدث خطأ. يرجى المحاولة مرة أخرى" : "An error occurred. Please try again";
isLoading = false;
notifyListeners();
if (onFailure != null) onFailure(_errorMessage!);
@ -1117,34 +1192,36 @@ class HealthTrackersViewModel extends ChangeNotifier {
// Validate blood pressure entry before saving
String? _validateBloodPressureEntry(String dateTime) {
final isArabic = getIt.get<AppState>().isArabic();
// Validate systolic value
final systolicValue = systolicController.text.trim();
if (systolicValue.isEmpty) {
return "Please enter systolic value";
return isArabic ? "الرجاء إدخال القيمة الانقباضية" : "Please enter systolic value";
}
final parsedSystolic = int.tryParse(systolicValue);
if (parsedSystolic == null || parsedSystolic <= 0) {
return "Please enter a valid systolic value";
return isArabic ? "الرجاء إدخال قيمة صحيحة للضغط الانقباضي" : "Please enter a valid systolic value";
}
// Validate diastolic value
final diastolicValue = diastolicController.text.trim();
if (diastolicValue.isEmpty) {
return "Please enter diastolic value";
return isArabic ? "الرجاء إدخال قيمة الضغط الانبساطي" : "Please enter diastolic value";
}
final parsedDiastolic = int.tryParse(diastolicValue);
if (parsedDiastolic == null || parsedDiastolic <= 0) {
return "Please enter a valid diastolic value";
return isArabic ? "الرجاء إدخال قيمة صحيحة للضغط الانبساطي" : "Please enter a valid diastolic value";
}
// Validate arm selection
if (_selectedMeasuredArm.isEmpty) {
return "Please select measured arm";
return isArabic ? "الرجاء اختيار الذراع المقاسة" : "Please select measured arm";
}
// Validate date time
if (dateTime.trim().isEmpty) {
return "Please select date and time";
return isArabic ? "الرجاء تحديد التاريخ والوقت" : "Please select date and time";
}
return null; // No errors
@ -1156,6 +1233,8 @@ class HealthTrackersViewModel extends ChangeNotifier {
Function()? onSuccess,
Function(String error)? onFailure,
}) async {
final isArabic = getIt.get<AppState>().isArabic();
// Validate
final validationError = _validateBloodPressureEntry(dateTime);
if (validationError != null) {
@ -1171,7 +1250,7 @@ class HealthTrackersViewModel extends ChangeNotifier {
try {
// Get measured arm index (0 = Left Arm, 1 = Right Arm)
final measuredArmIndex = measuredArmList.indexOf(_selectedMeasuredArm);
final measuredArmIndex = measuredArmListEn.indexOf(_selectedMeasuredArm);
// Call API
final success = await addOrUpdateBloodPressureResult(
@ -1192,13 +1271,13 @@ class HealthTrackersViewModel extends ChangeNotifier {
notifyListeners();
if (onSuccess != null) onSuccess();
} else {
_errorMessage = "Failed to save blood pressure entry. Please try again";
_errorMessage = isArabic ? "فشل حفظ قراءة ضغط الدم. يرجى المحاولة مرة أخرى" : "Failed to save blood pressure entry. Please try again";
notifyListeners();
if (onFailure != null) onFailure(_errorMessage!);
}
} catch (e) {
log('Error in saveBloodPressureEntry: $e');
_errorMessage = "An error occurred. Please try again";
_errorMessage = isArabic ? "حدث خطأ. يرجى المحاولة مرة أخرى" : "An error occurred. Please try again";
isLoading = false;
notifyListeners();
if (onFailure != null) onFailure(_errorMessage!);

@ -40,7 +40,20 @@ class WaterMonitorViewModel extends ChangeNotifier {
// Units
final List<String> heightUnits = ['cm', 'm', 'ft', 'in'];
final List<String> heightUnitsEn = ['cm', 'm', 'ft', 'in'];
final List<String> heightUnitsAr = ['سم', 'م', 'قدم', 'بوصة'];
final List<String> weightUnits = ['kg', 'lb'];
final List<String> weightUnitsEn = ['kg', 'lb'];
final List<String> weightUnitsAr = ['كجم', 'رطل'];
List<String> getHeightUnitsList() {
return getIt.get<AppState>().isArabic() ? heightUnitsAr : heightUnitsEn;
}
List<String> getWeightUnitsList() {
return getIt.get<AppState>().isArabic() ? weightUnitsAr : weightUnitsEn;
}
// Selected values
String _selectedHeightUnit = 'cm';
@ -62,8 +75,26 @@ class WaterMonitorViewModel extends ChangeNotifier {
String get selectedHeightUnit => _selectedHeightUnit;
// Get the localized display value for the selected height unit
String get selectedHeightUnitDisplay {
final index = heightUnitsEn.indexOf(_selectedHeightUnit);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? heightUnitsAr[index] : heightUnitsEn[index];
}
return _selectedHeightUnit;
}
String get selectedWeightUnit => _selectedWeightUnit;
// Get the localized display value for the selected weight unit
String get selectedWeightUnitDisplay {
final index = weightUnitsEn.indexOf(_selectedWeightUnit);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? weightUnitsAr[index] : weightUnitsEn[index];
}
return _selectedWeightUnit;
}
String get selectedActivityLevel => _selectedActivityLevel;
String get selectedNumberOfReminders => _selectedNumberOfReminders;
@ -75,17 +106,75 @@ class WaterMonitorViewModel extends ChangeNotifier {
bool get isGraphView => _isGraphView;
// Activity level options
List<String> get activityLevels =>
["Almost Inactive (no exercise)", "Lightly active", "Lightly active (1-3) days per week", "Super active (very hard exercise)"];
final List<String> activityLevelsEn = [
"Almost Inactive (no exercise)",
"Lightly active",
"Lightly active (1-3) days per week",
"Super active (very hard exercise)"
];
final List<String> activityLevelsAr = [
"غير نشط تقريباً (بدون تمرين)",
"نشط قليلاً",
"نشط قليلاً (1-3) أيام في الأسبوع",
"نشط جداً (تمرين شاق جداً)"
];
List<String> get activityLevels => getIt.get<AppState>().isArabic() ? activityLevelsAr : activityLevelsEn;
// Get the localized display value for the selected activity level
String get selectedActivityLevelDisplay {
final index = activityLevelsEn.indexOf(_selectedActivityLevel);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? activityLevelsAr[index] : activityLevelsEn[index];
}
return _selectedActivityLevel;
}
// Reminder options
List<String> get reminderOptions => ["1 Time", "2 Time", "3 Time", "4 Time", "5 Time", "6 Time"];
final List<String> reminderOptionsEn = ["1 Time", "2 Time", "3 Time", "4 Time", "5 Time", "6 Time"];
final List<String> reminderOptionsAr = ["مرة واحدة", "مرتين", "3 مرات", "4 مرات", "5 مرات", "6 مرات"];
List<String> get reminderOptions => getIt.get<AppState>().isArabic() ? reminderOptionsAr : reminderOptionsEn;
// Get the localized display value for the selected number of reminders
String get selectedNumberOfRemindersDisplay {
final index = reminderOptionsEn.indexOf(_selectedNumberOfReminders);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? reminderOptionsAr[index] : reminderOptionsEn[index];
}
return _selectedNumberOfReminders;
}
// Gender options
List<String> get genderOptions => ["Male", "Female"];
final List<String> genderOptionsEn = ["Male", "Female"];
final List<String> genderOptionsAr = ["ذكر", "أنثى"];
List<String> get genderOptions => getIt.get<AppState>().isArabic() ? genderOptionsAr : genderOptionsEn;
// Get the localized display value for the selected gender
String get selectedGenderDisplay {
final index = genderOptionsEn.indexOf(_selectedGender);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? genderOptionsAr[index] : genderOptionsEn[index];
}
return _selectedGender;
}
// Duration Options
final List<String> durationFiltersEn = ["Daily", "Weekly", "Monthly"];
final List<String> durationFiltersAr = ["يومي", "أسبوعي", "شهري"];
//Duration Options
List<String> get durationFilters => ["Daily", "Weekly", "Monthly"];
List<String> get durationFilters => getIt.get<AppState>().isArabic() ? durationFiltersAr : durationFiltersEn;
// Get the localized display value for the selected duration
String get selectedDurationFilterDisplay {
final index = durationFiltersEn.indexOf(_selectedDuration);
if (index >= 0) {
return getIt.get<AppState>().isArabic() ? durationFiltersAr[index] : durationFiltersEn[index];
}
return _selectedDuration;
}
// Network/data
final AppState _appState = GetIt.instance<AppState>();
@ -503,7 +592,15 @@ class WaterMonitorViewModel extends ChangeNotifier {
// Setters with notification
void setFilterDuration(String duration) async {
_selectedDuration = duration;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = durationFiltersAr.indexOf(duration);
if (index >= 0 && index < durationFiltersEn.length) {
_selectedDuration = durationFiltersEn[index];
}
} else {
_selectedDuration = duration;
}
notifyListeners();
// Fetch new progress data when duration filter changes
await fetchUserProgressForMonitoring();
@ -517,27 +614,67 @@ class WaterMonitorViewModel extends ChangeNotifier {
// Setters with notification
void setGender(String gender) {
_selectedGender = gender;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = genderOptionsAr.indexOf(gender);
if (index >= 0 && index < genderOptionsEn.length) {
_selectedGender = genderOptionsEn[index];
}
} else {
_selectedGender = gender;
}
notifyListeners();
}
void setHeightUnit(String unit) {
_selectedHeightUnit = unit;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = heightUnitsAr.indexOf(unit);
if (index >= 0 && index < heightUnitsEn.length) {
_selectedHeightUnit = heightUnitsEn[index];
}
} else {
_selectedHeightUnit = unit;
}
notifyListeners();
}
void setWeightUnit(String unit) {
_selectedWeightUnit = unit;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = weightUnitsAr.indexOf(unit);
if (index >= 0 && index < weightUnitsEn.length) {
_selectedWeightUnit = weightUnitsEn[index];
}
} else {
_selectedWeightUnit = unit;
}
notifyListeners();
}
void setActivityLevel(String level) {
_selectedActivityLevel = level;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = activityLevelsAr.indexOf(level);
if (index >= 0 && index < activityLevelsEn.length) {
_selectedActivityLevel = activityLevelsEn[index];
}
} else {
_selectedActivityLevel = level;
}
notifyListeners();
}
void setNumberOfReminders(String number) {
_selectedNumberOfReminders = number;
// Map Arabic values to English keys
if (getIt.get<AppState>().isArabic()) {
final index = reminderOptionsAr.indexOf(number);
if (index >= 0 && index < reminderOptionsEn.length) {
_selectedNumberOfReminders = reminderOptionsEn[index];
}
} else {
_selectedNumberOfReminders = number;
}
notifyListeners();
}

@ -1783,5 +1783,9 @@ abstract class LocaleKeys {
static const selectBloodDonationCity = 'selectBloodDonationCity';
static const selectBloodDonationGender = 'selectBloodDonationGender';
static const selectBloodType = 'selectBloodType';
static const doctors2 = 'doctors2';
static const illurgyInfomation = 'illurgyInfomation';
static const vaccineInfomation = 'vaccineInfomation';
static const approvals1 = 'approvals1';
}

@ -222,7 +222,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
richText: Row(
children: [
"${group.length} ".toText10(isEnglishOnly: true),
"${LocaleKeys.doctors.tr(context: context)} ".toText10()
"${LocaleKeys.doctors2.tr(context: context)} ".toText10()
],
),
// labelText: "${group.length} ${'doctors'}",

@ -77,8 +77,8 @@ class QuickLoginState extends State<QuickLogin> {
// color: Colors.black,
// ),
// ),
SizedBox(height: 5.h),
LocaleKeys.enableQuickLogin.tr(context: context).toText16(color: AppColors.quickLoginColor),
// SizedBox(height: 5.h),
// LocaleKeys.enableQuickLogin.tr(context: context).toText16(color: AppColors.quickLoginColor),
// Description
// Text(
// 'TranslationBase.of(context).enableMsg',

@ -63,7 +63,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
bookAppointmentsViewModel.getClinics();
});
name = (widget.calculatorType?.name.toLowerCase() =="bmi"? widget.calculatorType?.name.toUpperCase(): widget.calculatorType?.name.toCamelCase)??"";
name = (widget.calculatorType?.name.toLowerCase() == "bmi" ? widget.calculatorType?.name.toUpperCase() : widget.calculatorType?.name.toCamelCase) ?? "";
super.initState();
}
@ -80,28 +80,29 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
appState = getIt.get<AppState>();
if (widget.calculatorType != null) {
return CollapsingListView(
title: widget.calculatorType!.title,
title: appState.isArabic() ? widget.calculatorType!.displayName.toCamelCase : "Your ${widget.calculatorType!.displayName.toCamelCase}",
bottomChild: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))),
padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h),
child: CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () {
if (widget.calculatedResult["clinicId"] == null) {
bookAppointmentsViewModel.setIsDoctorsListLoading(true);
bookAppointmentsViewModel.isGetDocForHealthCal = true;
bookAppointmentsViewModel.calculationID = widget.calculatedResult["calculationID"];
Navigator.push(context, CustomPageRoute(page: SelectDoctorPage()));
} else {
onClinicSelected(GetClinicsListResponseModel(clinicID: widget.calculatedResult["clinicId"], clinicDescription: "asdfds", clinicDescriptionN: "asdfds"));
}
},
icon: null,
fontSize: 16.f,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
borderRadius: 12.r,
fontWeight: FontWeight.w600,),
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () {
if (widget.calculatedResult["clinicId"] == null) {
bookAppointmentsViewModel.setIsDoctorsListLoading(true);
bookAppointmentsViewModel.isGetDocForHealthCal = true;
bookAppointmentsViewModel.calculationID = widget.calculatedResult["calculationID"];
Navigator.push(context, CustomPageRoute(page: SelectDoctorPage()));
} else {
onClinicSelected(GetClinicsListResponseModel(clinicID: widget.calculatedResult["clinicId"], clinicDescription: "asdfds", clinicDescriptionN: "asdfds"));
}
},
icon: null,
fontSize: 16.f,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
borderRadius: 12.r,
fontWeight: FontWeight.w600,
),
),
child: getCalculatorResultWidget(type: widget.calculatorType!, calculatedResult: widget.calculatedResult).paddingSymmetrical(18.w, 24.h),
);
@ -269,6 +270,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
}
Widget resultWidget({required HealthCalculatorsTypeEnum type, dynamic calculatedResult}) {
AppState appState = getIt<AppState>();
return Column(
children: [
if (type == HealthCalculatorsTypeEnum.bmi) ...[
@ -658,7 +660,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
borderRadius: 8.h,
textColor: AppColors.textColor),
SizedBox(height: 16.h),
"Fertility Window".toText16(color: AppColors.textColor, isBold: true),
appState.isArabic() ? "فترة الخصوبة".toText16(color: AppColors.textColor, isBold: true) : "Fertility Window".toText16(color: AppColors.textColor, isBold: true),
SizedBox(height: 8.h),
Row(
children: [
@ -678,8 +680,11 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
],
),
SizedBox(height: 8.h),
"This is your fertile window. Maintaining a healthy calorie range supports your body during this period, considering your Basal Metabolic Rate and activity. Your Body Mass Index is within the healthy range."
.toText12(height: 1.5, color: AppColors.textColorLight, isBold: true)
appState.isArabic()
? "هذه هي فترة خصوبتك. يساعد الحفاظ على نطاق صحي من السعرات الحرارية في دعم جسمك خلال هذه الفترة، مع مراعاة معدل الأيض الأساسي ومستوى نشاطك. مؤشر كتلة جسمك ضمن النطاق الصحي."
.toText12(height: 1.5, color: AppColors.textColorLight, isBold: true)
: "This is your fertile window. Maintaining a healthy calorie range supports your body during this period, considering your Basal Metabolic Rate and activity. Your Body Mass Index is within the healthy range."
.toText12(height: 1.5, color: AppColors.textColorLight, isBold: true)
],
),
),
@ -700,7 +705,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
),
Row(
children: [
"Tips to keep in mind".toText16(color: AppColors.textColor, isBold: true),
appState.isArabic() ? "نصائح هامة".toText16(color: AppColors.textColor, isBold: true) : "Tips to keep in mind".toText16(color: AppColors.textColor, isBold: true),
],
),
],
@ -708,13 +713,13 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
SizedBox(height: 8.h),
Column(
children: [
_buildTipRow("Drink before you feel thirsty."),
_buildTipRow(appState.isArabic() ? "اشربي الماء قبل الشعور بالعطش" : "Drink before you feel thirsty."),
SizedBox(height: 4.h),
_buildTipRow("Keep a refillable bottle next to you."),
_buildTipRow(appState.isArabic() ? "احتفظي بزجاجة ماء قابلة لإعادة التعبئة بجانبك" : "Keep a refillable bottle next to you."),
SizedBox(height: 4.h),
_buildTipRow("Track your daily intake to stay motivated."),
_buildTipRow(appState.isArabic() ? "تابعي استهلاكك اليومي للحفاظ على حماسك" : "Track your daily intake to stay motivated."),
SizedBox(height: 4.h),
_buildTipRow("Choose sparkling water instead of soda."),
_buildTipRow(appState.isArabic() ? "اختاري المياه الفوارة بدلاً من المشروبات الغازية" : "Choose sparkling water instead of soda."),
],
).paddingOnly(left: 4.w, right: 4.w)
],
@ -1378,6 +1383,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
}
}
}
bookAppointmentsViewModel.addListener(listener);
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION || regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) {

@ -49,18 +49,21 @@ class ErOnlineCheckinHome extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.immediate_service_icon, width: 58.h, height: 58.h),
SizedBox(width: 18.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.onlineCheckIn.tr().toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.erOnlineCheckInDescription.tr().toText14(color: AppColors.greyTextColor, isBold: true),
],
),
),
Utils.getNoDataWidget(context)
// Utils.buildSvgWithAssets(icon: AppAssets.immediate_service_icon, width: 58.h, height: 58.h),
// SizedBox(width: 18.h),
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// LocaleKeys.onlineCheckIn.tr().toText18(color: AppColors.textColor, isBold: true),
// LocaleKeys.erOnlineCheckInDescription.tr().toText14(color: AppColors.greyTextColor, isBold: true),
// ],
// ),
// ),
],
),
],

@ -1,5 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/generated/locale_keys.g.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -56,6 +58,7 @@ class _OvulationWidgetState extends State<OvulationWidget> {
@override
Widget build(BuildContext context) {
AppState appState = getIt<AppState>();
return Consumer<HealthCalcualtorViewModel>(builder: (context, provider, _) {
return Container(
margin: EdgeInsets.zero,
@ -165,7 +168,9 @@ class _OvulationWidgetState extends State<OvulationWidget> {
Utils.buildSvgWithAssets(icon: AppAssets.globe, width: 18.w, height: 18.w),
SizedBox(width: 12.w),
Expanded(
child: "Calculate ovulation and fertile window based on last period, cycle length and luteal phase.".toText12(isBold: true, color: AppColors.inputLabelTextColor),
child: appState.isArabic()
? "احسب فترة الإباضة وفترة الخصوبة بناءً على آخر دورة شهرية وطول الدورة الشهرية ومرحلة الجسم الأصفر.".toText12(isBold: true, color: AppColors.inputLabelTextColor)
: "Calculate ovulation and fertile window based on last period, cycle length and luteal phase.".toText12(isBold: true, color: AppColors.inputLabelTextColor),
),
],
).paddingSymmetrical(0.w, 16.w),

@ -265,8 +265,8 @@ class _AddHealthTrackerEntryPageState extends State<AddHealthTrackerEntryPage> {
_showSelectionBottomSheet(
context: context,
title: LocaleKeys.selectUnit.tr(context: context),
items: viewModel.weightUnits,
selectedValue: viewModel.selectedWeightUnit,
items: viewModel.getWeightUnitsList(),
selectedValue: viewModel.selectedWeightUnitDisplay,
onSelected: viewModel.setWeightUnit,
useUpperCase: false,
);
@ -278,8 +278,8 @@ class _AddHealthTrackerEntryPageState extends State<AddHealthTrackerEntryPage> {
_showSelectionBottomSheet(
context: context,
title: LocaleKeys.selectArm.tr(context: context),
items: viewModel.measuredArmList,
selectedValue: viewModel.selectedMeasuredArm,
items: viewModel.getMeasuredArmList(),
selectedValue: viewModel.selectedMeasuredArmDisplay,
onSelected: viewModel.setMeasuredArm,
useUpperCase: false,
);
@ -442,7 +442,7 @@ class _AddHealthTrackerEntryPageState extends State<AddHealthTrackerEntryPage> {
icon: AppAssets.bodyIcon,
iconColor: AppColors.greyTextColor,
label: LocaleKeys.selectArm.tr(context: context),
value: viewModel.selectedMeasuredArm,
value: viewModel.selectedMeasuredArmDisplay,
onRowTap: () => _showMeasuredArmSelectionBottomSheet(context, viewModel),
),
_buildDateTimeFields(),
@ -458,7 +458,7 @@ class _AddHealthTrackerEntryPageState extends State<AddHealthTrackerEntryPage> {
icon: AppAssets.weightScale,
label: LocaleKeys.enterWeight.tr(context: context),
inputField: _buildTextField(viewModel.weightController, '', keyboardType: TextInputType.number),
unit: viewModel.selectedWeightUnit,
unit: viewModel.selectedWeightUnitDisplay,
onUnitTap: () => _showWeightUnitSelectionBottomSheet(context, viewModel),
),
_buildDateTimeFields(),
@ -487,6 +487,7 @@ class _AddHealthTrackerEntryPageState extends State<AddHealthTrackerEntryPage> {
leadingIcon: AppAssets.calendarGrey,
selectionType: SelectionTypeEnum.calendar,
isHideSwitcher: true,
btnTitle: LocaleKeys.add.tr(context: context),
onCalendarTypeChanged: (val) {},
onChange: (val) {
if (val == null) return;

@ -92,13 +92,15 @@ class _HealthTrackerDetailPageState extends State<HealthTrackerDetailPage> {
/// Get empty state message based on tracker type
String _getEmptyStateMessage() {
final isArabic = getIt.get<AppState>().isArabic();
switch (widget.trackerType) {
case HealthTrackerTypeEnum.bloodSugar:
return "Please add data to track your Blood Sugar";
return isArabic ? "الرجاء إضافة قراءة جديدة لتتبع سكر الدم" : "Please add data to track your Blood Sugar";
case HealthTrackerTypeEnum.bloodPressure:
return "Please add data to track your Blood Pressure";
return isArabic ? "الرجاء إضافة قراءة جديدة لتتبع ضغط الدم" : "Please add data to track your Blood Pressure";
case HealthTrackerTypeEnum.weightTracker:
return "Please add data to track your Weight";
return isArabic ? "الرجاء إضافة قراءة جديدة لتتبع الوزن" : "Please add data to track your Weight";
}
}
@ -188,7 +190,7 @@ class _HealthTrackerDetailPageState extends State<HealthTrackerDetailPage> {
context: context,
title: LocaleKeys.selectDuration.tr(),
items: viewModel.durationFilters,
selectedValue: viewModel.selectedDurationFilter,
selectedValue: viewModel.selectedDurationFilterDisplay,
onSelected: viewModel.setFilterDuration,
);
}
@ -304,7 +306,7 @@ class _HealthTrackerDetailPageState extends State<HealthTrackerDetailPage> {
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
viewModel.selectedDurationFilter.toText12(isBold: true),
viewModel.selectedDurationFilterDisplay.toText12(isBold: true),
SizedBox(width: 4.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 16.h),
],
@ -573,6 +575,8 @@ class _HealthTrackerDetailPageState extends State<HealthTrackerDetailPage> {
}
Widget _buildEmptyStateWidget() {
final isArabic = getIt.get<AppState>().isArabic();
return SizedBox(
height: MediaQuery.of(context).size.height * 0.5,
child: Center(
@ -587,7 +591,7 @@ class _HealthTrackerDetailPageState extends State<HealthTrackerDetailPage> {
width: 48.w,
),
SizedBox(height: 16.h),
"You do not have any data available.".toText14(
(isArabic ? "ليس لديك أي بيانات متاحة." : "You do not have any data available.").toText14(
weight: FontWeight.w600,
color: AppColors.textColor,
isCenter: true,

@ -47,7 +47,7 @@ class _InsuranceHomePageState extends State<InsuranceHomePage> {
appState = getIt.get<AppState>();
insuranceViewModel = Provider.of<InsuranceViewModel>(context, listen: false);
return CollapsingListView(
title: "${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.updateInsurance.tr(context: context)}",
title: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.insurance.tr(context: context)}",
// history: () {
// // insuranceViewModel.setIsInsuranceHistoryLoading(true);
// // insuranceViewModel.getPatientInsuranceCardHistory();

@ -747,7 +747,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Expanded(
child: LabRadCard(
icon: AppAssets.radiology_icon,
labelText: "${LocaleKeys.radiology.tr(context: context)} ${LocaleKeys.results.tr(context: context)}",
labelText: LocaleKeys.radiologyLabResults.tr(context: context),
// labOrderTests: ["Complete blood count", "Creatinine", "Blood Sugar",
// labOrderTests: ["Chest X-ray", "Abdominal Ultrasound", "Dental X-ray"],
labOrderTests: [],
@ -1081,7 +1081,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
);
}),
MedicalFileCard(
label: "Allergy Information".needTranslation,
label: LocaleKeys.illurgyInfomation.tr(),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.allergy_info_icon,
@ -1096,7 +1096,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
);
}),
MedicalFileCard(
label: "Vaccine Information".needTranslation,
label: LocaleKeys.vaccineInfomation.tr(),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.vaccine_info_icon,
@ -1191,7 +1191,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Navigator.of(context).push(CustomPageRoute(page: InsuranceHomePage()));
}),
MedicalFileCard(
label: "${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.approvals.tr(context: context)}",
label: "${LocaleKeys.approvals1.tr(context: context)} ${LocaleKeys.insurance.tr(context: context)}",
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.insurance_approval_icon,
@ -1245,7 +1245,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true),
"${LocaleKeys.sickSubtitle.tr(context: context)} ${LocaleKeys.sick2.tr(context: context)}".toText16(isBold: true),
Row(
children: [
LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor),
@ -1567,7 +1567,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
icon: AppAssets.heightVital,
label: LocaleKeys.height.tr(context: context),
value: _formatValue(vitalSign.heightCm),
unit: 'cm',
unit: LocaleKeys.cm.tr(),
status: null,
onTap: onTap,
),
@ -1585,7 +1585,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
icon: AppAssets.weightVital,
label: LocaleKeys.weight.tr(context: context),
value: _formatValue(vitalSign.weightKg),
unit: 'kg',
unit: LocaleKeys.kg.tr(),
status: vitalSign.weightKg != null ? _getWeightStatus(vitalSign.bodyMassIndex) : null,
onTap: onTap,
),

@ -53,7 +53,7 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}",
title: "${LocaleKeys.sickSubtitle.tr(context: context)} ${LocaleKeys.sick.tr(context: context)}",
child: SingleChildScrollView(
child: Consumer<MedicalFileViewModel>(builder: (context, model, child) {
return Column(

@ -50,7 +50,7 @@ class _VaccineListPageState extends State<VaccineListPage> {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.vaccineInfo.tr(context: context),
title: LocaleKeys.vaccineInfomation.tr(context: context),
child: SingleChildScrollView(
child: Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return Column(

@ -199,7 +199,7 @@ class _SuggestionsScreenState extends State<SuggestionsScreen> {
children: [
Expanded(
child: CollapsingListView(
title: LocaleKeys.suggestions.tr(),
title: LocaleKeys.suggestions.tr() ,
leadingCallback: () => context.pop(),
child: viewModel.isSuggestionsLoading
? _buildLoadingShimmer()

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -53,9 +54,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
onChanged: (_) => onTap(),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
(useUpperCase ? value.toUpperCase() : value.toCamelCase)
.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1)
.expanded,
(useUpperCase ? value.toUpperCase() : value.toCamelCase).toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(onTap),
);
@ -103,7 +102,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
context: context,
title: LocaleKeys.selectGender.tr(context: context),
items: viewModel.genderOptions,
selectedValue: viewModel.selectedGender,
selectedValue: viewModel.selectedGenderDisplay,
onSelected: viewModel.setGender,
);
}
@ -112,8 +111,8 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
_showSelectionBottomSheet(
context: context,
title: LocaleKeys.selectUnit.tr(context: context),
items: viewModel.heightUnits,
selectedValue: viewModel.selectedHeightUnit,
items: viewModel.getHeightUnitsList(),
selectedValue: viewModel.selectedHeightUnitDisplay,
onSelected: viewModel.setHeightUnit,
useUpperCase: true,
);
@ -123,8 +122,8 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
_showSelectionBottomSheet(
context: context,
title: LocaleKeys.selectUnit.tr(context: context),
items: viewModel.weightUnits,
selectedValue: viewModel.selectedWeightUnit,
items: viewModel.getWeightUnitsList(),
selectedValue: viewModel.selectedWeightUnitDisplay,
onSelected: viewModel.setWeightUnit,
useUpperCase: true,
);
@ -135,7 +134,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
context: context,
title: LocaleKeys.selectActivityLevel.tr(context: context),
items: viewModel.activityLevels,
selectedValue: viewModel.selectedActivityLevel,
selectedValue: viewModel.selectedActivityLevelDisplay,
onSelected: viewModel.setActivityLevel,
);
}
@ -145,7 +144,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
context: context,
title: LocaleKeys.selectNumberOfReminders.tr(context: context),
items: viewModel.reminderOptions,
selectedValue: viewModel.selectedNumberOfReminders,
selectedValue: viewModel.selectedNumberOfRemindersDisplay,
onSelected: viewModel.setNumberOfReminders,
);
}
@ -184,6 +183,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
VoidCallback? onRowTap,
bool showDivider = true,
}) {
AppState appState = getIt<AppState>();
return Column(
children: [
Row(
@ -231,7 +231,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
appState.isArabic() ? "الوحدة".toText12(isBold: true, color: AppColors.inputLabelTextColor) : "Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
unit.toText12(isBold: true, color: AppColors.textColor),
],
),
@ -307,7 +307,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
_buildSettingsRow(
icon: AppAssets.genderIcon,
label: LocaleKeys.selectGender.tr(context: context),
value: viewModel.selectedGender,
value: viewModel.selectedGenderDisplay,
onRowTap: () => _showGenderSelectionBottomsheet(context, viewModel),
),
_buildSettingsRow(
@ -327,7 +327,7 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
'175',
keyboardType: TextInputType.number,
),
unit: viewModel.selectedHeightUnit,
unit: viewModel.selectedHeightUnitDisplay,
onUnitTap: () => _showHeightUnitSelectionBottomSheet(context, viewModel),
),
_buildSettingsRow(
@ -338,19 +338,19 @@ class _WaterMonitorSettingsPageState extends State<WaterMonitorSettingsPage> {
'75',
keyboardType: TextInputType.number,
),
unit: viewModel.selectedWeightUnit,
unit: viewModel.selectedWeightUnitDisplay,
onUnitTap: () => _showWeightUnitSelectionBottomsheet(context, viewModel),
),
_buildSettingsRow(
icon: AppAssets.dumbellIcon,
label: LocaleKeys.activityLevel.tr(context: context),
value: viewModel.selectedActivityLevel,
value: viewModel.selectedActivityLevelDisplay,
onRowTap: () => _showActivityLevelSelectionBottomsheet(context, viewModel),
),
_buildSettingsRow(
icon: AppAssets.notificationIconGrey,
label: LocaleKeys.numberOfRemindersInADay.tr(context: context),
value: viewModel.selectedNumberOfReminders,
value: viewModel.selectedNumberOfRemindersDisplay,
onRowTap: () => _showNumberOfRemindersSelectionBottomsheet(context, viewModel),
showDivider: false,
),

@ -2,6 +2,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -17,13 +19,15 @@ import 'package:uuid/uuid.dart';
/// Bottom sheet to switch between existing cups or add new custom cup
void showSwitchCupBottomSheet(BuildContext context) {
final isArabic = getIt.get<AppState>().isArabic();
return showCommonBottomSheetWithoutHeight(
context,
titleWidget: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Switch Cups".toText20(isBold: true),
"Select your preferred cup size".toText16(isBold: true, color: AppColors.greyTextColor),
(isArabic ? "تبديل الأكواب" : "Switch Cups").toText20(isBold: true),
(isArabic ? "اختر حجم الكوب المفضل لديك" : "Select your preferred cup size").toText16(isBold: true, color: AppColors.greyTextColor),
],
),
child: SwitchCupBottomSheet(),

@ -28,6 +28,7 @@ class DateRangeSelector extends StatefulWidget {
final CalendarDesignType designType;
final bool showCalendarToggle;
final OnCalendarTypeChanged? onCalendarTypeChanged;
final String? btnTitle;
const DateRangeSelector({
super.key,
@ -35,6 +36,7 @@ class DateRangeSelector extends StatefulWidget {
this.designType = CalendarDesignType.defaultUI,
this.showCalendarToggle = true,
this.onCalendarTypeChanged,
this.btnTitle,
});
@override
@ -83,7 +85,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
_calendarController.selectedRange = PickerDateRange(model.fromDate, model.toDate);
return widget.designType == CalendarDesignType.designV2 ? _buildDesignV2() : _buildDefaultUI();
return widget.designType == CalendarDesignType.designV2 ? _buildDesignV2(widget.btnTitle) : _buildDefaultUI();
}
Widget _buildDefaultUI() {
@ -247,7 +249,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
);
}
Widget _buildDesignV2() {
Widget _buildDesignV2(String? btnTitle) {
return ChangeNotifierProvider(
create: (_) => DateRangCalenderModel(appState: getIt(), navigationService: getIt(), dialogService: getIt()),
child: Consumer<DateRangCalenderModel>(
@ -317,7 +319,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
),
// Only Select button for V2 (no cancel button)
CustomButton(
text: LocaleKeys.select.tr(context: context),
text: btnTitle ?? LocaleKeys.select.tr(context: context),
onPressed: () {
// Don't reset calendar type - keep user's preference
Navigator.of(context).pop();

@ -45,6 +45,7 @@ class TextInputWidget extends StatelessWidget {
final Widget? suffix;
final Color? labelColor;
final Function(String)? onSubmitted;
final String? btnTitle;
// new multiline options
final bool isMultiline;
@ -59,45 +60,45 @@ class TextInputWidget extends StatelessWidget {
// final List<Country> countryList;
// final Function(Country)? onCountryChange;
TextInputWidget({
super.key,
required this.labelText,
required this.hintText,
this.controller,
this.onChange,
this.onCalendarTypeChanged,
this.prefix,
this.isEnable = true,
this.isBorderAllowed = true,
this.isAllowRadius = true,
this.isReadOnly = false,
this.keyboardType = TextInputType.number,
this.focusNode,
this.autoFocus = false,
this.padding,
this.isAllowLeadingIcon = false,
this.leadingIcon,
this.isCountryDropDown = false,
this.hasError = false,
this.errorMessage,
this.onCountryChange,
this.selectionType,
this.fontSize,
this.isWalletAmountInput = false,
this.suffix,
this.labelColor,
this.onSubmitted,
this.hintColor,
// multiline defaults
this.isMultiline = false,
this.minLines = 3,
this.maxLines = 6,
this.isHideSwitcher,
this.isArrowTrailing,
this.fontFamily,
// this.countryList = const [],
// this.onCountryChange,
});
TextInputWidget(
{super.key,
required this.labelText,
required this.hintText,
this.controller,
this.onChange,
this.onCalendarTypeChanged,
this.prefix,
this.isEnable = true,
this.isBorderAllowed = true,
this.isAllowRadius = true,
this.isReadOnly = false,
this.keyboardType = TextInputType.number,
this.focusNode,
this.autoFocus = false,
this.padding,
this.isAllowLeadingIcon = false,
this.leadingIcon,
this.isCountryDropDown = false,
this.hasError = false,
this.errorMessage,
this.onCountryChange,
this.selectionType,
this.fontSize,
this.isWalletAmountInput = false,
this.suffix,
this.labelColor,
this.onSubmitted,
this.hintColor,
// multiline defaults
this.isMultiline = false,
this.minLines = 3,
this.maxLines = 6,
this.isHideSwitcher,
this.isArrowTrailing,
this.fontFamily,
// this.countryList = const [],
// this.onCountryChange,
this.btnTitle});
final FocusNode _focusNode = FocusNode();
@ -218,7 +219,6 @@ class TextInputWidget extends StatelessWidget {
}
Widget _buildTrailingIcon(BuildContext context, {bool isArrowTrailing = false}) {
final AppState appState = getIt.get<AppState>();
return Container(
height: 40.h,
width: 40.w,
@ -227,20 +227,20 @@ class TextInputWidget extends StatelessWidget {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 12.r, color: AppColors.whiteColor),
child: GestureDetector(
onTap: () async {
showCommonBottomSheetWithoutHeight(
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.selectDate.tr(context: context),
context,
child: DateRangeSelector(
onRangeSelected: (DateTime? start, DateTime? end) {
var picked = start.toString().split(" ").first;
if (picked != null && onChange != null) {
onChange!(picked.toString());
}
},
designType: CalendarDesignType.designV2,
showCalendarToggle: isHideSwitcher == true ? false : true,
onCalendarTypeChanged: onCalendarTypeChanged,
),
onRangeSelected: (DateTime? start, DateTime? end) {
var picked = start.toString().split(" ").first;
if (picked != null && onChange != null) {
onChange!(picked.toString());
}
},
designType: CalendarDesignType.designV2,
showCalendarToggle: isHideSwitcher == true ? false : true,
onCalendarTypeChanged: onCalendarTypeChanged,
btnTitle: btnTitle ?? LocaleKeys.done.tr()),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {

Loading…
Cancel
Save