diff --git a/README.md b/README.md index 1a459e3..3fea310 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +# Translation prompt & Command + +Read the context for both files & generate translations strings in the en-US.json & ar-SA.json files for the strings containing "needTranslation". Also replace the strings in the dart with the generated Strings. Also do not remove existing properties & do no generate duplicate strings in the json files + +flutter3_32 pub run easy_localization:generate -O ./lib/generated -f keys -o locale_keys.g.dart --source-dir ./assets/langs + + + # HMG Patient App A comprehensive Flutter-based mobile application for HMG (Habib Medical Group) patients, diff --git a/assets/images/svg/ar_lang_icon.svg b/assets/images/svg/ar_lang_icon.svg new file mode 100644 index 0000000..d1c2be0 --- /dev/null +++ b/assets/images/svg/ar_lang_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/colored_dots_icon.svg b/assets/images/svg/colored_dots_icon.svg new file mode 100644 index 0000000..7f05dc5 --- /dev/null +++ b/assets/images/svg/colored_dots_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svg/en_lang_icon.svg b/assets/images/svg/en_lang_icon.svg new file mode 100644 index 0000000..fa1c143 --- /dev/null +++ b/assets/images/svg/en_lang_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 9c1c962..3ceb2e9 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1377,6 +1377,18 @@ "suggestions": "الاقتراحات", "pleaseGoBackAndSelectOrgansFirst": "يرجى العودة واختيار الأعضاء أولاً", "symptomsSelector": "محدد الأعراض", + "possibleSymptomsRelatedTo": "الأعراض المحتملة المتعلقة بـ", + "suggestionAIListDescription": "هذه قائمة بالأعراض المقترحة من قبل الذكاء الاصطناعي، بناءً على المعلومات التي تم جمعها حتى الآن خلال المقابلة", + "analyzing": "جاري التحليل...", + "seekMedicalAdvice": "اطلب المشورة الطبية", + "monitorDescription": "لا حاجة لطلب المشورة الطبية. فقط حافظ على روتين صحي.", + "seekMedicalAdviceDescription": "ليست حالة طوارئ ولكن من الأفضل مراقبة الأعراض.", + "emergencyDescription": "تحتاج إلى استشارة الطبيب في أقرب وقت ممكن قبل فوات الأوان.", + "colorScience": "دلالات الألوان", + "noNeedToVisitDoctor": "لا حاجة لزي��رة الطبيب", + "commonSymptom": "الأعراض الشائعة", + "bookAppointment": "احجز موعد", + "notApplicable": "لا ينطبق", "emergencyTriage": "طوارئ", "emergencyEvidenceDetected": "تم اكتشاف دليل طوارئ. يرجى طلب العناية الطبية.", "noQuestionItemsAvailable": "لا توجد عناصر أسئلة متاحة", @@ -1499,5 +1511,20 @@ "selectTime": "حدد الوقت", "pleaseWaitYouWillBeCalledForVitalSigns": "يرجى الانتظار! سيتم استدعاؤك لقياس العلامات الحيوية", "pleaseVisitRoomForVitalSigns": "يرجى زيارة الغرفة {roomNumber} لقياس العلامات الحيوية", - "pleaseVisitRoomToTheDoctor": "يرجى زيارة الغرفة {roomNumber} لمقابلة الطبيب" + "pleaseVisitRoomToTheDoctor": "يرجى زيارة الغرفة {roomNumber} لمقابلة الطبيب", + "erOnlineCheckInRequest": "طلب تسجيل الوصول عبر الإنترنت لقسم الطوارئ", + "indoor": "داخلي", + "navigation": "الملاحة", + "health": "الصحة", + "calculators": "الحاسبات", + "converters": "المحولات", + "guide": "الدليل", + "liveCareServiceDesc": "احصل على استشارة طبية من طبيب متخصص عبر مكالمة فيديو", + "bloodGroup": "فصيلة الدم: {bloodType}", + "medicalServices": "الخدمات الطبية", + "insuranceAndPayments": "التأمين والمدفوعات", + "trackerAndOthers": "المتتبع وأخرى", + "bmi": "مؤشر كتلة الجسم" + + } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 5f356ba..50d4481 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1367,6 +1367,18 @@ "suggestions": "Suggestions", "pleaseGoBackAndSelectOrgansFirst": "Please go back and select organs first", "symptomsSelector": "Symptoms Selector", + "possibleSymptomsRelatedTo": "Possible symptoms related to", + "suggestionAIListDescription": "This is a list of symptoms suggested by our AI, based on the information gathered so far during the interview", + "analyzing": "Analyzing...", + "seekMedicalAdvice": "Seek Medical Advice", + "monitorDescription": "No need to seek medical advice. Just keep healthy routine.", + "seekMedicalAdviceDescription": "Not emergency but better to monitor the symptoms.", + "emergencyDescription": "Need to consult doctor as soon as possible before getting too late.", + "colorScience": "Color Science", + "noNeedToVisitDoctor": "No need to visit doctor", + "commonSymptom": "Common Symptom", + "bookAppointment": "Book Appointment", + "notApplicable": "Not Applicable", "emergencyTriage": "Emergency", "emergencyEvidenceDetected": "Emergency evidence detected. Please seek medical attention.", "noQuestionItemsAvailable": "No question items available", @@ -1490,5 +1502,20 @@ "selectTime": "Select Time", "pleaseWaitYouWillBeCalledForVitalSigns": "Please wait! you will be called for vital signs", "pleaseVisitRoomForVitalSigns": "Please visit Room {roomNumber} for vital signs", - "pleaseVisitRoomToTheDoctor": "Please visit Room {roomNumber} to the Doctor" + "pleaseVisitRoomToTheDoctor": "Please visit Room {roomNumber} to the Doctor", + "erOnlineCheckInRequest": "ER Online Check-In Request", + "indoor": "Indoor", + "navigation": "Navigation", + "health": "Health", + "calculators": "Calculators", + "converters": "Converters", + "guide": "Guide", + "liveCareServiceDesc": "Get medical advice with a specialist doctor Via a video call", + "bloodGroup": "Blood: {bloodType}", + "medicalServices": "Medical Services", + "insuranceAndPayments": "Insurance & Payments", + "trackerAndOthers": "Tracker & Others", + "bmi": "BMI" + + } diff --git a/convert_json.dart b/convert_json.dart index 08f344d..af5c594 100644 --- a/convert_json.dart +++ b/convert_json.dart @@ -1,73 +1,73 @@ -import 'dart:convert'; -import 'dart:io'; - -void main() async { - final file = File('assets/json/body_symptoms_data.json'); - final content = await file.readAsString(); - - print('File size: ${content.length} characters'); - - // Split into two parts - final parts = content.split('export const SymptomsData = ['); - if (parts.length != 2) { - print('ERROR: Could not split file properly'); - exit(1); - } - - print('Split into ${parts.length} parts'); - - // Process BodySymptomsData - var bodyPart = parts[0] - .replaceAll('export const BodySymptomsData = ', '') - .trim() - .replaceAll(RegExp(r';$'), ''); - - print('Parsing body symptoms...'); - Map bodySymptomsData; - try { - bodySymptomsData = json.decode(bodyPart); - print('✅ Body symptoms parsed: ${bodySymptomsData.length} body parts'); - } catch (e) { - print('❌ Error parsing body symptoms: $e'); - exit(1); - } - - // Process SymptomsData - print('Processing symptoms data...'); - var symptomsPart = parts[1] - .trim() - .replaceAll(RegExp(r'\];$'), '') - .replaceAllMapped(RegExp(r'\n(\s*)id:'), (m) => '\n${m.group(1)}"id":') - .replaceAllMapped(RegExp(r'\n(\s*)type:'), (m) => '\n${m.group(1)}"type":') - .replaceAllMapped(RegExp(r'\n(\s*)name:'), (m) => '\n${m.group(1)}"name":') - .replaceAllMapped(RegExp(r'\n(\s*)common_name:'), (m) => '\n${m.group(1)}"common_name":'); - - print('Parsing symptoms...'); - List symptomsData; - try { - symptomsData = json.decode('[$symptomsPart]'); - print('✅ Symptoms parsed: ${symptomsData.length} symptoms'); - } catch (e) { - print('❌ Error parsing symptoms: $e'); - print('First 1000 chars:'); - print('[$symptomsPart]'.substring(0, 1000)); - exit(1); - } - - // Create final JSON - print('Creating final JSON structure...'); - final jsonStructure = { - 'bodySymptoms': bodySymptomsData, - 'symptoms': symptomsData, - }; - - // Write to file - print('Writing to file...'); - final encoder = JsonEncoder.withIndent(' '); - await file.writeAsString(encoder.convert(jsonStructure)); - - print('\n✅ SUCCESS! File converted to proper JSON'); - print('✅ Body parts: ${bodySymptomsData.length}'); - print('✅ Symptoms: ${symptomsData.length}'); -} - +// import 'dart:convert'; +// import 'dart:io'; +// +// void main() async { +// final file = File('assets/json/body_symptoms_data.json'); +// final content = await file.readAsString(); +// +// print('File size: ${content.length} characters'); +// +// // Split into two parts +// final parts = content.split('export const SymptomsData = ['); +// if (parts.length != 2) { +// print('ERROR: Could not split file properly'); +// exit(1); +// } +// +// print('Split into ${parts.length} parts'); +// +// // Process BodySymptomsData +// var bodyPart = parts[0] +// .replaceAll('export const BodySymptomsData = ', '') +// .trim() +// .replaceAll(RegExp(r';$'), ''); +// +// print('Parsing body symptoms...'); +// Map bodySymptomsData; +// try { +// bodySymptomsData = json.decode(bodyPart); +// print('✅ Body symptoms parsed: ${bodySymptomsData.length} body parts'); +// } catch (e) { +// print('❌ Error parsing body symptoms: $e'); +// exit(1); +// } +// +// // Process SymptomsData +// print('Processing symptoms data...'); +// var symptomsPart = parts[1] +// .trim() +// .replaceAll(RegExp(r'\];$'), '') +// .replaceAllMapped(RegExp(r'\n(\s*)id:'), (m) => '\n${m.group(1)}"id":') +// .replaceAllMapped(RegExp(r'\n(\s*)type:'), (m) => '\n${m.group(1)}"type":') +// .replaceAllMapped(RegExp(r'\n(\s*)name:'), (m) => '\n${m.group(1)}"name":') +// .replaceAllMapped(RegExp(r'\n(\s*)common_name:'), (m) => '\n${m.group(1)}"common_name":'); +// +// print('Parsing symptoms...'); +// List symptomsData; +// try { +// symptomsData = json.decode('[$symptomsPart]'); +// print('✅ Symptoms parsed: ${symptomsData.length} symptoms'); +// } catch (e) { +// print('❌ Error parsing symptoms: $e'); +// print('First 1000 chars:'); +// print('[$symptomsPart]'.substring(0, 1000)); +// exit(1); +// } +// +// // Create final JSON +// print('Creating final JSON structure...'); +// final jsonStructure = { +// 'bodySymptoms': bodySymptomsData, +// 'symptoms': symptomsData, +// }; +// +// // Write to file +// print('Writing to file...'); +// final encoder = JsonEncoder.withIndent(' '); +// await file.writeAsString(encoder.convert(jsonStructure)); +// +// print('\n✅ SUCCESS! File converted to proper JSON'); +// print('✅ Body parts: ${bodySymptomsData.length}'); +// print('✅ Symptoms: ${symptomsData.length}'); +// } +// diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 722a45e..39a6177 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -189,6 +189,8 @@ class ApiClientImp implements ApiClient { // body['SessionID'] = "45786230487560q"; } + // body['IsNewFlutterApp'] = true; + body.removeWhere((key, value) => value == null); } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index de750ad..f715305 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -841,7 +841,7 @@ class ApiConsts { static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors'; static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion'; static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis'; - static final String explain = '$symptomsCheckerApi/explain'; + static final String explain = '$symptomsCheckerApi/ExplainDiagnosisResult'; //E-REFERRAL SERVICES static final getAllRelationshipTypes = "Services/Patients.svc/REST/GetAllRelationshipTypes"; diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 17422a6..e0a99a7 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -254,6 +254,7 @@ class AppAssets { static const String homeBorderedIcon = '$svgBasePath/home_bordered.svg'; static const String symptomCheckerIcon = '$svgBasePath/symptom_checker_icon.svg'; static const String symptomCheckerBottomIcon = '$svgBasePath/symptom_bottom_icon.svg'; + static const String coloredDotsIcon = '$svgBasePath/colored_dots_icon.svg'; // Water Monitor static const String waterBottle = '$svgBasePath/water_bottle.svg'; @@ -306,6 +307,9 @@ class AppAssets { static const String bloodPressure = '$svgBasePath/blood_pressure.svg'; static const String temperature = '$svgBasePath/temperature.svg'; + static const String arLangIcon = '$svgBasePath/ar_lang_icon.svg'; + static const String enLangIcon = '$svgBasePath/en_lang_icon.svg'; + // PNGS // static const String hmgLogo = '$pngBasePath/hmg_logo.png'; static const String liveCareService = '$pngBasePath/livecare_service.png'; @@ -353,4 +357,3 @@ class AppAnimations { static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json'; static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json'; } - diff --git a/lib/core/enums.dart b/lib/core/enums.dart index 6dc3bf6..6613702 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -311,3 +311,150 @@ extension ServiceTypeEnumExt on ServiceTypeEnum { enum PossibleConditionsSeverityEnum { seekMedicalAdvice, monitorOnly, emergency } enum HealthTrackerTypeEnum { bloodSugar, bloodPressure, weightTracker } + +// Severity Enum +enum SeverityEnum { mild, moderate, severe } + +extension SeverityEnumExtension on SeverityEnum { + int get toInt { + switch (this) { + case SeverityEnum.mild: + return 0; + case SeverityEnum.moderate: + return 1; + case SeverityEnum.severe: + return 2; + } + } + + String get displayName { + AppState appState = getIt.get(); + bool isArabic = appState.getLanguageID() == 1 ? true : false; + switch (this) { + case SeverityEnum.mild: + return isArabic ? 'خفيف' : 'Mild'; + case SeverityEnum.moderate: + return isArabic ? 'متوسط' : 'Moderate'; + case SeverityEnum.severe: + return isArabic ? 'شديد' : 'Severe'; + } + } + + static SeverityEnum? fromInt(int value) { + switch (value) { + case 0: + return SeverityEnum.mild; + case 1: + return SeverityEnum.moderate; + case 2: + return SeverityEnum.severe; + default: + return null; + } + } +} + +// Triage Level Enum +enum TriageLevelEnum { emergencyAmbulance, emergency, consultation24, consultation, selfCare } + +extension TriageLevelEnumExtension on TriageLevelEnum { + int get toInt { + switch (this) { + case TriageLevelEnum.emergencyAmbulance: + return 0; + case TriageLevelEnum.emergency: + return 1; + case TriageLevelEnum.consultation24: + return 2; + case TriageLevelEnum.consultation: + return 3; + case TriageLevelEnum.selfCare: + return 4; + } + } + + String get displayName { + AppState appState = getIt.get(); + bool isArabic = appState.getLanguageID() == 1 ? true : false; + switch (this) { + case TriageLevelEnum.emergencyAmbulance: + return isArabic ? 'طوارئ - إسعاف' : 'Emergency - Ambulance'; + case TriageLevelEnum.emergency: + return isArabic ? 'طوارئ' : 'Emergency'; + case TriageLevelEnum.consultation24: + return isArabic ? 'استشارة خلال 24 ساعة' : 'Consultation within 24 hours'; + case TriageLevelEnum.consultation: + return isArabic ? 'استشارة' : 'Consultation'; + case TriageLevelEnum.selfCare: + return isArabic ? 'رعاية ذاتية' : 'Self Care'; + } + } + + static TriageLevelEnum? fromInt(int value) { + switch (value) { + case 0: + return TriageLevelEnum.emergencyAmbulance; + case 1: + return TriageLevelEnum.emergency; + case 2: + return TriageLevelEnum.consultation24; + case 3: + return TriageLevelEnum.consultation; + case 4: + return TriageLevelEnum.selfCare; + default: + return null; + } + } +} + +// Question Type Enum +enum QuestionTypeEnum { single, groupSingle, groupMultiple, duration } + +extension QuestionTypeEnumExtension on QuestionTypeEnum { + int get toInt { + switch (this) { + case QuestionTypeEnum.single: + return 0; + case QuestionTypeEnum.groupSingle: + return 1; + case QuestionTypeEnum.groupMultiple: + return 2; + case QuestionTypeEnum.duration: + return 3; + } + } + + String get displayName { + AppState appState = getIt.get(); + bool isArabic = appState.getLanguageID() == 1 ? true : false; + switch (this) { + case QuestionTypeEnum.single: + return isArabic ? 'سؤال واحد' : 'Single'; + case QuestionTypeEnum.groupSingle: + return isArabic ? 'مجموعة - اختيار واحد' : 'Group Single'; + case QuestionTypeEnum.groupMultiple: + return isArabic ? 'مجموعة - اختيار متعدد' : 'Group Multiple'; + case QuestionTypeEnum.duration: + return isArabic ? 'المدة' : 'Duration'; + } + } + + static QuestionTypeEnum? fromInt(int value) { + switch (value) { + case 0: + return QuestionTypeEnum.single; + case 1: + return QuestionTypeEnum.groupSingle; + case 2: + return QuestionTypeEnum.groupMultiple; + case 3: + return QuestionTypeEnum.duration; + default: + return null; + } + } +} + + + diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index e5b0ca4..5995438 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -814,7 +814,8 @@ class Utils { child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: iconColor), ), TextSpan( - text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount), + // text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount), + text: " ${habibWalletAmount.toStringAsFixed(2)}", style: TextStyle( color: textColor, fontSize: fontSize ?? 32.f, diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 7ac2ae5..f1182e0 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -571,7 +571,7 @@ class AuthenticationViewModel extends ChangeNotifier { MedicalFileViewModel medicalVm = getIt(); if (!_appState.getIsChildLoggedIn) { await medicalVm.getFamilyFiles(status: 0); - await medicalVm.getAllPendingRecordsByResponseId(); + // await medicalVm.getAllPendingRecordsByResponseId(); _navigationService.replaceAllRoutesAndNavigateToLanding(); } } else { @@ -610,7 +610,7 @@ class AuthenticationViewModel extends ChangeNotifier { MedicalFileViewModel medicalVm = getIt(); insertPatientIMEIData(loginTypeEnum.toInt); medicalVm.getFamilyFiles(status: 0); //TODO: Remove status: 1 by Aamir Need to Discuss With Sultan - medicalVm.getAllPendingRecordsByResponseId(); + // medicalVm.getAllPendingRecordsByResponseId(); } await clearDefaultInputValues(); if (isUserAgreedBefore) { diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart index e33222c..7ddccda 100644 --- a/lib/features/authentication/widgets/otp_verification_screen.dart +++ b/lib/features/authentication/widgets/otp_verification_screen.dart @@ -545,20 +545,20 @@ class _OTPVerificationScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 10.h), - LocaleKeys.otpVerification.tr().toText24(isBold: true), + LocaleKeys.otpVerification.tr(context: context).toText24(isBold: true), SizedBox(height: 20.h), Wrap( spacing: 2.h, runSpacing: 2.h, children: [ - LocaleKeys.weHaveSendOTP.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), + LocaleKeys.weHaveSendOTP.tr(context: context).toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), _getMaskedPhoneNumber().toText15(color: AppColors.inputLabelTextColor, isBold: true), - LocaleKeys.via.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), + LocaleKeys.via.tr(context: context).toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), (widget.isFormFamilyFile ? LoginTypeEnum.sms.displayName : authVM.loginTypeEnum.displayName) .toText15(color: AppColors.inputLabelTextColor, isBold: true, letterSpacing: -0.4), appState.getUserRegistrationPayload.isRegister != null && appState.getUserRegistrationPayload.isRegister == true - ? LocaleKeys.forRegistrationVerification.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4) - : LocaleKeys.forLoginVerification.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), + ? LocaleKeys.forRegistrationVerification.tr(context: context).toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4) + : LocaleKeys.forLoginVerification.tr(context: context).toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), ], ), @@ -590,7 +590,7 @@ class _OTPVerificationScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - LocaleKeys.didntReceiveIt.tr().toText16(color: AppColors.inputLabelTextColor), + LocaleKeys.didntReceiveIt.tr(context: context).toText16(color: AppColors.inputLabelTextColor), SizedBox(width: 5.h), if (_resendTime > 0) Builder( @@ -599,7 +599,7 @@ class _OTPVerificationScreenState extends State { final seconds = (_resendTime % 60).toString().padLeft(2, '0'); return Row( children: [ - LocaleKeys.resendIn.tr().toText16(color: AppColors.inputLabelTextColor), + LocaleKeys.resendIn.tr(context: context).toText16(color: AppColors.inputLabelTextColor), SizedBox(width: 2.h), ' ($minutes:$seconds). '.toText16(color: AppColors.inputLabelTextColor) ], @@ -609,7 +609,7 @@ class _OTPVerificationScreenState extends State { else GestureDetector( onTap: _resendOtp, - child: LocaleKeys.resendOTP.tr().toText16(color: AppColors.primaryRedColor), + child: LocaleKeys.resendOTP.tr(context: context).toText16(color: AppColors.primaryRedColor), ), ], ), diff --git a/lib/features/immediate_livecare/immediate_livecare_view_model.dart b/lib/features/immediate_livecare/immediate_livecare_view_model.dart index 1baa81b..ffa0b00 100644 --- a/lib/features/immediate_livecare/immediate_livecare_view_model.dart +++ b/lib/features/immediate_livecare/immediate_livecare_view_model.dart @@ -45,9 +45,7 @@ class ImmediateLiveCareViewModel extends ChangeNotifier { initImmediateLiveCare() { _appState = getIt(); immediateLiveCareClinicsList = []; - patientLiveCareHistoryList = []; isImmediateLiveCareClinicsLoading = true; - patientHasPendingLiveCareRequest = false; liveCareSelectedCallType = 0; // 1- Video, 2- Audio, 3- Phone immediateLiveCareSelectedClinic = GetLiveCareClinicListResponseModel(); liveCareImmediateAppointmentFeesList = LiveCareImmediateAppointmentFeesList(); @@ -136,6 +134,10 @@ class ImmediateLiveCareViewModel extends ChangeNotifier { } Future getPatientLiveCareHistory({Function(dynamic)? onSuccess, Function(String)? onError}) async { + patientLiveCareHistoryList = []; + patientHasPendingLiveCareRequest = false; + notifyListeners(); + final result = await immediateLiveCareRepo.getPatientLiveCareHistory(); result.fold( diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 96340a7..f287803 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -220,6 +220,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + isPatientHasQueueAppointment = false; if (!isAppointmentDataToBeLoaded) return; filteredAppointmentList.clear(); @@ -727,6 +728,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { Future getPatientAppointmentQueueDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async { //TODO: Discuss With Haroon, Is the User Has no data it return No Element Bad State; + isPatientHasQueueAppointment = false; isAppointmentQueueDetailsLoading = true; notifyListeners(); final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails( diff --git a/lib/features/symptoms_checker/data/organ_mapping_data.dart b/lib/features/symptoms_checker/data/organ_mapping_data.dart index 6b50b25..c338a94 100644 --- a/lib/features/symptoms_checker/data/organ_mapping_data.dart +++ b/lib/features/symptoms_checker/data/organ_mapping_data.dart @@ -8,28 +8,36 @@ class OrganData { OrganModel( id: 'head', name: 'whole_head', + nameAr: 'الرأس_كامل', description: 'Head', + descriptionAr: 'الرأس', bodyView: BodyView.front, position: OrganPosition(x: 0.50, y: 0.03), ), OrganModel( id: 'left_eye', name: 'eyes', + nameAr: 'العيون', description: 'Left Eye', + descriptionAr: 'العين اليسرى', bodyView: BodyView.front, position: OrganPosition(x: 0.43, y: 0.07), ), OrganModel( id: 'right_eye', name: 'eyes', + nameAr: 'العيون', description: 'Right Eye', + descriptionAr: 'العين اليمنى', bodyView: BodyView.front, position: OrganPosition(x: 0.57, y: 0.07), ), OrganModel( id: 'nose_mouth', name: 'oral_cavity', + nameAr: 'تجويف_الفم', description: 'Nose/Mouth', + descriptionAr: 'الأنف/الفم', bodyView: BodyView.front, position: OrganPosition(x: 0.50, y: 0.09), ), @@ -38,7 +46,9 @@ class OrganData { OrganModel( id: 'throat', name: 'neck_or_throat', + nameAr: 'الرقبة_أو_الحلق', description: 'Throat', + descriptionAr: 'الحلق', bodyView: BodyView.front, position: OrganPosition(x: 0.50, y: 0.15), ), @@ -47,14 +57,18 @@ class OrganData { OrganModel( id: 'left_shoulder', name: 'upper_arm', + nameAr: 'الذراع_العلوي', description: 'Left Shoulder', + descriptionAr: 'الكتف الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.22, y: 0.22), ), OrganModel( id: 'right_shoulder', name: 'upper_arm', + nameAr: 'الذراع_العلوي', description: 'Right Shoulder', + descriptionAr: 'الكتف الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.8, y: 0.22), ), @@ -63,21 +77,27 @@ class OrganData { OrganModel( id: 'left_chest', name: 'chest', + nameAr: 'الصدر', description: 'Left Chest', + descriptionAr: 'الصدر الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.38, y: 0.22), ), OrganModel( id: 'center_chest', name: 'chest', + nameAr: 'الصدر', description: 'Center Chest', + descriptionAr: 'وسط الصدر', bodyView: BodyView.front, position: OrganPosition(x: 0.52, y: 0.25), ), OrganModel( id: 'right_chest', name: 'chest', + nameAr: 'الصدر', description: 'Right Chest', + descriptionAr: 'الصدر الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.65, y: 0.22), ), @@ -86,14 +106,18 @@ class OrganData { OrganModel( id: 'left_ribs', name: 'chest', + nameAr: 'الصدر', description: 'Left Ribs', + descriptionAr: 'الأضلاع اليسرى', bodyView: BodyView.front, position: OrganPosition(x: 0.38, y: 0.35), ), OrganModel( id: 'right_ribs', name: 'chest', + nameAr: 'الصدر', description: 'Right Ribs', + descriptionAr: 'الأضلاع اليمنى', bodyView: BodyView.front, position: OrganPosition(x: 0.64, y: 0.35), ), @@ -102,21 +126,27 @@ class OrganData { OrganModel( id: 'upper_abdomen', name: 'upper_abdomen', + nameAr: 'البطن_العلوي', description: 'Upper Abdomen', + descriptionAr: 'أعلى البطن', bodyView: BodyView.front, position: OrganPosition(x: 0.51, y: 0.31), ), OrganModel( id: 'navel', name: 'mid_abdomen', + nameAr: 'البطن_الأوسط', description: 'Navel', + descriptionAr: 'السرة', bodyView: BodyView.front, position: OrganPosition(x: 0.51, y: 0.38), ), OrganModel( id: 'lower_abdomen', name: 'lower_abdomen', + nameAr: 'البطن_السفلي', description: 'Lower Abdomen', + descriptionAr: 'أسفل البطن', bodyView: BodyView.front, position: OrganPosition(x: 0.51, y: 0.44), ), @@ -125,14 +155,18 @@ class OrganData { OrganModel( id: 'left_groin', name: 'sexual_organs', + nameAr: 'الأعضاء_التناسلية', description: 'Left Groin', + descriptionAr: 'الفخذ الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.42, y: 0.49), ), OrganModel( id: 'right_groin', name: 'sexual_organs', + nameAr: 'الأعضاء_التناسلية', description: 'Right Groin', + descriptionAr: 'الفخذ الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.59, y: 0.49), ), @@ -142,21 +176,27 @@ class OrganData { OrganModel( id: 'left_elbow', name: 'elbow', + nameAr: 'الكوع', description: 'Left Elbow', + descriptionAr: 'الكوع الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.21, y: 0.35), ), OrganModel( id: 'left_forearm', name: 'forearm', + nameAr: 'الساعد', description: 'Left Forearm', + descriptionAr: 'الساعد الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.19, y: 0.43), ), OrganModel( id: 'left_wrist', name: 'hand', + nameAr: 'اليد', description: 'Left Wrist', + descriptionAr: 'المعصم الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.14, y: 0.5), ), @@ -166,21 +206,27 @@ class OrganData { OrganModel( id: 'right_elbow', name: 'elbow', + nameAr: 'الكوع', description: 'Right Elbow', + descriptionAr: 'الكوع الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.79, y: 0.35), ), OrganModel( id: 'right_forearm', name: 'forearm', + nameAr: 'الساعد', description: 'Right Forearm', + descriptionAr: 'الساعد الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.81, y: 0.43), ), OrganModel( id: 'right_wrist', name: 'hand', + nameAr: 'اليد', description: 'Right Wrist', + descriptionAr: 'المعصم الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.85, y: 0.5), ), @@ -189,28 +235,36 @@ class OrganData { OrganModel( id: 'left_thigh', name: 'thigh', + nameAr: 'الفخذ', description: 'Left Thigh', + descriptionAr: 'الفخذ الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.4, y: 0.60), ), OrganModel( id: 'left_knee', name: 'knee', + nameAr: 'الركبة', description: 'Left Knee', + descriptionAr: 'الركبة اليسرى', bodyView: BodyView.front, position: OrganPosition(x: 0.4, y: 0.72), ), OrganModel( id: 'left_shin', name: 'lower_leg', + nameAr: 'الساق_السفلي', description: 'Left Shin', + descriptionAr: 'الساق اليسرى', bodyView: BodyView.front, position: OrganPosition(x: 0.41, y: 0.82), ), OrganModel( id: 'left_ankle', name: 'foot', + nameAr: 'القدم', description: 'Left Ankle', + descriptionAr: 'الكاحل الأيسر', bodyView: BodyView.front, position: OrganPosition(x: 0.43, y: 0.91), ), @@ -219,28 +273,36 @@ class OrganData { OrganModel( id: 'right_thigh', name: 'thigh', + nameAr: 'الفخذ', description: 'Right Thigh', + descriptionAr: 'الفخذ الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.65, y: 0.60), ), OrganModel( id: 'right_knee', name: 'knee', + nameAr: 'الركبة', description: 'Right Knee', + descriptionAr: 'الركبة اليمنى', bodyView: BodyView.front, position: OrganPosition(x: 0.6, y: 0.72), ), OrganModel( id: 'right_shin', name: 'lower_leg', + nameAr: 'الساق_السفلي', description: 'Right Shin', + descriptionAr: 'الساق اليمنى', bodyView: BodyView.front, position: OrganPosition(x: 0.57, y: 0.82), ), OrganModel( id: 'right_ankle', name: 'foot', + nameAr: 'القدم', description: 'Right Ankle', + descriptionAr: 'الكاحل الأيمن', bodyView: BodyView.front, position: OrganPosition(x: 0.57, y: 0.91), ), @@ -252,14 +314,18 @@ class OrganData { OrganModel( id: 'back_of_head', name: 'whole_head', + nameAr: 'الرأس_كامل', description: 'Back of Head', + descriptionAr: 'مؤخرة الرأس', bodyView: BodyView.back, position: OrganPosition(x: 0.50, y: 0.04), ), OrganModel( id: 'neck_back', name: 'nape_of_neck', + nameAr: 'مؤخرة_الرقبة', description: 'Neck', + descriptionAr: 'الرقبة', bodyView: BodyView.back, position: OrganPosition(x: 0.50, y: 0.14), ), @@ -268,14 +334,18 @@ class OrganData { OrganModel( id: 'left_shoulder_back', name: 'upper_arm', + nameAr: 'الذراع_العلوي', description: 'Left Shoulder', + descriptionAr: 'الكتف الأيسر', bodyView: BodyView.back, position: OrganPosition(x: 0.33, y: 0.19), ), OrganModel( id: 'right_shoulder_back', name: 'upper_arm', + nameAr: 'الذراع_العلوي', description: 'Right Shoulder', + descriptionAr: 'الكتف الأيمن', bodyView: BodyView.back, position: OrganPosition(x: 0.67, y: 0.19), ), @@ -284,21 +354,27 @@ class OrganData { OrganModel( id: 'upper_spine', name: 'back', + nameAr: 'الظهر', description: 'Upper Spine', + descriptionAr: 'العمود الفقري العلوي', bodyView: BodyView.back, position: OrganPosition(x: 0.50, y: 0.23), ), OrganModel( id: 'left_upper_back', name: 'back', + nameAr: 'الظهر', description: 'Left Upper Back', + descriptionAr: 'أعلى الظهر الأيسر', bodyView: BodyView.back, position: OrganPosition(x: 0.38, y: 0.28), ), OrganModel( id: 'right_upper_back', name: 'back', + nameAr: 'الظهر', description: 'Right Upper Back', + descriptionAr: 'أعلى الظهر الأيمن', bodyView: BodyView.back, position: OrganPosition(x: 0.62, y: 0.28), ), @@ -307,21 +383,27 @@ class OrganData { OrganModel( id: 'mid_spine', name: 'back', + nameAr: 'الظهر', description: 'Mid Spine', + descriptionAr: 'العمود الفقري الأوسط', bodyView: BodyView.back, position: OrganPosition(x: 0.50, y: 0.35), ), OrganModel( id: 'left_mid_back', name: 'back', + nameAr: 'الظهر', description: 'Left Mid Back', + descriptionAr: 'وسط الظهر الأيسر', bodyView: BodyView.back, position: OrganPosition(x: 0.38, y: 0.35), ), OrganModel( id: 'right_mid_back', name: 'back', + nameAr: 'الظهر', description: 'Right Mid Back', + descriptionAr: 'وسط الظهر الأيمن', bodyView: BodyView.back, position: OrganPosition(x: 0.62, y: 0.35), ), @@ -330,21 +412,27 @@ class OrganData { OrganModel( id: 'lower_spine', name: 'lower_back', + nameAr: 'أسفل_الظهر', description: 'Lower Back', + descriptionAr: 'أسفل الظهر', bodyView: BodyView.back, position: OrganPosition(x: 0.50, y: 0.43), ), OrganModel( id: 'left_lower_back', name: 'lower_back', + nameAr: 'أسفل_الظهر', description: 'Left Lower Back', + descriptionAr: 'أسفل الظهر الأيسر', bodyView: BodyView.back, position: OrganPosition(x: 0.40, y: 0.43), ), OrganModel( id: 'right_lower_back', name: 'lower_back', + nameAr: 'أسفل_الظهر', description: 'Right Lower Back', + descriptionAr: 'أسفل الظهر الأيمن', bodyView: BodyView.back, position: OrganPosition(x: 0.60, y: 0.43), ), @@ -353,21 +441,27 @@ class OrganData { OrganModel( id: 'sacrum', name: 'lower_back', + nameAr: 'أسفل_الظهر', description: 'Sacrum', + descriptionAr: 'العجز', bodyView: BodyView.back, position: OrganPosition(x: 0.50, y: 0.52), ), OrganModel( id: 'left_glute', name: 'buttocks', + nameAr: 'الأرداف', description: 'Left Glute', + descriptionAr: 'الأرداف اليسرى', bodyView: BodyView.back, position: OrganPosition(x: 0.45, y: 0.56), ), OrganModel( id: 'right_glute', name: 'buttocks', + nameAr: 'الأرداف', description: 'Right Glute', + descriptionAr: 'الأرداف اليمنى', bodyView: BodyView.back, position: OrganPosition(x: 0.55, y: 0.56), ), @@ -376,28 +470,36 @@ class OrganData { OrganModel( id: 'left_hamstring', name: 'thigh', + nameAr: 'الفخذ', description: 'Left Hamstring', + descriptionAr: 'عضلة الفخذ الخلفية اليسرى', bodyView: BodyView.back, position: OrganPosition(x: 0.43, y: 0.65), ), OrganModel( id: 'right_hamstring', name: 'thigh', + nameAr: 'الفخذ', description: 'Right Hamstring', + descriptionAr: 'عضلة الفخذ الخلفية اليمنى', bodyView: BodyView.back, position: OrganPosition(x: 0.57, y: 0.65), ), OrganModel( id: 'left_calf', name: 'lower_leg', + nameAr: 'الساق_السفلي', description: 'Left Calf', + descriptionAr: 'ربلة الساق اليسرى', bodyView: BodyView.back, position: OrganPosition(x: 0.43, y: 0.79), ), OrganModel( id: 'right_calf', name: 'lower_leg', + nameAr: 'الساق_السفلي', description: 'Right Calf', + descriptionAr: 'ربلة الساق اليمنى', bodyView: BodyView.back, position: OrganPosition(x: 0.57, y: 0.79), ), diff --git a/lib/features/symptoms_checker/models/conditions_model.dart b/lib/features/symptoms_checker/models/conditions_model.dart index 774d8c3..af66c21 100644 --- a/lib/features/symptoms_checker/models/conditions_model.dart +++ b/lib/features/symptoms_checker/models/conditions_model.dart @@ -1,97 +1,97 @@ -import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/core/enums.dart'; - -class ConditionsModel { - final IconData icon; - final String title; - final int percentage; - final String tagText; - final String clinic; - final List symptoms; - final String description; - final String? monitorNote; - final String? appointmentLabel; - final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum; - - ConditionsModel({ - required this.icon, - required this.title, - required this.percentage, - required this.tagText, - required this.clinic, - required this.symptoms, - required this.description, - required this.possibleConditionsSeverityEnum, - this.monitorNote, - this.appointmentLabel, - }); -} - -List dummyConditions = [ - ConditionsModel( - icon: Icons.psychology_alt, - possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, - title: "Migraine", - percentage: 87, - tagText: "Seek Medical Advice", - clinic: "Internal Medicine Clinic", - symptoms: ["Headache", "Nausea", "Sensitivity to light"], - description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.", - appointmentLabel: "Book Appointment", - ), - ConditionsModel( - icon: Icons.deblur, - title: "Tension Headache", - percentage: 37, - tagText: "Monitor", - monitorNote: "No need to visit doctor", - clinic: "GP Clinic", - symptoms: ["Mild head pressure", "Scalp tenderness"], - description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", - possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly, - ), - ConditionsModel( - icon: Icons.medication_liquid, - title: "Meningitis", - percentage: 28, - tagText: "Emergency", - clinic: "Neurology Clinic", - symptoms: ["Mild head pressure", "Scalp tenderness"], - description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", - appointmentLabel: "Book Appointment", - possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency, - ), - ConditionsModel( - icon: Icons.psychology_alt, - title: "Migraine", - percentage: 87, - tagText: "Seek Medical Advice", - clinic: "Internal Medicine Clinic", - symptoms: ["Headache", "Nausea", "Sensitivity to light"], - description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.", - appointmentLabel: "Book Appointment", - possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, - ), - ConditionsModel( - icon: Icons.deblur, - title: "Tension Headache", - percentage: 37, - tagText: "Monitor", - monitorNote: "No need to visit doctor", - clinic: "GP Clinic", - symptoms: ["Mild head pressure", "Scalp tenderness"], - description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", - possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly, - ), - ConditionsModel( - icon: Icons.medication_liquid, - title: "Meningitis", - percentage: 28, - tagText: "Emergency", - clinic: "Neurology Clinic", - symptoms: ["Mild head pressure", "Scalp tenderness"], - description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", - appointmentLabel: "Book Appointment", - possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency, - ), -]; +// import 'package:flutter/material.dart'; +// import 'package:hmg_patient_app_new/core/enums.dart'; +// +// class ConditionsModel { +// final IconData icon; +// final String title; +// final int percentage; +// final String tagText; +// final String clinic; +// final List symptoms; +// final String description; +// final String? monitorNote; +// final String? appointmentLabel; +// final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum; +// +// ConditionsModel({ +// required this.icon, +// required this.title, +// required this.percentage, +// required this.tagText, +// required this.clinic, +// required this.symptoms, +// required this.description, +// required this.possibleConditionsSeverityEnum, +// this.monitorNote, +// this.appointmentLabel, +// }); +// } +// +// List dummyConditions = [ +// ConditionsModel( +// icon: Icons.psychology_alt, +// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, +// title: "Migraine", +// percentage: 87, +// tagText: "Seek Medical Advice", +// clinic: "Internal Medicine Clinic", +// symptoms: ["Headache", "Nausea", "Sensitivity to light"], +// description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.", +// appointmentLabel: "Book Appointment", +// ), +// ConditionsModel( +// icon: Icons.deblur, +// title: "Tension Headache", +// percentage: 37, +// tagText: "Monitor", +// monitorNote: "No need to visit doctor", +// clinic: "GP Clinic", +// symptoms: ["Mild head pressure", "Scalp tenderness"], +// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", +// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly, +// ), +// ConditionsModel( +// icon: Icons.medication_liquid, +// title: "Meningitis", +// percentage: 28, +// tagText: "Emergency", +// clinic: "Neurology Clinic", +// symptoms: ["Mild head pressure", "Scalp tenderness"], +// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", +// appointmentLabel: "Book Appointment", +// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency, +// ), +// ConditionsModel( +// icon: Icons.psychology_alt, +// title: "Migraine", +// percentage: 87, +// tagText: "Seek Medical Advice", +// clinic: "Internal Medicine Clinic", +// symptoms: ["Headache", "Nausea", "Sensitivity to light"], +// description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.", +// appointmentLabel: "Book Appointment", +// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, +// ), +// ConditionsModel( +// icon: Icons.deblur, +// title: "Tension Headache", +// percentage: 37, +// tagText: "Monitor", +// monitorNote: "No need to visit doctor", +// clinic: "GP Clinic", +// symptoms: ["Mild head pressure", "Scalp tenderness"], +// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", +// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly, +// ), +// ConditionsModel( +// icon: Icons.medication_liquid, +// title: "Meningitis", +// percentage: 28, +// tagText: "Emergency", +// clinic: "Neurology Clinic", +// symptoms: ["Mild head pressure", "Scalp tenderness"], +// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", +// appointmentLabel: "Book Appointment", +// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency, +// ), +// ]; diff --git a/lib/features/symptoms_checker/models/organ_model.dart b/lib/features/symptoms_checker/models/organ_model.dart index fab7dff..9a871f3 100644 --- a/lib/features/symptoms_checker/models/organ_model.dart +++ b/lib/features/symptoms_checker/models/organ_model.dart @@ -3,29 +3,47 @@ import 'package:hmg_patient_app_new/core/enums.dart'; class OrganModel { final String id; final String name; + final String nameAr; final String description; + final String descriptionAr; final BodyView bodyView; final OrganPosition position; const OrganModel({ required this.id, required this.name, + required this.nameAr, required this.description, + required this.descriptionAr, required this.bodyView, required this.position, }); + /// Get localized name based on isArabic flag + String getLocalizedName(bool isArabic) { + return isArabic ? nameAr : name; + } + + /// Get localized description based on isArabic flag + String getLocalizedDescription(bool isArabic) { + return isArabic ? descriptionAr : description; + } + OrganModel copyWith({ String? id, String? name, + String? nameAr, String? description, + String? descriptionAr, BodyView? bodyView, OrganPosition? position, }) { return OrganModel( id: id ?? this.id, name: name ?? this.name, + nameAr: nameAr ?? this.nameAr, description: description ?? this.description, + descriptionAr: descriptionAr ?? this.descriptionAr, bodyView: bodyView ?? this.bodyView, position: position ?? this.position, ); diff --git a/lib/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart b/lib/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart index b2be4a2..9928d78 100644 --- a/lib/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart +++ b/lib/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart @@ -22,6 +22,8 @@ class RiskAndSuggestionsItemModel { final String? type; final String? name; final String? commonName; + final String? nameAr; + final String? commonNameAr; final String? language; RiskAndSuggestionsItemModel({ @@ -29,6 +31,8 @@ class RiskAndSuggestionsItemModel { this.type, this.name, this.commonName, + this.nameAr, + this.commonNameAr, this.language, }); @@ -38,6 +42,8 @@ class RiskAndSuggestionsItemModel { type: json['type'], name: json['name'], commonName: json['common_name'], + nameAr: json['nameAr'], + commonNameAr: json['common_nameAr'], language: json['language'], ); } @@ -48,12 +54,17 @@ class RiskAndSuggestionsItemModel { 'type': type, 'name': name, 'common_name': commonName, + 'nameAr': nameAr, + 'common_nameAr': commonNameAr, 'language': language, }; } - // Helper method to get display name - String getDisplayName() { + // Helper method to get display name based on locale + String getDisplayName({bool isArabic = false}) { + if (isArabic) { + return commonNameAr ?? nameAr ?? commonName ?? name ?? ''; + } return commonName ?? name ?? ''; } } diff --git a/lib/features/symptoms_checker/models/resp_models/triage_response_model.dart b/lib/features/symptoms_checker/models/resp_models/triage_response_model.dart index f0d7e90..da0f4b6 100644 --- a/lib/features/symptoms_checker/models/resp_models/triage_response_model.dart +++ b/lib/features/symptoms_checker/models/resp_models/triage_response_model.dart @@ -1,3 +1,5 @@ +import 'package:hmg_patient_app_new/core/enums.dart'; + class TriageDataDetails { final TriageQuestion? question; final List? conditions; @@ -170,13 +172,17 @@ class TriageCondition { final String? id; final String? name; final String? commonName; + final String? nameAr; + final String? commonNameAr; final double? probability; - final dynamic conditionDetails; + final ConditionDetails? conditionDetails; TriageCondition({ this.id, this.name, this.commonName, + this.nameAr, + this.commonNameAr, this.probability, this.conditionDetails, }); @@ -186,8 +192,10 @@ class TriageCondition { id: json['id'], name: json['name'], commonName: json['common_name'], + nameAr: json['nameAr'], + commonNameAr: json['common_nameAr'], probability: json['probability']?.toDouble(), - conditionDetails: json['condition_details'], + conditionDetails: json['condition_details'] != null ? ConditionDetails.fromJson(json['condition_details']) : null, ); } @@ -196,14 +204,96 @@ class TriageCondition { 'id': id, 'name': name, 'common_name': commonName, + 'nameAr': nameAr, + 'common_nameAr': commonNameAr, 'probability': probability, - 'condition_details': conditionDetails, + 'condition_details': conditionDetails?.toJson(), }; } + /// Get display name based on locale + String getDisplayName({bool isArabic = false}) { + if (isArabic) { + return commonNameAr ?? nameAr ?? commonName ?? name ?? ''; + } + return commonName ?? name ?? ''; + } + /// Get probability as percentage String getProbabilityPercentage() { if (probability == null) return '0%'; return '${(probability! * 100).toStringAsFixed(1)}%'; } } + +class ConditionDetails { + final String? icd10Code; + final ConditionCategory? category; + final SeverityEnum? severity; + final TriageLevelEnum? triageLevel; + final String? hint; + final bool? hasPatientEducation; + final String? prevalence; + final String? acuteness; + + ConditionDetails({ + this.icd10Code, + this.category, + this.severity, + this.triageLevel, + this.hint, + this.hasPatientEducation, + this.prevalence, + this.acuteness, + }); + + factory ConditionDetails.fromJson(Map json) { + return ConditionDetails( + icd10Code: json['icd10_code'], + category: json['category'] != null ? ConditionCategory.fromJson(json['category']) : null, + severity: json['severity'] != null ? SeverityEnumExtension.fromInt(json['severity']) : null, + triageLevel: json['triage_level'] != null ? TriageLevelEnumExtension.fromInt(json['triage_level']) : null, + hint: json['hint'], + hasPatientEducation: json['has_patient_education'], + prevalence: json['prevalence'], + acuteness: json['acuteness'], + ); + } + + Map toJson() { + return { + 'icd10_code': icd10Code, + 'category': category?.toJson(), + 'severity': severity?.toInt, + 'triage_level': triageLevel?.toInt, + 'hint': hint, + 'has_patient_education': hasPatientEducation, + 'prevalence': prevalence, + 'acuteness': acuteness, + }; + } +} + +class ConditionCategory { + final String? id; + final String? name; + + ConditionCategory({ + this.id, + this.name, + }); + + factory ConditionCategory.fromJson(Map json) { + return ConditionCategory( + id: json['id'], + name: json['name'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + }; + } +} diff --git a/lib/features/symptoms_checker/symptoms_checker_repo.dart b/lib/features/symptoms_checker/symptoms_checker_repo.dart index c55c2f0..c0214e1 100644 --- a/lib/features/symptoms_checker/symptoms_checker_repo.dart +++ b/lib/features/symptoms_checker/symptoms_checker_repo.dart @@ -12,50 +12,42 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class SymptomsCheckerRepo { - Future>> - getUserDetails({ + Future>> getUserDetails({ required String userName, required String password, }); - Future>> - getBodySymptomsByName({ + Future>> getBodySymptomsByName({ required List organNames, required String userSessionToken, required int gender, }); - Future>> - getRiskFactors({ + Future>> getRiskFactors({ required int age, - required String sex, + required int gender, required List evidenceIds, required String language, required String userSessionToken, - required int gender, required String sessionId, }); - Future>> - getSuggestions({ + Future>> getSuggestions({ required int age, - required String sex, + required int gender, required List evidenceIds, required String language, required String userSessionToken, required String sessionId, - required int gender, }); - Future>> - getDiagnosisForTriage({ + Future>> getDiagnosisForTriage({ required int age, - required String sex, + required int gender, required List evidenceIds, List>? triageEvidence, required String language, required String userSessionToken, - required int gender, required String sessionId, }); } @@ -64,16 +56,14 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { final ApiClient apiClient; final LoggerService loggerService; - SymptomsCheckerRepoImp( - {required this.apiClient, required this.loggerService}); + SymptomsCheckerRepoImp({required this.apiClient, required this.loggerService}); @override - Future>> - getUserDetails({ + Future>> getUserDetails({ required String userName, required String password, }) async { - Map body = {"userName": userName, "password": password}; + Map body = {"userName": userName, "password": password}; try { GenericApiModel? apiResponse; @@ -92,11 +82,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { // Parse response if it's a string - final Map responseData = - response is String ? jsonDecode(response) : response; + final Map responseData = response is String ? jsonDecode(response) : response; - SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel = - SymptomsUserDetailsResponseModel.fromJson(responseData); + SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel = SymptomsUserDetailsResponseModel.fromJson(responseData); apiResponse = GenericApiModel( messageStatus: messageStatus ?? 1, @@ -123,8 +111,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { } @override - Future>> - getBodySymptomsByName({ + Future>> getBodySymptomsByName({ required List organNames, required String userSessionToken, required int gender, @@ -154,8 +141,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { - BodySymptomResponseModel bodySymptomResponse = - BodySymptomResponseModel.fromJson(response); + BodySymptomResponseModel bodySymptomResponse = BodySymptomResponseModel.fromJson(response); apiResponse = GenericApiModel( messageStatus: messageStatus ?? 1, @@ -164,8 +150,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { data: bodySymptomResponse, ); } catch (e, stackTrace) { - loggerService - .logError("Error parsing GetBodySymptomsByName response: $e"); + loggerService.logError("Error parsing GetBodySymptomsByName response: $e"); loggerService.logError("StackTrace: $stackTrace"); failure = DataParsingFailure(e.toString()); } @@ -183,21 +168,19 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { } @override - Future>> - getRiskFactors({ + Future>> getRiskFactors({ required int age, - required String sex, + required int gender, required List evidenceIds, required String language, required String userSessionToken, - required int gender, required String sessionId, }) async { final Map body = { "age": { "value": age, }, - "sex": sex, + "gender": gender, "evidence": evidenceIds.map((id) => {"id": id}).toList(), "language": language, "generalId": sessionId, @@ -225,11 +208,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { // Parse response if it's a string - final Map responseData = - response is String ? jsonDecode(response) : response; + final Map responseData = response is String ? jsonDecode(response) : response; - RiskAndSuggestionsResponseModel riskFactorsResponse = - RiskAndSuggestionsResponseModel.fromJson(responseData); + RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData); apiResponse = GenericApiModel( messageStatus: messageStatus ?? 1, @@ -255,16 +236,14 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { } } - Future>> - getDiagnosisForTriage({ + @override + Future>> getDiagnosisForTriage({ required int age, - required String sex, + required int gender, required List evidenceIds, - List>? - triageEvidence, // Additional triage-specific evidence + List>? triageEvidence, // Additional triage-specific evidence required String language, required String userSessionToken, - required int gender, required String sessionId, }) async { // Build evidence list: combine initial symptoms with triage evidence @@ -284,7 +263,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { "age": { "value": age, }, - "sex": sex, + "gender": gender, "evidence": evidenceList, "language": language, "suggest_method": "diagnosis", @@ -313,13 +292,11 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { // Parse response if it's a string - final Map responseData = - response is String ? jsonDecode(response) : response; + final Map responseData = response is String ? jsonDecode(response) : response; final updatedResponseData = responseData['dataDetails']; - TriageDataDetails riskFactorsResponse = - TriageDataDetails.fromJson(updatedResponseData); + TriageDataDetails riskFactorsResponse = TriageDataDetails.fromJson(updatedResponseData); apiResponse = GenericApiModel( messageStatus: messageStatus ?? 1, @@ -328,8 +305,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { data: riskFactorsResponse, ); } catch (e, stackTrace) { - loggerService - .logError("Error parsing getDiagnosisForTriage response: $e"); + loggerService.logError("Error parsing getDiagnosisForTriage response: $e"); loggerService.logError("StackTrace: $stackTrace"); failure = DataParsingFailure(e.toString()); } @@ -347,21 +323,19 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { } @override - Future>> - getSuggestions({ + Future>> getSuggestions({ required int age, - required String sex, + required int gender, required List evidenceIds, required String language, required String userSessionToken, required String sessionId, - required int gender, }) async { final Map body = { "age": { "value": age, }, - "sex": sex, + "gender": gender, "evidence": evidenceIds.map((id) => {"id": id}).toList(), "language": language, "generalId": sessionId, @@ -389,11 +363,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { // Parse response if it's a string - final Map responseData = - response is String ? jsonDecode(response) : response; + final Map responseData = response is String ? jsonDecode(response) : response; - RiskAndSuggestionsResponseModel riskFactorsResponse = - RiskAndSuggestionsResponseModel.fromJson(responseData); + RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData); apiResponse = GenericApiModel( messageStatus: messageStatus ?? 1, diff --git a/lib/features/symptoms_checker/symptoms_checker_view_model.dart b/lib/features/symptoms_checker/symptoms_checker_view_model.dart index 73768fe..ed82451 100644 --- a/lib/features/symptoms_checker/symptoms_checker_view_model.dart +++ b/lib/features/symptoms_checker/symptoms_checker_view_model.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/data/organ_mapping_data.dart'; @@ -23,6 +23,23 @@ class SymptomsCheckerViewModel extends ChangeNotifier { required this.appState, }); + // Gender constants for both English and Arabic + static const String _maleEn = "male"; + static const String _femaleEn = "female"; + static const String _maleAr = "ذكر"; + static const String _femaleAr = "أنثى"; + + /// Convert gender string to integer (1 for male, 2 for female) + /// Handles both English and Arabic values + int _getGenderAsInt(String? gender) { + if (gender == null) return 1; // Default to male + final lowerGender = gender.toLowerCase(); + if (lowerGender == _maleEn || gender == _maleAr) { + return 1; + } + return 2; // Female or any other value + } + // State variables bool isBodyHidden = false; BodyView _currentView = BodyView.front; @@ -47,12 +64,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier { TriageDataDetails? triageDataDetails; // Triage state - int? - _selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility - final Map _selectedTriageChoicesByItemId = - {}; // Map of itemId -> choiceIndex for multi-item questions - final List> _triageEvidenceList = - []; // Store triage evidence with proper format + int? _selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility + final Map _selectedTriageChoicesByItemId = {}; // Map of itemId -> choiceIndex for multi-item questions + final List> _triageEvidenceList = []; // Store triage evidence with proper format int _triageQuestionCount = 0; // Track number of triage questions answered // Selected risk factors tracking @@ -66,8 +80,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { // User Info Flow State int _userInfoCurrentPage = 0; - bool _isSinglePageEditMode = - false; // Track if editing single page or full flow + bool _isSinglePageEditMode = false; // Track if editing single page or full flow String? _selectedGender; DateTime? _dateOfBirth; int? _selectedAge; @@ -107,17 +120,14 @@ class SymptomsCheckerViewModel extends ChangeNotifier { String? get tooltipOrganId => _tooltipOrganId; - String get currentSessionAuthToken => - symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? ""; + String get currentSessionAuthToken => symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? ""; - String get currentSessionId => - symptomsUserDetailsResponseModel?.sessionId ?? ""; + String get currentSessionId => symptomsUserDetailsResponseModel?.sessionId ?? ""; // Triage-related getters bool get shouldStopTriage => triageDataDetails?.shouldStop ?? false; - bool get hasEmergencyEvidence => - triageDataDetails?.hasEmergencyEvidence ?? false; + bool get hasEmergencyEvidence => triageDataDetails?.hasEmergencyEvidence ?? false; String? get currentInterviewToken => triageDataDetails?.interviewToken; @@ -137,15 +147,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Check if all items in current question have been answered bool get areAllTriageItemsAnswered { - if (currentTriageQuestion?.items == null || - currentTriageQuestion!.items!.isEmpty) { + if (currentTriageQuestion?.items == null || currentTriageQuestion!.items!.isEmpty) { return false; } // Check if we have an answer for each item for (var item in currentTriageQuestion!.items!) { - if (item.id != null && - !_selectedTriageChoicesByItemId.containsKey(item.id)) { + if (item.id != null && !_selectedTriageChoicesByItemId.containsKey(item.id)) { return false; } } @@ -153,8 +161,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } /// Get organs for current view - List get currentOrgans => - OrganData.getOrgansForView(_currentView); + List get currentOrgans => OrganData.getOrgansForView(_currentView); /// Get all selected organs from both views List get selectedOrgans { @@ -162,9 +169,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { ...OrganData.frontViewOrgans, ...OrganData.backViewOrgans, ]; - return allOrgans - .where((organ) => _selectedOrganIds.contains(organ.id)) - .toList(); + return allOrgans.where((organ) => _selectedOrganIds.contains(organ.id)).toList(); } /// Check if any organs are selected @@ -181,13 +186,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } int get totalSelectedSymptomsCount { - return _selectedSymptomsByOrgan.values - .fold(0, (sum, symptomIds) => sum + symptomIds.length); + return _selectedSymptomsByOrgan.values.fold(0, (sum, symptomIds) => sum + symptomIds.length); } bool get hasSelectedSymptoms { - return _selectedSymptomsByOrgan.values - .any((symptomIds) => symptomIds.isNotEmpty); + return _selectedSymptomsByOrgan.values.any((symptomIds) => symptomIds.isNotEmpty); } /// Get risk factors list @@ -213,8 +216,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } void toggleView() { - _currentView = - _currentView == BodyView.front ? BodyView.back : BodyView.front; + _currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front; notifyListeners(); } @@ -317,8 +319,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { return; } - List organNames = - selectedOrgans.map((organ) => organ.name).toList(); + List organNames = selectedOrgans.map((organ) => organ.name).toList(); await getBodySymptomsByName( organNames: organNames, @@ -368,8 +369,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } } - if (matchingOrganId != null && - _selectedSymptomsByOrgan.containsKey(matchingOrganId)) { + if (matchingOrganId != null && _selectedSymptomsByOrgan.containsKey(matchingOrganId)) { final selectedIds = _selectedSymptomsByOrgan[matchingOrganId]!; if (organResult.bodySymptoms != null) { @@ -420,10 +420,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Get all selected risk factors List getAllSelectedRiskFactors() { - return riskFactorsList - .where((factor) => - factor.id != null && _selectedRiskFactorIds.contains(factor.id)) - .toList(); + return riskFactorsList.where((factor) => factor.id != null && _selectedRiskFactorIds.contains(factor.id)).toList(); } /// Clear all risk factor selections @@ -456,12 +453,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } // Extract symptom IDs - List evidenceIds = - selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList(); + List evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList(); await getRiskFactors( age: _selectedAge!, - sex: _selectedGender!.toLowerCase(), + gender: _getGenderAsInt(_selectedGender), evidenceIds: evidenceIds, sessionId: currentSessionId, language: appState.isArabic() ? 'ar' : 'en', @@ -481,7 +477,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Call Risk Factors API Future getRiskFactors({ required int age, - required String sex, + required int gender, required String sessionId, required List evidenceIds, required String language, @@ -493,12 +489,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier { final result = await symptomsCheckerRepo.getRiskFactors( age: age, - sex: sex, + gender: gender, evidenceIds: evidenceIds, language: language, sessionId: sessionId, userSessionToken: currentSessionAuthToken, - gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2, ); result.fold( @@ -515,13 +510,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier { if (apiResponse.messageStatus == 1 && apiResponse.data != null) { riskFactorsResponse = apiResponse.data; - if (riskFactorsResponse != null && - riskFactorsResponse!.dataDetails != null) { - RiskAndSuggestionsItemModel riskFactorItem = - RiskAndSuggestionsItemModel( + if (riskFactorsResponse != null && riskFactorsResponse!.dataDetails != null) { + RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel( id: "not_applicable", commonName: "Not Applicable", name: "Not Applicable", + commonNameAr: "لا ينطبق", + nameAr: "لا ينطبق", language: appState.isArabic() ? 'ar' : 'en', type: null, ); @@ -572,10 +567,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Get all selected risk factors List getAllSelectedSuggestions() { - return suggestionsList - .where((factor) => - factor.id != null && _selectedSuggestionsIds.contains(factor.id)) - .toList(); + return suggestionsList.where((factor) => factor.id != null && _selectedSuggestionsIds.contains(factor.id)).toList(); } /// Clear all risk factor selections @@ -590,20 +582,15 @@ class SymptomsCheckerViewModel extends ChangeNotifier { // Add selected symptoms final selectedSymptoms = getAllSelectedSymptoms(); - evidenceIds - .addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!)); + evidenceIds.addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!)); // Add selected risk factors (excluding "not_applicable") final selectedRiskFactors = getAllSelectedRiskFactors(); - evidenceIds.addAll(selectedRiskFactors - .where((rf) => rf.id != null && rf.id != "not_applicable") - .map((rf) => rf.id!)); + evidenceIds.addAll(selectedRiskFactors.where((rf) => rf.id != null && rf.id != "not_applicable").map((rf) => rf.id!)); // Add selected suggestions (excluding "not_applicable") final selectedSuggestions = getAllSelectedSuggestions(); - evidenceIds.addAll(selectedSuggestions - .where((s) => s.id != null && s.id != "not_applicable") - .map((s) => s.id!)); + evidenceIds.addAll(selectedSuggestions.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!)); return evidenceIds; } @@ -632,23 +619,19 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } // Extract symptom IDs - List evidenceIds = - selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList(); + List evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList(); // Get all selected symptoms final selectedRisks = getAllSelectedRiskFactors(); if (selectedRisks.isNotEmpty) { - List evidenceRisksIds = selectedRisks - .where((s) => s.id != null && s.id != "not_applicable") - .map((s) => s.id!) - .toList(); + List evidenceRisksIds = selectedRisks.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!).toList(); evidenceIds.addAll(evidenceRisksIds); } await getSuggestions( age: _selectedAge!, - sex: _selectedGender!.toLowerCase(), + gender: _getGenderAsInt(_selectedGender), evidenceIds: evidenceIds, language: appState.isArabic() ? 'ar' : 'en', onSuccess: (response) { @@ -667,7 +650,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Call Suggestions API Future getSuggestions({ required int age, - required String sex, + required int gender, required List evidenceIds, required String language, Function(RiskAndSuggestionsResponseModel)? onSuccess, @@ -678,12 +661,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier { final result = await symptomsCheckerRepo.getSuggestions( age: age, - sex: sex, + gender: gender, evidenceIds: evidenceIds, language: language, sessionId: currentSessionId, userSessionToken: currentSessionAuthToken, - gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2, ); result.fold( @@ -700,13 +682,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier { if (apiResponse.messageStatus == 1 && apiResponse.data != null) { suggestionsResponse = apiResponse.data; - if (suggestionsResponse != null && - suggestionsResponse!.dataDetails != null) { - RiskAndSuggestionsItemModel riskFactorItem = - RiskAndSuggestionsItemModel( + if (suggestionsResponse != null && suggestionsResponse!.dataDetails != null) { + RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel( id: "not_applicable", commonName: "Not Applicable", name: "Not Applicable", + commonNameAr: "لا ينطبق", + nameAr: "لا ينطبق", language: appState.isArabic() ? 'ar' : 'en', type: null, ); @@ -730,7 +712,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Call Diagnosis API for Triage - This is called iteratively until shouldStop is true Future getDiagnosisForTriage({ required int age, - required String sex, + required int gender, required List evidenceIds, List>? triageEvidence, required String language, @@ -742,13 +724,12 @@ class SymptomsCheckerViewModel extends ChangeNotifier { final result = await symptomsCheckerRepo.getDiagnosisForTriage( age: age, - sex: sex, + gender: gender, evidenceIds: evidenceIds, triageEvidence: triageEvidence, language: language, sessionId: currentSessionId, userSessionToken: currentSessionAuthToken, - gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2, ); result.fold( @@ -804,7 +785,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { await getDiagnosisForTriage( age: _selectedAge!, - sex: _selectedGender!.toLowerCase(), + gender: _getGenderAsInt(_selectedGender), evidenceIds: evidenceIds, language: appState.isArabic() ? 'ar' : 'en', onSuccess: (response) { @@ -941,8 +922,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { // Calculate age from date of birth final now = DateTime.now(); int age = now.year - dateOfBirth.year; - if (now.month < dateOfBirth.month || - (now.month == dateOfBirth.month && now.day < dateOfBirth.day)) { + if (now.month < dateOfBirth.month || (now.month == dateOfBirth.month && now.day < dateOfBirth.day)) { age--; } _selectedAge = age; @@ -968,6 +948,22 @@ class SymptomsCheckerViewModel extends ChangeNotifier { bool get isUserInfoFirstPage => _userInfoCurrentPage == 0; + /// Check if current user info page has valid selection + bool get isCurrentUserInfoPageValid { + switch (_userInfoCurrentPage) { + case 0: // Gender page + return _selectedGender != null && _selectedGender!.isNotEmpty; + case 1: // Age/Birth date page + return _dateOfBirth != null || (_selectedAge != null && _selectedAge! > 0); + case 2: // Height page + return _selectedHeight > 0; + case 3: // Weight page + return _selectedWeight > 0; + default: + return false; + } + } + /// Validate and submit user info Map getUserInfoData() { return { @@ -989,8 +985,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { }) async { isBodySymptomsLoading = true; notifyListeners(); - final result = await symptomsCheckerRepo.getUserDetails( - userName: userName, password: password); + final result = await symptomsCheckerRepo.getUserDetails(userName: userName, password: password); result.fold( (failure) async { @@ -1030,7 +1025,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { final result = await symptomsCheckerRepo.getBodySymptomsByName( organNames: organNames, userSessionToken: currentSessionAuthToken, - gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2, + gender: _getGenderAsInt(selectedGender ?? "Male"), ); result.fold( diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index b3b2edf..41cb64f 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1371,6 +1371,17 @@ abstract class LocaleKeys { static const suggestions = 'suggestions'; static const pleaseGoBackAndSelectOrgansFirst = 'pleaseGoBackAndSelectOrgansFirst'; static const symptomsSelector = 'symptomsSelector'; + static const possibleSymptomsRelatedTo = 'possibleSymptomsRelatedTo'; + static const suggestionAIListDescription = 'suggestionAIListDescription'; + static const analyzing = 'analyzing'; + static const seekMedicalAdvice = 'seekMedicalAdvice'; + static const monitorDescription = 'monitorDescription'; + static const seekMedicalAdviceDescription = 'seekMedicalAdviceDescription'; + static const emergencyDescription = 'emergencyDescription'; + static const colorScience = 'colorScience'; + static const noNeedToVisitDoctor = 'noNeedToVisitDoctor'; + static const commonSymptom = 'commonSymptom'; + static const notApplicable = 'notApplicable'; static const emergencyTriage = 'emergencyTriage'; static const emergencyEvidenceDetected = 'emergencyEvidenceDetected'; static const noQuestionItemsAvailable = 'noQuestionItemsAvailable'; @@ -1488,5 +1499,18 @@ abstract class LocaleKeys { static const pleaseWaitYouWillBeCalledForVitalSigns = 'pleaseWaitYouWillBeCalledForVitalSigns'; static const pleaseVisitRoomForVitalSigns = 'pleaseVisitRoomForVitalSigns'; static const pleaseVisitRoomToTheDoctor = 'pleaseVisitRoomToTheDoctor'; + static const erOnlineCheckInRequest = 'erOnlineCheckInRequest'; + static const indoor = 'indoor'; + static const navigation = 'navigation'; + static const health = 'health'; + static const calculators = 'calculators'; + static const converters = 'converters'; + static const guide = 'guide'; + static const liveCareServiceDesc = 'liveCareServiceDesc'; + static const bloodGroup = 'bloodGroup'; + static const medicalServices = 'medicalServices'; + static const insuranceAndPayments = 'insuranceAndPayments'; + static const trackerAndOthers = 'trackerAndOthers'; + static const bmi = 'bmi'; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 0b8066e..3f98e6d 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -87,7 +87,7 @@ class _AppointmentDetailsPageState extends State { children: [ Expanded( child: CollapsingListView( - title: LocaleKeys.appointmentDetails.tr(), + title: LocaleKeys.appointmentDetails.tr(context: context), report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? () { contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); @@ -105,7 +105,7 @@ class _AppointmentDetailsPageState extends State { AppointmentDoctorCard( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onAskDoctorTap: () async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); await myAppointmentsViewModel.isDoctorAvailable( projectID: widget.patientAppointmentHistoryResponseModel.projectID, doctorId: widget.patientAppointmentHistoryResponseModel.doctorID, @@ -135,7 +135,7 @@ class _AppointmentDetailsPageState extends State { onCancelTap: () async { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr(context: context)); await myAppointmentsViewModel.cancelAppointment( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onSuccess: (apiResponse) { @@ -144,7 +144,7 @@ class _AppointmentDetailsPageState extends State { myAppointmentsViewModel.getPatientAppointments(true, false); showCommonBottomSheetWithoutHeight( context, - child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentCancelledSuccessfully.tr()), + child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentCancelledSuccessfully.tr(context: context)), callBackFunc: () { Navigator.of(context).pop(); }, @@ -181,13 +181,13 @@ class _AppointmentDetailsPageState extends State { children: [ Row( children: [ - LocaleKeys.appointmentStatus.tr().toText16(isBold: true), + LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true), ], ), SizedBox(height: 4.h), (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) - ? LocaleKeys.notConfirmed.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) - : LocaleKeys.confirmed.tr().toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)), + ? LocaleKeys.notConfirmed.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) + : LocaleKeys.confirmed.tr(context: context).toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)), SizedBox(height: 16.h), //TODO Add countdown timer in case of LiveCare Appointment widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false @@ -199,7 +199,7 @@ class _AppointmentDetailsPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.doctorWillCallYou.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + LocaleKeys.doctorWillCallYou.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), @@ -225,7 +225,7 @@ class _AppointmentDetailsPageState extends State { MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName); }, - text: LocaleKeys.getDirections.tr(), + text: LocaleKeys.getDirections.tr(context: context), backgroundColor: AppColors.textColor.withValues(alpha: 0.8), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), textColor: AppColors.whiteColor, @@ -280,7 +280,7 @@ class _AppointmentDetailsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), - LocaleKeys.notifyMeBeforeAppointment.tr().toText11(color: AppColors.textColorLight, weight: FontWeight.w500), + LocaleKeys.notifyMeBeforeAppointment.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), ], ), const Spacer(), @@ -365,7 +365,7 @@ class _AppointmentDetailsPageState extends State { isLargeText: true, iconSize: 36.w, ).onPress(() async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingLabResults.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingLabResults.tr(context: context)); await labViewModel.getLabResultsByAppointmentNo( appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo, projectID: widget.patientAppointmentHistoryResponseModel.projectID, @@ -398,7 +398,7 @@ class _AppointmentDetailsPageState extends State { isLargeText: true, iconSize: 36.w, ).onPress(() async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingRadiologyResults.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingRadiologyResults.tr(context: context)); await radiologyViewModel.getPatientRadiologyOrdersByAppointment( appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo, projectID: widget.patientAppointmentHistoryResponseModel.projectID, @@ -425,7 +425,7 @@ class _AppointmentDetailsPageState extends State { isLargeText: true, iconSize: 36.w, ).onPress(() async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentPrescriptions.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentPrescriptions.tr(context: context)); await prescriptionsViewModel.getPrescriptionDetails( getPrescriptionRequestModel(), onSuccess: (val) { @@ -453,7 +453,7 @@ class _AppointmentDetailsPageState extends State { } else { showCommonBottomSheetWithoutHeight( context, - child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr()), + child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr(context: context)), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true, @@ -522,7 +522,7 @@ class _AppointmentDetailsPageState extends State { // ], // ), // SizedBox(height: 16.h), - // LocaleKeys.prescriptions.tr().toText18(isBold: true), + // LocaleKeys.prescriptions.tr(context: context).toText18(isBold: true), // SizedBox(height: 16.h), // Consumer(builder: (context, prescriptionVM, child) { // return prescriptionVM.isPrescriptionsDetailsLoading @@ -708,7 +708,7 @@ class _AppointmentDetailsPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.amountBeforeTax.tr().toText18(isBold: true), + LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true), Utils.getPaymentAmountWithSymbol( widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, @@ -752,7 +752,7 @@ class _AppointmentDetailsPageState extends State { ).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h), AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? CustomButton( - text: LocaleKeys.rebookAppointment.tr(), + text: LocaleKeys.rebookAppointment.tr(context: context), onPressed: () { openDoctorScheduleCalendar(); }, @@ -810,13 +810,13 @@ class _AppointmentDetailsPageState extends State { projectName: widget.patientAppointmentHistoryResponseModel.projectName, ); bookAppointmentsViewModel.setSelectedDoctor(doctor); - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingDoctorSchedulePleaseWait.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingDoctorSchedulePleaseWait.tr(context: context)); await bookAppointmentsViewModel.getDoctorFreeSlots( isBookingForLiveCare: false, onSuccess: (dynamic respData) async { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( - title: LocaleKeys.pickADate.tr(), + title: LocaleKeys.pickADate.tr(context: context), context, child: AppointmentCalendar(), isFullScreen: false, @@ -841,14 +841,14 @@ class _AppointmentDetailsPageState extends State { case 0: break; case 10: - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingAppointmentPleaseWait.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingAppointmentPleaseWait.tr(context: context)); await myAppointmentsViewModel.confirmAppointment( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onSuccess: (apiResponse) { LoaderBottomSheet.hideLoader(); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.getPatientAppointments(true, false); - showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr()), callBackFunc: (str) { + showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)), callBackFunc: (str) { Navigator.of(context).pop(); }, title: "", @@ -869,10 +869,10 @@ class _AppointmentDetailsPageState extends State { ), ); case 50: - // return LocaleKeys.confirmLiveCare.tr(); + // return LocaleKeys.confirmLiveCare.tr(context: context); case 90: showCommonBottomSheetWithoutHeight(context, - title: LocaleKeys.onlineCheckIn.tr(), + title: LocaleKeys.onlineCheckIn.tr(context: context), child: AppointmentCheckinBottomSheet( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, myAppointmentsViewModel: myAppointmentsViewModel, diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index a38a9f1..f817a89 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -90,7 +90,7 @@ class _AppointmentPaymentPageState extends State { children: [ Expanded( child: CollapsingListView( - title: LocaleKeys.appointmentPayment.tr(), + title: LocaleKeys.appointmentPayment.tr(context: context), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -248,7 +248,7 @@ class _AppointmentPaymentPageState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.insuranceExpiredOrInactive.tr() + LocaleKeys.insuranceExpiredOrInactive.tr(context: context) .toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500) .paddingSymmetrical(24.h, 0.h), CustomButton( @@ -274,12 +274,12 @@ class _AppointmentPaymentPageState extends State { ) : const SizedBox(), SizedBox(height: 24.h), - LocaleKeys.totalAmountToPay.tr().toText18(isBold: true).paddingSymmetrical(24.h, 0.h), + LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h), SizedBox(height: 17.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.amountBeforeTax.tr().toText14(isBold: true), + LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true), Utils.getPaymentAmountWithSymbol( myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, @@ -380,7 +380,7 @@ class _AppointmentPaymentPageState extends State { } void checkPaymentStatus() async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr()); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context)); if (selectedPaymentMethod == "TAMARA") { await payfortViewModel.checkTamaraPaymentStatus( transactionID: transID, @@ -438,7 +438,7 @@ class _AppointmentPaymentPageState extends State { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, - child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()), + child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true, @@ -519,7 +519,7 @@ class _AppointmentPaymentPageState extends State { } else { showCommonBottomSheetWithoutHeight( context, - child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()), + child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true, diff --git a/lib/presentation/appointments/my_appointments_page.dart b/lib/presentation/appointments/my_appointments_page.dart index 1209467..c9e7048 100644 --- a/lib/presentation/appointments/my_appointments_page.dart +++ b/lib/presentation/appointments/my_appointments_page.dart @@ -155,7 +155,7 @@ class _MyAppointmentsPageState extends State { isLoading: true, isFromHomePage: false, ), - ).paddingSymmetrical(24.h, 0.h) + ) : filteredAppointmentList.isNotEmpty ? AnimationConfiguration.staggeredList( position: index, diff --git a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart index eed45df..f3301f0 100644 --- a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart +++ b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart @@ -32,7 +32,7 @@ import '../../../emergency_services/call_ambulance/widgets/type_selection_widget // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text( -// LocaleKeys.selectHospital.tr(), +// LocaleKeys.selectHospital.tr(context: context), // style: TextStyle( // fontSize: 21, // fontWeight: FontWeight.w600, @@ -40,7 +40,7 @@ import '../../../emergency_services/call_ambulance/widgets/type_selection_widget // ), // ), // Text( -// LocaleKeys.selectHospitalSubTitle.tr(), +// LocaleKeys.selectHospitalSubTitle.tr(context: context), // style: TextStyle( // fontSize: 16, // fontWeight: FontWeight.w500, @@ -49,8 +49,8 @@ import '../../../emergency_services/call_ambulance/widgets/type_selection_widget // ), // SizedBox(height: 16.h), // TextInputWidget( -// labelText: LocaleKeys.search.tr(), -// hintText: LocaleKeys.searchHospital.tr(), +// labelText: LocaleKeys.search.tr(context: context), +// hintText: LocaleKeys.searchHospital.tr(context: context), // controller: searchText, // onChange: (value) { // appointmentsViewModel.filterHospitalListByString( @@ -135,8 +135,8 @@ class HospitalBottomSheetBody extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ TextInputWidget( - labelText: LocaleKeys.search.tr(), - hintText: LocaleKeys.searchHospital.tr(), + labelText: LocaleKeys.search.tr(context: context), + hintText: LocaleKeys.searchHospital.tr(context: context), controller: searchText, onChange: (value) { debouncer.run((){ diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index a59062d..6dcf15f 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -71,10 +71,10 @@ class LoginScreenState extends State { children: [ Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 200.h, height: 200.h, repeat: true, fit: BoxFit.cover), SizedBox(height: 130.h), // Adjusted to sizer unit - LocaleKeys.welcomeToDrSulaiman.tr().toText32(isBold: true, color: AppColors.textColor), + LocaleKeys.welcomeToDrSulaiman.tr(context: context).toText32(isBold: true, color: AppColors.textColor), SizedBox(height: 32.h), TextInputWidget( - labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", + labelText: "${LocaleKeys.nationalId.tr(context: context)} / ${LocaleKeys.fileNo.tr(context: context)}", hintText: "xxxxxxxxx", controller: authVm.nationalIdController, focusNode: _nationalIdFocusNode, @@ -87,13 +87,13 @@ class LoginScreenState extends State { isAllowLeadingIcon: true, padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 10.h), leadingIcon: AppAssets.student_card, - errorMessage: LocaleKeys.enterValidIDorIqama.tr(), + errorMessage: LocaleKeys.enterValidIDorIqama.tr(context: context), hasError: false, ), SizedBox(height: 16.h), CustomButton( height: 50.h, - text: LocaleKeys.login.tr(), + text: LocaleKeys.login.tr(context: context), icon: AppAssets.login1, iconColor: Colors.white, onPressed: () { @@ -116,10 +116,10 @@ class LoginScreenState extends State { text: TextSpan( style: context.dynamicTextStyle(color: Colors.black, fontSize: 14.f, height: 26 / 16, fontWeight: FontWeight.w500), children: [ - TextSpan(text: LocaleKeys.dontHaveAccount.tr(), style: context.dynamicTextStyle()), + TextSpan(text: LocaleKeys.dontHaveAccount.tr(context: context), style: context.dynamicTextStyle()), TextSpan(text: " "), TextSpan( - text: LocaleKeys.registernow.tr(), + text: LocaleKeys.registernow.tr(context: context), style: context.dynamicTextStyle( color: AppColors.primaryRedColor, fontSize: 14.f, // Adjusted to sizer unit @@ -172,7 +172,7 @@ class LoginScreenState extends State { Padding( padding: EdgeInsets.only(bottom: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPSMS.tr(), + text: LocaleKeys.sendOTPSMS.tr(context: context), onPressed: () async { if (ValidationUtils.isValidatePhone( phoneNumber: phoneNumberController!.text, @@ -196,14 +196,14 @@ class LoginScreenState extends State { children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 8.h), - child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor), + child: LocaleKeys.oR.tr(context: context).toText16(color: AppColors.textColor), ), ], ), Padding( padding: EdgeInsets.only(bottom: 10.h, top: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPWHATSAPP.tr(), + text: LocaleKeys.sendOTPWHATSAPP.tr(context: context), onPressed: () async { if (ValidationUtils.isValidatePhone( phoneNumber: phoneNumberController!.text, diff --git a/lib/presentation/authentication/quick_login.dart b/lib/presentation/authentication/quick_login.dart index bdeb0ff..fbcb17d 100644 --- a/lib/presentation/authentication/quick_login.dart +++ b/lib/presentation/authentication/quick_login.dart @@ -49,7 +49,7 @@ class QuickLoginState extends State { ], ), Utils.showLottie(context: context, assetPath: AppAnimations.checkmark, width: 120, height: 120, repeat: true), - LocaleKeys.allSet.tr().toText16(textAlign: TextAlign.center, weight: FontWeight.w500) + LocaleKeys.allSet.tr(context: context).toText16(textAlign: TextAlign.center, weight: FontWeight.w500) // Text( // ' TranslationBase.of(context).allSet', // textAlign: TextAlign.center, @@ -67,7 +67,7 @@ class QuickLoginState extends State { children: [ Image.asset(AppAssets.lockIcon, height: 100), SizedBox(height: 10.h), - LocaleKeys.enableQuickLogin.tr().toText26(isBold: true), + LocaleKeys.enableQuickLogin.tr(context: context).toText26(isBold: true), // Text( // ' TranslationBase.of(context).enableQuickLogin', // style: context.dynamicTextStyle( @@ -77,7 +77,7 @@ class QuickLoginState extends State { // ), // ), SizedBox(height: 5.h), - LocaleKeys.enableQuickLogin.tr().toText16(color: AppColors.quickLoginColor), + LocaleKeys.enableQuickLogin.tr(context: context).toText16(color: AppColors.quickLoginColor), // Description // Text( // 'TranslationBase.of(context).enableMsg', @@ -94,7 +94,7 @@ class QuickLoginState extends State { children: [ Expanded( child: CustomButton( - text: LocaleKeys.enableQuickLogin.tr(), + text: LocaleKeys.enableQuickLogin.tr(context: context), onPressed: () { widget.onPressed(); }, @@ -114,7 +114,7 @@ class QuickLoginState extends State { children: [ Expanded( child: CustomButton( - text: LocaleKeys.notNow.tr(), + text: LocaleKeys.notNow.tr(context: context), onPressed: () { cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: false); Navigator.pop(context, "true"); diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index fa10b95..d14419f 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -80,7 +80,7 @@ class _RegisterNew extends State { children: [ Utils.showLottie(context: context, assetPath: 'assets/animations/lottie/register.json', width: 200.w, height: 200.h, fit: BoxFit.cover, repeat: true), SizedBox(height: 16.h), - LocaleKeys.prepareToElevate.tr().toText32(isBold: true), + LocaleKeys.prepareToElevate.tr(context: context).toText32(isBold: true), SizedBox(height: 24.h), Directionality( textDirection: Directionality.of(context), @@ -96,7 +96,7 @@ class _RegisterNew extends State { ).withVerticalPadding(8.h), Divider(height: 1.h), TextInputWidget( - labelText: LocaleKeys.nationalIdNumber.tr(), + labelText: LocaleKeys.nationalIdNumber.tr(context: context), hintText: "xxxxxxxxx", controller: authVm.nationalIdController, focusNode: _nationalIdFocusNode, @@ -111,7 +111,7 @@ class _RegisterNew extends State { ).withVerticalPadding(8), Divider(height: 1), TextInputWidget( - labelText: LocaleKeys.dob.tr(), + labelText: LocaleKeys.dob.tr(context: context), hintText: "11 July, 1994", controller: authVm.dobController, focusNode: _dobFocusNode, @@ -156,7 +156,7 @@ class _RegisterNew extends State { Row( children: [ Text( - LocaleKeys.iAcceptThe.tr(), + LocaleKeys.iAcceptThe.tr(context: context), style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), ), GestureDetector( @@ -165,7 +165,7 @@ class _RegisterNew extends State { Navigator.of(context).pushNamed('/terms'); }, child: Text( - LocaleKeys.termsConditoins.tr(), + LocaleKeys.termsConditoins.tr(context: context), style: context.dynamicTextStyle( fontSize: 14.f, fontWeight: FontWeight.w500, @@ -179,7 +179,7 @@ class _RegisterNew extends State { ), // Expanded( // child: Text( - // LocaleKeys.iAcceptTermsConditions.tr().split("the").first, + // LocaleKeys.iAcceptTermsConditions.tr(context: context).split("the").first, // style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), // ), // ), @@ -188,7 +188,7 @@ class _RegisterNew extends State { ), SizedBox(height: 25.h), CustomButton( - text: LocaleKeys.registernow.tr(), + text: LocaleKeys.registernow.tr(context: context), icon: AppAssets.note_edit, onPressed: () { // Dismiss keyboard before proceeding @@ -220,10 +220,10 @@ class _RegisterNew extends State { fontWeight: FontWeight.w500, ), children: [ - TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(), style: context.dynamicTextStyle()), + TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(context: context), style: context.dynamicTextStyle()), TextSpan(text: " "), TextSpan( - text: LocaleKeys.loginNow.tr(), + text: LocaleKeys.loginNow.tr(context: context), style: context.dynamicTextStyle( color: AppColors.primaryRedColor, fontSize: 16.f, @@ -271,7 +271,7 @@ class _RegisterNew extends State { Padding( padding: const EdgeInsets.only(bottom: 10), child: CustomButton( - text: LocaleKeys.sendOTPSMS.tr(), + text: LocaleKeys.sendOTPSMS.tr(context: context), onPressed: () async { // Dismiss keyboard before validation FocusScope.of(context).unfocus(); @@ -298,14 +298,14 @@ class _RegisterNew extends State { children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 8.h), - child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor), + child: LocaleKeys.oR.tr(context: context).toText16(color: AppColors.textColor), ), ], ), Padding( padding: EdgeInsets.only(bottom: 10.h, top: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPWHATSAPP.tr(), + text: LocaleKeys.sendOTPWHATSAPP.tr(context: context), onPressed: () async { FocusScope.of(context).unfocus(); if (ValidationUtils.isValidatePhone( diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart index 71cef96..c4bdf0f 100644 --- a/lib/presentation/authentication/register_step2.dart +++ b/lib/presentation/authentication/register_step2.dart @@ -73,7 +73,7 @@ class _RegisterNew extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.personalDetailsVerification.tr().toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2), + LocaleKeys.personalDetailsVerification.tr(context: context).toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2), SizedBox(height: 24.h), Container( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), @@ -81,8 +81,8 @@ class _RegisterNew extends State { child: Column( children: [ TextInputWidget( - labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(), - hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr() : (name), + labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr(context: context) : LocaleKeys.name.tr(context: context), + hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr(context: context) : (name), controller: authVM!.isUserFromUAE() ? authVM!.nameController : null, isEnable: true, prefix: null, @@ -100,7 +100,7 @@ class _RegisterNew extends State { ).paddingSymmetrical(0.h, 16.h), Divider(height: 1.h, color: AppColors.greyColor), TextInputWidget( - labelText: LocaleKeys.nationalIdNumber.tr(), + labelText: LocaleKeys.nationalIdNumber.tr(context: context), hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.patientIdentificationId.toString() : (appState.getNHICUserData.idNumber ?? ""), controller: null, isEnable: true, @@ -120,8 +120,8 @@ class _RegisterNew extends State { builder: (context, genderType, child) { final authVM = context.read(); return DropdownWidget( - labelText: LocaleKeys.gender.tr(), - hintText: LocaleKeys.malE.tr(), + labelText: LocaleKeys.gender.tr(context: context), + hintText: LocaleKeys.malE.tr(context: context), isEnable: true, dropdownItems: GenderTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(), selectedValue: genderType != null ? (appState.isArabic() ? genderType.typeAr : genderType.type) : "", @@ -136,7 +136,7 @@ class _RegisterNew extends State { ).withVerticalPadding(8); }) : TextInputWidget( - labelText: LocaleKeys.gender.tr(), + labelText: LocaleKeys.gender.tr(context: context), hintText: (appState.getNHICUserData.gender ?? ""), controller: null, isEnable: true, @@ -157,8 +157,8 @@ class _RegisterNew extends State { builder: (context, maritalStatus, child) { final authVM = context.read(); // For onChange return DropdownWidget( - labelText: LocaleKeys.maritalStatus.tr(), - hintText: LocaleKeys.married.tr(), + labelText: LocaleKeys.maritalStatus.tr(context: context), + hintText: LocaleKeys.married.tr(context: context), isEnable: true, dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(), selectedValue: maritalStatus != null ? (appState.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "", @@ -174,7 +174,7 @@ class _RegisterNew extends State { }, ) : TextInputWidget( - labelText: LocaleKeys.maritalStatus.tr(), + labelText: LocaleKeys.maritalStatus.tr(context: context), hintText: appState.isArabic() ? (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)!.typeAr) : (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)!.type), @@ -203,8 +203,8 @@ class _RegisterNew extends State { builder: (context, data, child) { final authVM = context.read(); return DropdownWidget( - labelText: LocaleKeys.country.tr(), - hintText: LocaleKeys.uae.tr(), + labelText: LocaleKeys.country.tr(context: context), + hintText: LocaleKeys.uae.tr(context: context), isEnable: true, dropdownItems: (data.countriesList ?? []).map((e) => data.isArabic ? e.nameN ?? "" : e.name ?? "").toList(), selectedValue: data.selectedCountry != null @@ -224,7 +224,7 @@ class _RegisterNew extends State { }, ) : TextInputWidget( - labelText: LocaleKeys.nationality.tr(), + labelText: LocaleKeys.nationality.tr(context: context), hintText: appState.isArabic() ? (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "") : (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""), @@ -243,7 +243,7 @@ class _RegisterNew extends State { color: AppColors.greyColor, ), TextInputWidget( - labelText: LocaleKeys.mobileNumber.tr(), + labelText: LocaleKeys.mobileNumber.tr(context: context), hintText: (appState.getUserRegistrationPayload.patientMobileNumber.toString() ?? ""), controller: null, isEnable: false, @@ -260,7 +260,7 @@ class _RegisterNew extends State { color: AppColors.greyColor, ), TextInputWidget( - labelText: LocaleKeys.dob.tr(), + labelText: LocaleKeys.dob.tr(context: context), hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.dob! : appState.getNHICUserData.dateOfBirth ?? "", controller: authVM!.isUserFromUAE() ? authVM!.dobController : null, isEnable: false, @@ -280,7 +280,7 @@ class _RegisterNew extends State { children: [ Expanded( child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: LocaleKeys.cancel.tr(context: context), icon: AppAssets.cancel, onPressed: () { Navigator.of(context).pop(); @@ -298,7 +298,7 @@ class _RegisterNew extends State { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, - text: LocaleKeys.confirm.tr(), + text: LocaleKeys.confirm.tr(context: context), icon: AppAssets.confirm, iconColor: AppColors.whiteColor, onPressed: () { @@ -345,7 +345,7 @@ class _RegisterNew extends State { Padding( padding: const EdgeInsets.only(bottom: 10), child: CustomButton( - text: LocaleKeys.submit.tr(), + text: LocaleKeys.submit.tr(context: context), onPressed: () { if (ValidationUtils.isValidateEmail( email: authVM!.emailController.text, diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index 39d5eee..bc0c49a 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -89,8 +89,8 @@ class _BookAppointmentPageState extends State { activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), initialIndex: bookAppointmentsVM.selectedTabIndex, tabs: [ - CustomTabBarModel(null, LocaleKeys.general.tr()), - CustomTabBarModel(null, LocaleKeys.liveCare.tr()), + CustomTabBarModel(null, LocaleKeys.general.tr(context: context)), + CustomTabBarModel(null, LocaleKeys.liveCare.tr(context: context)), ], onTabChange: (index) { bookAppointmentsVM.onTabChanged(index); @@ -121,7 +121,7 @@ class _BookAppointmentPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (appState.isAuthenticated) ...[], - LocaleKeys.recentVisits.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0.h), + LocaleKeys.recentVisits.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h), SizedBox(height: 16.h), SizedBox( height: 110.h, @@ -232,8 +232,8 @@ class _BookAppointmentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.searchByClinic.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500), - LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.searchByClinic.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), + LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), ], ), ], @@ -264,8 +264,8 @@ class _BookAppointmentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.searchByDoctor.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500), - LocaleKeys.tapToSelect.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.searchByDoctor.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), + LocaleKeys.tapToSelect.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), ], ), ], @@ -294,8 +294,8 @@ class _BookAppointmentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.searchByRegion.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500), - LocaleKeys.centralRegion.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.searchByRegion.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), + LocaleKeys.centralRegion.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), ], ), ], @@ -340,8 +340,8 @@ class _BookAppointmentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.immediateConsultation.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500), - LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.immediateConsultation.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), + LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), ], ), ], @@ -382,8 +382,8 @@ class _BookAppointmentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.scheduledConsultation.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500), - LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.scheduledConsultation.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), + LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), ], ), ], @@ -412,7 +412,7 @@ class _BookAppointmentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.pharmaLiveCare.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500), + LocaleKeys.pharmaLiveCare.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), "".toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), ], ), @@ -447,9 +447,9 @@ class _BookAppointmentPageState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.notSureHelpMeChooseClinic.tr().toText16(weight: FontWeight.w600, color: AppColors.textColor), + LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText16(weight: FontWeight.w600, color: AppColors.textColor), SizedBox(height: 8.h), - LocaleKeys.mentionYourSymptomsAndFindDoctors.tr().toText12( + LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12( fontWeight: FontWeight.w500, color: AppColors.greyTextColor, ), @@ -531,7 +531,7 @@ class _BookAppointmentPageState extends State { getTitle(AppointmentViaRegionViewmodel data) { if (data.selectedRegionId == null) { - return LocaleKeys.selectRegion.tr().toText20(weight: FontWeight.w600); + return LocaleKeys.selectRegion.tr(context: context).toText20(weight: FontWeight.w600); } else { return Transform.flip( flipX: data.isArabic ? true : false, @@ -558,8 +558,8 @@ class _BookAppointmentPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.immediateService.tr().toText18(color: AppColors.textColor, isBold: true), - LocaleKeys.noNeedToWaitGetMedicalConsultation.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + LocaleKeys.immediateService.tr(context: context).toText18(color: AppColors.textColor, isBold: true), + LocaleKeys.noNeedToWaitGetMedicalConsultation.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), @@ -574,7 +574,7 @@ class _BookAppointmentPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.noVisitRequired.tr().toText18(color: AppColors.textColor, isBold: true), + LocaleKeys.noVisitRequired.tr(context: context).toText18(color: AppColors.textColor, isBold: true), LocaleKeys.livecarePoint5.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), @@ -590,8 +590,8 @@ class _BookAppointmentPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.doctorWillContact.tr().toText18(color: AppColors.textColor, isBold: true), - LocaleKeys.specialisedDoctorWillContactYou.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + LocaleKeys.doctorWillContact.tr(context: context).toText18(color: AppColors.textColor, isBold: true), + LocaleKeys.specialisedDoctorWillContactYou.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), @@ -606,8 +606,8 @@ class _BookAppointmentPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.freeMedicineDelivery.tr().toText18(color: AppColors.textColor, isBold: true), - LocaleKeys.offersFreeMedicineDelivery.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + LocaleKeys.freeMedicineDelivery.tr(context: context).toText18(color: AppColors.textColor, isBold: true), + LocaleKeys.offersFreeMedicineDelivery.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), diff --git a/lib/presentation/book_appointment/select_clinic_page.dart b/lib/presentation/book_appointment/select_clinic_page.dart index e76e1c9..d96c9da 100644 --- a/lib/presentation/book_appointment/select_clinic_page.dart +++ b/lib/presentation/book_appointment/select_clinic_page.dart @@ -79,7 +79,7 @@ class _SelectClinicPageState extends State { decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))), padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h), child: CustomButton( - text: LocaleKeys.bookAppo.tr(), + text: LocaleKeys.bookAppo.tr(context: context), onPressed: () { if (widget.calculatedResult["clinicId"] == null) { bookAppointmentsViewModel.setIsDoctorsListLoading(true); @@ -1097,7 +1097,7 @@ class _SelectClinicPageState extends State { getTitle(AppointmentViaRegionViewmodel data) { if (data.selectedRegionId == null) { - return LocaleKeys.selectRegion.tr().toText20(weight: FontWeight.w600); + return LocaleKeys.selectRegion.tr(context: context).toText20(weight: FontWeight.w600); } else { return Transform.flip( flipX: data.isArabic ? true : false, @@ -1185,7 +1185,7 @@ class _SelectClinicPageState extends State { children: [ Expanded( child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: LocaleKeys.cancel.tr(context: context), onPressed: () { bookAppointmentsViewModel.setIsContinueDentalPlan(false); bookAppointmentsViewModel.setIsChiefComplaintsListLoading(true); @@ -1206,7 +1206,7 @@ class _SelectClinicPageState extends State { SizedBox(width: 8.h), Expanded( child: CustomButton( - text: LocaleKeys.confirm.tr(), + text: LocaleKeys.confirm.tr(context: context), onPressed: () async { bookAppointmentsViewModel.setIsContinueDentalPlan(true); Navigator.of(context).pop(); diff --git a/lib/presentation/book_appointment/select_doctor_page.dart b/lib/presentation/book_appointment/select_doctor_page.dart index e57ed51..3723bee 100644 --- a/lib/presentation/book_appointment/select_doctor_page.dart +++ b/lib/presentation/book_appointment/select_doctor_page.dart @@ -178,7 +178,7 @@ class _SelectDoctorPageState extends State { children: [ LocaleKeys.nearestAppo.tr(context: context).toText13(isBold: true), SizedBox(height: 4.h), - LocaleKeys.viewNearestAppos.toText11(color: AppColors.textColorLight, weight: FontWeight.w500), + LocaleKeys.viewNearestAppos.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), ], ), const Spacer(), diff --git a/lib/presentation/book_appointment/widgets/appointment_calendar.dart b/lib/presentation/book_appointment/widgets/appointment_calendar.dart index c91e7a7..8fa72d4 100644 --- a/lib/presentation/book_appointment/widgets/appointment_calendar.dart +++ b/lib/presentation/book_appointment/widgets/appointment_calendar.dart @@ -204,13 +204,13 @@ class _AppointmentCalendarState extends State { children: [ Lottie.asset(AppAnimations.errorAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill), SizedBox(height: 8.h), - (LocaleKeys.loginToUseService.tr()).toText16(color: AppColors.blackColor), + (LocaleKeys.loginToUseService.tr(context: context)).toText16(color: AppColors.blackColor), SizedBox(height: 16.h), Row( children: [ Expanded( child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: LocaleKeys.cancel.tr(context: context), onPressed: () { Navigator.of(context).pop(); }, @@ -224,7 +224,7 @@ class _AppointmentCalendarState extends State { SizedBox(width: 8.h), Expanded( child: CustomButton( - text: LocaleKeys.confirm.tr(), + text: LocaleKeys.confirm.tr(context: context), onPressed: () async { Navigator.of(context).pop(); Navigator.pushAndRemoveUntil( diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index fd19fe5..bf4ef3e 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -50,7 +50,14 @@ class ServicesPage extends StatelessWidget { late MedicalFileViewModel medicalFileViewModel; late final List hmgServices = [ - HmgServicesComponentModel(11, LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, bgColor: AppColors.primaryRedColor, true, route: null, onTap: () async { + HmgServicesComponentModel( + 11, + LocaleKeys.emergencyServices.tr(), + "", + AppAssets.emergency_services_icon, + bgColor: AppColors.primaryRedColor, + true, + route: null, onTap: () async { if (getIt.get().isAuthenticated) { getIt.get().flushData(); getIt.get().getTransportationOrders( @@ -59,7 +66,7 @@ class ServicesPage extends StatelessWidget { getIt.get().getRRTOrders( showLoader: false, ); - Navigator.of(GetIt.instance().navigatorKey.currentContext!).push( + Navigator.of(getIt.get().navigatorKey.currentContext!).push( CustomPageRoute( page: EmergencyServicesPage(), settings: const RouteSettings(name: '/EmergencyServicesPage'), @@ -78,7 +85,8 @@ class ServicesPage extends StatelessWidget { true, route: AppRoutes.bookAppointmentPage, ), - HmgServicesComponentModel(5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async { + HmgServicesComponentModel( + 5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async { if (getIt.get().isAuthenticated) { getIt.get().pushPageRoute(AppRoutes.comprehensiveCheckupPage); } else { @@ -131,7 +139,7 @@ class ServicesPage extends StatelessWidget { }, ), HmgServicesComponentModel( - 11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async { + 11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async { if (getIt.get().isAuthenticated) { getIt.get().pushPageRoute(AppRoutes.eReferralPage); } else { @@ -387,19 +395,19 @@ class ServicesPage extends StatelessWidget { ? CustomButton( height: 40.h, icon: AppAssets.recharge_icon, - iconSize: 16.w, - iconColor: AppColors.infoColor, - textColor: AppColors.infoColor, - text: LocaleKeys.recharge.tr(), - borderWidth: 0.w, - fontWeight: FontWeight.w500, - borderColor: Colors.transparent, - backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), - padding: EdgeInsets.all(8.w), - fontSize: 12.f, - onPressed: () { - Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); - }, + iconSize: 16.w, + iconColor: AppColors.infoColor, + textColor: AppColors.infoColor, + text: LocaleKeys.recharge.tr(), + borderWidth: 0.w, + fontWeight: FontWeight.w500, + borderColor: Colors.transparent, + backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), + padding: EdgeInsets.all(8.w), + fontSize: 12.f, + onPressed: () { + Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); + }, ) : SizedBox.shrink(), ], @@ -438,60 +446,60 @@ class ServicesPage extends StatelessWidget { getIt.get().isAuthenticated ? Wrap( spacing: -8.h, - // runSpacing: 0.h, - children: [ - Utils.buildImgWithAssets( - icon: AppAssets.babyGirlImg, - height: 28.h, - width: 28.w, - border: 1, - fit: BoxFit.contain, - borderRadius: 50.r, - ), - Utils.buildImgWithAssets( - icon: AppAssets.femaleImg, - height: 28.h, - width: 28.w, - border: 1, - borderRadius: 50.r, - fit: BoxFit.contain, - ), - Utils.buildImgWithAssets( - icon: AppAssets.maleImg, - height: 28.h, - width: 28.w, - border: 1, - borderRadius: 50.r, - fit: BoxFit.contain, - ), - ], + // runSpacing: 0.h, + children: [ + Utils.buildImgWithAssets( + icon: AppAssets.babyGirlImg, + height: 28.h, + width: 28.w, + border: 1, + fit: BoxFit.contain, + borderRadius: 50.r, + ), + Utils.buildImgWithAssets( + icon: AppAssets.femaleImg, + height: 28.h, + width: 28.w, + border: 1, + borderRadius: 50.r, + fit: BoxFit.contain, + ), + Utils.buildImgWithAssets( + icon: AppAssets.maleImg, + height: 28.h, + width: 28.w, + border: 1, + borderRadius: 50.r, + fit: BoxFit.contain, + ), + ], ) : LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2), Spacer(), getIt.get().isAuthenticated ? CustomButton( height: 40.h, - icon: AppAssets.add_icon, - iconSize: 16.w, - iconColor: AppColors.primaryRedColor, - textColor: AppColors.primaryRedColor, - text: LocaleKeys.addMember.tr(), - borderWidth: 0.w, - fontWeight: FontWeight.w500, - borderColor: Colors.transparent, - backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08), - padding: EdgeInsets.all(8.w), - fontSize: 12.f, - onPressed: () { - DialogService dialogService = getIt.get(); - medicalFileViewModel.clearAuthValues(); - dialogService.showAddFamilyFileSheet( - label: LocaleKeys.addFamilyMember.tr(), - message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(), - onVerificationPress: () { - medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); - }); - }, + icon: AppAssets.add_icon, + iconSize: 16.w, + iconColor: AppColors.primaryRedColor, + textColor: AppColors.primaryRedColor, + text: LocaleKeys.addMember.tr(), + borderWidth: 0.w, + fontWeight: FontWeight.w500, + borderColor: Colors.transparent, + backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08), + padding: EdgeInsets.all(8.w), + fontSize: 12.f, + onPressed: () { + DialogService dialogService = getIt.get(); + medicalFileViewModel.clearAuthValues(); + dialogService.showAddFamilyFileSheet( + label: LocaleKeys.addFamilyMember.tr(), + message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(), + onVerificationPress: () { + medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); + }); + }, ) : SizedBox.shrink(), ], diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index ef2832b..c52d5e1 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -1,4 +1,6 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/home/data/service_card_data.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -7,8 +9,8 @@ class LandingPageData { ServiceCardData( serviceName: "emergency", icon: AppAssets.emergency_services_icon, - title: "Emergency", - subtitle: "Services", + title: LocaleKeys.emergency, + subtitle: LocaleKeys.services2, backgroundColor: AppColors.primaryRedColor, iconColor: AppColors.whiteColor, textColor: AppColors.whiteColor, @@ -17,8 +19,8 @@ class LandingPageData { ServiceCardData( serviceName: "indoor_navigation", icon: AppAssets.indoor_nav_icon, - title: "Indoor", - subtitle: "Navigation", + title: LocaleKeys.indoor, + subtitle: LocaleKeys.navigation, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -27,8 +29,8 @@ class LandingPageData { ServiceCardData( serviceName: "search_doctor", icon: AppAssets.search_doctor_icon, - title: "Search", - subtitle: "Doctor", + title: LocaleKeys.search, + subtitle: LocaleKeys.doctor, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -37,8 +39,8 @@ class LandingPageData { ServiceCardData( serviceName: "health_calculators_and_converts", icon: AppAssets.health_calculators_icon, - title: "Health", - subtitle: "Calculators", + title: LocaleKeys.health, + subtitle: LocaleKeys.calculators, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -47,8 +49,8 @@ class LandingPageData { ServiceCardData( serviceName: "health_converters", icon: AppAssets.health_converters_icon, - title: "Health", - subtitle: "Converters", + title: LocaleKeys.health, + subtitle: LocaleKeys.converters, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -57,8 +59,8 @@ class LandingPageData { ServiceCardData( serviceName: "parking_guide", icon: AppAssets.car_parking_icon, - title: "Parking", - subtitle: "Guide", + title: LocaleKeys.parking, + subtitle: LocaleKeys.guide, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -70,8 +72,8 @@ class LandingPageData { ServiceCardData( serviceName: "emergency", icon: AppAssets.emergency_services_icon, - title: "Emergency", - subtitle: "Services", + title: LocaleKeys.emergency, + subtitle: LocaleKeys.services2, backgroundColor: AppColors.primaryRedColor, iconColor: AppColors.whiteColor, textColor: AppColors.whiteColor, @@ -80,8 +82,8 @@ class LandingPageData { ServiceCardData( serviceName: "lab_results", icon: AppAssets.home_lab_result_icon, - title: "Lab", - subtitle: "Results", + title: LocaleKeys.lab, + subtitle: LocaleKeys.labSubtitle, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -90,8 +92,8 @@ class LandingPageData { ServiceCardData( serviceName: "radiology_results", icon: AppAssets.my_radiology_icon, - title: "Radiology", - subtitle: "Results", + title: LocaleKeys.radiology, + subtitle: LocaleKeys.radiologySubtitle, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -100,8 +102,8 @@ class LandingPageData { ServiceCardData( serviceName: "prescriptions", icon: AppAssets.my_prescription_icon, - title: "Prescriptions", - subtitle: "Details", + title: LocaleKeys.medicinesSubtitle, + subtitle: LocaleKeys.details, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -110,8 +112,8 @@ class LandingPageData { ServiceCardData( serviceName: "insurance_update", icon: AppAssets.insurance_update_icon, - title: "Insurance", - subtitle: "Details", + title: LocaleKeys.insurance, + subtitle: LocaleKeys.details, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -130,8 +132,8 @@ class LandingPageData { ServiceCardData( serviceName: "sick_leaves", icon: AppAssets.my_sick_leave_icon, - title: "Sick", - subtitle: "Leaves", + title: LocaleKeys.sick, + subtitle: LocaleKeys.sickSubtitle, backgroundColor: AppColors.whiteColor, iconColor: AppColors.blackColor, textColor: AppColors.blackColor, @@ -143,8 +145,8 @@ class LandingPageData { ServiceCardData( serviceName: "livecare", icon: AppAssets.small_livecare_icon, - title: "LiveCare", - subtitle: "Explore our app, View our services and offers", + title: LocaleKeys.liveCare, + subtitle: LocaleKeys.liveCareServiceDesc, largeCardIcon: AppAssets.liveCareService, backgroundColor: AppColors.successColor, iconColor: AppColors.whiteColor, @@ -161,8 +163,8 @@ class LandingPageData { ServiceCardData( serviceName: "home_health_care", icon: AppAssets.homeBottom, - title: "Home Health Care", - subtitle: "Explore our app, View our services and offers", + title: LocaleKeys.homeHealthCare, + subtitle: LocaleKeys.liveCareServiceDesc, largeCardIcon: AppAssets.homeHealthCareService, backgroundColor: AppColors.primaryRedColor, iconColor: AppColors.whiteColor, @@ -171,8 +173,8 @@ class LandingPageData { ServiceCardData( serviceName: "pharmacy", icon: AppAssets.pharmacy_icon, //359846 - title: "Pharmacy", - subtitle: "Explore our app, View our services and offers", + title: LocaleKeys.hmgPharmacy, + subtitle: LocaleKeys.liveCareServiceDesc, largeCardIcon: AppAssets.pharmacyService, backgroundColor: AppColors.pharmacyBGColor, iconColor: null, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index fc400c4..b633404 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -28,7 +28,6 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart'; -import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart'; @@ -62,8 +61,6 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart'; import 'package:provider/provider.dart'; -import '../active_medication/active_medication_page.dart'; - import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart'; class LandingPage extends StatefulWidget { @@ -198,10 +195,11 @@ class _LandingPageState extends State { mainAxisSize: MainAxisSize.min, spacing: 12.h, children: [ - Stack(children: [ - Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 18.h, width: 18.h).onPress(() async { - if (appState.isAuthenticated) { - notificationsViewModel.setNotificationStatusID(2); + appState.isAuthenticated + ? Stack(children: [ + Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 18.h, width: 18.h).onPress(() async { + if (appState.isAuthenticated) { + notificationsViewModel.setNotificationStatusID(2); notificationsViewModel.getAllNotifications(); Navigator.of(context).push( CustomPageRoute( @@ -236,7 +234,8 @@ class _LandingPageState extends State { ), ) : SizedBox.shrink(), - ]), + ]) + : SizedBox.shrink(), Utils.buildSvgWithAssets(icon: AppAssets.indoor_nav_icon, height: 18.h, width: 18.h).onPress(() { openIndoorNavigationBottomSheet(context); }), @@ -249,6 +248,11 @@ class _LandingPageState extends State { isFullScreen: false, ); }), + !appState.isAuthenticated + ? Utils.buildSvgWithAssets(icon: appState.isArabic() ? AppAssets.enLangIcon : AppAssets.arLangIcon, height: 18.h, width: 18.h).onPress(() { + context.setLocale(appState.isArabic() ? Locale('en', 'US') : Locale('ar', 'SA')); + }) + : SizedBox.shrink() ], ); }), @@ -305,7 +309,7 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Appointments & Visits".toText16(isBold: true), + LocaleKeys.appointmentsAndVisits.tr(context: context).toText16(isBold: true), Row( children: [ LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor), @@ -394,22 +398,23 @@ class _LandingPageState extends State { layout: SwiperLayout.STACK, loop: true, itemWidth: MediaQuery.of(context).size.width - 48.h, - indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: AxisDirection.right, - controller: _controller, - itemHeight: 255.h, - pagination: SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: 240.h + 8 + 24), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), - ), - itemBuilder: (BuildContext context, int index) { - return getIndexSwiperCard(index); - }, - ) + indicatorLayout: PageIndicatorLayout.COLOR, + axisDirection: AxisDirection.right, + controller: _controller, + itemHeight: 255.h, + pagination: SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: 240.h + 8 + 24), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + ), + itemBuilder: (BuildContext context, int index) { + return getIndexSwiperCard(index); + }, + ) : Container( width: double.infinity, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + decoration: RoundedRectangleBorder() + .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), child: Padding( padding: EdgeInsets.all(16.h), child: Column( @@ -465,11 +470,15 @@ class _LandingPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget( - labelText: "ER Online Check-In Request", + labelText: LocaleKeys.erOnlineCheckInRequest.tr(context: context), backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10), textColor: AppColors.primaryRedColor, ), - Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor), + Utils.buildSvgWithAssets( + icon: AppAssets.appointment_checkin_icon, + width: 24.h, + height: 24.h, + iconColor: AppColors.primaryRedColor), ], ), SizedBox(height: 8.h), @@ -597,10 +606,10 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Services".toText16(isBold: true), + LocaleKeys.services2.tr(context: context).toText16(isBold: true), Row( children: [ - "View all services".toText12(color: AppColors.primaryRedColor), + LocaleKeys.viewAllServices.tr(context: context).toText12(color: AppColors.primaryRedColor), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], @@ -690,10 +699,18 @@ class _LandingPageState extends State { myAppointmentsViewModel.patientQueueDetailsList.first.queueNo!.toText12(isBold: true), SizedBox(width: 8.w), AppCustomChipWidget( - deleteIcon: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppAssets.call_for_vitals : AppAssets.call_for_doctor, - labelText: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? LocaleKeys.callForVitalSigns.tr() : LocaleKeys.callForDoctor.tr(), - iconColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor : AppColors.successColor, - textColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor : AppColors.successColor, + deleteIcon: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 + ? AppAssets.call_for_vitals + : AppAssets.call_for_doctor, + labelText: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 + ? LocaleKeys.callForVitalSigns.tr() + : LocaleKeys.callForDoctor.tr(), + iconColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 + ? AppColors.primaryRedColor + : AppColors.successColor, + textColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 + ? AppColors.primaryRedColor + : AppColors.successColor, iconSize: 14.w, backgroundColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor.withValues(alpha: 0.1) @@ -707,7 +724,8 @@ class _LandingPageState extends State { : SizedBox(height: 12.h), SizedBox(height: 5.h), CustomButton( - text: Utils.getCardButtonText(myAppointmentsViewModel.currentQueueStatus, myAppointmentsViewModel.currentPatientQueueDetails.roomNo ?? ""), + text: Utils.getCardButtonText( + myAppointmentsViewModel.currentQueueStatus, myAppointmentsViewModel.currentPatientQueueDetails.roomNo ?? ""), onPressed: () {}, backgroundColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus), borderColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus).withValues(alpha: 0.01), @@ -761,7 +779,8 @@ class _LandingPageState extends State { SizedBox(width: 8.w), AppCustomChipWidget( icon: AppAssets.appointment_calendar_icon, - labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)), + labelText: DateUtil.formatDateToDate( + DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)), ], ), Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h), @@ -769,9 +788,12 @@ class _LandingPageState extends State { ], ), SizedBox(height: 10.h), - LocaleKeys.halaFirstName.tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context).toText16(isBold: true), + LocaleKeys.halaFirstName + .tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context).toText16(isBold: true), SizedBox(height: 8.h), - LocaleKeys.yourTurnIsAfterPatients.tr(namedArgs: {'count': immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount.toString()}, context: context).toText14(isBold: true), + LocaleKeys.yourTurnIsAfterPatients.tr( + namedArgs: {'count': immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount.toString()}, + context: context).toText14(isBold: true), SizedBox(height: 8.h), Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -840,7 +862,7 @@ class _LandingPageState extends State { hasShadow: true, ), child: AppointmentCard( - patientAppointmentHistoryResponseModel: myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.first, + patientAppointmentHistoryResponseModel: myAppointmentsViewModel.patientAppointmentsHistoryList.first, myAppointmentsViewModel: myAppointmentsViewModel, bookAppointmentsViewModel: bookAppointmentsViewModel, isLoading: false, @@ -886,7 +908,7 @@ class _LandingPageState extends State { } } else if (index == 2) { if ((myAppointmentsViewModel.isPatientHasQueueAppointment || immediateLiveCareViewModel.patientHasPendingLiveCareRequest) && - myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.isNotEmpty) { + todoSectionViewModel.patientAncillaryOrdersList.isNotEmpty) { return AncillaryOrderCard( order: todoSectionViewModel.patientAncillaryOrdersList.first, isLoading: false, @@ -978,7 +1000,6 @@ class _LandingPageState extends State { isCloseButtonVisible: true, child: StatefulBuilder( builder: (context, setState) { - return RateAppointmentDoctor(); }, ), diff --git a/lib/presentation/home/navigation_screen.dart b/lib/presentation/home/navigation_screen.dart index 43cc3b9..b22e46b 100644 --- a/lib/presentation/home/navigation_screen.dart +++ b/lib/presentation/home/navigation_screen.dart @@ -8,11 +8,8 @@ import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart'; import 'package:hmg_patient_app_new/presentation/hmg_services/services_page.dart'; import 'package:hmg_patient_app_new/presentation/home/landing_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; -import 'package:hmg_patient_app_new/presentation/symptoms_checker/user_info_selection.dart'; -import 'package:hmg_patient_app_new/presentation/todo_section/todo_page.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart'; -import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; class LandingNavigation extends StatefulWidget { const LandingNavigation({super.key}); @@ -53,11 +50,7 @@ class _LandingNavigationState extends State { } if (_currentIndex == 3) { if (appState.isAuthenticated) { - Navigator.of(context).push( - CustomPageRoute( - page: UserInfoSelectionScreen(), - ), - ); + context.navigateWithName(AppRoutes.userInfoSelection); } else { Utils.openWebView( url: 'https://x.com/HMG', diff --git a/lib/presentation/home/widgets/habib_wallet_card.dart b/lib/presentation/home/widgets/habib_wallet_card.dart index 9058c8f..fb04baf 100644 --- a/lib/presentation/home/widgets/habib_wallet_card.dart +++ b/lib/presentation/home/widgets/habib_wallet_card.dart @@ -23,10 +23,10 @@ class HabibWalletCard extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "My Balance".toText16(isBold: true), + LocaleKeys.myBalance.tr(context: context).toText16(isBold: true), Row( children: [ - "View all services".toText12(color: AppColors.primaryRedColor), + LocaleKeys.viewAllServices.tr(context: context).toText12(color: AppColors.primaryRedColor), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], @@ -54,7 +54,7 @@ class HabibWalletCard extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Habib Wallet".toText15(isBold: true), + LocaleKeys.habibWallet.tr(context: context).toText15(isBold: true), Container( height: 40.h, width: 40.h, @@ -94,7 +94,7 @@ class HabibWalletCard extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 50.h), child: Row( children: [ - "View details".toText12(color: AppColors.primaryRedColor), + LocaleKeys.viewDetails.tr(context: context).toText12(color: AppColors.primaryRedColor), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], diff --git a/lib/presentation/home/widgets/large_service_card.dart b/lib/presentation/home/widgets/large_service_card.dart index 6025ba8..9292004 100644 --- a/lib/presentation/home/widgets/large_service_card.dart +++ b/lib/presentation/home/widgets/large_service_card.dart @@ -89,16 +89,15 @@ class LargeServiceCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - serviceCardData.title.toText14(isBold: true, color: AppColors.textColor), - SizedBox(width: 6.h), - serviceCardData.subtitle.toText14(weight: FontWeight.w500, color: AppColors.textColorLight), + serviceCardData.title.tr(context: context).toText14(isBold: true, color: AppColors.textColor), + serviceCardData.subtitle.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), ], ), ), ], - ).paddingSymmetrical(16.w, 20.h), + ).paddingSymmetrical(12.w, 24.h), CustomButton( - text: serviceCardData.isBold ? LocaleKeys.visitPharmacyOnline.tr() : LocaleKeys.bookNow.tr(context: context), + text: serviceCardData.isBold ? LocaleKeys.visitPharmacyOnline.tr(context: context) : LocaleKeys.bookNow.tr(context: context), onPressed: () { handleOnTap(); }, diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart index 49db8bf..390c001 100644 --- a/lib/presentation/home/widgets/small_service_card.dart +++ b/lib/presentation/home/widgets/small_service_card.dart @@ -65,8 +65,8 @@ class SmallServiceCard extends StatelessWidget { children: [ Utils.buildSvgWithAssets(icon: icon, iconColor: iconColor, width: 32.h, height: 32.h), SizedBox(height: 6.h), - title.toText11(color: textColor, isBold: isBold, isCenter: true), - subtitle.toText11(color: textColor, isBold: isBold, isCenter: true), + title.tr(context: context).toText11(color: textColor, isBold: isBold, isCenter: true), + subtitle.tr(context: context).toText11(color: textColor, isBold: isBold, isCenter: true), ], ), ), @@ -173,7 +173,7 @@ class SmallServiceCard extends StatelessWidget { void openIndoorNavigationBottomSheet(BuildContext context) { showCommonBottomSheetWithoutHeight( - title: LocaleKeys.selectHospital.tr(), + title: LocaleKeys.selectHospital.tr(context: context), context, child: ChangeNotifierProvider( create: (context) => HospitalSelectionBottomSheetViewModel(getIt()), diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index 799f574..538f250 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingToolbar( title: LocaleKeys.labResults.tr(), search: () async { final lavVM = Provider.of(context, listen: false); if (lavVM.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; lavVM.filterLabReports(value); } } }, child: Consumer( builder: (context, model, child) { return SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { model.setIsSortByClinic(true); }, backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { model.setIsSortByClinic(false); }, backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: model.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? CustomChipWidget( chipText: selectedFilterText!, chipType: ChipTypeEnum.alert, isSelected: true, ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available model.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (model.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: model.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = model.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder() .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( model.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ...group.map((order) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr()}: ${order.orderNo!}"), ), AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), ), AppCustomChipWidget( labelText: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex:2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { model.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), SizedBox(height: 12.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), SizedBox(height: 12.h), ], ); }), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (model.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: model.indexedCharacterForUniqueTest, details: model.uniqueTestsList, labViewModel: model, rangeViewModel: rangeViewModel, appState: _appState, ) ], ) ); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingToolbar( title: LocaleKeys.labResults.tr(context: context), search: () async { final lavVM = Provider.of(context, listen: false); if (lavVM.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; lavVM.filterLabReports(value); } } }, child: Consumer( builder: (context, model, child) { return SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr(context: context)), CustomTabBarModel(null, LocaleKeys.byTest.tr(context: context)), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { model.setIsSortByClinic(true); }, backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { model.setIsSortByClinic(false); }, backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: model.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? CustomChipWidget( chipText: selectedFilterText!, chipType: ChipTypeEnum.alert, isSelected: true, ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available model.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (model.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: model.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = model.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder() .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( model.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ...group.map((order) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), ), AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), ), AppCustomChipWidget( labelText: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex:2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { model.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), SizedBox(height: 12.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), SizedBox(height: 12.h), ], ); }), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (model.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: model.indexedCharacterForUniqueTest, details: model.uniqueTestsList, labViewModel: model, rangeViewModel: rangeViewModel, appState: _appState, ) ], ) ); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index eb39fef..29e15ee 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -74,7 +74,7 @@ class LabResultDetails extends StatelessWidget { .getSeverityText( recentLabResult.calculatedResultFlag ?? "", ) - .tr() + .tr(context: context) .toText10(weight: FontWeight.w500, color: AppColors.greyTextColor), Utils.buildSvgWithAssets( icon: AppAssets.lab_result_indicator, @@ -151,8 +151,8 @@ class LabResultDetails extends StatelessWidget { children: [ Text( labmodel.isGraphVisible - ? LocaleKeys.historyFlowchart.tr() - : LocaleKeys.history.tr(), + ? LocaleKeys.historyFlowchart.tr(context: context) + : LocaleKeys.history.tr(context: context), style: TextStyle( fontSize: 16, fontFamily: 'Poppins', @@ -181,7 +181,7 @@ class LabResultDetails extends StatelessWidget { height: 24) .onPress(() { showCommonBottomSheetWithoutHeight( - title: LocaleKeys.setTheDateRange.tr(), + title: LocaleKeys.setTheDateRange.tr(context: context), context, child: DateRangeSelector( onRangeSelected: (start, end) { diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index ad2461f..fa8a591 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -192,7 +192,7 @@ class _MedicalFilePageState extends State { SizedBox(width: 4.h), Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w) ], - ).withHorizontalPadding(24.w).onPress(() { + ).onPress(() { DialogService dialogService = getIt.get(); dialogService.showFamilyBottomSheetWithoutH( label: LocaleKeys.familyTitle.tr(context: context), @@ -276,12 +276,12 @@ class _MedicalFilePageState extends State { runSpacing: 4.h, children: [ AppCustomChipWidget( - labelText: "${appState.getAuthenticatedUser()!.age} Years Old", + labelText: LocaleKeys.ageYearsOld.tr(namedArgs: {'age': '${appState.getAuthenticatedUser()!.age}', 'yearsOld': LocaleKeys.yearsOld.tr(context: context)}, context: context), labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w), ), AppCustomChipWidget( icon: AppAssets.blood_icon, - labelText: "Blood: ${appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup}", + labelText: LocaleKeys.bloodGroup.tr(namedArgs: {'bloodType': appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup}, context: context), iconColor: AppColors.primaryRedColor, labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), padding: EdgeInsets.zero, @@ -319,7 +319,7 @@ class _MedicalFilePageState extends State { LocaleKeys.vitalSigns.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), Row( children: [ - LocaleKeys.viewAll.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], @@ -359,7 +359,7 @@ class _MedicalFilePageState extends State { children: [ Utils.buildSvgWithAssets(icon: AppAssets.call_for_vitals, width: 32.h, height: 32.h), SizedBox(height: 12.h), - LocaleKeys.noVitalSignsRecordedYet.tr().toText12(isCenter: true), + LocaleKeys.noVitalSignsRecordedYet.tr(context: context).toText12(isCenter: true), ], ), ), @@ -439,14 +439,14 @@ class _MedicalFilePageState extends State { itemPadding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 14.h), items: [ ExpandableListItem( - title: "Medical Services".toText18(weight: FontWeight.w600), + title: LocaleKeys.medicalServices.tr(context: context).toText18(weight: FontWeight.w600), children: [ SizedBox(height: 10.h), getSelectedTabData(0), ], ), ExpandableListItem( - title: "Medical Reports".toText18( + title: LocaleKeys.medicalReports.tr(context: context).toText18( weight: FontWeight.w600, ), expandedBackgroundColor: Colors.transparent, @@ -455,7 +455,7 @@ class _MedicalFilePageState extends State { getSelectedTabData(2), ]), ExpandableListItem( - title: "Insurance & Payments".toText18(weight: FontWeight.w600), + title: LocaleKeys.insuranceAndPayments.tr(context: context).toText18(weight: FontWeight.w600), expandedBackgroundColor: Colors.transparent, children: [ SizedBox(height: 10.h), @@ -463,7 +463,7 @@ class _MedicalFilePageState extends State { ], ), ExpandableListItem( - title: "Tracker & Others".toText18(weight: FontWeight.w600), + title: LocaleKeys.trackerAndOthers.tr(context: context).toText18(weight: FontWeight.w600), expandedBackgroundColor: Colors.transparent, children: [ SizedBox(height: 10.h), @@ -577,10 +577,10 @@ class _MedicalFilePageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.appointmentsAndVisits.tr().toText16(weight: FontWeight.w500, letterSpacing: -0.2), + LocaleKeys.appointmentsAndVisits.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), Row( children: [ - LocaleKeys.viewAll.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], @@ -645,6 +645,7 @@ class _MedicalFilePageState extends State { scrollDirection: Axis.horizontal, shrinkWrap: true, itemCount: myAppointmentsVM.patientAppointmentsHistoryList.length, + padding: EdgeInsets.zero, itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, @@ -699,12 +700,12 @@ class _MedicalFilePageState extends State { ), )); }, - separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 12.h), + separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 12.w), ), - ).paddingSymmetrical(0.w, 0.h); + ); }), SizedBox(height: 10.h), - LocaleKeys.labAndRadiology.tr().toText16(weight: FontWeight.w500, letterSpacing: -0.2), + LocaleKeys.labAndRadiology.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), SizedBox(height: 16.h), Row( children: [ @@ -743,7 +744,7 @@ class _MedicalFilePageState extends State { ], ).paddingSymmetrical(0.w, 0.h), SizedBox(height: 24.h), - LocaleKeys.activeMedicationsAndPrescriptions.tr().toText16(weight: FontWeight.w500, letterSpacing: -0.2), + LocaleKeys.activeMedicationsAndPrescriptions.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), SizedBox(height: 16.h), Consumer(builder: (context, prescriptionVM, child) { return prescriptionVM.isPrescriptionsOrdersLoading @@ -901,7 +902,7 @@ class _MedicalFilePageState extends State { LocaleKeys.myDoctor.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), Row( children: [ - LocaleKeys.viewAll.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), SizedBox(width: 2.w), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], @@ -1351,7 +1352,7 @@ class _MedicalFilePageState extends State { SizedBox(height: 16.h), Row( children: [ - LocaleKeys.others.tr().toText16(weight: FontWeight.w500, color: AppColors.textColor), + LocaleKeys.others.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.textColor), ], ), SizedBox(height: 16.h), @@ -1484,7 +1485,7 @@ class _MedicalFilePageState extends State { Expanded( child: _buildVitalSignCard( icon: AppAssets.bmiVital, - label: "BMI", + label: LocaleKeys.bmi.tr(context: context), value: vitalSign.bodyMassIndex?.toString() ?? '--', unit: '', status: vitalSign.bodyMassIndex != null ? _getBMIStatus(vitalSign.bodyMassIndex) : null, @@ -1495,7 +1496,7 @@ class _MedicalFilePageState extends State { Expanded( child: _buildVitalSignCard( icon: AppAssets.heightVital, - label: "Height", + label: LocaleKeys.height.tr(context: context), value: vitalSign.heightCm?.toString() ?? '--', unit: 'cm', status: null, @@ -1511,7 +1512,7 @@ class _MedicalFilePageState extends State { Expanded( child: _buildVitalSignCard( icon: AppAssets.weightVital, - label: "Weight", + label: LocaleKeys.weight.tr(context: context), value: vitalSign.weightKg?.toString() ?? '--', unit: 'kg', status: vitalSign.weightKg != null ? "Normal" : null, @@ -1522,7 +1523,7 @@ class _MedicalFilePageState extends State { Expanded( child: _buildVitalSignCard( icon: AppAssets.bloodPressure, - label: "Blood Pressure", + label: LocaleKeys.bloodPressure.tr(context: context), value: vitalSign.bloodPressureLower != null && vitalSign.bloodPressureHigher != null ? "${vitalSign.bloodPressureHigher}/${vitalSign.bloodPressureLower}" : '--', diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index df2efb2..88dfb13 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -117,8 +117,8 @@ class ProfileSettingsState extends State { onAddFamilyMemberPress: () { DialogService dialogService = getIt.get(); dialogService.showAddFamilyFileSheet( - label: LocaleKeys.addFamilyMember.tr(), - message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(), + label: LocaleKeys.addFamilyMember.tr(context: context), + message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), onVerificationPress: () { medicalVm.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); }); @@ -199,18 +199,18 @@ class ProfileSettingsState extends State { 1.divider, actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () {}), 1.divider, - actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(), () {}, switchValue: true), + actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true), ], ), ), - LocaleKeys.personalInformation.tr().toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), + LocaleKeys.personalInformation.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), Container( margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h), padding: EdgeInsets.only(top: 4.h, bottom: 4.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), child: Column( children: [ - actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(), () {}), + actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () {}), // 1.divider, // actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}), // 1.divider, @@ -220,7 +220,7 @@ class ProfileSettingsState extends State { ], ), ), - LocaleKeys.helpAndSupport.tr().toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), + LocaleKeys.helpAndSupport.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), Container( margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h), padding: EdgeInsets.only(top: 4.h, bottom: 4.h), @@ -231,9 +231,9 @@ class ProfileSettingsState extends State { launchUrl(Uri.parse("tel://" + "+966 11 525 9999")); }, trailingLabel: "011 525 9999"), 1.divider, - actionItem(AppAssets.permission, LocaleKeys.permissions.tr(), () {}, trailingLabel: "Location, Camera"), + actionItem(AppAssets.permission, LocaleKeys.permissions.tr(context: context), () {}, trailingLabel: "Location, Camera"), 1.divider, - actionItem(AppAssets.rate, LocaleKeys.rateApp.tr(), () { + actionItem(AppAssets.rate, LocaleKeys.rateApp.tr(context: context), () { if (Platform.isAndroid) { Utils.openWebView( url: 'https://play.google.com/store/apps/details?id=com.ejada.hmg', @@ -245,7 +245,7 @@ class ProfileSettingsState extends State { } }, isExternalLink: true), 1.divider, - actionItem(AppAssets.privacy_terms, LocaleKeys.privacyPolicy.tr(), () { + actionItem(AppAssets.privacy_terms, LocaleKeys.privacyPolicy.tr(context: context), () { Utils.openWebView( url: 'https://hmg.com/en/Pages/Privacy.aspx', ); @@ -262,7 +262,7 @@ class ProfileSettingsState extends State { CustomButton( height: 56.h, icon: AppAssets.minus, - text: LocaleKeys.deactivateAccount.tr(), + text: LocaleKeys.deactivateAccount.tr(context: context), onPressed: () {}, ).paddingAll(24.w), ], @@ -345,7 +345,8 @@ class FamilyCardWidget extends StatelessWidget { ), ], ).expanded, - Icon(Icons.qr_code, size: 56.h) + // Icon(Icons.qr_code, size: 56.h) + Image.network("https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${profile.responseId.toString()}", fit: BoxFit.contain, height: 56.h, width: 56.w) ], ), SizedBox(height: 4.h), @@ -420,7 +421,7 @@ class FamilyCardWidget extends StatelessWidget { ), ], ).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 12.h), - 1.divider, + 1.divider.paddingSymmetrical(16.w, 0.h), _buildActionButton(appState), ], ), @@ -444,7 +445,7 @@ class FamilyCardWidget extends StatelessWidget { return CustomButton( icon: canSwitch ? AppAssets.switch_user : AppAssets.add_family, - text: canSwitch ? LocaleKeys.switchFamilyFile.tr() : LocaleKeys.addANewFamilyMember.tr(), + text: canSwitch ? LocaleKeys.switchAccount.tr() : LocaleKeys.addANewFamilyMember.tr(), onPressed: canSwitch ? () => onFamilySwitchPress(profile) : onAddFamilyMemberPress, backgroundColor: canSwitch ? AppColors.secondaryLightRedColor : AppColors.primaryRedColor, borderColor: canSwitch ? AppColors.secondaryLightRedColor : AppColors.primaryRedColor, @@ -460,7 +461,7 @@ class FamilyCardWidget extends StatelessWidget { return CustomButton( icon: AppAssets.switch_user, - text: canSwitchBack ? LocaleKeys.switchBackFamilyFile.tr() : LocaleKeys.switchLogin.tr(), + text: canSwitchBack ? LocaleKeys.switchBackFamilyFile.tr() : LocaleKeys.switchAccount.tr(), backgroundColor: canSwitchBack ? AppColors.primaryRedColor : Colors.grey.shade200, borderColor: canSwitchBack ? AppColors.primaryRedColor : Colors.grey.shade200, textColor: canSwitchBack ? AppColors.whiteColor : AppColors.greyTextColor, diff --git a/lib/presentation/symptoms_checker/organ_selector_screen.dart b/lib/presentation/symptoms_checker/organ_selector_screen.dart index cc956dc..e3944c2 100644 --- a/lib/presentation/symptoms_checker/organ_selector_screen.dart +++ b/lib/presentation/symptoms_checker/organ_selector_screen.dart @@ -7,7 +7,6 @@ import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.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/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; @@ -44,7 +43,9 @@ class _OrganSelectorPageState extends State { ); return; } - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.pleaseWait.tr(context: context),); + LoaderBottomSheet.showLoader( + loadingText: LocaleKeys.pleaseWait.tr(context: context), + ); final String userName = 'guest_user'; final String password = '123456'; @@ -102,7 +103,7 @@ class _OrganSelectorPageState extends State { width: 32.h, height: 32.h, ), - padding: const EdgeInsets.only(left: 12), + padding: EdgeInsetsDirectional.only(start: 12), onPressed: () => Navigator.pop(context), highlightColor: Colors.transparent, ), @@ -125,21 +126,32 @@ class _OrganSelectorPageState extends State { } Widget _buildBodyViewer(SymptomsCheckerViewModel viewModel) { - return Padding( - padding: EdgeInsets.fromLTRB(16.h, 16.h, 16.h, 60.h), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 600), - transitionBuilder: (child, animation) => _build3DFlipTransition(child, animation), - switchInCurve: Curves.easeInOut, - switchOutCurve: Curves.easeInOut, - child: InteractiveBodyWidget( - key: ValueKey(viewModel.currentView), - bodyImageAsset: viewModel.currentView == BodyView.front ? AppAssets.fullBodyFront : AppAssets.fullBodyBack, - organs: viewModel.currentOrgans, - selectedOrganIds: viewModel.selectedOrganIds, - onOrganTap: viewModel.toggleOrganSelection, - isBodyHidden: viewModel.isBodyHidden, - tooltipOrganId: viewModel.tooltipOrganId, + return GestureDetector( + onHorizontalDragEnd: (details) { + // Swipe left or right to toggle view + if (details.primaryVelocity != null) { + if (details.primaryVelocity! < -200 || details.primaryVelocity! > 200) { + viewModel.toggleView(); + } + } + }, + child: Padding( + padding: EdgeInsets.fromLTRB(16.h, 16.h, 16.h, 60.h), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 600), + transitionBuilder: (child, animation) => _build3DFlipTransition(child, animation), + switchInCurve: Curves.easeInOut, + switchOutCurve: Curves.easeInOut, + child: InteractiveBodyWidget( + key: ValueKey(viewModel.currentView), + bodyImageAsset: viewModel.currentView == BodyView.front ? AppAssets.fullBodyFront : AppAssets.fullBodyBack, + organs: viewModel.currentOrgans, + selectedOrganIds: viewModel.selectedOrganIds, + onOrganTap: viewModel.toggleOrganSelection, + isBodyHidden: viewModel.isBodyHidden, + tooltipOrganId: viewModel.tooltipOrganId, + isArabic: _appState.isArabic(), + ), ), ), ); @@ -169,8 +181,8 @@ class _OrganSelectorPageState extends State { } Widget _buildViewToggleButtons(SymptomsCheckerViewModel viewModel) { - return Positioned( - left: 16.w, + return PositionedDirectional( + start: 16.w, top: 36.h, child: Column( children: [ @@ -275,6 +287,8 @@ class _OrganSelectorPageState extends State { ); } + final isArabic = _appState.isArabic(); + return ConstrainedBox( constraints: BoxConstraints(maxHeight: 150.h), child: SingleChildScrollView( @@ -284,7 +298,7 @@ class _OrganSelectorPageState extends State { runSpacing: 8.h, children: viewModel.selectedOrgans.map((organ) { return AppCustomChipWidget( - labelText: organ.description, + labelText: organ.getLocalizedDescription(isArabic), backgroundColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, deleteIcon: AppAssets.cancel, @@ -313,8 +327,8 @@ class _OrganSelectorPageState extends State { } Widget _buildExpandCollapseButton(SymptomsCheckerViewModel viewModel) { - return Positioned( - right: 24.w, + return PositionedDirectional( + end: 24.w, top: -24.h, child: GestureDetector( onTap: viewModel.toggleBottomSheet, @@ -331,13 +345,16 @@ class _OrganSelectorPageState extends State { borderRadius: 11.r, ), child: Center( - child: AnimatedRotation( - duration: const Duration(milliseconds: 300), - turns: viewModel.isBottomSheetExpanded ? 0.25 : -0.25, - child: Utils.buildSvgWithAssets( - icon: AppAssets.arrowRight, - width: 25.w, - height: 25.h, + child: Transform.flip( + flipX: _appState.isArabic(), + child: AnimatedRotation( + duration: const Duration(milliseconds: 300), + turns: viewModel.isBottomSheetExpanded ? 0.25 : -0.25, + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrowRight, + width: 25.w, + height: 25.h, + ), ), ), ), diff --git a/lib/presentation/symptoms_checker/possible_conditions_screen.dart b/lib/presentation/symptoms_checker/possible_conditions_screen.dart index bc233a4..8fb0e0f 100644 --- a/lib/presentation/symptoms_checker/possible_conditions_screen.dart +++ b/lib/presentation/symptoms_checker/possible_conditions_screen.dart @@ -3,13 +3,14 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.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/symptoms_checker/models/conditions_model.dart'; -import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/condition_card.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; @@ -45,7 +46,7 @@ class PossibleConditionsPage extends StatelessWidget { ); } - Widget _buildPredictionsList(BuildContext context, List conditions) { + Widget _buildPredictionsList(BuildContext context, List conditions, List symptoms) { if (conditions.isEmpty) { return Center( child: Padding( @@ -74,19 +75,13 @@ class PossibleConditionsPage extends StatelessWidget { physics: NeverScrollableScrollPhysics(), separatorBuilder: (context, index) => SizedBox(height: 16.h), itemBuilder: (context, index) { - final conditionModel = conditions[index]; + final condition = conditions[index]; return ConditionCard( - icon: conditionModel.icon, - title: conditionModel.title, - percentage: conditionModel.percentage, - tagText: conditionModel.tagText, - clinic: conditionModel.clinic, - symptoms: conditionModel.symptoms, - description: conditionModel.description, - possibleConditionsSeverityEnum: conditionModel.possibleConditionsSeverityEnum, + condition: condition, + symptoms: symptoms, onActionPressed: () { dialogService.showErrorBottomSheet( - message: 'We are not available for a week. May you Rest In Peace :(', + message: 'icd10 Code is ${condition.conditionDetails?.icd10Code}. We need to get the clinics mapped against this code.', ); }, ); @@ -102,7 +97,7 @@ class PossibleConditionsPage extends StatelessWidget { title: LocaleKeys.notice.tr(context: context), context, child: Utils.getWarningWidget( - loadingText: LocaleKeys.areYouSureYouWantToRestartOrganSelection.tr(context: context), + loadingText: LocaleKeys.areYouSureYouWantToExitProgress.tr(context: context), isShowActionButtons: true, onCancelTap: () => Navigator.pop(context), onConfirmTap: () => onConfirm(), @@ -113,47 +108,88 @@ class PossibleConditionsPage extends StatelessWidget { ); } - _restartOrganSelection(BuildContext context) async { - final symptomsCheckerVm = context.read(); - symptomsCheckerVm.reset(); - context.pop(); - await Future.delayed(Duration(seconds: 1)).whenComplete(() => context.pop()); - } + Widget _buildInfoTile({required PossibleConditionsSeverityEnum severityEnum, required BuildContext context}) { + String title; + String description; + Color dotColor; - _navigateToLandingPage() { - NavigationService navigationService = getIt.get(); - navigationService.replaceAllRoutesAndNavigateToLanding(); - } + switch (severityEnum) { + case PossibleConditionsSeverityEnum.monitorOnly: + title = LocaleKeys.monitor.tr(context: context); + description = LocaleKeys.monitorDescription.tr(context: context); + dotColor = AppColors.chipColorMonitor; + break; + case PossibleConditionsSeverityEnum.seekMedicalAdvice: + title = LocaleKeys.seekMedicalAdvice.tr(context: context); + description = LocaleKeys.seekMedicalAdviceDescription.tr(context: context); + dotColor = AppColors.chipColorSeekMedicalAdvice; + break; + case PossibleConditionsSeverityEnum.emergency: + title = LocaleKeys.emergency.tr(context: context); + description = LocaleKeys.emergencyDescription.tr(context: context); + dotColor = AppColors.chipColorEmergency; + break; + } - _buildTrailingSection(BuildContext context) { return Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - height: 40.h, - padding: EdgeInsets.all(8.w), - child: Center( - child: Utils.buildSvgWithAssets( - icon: AppAssets.refreshIcon, - height: 20.h, - width: 20.w, - iconColor: AppColors.textColor, - ), + height: 14.h, + width: 14.w, + decoration: BoxDecoration(shape: BoxShape.circle, color: dotColor), + ).paddingOnly(top: 3.h), + SizedBox(width: 8.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title.toText14(weight: FontWeight.w600, color: AppColors.textColor), + SizedBox(height: 4.h), + description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + ], ), - ).onPress(() => _buildConfirmationBottomSheet(context: context, onConfirm: () => _restartOrganSelection(context))), - Container( - height: 40.h, - padding: EdgeInsets.all(8.w), - child: Center( - child: Utils.buildSvgWithAssets( - icon: AppAssets.homeBorderedIcon, - height: 20.h, - width: 20.w, - iconColor: AppColors.textColor, - ), - ), - ).onPress(() => _buildConfirmationBottomSheet(context: context, onConfirm: () => _navigateToLandingPage())), + ), ], - ).paddingSymmetrical(20.w, 0); + ); + } + + _buildSeverityDetailsBottomsheet({required BuildContext context}) { + return showCommonBottomSheetWithoutHeight( + title: LocaleKeys.colorScience.tr(context: context), + context, + child: Container( + padding: EdgeInsets.all(16.w), + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + child: Column( + children: [ + _buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.monitorOnly, context: context), + Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1), + _buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, context: context), + Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1), + _buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.emergency, context: context), + ], + ), + ), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + + _buildTrailingSection(BuildContext context) { + return Container( + height: 40.h, + padding: EdgeInsets.all(8.w), + child: Center( + child: Utils.buildSvgWithAssets( + icon: AppAssets.coloredDotsIcon, + height: 20.h, + width: 20.w, + ), + ), + ).onPress(() => _buildSeverityDetailsBottomsheet(context: context)); } @override @@ -162,13 +198,32 @@ class PossibleConditionsPage extends StatelessWidget { backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( title: LocaleKeys.possibleConditions.tr(context: context), + leadingCallback: () => _buildConfirmationBottomSheet( + context: context, + onConfirm: () { + context.pop(); + final SymptomsCheckerViewModel symptomsCheckerViewModel = context.read(); + symptomsCheckerViewModel.reset(); // Clear all symptoms checker data + final navigationService = getIt.get(); + navigationService.replaceAllRoutesAndNavigateToLanding(); + }, + ), trailing: _buildTrailingSection(context), child: Consumer( builder: (context, symptomsCheckerViewModel, child) { - if (symptomsCheckerViewModel.isPossibleConditionsLoading || symptomsCheckerViewModel.isPossibleConditionsLoading) { + if (symptomsCheckerViewModel.isPossibleConditionsLoading || symptomsCheckerViewModel.isTriageDiagnosisLoading) { return _buildLoadingShimmer(); } - return _buildPredictionsList(context, dummyConditions); + // Get conditions directly from ViewModel + final conditions = symptomsCheckerViewModel.currentConditions ?? []; + // Get selected symptoms names for display + final symptoms = symptomsCheckerViewModel + .getAllSelectedSymptoms() + .map((s) => s.commonName ?? s.name ?? '') + .where((name) => name.isNotEmpty) + .take(3) + .toList(); + return _buildPredictionsList(context, conditions, symptoms); }, ), ), diff --git a/lib/presentation/symptoms_checker/risk_factors_screen.dart b/lib/presentation/symptoms_checker/risk_factors_screen.dart index 6ee4f29..8264b8b 100644 --- a/lib/presentation/symptoms_checker/risk_factors_screen.dart +++ b/lib/presentation/symptoms_checker/risk_factors_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; @@ -25,11 +26,13 @@ class RiskFactorsScreen extends StatefulWidget { class _RiskFactorsScreenState extends State { late DialogService dialogService; + late AppState _appState; @override void initState() { super.initState(); dialogService = getIt(); + _appState = getIt(); // Fetch risk factors based on selected symptoms WidgetsBinding.instance.addPostFrameCallback((_) { final viewModel = context.read(); @@ -90,6 +93,8 @@ class _RiskFactorsScreenState extends State { } Widget _buildRiskFactorsList(SymptomsCheckerViewModel viewModel) { + final isArabic = _appState.isArabic(); + return Container( key: ValueKey(viewModel.riskFactorsList.length), width: double.infinity, @@ -100,7 +105,7 @@ class _RiskFactorsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ ...viewModel.riskFactorsList.map((factor) { - return _buildRiskFactorItem(viewModel, factor.id ?? '', factor.getDisplayName()); + return _buildRiskFactorItem(viewModel, factor.id ?? '', factor.getDisplayName(isArabic: isArabic)); }), SizedBox(height: 12.w), Row( @@ -196,7 +201,7 @@ class _RiskFactorsScreenState extends State { border: Border.all(color: AppColors.bottomNAVBorder, width: 1), ), child: Text( - 'Not Applicable Risk Factor', + 'Not Applicable Risk Factor'.needTranslation, style: TextStyle(fontSize: 14.f, color: AppColors.textColor), ), ).toShimmer2(isShow: true, radius: 24.r); diff --git a/lib/presentation/symptoms_checker/suggestions_screen.dart b/lib/presentation/symptoms_checker/suggestions_screen.dart index f09ebd5..8d32b7f 100644 --- a/lib/presentation/symptoms_checker/suggestions_screen.dart +++ b/lib/presentation/symptoms_checker/suggestions_screen.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; @@ -24,11 +25,13 @@ class SuggestionsScreen extends StatefulWidget { class _SuggestionsScreenState extends State { late DialogService dialogService; + late AppState _appState; @override void initState() { super.initState(); dialogService = getIt(); + _appState = getIt(); // Initialize symptom groups based on selected organs WidgetsBinding.instance.addPostFrameCallback((_) { final viewModel = context.read(); @@ -92,6 +95,8 @@ class _SuggestionsScreenState extends State { } Widget _buildSuggestionsList(SymptomsCheckerViewModel viewModel) { + final isArabic = _appState.isArabic(); + return Container( key: ValueKey(viewModel.suggestionsList.length), width: double.infinity, @@ -102,7 +107,7 @@ class _SuggestionsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ ...viewModel.suggestionsList.map((factor) { - return _buildSuggestionItem(viewModel, factor.id ?? '', factor.getDisplayName()); + return _buildSuggestionItem(viewModel, factor.id ?? '', factor.getDisplayName(isArabic: isArabic)); }), SizedBox(height: 12.w), Row( @@ -115,7 +120,7 @@ class _SuggestionsScreenState extends State { ), SizedBox(width: 12.w), Expanded( - child: "This is a list of symptoms suggested by our AI, based on the information gathered so far during the interview".toText12( + child: LocaleKeys.suggestionAIListDescription.tr(context: context).toText12( color: AppColors.greyInfoTextColor, ), ) diff --git a/lib/presentation/symptoms_checker/symptoms_selector_screen.dart b/lib/presentation/symptoms_checker/symptoms_selector_screen.dart index b4ba802..2bfcb62 100644 --- a/lib/presentation/symptoms_checker/symptoms_selector_screen.dart +++ b/lib/presentation/symptoms_checker/symptoms_selector_screen.dart @@ -1,15 +1,16 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; -import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -26,11 +27,13 @@ class SymptomsSelectorPage extends StatefulWidget { class _SymptomsSelectorPageState extends State { late DialogService dialogService; + late AppState _appState; @override void initState() { super.initState(); dialogService = getIt(); + _appState = getIt(); // Initialize symptom groups based on selected organs WidgetsBinding.instance.addPostFrameCallback((_) { final viewModel = context.read(); @@ -82,10 +85,12 @@ class _SymptomsSelectorPageState extends State { title: LocaleKeys.symptomsSelector.tr(), leadingCallback: () => _buildConfirmationBottomSheet( context: context, - onConfirm: () => { - context.pop(), - context.pop(), - }), + onConfirm: () { + context.pop(); + viewModel.reset(); // Clear all symptoms checker data + final navigationService = getIt.get(); + navigationService.replaceAllRoutesAndNavigateToLanding(); + }), child: viewModel.isBodySymptomsLoading ? _buildLoadingShimmer() : viewModel.organSymptomsResults.isEmpty @@ -98,10 +103,11 @@ class _SymptomsSelectorPageState extends State { // Find matching organ ID from selected organs String? organId; String? organName; + final isArabic = _appState.isArabic(); for (var organ in viewModel.selectedOrgans) { if (organ.name == organResult.name) { organId = organ.id; - organName = organ.description; + organName = organ.getLocalizedDescription(isArabic); break; } } @@ -139,6 +145,8 @@ class _SymptomsSelectorPageState extends State { String organName, List symptoms, ) { + final isArabic = _appState.isArabic(); + return Container( width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 24.w), @@ -152,7 +160,7 @@ class _SymptomsSelectorPageState extends State { children: [ Expanded( child: Text( - 'Possible symptoms related to "$organName"', + '${LocaleKeys.possibleSymptomsRelatedTo.tr(context: context)} "$organName"', style: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, color: AppColors.textColor), ), ), @@ -164,7 +172,7 @@ class _SymptomsSelectorPageState extends State { spacing: 8.w, children: symptoms.map((symptom) { final symptomId = symptom.id ?? ''; - final symptomLabel = symptom.getDisplayName(false); // Pass isArabic from AppState if needed + final symptomLabel = symptom.getDisplayName(isArabic); bool isSelected = viewModel.isSymptomSelected(organId, symptomId); return GestureDetector( onTap: () => viewModel.toggleSymptomSelection(organId, symptomId), @@ -304,7 +312,7 @@ class _SymptomsSelectorPageState extends State { fontSize: 16.f, ), ), - ], + ], ), SizedBox(height: 24.h), ], diff --git a/lib/presentation/symptoms_checker/triage_screen.dart b/lib/presentation/symptoms_checker/triage_screen.dart index 526136c..a7975e2 100644 --- a/lib/presentation/symptoms_checker/triage_screen.dart +++ b/lib/presentation/symptoms_checker/triage_screen.dart @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; @@ -14,6 +15,7 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_v import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -31,12 +33,14 @@ class TriagePage extends StatefulWidget { class _TriagePageState extends State { late SymptomsCheckerViewModel viewModel; late DialogService dialogService; + late AppState _appState; @override void initState() { super.initState(); viewModel = context.read(); dialogService = getIt.get(); + _appState = getIt.get(); // Start triage process when screen loads WidgetsBinding.instance.addPostFrameCallback((_) { @@ -119,12 +123,14 @@ class _TriagePageState extends State { SizedBox(height: 8.h), LocaleKeys.emergencyTriage.tr(context: context).toText28(color: AppColors.whiteColor, isBold: true), SizedBox(height: 8.h), - LocaleKeys.emergencyEvidenceDetected.tr(context: context) - .toText14(color: AppColors.whiteColor, weight: FontWeight.w500), + LocaleKeys.emergencyEvidenceDetected.tr(context: context).toText14(color: AppColors.whiteColor, weight: FontWeight.w500), SizedBox(height: 24.h), CustomButton( text: LocaleKeys.confirm.tr(context: context), - onPressed: () async => Navigator.of(context).pop(), + onPressed: () { + context.pop(); + context.navigateWithName(AppRoutes.possibleConditionsPage); + }, backgroundColor: AppColors.whiteColor, borderColor: AppColors.whiteColor, textColor: AppColors.primaryRedColor, @@ -197,7 +203,7 @@ class _TriagePageState extends State { // Call API with updated evidence viewModel.getDiagnosisForTriage( age: viewModel.selectedAge!, - sex: viewModel.selectedGender!.toLowerCase(), + gender: viewModel.selectedGender!.toLowerCase() == "male" ? 1 : 2, evidenceIds: initialEvidenceIds, triageEvidence: triageEvidence, language: viewModel.appState.isArabic() ? 'ar' : 'en', @@ -307,8 +313,10 @@ class _TriagePageState extends State { isShowActionButtons: true, onCancelTap: () => Navigator.pop(context), onConfirmTap: () { - Navigator.pop(context); context.pop(); + viewModel.reset(); // Clear all symptoms checker data + final navigationService = getIt.get(); + navigationService.replaceAllRoutesAndNavigateToLanding(); }, ), callBackFunc: () {}, @@ -431,7 +439,8 @@ class _TriagePageState extends State { Widget _buildStickyBottomCard(BuildContext context, SymptomsCheckerViewModel viewModel) { // Get the top condition with highest probability final conditions = viewModel.currentConditions ?? []; - String suggestedCondition = "Analyzing..."; + final isArabic = _appState.isArabic(); + String suggestedCondition = LocaleKeys.analyzing.tr(context: context); double probability = 0.0; if (conditions.isNotEmpty) { @@ -440,7 +449,7 @@ class _TriagePageState extends State { sortedConditions.sort((a, b) => (b.probability ?? 0.0).compareTo(a.probability ?? 0.0)); final topCondition = sortedConditions.first; - suggestedCondition = topCondition.commonName ?? topCondition.name ?? "Unknown"; + suggestedCondition = topCondition.getDisplayName(isArabic: isArabic); probability = (topCondition.probability ?? 0.0) * 100; // Convert to percentage } // final bool isHighConfidence = probability >= 70.0; diff --git a/lib/presentation/symptoms_checker/user_info_selection.dart b/lib/presentation/symptoms_checker/user_info_selection.dart index 9973d54..1d05c5a 100644 --- a/lib/presentation/symptoms_checker/user_info_selection.dart +++ b/lib/presentation/symptoms_checker/user_info_selection.dart @@ -16,14 +16,14 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:provider/provider.dart'; -class UserInfoSelectionScreen extends StatefulWidget { - const UserInfoSelectionScreen({super.key}); +class UserInfoSelectionPage extends StatefulWidget { + const UserInfoSelectionPage({super.key}); @override - State createState() => _UserInfoSelectionScreenState(); + State createState() => _UserInfoSelectionPageState(); } -class _UserInfoSelectionScreenState extends State { +class _UserInfoSelectionPageState extends State { @override void initState() { super.initState(); @@ -43,13 +43,10 @@ class _UserInfoSelectionScreenState extends State { if (user == null) return; // Populate gender (gender is int: 1=Male, 2=Female) + // Use internal keys (male/female) for storage if (user.gender != null) { - String genderStr = user.gender == 1 - ? "Male" - : user.gender == 2 - ? "Female" - : "Other"; - viewModel.setGender(genderStr); + String genderKey = user.gender == 1 ? "male" : user.gender == 2 ? "female" : "other"; + viewModel.setGender(genderKey); } if (user.dateofBirth != null && user.dateofBirth!.isNotEmpty) { @@ -84,12 +81,13 @@ class _UserInfoSelectionScreenState extends State { child: Row( children: [ Container( - height: 40.h, - width: 40.h, - margin: EdgeInsets.only(right: 10.h), - padding: EdgeInsets.all(8.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 12.r, color: AppColors.greyColor), - child: Utils.buildSvgWithAssets(icon: leadingIcon, iconColor: iconColor)), + height: 40.h, + width: 40.h, + margin: EdgeInsetsDirectional.only(end: 10.h), + padding: EdgeInsets.all(8.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 12.r, color: AppColors.greyColor), + child: Utils.buildSvgWithAssets(icon: leadingIcon, iconColor: iconColor), + ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -112,6 +110,20 @@ class _UserInfoSelectionScreenState extends State { ).paddingSymmetrical(0, 8.h); } + /// Convert internal gender key to localized display string + String _getLocalizedGender(String? genderKey, BuildContext context) { + if (genderKey == null) return LocaleKeys.notSet.tr(context: context); + + final lowerKey = genderKey.toLowerCase(); + if (lowerKey == "male") { + return LocaleKeys.malE.tr(context: context); + } else if (lowerKey == "female") { + return LocaleKeys.femaleGender.tr(context: context); + } else { + return genderKey; // Return as-is if not recognized + } + } + @override Widget build(BuildContext context) { AppState appState = getIt.get(); @@ -151,14 +163,16 @@ class _UserInfoSelectionScreenState extends State { viewModel.selectedWeight == null; // Get display values - String genderText = viewModel.selectedGender ?? LocaleKeys.notSet.tr(context: context); + String genderText = _getLocalizedGender(viewModel.selectedGender, context); // Show age calculated from DOB (prefer viewModel's age, fallback to calculated from user's DOB) int? displayAge = viewModel.selectedAge ?? userAgeFromDOB; String ageText = displayAge != null ? "$displayAge ${LocaleKeys.years.tr(context: context)}" : LocaleKeys.notSet.tr(context: context); - String heightText = - viewModel.selectedHeight != null ? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}" : LocaleKeys.notSet.tr(context: context); - String weightText = - viewModel.selectedWeight != null ? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}" : LocaleKeys.notSet.tr(context: context); + String heightText = viewModel.selectedHeight != null + ? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}" + : LocaleKeys.notSet.tr(context: context); + String weightText = viewModel.selectedWeight != null + ? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}" + : LocaleKeys.notSet.tr(context: context); return Column( children: [ @@ -176,9 +190,9 @@ class _UserInfoSelectionScreenState extends State { child: Column( children: [ LocaleKeys.helloIsYourInformationUpToDate.tr(namedArgs: {'name': name}).toText16( - weight: FontWeight.w600, - color: AppColors.textColor, - ), + weight: FontWeight.w600, + color: AppColors.textColor, + ), SizedBox(height: 32.h), _buildEditInfoTile( context: context, diff --git a/lib/presentation/symptoms_checker/user_info_selection/pages/gender_selection_page.dart b/lib/presentation/symptoms_checker/user_info_selection/pages/gender_selection_page.dart index 6eaae8c..07f44f1 100644 --- a/lib/presentation/symptoms_checker/user_info_selection/pages/gender_selection_page.dart +++ b/lib/presentation/symptoms_checker/user_info_selection/pages/gender_selection_page.dart @@ -15,12 +15,16 @@ class GenderSelectionPage extends StatelessWidget { final String? selectedGender; final Function(String) onGenderSelected; - GenderSelectionPage({ + const GenderSelectionPage({ super.key, required this.selectedGender, required this.onGenderSelected, }); + // Internal gender keys (constant, not localized) + static const String maleKey = "male"; + static const String femaleKey = "female"; + _buildGenderOption(String iconPng, String label, bool isSelected) { return Container( height: 160.h, @@ -40,7 +44,27 @@ class GenderSelectionPage extends StatelessWidget { ); } - final genders = ["Male", "Female"]; + /// Check if the selected gender matches the given key + /// Handles both internal keys and localized strings + bool _isGenderSelected(String genderKey, String? currentSelection, BuildContext context) { + if (currentSelection == null) return false; + + final lowerSelection = currentSelection.toLowerCase(); + + if (genderKey == maleKey) { + // Check against internal key, English, and Arabic + return lowerSelection == maleKey || + lowerSelection == "male" || + currentSelection == LocaleKeys.malE.tr(context: context) || + currentSelection == "ذكر"; + } else { + // Check against internal key, English, and Arabic + return lowerSelection == femaleKey || + lowerSelection == "female" || + currentSelection == LocaleKeys.femaleGender.tr(context: context) || + currentSelection == "أنثى"; + } + } @override Widget build(BuildContext context) { @@ -56,16 +80,25 @@ class GenderSelectionPage extends StatelessWidget { children: [ Expanded( child: InkWell( - onTap: () => onGenderSelected(genders[0]), - child: _buildGenderOption(AppAssets.maleIcon, LocaleKeys.malE.tr(context: context), symptomsViewModel.selectedGender == genders[0]), + onTap: () => onGenderSelected(maleKey), + child: _buildGenderOption( + AppAssets.maleIcon, + LocaleKeys.malE.tr(context: context), + _isGenderSelected(maleKey, symptomsViewModel.selectedGender, context), + ), ), ), SizedBox(width: 16.w), Expanded( - child: InkWell( - onTap: () => onGenderSelected(genders[1]), - child: _buildGenderOption(AppAssets.femaleIcon, LocaleKeys.femaleGender.tr(context: context), symptomsViewModel.selectedGender == genders[1]), - )) + child: InkWell( + onTap: () => onGenderSelected(femaleKey), + child: _buildGenderOption( + AppAssets.femaleIcon, + LocaleKeys.femaleGender.tr(context: context), + _isGenderSelected(femaleKey, symptomsViewModel.selectedGender, context), + ), + ), + ) ], ), ], diff --git a/lib/presentation/symptoms_checker/user_info_selection/user_info_flow_manager.dart b/lib/presentation/symptoms_checker/user_info_selection/user_info_flow_manager.dart index b5df05b..fdfe228 100644 --- a/lib/presentation/symptoms_checker/user_info_selection/user_info_flow_manager.dart +++ b/lib/presentation/symptoms_checker/user_info_selection/user_info_flow_manager.dart @@ -4,7 +4,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; -import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/user_info_selection/pages/age_selection_page.dart'; @@ -29,13 +28,15 @@ class _UserInfoFlowManagerState extends State { late PageController _pageController; late SymptomsCheckerViewModel _viewModel; - // Page titles - final List _pageTitles = [ - "Your Gender", - "Your Birth Date", - "Your Height", - "Your Weight", - ]; + // Get localized page titles + List _getPageTitles(BuildContext context) { + return [ + LocaleKeys.genderSymptoms.tr(context: context), + LocaleKeys.dateOfBirthSymptoms.tr(context: context), + LocaleKeys.heightSymptoms.tr(context: context), + LocaleKeys.weightSymptoms.tr(context: context), + ]; + } @override void initState() { @@ -187,9 +188,11 @@ class _UserInfoFlowManagerState extends State { ? // Single page edit mode - show only Save button CustomButton( text: LocaleKeys.save.tr(context: context), - onPressed: _onNext, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, + isDisabled: !(viewModel.isCurrentUserInfoPageValid), + onPressed: () => viewModel.isCurrentUserInfoPageValid ? _onNext() : () {}, + backgroundColor: + viewModel.isCurrentUserInfoPageValid ? AppColors.primaryRedColor : AppColors.primaryRedColor.withValues(alpha: 0.5), + borderColor: viewModel.isCurrentUserInfoPageValid ? AppColors.primaryRedColor : AppColors.primaryRedColor.withValues(alpha: 0.5), textColor: AppColors.whiteColor, fontSize: 16.f, ) @@ -228,6 +231,8 @@ class _UserInfoFlowManagerState extends State { @override Widget build(BuildContext context) { + final pageTitles = _getPageTitles(context); + return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Column( @@ -235,7 +240,7 @@ class _UserInfoFlowManagerState extends State { Expanded( child: CollapsingListView( physics: NeverScrollableScrollPhysics(), - title: _pageTitles[_viewModel.userInfoCurrentPage], + title: pageTitles[_viewModel.userInfoCurrentPage], isLeading: true, child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/presentation/symptoms_checker/widgets/condition_card.dart b/lib/presentation/symptoms_checker/widgets/condition_card.dart index b89eac2..e48f41e 100644 --- a/lib/presentation/symptoms_checker/widgets/condition_card.dart +++ b/lib/presentation/symptoms_checker/widgets/condition_card.dart @@ -2,9 +2,12 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.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/symptoms_checker/models/resp_models/triage_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -12,33 +15,131 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; class ConditionCard extends StatelessWidget { - final IconData icon; - final String title; - final int percentage; - final String tagText; - final String clinic; + final TriageCondition condition; final List symptoms; - final String description; - final String? monitorNote; - final String? appointmentLabel; - final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum; final VoidCallback? onActionPressed; const ConditionCard({ super.key, - required this.icon, - required this.title, - required this.percentage, - required this.tagText, - required this.clinic, + required this.condition, required this.symptoms, - required this.description, - this.monitorNote, - this.appointmentLabel, - required this.possibleConditionsSeverityEnum, this.onActionPressed, }); + /// Get title from condition (localized) + String get title { + final appState = getIt(); + return condition.getDisplayName(isArabic: appState.isArabic()); + } + + /// Get percentage from probability (0-1 to 0-100) + int get percentage => ((condition.probability ?? 0) * 100).toInt(); + + /// Get clinic name from category + String get clinic => condition.conditionDetails?.category?.name ?? ''; + + /// Get description from hint + String get description => condition.conditionDetails?.hint ?? ''; + + /// Get severity enum based on triage level + PossibleConditionsSeverityEnum get severityEnum { + final triageLevel = condition.conditionDetails?.triageLevel; + if (triageLevel != null) { + switch (triageLevel) { + case TriageLevelEnum.emergencyAmbulance: + case TriageLevelEnum.emergency: + return PossibleConditionsSeverityEnum.emergency; + case TriageLevelEnum.consultation24: + case TriageLevelEnum.consultation: + return PossibleConditionsSeverityEnum.seekMedicalAdvice; + case TriageLevelEnum.selfCare: + return PossibleConditionsSeverityEnum.monitorOnly; + } + } + // Default based on probability + if (percentage >= 70) { + return PossibleConditionsSeverityEnum.seekMedicalAdvice; + } else { + return PossibleConditionsSeverityEnum.monitorOnly; + } + } + + /// Get tag text based on triage level + String getTagText(BuildContext context) { + final triageLevel = condition.conditionDetails?.triageLevel; + if (triageLevel != null) { + switch (triageLevel) { + case TriageLevelEnum.emergencyAmbulance: + case TriageLevelEnum.emergency: + return LocaleKeys.emergency.tr(context: context); + case TriageLevelEnum.consultation24: + case TriageLevelEnum.consultation: + return LocaleKeys.seekMedicalAdvice.tr(context: context); + case TriageLevelEnum.selfCare: + return LocaleKeys.monitor.tr(context: context); + } + } + // Default based on probability + if (percentage >= 70) { + return LocaleKeys.seekMedicalAdvice.tr(context: context); + } else { + return LocaleKeys.monitor.tr(context: context); + } + } + + /// Get monitor note if applicable + String? getMonitorNote(BuildContext context) { + if (severityEnum == PossibleConditionsSeverityEnum.monitorOnly) { + return LocaleKeys.noNeedToVisitDoctor.tr(context: context); + } + return null; + } + + /// Get icon based on category name from API + IconData get icon { + final categoryName = condition.conditionDetails?.category?.name?.toLowerCase() ?? ''; + + if (categoryName.contains('cardio') || categoryName.contains('heart')) { + return Icons.favorite; + } else if (categoryName.contains('neuro') || categoryName.contains('brain')) { + return Icons.psychology_alt; + } else if (categoryName.contains('psychiatr') || categoryName.contains('mental')) { + return Icons.psychology; + } else if (categoryName.contains('eye') || categoryName.contains('ophthalmo')) { + return Icons.remove_red_eye; + } else if (categoryName.contains('ent') || categoryName.contains('ear')) { + return Icons.hearing; + } else if (categoryName.contains('derma') || categoryName.contains('skin')) { + return Icons.face; + } else if (categoryName.contains('ortho') || categoryName.contains('bone')) { + return Icons.accessibility_new; + } else if (categoryName.contains('gyneco') || categoryName.contains('obstet')) { + return Icons.pregnant_woman; + } else if (categoryName.contains('pediatr') || categoryName.contains('child')) { + return Icons.child_care; + } else if (categoryName.contains('surg')) { + return Icons.local_hospital; + } else if (categoryName.contains('pulmo') || categoryName.contains('lung') || categoryName.contains('respiratory')) { + return Icons.air; + } else if (categoryName.contains('gastro') || categoryName.contains('digest')) { + return Icons.restaurant; + } else if (categoryName.contains('nephro') || categoryName.contains('kidney')) { + return Icons.water_drop; + } else if (categoryName.contains('hemato') || categoryName.contains('blood')) { + return Icons.bloodtype; + } else if (categoryName.contains('infect') || categoryName.contains('virus')) { + return Icons.coronavirus; + } else if (categoryName.contains('emergency')) { + return Icons.emergency; + } else if (categoryName.contains('geriatr') || categoryName.contains('elder')) { + return Icons.elderly; + } else if (categoryName.contains('internal')) { + return Icons.medical_services; + } + + return Icons.medical_services; + } + Color getChipColorBySeverityEnum(PossibleConditionsSeverityEnum possibleConditionsSeverityEnum) { switch (possibleConditionsSeverityEnum) { case PossibleConditionsSeverityEnum.seekMedicalAdvice: @@ -67,7 +168,7 @@ class ConditionCard extends StatelessWidget { crossAxisAlignment: WrapCrossAlignment.center, children: [ for (int i = 0; i < symptoms.length; i++) ...[ - Text(symptoms[i], style: TextStyle(color: AppColors.greyTextColor, fontWeight: FontWeight.w500, fontSize: 12.f)), + "● ${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), if (i != symptoms.length - 1) Padding( padding: EdgeInsets.symmetric(horizontal: 2.w), @@ -80,9 +181,12 @@ class ConditionCard extends StatelessWidget { @override Widget build(BuildContext context) { + // final monitorNote = getMonitorNote(context); + final tagText = getTagText(context); + return Container( width: double.infinity, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -90,14 +194,14 @@ class ConditionCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 48.w, - height: 48.w, + width: 32.w, + height: 32.w, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum).withValues(alpha: 0.2), - borderRadius: 12.r, + color: getChipColorBySeverityEnum(severityEnum).withValues(alpha: 0.2), + borderRadius: 8.r, hasShadow: false, ), - child: Icon(icon, color: getChipTextColorBySeverityEnum(possibleConditionsSeverityEnum), size: 24.f), + child: Icon(icon, color: getChipTextColorBySeverityEnum(severityEnum), size: 16.f), ), SizedBox(width: 12.w), Expanded( @@ -108,34 +212,23 @@ class ConditionCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: Text( - title, - style: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, color: AppColors.textColor), - overflow: TextOverflow.ellipsis, - ), + child: title.toText18(weight: FontWeight.w600, color: AppColors.textColor), ), AppCustomChipWidget( labelText: tagText, - backgroundColor: getChipColorBySeverityEnum(possibleConditionsSeverityEnum).withValues(alpha: 0.2), - textColor: getChipTextColorBySeverityEnum(possibleConditionsSeverityEnum), + backgroundColor: getChipColorBySeverityEnum(severityEnum).withValues(alpha: 0.2), + textColor: getChipTextColorBySeverityEnum(severityEnum), ), ], ), CustomRoundedProgressBar( percentage: percentage, height: 6.h, - color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum), + color: getChipColorBySeverityEnum(severityEnum), backgroundColor: AppColors.scaffoldBgColor, titleWidget: Row( children: [ - Text( - "$percentage%", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12.f, - color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum), - ), - ), + "$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum)), ], ).paddingSymmetrical(0, 4.h), ), @@ -148,50 +241,42 @@ class ConditionCard extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - clinic, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14.f, - color: AppColors.textColor, - ), - ), + LocaleKeys.commonSymptom.tr(context: context).toText14(weight: FontWeight.w600, color: AppColors.textColor), _buildSymptomsRow(), SizedBox(height: 16.h), - Text(LocaleKeys.description.tr(context: context), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14.f, color: AppColors.textColor)), + LocaleKeys.description.tr(context: context).toText14(weight: FontWeight.bold, color: AppColors.textColor), SizedBox(height: 2.h), - Text(description, style: TextStyle(color: AppColors.greyTextColor, fontWeight: FontWeight.w500, fontSize: 12.f)), - if (possibleConditionsSeverityEnum == PossibleConditionsSeverityEnum.emergency) + description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + if (severityEnum != PossibleConditionsSeverityEnum.monitorOnly) CustomButton( - text: appointmentLabel ?? LocaleKeys.bookAppointment.tr(context: context), + text: LocaleKeys.bookAppointment.tr(context: context), onPressed: () { if (onActionPressed != null) { onActionPressed!(); } }, - backgroundColor: AppColors.lightRedButtonColor, + backgroundColor: AppColors.primaryRedColor, borderColor: Colors.transparent, - textColor: AppColors.primaryRedColor, - fontSize: 16.f, + textColor: AppColors.whiteColor, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12.r, padding: EdgeInsets.symmetric(horizontal: 10.w), - height: 48.h, icon: AppAssets.add_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 18.h, + height: 48.h, + iconColor: AppColors.whiteColor, ).paddingOnly(top: 16.w), - if (monitorNote != null) - Container( - margin: EdgeInsets.only(top: 12.h), - child: AppCustomChipWidget( - labelText: monitorNote!, - backgroundColor: AppColors.whiteColor, - textColor: AppColors.textColor, - padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), - ), - ), + + // if (monitorNote != null) + // Container( + // margin: EdgeInsets.only(top: 12.h), + // child: AppCustomChipWidget( + // labelText: monitorNote, + // backgroundColor: AppColors.whiteColor, + // textColor: AppColors.textColor, + // padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h), + // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + // ), + // ), ], ).paddingAll(16.w), ], diff --git a/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart b/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart index 8957fb1..62c38f9 100644 --- a/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart +++ b/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart @@ -13,6 +13,7 @@ class InteractiveBodyWidget extends StatefulWidget { final bool isBodyHidden; final Function(String organId) onOrganTap; final String? tooltipOrganId; + final bool isArabic; const InteractiveBodyWidget({ super.key, @@ -22,6 +23,7 @@ class InteractiveBodyWidget extends StatefulWidget { required this.onOrganTap, this.isBodyHidden = false, this.tooltipOrganId, + this.isArabic = false, }); @override @@ -118,7 +120,10 @@ class _InteractiveBodyWidgetState extends State { (organ) { final centerX = organ.position.x * imageConstraints.maxWidth; final centerY = organ.position.y * imageConstraints.maxHeight; - return OrganTooltipWidget(organName: organ.description, position: Offset(centerX, centerY)); + return OrganTooltipWidget( + organName: organ.getLocalizedDescription(widget.isArabic), + position: Offset(centerX, centerY), + ); }, ), ], diff --git a/lib/presentation/todo_section/widgets/ancillary_orders_list.dart b/lib/presentation/todo_section/widgets/ancillary_orders_list.dart index aa4d0ba..71d2cf0 100644 --- a/lib/presentation/todo_section/widgets/ancillary_orders_list.dart +++ b/lib/presentation/todo_section/widgets/ancillary_orders_list.dart @@ -145,7 +145,7 @@ class AncillaryOrderCard extends StatelessWidget { if (!isLoading) ...[ Image.network( "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png", - width: 63.w, + width: 63.h, height: 63.h, fit: BoxFit.cover, ).circle(100.r), @@ -177,11 +177,11 @@ class AncillaryOrderCard extends StatelessWidget { labelText: order.projectName ?? '-', ).toShimmer2(isShow: isLoading), // orderNo - // if (order.orderNo != null || isLoading) - // AppCustomChipWidget( - // // icon: AppAssets.calendar, - // labelText: "${"Order# :".needTranslation}${order.orderNo ?? '-'}", - // ).toShimmer2(isShow: isLoading), + if (order.orderNo != null || isLoading) + AppCustomChipWidget( + // icon: AppAssets.calendar, + labelText: "${LocaleKeys.orderNumber.tr(context: context)}${order.orderNo ?? '-'}", + ).toShimmer2(isShow: isLoading), // Appointment Date if (order.appointmentDate != null || isLoading) diff --git a/lib/presentation/vital_sign/vital_sign_page.dart b/lib/presentation/vital_sign/vital_sign_page.dart index fbf9fc6..e457023 100644 --- a/lib/presentation/vital_sign/vital_sign_page.dart +++ b/lib/presentation/vital_sign/vital_sign_page.dart @@ -1,5 +1,6 @@ import 'dart:ui'; +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/utils/size_utils.dart'; @@ -8,6 +9,7 @@ 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/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/vital_sign_respo_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; @@ -42,7 +44,7 @@ class _VitalSignPageState extends State { return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( - title: 'Vital Signs', + title: LocaleKeys.vitalSigns.tr(context: context), child: Consumer( builder: (context, viewModel, child) { @@ -70,14 +72,14 @@ class _VitalSignPageState extends State { // BMI Card _buildVitalSignCard( icon: AppAssets.bmiVital, - label: 'BMI', + label: LocaleKeys.bmi.tr(context: context), value: latestVitalSign?.bodyMassIndex?.toString() ?? '--', unit: '', status: VitalSignUiModel.bmiStatus(latestVitalSign?.bodyMassIndex), onTap: () => _openDetails( - const VitalSignDetailsArgs( + VitalSignDetailsArgs( metric: VitalSignMetric.bmi, - title: 'BMI', + title: LocaleKeys.bmi.tr(context: context), icon: AppAssets.bmiVital, unit: '', ), @@ -88,14 +90,14 @@ class _VitalSignPageState extends State { // Height Card _buildVitalSignCard( icon: AppAssets.heightVital, - label: 'Height', + label: LocaleKeys.height.tr(context: context), value: latestVitalSign?.heightCm?.toString() ?? '--', unit: 'cm', status: null, onTap: () => _openDetails( - const VitalSignDetailsArgs( + VitalSignDetailsArgs( metric: VitalSignMetric.height, - title: 'Height', + title: LocaleKeys.height.tr(context: context), icon: AppAssets.heightVital, unit: 'cm', ), @@ -106,14 +108,14 @@ class _VitalSignPageState extends State { // Weight Card _buildVitalSignCard( icon: AppAssets.weightVital, - label: 'Weight', + label: LocaleKeys.weight.tr(context: context), value: latestVitalSign?.weightKg?.toString() ?? '--', unit: 'kg', status: (latestVitalSign?.weightKg != null) ? 'Normal' : null, onTap: () => _openDetails( - const VitalSignDetailsArgs( + VitalSignDetailsArgs( metric: VitalSignMetric.weight, - title: 'Weight', + title: LocaleKeys.height.tr(context: context), icon: AppAssets.weightVital, unit: 'kg', ), @@ -124,7 +126,7 @@ class _VitalSignPageState extends State { // Blood Pressure Card _buildVitalSignCard( icon: AppAssets.bloodPressure, - label: 'Blood Pressure', + label: LocaleKeys.bloodPressure.tr(context: context), value: latestVitalSign != null && latestVitalSign.bloodPressureHigher != null && latestVitalSign.bloodPressureLower != null @@ -136,9 +138,9 @@ class _VitalSignPageState extends State { diastolic: latestVitalSign?.bloodPressureLower, ), onTap: () => _openDetails( - const VitalSignDetailsArgs( + VitalSignDetailsArgs( metric: VitalSignMetric.bloodPressure, - title: 'Blood Pressure', + title: LocaleKeys.bloodPressure.tr(context: context), icon: AppAssets.bloodPressure, unit: 'mmHg', low: 90, @@ -151,14 +153,14 @@ class _VitalSignPageState extends State { // Temperature Card _buildVitalSignCard( icon: AppAssets.temperature, - label: 'Temperature', + label: LocaleKeys.temperature.tr(context: context), value: latestVitalSign?.temperatureCelcius?.toString() ?? '--', unit: '°C', status: null, onTap: () => _openDetails( - const VitalSignDetailsArgs( + VitalSignDetailsArgs( metric: VitalSignMetric.temperature, - title: 'Temperature', + title: LocaleKeys.temperature.tr(context: context), icon: AppAssets.temperature, unit: '°C', low: 36.1, @@ -226,14 +228,14 @@ class _VitalSignPageState extends State { bottom: 12.h, child: _buildVitalSignCard( icon: AppAssets.heart, - label: 'Heart Rate', + label: LocaleKeys.heart.tr(context: context), value: latestVitalSign?.heartRate?.toString() ?? latestVitalSign?.pulseBeatPerMinute?.toString() ?? '--', unit: 'bpm', status: 'Normal', onTap: () => _openDetails( - const VitalSignDetailsArgs( + VitalSignDetailsArgs( metric: VitalSignMetric.heartRate, - title: 'Heart Rate', + title: LocaleKeys.heart.tr(context: context), icon: AppAssets.heart, unit: 'bpm', low: 60, @@ -250,15 +252,15 @@ class _VitalSignPageState extends State { // Respiratory rate Card _buildVitalSignCard( icon: AppAssets.respRate, - label: 'Respiratory rate', - value: latestVitalSign?.respirationBeatPerMinute?.toString() ?? '--', + label: LocaleKeys.respirationRate.tr(context: context), + value: latestVitalSign?.respirationBeatPerMinute?.toString() ?? '--', unit: 'bpm', status: 'Normal', onTap: () => _openDetails( - const VitalSignDetailsArgs( - metric: VitalSignMetric.respiratoryRate, - title: 'Respiratory rate', - icon: AppAssets.respRate, + VitalSignDetailsArgs( + metric: VitalSignMetric.respiratoryRate, + title: LocaleKeys.respirationRate.tr(context: context), + icon: AppAssets.respRate, unit: 'bpm', low: 12, high: 20, diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 325f48e..702b37e 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/presentation/child_vaccine/my_child_vaccine_ import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart'; import 'package:hmg_patient_app_new/presentation/covid19test/covid19_landing_page.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/emergency_services_page.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculators_page.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/add_health_tracker_entry_page.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/health_tracker_detail_page.dart'; @@ -31,16 +32,14 @@ import 'package:hmg_patient_app_new/presentation/vital_sign/vital_sign_page.dart import 'package:hmg_patient_app_new/presentation/water_monitor/water_consumption_page.dart'; import 'package:hmg_patient_app_new/presentation/water_monitor/water_monitor_settings_page.dart'; import 'package:hmg_patient_app_new/splashPage.dart'; - -import '../features/qr_parking/qr_parking_view_model.dart'; -import '../presentation/covid19test/covid19_landing_page.dart'; +import 'package:provider/provider.dart'; import '../core/dependencies.dart'; import '../features/monthly_reports/monthly_reports_repo.dart'; import '../features/monthly_reports/monthly_reports_view_model.dart'; +import '../features/qr_parking/qr_parking_view_model.dart'; import '../presentation/parking/paking_page.dart'; import '../services/error_handler_service.dart'; -import 'package:provider/provider.dart'; class AppRoutes { static const String initialRoute = '/initialRoute'; @@ -86,8 +85,10 @@ class AppRoutes { static const String addHealthTrackerEntryPage = '/addHealthTrackerEntryPage'; static const String healthTrackerDetailPage = '/healthTrackerDetailPage'; - static Map get routes => - { + // Emergency Services + static const String emergencyServicesPage = '/emergencyServicesPage'; + + static Map get routes => { initialRoute: (context) => SplashPage(), loginScreen: (context) => LoginScreen(), landingScreen: (context) => LandingNavigation(), @@ -107,7 +108,7 @@ class AppRoutes { bloodDonationPage: (context) => BloodDonationPage(), myChildVaccine: (context) => MyChildVaccinePage(), bookAppointmentPage: (context) => BookAppointmentPage(), - userInfoSelection: (context) => UserInfoSelectionScreen(), + userInfoSelection: (context) => UserInfoSelectionPage(), userInfoFlowManager: (context) => UserInfoFlowManager(), smartWatches: (context) => SmartwatchInstructionsPage(), huaweiHealthExample: (context) => HuaweiHealthExample(), @@ -118,34 +119,28 @@ class AppRoutes { healthConvertersPage: (context) => HealthCalculatorsPage(type: HealthCalConEnum.converter), healthTrackersPage: (context) => HealthTrackersPage(), vitalSign: (context) => VitalSignPage(), + emergencyServicesPage: (context) => EmergencyServicesPage(), addHealthTrackerEntryPage: (context) { - final args = ModalRoute - .of(context) - ?.settings - .arguments as HealthTrackerTypeEnum?; + final args = ModalRoute.of(context)?.settings.arguments as HealthTrackerTypeEnum?; return AddHealthTrackerEntryPage( trackerType: args ?? HealthTrackerTypeEnum.bloodSugar, ); }, healthTrackerDetailPage: (context) { - final args = ModalRoute - .of(context) - ?.settings - .arguments as HealthTrackerTypeEnum?; + final args = ModalRoute.of(context)?.settings.arguments as HealthTrackerTypeEnum?; return HealthTrackerDetailPage( trackerType: args ?? HealthTrackerTypeEnum.bloodSugar, ); }, - - monthlyReports: (context) => ChangeNotifierProvider( - create: (_) => MonthlyReportsViewModel( - monthlyReportsRepo: getIt(), - errorHandlerService: getIt(), - ), - ), - qrParking: (context) => ChangeNotifierProvider( - create: (_) => getIt(), - child: const ParkingPage(), + monthlyReports: (context) => ChangeNotifierProvider( + create: (_) => MonthlyReportsViewModel( + monthlyReportsRepo: getIt(), + errorHandlerService: getIt(), + ), + ), + qrParking: (context) => ChangeNotifierProvider( + create: (_) => getIt(), + child: const ParkingPage(), ) }; } diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index 48c3285..b8d480e 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -230,7 +230,7 @@ Widget exceptionBottomSheetWidget( children: [ Expanded( child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: LocaleKeys.cancel.tr(context: context), onPressed: () { Navigator.of(context).pop(); }, @@ -244,7 +244,7 @@ Widget exceptionBottomSheetWidget( SizedBox(width: 10.h), Expanded( child: CustomButton( - text: LocaleKeys.confirm.tr(), + text: LocaleKeys.confirm.tr(context: context), onPressed: onOkPressed, backgroundColor: AppColors.bgGreenColor, borderColor: AppColors.bgGreenColor, @@ -258,7 +258,7 @@ Widget exceptionBottomSheetWidget( Padding( padding: EdgeInsets.only(bottom: 10.h), child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: LocaleKeys.cancel.tr(context: context), onPressed: (onCancelPressed == null) ? () { context.pop(); @@ -286,7 +286,7 @@ Widget showPhoneNumberPickerWidget( Padding( padding: EdgeInsets.only(bottom: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPSMS.tr(), + text: LocaleKeys.sendOTPSMS.tr(context: context), onPressed: onSMSPress, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedBorderColor, @@ -300,14 +300,14 @@ Widget showPhoneNumberPickerWidget( children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 8.h), - child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor), + child: LocaleKeys.oR.tr(context: context).toText16(color: AppColors.textColor), ), ], ), Padding( padding: EdgeInsets.only(bottom: 10.h, top: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPWHATSAPP.tr(), + text: LocaleKeys.sendOTPWHATSAPP.tr(context: context), onPressed: onWhatsappPress, backgroundColor: Colors.white, borderColor: AppColors.borderOnlyColor, diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index f017185..d56178b 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -92,7 +92,7 @@ class AppColors { // SymptomsChecker static const Color chipColorSeekMedicalAdvice = Color(0xFFFFAF15); // #FFAF15 - static const Color chipTextColorSeekMedicalAdvice = Color(0xFFAB7103); // #AB7103 + static const Color chipTextColorSeekMedicalAdvice = Color(0xFFD48D05); // #AB7103 static const Color chipColorMonitor = Color(0xFF18C273); // #18C273 static const Color chipColorEmergency = Color(0xFFED1C2B); // #ED1C2B diff --git a/lib/widgets/app_language_change.dart b/lib/widgets/app_language_change.dart index 67a52db..c94195a 100644 --- a/lib/widgets/app_language_change.dart +++ b/lib/widgets/app_language_change.dart @@ -48,7 +48,7 @@ class _AppLanguageChangeState extends State { ), ), CustomButton( - text: LocaleKeys.save.tr(), + text: LocaleKeys.save.tr(context: context), onPressed: () { context.setLocale(selectedValue == 'en' ? Locale('en', 'US') : Locale('ar', 'SA')).then((val) { Navigator.pop(context); diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 08d281f..a81f0eb 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -74,26 +74,25 @@ class CustomButton extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ if (icon != null) - Padding( - padding: text.isNotEmpty ? EdgeInsets.only(right: 8.w, left: 8.w) : EdgeInsets.zero, - child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconS, height: iconS), + Flexible( + child: Padding( + padding: text.isNotEmpty ? EdgeInsets.only(right: 4.w, left: 4.w) : EdgeInsets.zero, + child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconS, height: iconS), + ), ), - Visibility( - visible: text.isNotEmpty, - child: Padding( - padding: EdgeInsets.only(top: 0), - child: Text( - text, - overflow: textOverflow, - style: context.dynamicTextStyle( - fontSize: fontS, - color: isDisabled ? AppColors.greyTextColor : textColor, - letterSpacing: 0, - fontWeight: fontWeight, - ), + if (text.isNotEmpty) + Text( + text, + overflow: textOverflow ?? TextOverflow.ellipsis, + maxLines: 1, + textAlign: TextAlign.center, + style: context.dynamicTextStyle( + fontSize: fontS, + color: isDisabled ? AppColors.greyTextColor : textColor, + letterSpacing: 0, + fontWeight: fontWeight, ), ), - ), ], ), )); diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart index 4cfde1b..1f8593a 100644 --- a/lib/widgets/common_bottom_sheet.dart +++ b/lib/widgets/common_bottom_sheet.dart @@ -42,13 +42,13 @@ class BottomSheetUtils{ Future _showReminderBottomSheet(BuildContext providedContext, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted, {required Function onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool? isMultiAllowed}) async { - showCommonBottomSheetWithoutHeight(providedContext, title: LocaleKeys.setTimerOfReminder.tr(), child: PrescriptionReminderView( + showCommonBottomSheetWithoutHeight(providedContext, title: LocaleKeys.setTimerOfReminder.tr(context: providedContext), child: PrescriptionReminderView( setReminder: (int value) async { if (!isMultiAllowed!) { if (onMultiDateSuccess == null) { CalenderUtilsNew calendarUtils = CalenderUtilsNew.instance; await calendarUtils.createOrUpdateEvent( - title: title ?? LocaleKeys.youHaveAppointmentWithDr.tr() + doctorName, + title: title ?? LocaleKeys.youHaveAppointmentWithDr.tr(context: providedContext) + doctorName, description: description ?? "At " + appoDateFormatted + " " + appoTimeFormatted, scheduleDateTime: dateTime, eventId: eventId, diff --git a/lib/widgets/expandable_list_widget.dart b/lib/widgets/expandable_list_widget.dart index b948299..db4e398 100644 --- a/lib/widgets/expandable_list_widget.dart +++ b/lib/widgets/expandable_list_widget.dart @@ -282,9 +282,9 @@ class ExpandableListTheme { dividerColor: dividerColor ?? Colors.grey.shade300, defaultTrailingIcon: defaultTrailingIcon ?? Icon(Icons.keyboard_arrow_down, color: Colors.black, size: 24), - itemPadding: itemPadding ?? const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), - contentPadding: contentPadding ?? const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 16.0), - leadingSpacing: leadingSpacing ?? 12.0, + itemPadding: itemPadding ?? EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), + contentPadding: contentPadding ?? EdgeInsets.only(left: 16.w, right: 16.w, bottom: 16.h), + leadingSpacing: leadingSpacing ?? 12.w, ); } } diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 9f101d4..ad2a579 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -153,10 +153,18 @@ class TextInputWidget extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildLabelText(labelColor).paddingOnly(right: (appState.getLanguageCode() == "ar" ? 10 : 0)), + _buildLabelText(labelColor).paddingOnly( + right: (appState.getLanguageCode() == "ar" ? 10 : 0), + left: (appState.getLanguageCode() == "en" ? 10 : 0), + ), Row( children: [ - Expanded(child: _buildTextField(context)), + Expanded( + child: _buildTextField(context).paddingOnly( + right: (appState.getLanguageCode() == "ar" ? 10 : 0), + left: (appState.getLanguageCode() == "en" ? 10 : 0), + ), + ) ], ), ], @@ -191,7 +199,7 @@ class TextInputWidget extends StatelessWidget { return Container( height: 40.h, width: 40.h, - margin: EdgeInsets.only(right: 10.h), + // margin: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.all(8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( borderRadius: 12.r, @@ -204,7 +212,7 @@ class TextInputWidget extends StatelessWidget { final AppState appState = getIt.get(); return Container( height: 40.h, - width: 40.h, + width: 40.w, margin: EdgeInsets.zero, padding: EdgeInsets.all(8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 12.r, color: AppColors.whiteColor),