Merge branch 'master' into dev_aamir

# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/generated/locale_keys.g.dart
#	lib/presentation/book_appointment/select_clinic_page.dart
dev_aamir
aamir-csol 3 hours ago
commit cb2e3c7574

@ -0,0 +1,5 @@
<svg width="11" height="13" viewBox="0 0 11 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.3125 9.18754C8.3125 9.5097 8.05133 9.77087 7.72917 9.77087H3.64583C3.32367 9.77087 3.0625 9.5097 3.0625 9.18753C3.0625 8.86537 3.32367 8.6042 3.64583 8.6042L7.72917 8.6042C8.05133 8.6042 8.3125 8.86537 8.3125 9.18754Z" fill="#D48D05"/>
<path d="M7.72917 7.43754C8.05133 7.43754 8.3125 7.17637 8.3125 6.8542C8.3125 6.53204 8.05133 6.27087 7.72917 6.27087H5.97917C5.657 6.27087 5.39583 6.53204 5.39583 6.8542C5.39583 7.17637 5.657 7.43754 5.97917 7.43754H7.72917Z" fill="#D48D05"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.73382 12.4817C3.3068 12.5417 4.02593 12.5417 4.92491 12.5416H5.43552C6.53974 12.5417 7.42285 12.5417 8.11587 12.4537C8.83017 12.3629 9.42828 12.17 9.90594 11.7188C10.3885 11.263 10.5993 10.6844 10.6976 9.99371C10.7917 9.33241 10.7917 8.49251 10.7917 7.45491V3.86752C10.7917 3.40135 10.7917 3.02361 10.7714 2.71527C10.7505 2.39757 10.7064 2.11426 10.5995 1.8435C10.291 1.06224 9.64446 0.458909 8.84147 0.17599C8.3405 -0.000517334 7.48179 -0.000290103 6.5747 2.63095e-05C4.91826 -0.000183545 3.93438 -0.000307483 3.12796 0.28382C1.83296 0.74009 0.798282 1.71002 0.3063 2.95606C0.142319 3.37137 0.0696729 3.81745 0.034526 4.35227C-2.24045e-06 4.87769 -1.10714e-06 5.52671 3.38423e-07 6.35404L3.38423e-07 7.8611C-1.19404e-05 8.70582 -2.16874e-05 9.38986 0.0640774 9.93664C0.130643 10.5045 0.272541 10.9932 0.604942 11.4127C0.777131 11.63 0.98045 11.8217 1.20816 11.9828C1.64261 12.29 2.14499 12.4201 2.73382 12.4817ZM9.12738 10.8885C8.89802 11.1052 8.57364 11.2463 7.97325 11.3225C7.35988 11.4004 6.5489 11.4015 5.39582 11.4015H4.95693C4.01857 11.4015 3.35874 11.4008 2.85157 11.3477C2.35344 11.2956 2.07116 11.1983 1.86242 11.0507C1.72157 10.9511 1.59769 10.8338 1.49397 10.7029C1.3449 10.5148 1.24605 10.2623 1.19225 9.80338C1.13687 9.33102 1.13596 8.71425 1.13596 7.82557L1.13591 6.13379C1.1359 5.97803 1.136 5.60554 1.29969 5.33011C1.40057 5.16037 1.52973 5.01856 1.66241 4.94633C1.87621 4.82994 2.12132 4.76381 2.38188 4.76381L2.98876 4.7851C3.21048 4.7897 3.46921 4.7827 3.71896 4.71578C4.20545 4.58542 4.58543 4.20544 4.71579 3.71895C4.78271 3.4692 4.78971 3.21047 4.78511 2.98875L4.76382 2.38187C4.76382 2.10905 4.83638 1.87156 4.96316 1.65082C5.03707 1.52214 5.16584 1.40437 5.34361 1.30094C5.61319 1.14408 5.93601 1.14262 6.13327 1.14173C6.33053 1.14084 6.53865 1.14016 6.71251 1.14016C7.78242 1.14016 8.17157 1.1483 8.4652 1.25175C8.97423 1.4311 9.36256 1.8054 9.54344 2.26352C9.58874 2.37823 9.62073 2.52898 9.6379 2.79028C9.6554 3.05668 9.65569 3.39673 9.65569 3.88688V7.41097C9.65569 8.503 9.65433 9.26115 9.57302 9.83245C9.49457 10.3836 9.35187 10.6765 9.12738 10.8885Z" fill="#D48D05"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -0,0 +1,4 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.32954 16.125C6.17371 16.125 4.2516 16.125 3.5149 16.0479C2.75784 15.9687 2.11193 15.8014 1.55335 15.4064C1.26058 15.1994 0.999168 14.9528 0.777782 14.6734C0.35041 14.1341 0.16797 13.5057 0.082385 12.7757C-2.81744e-05 12.0727 -1.53024e-05 11.1932 4.33207e-07 10.1071V8.16951C-9.97304e-07 7.10582 -2.42796e-06 6.27131 0.0443906 5.59578C0.0895791 4.90815 0.182981 4.33462 0.393815 3.80065C1.02636 2.1986 2.35666 0.951546 4.02166 0.364913C5.05849 -0.000393972 6.32348 -0.000236608 8.45319 3.37585e-05C9.61944 -0.000372507 10.7235 -0.000664338 11.3676 0.226273C12.4 0.590027 13.2313 1.36573 13.6279 2.37021C13.7654 2.71833 13.8221 3.08259 13.849 3.49106C13.875 3.88749 13.875 4.37316 13.875 4.97253V5.83223C13.875 6.23555 13.548 6.5625 13.1447 6.5625C12.7414 6.5625 12.4145 6.23555 12.4145 5.83223V4.99742C12.4145 4.36722 12.4141 3.93001 12.3916 3.58751C12.3695 3.25154 12.3284 3.05773 12.2701 2.91025C12.0376 2.32122 11.5383 1.83999 10.8838 1.6094C10.5063 1.47639 10.006 1.46592 8.63037 1.46592C8.40683 1.46592 8.13925 1.4668 7.88563 1.46794C7.63201 1.46909 7.21696 1.47096 6.87035 1.67263C6.6418 1.80562 6.47623 1.95704 6.38121 2.12248C6.2182 2.40629 6.12491 2.71164 6.12491 3.0624L6.15228 3.84268C6.1582 4.12775 6.14919 4.4604 6.06315 4.78151C5.89556 5.40699 5.407 5.89555 4.78152 6.06314C4.46041 6.14919 4.12776 6.15819 3.84268 6.15227L3.06241 6.1249C2.72741 6.1249 2.41226 6.20992 2.13738 6.35957C1.96679 6.45243 1.80073 6.63476 1.67103 6.85299C1.46057 7.20712 1.46044 7.68604 1.46045 7.88631L1.46052 10.0614C1.46052 11.204 1.4617 11.997 1.53289 12.6044C1.60207 13.1944 1.72915 13.519 1.92082 13.7609C2.05417 13.9292 2.21345 14.08 2.39454 14.2081C2.66291 14.3978 3.02586 14.5229 3.6663 14.5899C4.31838 14.6581 6.12307 14.6591 7.32954 14.6591C7.73434 14.6591 8.0625 14.9872 8.0625 15.3921C8.0625 15.7969 7.73434 16.125 7.32954 16.125Z" fill="#F43333"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.1909 7.74268C12.0592 7.4633 11.7697 7.29324 11.4615 7.31423C11.1534 7.33522 10.8896 7.54297 10.797 7.83762L9.72246 11.2566L9.33448 10.4336C9.23436 10.2212 9.13716 10.0149 9.03714 9.84819C8.92509 9.6614 8.77697 9.46633 8.54751 9.31592C8.31524 9.16367 8.07628 9.10728 7.8576 9.0833C7.66706 9.0624 7.44476 9.06245 7.22295 9.06249L6.5625 9.06249C6.14829 9.06249 5.8125 9.39828 5.8125 9.81249C5.8125 10.2267 6.14829 10.5625 6.5625 10.5625H7.19274C7.45714 10.5625 7.59536 10.5635 7.69409 10.5744C7.70631 10.5757 7.71628 10.577 7.72429 10.5783C7.73108 10.5881 7.73992 10.6016 7.75086 10.6199C7.80748 10.7142 7.8728 10.8507 7.99016 11.0997L9.18411 13.6323C9.31581 13.9117 9.60532 14.0817 9.91347 14.0608C10.2216 14.0398 10.4854 13.832 10.578 13.5374L11.6525 10.1184L12.0405 10.9414C12.1406 11.1538 12.2378 11.3601 12.3379 11.5268C12.4499 11.7136 12.598 11.9087 12.8275 12.0591C13.0598 12.2113 13.2987 12.2677 13.5174 12.2917C13.7079 12.3126 13.9302 12.3125 14.1521 12.3125L14.8125 12.3125C15.2267 12.3125 15.5625 11.9767 15.5625 11.5625C15.5625 11.1483 15.2267 10.8125 14.8125 10.8125H14.1823C13.9179 10.8125 13.7796 10.8115 13.6809 10.8006C13.6687 10.7993 13.6587 10.7979 13.6507 10.7967C13.6439 10.7869 13.6351 10.7734 13.6241 10.7551C13.5675 10.6608 13.5022 10.5242 13.3848 10.2753L12.1909 7.74268ZM7.70832 10.5571L7.70719 10.5559C7.70719 10.5559 7.70757 10.5563 7.70832 10.5571ZM13.6667 10.8179L13.6678 10.8191C13.6678 10.8191 13.6674 10.8187 13.6667 10.8179Z" fill="#F43333"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 6.27083C0 9.73408 2.80758 12.5417 6.27083 12.5417C9.73408 12.5417 12.5417 9.73408 12.5417 6.27083C12.5417 2.80758 9.73408 0 6.27083 0C2.80758 0 0 2.80758 0 6.27083ZM8.9985 4.09091C9.23592 4.30849 9.25167 4.67774 9.03409 4.91515L5.82576 8.41515C5.71842 8.5324 5.56733 8.60067 5.40867 8.60417C5.24941 8.60767 5.096 8.54585 4.98341 8.43327L3.52508 6.97494C3.297 6.74744 3.297 6.37756 3.52508 6.15006C3.75258 5.92198 4.12242 5.92198 4.34992 6.15006L5.37775 7.17734L8.17424 4.12651C8.39183 3.8891 8.76108 3.87333 8.9985 4.09091Z" fill="#18C273"/>
</svg>

After

Width:  |  Height:  |  Size: 697 B

@ -680,8 +680,8 @@
"noOffersAvailable": "لا توجد عروض متاحة!",
"accessibility": "وضع الوصول",
"orderStatus": "حالة الطلب",
"findUs": "اعثر علينا",
"liveChat": "دردشة مباشرة",
"findUs": "فروعنا",
"liveChat": "محادثة مباشرة",
"service": "خدمة",
"hmgServiceLabel": "خدمة مجموعة الحبيب الطبية",
"healthWeatherIndicators": "مؤشرات الطقس الصحية",
@ -1049,9 +1049,9 @@
"noServicesAvailable": "لا توجد خدمات متاحة",
"selectAService": "اختر خدمة",
"comprehensiveCheckup": "الفحص الشامل",
"viewNearestHMGLocations": "عرض أقرب مواقع مجموعة الحبيب الطبية",
"viewNearestHMGLocations": "عرض أقرب فرع",
"provideFeedbackOnServices": "قدم ملاحظاتك على خدماتنا",
"liveChatWithHMG": "خيار الدردشة المباشرة مع مجموعة الحبيب الطبية",
"liveChatWithHMG": "حدث مباشرة مع الموظف",
"send": "إرسال",
"status": "الحالة",
"sendingFeedback": "جاري إرسال الملاحظات...",
@ -1160,11 +1160,18 @@
"recharge": "شحن المحفظة",
"activityLevel": "مستوى النشاط",
"selectActivityLevel": "حدد مستوى النشاط",
"almostInactive": "غير نشط تقريبًا (بدون تمارين)",
"lightlyActive": "نشاط خفيف",
"lightlyActive13Days": "نشاط خفيف (١-٣) أيام في الأسبوع",
"superActive": "نشاط مكثف (تمارين شاقة جدًا)",
"caloriesPerDay": "السعرات الحرارية في اليوم الواحد",
"dietType": "نوع النظام الغذائي",
"selectDietType": "حدد نوع النظام الغذائي",
"bodyFrameSize": "حجم إطار الجسم",
"selectBodyFrameSize": "حدد حجم إطار الجسم",
"bodyFrameSmall": "صغير (الأصابع متداخلة)",
"bodyFrameMedium": "متوسط (الأصابع متلامسة)",
"bodyFrameLarge": "كبير (الأصابع لا تتلامس)",
"averageCycleLength": "متوسط طول الدورة الشهرية (عادةً 28 يومًا)",
"averageLutealPhase": "متوسط طول المرحلة الأصفرية (عادةً 14 يومًا)",
"convert": "تحويل الوحدات",
@ -1254,7 +1261,7 @@
"virtualTour": "جولة افتراضية",
"carParking": "موقف السيارات",
"latestNews": "آخر الأخبار",
"hmgContact": "اتصل بمجموعة الحبيب الطبية",
"hmgContact": "تواصل معنا",
"durationCannotExceed90": "لا يجوز أن تتجاوز المدة 90 دقيقة",
"unexpectedError": "حدث خطأ غير متوقع",
"gettingAmbulanceTransportOption": "جاري الحصول على خيارات نقل الإسعاف",
@ -1333,6 +1340,7 @@
"askYourDoctor": "اسأل طبيبك",
"internetPairing": "الاقتران بالإنترنت",
"requested": "مطلوب",
"readyToDownload": "جاهز للتحميل",
"youDontHaveAnyMedicalReportsYet": "ليس لديك أي تقارير طبية",
"requestMedicalReport": "طلب تقرير طبي",
"youDoNotHaveAnyAppointmentsToRequestMedicalReport": "ليس لديك أي مواعيد لطلب تقرير طبي.",
@ -1470,7 +1478,7 @@
"covered": "مغطى",
"vatPercent": "ضريبة القيمة المضافة (15%)",
"proceedToPayment": "المتابعة للدفع",
"supportedSmartWatches": "الساعات الذكية المدعومة",
"supportedSmartWatches": "كيف تعمل؟",
"pleaseMakeSureSamsungWatchConnected": "يرجى التأكد من أن ساعة Samsung الخاصة بك متصلة بهاتفك، ومتزامنة ومحدثة بشكل نشط.",
"beforeSyncingDataFollowInstructions": "قبل مزامنة البيانات، يرجى التأكد من اتباع التعليمات بشكل صحيح.",
"viewWatchInstructions": "عرض تعليمات الساعة",
@ -1704,7 +1712,7 @@
"enterAmount": "يرجى إدخال المبلغ للمتابعة.",
"selectHospitalContinue": "يرجى اختيار المستشفى للمتابعة.",
"year": "سنة",
"notifyPrescription": "أبلغني قبل وقت الاستهلاك",
"notifyPrescription": "تنبيه قبل موعد الجرعة",
"doctorRatingAppointment": "طبيب\nتصنيف",
"ratingSubmitted": "تم إرسال التقييم",
"rateTheDoctor": "يرجى تقييم الطبيب",
@ -1771,6 +1779,20 @@
"illurgyInfomation": "الحساسية",
"vaccineInfomation": "التطعيمات",
"approvals1": "موافقات",
"convertBloodcholesterolInfo":"حول قيمة كوليسترول الدم بين ملجم/ديسيلتر و مليمول/لتر"
"convertBloodcholesterolInfo":"حول قيمة كوليسترول الدم بين ملجم/ديسيلتر و مليمول/لتر",
"carbsAlert": "حساب نسب المغذيات (الكربوهيدرات ،البروتين والدهون) بالسعرات الحرارية والقرامات وفقا لنسب محددة مسبقا",
"bodyFatAlert": "يحسب بناءً على الحجم",
"ibwAlert": "حساب الوزن المثالي بناءً على الطول، الوزن، وبنية الجسم",
"glucoseAlert":"تغيير وحدات القياس بين مليجرام لكل ديسيلتر و ملي مول لكل لتر",
"selectBloodGroup": "اختر الفصيلة",
"routePrescription": "طريقة الاستخدام",
"noNearestER": "لا يوجد طوارئ قريب منك",
"loginToUseServiceLiveCare": "تحتاج إلى تسجيل الدخول لاستخدام هذه الخدمة",
"mldl": "مليجرام لكل ديسيلتر",
"mmol": "ملي مول لكل لتر",
"triglycerideInfo": "تغيير وحدات القياس بين مليجرام لكل ديسيلتر و ملي مول لكل لتر",
"selectSmartWatch": "تعيين",
"selectBloodDonationCity": "اختر المدينة",
"selectBloodDonationGender": "اختر الجنس",
"selectBloodType": "اختر الفصيلة"
}

@ -944,7 +944,7 @@
"doctorWillContact": "Doctor will contact you",
"specialisedDoctorWillContactYou": "A specialized doctor will contact you and will be able to view your medical history",
"freeMedicineDelivery": "Free medicine delivery",
"offersFreeMedicineDelivery": "Offers free medicine delivery for the LiveCare appointment",
"offersFreeMedicineDelivery": "Receive free medicine delivery with your LiveCare appointment.",
"dentalChiefComplaints": "Dental Chief Complaints",
"viewAvailableAppointments": "View available appointments",
"doctorProfile": "Doctor Profile",
@ -1136,14 +1136,14 @@
"allFacilities": "All Facilities",
"selectLocation": "Select Location",
"pleaseSelectTheLocation": "Please select the location",
"viewLocationGoogleMaps": "View Location on Google Maps",
"viewLocationGoogleMaps": "Get Directions on Google Maps",
"callAmbulance": "Call Ambulance",
"requestAmbulanceInEmergency": "Request an ambulance in emergency from home or hospital",
"requestAmbulanceInEmergency": "Request an ambulance for immediate assistance in cases of emergency.",
"confirmation": "Confirmation",
"areYouSureYouWantToCallAmbulance": "Are you sure you want to call an ambulance?",
"getDetailsOfNearestBranch": "Get the details of nearest branch including directions",
"getDetailsOfNearestBranch": "Find the nearest ER and get directions.",
"areYouSureYouWantToCallRRT": "Are you sure you want to call Rapid Response Team (RRT)?",
"priorERCheckInToSkipLine": "Prior ER Check-In to skip the line & payment at the reception.",
"priorERCheckInToSkipLine": "Check in before you arrive to the ER to skip the line & payment at reception.",
"areYouSureYouWantToMakeERCheckIn": "Are you sure you want to request an online ER check-in?",
"checkingYourERAppointmentStatus": "Please Wait...",
"transportOptions": "Transport Options",
@ -1151,11 +1151,18 @@
"recharge": "Add Funds",
"activityLevel": "Activity Level",
"selectActivityLevel": "Select Activity Level",
"almostInactive": "Almost Inactive (no exercise)",
"lightlyActive": "Lightly active",
"lightlyActive13Days": "Lightly active (1-3) days per week",
"superActive": "Super active (very hard exercise)",
"caloriesPerDay": "Calories Per Day",
"dietType": "Diet Type",
"selectDietType": "Select Diet Type",
"bodyFrameSize": "Body Frame Size",
"selectBodyFrameSize": "Select Body Frame Size",
"bodyFrameSmall": "Small (fingers overlaps)",
"bodyFrameMedium": "Medium (fingers touch)",
"bodyFrameLarge": "Large (fingers don't touch)",
"averageCycleLength": "Average Cycle Length (Usually 28 days)",
"averageLutealPhase": "Average Luteal Phase Length(Usually 14 days)",
"convert": "Convert",
@ -1323,6 +1330,7 @@
"askYourDoctor": "Ask Your Doctor",
"internetPairing": "Internet Pairing",
"requested": "Requested",
"readyToDownload": "Ready to download",
"youDontHaveAnyMedicalReportsYet": "You don't have any medical reports yet.",
"requestMedicalReport": "Request medical report",
"youDoNotHaveAnyAppointmentsToRequestMedicalReport": "You do not have any appointments to request a medical report.",
@ -1662,8 +1670,8 @@
"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.",
"emergencyServiceHeader": "Emergency Care, Faster than Ever.",
"emergencyServiceDescription": "Facing a medical emergency? Our ambulances are on standby 24/7 for your immediate assistance.",
"homeHealthCareServiceHeader": "Premium care, delivered right to your doorstep",
"homeHealthCareServiceDescription": "We provide the highest degree of patient care at home in a value-oriented, efficient, and professional manner.",
"profileOnlyText": "Profile",
@ -1705,7 +1713,7 @@
"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.",
"RRTDDetails": "Comprehensive medical services for stable and urgent cases, available for all ages.",
"fromHospitalSubtitle": "Transfer from the hospital back to your home",
"normalMapType": "Default",
"satelliteMapType": "Satellite",
@ -1756,8 +1764,23 @@
"selectCriteria": "Select Criteria",
"locationServicesDisabled": "Weather is unavailable because location services are disabled. Please enable location services to see the weather information.",
"selectDateTimeKey": "Select",
"carbsAlert":"Calculate carbohydrate based protein and fat ration in calories and grams according to a pre set ratio.",
"bodyFatAlert": "Estimate the total body fat based on the size.",
"ibwAlert": "Calculates the ideal body weight based on height, weight and body size.",
"glucoseAlert":"Convert blood glucose values between mg/dL and mmol/L. (1 mmol/L ≈ 18.0182 mg/dL)",
"selectBloodGroup": "Select Blood Group",
"routePrescription": "Route",
"noNearestER": "No nearest Er Around you",
"loginToUseServiceLiveCare": "Log In to Use This Service",
"medicalKey": "Medical",
"convertBloodcholesterolInfo": "Convert blood cholesterol values between mg/dL and mmol/L. "
"convertBloodcholesterolInfo": "Convert blood cholesterol values between mg/dL and mmol/L. ",
"mldl": "مليجرام لكل ديسيلتر",
"mmol": "ملي مول لكل لتر",
"triglycerideInfo": "Convert triglyceride values between mg/dL and mmol/L.",
"selectSmartWatch": "Select",
"selectBloodDonationCity": "Select City",
"selectBloodDonationGender": "Select Gender",
"selectBloodType": "Select Blood Type",
"doctors2": "Doctor",
"illurgyInfomation": "Allergy",
"vaccineInfomation": "Vaccine",

@ -172,6 +172,7 @@ class ApiClientImp implements ApiClient {
// body['VersionID'] = ApiConsts.appVersionID.toString();
if (!isExternal) {
body['VersionID'] = ApiConsts.appVersionID.toString();
if(!isRCService)
body['Channel'] = ApiConsts.appChannelId.toString();
body['IPAdress'] = ApiConsts.appIpAddress;
body['generalid'] = ApiConsts.appGeneralId;

@ -189,6 +189,7 @@ class ApiConsts {
static final createEReferral = "Services/Patients.svc/REST/CreateEReferral";
static final getEReferrals = "Services/Patients.svc/REST/GetEReferrals";
//WATER CONSUMPTION
static String h2oGetUserProgress = "Services/H2ORemainder.svc/REST/H2O_GetUserProgress";
static String h2oInsertUserActivity = "Services/H2ORemainder.svc/REST/H2O_InsertUserActivity";

@ -17,6 +17,9 @@ class AppAssets {
static const String email = '$svgBasePath/email.svg';
static const String globe = '$svgBasePath/globe.svg';
static const String globeOther = '$svgBasePath/globe_other.svg';
static const String document = '$svgBasePath/document.svg';
static const String report = '$svgBasePath/report.svg';
static const String sucess = '$svgBasePath/sucess.svg';
// static const String globeOther = '$svgBasePath/globe_other.svg';
static const String cancel = '$svgBasePath/cancel.svg';
@ -401,7 +404,7 @@ class AppAssets {
static const String lockIcon = '$pngBasePath/lock-icon.png';
static const String dummyUser = '$pngBasePath/dummy_user.png';
static const String comprehensiveCheckupEn = '$pngBasePath/cc_en.png';
static const String comprehensiveCheckupAr = '$pngBasePath/cc_er.png';
static const String comprehensiveCheckupAr = '$pngBasePath/cc_ar.png';
static const String maleIcon = '$pngBasePath/male_icon.png';
static const String femaleIcon = '$pngBasePath/female_icon.png';

@ -5,8 +5,11 @@
// unverified,
// }
import 'package:easy_localization/easy_localization.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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
enum AuthMethodTypesEnum { sms, whatsApp, fingerPrint, faceID, moreOptions }
@ -20,6 +23,17 @@ enum SelectionTypeEnum { dropdown, calendar, search, time }
enum GenderTypeEnum { male, female }
extension GenderTypeEnumExtension on GenderTypeEnum {
String get displayName {
switch (this) {
case GenderTypeEnum.male:
return LocaleKeys.malE.tr();
case GenderTypeEnum.female:
return LocaleKeys.femaleGender.tr();
}
}
}
enum MaritalStatusTypeEnum { single, married, divorced, widowed }
enum ChipTypeEnum { success, error, alert, info, warning, lightBg, primaryRed }
@ -68,7 +82,7 @@ extension HealthCalculatorExtenshion on HealthCalculatorsTypeEnum {
case HealthCalculatorsTypeEnum.bodyFat:
return isArabic ? "دهون الجسم" : "Body Fat Calculator";
case HealthCalculatorsTypeEnum.crabsProteinFat:
return isArabic ? "حاسبة البروتين والدهون في سرطان البحر" : "Crabs Protein & Fat Calculator";
return isArabic ? "حاسبة المغذيات" : "Crabs Protein & Fat Calculator";
case HealthCalculatorsTypeEnum.ovulation:
return isArabic ? "فترة الإباضة" : "Ovulation Period";
case HealthCalculatorsTypeEnum.deliveryDueDate:
@ -80,6 +94,22 @@ extension HealthCalculatorExtenshion on HealthCalculatorsTypeEnum {
case HealthCalculatorsTypeEnum.triglycerides:
return isArabic ? "الدهون الثلاثية في الدم" : "Triglycerides Fat Blood";
}
}
String get title {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case HealthCalculatorsTypeEnum.crabsProteinFat:
return isArabic ? "نتيجة المغذيات" : "Nutrient Results";
case HealthCalculatorsTypeEnum.calories:
return isArabic ? "سعراتك الحرارية" : "Calories";
case HealthCalculatorsTypeEnum.calories:
return isArabic ? "مؤشر كتلة الجسم" : "BMI";
default:
return "Your ${this.name.toCamelCase}";
}
}
static LoginTypeEnum? fromValue(int value) {

@ -9,17 +9,27 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/entities/android_params.dart';
import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/entities/call_kit_params.dart';
import 'package:flutter_callkit_incoming/entities/ios_params.dart';
import 'package:flutter_callkit_incoming/entities/notification_params.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_ios_voip_kit_karmm/call_state_type.dart';
import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
// Global tracking variables for call state
bool _isCallInProgress = false;
String? _currentCallId;
Timer? _callTimeoutTimer;
String? _currentSessionId; // Store session ID for API call
// |--> Push Notification Background
@pragma('vm:entry-point')
Future<dynamic> backgroundMessageHandler(dynamic message) async {
@ -39,34 +49,36 @@ callPage(String sessionID, String token) async {}
_incomingCall(Map<String, dynamic> data) async {
print('the value of the _incomingCall remote message is $data');
// LandingPage.incomingCallData = IncomingCallData.fromJson(data);
// var dataItem = await AppSharedPreferences().getObject('call_data');
// if(dataItem != null ) return; // to stop repeated attempt to invoke the call
// if (LandingPage.isOpenCallPage == false) {
// LandingPage.isOpenCallPage = true;
// Check if there's already a call in progress to prevent duplicates
if (_isCallInProgress && _currentCallId != null) {
print('⚠️ Call already in progress (ID: $_currentCallId), ignoring duplicate notification');
return;
}
String roomID = data['session_id'] ?? '';
String callTypeID = data['AppointmentNo'] ?? '';
// GetIt.instance<CacheService>().saveString(key: CacheConst.zoomRoomID, value: roomID);
// GetIt.instance<CacheService>().saveBool(key: CacheConst.isAppOpenedFromCall, value: true);
// Generate unique call ID
var _currentUuid = Uuid().v4();
_currentCallId = _currentUuid;
_isCallInProgress = true;
_currentSessionId = roomID; // Store session ID for decline API call
print('📞 Starting new call with ID: $_currentCallId, Session: $_currentSessionId');
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, roomID);
await Utils.saveStringFromPrefs(CacheConst.callTypeID, callTypeID);
await Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, true);
WidgetsFlutterBinding.ensureInitialized();
int callKitType = callTypeID == '2' ? 0 : 1;
var _currentUuid = Uuid().v4();
CallKitParams callKitParams = CallKitParams(
id: _currentUuid,
nameCaller: "Dr Al Habib",
appName: 'Dr Al Habib',
avatar: 'https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG',
// handle: LandingPage.incomingCallData.name,
type: callKitType,
textAccept: 'Accept',
textDecline: 'Decline',
@ -85,8 +97,8 @@ _incomingCall(Map<String, dynamic> data) async {
duration: 30000,
extra: <String, dynamic>{
'userId': '1a2b3c4d',
'callTypeID': callTypeID, // Store actual callTypeID here
'roomID': roomID, // Store roomID here for backup
'callTypeID': callTypeID,
'roomID': roomID,
},
headers: <String, dynamic>{'apiKey': 'Abc@123!', 'platform': 'flutter'},
android: const AndroidParams(
@ -96,10 +108,10 @@ _incomingCall(Map<String, dynamic> data) async {
isShowLogo: false,
logoUrl: "https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG",
ringtonePath: 'system_ringtone_default',
backgroundColor: '#ED1C2B',
backgroundColor: '#2E3039',
backgroundUrl: 'https://saudipedia.com/en/saudipediaen/uploads/images/2024/08/02/97358.jpg',
actionColor: '#4CAF50',
textColor: '#000000',
textColor: '#FFFFFF',
incomingCallNotificationChannelName: "Incoming Call",
missedCallNotificationChannelName: "Missed Call",
isShowCallID: false),
@ -120,12 +132,89 @@ _incomingCall(Map<String, dynamic> data) async {
ringtonePath: 'system_ringtone_default',
),
);
FlutterCallkitIncoming.unsilenceEvents();
await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
// Start 60-second timeout timer to auto-dismiss call
_callTimeoutTimer?.cancel(); // Cancel any existing timer
_callTimeoutTimer = Timer(Duration(seconds: 40), () async {
print('⏱️ Call timeout (60 seconds) - auto dismissing call notification');
await _endCallAndCleanup(_currentUuid);
});
await Future.delayed(Duration(milliseconds: 500));
}
// Helper method to end call and cleanup
Future<void> _endCallAndCleanup(String callId, {bool isDeclined = false}) async {
try {
print('🧹 Cleaning up call: $callId');
// If call was declined, update session status via API
if (isDeclined && _currentSessionId != null && _currentSessionId!.isNotEmpty) {
await _updateSessionStatus(_currentSessionId!, 3, 'Patient');
}
// End the specific call
await FlutterCallkitIncoming.endCall(callId);
// Clear all calls to ensure clean state
await FlutterCallkitIncoming.endAllCalls();
// Reset tracking flags
_isCallInProgress = false;
_currentCallId = null;
_currentSessionId = null;
// Cancel timer
_callTimeoutTimer?.cancel();
_callTimeoutTimer = null;
// Clear cache
await Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, false);
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, '');
await Utils.saveStringFromPrefs(CacheConst.callTypeID, '');
print('✅ Call and push notification cleanup completed successfully');
} catch (e) {
print('❌ Error during call cleanup: $e');
// Force reset flags even if there's an error
_isCallInProgress = false;
_currentCallId = null;
_currentSessionId = null;
_callTimeoutTimer?.cancel();
_callTimeoutTimer = null;
}
}
// Helper method to update session status via API
Future<void> _updateSessionStatus(String sessionId, int sessionStatus, String sessionEndedBy) async {
try {
final apiClient = getIt.get<ApiClient>();
Map<String, dynamic> requestBody = {
"Open_SessionID": sessionId,
"SessionStatus": sessionStatus,
"SessionEndedBy": sessionEndedBy
};
await apiClient.post(
CHANGE_PATIENT_ER_SESSION,
body: requestBody,
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
print('✅ Session status updated successfully: $response');
},
onFailure: (error, statusCode, {messageStatus, failureType}) {
print('❌ Failed to update session status: $error');
},
);
} catch (e) {
print('❌ Exception updating session status: $e');
}
}
Future<void> openCallPage(BuildContext context) async {
try {
// if (incomingCallData!.background == "0") {
@ -291,6 +380,10 @@ class PushNotificationHandler {
try {
print('🎈 example: onDidRejectIncomingCall $uuid - $callerId');
timeOutTimer.cancel();
// Cleanup on reject with API call
if (_currentCallId != null) {
await _endCallAndCleanup(_currentCallId!, isDeclined: true);
}
} catch (err) {}
};
@ -301,6 +394,12 @@ class PushNotificationHandler {
print('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected();
// Cleanup on accept - cancel timer and reset flags
_callTimeoutTimer?.cancel();
_callTimeoutTimer = null;
_isCallInProgress = false;
_currentCallId = null;
await Future.delayed(Duration(seconds: 2)).then((val) async {
await voIPKit.endCall();
});

@ -306,6 +306,23 @@ class PrescriptionsViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) {
isPrescriptionsDeliveryOrdersLoading = false;
prescriptionsOrderList = apiResponse.data!;
// Sort by created date (newest first)
prescriptionsOrderList.sort((a, b) {
try {
if (a.created == null && b.created == null) return 0;
if (a.created == null) return 1;
if (b.created == null) return -1;
DateTime dateA = DateTime.parse(a.created!);
DateTime dateB = DateTime.parse(b.created!);
return dateB.compareTo(dateA); // Descending order (newest first)
} catch (e) {
print('Error parsing date for sorting: $e');
return 0;
}
});
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);

@ -1158,11 +1158,18 @@ abstract class LocaleKeys {
static const recharge = 'recharge';
static const activityLevel = 'activityLevel';
static const selectActivityLevel = 'selectActivityLevel';
static const almostInactive = 'almostInactive';
static const lightlyActive = 'lightlyActive';
static const lightlyActive13Days = 'lightlyActive13Days';
static const superActive = 'superActive';
static const caloriesPerDay = 'caloriesPerDay';
static const dietType = 'dietType';
static const selectDietType = 'selectDietType';
static const bodyFrameSize = 'bodyFrameSize';
static const selectBodyFrameSize = 'selectBodyFrameSize';
static const bodyFrameSmall = 'bodyFrameSmall';
static const bodyFrameMedium = 'bodyFrameMedium';
static const bodyFrameLarge = 'bodyFrameLarge';
static const averageCycleLength = 'averageCycleLength';
static const averageLutealPhase = 'averageLutealPhase';
static const convert = 'convert';
@ -1330,6 +1337,7 @@ abstract class LocaleKeys {
static const askYourDoctor = 'askYourDoctor';
static const internetPairing = 'internetPairing';
static const requested = 'requested';
static const readyToDownload = 'readyToDownload';
static const youDontHaveAnyMedicalReportsYet = 'youDontHaveAnyMedicalReportsYet';
static const requestMedicalReport = 'requestMedicalReport';
static const youDoNotHaveAnyAppointmentsToRequestMedicalReport = 'youDoNotHaveAnyAppointmentsToRequestMedicalReport';
@ -1759,6 +1767,22 @@ abstract class LocaleKeys {
static const locationServicesDisabled = 'locationServicesDisabled';
static const selectDateTimeKey = 'selectDateTimeKey';
static const medicalKey = 'medicalKey';
static const convertBloodcholesterolInfo = 'convertBloodcholesterolInfo';
static const carbsAlert = 'carbsAlert';
static const bodyFatAlert = 'bodyFatAlert';
static const ibwAlert = 'ibwAlert';
static const glucoseAlert = 'glucoseAlert';
static const selectBloodGroup = 'selectBloodGroup';
static const routePrescription = 'routePrescription';
static const noNearestER = 'noNearestER';
static const loginToUseServiceLiveCare = 'loginToUseServiceLiveCare';
static const mldl = 'mldl';
static const mmol = 'mmol';
static const triglycerideInfo = 'triglycerideInfo';
static const selectSmartWatch = 'selectSmartWatch';
static const selectBloodDonationCity = 'selectBloodDonationCity';
static const selectBloodDonationGender = 'selectBloodDonationGender';
static const selectBloodType = 'selectBloodType';
static const doctors2 = 'doctors2';
static const illurgyInfomation = 'illurgyInfomation';
static const vaccineInfomation = 'vaccineInfomation';

@ -148,8 +148,8 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
children: [
LocaleKeys.city.tr().toText16(color: AppColors.textColor, isBold: true),
(appState.isArabic()
? (bloodDonationVM.selectedCity?.descriptionN ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedCity?.description ?? LocaleKeys.select.tr(context: context))
? (bloodDonationVM.selectedCity?.descriptionN ?? LocaleKeys.selectBloodDonationCity.tr())
: bloodDonationVM.selectedCity?.description ?? LocaleKeys.selectBloodDonationCity.tr(context: context))
.toText14(color: AppColors.greyTextColor, isBold: true),
],
),
@ -176,8 +176,8 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
children: [
LocaleKeys.gender.tr().toText16(color: AppColors.textColor, isBold: true),
(appState.isArabic()
? (bloodDonationVM.selectedGender?.typeAr ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedGender?.type ?? LocaleKeys.select.tr(context: context))
? (bloodDonationVM.selectedGender?.typeAr ?? LocaleKeys.selectBloodDonationGender.tr())
: bloodDonationVM.selectedGender?.type ?? LocaleKeys.selectBloodDonationGender.tr(context: context))
.toText14(color: AppColors.greyTextColor, isBold: true),
],
),
@ -208,8 +208,8 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
LocaleKeys.bloodType.tr().toText16(color: AppColors.textColor, isBold: true),
// bloodDonationVM.selectedBloodType?.toText14(color: AppColors.greyTextColor, isBold: true),
(appState.isArabic()
? (bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr(context: context))
? (bloodDonationVM.selectedBloodType ?? LocaleKeys.selectBloodType.tr())
: bloodDonationVM.selectedBloodType ?? LocaleKeys.selectBloodType.tr(context: context))
.toText14(color: AppColors.greyTextColor, isBold: true)
],
),
@ -219,7 +219,7 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
],
).onPress(() {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.select.tr(context: context),
title: LocaleKeys.selectBloodGroup.tr(context: context),
isDismissible: true,
child: SelectBloodGroupWidget(isArabic: appState.isArabic(), bloodDonationViewModel: bloodDonationVM),
callBackFunc: () {});

@ -37,7 +37,12 @@ class SelectGenderWidget extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [GenderTypeEnum.values[index].name.toCamelCase.toText16(color: AppColors.textColor, isBold: true)],
children: [
(isArabic
? GenderTypeEnum.values[index].typeAr
: GenderTypeEnum.values[index].type)
.toText16(color: AppColors.textColor, isBold: true)
],
),
),
Transform.flip(
@ -52,7 +57,10 @@ class SelectGenderWidget extends StatelessWidget {
),
],
).paddingSymmetrical(16.h, 16.h).onPress(() {
bloodDonationViewModel.onGenderChange(GenderTypeEnum.values[index].name.toCamelCase);
final genderValue = isArabic
? GenderTypeEnum.values[index].typeAr
: GenderTypeEnum.values[index].type;
bloodDonationViewModel.onGenderChange(genderValue);
Navigator.of(context).pop();
}));
},

@ -907,7 +907,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
),
SizedBox(height: 36.h),
CustomButton(
text: LocaleKeys.loginToUseService.tr(),
text: LocaleKeys.loginToUseServiceLiveCare.tr(),
onPressed: () async {
await authVM.onLoginPressed();
},

@ -240,6 +240,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
],
).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0.0")
// (true)
? CustomButton(
text: LocaleKeys.confirmLiveCare.tr(context: context),
onPressed: () async {

@ -250,7 +250,10 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final service = services[index];
final serviceName = service.text ?? service.textN ?? '';
final appStateLocal = getIt.get<AppState>();
final serviceName = appStateLocal.isArabic()
? (service.textN ?? service.text ?? '')
: (service.text ?? service.textN ?? '');
final price = service.priceTotal ?? 0.0;
return RadioListTileWidget<int>(
value: service.iD ?? 0,

@ -90,7 +90,7 @@ class _EmergencyServicesPageState extends State<EmergencyServicesPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.callAmbulance.tr().toText16(isBold: true, color: AppColors.blackColor),
LocaleKeys.requestAmbulanceInEmergency.tr().toText12(color: AppColors.greyTextColor, isBold: true),
LocaleKeys.requestAmbulanceInEmergency.tr().toText12(color: AppColors.greyTextColor, isBold: true),
],
),
),

@ -92,7 +92,7 @@ class _NearestErPageState extends State<NearestErPage> {
},
);
} else {
return Center(child: Utils.getNoDataWidget(context, noDataText: "No nearest Er Around you"));
return Center(child: Utils.getNoDataWidget(context, noDataText: LocaleKeys.noNearestER.tr()));
}
}),
),

@ -146,7 +146,10 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
SizedBox(
width: 12.w,
),
Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
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),),
],
).paddingAll(16.w))
.onPress(() {
@ -172,8 +175,10 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
),
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
],
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),), ],
).paddingAll(16.w))
.onPress(() {
Navigator.of(context).push(
@ -201,8 +206,10 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
),
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
],
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),), ],
).paddingAll(16.w))
.onPress(() {
Navigator.of(context).push(

@ -26,7 +26,19 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
final TextEditingController _neckController = TextEditingController();
final TextEditingController _waistController = TextEditingController();
final TextEditingController _hipController = TextEditingController();
final List<String> _heightUnits = ['cm', 'm', 'ft', 'in'];
final Map<String, String> _heightUnits = {
'cm': LocaleKeys.cm,
'm': LocaleKeys.m,
'ft': LocaleKeys.ft,
'in': LocaleKeys.inch,
};
final Map<String, String> _genders = {
'Male': LocaleKeys.malE,
'Female': LocaleKeys.femaleGender,
};
String selectedHeightUnit = 'cm';
String selectedNeckUnit = 'in';
String selectedWaistUnit = 'in';
@ -82,6 +94,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
children: [
// === GENDER ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -95,7 +108,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.selectGender.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedGender.toText12(isBold: true, color: AppColors.textColor),
(_genders[selectedGender] ?? selectedGender).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
],
@ -105,7 +118,6 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
List<String> _genders = ["Male", "Female"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectGender.tr(context: context),
message: "",
@ -116,7 +128,8 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
shrinkWrap: true,
itemCount: _genders.length,
itemBuilder: (context, index) {
final unit = _genders[index];
final key = _genders.keys.elementAt(index);
final localeKey = _genders[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -127,7 +140,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedGender,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -140,13 +153,13 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toCamelCase.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedGender = unit;
_onInputChanged();
selectedGender = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -162,6 +175,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
);
}),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === HEIGHT ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -208,72 +222,24 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedHeightUnit.toText12(isBold: true, color: AppColors.textColor),
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
(_heightUnits[selectedHeightUnit] ?? selectedHeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down)
],
).onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: unit,
groupValue: selectedHeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
setState(() {
selectedHeightUnit = value;
});
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedHeightUnit = unit;
_onInputChanged();
});
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
_showUnitBottomSheet(context, dialogService, selectedHeightUnit, (value) {
setState(() { selectedHeightUnit = value; });
_onInputChanged();
});
}),
),
],
).paddingSymmetrical(0.w, 16.w),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === NECK ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -302,12 +268,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
hintText: '7',
hintStyle: TextStyle(color: Colors.grey),
),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
height: 1.0,
),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black87, height: 1.0),
),
)
],
@ -326,71 +287,23 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedNeckUnit.toText12(isBold: true, color: AppColors.textColor),
(_heightUnits[selectedNeckUnit] ?? selectedNeckUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down)
],
).onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: unit,
groupValue: selectedNeckUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
setState(() {
selectedNeckUnit = value;
});
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedNeckUnit = unit;
_onInputChanged();
});
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
_showUnitBottomSheet(context, dialogService, selectedNeckUnit, (value) {
setState(() { selectedNeckUnit = value; });
_onInputChanged();
});
}),
),
],
).paddingSymmetrical(0.w, 16.w),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === WAIST ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -419,12 +332,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
hintText: '30',
hintStyle: TextStyle(color: Colors.grey),
),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
height: 1.0,
),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black87, height: 1.0),
),
)
],
@ -442,72 +350,24 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedWaistUnit.toText12(isBold: true, color: AppColors.textColor),
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
(_heightUnits[selectedWaistUnit] ?? selectedWaistUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down)
],
).onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: unit,
groupValue: selectedWaistUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
setState(() {
selectedWaistUnit = value;
});
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedWaistUnit = unit;
_onInputChanged();
});
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
_showUnitBottomSheet(context, dialogService, selectedWaistUnit, (value) {
setState(() { selectedWaistUnit = value; });
_onInputChanged();
});
}),
),
],
).paddingSymmetrical(0.w, 16.w),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === HIP ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -536,12 +396,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
hintText: '0',
hintStyle: TextStyle(color: Colors.grey),
),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
height: 1.0,
),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black87, height: 1.0),
),
)
],
@ -560,66 +415,17 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedHipUnit.toText12(isBold: true, color: AppColors.textColor),
(_heightUnits[selectedHipUnit] ?? selectedHipUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down)
],
).onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: unit,
groupValue: selectedHipUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
setState(() {
selectedHipUnit = value;
});
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedHipUnit = unit;
_onInputChanged();
});
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
_showUnitBottomSheet(context, dialogService, selectedHipUnit, (value) {
setState(() { selectedHipUnit = value; });
_onInputChanged();
});
}),
),
],
@ -631,7 +437,7 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
Utils.buildSvgWithAssets(icon: AppAssets.globe, width: 18.w, height: 18.w),
SizedBox(width: 12.w),
Expanded(
child: "Estimate the total body fat based on the size.".toText12(isBold: true, color: AppColors.inputLabelTextColor),
child: LocaleKeys.bodyFatAlert.tr().toText12(isBold: true, color: AppColors.inputLabelTextColor),
),
],
).paddingSymmetrical(0.w, 16.w),
@ -640,4 +446,56 @@ class _BodyFatWidgetState extends State<BodyFatWidget> {
);
});
}
void _showUnitBottomSheet(BuildContext context, DialogService dialogService, String currentValue, Function(String) onSelected) {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final key = _heightUnits.keys.elementAt(index);
final localeKey = _heightUnits[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: key,
groupValue: currentValue,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
onSelected(value);
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
onSelected(key);
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
}
}

@ -78,7 +78,7 @@ class _BloodCholesterolWidgetState extends State<BloodCholesterolWidget> {
child: Column(
children: [
_buildInputField(
label: "MG/DL",
label: LocaleKeys.mldl.tr(),
hint: "120",
controller: _mgdlController,
focusNode: _mgdlFocus,
@ -107,7 +107,7 @@ class _BloodCholesterolWidgetState extends State<BloodCholesterolWidget> {
],
),
_buildInputField(
label: "MMOL/L",
label:LocaleKeys.mmol.tr(),
hint: "3.1",
controller: _mmolController,
focusNode: _mmolFocus,

@ -1,4 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -129,7 +131,7 @@ class _BloodSugarWidgetState extends State<BloodSugarWidget> {
),
SizedBox(width: 12.w),
Expanded(
child: "Convert blood glucose values between mg/dL and mmol/L. (1 mmol/L ≈ 18.0182 mg/dL)".toText12(
child: LocaleKeys.glucoseAlert.tr().toText12(
isBold: true,
color: AppColors.inputLabelTextColor,
),

@ -26,8 +26,31 @@ class _BMRWidgetState extends State<BMRWidget> {
final TextEditingController _heightController = TextEditingController();
final TextEditingController _weightController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
final List<String> _heightUnits = ['cm', 'm', 'ft', 'in'];
final List<String> _weightUnits = ['kg', 'lb'];
final Map<String, String> _heightUnits = {
'cm': LocaleKeys.cm,
'm': LocaleKeys.m,
'ft': LocaleKeys.ft,
'in': LocaleKeys.inch,
};
final Map<String, String> _weightUnits = {
'kg': LocaleKeys.kg,
'lb': LocaleKeys.lb,
};
final Map<String, String> _genders = {
'Male': LocaleKeys.malE,
'Female': LocaleKeys.femaleGender,
};
final Map<String, String> _activityLevels = {
'Almost Inactive (no exercise)': LocaleKeys.almostInactive,
'Lightly active': LocaleKeys.lightlyActive,
'Lightly active (1-3) days per week': LocaleKeys.lightlyActive13Days,
'Super active (very hard exercise)': LocaleKeys.superActive,
};
String selectedHeightUnit = 'cm';
String selectedWeightUnit = 'kg';
String selectedActivityLevel = 'Lightly active';
@ -90,7 +113,7 @@ class _BMRWidgetState extends State<BMRWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.selectGender.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedGender.toCamelCase.toText12(isBold: true, color: AppColors.textColor),
(_genders[selectedGender] ?? selectedGender).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
],
@ -100,8 +123,6 @@ class _BMRWidgetState extends State<BMRWidget> {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
List<String> _genders = ["Male", "Female"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectGender.tr(context: context),
message: "",
@ -112,7 +133,8 @@ class _BMRWidgetState extends State<BMRWidget> {
shrinkWrap: true,
itemCount: _genders.length,
itemBuilder: (context, index) {
final unit = _genders[index];
final key = _genders.keys.elementAt(index);
final localeKey = _genders[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -123,12 +145,11 @@ class _BMRWidgetState extends State<BMRWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedGender,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
print(value);
setState(() {
selectedGender = value;
});
@ -137,11 +158,11 @@ class _BMRWidgetState extends State<BMRWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toCamelCase.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedGender = unit;
selectedGender = key;
});
_onInputChanged();
Navigator.pop(context);
@ -243,7 +264,7 @@ class _BMRWidgetState extends State<BMRWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedHeightUnit.toText12(isBold: true, color: AppColors.textColor),
(_heightUnits[selectedHeightUnit] ?? selectedHeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
@ -260,7 +281,8 @@ class _BMRWidgetState extends State<BMRWidget> {
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
final key = _heightUnits.keys.elementAt(index);
final localeKey = _heightUnits[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -271,7 +293,7 @@ class _BMRWidgetState extends State<BMRWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedHeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -284,13 +306,13 @@ class _BMRWidgetState extends State<BMRWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedHeightUnit = unit;
_onInputChanged();
selectedHeightUnit = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -361,7 +383,7 @@ class _BMRWidgetState extends State<BMRWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedWeightUnit.toText12(isBold: true, color: AppColors.textColor),
(_weightUnits[selectedWeightUnit] ?? selectedWeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
@ -378,7 +400,8 @@ class _BMRWidgetState extends State<BMRWidget> {
shrinkWrap: true,
itemCount: _weightUnits.length,
itemBuilder: (context, index) {
final unit = _weightUnits[index];
final key = _weightUnits.keys.elementAt(index);
final localeKey = _weightUnits[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -389,7 +412,7 @@ class _BMRWidgetState extends State<BMRWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedWeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -402,13 +425,13 @@ class _BMRWidgetState extends State<BMRWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedWeightUnit = unit;
_onInputChanged();
selectedWeightUnit = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -440,7 +463,7 @@ class _BMRWidgetState extends State<BMRWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.activityLevel.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedActivityLevel.toText12(isBold: true, color: AppColors.textColor),
(_activityLevels[selectedActivityLevel] ?? selectedActivityLevel).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
],
@ -450,7 +473,6 @@ class _BMRWidgetState extends State<BMRWidget> {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
List<String> _activity = ["Almost Inactive (no exercise)", "Lightly active", "Lightly active (1-3) days per week", "Super active (very hard exercise)"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectActivityLevel.tr(context: context),
message: "",
@ -459,9 +481,10 @@ class _BMRWidgetState extends State<BMRWidget> {
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _activity.length,
itemCount: _activityLevels.length,
itemBuilder: (context, index) {
final unit = _activity[index];
final key = _activityLevels.keys.elementAt(index);
final localeKey = _activityLevels[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -472,7 +495,7 @@ class _BMRWidgetState extends State<BMRWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedActivityLevel,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -485,13 +508,13 @@ class _BMRWidgetState extends State<BMRWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toCamelCase.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedActivityLevel = unit;
_onInputChanged();
selectedActivityLevel = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),

@ -26,8 +26,31 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
final TextEditingController _heightController = TextEditingController();
final TextEditingController _weightController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
final List<String> _heightUnits = ['cm', 'm', 'ft', 'in'];
final List<String> _weightUnits = ['kg', 'lb'];
final Map<String, String> _heightUnits = {
'cm': LocaleKeys.cm,
'm': LocaleKeys.m,
'ft': LocaleKeys.ft,
'in': LocaleKeys.inch,
};
final Map<String, String> _weightUnits = {
'kg': LocaleKeys.kg,
'lb': LocaleKeys.lb,
};
final Map<String, String> _genders = {
'Male': LocaleKeys.malE,
'Female': LocaleKeys.femaleGender,
};
final Map<String, String> _activityLevels = {
'Almost Inactive (no exercise)': LocaleKeys.almostInactive,
'Lightly active': LocaleKeys.lightlyActive,
'Lightly active (1-3) days per week': LocaleKeys.lightlyActive13Days,
'Super active (very hard exercise)': LocaleKeys.superActive,
};
String selectedHeightUnit = 'cm';
String selectedWeightUnit = 'kg';
String selectedActivityLevel = 'Lightly active';
@ -69,7 +92,6 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
@override
Widget build(BuildContext context) {
DialogService dialogService = getIt<DialogService>();
AppState appState = getIt<AppState>();
return Consumer<HealthCalcualtorViewModel>(builder: (context, provider, _) {
return Container(
@ -78,6 +100,7 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
children: [
// === GENDER ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -90,8 +113,8 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Select Gender".toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedGender.toCamelCase.toText12(isBold: true, color: AppColors.textColor),
LocaleKeys.selectGender.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
(_genders[selectedGender] ?? selectedGender).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
],
@ -101,8 +124,6 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
List<String> _genders = ["Male", "Female"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectGender.tr(context: context),
message: "",
@ -113,7 +134,8 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
shrinkWrap: true,
itemCount: _genders.length,
itemBuilder: (context, index) {
final unit = _genders[index];
final key = _genders.keys.elementAt(index);
final localeKey = _genders[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -124,7 +146,7 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedGender,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -137,13 +159,13 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toCamelCase.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedGender = unit;
_onInputChanged();
selectedGender = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -159,6 +181,7 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
);
}),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === AGE ROW (unchanged) ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -196,6 +219,7 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
],
).paddingSymmetrical(0.w, 16.w),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === HEIGHT ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -242,72 +266,24 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedHeightUnit.toText12(isBold: true, color: AppColors.textColor),
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
(_heightUnits[selectedHeightUnit] ?? selectedHeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down)
],
).onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: unit,
groupValue: selectedHeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
setState(() {
selectedHeightUnit = value;
});
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedHeightUnit = unit;
_onInputChanged();
});
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
_showUnitBottomSheet(context, dialogService, _heightUnits, selectedHeightUnit, (value) {
setState(() { selectedHeightUnit = value; });
_onInputChanged();
});
}),
),
],
).paddingSymmetrical(0.w, 16.w),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === WEIGHT ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -359,73 +335,24 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedWeightUnit.toText12(isBold: true, color: AppColors.textColor),
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
(_weightUnits[selectedWeightUnit] ?? selectedWeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down)
],
).onPress(() {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _weightUnits.length,
itemBuilder: (context, index) {
final unit = _weightUnits[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: unit,
groupValue: selectedWeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
setState(() {
selectedWeightUnit = value;
});
_onInputChanged();
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedWeightUnit = unit;
_onInputChanged();
});
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
_showUnitBottomSheet(context, dialogService, _weightUnits, selectedWeightUnit, (value) {
setState(() { selectedWeightUnit = value; });
_onInputChanged();
});
}),
),
],
).paddingSymmetrical(0.w, 16.w),
Divider(height: 1, color: Color(0xFFEEEEEE)),
// === ACTIVITY LEVEL ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -439,7 +366,7 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.activityLevel.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedActivityLevel.toText12(isBold: true, color: AppColors.textColor),
(_activityLevels[selectedActivityLevel] ?? selectedActivityLevel).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
],
@ -449,7 +376,6 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
List<String> _activity = ["Almost Inactive (no exercise)", "Lightly active", "Lightly active (1-3) days per week", "Super active (very hard exercise)"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectActivityLevel.tr(context: context),
message: "",
@ -458,9 +384,10 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _activity.length,
itemCount: _activityLevels.length,
itemBuilder: (context, index) {
final unit = _activity[index];
final key = _activityLevels.keys.elementAt(index);
final localeKey = _activityLevels[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -471,7 +398,7 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedActivityLevel,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -484,13 +411,13 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toCamelCase.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedActivityLevel = unit;
_onInputChanged();
selectedActivityLevel = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -522,4 +449,56 @@ class _CaloriesWidgetState extends State<CaloriesWidget> {
);
});
}
void _showUnitBottomSheet(BuildContext context, DialogService dialogService, Map<String, String> units, String currentValue, Function(String) onSelected) {
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.unit.tr(context: context),
message: "",
child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 4.h),
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: units.length,
itemBuilder: (context, index) {
final key = units.keys.elementAt(index);
final localeKey = units[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 70,
child: Row(
spacing: 8.h,
children: [
Radio<String>(
value: key,
groupValue: currentValue,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
if (value == null) return;
onSelected(value);
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
onSelected(key);
Navigator.pop(context);
}),
),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1, color: Color(0xFFEEEEEE));
},
),
),
onOkPressed: () {},
);
}
}

@ -187,7 +187,7 @@ class _CrabsWidgetState extends State<CrabsWidget> {
Utils.buildSvgWithAssets(icon: AppAssets.globe, width: 18.w, height: 18.w),
SizedBox(width: 12.w),
Expanded(
child: "Calculate carbohydrate based protein and fat ration in calories and grams according to a pre set ratio."
child: LocaleKeys.carbsAlert.tr()
.toText12(isBold: true, color: AppColors.inputLabelTextColor),
),
],

@ -24,12 +24,24 @@ class IdealBodyWeightWidget extends StatefulWidget {
class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
final TextEditingController _heightController = TextEditingController();
final TextEditingController _weightController = TextEditingController();
final List<String> _heightUnits = ['cm', 'm', 'ft', 'in'];
final List<String> _weightUnits = ['kg', 'lb'];
final Map<String, String> _heightUnits = {
'cm': LocaleKeys.cm,
'm': LocaleKeys.m,
'ft': LocaleKeys.ft,
'in': LocaleKeys.inch,
};
final Map<String, String> _weightUnits = {
'kg': LocaleKeys.kg,
'lb': LocaleKeys.lb,
};
final Map<String, String> _bodyFrameSizes = {
'Small (fingers overlaps)': LocaleKeys.bodyFrameSmall,
'Medium (fingers touch)': LocaleKeys.bodyFrameMedium,
"Large (fingers don't touch)": LocaleKeys.bodyFrameLarge,
};
String selectedHeightUnit = 'cm';
String selectedWeightUnit = 'kg';
String selectedBodyFrameSize = 'Medium (fingers touch)';
Function(String)? onUnitSelected;
@override
void initState() {
@ -117,7 +129,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedHeightUnit.toText12(isBold: true, color: AppColors.textColor),
(_heightUnits[selectedHeightUnit] ?? selectedHeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
@ -134,7 +146,8 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
shrinkWrap: true,
itemCount: _heightUnits.length,
itemBuilder: (context, index) {
final unit = _heightUnits[index];
final key = _heightUnits.keys.elementAt(index);
final localeKey = _heightUnits[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -145,7 +158,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedHeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -153,17 +166,18 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
setState(() {
selectedHeightUnit = value;
});
_onInputChanged();
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedHeightUnit = unit;
_onInputChanged();
selectedHeightUnit = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -234,7 +248,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedWeightUnit.toText12(isBold: true, color: AppColors.textColor),
(_weightUnits[selectedWeightUnit] ?? selectedWeightUnit).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
SizedBox(width: 12.w),
@ -251,7 +265,8 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
shrinkWrap: true,
itemCount: _weightUnits.length,
itemBuilder: (context, index) {
final unit = _weightUnits[index];
final key = _weightUnits.keys.elementAt(index);
final localeKey = _weightUnits[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -262,7 +277,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedWeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -270,16 +285,18 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
setState(() {
selectedWeightUnit = value;
});
_onInputChanged();
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toUpperCase().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedWeightUnit = unit;
_onInputChanged();
selectedWeightUnit = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -311,7 +328,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
LocaleKeys.bodyFrameSize.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
selectedBodyFrameSize.toText12(isBold: true, color: AppColors.textColor),
(_bodyFrameSizes[selectedBodyFrameSize] ?? selectedBodyFrameSize).tr().toText12(isBold: true, color: AppColors.textColor),
],
),
],
@ -321,7 +338,6 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
List<String> _activity = ["Small (fingers overlaps)", "Medium (fingers touch)", "Large (fingers don't touch)"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectBodyFrameSize.tr(context: context),
message: "",
@ -330,9 +346,10 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(20.r)),
child: ListView.separated(
shrinkWrap: true,
itemCount: _activity.length,
itemCount: _bodyFrameSizes.length,
itemBuilder: (context, index) {
final unit = _activity[index];
final key = _bodyFrameSizes.keys.elementAt(index);
final localeKey = _bodyFrameSizes[key]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -343,7 +360,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
spacing: 8.h,
children: [
Radio<String>(
value: unit,
value: key,
groupValue: selectedBodyFrameSize,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@ -351,17 +368,18 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
setState(() {
selectedBodyFrameSize = value;
});
_onInputChanged();
Navigator.pop(context);
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
unit.toCamelCase.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
localeKey.tr().toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
],
).onPress(() {
setState(() {
selectedBodyFrameSize = unit;
_onInputChanged();
selectedBodyFrameSize = key;
});
_onInputChanged();
Navigator.pop(context);
}),
),
@ -383,7 +401,7 @@ class _IdealBodyWeightWidgetState extends State<IdealBodyWeightWidget> {
Utils.buildSvgWithAssets(icon: AppAssets.globe, width: 18.w, height: 18.w),
SizedBox(width: 12.w),
Expanded(
child: "Calculates the ideal body weight based on height, weight and body size.".toText12(isBold: true, color: AppColors.inputLabelTextColor),
child: LocaleKeys.ibwAlert.tr().toText12(isBold: true, color: AppColors.inputLabelTextColor),
),
],
).paddingSymmetrical(0.w, 16.w),

@ -1,4 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -80,7 +82,7 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
child: Column(
children: [
_buildInputField(
label: "MG/DL",
label: LocaleKeys.mldl.tr(),
hint: "150",
controller: _mgdlController,
focusNode: _mgdlFocus,
@ -111,7 +113,7 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
),
_buildInputField(
label: "MMOL/L",
label: LocaleKeys.mmol,
hint: "1.7",
controller: _mmolController,
focusNode: _mmolFocus,
@ -134,7 +136,7 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
SizedBox(width: 12.w),
Expanded(
child:
"Convert triglyceride values between mg/dL and mmol/L."
LocaleKeys.triglycerideInfo.tr()
.toText12(
isBold: true,
color: AppColors.inputLabelTextColor,

@ -105,51 +105,51 @@ class _ServicesPageState extends State<ServicesPage> {
);
}
}),
HmgServicesComponentModel(
11,
LocaleKeys.indoorNavigation.tr(),
"",
AppAssets.indoor_nav_icon,
bgColor: Color(0xff45A2F8),
true,
route: null,
onTap: () {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.selectHospital.tr(),
GetIt.instance<NavigationService>().navigatorKey.currentContext!,
child: ChangeNotifierProvider(
create: (context) => HospitalSelectionBottomSheetViewModel(getIt()),
child: Consumer<HospitalSelectionBottomSheetViewModel>(
builder: (_, vm, __) => HospitalBottomSheetBody(
searchText: vm.searchController,
displayList: vm.displayList,
onFacilityClicked: (value) {
vm.setSelectedFacility(value);
vm.getDisplayList();
},
onHospitalClicked: (hospital) {
Navigator.pop(GetIt.instance<NavigationService>().navigatorKey.currentContext!);
vm.openPenguin(hospital);
},
onHospitalSearch: (value) {
vm.searchHospitals(value ?? "");
},
selectedFacility: vm.selectedFacility,
hmcCount: vm.hmcCount,
hmgCount: vm.hmgCount,
),
),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {
GetIt.instance<NavigationService>().navigatorKey.currentContext!.read<EmergencyServicesViewModel>().clearSearchText();
},
);
},
),
// HmgServicesComponentModel(
// 11,
// LocaleKeys.indoorNavigation.tr(),
// "",
// AppAssets.indoor_nav_icon,
// bgColor: Color(0xff45A2F8),
// true,
// route: null,
// onTap: () {
// showCommonBottomSheetWithoutHeight(
// title: LocaleKeys.selectHospital.tr(),
// GetIt.instance<NavigationService>().navigatorKey.currentContext!,
// child: ChangeNotifierProvider(
// create: (context) => HospitalSelectionBottomSheetViewModel(getIt()),
// child: Consumer<HospitalSelectionBottomSheetViewModel>(
// builder: (_, vm, __) => HospitalBottomSheetBody(
// searchText: vm.searchController,
// displayList: vm.displayList,
// onFacilityClicked: (value) {
// vm.setSelectedFacility(value);
// vm.getDisplayList();
// },
// onHospitalClicked: (hospital) {
// Navigator.pop(GetIt.instance<NavigationService>().navigatorKey.currentContext!);
// vm.openPenguin(hospital);
// },
// onHospitalSearch: (value) {
// vm.searchHospitals(value ?? "");
// },
// selectedFacility: vm.selectedFacility,
// hmcCount: vm.hmcCount,
// hmgCount: vm.hmgCount,
// ),
// ),
// ),
// isFullScreen: false,
// isCloseButtonVisible: true,
// hasBottomPadding: false,
// backgroundColor: AppColors.bottomSheetBgColor,
// callBackFunc: () {
// GetIt.instance<NavigationService>().navigatorKey.currentContext!.read<EmergencyServicesViewModel>().clearSearchText();
// },
// );
// },
// ),
HmgServicesComponentModel(11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.eReferralPage);

@ -27,6 +27,7 @@ import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
@ -59,6 +60,7 @@ import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_ca
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/medical_report_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';
import 'package:hmg_patient_app_new/presentation/monthly_report/monthly_report.dart';
@ -132,6 +134,8 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
medicalFileViewModel.setIsPatientSickLeaveListLoading(true);
medicalFileViewModel.getPatientSickLeaveList();
medicalFileViewModel.onTabChanged(0);
medicalFileViewModel.setIsPatientMedicalReportsLoading(true);
medicalFileViewModel.getPatientMedicalReportList();
// Load vital signs
hmgServicesViewModel.getPatientVitalSign();
}
@ -1285,65 +1289,78 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
).paddingSymmetrical(0.w, 0.h);
}),
SizedBox(height: 16.h),
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.h,
mainAxisSpacing: 16.w,
mainAxisExtent: 110.h,
),
physics: NeverScrollableScrollPhysics(),
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.medicalReports.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.medical_reports_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() {
medicalFileViewModel.setIsPatientMedicalReportsLoading(true);
medicalFileViewModel.getPatientMedicalReportList();
Navigator.of(context).push(
CustomPageRoute(
page: MedicalReportsPage(),
),
);
}),
// MedicalFileCard(
// label: LocaleKeys.sickLeaveReport.tr(context: context),
// textColor: AppColors.blackColor,
// backgroundColor: AppColors.whiteColor,
// svgIcon: AppAssets.sick_leave_report_icon,
// isLargeText: true,
// iconSize: 36.h,
// ).onPress(() {
// Navigator.of(context).push(
// CustomPageRoute(
// page: PatientSickleavesListPage(),
// ),
// );
// }),
],
).paddingSymmetrical(0.w, 0.0),
SizedBox(height: 24.h),
Selector<MedicalFileViewModel,({bool isLoading, List<PatientMedicalReportResponseModel> listRequest, List<PatientMedicalReportResponseModel> listReady})>(
selector: (context, vm) => (isLoading: vm.isPatientMedicalReportsListLoading, listRequest: vm.patientMedicalReportRequestedList, listReady: vm.patientMedicalReportReadyList),
builder: (context, data, _){
print("isloading are ${data.isLoading}");
print("listRequest are ${data.listRequest}");
print("listReady are ${data.listReady}");
return MedicalReportCard(
isLoading: data.isLoading, listRequest: data.listRequest, listReady: data.listReady
);
},
)
// GridView(
// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 3,
// crossAxisSpacing: 10.h,
// mainAxisSpacing: 16.w,
// mainAxisExtent: 110.h,
// ),
// physics: NeverScrollableScrollPhysics(),
// 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(),
// // ),
// // );
// // }),
// ///todo te changes of the medical report should be displayed here.
// ///
//
// // MedicalFileCard(
// // label: LocaleKeys.medicalReports.tr(context: context),
// // textColor: AppColors.blackColor,
// // backgroundColor: AppColors.whiteColor,
// // svgIcon: AppAssets.medical_reports_icon,
// // isLargeText: true,
// // iconSize: 36.w,
// // ).onPress(() {
// //
// // Navigator.of(context).push(
// // CustomPageRoute(
// // page: MedicalReportsPage(),
// // ),
// // );
// // }),
// // MedicalFileCard(
// // label: LocaleKeys.sickLeaveReport.tr(context: context),
// // textColor: AppColors.blackColor,
// // backgroundColor: AppColors.whiteColor,
// // svgIcon: AppAssets.sick_leave_report_icon,
// // isLargeText: true,
// // iconSize: 36.h,
// // ).onPress(() {
// // Navigator.of(context).push(
// // CustomPageRoute(
// // page: PatientSickleavesListPage(),
// // ),
// // );
// // }),
// ],
// ).paddingSymmetrical(0.w, 0.0),
,SizedBox(height: 24.h),
],
);
case 3:

@ -0,0 +1,101 @@
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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/medical_report/medical_reports_page.dart';
import 'package:hmg_patient_app_new/presentation/monthly_report/monthly_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class MedicalReportCard extends StatelessWidget {
final bool isLoading;
final List<PatientMedicalReportResponseModel> listRequest;
final List<PatientMedicalReportResponseModel> listReady;
final VoidCallback? onViewDetails;
const MedicalReportCard({
super.key,
required this.isLoading,
required this.listRequest,
required this.listReady,
this.onViewDetails,
});
@override
Widget build(BuildContext context) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.medicalReport.tr().toText18(
isBold: true,
weight: FontWeight.w700,
).toShimmer2(isShow: isLoading),
SizedBox(height: 12.h),
Wrap(
spacing: 8.w,
runSpacing: 8.h,
children: [
if ( listRequest.isNotEmpty )
AppCustomChipWidget(
labelText: '${listRequest.length.toString().padLeft(2, '0')} ${LocaleKeys.requested.tr()}',
icon: AppAssets.document,
iconColor: AppColors.alertColor,
textColor: AppColors.alertColor,
backgroundColor: AppColors.warningColorYellow.withOpacity(.2),
iconSize: 14.w,
),
if (listReady.isNotEmpty)
AppCustomChipWidget(
labelText: '${listRequest.length.toString().padLeft(2, '0')} ${LocaleKeys.readyToDownload.tr()}',
icon: AppAssets.sucess,
iconColor: AppColors.successColor,
textColor: AppColors.successColor,
backgroundColor: AppColors.switchBackgroundColor,
iconSize: 14.w,
),
],
).toShimmer2(isShow: isLoading),
SizedBox(height: 16.h),
CustomButton(
text: LocaleKeys.viewDetails.tr(),
icon: AppAssets.report,
borderWidth: 0,
isDisabled: false,
onPressed: (){
Navigator.of(context).push(
CustomPageRoute(
page: MedicalReportsPage(),
),
);
},
backgroundColor: AppColors.lightRedButtonColor,
borderColor: AppColors.lightRedButtonColor,
textColor: AppColors.primaryRedColor,
iconColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
height: 48.h,
).toShimmer2(isShow: isLoading),
],
),
),
);
}
}

@ -59,7 +59,7 @@ class PrescriptionItemView extends StatelessWidget {
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.route.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].route}",
labelText: "${LocaleKeys.routePrescription.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].route}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${LocaleKeys.frequency.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].frequency}",

@ -85,7 +85,7 @@ class SmartwatchHomePage extends StatelessWidget {
Image.asset("assets/images/png/smartwatches/apple-watch-5.jpg", width: 136.w, height: 136.h).paddingSymmetrical(24.w, 8.h),
"Apple Watch".needTranslation.toText16(isBold: true),
CustomButton(
text: LocaleKeys.select.tr(context: context),
text: LocaleKeys.selectSmartWatch.tr(context: context),
onPressed: () {
context.read<HealthProvider>().setSelectedWatchType(SmartWatchTypes.apple, "assets/images/png/smartwatches/apple-watch-5.jpg");
getIt.get<NavigationService>().pushPage(page: SmartwatchInstructionsPage(

@ -5,6 +5,7 @@ import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
@ -182,9 +183,22 @@ class _SplashScreenState extends State<SplashPage> {
}
break;
case Event.actionCallDecline:
print('actionCallConnected Event Received: ------->');
print('actionCallDecline Event Received: ------->');
// Get session ID from cache
String sessionId = await Utils.getStringFromPrefs(CacheConst.zoomRoomID);
//
// // Update session status to 3 (declined by patient)
// if (sessionId.isNotEmpty) {
await _updateSessionStatus(sessionId, 3, 'Patient');
// }
await FlutterCallkitIncoming.endAllCalls();
GetIt.instance<CacheService>().remove(key: CacheConst.isAppOpenedFromCall);
// Clear cache
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, '');
await Utils.saveStringFromPrefs(CacheConst.callTypeID, '');
break;
case Event.actionCallEnded:
break;
@ -220,20 +234,35 @@ class _SplashScreenState extends State<SplashPage> {
/// load the Privilege from service
Future loadPrivilege() async {
// ProjectViewModel projectProvider = Provider.of<ProjectViewModel>(context, listen: false);
// projectProvider.setPrivilegeModelList(privilege: _privilegeService.privilegeModelList);
// projectProvider.setVidaPlusProjectList(_privilegeService.vidaPlusProjectListModel);
// projectProvider.setHMCProjectList(_privilegeService.hMCProjectListModel);
// projectProvider.setProjectsDetailList(_privilegeService.projectDetailListModel);
// double lat = await AppSharedPreferences().getDouble(USER_LAT) ?? 0.0;
// double long = await AppSharedPreferences().getDouble(USER_LONG) ?? 0.0;
// AppSharedPreferences().clear(); // Clearing Shared Preferences On App Launch
// await AppSharedPreferences().setDouble(USER_LAT, lat);
// await AppSharedPreferences().setDouble(USER_LONG, long);
// AppSharedPreferences().setString(APP_LANGUAGE, projectProvider.isArabic ? "ar" : "en");
// var themeNotifier = Provider.of<ThemeNotifier>(context, listen: false);
// themeNotifier.setTheme(defaultTheme(fontName: projectProvider.isArabic ? 'Cairo' : 'Poppins'));
// PushNotificationHandler().init(context); // Asyncronously
// ...existing code...
}
/// Update session status when call is declined
Future<void> _updateSessionStatus(String sessionId, int sessionStatus, String sessionEndedBy) async {
try {
print('📡 Updating session status - SessionID: $sessionId, Status: $sessionStatus, EndedBy: $sessionEndedBy');
final apiClient = getIt.get<ApiClient>();
String sessionID = await Utils.getStringFromPrefs(CacheConst.zoomRoomID);
Map<String, dynamic> requestBody = {
"Open_SessionID": sessionID,
"SessionStatus": sessionStatus,
"SessionEndedBy": sessionEndedBy
};
await apiClient.post(
CHANGE_PATIENT_ER_SESSION,
body: requestBody,
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
print('✅ Session status updated successfully: $response');
},
onFailure: (error, statusCode, {messageStatus, failureType}) {
print('❌ Failed to update session status: $error');
},
);
} catch (e) {
print('❌ Exception updating session status: $e');
}
}
@override

Loading…
Cancel
Save