diff --git a/assets/images/svg/document.svg b/assets/images/svg/document.svg
new file mode 100644
index 00000000..5073ead5
--- /dev/null
+++ b/assets/images/svg/document.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/report.svg b/assets/images/svg/report.svg
new file mode 100644
index 00000000..b5ca54b1
--- /dev/null
+++ b/assets/images/svg/report.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/svg/sucess.svg b/assets/images/svg/sucess.svg
new file mode 100644
index 00000000..6df93d5e
--- /dev/null
+++ b/assets/images/svg/sucess.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index 11732dea..72199078 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -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": "اختر الفصيلة"
}
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index 5c0d89be..27373b5f 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -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",
diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart
index 374ac9d1..3c71281c 100644
--- a/lib/core/api/api_client.dart
+++ b/lib/core/api/api_client.dart
@@ -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;
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index 819691be..ff39fa70 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -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";
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index c3811a94..107e06d1 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -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';
diff --git a/lib/core/enums.dart b/lib/core/enums.dart
index 2d42a2ae..4ac919e7 100644
--- a/lib/core/enums.dart
+++ b/lib/core/enums.dart
@@ -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();
+ 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) {
diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart
index 770961de..c82c608d 100644
--- a/lib/core/utils/push_notification_handler.dart
+++ b/lib/core/utils/push_notification_handler.dart
@@ -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 backgroundMessageHandler(dynamic message) async {
@@ -39,34 +49,36 @@ callPage(String sessionID, String token) async {}
_incomingCall(Map 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().saveString(key: CacheConst.zoomRoomID, value: roomID);
- // GetIt.instance().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 data) async {
duration: 30000,
extra: {
'userId': '1a2b3c4d',
- 'callTypeID': callTypeID, // Store actual callTypeID here
- 'roomID': roomID, // Store roomID here for backup
+ 'callTypeID': callTypeID,
+ 'roomID': roomID,
},
headers: {'apiKey': 'Abc@123!', 'platform': 'flutter'},
android: const AndroidParams(
@@ -96,10 +108,10 @@ _incomingCall(Map 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 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 _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 _updateSessionStatus(String sessionId, int sessionStatus, String sessionEndedBy) async {
+ try {
+
+ final apiClient = getIt.get();
+
+ Map 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 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();
});
diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart
index 0f09f1e9..c374b3e2 100644
--- a/lib/features/prescriptions/prescriptions_view_model.dart
+++ b/lib/features/prescriptions/prescriptions_view_model.dart
@@ -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);
diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart
index ea55f341..22cca7e4 100644
--- a/lib/generated/locale_keys.g.dart
+++ b/lib/generated/locale_keys.g.dart
@@ -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';
diff --git a/lib/presentation/blood_donation/blood_donation_page.dart b/lib/presentation/blood_donation/blood_donation_page.dart
index c6767c2d..b706d2cd 100644
--- a/lib/presentation/blood_donation/blood_donation_page.dart
+++ b/lib/presentation/blood_donation/blood_donation_page.dart
@@ -148,8 +148,8 @@ class _BloodDonationPageState extends State {
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 {
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 {
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 {
],
).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: () {});
diff --git a/lib/presentation/blood_donation/widgets/select_gender_widget.dart b/lib/presentation/blood_donation/widgets/select_gender_widget.dart
index 0d360a80..1368c4e3 100644
--- a/lib/presentation/blood_donation/widgets/select_gender_widget.dart
+++ b/lib/presentation/blood_donation/widgets/select_gender_widget.dart
@@ -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();
}));
},
diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart
index d0ef2a4f..15b019e9 100644
--- a/lib/presentation/book_appointment/book_appointment_page.dart
+++ b/lib/presentation/book_appointment/book_appointment_page.dart
@@ -907,7 +907,7 @@ class _BookAppointmentPageState extends State {
),
SizedBox(height: 36.h),
CustomButton(
- text: LocaleKeys.loginToUseService.tr(),
+ text: LocaleKeys.loginToUseServiceLiveCare.tr(),
onPressed: () async {
await authVM.onLoginPressed();
},
diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
index 1228e1e4..b3801113 100644
--- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
+++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
@@ -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 {
diff --git a/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart b/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart
index 589764c1..0761ab6c 100644
--- a/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart
+++ b/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart
@@ -250,7 +250,10 @@ class _ComprehensiveCheckupPageState extends State {
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final service = services[index];
- final serviceName = service.text ?? service.textN ?? '';
+ final appStateLocal = getIt.get();
+ final serviceName = appStateLocal.isArabic()
+ ? (service.textN ?? service.text ?? '')
+ : (service.text ?? service.textN ?? '');
final price = service.priceTotal ?? 0.0;
return RadioListTileWidget(
value: service.iD ?? 0,
diff --git a/lib/presentation/emergency_services/emergency_services_page.dart b/lib/presentation/emergency_services/emergency_services_page.dart
index 3d5470a8..2d4ef828 100644
--- a/lib/presentation/emergency_services/emergency_services_page.dart
+++ b/lib/presentation/emergency_services/emergency_services_page.dart
@@ -90,7 +90,7 @@ class _EmergencyServicesPageState extends State {
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),
],
),
),
diff --git a/lib/presentation/emergency_services/nearest_er_page.dart b/lib/presentation/emergency_services/nearest_er_page.dart
index ea9a1517..97e601d5 100644
--- a/lib/presentation/emergency_services/nearest_er_page.dart
+++ b/lib/presentation/emergency_services/nearest_er_page.dart
@@ -92,7 +92,7 @@ class _NearestErPageState extends State {
},
);
} else {
- return Center(child: Utils.getNoDataWidget(context, noDataText: "No nearest Er Around you"));
+ return Center(child: Utils.getNoDataWidget(context, noDataText: LocaleKeys.noNearestER.tr()));
}
}),
),
diff --git a/lib/presentation/health_calculators_and_converts/health_calculators_page.dart b/lib/presentation/health_calculators_and_converts/health_calculators_page.dart
index a7fe0ef5..8b351ecf 100644
--- a/lib/presentation/health_calculators_and_converts/health_calculators_page.dart
+++ b/lib/presentation/health_calculators_and_converts/health_calculators_page.dart
@@ -146,7 +146,10 @@ class _HealthCalculatorsPageState extends State {
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().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 {
),
),
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().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 {
),
),
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().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(
diff --git a/lib/presentation/health_calculators_and_converts/widgets/bf.dart b/lib/presentation/health_calculators_and_converts/widgets/bf.dart
index d71566a2..a2d804b0 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/bf.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/bf.dart
@@ -26,7 +26,19 @@ class _BodyFatWidgetState extends State {
final TextEditingController _neckController = TextEditingController();
final TextEditingController _waistController = TextEditingController();
final TextEditingController _hipController = TextEditingController();
- final List _heightUnits = ['cm', 'm', 'ft', 'in'];
+
+ final Map _heightUnits = {
+ 'cm': LocaleKeys.cm,
+ 'm': LocaleKeys.m,
+ 'ft': LocaleKeys.ft,
+ 'in': LocaleKeys.inch,
+ };
+
+ final Map _genders = {
+ 'Male': LocaleKeys.malE,
+ 'Female': LocaleKeys.femaleGender,
+ };
+
String selectedHeightUnit = 'cm';
String selectedNeckUnit = 'in';
String selectedWaistUnit = 'in';
@@ -82,6 +94,7 @@ class _BodyFatWidgetState extends State {
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 {
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 {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
- List _genders = ["Male", "Female"];
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectGender.tr(context: context),
message: "",
@@ -116,7 +128,8 @@ class _BodyFatWidgetState extends State {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedGender,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -140,13 +153,13 @@ class _BodyFatWidgetState extends State {
},
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 {
);
}),
Divider(height: 1, color: Color(0xFFEEEEEE)),
+ // === HEIGHT ROW ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@@ -208,72 +222,24 @@ class _BodyFatWidgetState extends State {
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(
- 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 {
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 {
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(
- 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 {
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 {
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(
- 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 {
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 {
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(
- 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 {
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 {
);
});
}
+
+ 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(
+ 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: () {},
+ );
+ }
}
diff --git a/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart b/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart
index d24463bf..14b956e0 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart
@@ -78,7 +78,7 @@ class _BloodCholesterolWidgetState extends State {
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 {
],
),
_buildInputField(
- label: "MMOL/L",
+ label:LocaleKeys.mmol.tr(),
hint: "3.1",
controller: _mmolController,
focusNode: _mmolFocus,
diff --git a/lib/presentation/health_calculators_and_converts/widgets/blood_sugar.dart b/lib/presentation/health_calculators_and_converts/widgets/blood_sugar.dart
index f2110646..670236de 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/blood_sugar.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/blood_sugar.dart
@@ -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 {
),
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,
),
diff --git a/lib/presentation/health_calculators_and_converts/widgets/bmr.dart b/lib/presentation/health_calculators_and_converts/widgets/bmr.dart
index 003faf06..2b013549 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/bmr.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/bmr.dart
@@ -26,8 +26,31 @@ class _BMRWidgetState extends State {
final TextEditingController _heightController = TextEditingController();
final TextEditingController _weightController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
- final List _heightUnits = ['cm', 'm', 'ft', 'in'];
- final List _weightUnits = ['kg', 'lb'];
+
+ final Map _heightUnits = {
+ 'cm': LocaleKeys.cm,
+ 'm': LocaleKeys.m,
+ 'ft': LocaleKeys.ft,
+ 'in': LocaleKeys.inch,
+ };
+
+ final Map _weightUnits = {
+ 'kg': LocaleKeys.kg,
+ 'lb': LocaleKeys.lb,
+ };
+
+ final Map _genders = {
+ 'Male': LocaleKeys.malE,
+ 'Female': LocaleKeys.femaleGender,
+ };
+
+ final Map _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 {
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 {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
- List _genders = ["Male", "Female"];
-
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectGender.tr(context: context),
message: "",
@@ -112,7 +133,8 @@ class _BMRWidgetState extends State {
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 {
spacing: 8.h,
children: [
Radio(
- 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 {
},
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 {
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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedHeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -284,13 +306,13 @@ class _BMRWidgetState extends State {
},
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 {
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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedWeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -402,13 +425,13 @@ class _BMRWidgetState extends State {
},
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 {
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 {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
- List _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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedActivityLevel,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -485,13 +508,13 @@ class _BMRWidgetState extends State {
},
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);
}),
),
diff --git a/lib/presentation/health_calculators_and_converts/widgets/calories.dart b/lib/presentation/health_calculators_and_converts/widgets/calories.dart
index d354ce8e..ad31cd6c 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/calories.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/calories.dart
@@ -26,8 +26,31 @@ class _CaloriesWidgetState extends State {
final TextEditingController _heightController = TextEditingController();
final TextEditingController _weightController = TextEditingController();
final TextEditingController _ageController = TextEditingController();
- final List _heightUnits = ['cm', 'm', 'ft', 'in'];
- final List _weightUnits = ['kg', 'lb'];
+
+ final Map _heightUnits = {
+ 'cm': LocaleKeys.cm,
+ 'm': LocaleKeys.m,
+ 'ft': LocaleKeys.ft,
+ 'in': LocaleKeys.inch,
+ };
+
+ final Map _weightUnits = {
+ 'kg': LocaleKeys.kg,
+ 'lb': LocaleKeys.lb,
+ };
+
+ final Map _genders = {
+ 'Male': LocaleKeys.malE,
+ 'Female': LocaleKeys.femaleGender,
+ };
+
+ final Map _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 {
@override
Widget build(BuildContext context) {
DialogService dialogService = getIt();
- AppState appState = getIt();
return Consumer(builder: (context, provider, _) {
return Container(
@@ -78,6 +100,7 @@ class _CaloriesWidgetState extends State {
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 {
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 {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
- List _genders = ["Male", "Female"];
-
dialogService.showFamilyBottomSheetWithoutHWithChild(
label: LocaleKeys.selectGender.tr(context: context),
message: "",
@@ -113,7 +134,8 @@ class _CaloriesWidgetState extends State {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedGender,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -137,13 +159,13 @@ class _CaloriesWidgetState extends State {
},
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 {
);
}),
Divider(height: 1, color: Color(0xFFEEEEEE)),
+ // === AGE ROW (unchanged) ===
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@@ -196,6 +219,7 @@ class _CaloriesWidgetState extends State {
],
).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 {
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(
- 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 {
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(
- 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 {
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 {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
- List _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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedActivityLevel,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -484,13 +411,13 @@ class _CaloriesWidgetState extends State {
},
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 {
);
});
}
+
+ void _showUnitBottomSheet(BuildContext context, DialogService dialogService, Map 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(
+ 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: () {},
+ );
+ }
}
diff --git a/lib/presentation/health_calculators_and_converts/widgets/crabs.dart b/lib/presentation/health_calculators_and_converts/widgets/crabs.dart
index e3e7c1e3..8a2f6343 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/crabs.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/crabs.dart
@@ -187,7 +187,7 @@ class _CrabsWidgetState extends State {
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),
),
],
diff --git a/lib/presentation/health_calculators_and_converts/widgets/ibw.dart b/lib/presentation/health_calculators_and_converts/widgets/ibw.dart
index 070e373e..f9d7e964 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/ibw.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/ibw.dart
@@ -24,12 +24,24 @@ class IdealBodyWeightWidget extends StatefulWidget {
class _IdealBodyWeightWidgetState extends State {
final TextEditingController _heightController = TextEditingController();
final TextEditingController _weightController = TextEditingController();
- final List _heightUnits = ['cm', 'm', 'ft', 'in'];
- final List _weightUnits = ['kg', 'lb'];
+ final Map _heightUnits = {
+ 'cm': LocaleKeys.cm,
+ 'm': LocaleKeys.m,
+ 'ft': LocaleKeys.ft,
+ 'in': LocaleKeys.inch,
+ };
+ final Map _weightUnits = {
+ 'kg': LocaleKeys.kg,
+ 'lb': LocaleKeys.lb,
+ };
+ final Map _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 {
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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedHeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -153,17 +166,18 @@ class _IdealBodyWeightWidgetState extends State {
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 {
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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedWeightUnit,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -270,16 +285,18 @@ class _IdealBodyWeightWidgetState extends State {
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 {
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 {
SizedBox(width: 4.w),
],
).paddingSymmetrical(0.w, 16.w).onPress(() {
- List _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 {
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 {
spacing: 8.h,
children: [
Radio(
- value: unit,
+ value: key,
groupValue: selectedBodyFrameSize,
activeColor: AppColors.errorColor,
onChanged: (String? value) {
@@ -351,17 +368,18 @@ class _IdealBodyWeightWidgetState extends State {
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 {
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),
diff --git a/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart b/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart
index b61eaaed..dd5eb0f0 100644
--- a/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart
+++ b/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart
@@ -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 {
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 {
),
_buildInputField(
- label: "MMOL/L",
+ label: LocaleKeys.mmol,
hint: "1.7",
controller: _mmolController,
focusNode: _mmolFocus,
@@ -134,7 +136,7 @@ class _TriglyceridesWidgetState extends State {
SizedBox(width: 12.w),
Expanded(
child:
- "Convert triglyceride values between mg/dL and mmol/L."
+ LocaleKeys.triglycerideInfo.tr()
.toText12(
isBold: true,
color: AppColors.inputLabelTextColor,
diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart
index 734401fe..af6672ea 100644
--- a/lib/presentation/hmg_services/services_page.dart
+++ b/lib/presentation/hmg_services/services_page.dart
@@ -105,51 +105,51 @@ class _ServicesPageState extends State {
);
}
}),
- HmgServicesComponentModel(
- 11,
- LocaleKeys.indoorNavigation.tr(),
- "",
- AppAssets.indoor_nav_icon,
- bgColor: Color(0xff45A2F8),
- true,
- route: null,
- onTap: () {
- showCommonBottomSheetWithoutHeight(
- title: LocaleKeys.selectHospital.tr(),
- GetIt.instance().navigatorKey.currentContext!,
- child: ChangeNotifierProvider(
- create: (context) => HospitalSelectionBottomSheetViewModel(getIt()),
- child: Consumer(
- builder: (_, vm, __) => HospitalBottomSheetBody(
- searchText: vm.searchController,
- displayList: vm.displayList,
- onFacilityClicked: (value) {
- vm.setSelectedFacility(value);
- vm.getDisplayList();
- },
- onHospitalClicked: (hospital) {
- Navigator.pop(GetIt.instance().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().navigatorKey.currentContext!.read().clearSearchText();
- },
- );
- },
- ),
+ // HmgServicesComponentModel(
+ // 11,
+ // LocaleKeys.indoorNavigation.tr(),
+ // "",
+ // AppAssets.indoor_nav_icon,
+ // bgColor: Color(0xff45A2F8),
+ // true,
+ // route: null,
+ // onTap: () {
+ // showCommonBottomSheetWithoutHeight(
+ // title: LocaleKeys.selectHospital.tr(),
+ // GetIt.instance().navigatorKey.currentContext!,
+ // child: ChangeNotifierProvider(
+ // create: (context) => HospitalSelectionBottomSheetViewModel(getIt()),
+ // child: Consumer(
+ // builder: (_, vm, __) => HospitalBottomSheetBody(
+ // searchText: vm.searchController,
+ // displayList: vm.displayList,
+ // onFacilityClicked: (value) {
+ // vm.setSelectedFacility(value);
+ // vm.getDisplayList();
+ // },
+ // onHospitalClicked: (hospital) {
+ // Navigator.pop(GetIt.instance().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().navigatorKey.currentContext!.read().clearSearchText();
+ // },
+ // );
+ // },
+ // ),
HmgServicesComponentModel(11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async {
if (getIt.get().isAuthenticated) {
getIt.get().pushPageRoute(AppRoutes.eReferralPage);
diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart
index ab8ca725..9d8c6cc1 100644
--- a/lib/presentation/medical_file/medical_file_page.dart
+++ b/lib/presentation/medical_file/medical_file_page.dart
@@ -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 {
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 {
).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 listRequest, List 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:
diff --git a/lib/presentation/medical_file/widgets/medical_report_card.dart b/lib/presentation/medical_file/widgets/medical_report_card.dart
new file mode 100644
index 00000000..4759a65b
--- /dev/null
+++ b/lib/presentation/medical_file/widgets/medical_report_card.dart
@@ -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 listRequest;
+ final List 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),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/prescriptions/prescription_item_view.dart b/lib/presentation/prescriptions/prescription_item_view.dart
index 086b3f83..66ba13ed 100644
--- a/lib/presentation/prescriptions/prescription_item_view.dart
+++ b/lib/presentation/prescriptions/prescription_item_view.dart
@@ -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}",
diff --git a/lib/presentation/smartwatches/smartwatch_home_page.dart b/lib/presentation/smartwatches/smartwatch_home_page.dart
index b6c98ee9..53e562e6 100644
--- a/lib/presentation/smartwatches/smartwatch_home_page.dart
+++ b/lib/presentation/smartwatches/smartwatch_home_page.dart
@@ -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().setSelectedWatchType(SmartWatchTypes.apple, "assets/images/png/smartwatches/apple-watch-5.jpg");
getIt.get().pushPage(page: SmartwatchInstructionsPage(
diff --git a/lib/splashPage.dart b/lib/splashPage.dart
index c7be036f..7fe97e6f 100644
--- a/lib/splashPage.dart
+++ b/lib/splashPage.dart
@@ -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 {
}
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().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 {
/// load the Privilege from service
Future loadPrivilege() async {
- // ProjectViewModel projectProvider = Provider.of(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(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 _updateSessionStatus(String sessionId, int sessionStatus, String sessionEndedBy) async {
+ try {
+ print('📡 Updating session status - SessionID: $sessionId, Status: $sessionStatus, EndedBy: $sessionEndedBy');
+
+ final apiClient = getIt.get();
+ String sessionID = await Utils.getStringFromPrefs(CacheConst.zoomRoomID);
+ Map 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