Compare commits

...

12 Commits

@ -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,

@ -0,0 +1,3 @@
<svg width="15" height="23" viewBox="0 0 15 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.32806 22.32C7.33606 22.32 6.34406 22.2 5.35206 21.96C4.37606 21.736 3.48006 21.36 2.66406 20.832C1.86406 20.304 1.21606 19.616 0.720063 18.768C0.240063 17.92 6.25104e-05 16.88 6.25104e-05 15.648C6.25104e-05 14.4 0.248063 13.248 0.744063 12.192C1.25606 11.12 1.96806 10.168 2.88006 9.336C3.80806 8.488 4.90406 7.784 6.16806 7.224C7.43206 6.664 8.81606 6.264 10.3201 6.024L10.9921 8.688C9.68006 8.928 8.51206 9.256 7.48806 9.672C6.48006 10.088 5.62406 10.584 4.92006 11.16C4.23206 11.736 3.71206 12.368 3.36006 13.056C3.00806 13.76 2.83206 14.512 2.83206 15.312C2.83206 15.952 2.94406 16.504 3.16806 16.968C3.40806 17.448 3.72006 17.848 4.10406 18.168C4.48806 18.488 4.92006 18.744 5.40006 18.936C5.88006 19.128 6.37606 19.264 6.88806 19.344C7.40006 19.44 7.88006 19.488 8.32806 19.488C9.33606 19.488 10.3041 19.392 11.2321 19.2C12.1601 19.024 12.9841 18.784 13.7041 18.48L14.5201 21.024C14.1361 21.216 13.6081 21.408 12.9361 21.6C12.2641 21.808 11.5281 21.976 10.7281 22.104C9.92806 22.248 9.12806 22.32 8.32806 22.32ZM3.86406 9.24C3.27206 9.048 2.72806 8.744 2.23206 8.328C1.75206 7.912 1.36806 7.4 1.08006 6.792C0.792063 6.184 0.648063 5.512 0.648063 4.776C0.648063 3.768 0.904063 2.912 1.41606 2.208C1.92806 1.488 2.59206 0.943998 3.40806 0.575998C4.24006 0.191998 5.13606 -1.90735e-06 6.09606 -1.90735e-06C6.56006 -1.90735e-06 7.00806 0.0319982 7.44006 0.0959983C7.87206 0.159998 8.30406 0.255998 8.73606 0.383997L8.25606 3.072C7.92006 2.992 7.57606 2.928 7.22406 2.88C6.87206 2.832 6.56006 2.808 6.28806 2.808C5.72806 2.808 5.23206 2.896 4.80006 3.072C4.38406 3.248 4.05606 3.496 3.81606 3.816C3.59206 4.136 3.48006 4.512 3.48006 4.944C3.48006 5.312 3.58406 5.656 3.79206 5.976C4.01606 6.28 4.29606 6.544 4.63206 6.768C4.98406 6.992 5.35206 7.168 5.73606 7.296C6.13606 7.424 6.50406 7.496 6.84006 7.512L3.86406 9.24Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,3 @@
<svg width="12" height="21" viewBox="0 0 12 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.72994 2.25V9.24H10.3499V11.49H2.72994V18.69H11.2499V20.94H-5.83827e-05V2.02656e-06H11.2499V2.25H2.72994Z" fill="#2B353E"/>
</svg>

After

Width:  |  Height:  |  Size: 242 B

@ -1377,6 +1377,18 @@
"suggestions": "الاقتراحات",
"pleaseGoBackAndSelectOrgansFirst": "يرجى العودة واختيار الأعضاء أولاً",
"symptomsSelector": "محدد الأعراض",
"possibleSymptomsRelatedTo": "الأعراض المحتملة المتعلقة بـ",
"suggestionAIListDescription": "هذه قائمة بالأعراض المقترحة من قبل الذكاء الاصطناعي، بناءً على المعلومات التي تم جمعها حتى الآن خلال المقابلة",
"analyzing": "جاري التحليل...",
"seekMedicalAdvice": "اطلب المشورة الطبية",
"monitorDescription": "لا حاجة لطلب المشورة الطبية. فقط حافظ على روتين صحي.",
"seekMedicalAdviceDescription": "ليست حالة طوارئ ولكن من الأفضل مراقبة الأعراض.",
"emergencyDescription": "تحتاج إلى استشارة الطبيب في أقرب وقت ممكن قبل فوات الأوان.",
"colorScience": "دلالات الألوان",
"noNeedToVisitDoctor": "لا حاجة لزي<D8B2><D98A>رة الطبيب",
"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": "مؤشر كتلة الجسم"
}

@ -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"
}

@ -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<String, dynamic> 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<dynamic> 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<String, dynamic> 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<dynamic> 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}');
// }
//

@ -189,6 +189,8 @@ class ApiClientImp implements ApiClient {
// body['SessionID'] = "45786230487560q";
}
// body['IsNewFlutterApp'] = true;
body.removeWhere((key, value) => value == null);
}

@ -680,7 +680,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -306,6 +306,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';

@ -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,

@ -571,7 +571,7 @@ class AuthenticationViewModel extends ChangeNotifier {
MedicalFileViewModel medicalVm = getIt<MedicalFileViewModel>();
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<MedicalFileViewModel>();
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) {

@ -545,20 +545,20 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
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<OTPVerificationScreen> {
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<OTPVerificationScreen> {
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<OTPVerificationScreen> {
else
GestureDetector(
onTap: _resendOtp,
child: LocaleKeys.resendOTP.tr().toText16(color: AppColors.primaryRedColor),
child: LocaleKeys.resendOTP.tr(context: context).toText16(color: AppColors.primaryRedColor),
),
],
),

@ -45,9 +45,7 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
initImmediateLiveCare() {
_appState = getIt<AppState>();
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<void> getPatientLiveCareHistory({Function(dynamic)? onSuccess, Function(String)? onError}) async {
patientLiveCareHistoryList = [];
patientHasPendingLiveCareRequest = false;
notifyListeners();
final result = await immediateLiveCareRepo.getPatientLiveCareHistory();
result.fold(

@ -220,6 +220,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
Future<void> 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<void> 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(

@ -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),
),

@ -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,
);

@ -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 ?? '';
}
}

@ -172,6 +172,8 @@ class TriageCondition {
final String? id;
final String? name;
final String? commonName;
final String? nameAr;
final String? commonNameAr;
final double? probability;
final ConditionDetails? conditionDetails;
@ -179,6 +181,8 @@ class TriageCondition {
this.id,
this.name,
this.commonName,
this.nameAr,
this.commonNameAr,
this.probability,
this.conditionDetails,
});
@ -188,6 +192,8 @@ 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'] != null ? ConditionDetails.fromJson(json['condition_details']) : null,
);
@ -198,11 +204,21 @@ class TriageCondition {
'id': id,
'name': name,
'common_name': commonName,
'nameAr': nameAr,
'common_nameAr': commonNameAr,
'probability': probability,
'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%';

@ -63,7 +63,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
required String userName,
required String password,
}) async {
Map<String, String> body = {"userName": userName, "password": password};
Map<String, dynamic> body = {"userName": userName, "password": password};
try {
GenericApiModel<SymptomsUserDetailsResponseModel>? apiResponse;

@ -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;
@ -440,7 +457,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
await getRiskFactors(
age: _selectedAge!,
gender: _selectedGender!.toLowerCase() == "male" ? 1 : 2,
gender: _getGenderAsInt(_selectedGender),
evidenceIds: evidenceIds,
sessionId: currentSessionId,
language: appState.isArabic() ? 'ar' : 'en',
@ -498,6 +515,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
id: "not_applicable",
commonName: "Not Applicable",
name: "Not Applicable",
commonNameAr: "لا ينطبق",
nameAr: "لا ينطبق",
language: appState.isArabic() ? 'ar' : 'en',
type: null,
);
@ -612,7 +631,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
await getSuggestions(
age: _selectedAge!,
gender: _selectedGender!.toLowerCase() == "male" ? 1 : 2,
gender: _getGenderAsInt(_selectedGender),
evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) {
@ -668,6 +687,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
id: "not_applicable",
commonName: "Not Applicable",
name: "Not Applicable",
commonNameAr: "لا ينطبق",
nameAr: "لا ينطبق",
language: appState.isArabic() ? 'ar' : 'en',
type: null,
);
@ -764,7 +785,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
await getDiagnosisForTriage(
age: _selectedAge!,
gender: _selectedGender!.toLowerCase() == "male" ? 1 : 2,
gender: _getGenderAsInt(_selectedGender),
evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) {
@ -927,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<String, dynamic> getUserInfoData() {
return {
@ -988,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(

@ -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';
}

@ -87,7 +87,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
} 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<AppointmentDetailsPage> {
// ],
// ),
// SizedBox(height: 16.h),
// LocaleKeys.prescriptions.tr().toText18(isBold: true),
// LocaleKeys.prescriptions.tr(context: context).toText18(isBold: true),
// SizedBox(height: 16.h),
// Consumer<PrescriptionsViewModel>(builder: (context, prescriptionVM, child) {
// return prescriptionVM.isPrescriptionsDetailsLoading
@ -708,7 +708,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
).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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
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<AppointmentDetailsPage> {
),
);
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,

@ -90,7 +90,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
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<AppointmentPaymentPage> {
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<AppointmentPaymentPage> {
)
: 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<AppointmentPaymentPage> {
}
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<AppointmentPaymentPage> {
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<AppointmentPaymentPage> {
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()),
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,

@ -155,7 +155,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
isLoading: true,
isFromHomePage: false,
),
).paddingSymmetrical(24.h, 0.h)
)
: filteredAppointmentList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,

@ -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((){

@ -71,10 +71,10 @@ class LoginScreenState extends State<LoginScreen> {
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<LoginScreen> {
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<LoginScreen> {
text: TextSpan(
style: context.dynamicTextStyle(color: Colors.black, fontSize: 14.f, height: 26 / 16, fontWeight: FontWeight.w500),
children: <TextSpan>[
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<LoginScreen> {
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<LoginScreen> {
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,

@ -49,7 +49,7 @@ class QuickLoginState extends State<QuickLogin> {
],
),
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<QuickLogin> {
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<QuickLogin> {
// ),
// ),
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<QuickLogin> {
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<QuickLogin> {
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");

@ -80,7 +80,7 @@ class _RegisterNew extends State<RegisterNew> {
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<RegisterNew> {
).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<RegisterNew> {
).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<RegisterNew> {
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<RegisterNew> {
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<RegisterNew> {
),
// 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<RegisterNew> {
),
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<RegisterNew> {
fontWeight: FontWeight.w500,
),
children: <TextSpan>[
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<RegisterNew> {
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<RegisterNew> {
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(

@ -73,7 +73,7 @@ class _RegisterNew extends State<RegisterNewStep2> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
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<RegisterNewStep2> {
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<RegisterNewStep2> {
).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<RegisterNewStep2> {
builder: (context, genderType, child) {
final authVM = context.read<AuthenticationViewModel>();
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<RegisterNewStep2> {
).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<RegisterNewStep2> {
builder: (context, maritalStatus, child) {
final authVM = context.read<AuthenticationViewModel>(); // 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<RegisterNewStep2> {
},
)
: 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<RegisterNewStep2> {
builder: (context, data, child) {
final authVM = context.read<AuthenticationViewModel>();
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<RegisterNewStep2> {
},
)
: 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<RegisterNewStep2> {
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<RegisterNewStep2> {
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<RegisterNewStep2> {
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<RegisterNewStep2> {
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<RegisterNewStep2> {
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,

@ -89,8 +89,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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<BookAppointmentPage> {
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),
],
),
),

@ -79,7 +79,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
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<SelectClinicPage> {
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<SelectClinicPage> {
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<SelectClinicPage> {
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();

@ -178,7 +178,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
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(),

@ -204,13 +204,13 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
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<AppointmentCalendar> {
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(

@ -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,

@ -195,10 +195,11 @@ class _LandingPageState extends State<LandingPage> {
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(
@ -233,7 +234,8 @@ class _LandingPageState extends State<LandingPage> {
),
)
: SizedBox.shrink(),
]),
])
: SizedBox.shrink(),
Utils.buildSvgWithAssets(icon: AppAssets.indoor_nav_icon, height: 18.h, width: 18.h).onPress(() {
openIndoorNavigationBottomSheet(context);
}),
@ -246,6 +248,11 @@ class _LandingPageState extends State<LandingPage> {
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()
],
);
}),
@ -302,7 +309,7 @@ class _LandingPageState extends State<LandingPage> {
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),
@ -463,7 +470,7 @@ class _LandingPageState extends State<LandingPage> {
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,
),
@ -599,10 +606,10 @@ class _LandingPageState extends State<LandingPage> {
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),
],
@ -855,7 +862,7 @@ class _LandingPageState extends State<LandingPage> {
hasShadow: true,
),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.first,
patientAppointmentHistoryResponseModel: myAppointmentsViewModel.patientAppointmentsHistoryList.first,
myAppointmentsViewModel: myAppointmentsViewModel,
bookAppointmentsViewModel: bookAppointmentsViewModel,
isLoading: false,
@ -901,7 +908,7 @@ class _LandingPageState extends State<LandingPage> {
}
} else if (index == 2) {
if ((myAppointmentsViewModel.isPatientHasQueueAppointment || immediateLiveCareViewModel.patientHasPendingLiveCareRequest) &&
myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.isNotEmpty) {
todoSectionViewModel.patientAncillaryOrdersList.isNotEmpty) {
return AncillaryOrderCard(
order: todoSectionViewModel.patientAncillaryOrdersList.first,
isLoading: false,

@ -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),
],

@ -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();
},

@ -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()),

File diff suppressed because one or more lines are too long

@ -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) {

@ -192,7 +192,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
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>();
dialogService.showFamilyBottomSheetWithoutH(
label: LocaleKeys.familyTitle.tr(context: context),
@ -276,12 +276,12 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
],
),
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
),
));
},
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<MedicalFilePage> {
],
).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<PrescriptionsViewModel>(builder: (context, prescriptionVM, child) {
return prescriptionVM.isPrescriptionsOrdersLoading
@ -901,7 +902,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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<MedicalFilePage> {
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}"
: '--',

@ -114,8 +114,8 @@ class ProfileSettingsState extends State<ProfileSettings> {
onAddFamilyMemberPress: () {
DialogService dialogService = getIt.get<DialogService>();
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);
});
@ -197,19 +197,18 @@ class ProfileSettingsState extends State<ProfileSettings> {
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,
@ -219,8 +218,7 @@ class ProfileSettingsState extends State<ProfileSettings> {
],
),
),
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 +229,9 @@ class ProfileSettingsState extends State<ProfileSettings> {
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 +243,7 @@ class ProfileSettingsState extends State<ProfileSettings> {
}
}, 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 +260,7 @@ class ProfileSettingsState extends State<ProfileSettings> {
CustomButton(
height: 56.h,
icon: AppAssets.minus,
text: LocaleKeys.deactivateAccount.tr(),
text: LocaleKeys.deactivateAccount.tr(context: context),
onPressed: () {},
).paddingAll(24.w),
],
@ -346,7 +344,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),
@ -421,7 +420,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),
],
),
@ -445,7 +444,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,
@ -461,7 +460,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,

@ -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<OrganSelectorPage> {
);
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<OrganSelectorPage> {
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<OrganSelectorPage> {
}
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<BodyView>(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<BodyView>(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<OrganSelectorPage> {
}
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<OrganSelectorPage> {
);
}
final isArabic = _appState.isArabic();
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: 150.h),
child: SingleChildScrollView(
@ -284,7 +298,7 @@ class _OrganSelectorPageState extends State<OrganSelectorPage> {
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<OrganSelectorPage> {
}
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<OrganSelectorPage> {
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,
),
),
),
),

@ -108,25 +108,25 @@ class PossibleConditionsPage extends StatelessWidget {
);
}
Widget _buildInfoTile({required PossibleConditionsSeverityEnum severityEnum}) {
Widget _buildInfoTile({required PossibleConditionsSeverityEnum severityEnum, required BuildContext context}) {
String title;
String description;
Color dotColor;
switch (severityEnum) {
case PossibleConditionsSeverityEnum.monitorOnly:
title = "Monitor".needTranslation;
description = "No need to seek medical advice. Just keep healthy routine.".needTranslation;
title = LocaleKeys.monitor.tr(context: context);
description = LocaleKeys.monitorDescription.tr(context: context);
dotColor = AppColors.chipColorMonitor;
break;
case PossibleConditionsSeverityEnum.seekMedicalAdvice:
title = "Seek Medical Advice".needTranslation;
description = "Not emergency but better to monitor the symptoms.".needTranslation;
title = LocaleKeys.seekMedicalAdvice.tr(context: context);
description = LocaleKeys.seekMedicalAdviceDescription.tr(context: context);
dotColor = AppColors.chipColorSeekMedicalAdvice;
break;
case PossibleConditionsSeverityEnum.emergency:
title = "Emergency".needTranslation;
description = "Need to consult doctor as soon as possible before getting too late.".needTranslation;
title = LocaleKeys.emergency.tr(context: context);
description = LocaleKeys.emergencyDescription.tr(context: context);
dotColor = AppColors.chipColorEmergency;
break;
}
@ -156,7 +156,7 @@ class PossibleConditionsPage extends StatelessWidget {
_buildSeverityDetailsBottomsheet({required BuildContext context}) {
return showCommonBottomSheetWithoutHeight(
title: "Color Science".needTranslation,
title: LocaleKeys.colorScience.tr(context: context),
context,
child: Container(
padding: EdgeInsets.all(16.w),
@ -164,11 +164,11 @@ class PossibleConditionsPage extends StatelessWidget {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
children: [
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.monitorOnly),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.monitorOnly, context: context),
Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, context: context),
Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.emergency),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.emergency, context: context),
],
),
),

@ -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<RiskFactorsScreen> {
late DialogService dialogService;
late AppState _appState;
@override
void initState() {
super.initState();
dialogService = getIt<DialogService>();
_appState = getIt<AppState>();
// Fetch risk factors based on selected symptoms
WidgetsBinding.instance.addPostFrameCallback((_) {
final viewModel = context.read<SymptomsCheckerViewModel>();
@ -90,6 +93,8 @@ class _RiskFactorsScreenState extends State<RiskFactorsScreen> {
}
Widget _buildRiskFactorsList(SymptomsCheckerViewModel viewModel) {
final isArabic = _appState.isArabic();
return Container(
key: ValueKey<int>(viewModel.riskFactorsList.length),
width: double.infinity,
@ -100,7 +105,7 @@ class _RiskFactorsScreenState extends State<RiskFactorsScreen> {
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(

@ -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<SuggestionsScreen> {
late DialogService dialogService;
late AppState _appState;
@override
void initState() {
super.initState();
dialogService = getIt<DialogService>();
_appState = getIt<AppState>();
// Initialize symptom groups based on selected organs
WidgetsBinding.instance.addPostFrameCallback((_) {
final viewModel = context.read<SymptomsCheckerViewModel>();
@ -92,6 +95,8 @@ class _SuggestionsScreenState extends State<SuggestionsScreen> {
}
Widget _buildSuggestionsList(SymptomsCheckerViewModel viewModel) {
final isArabic = _appState.isArabic();
return Container(
key: ValueKey<int>(viewModel.suggestionsList.length),
width: double.infinity,
@ -102,7 +107,7 @@ class _SuggestionsScreenState extends State<SuggestionsScreen> {
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<SuggestionsScreen> {
),
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,
),
)

@ -1,6 +1,7 @@
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';
@ -26,11 +27,13 @@ class SymptomsSelectorPage extends StatefulWidget {
class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
late DialogService dialogService;
late AppState _appState;
@override
void initState() {
super.initState();
dialogService = getIt<DialogService>();
_appState = getIt<AppState>();
// Initialize symptom groups based on selected organs
WidgetsBinding.instance.addPostFrameCallback((_) {
final viewModel = context.read<SymptomsCheckerViewModel>();
@ -100,10 +103,11 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
// 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;
}
}
@ -141,6 +145,8 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
String organName,
List<BodySymptom> symptoms,
) {
final isArabic = _appState.isArabic();
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 24.w),
@ -154,7 +160,7 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
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),
),
),
@ -166,7 +172,7 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
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),
@ -306,7 +312,7 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
fontSize: 16.f,
),
),
],
],
),
SizedBox(height: 24.h),
],

@ -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';
@ -32,12 +33,14 @@ class TriagePage extends StatefulWidget {
class _TriagePageState extends State<TriagePage> {
late SymptomsCheckerViewModel viewModel;
late DialogService dialogService;
late AppState _appState;
@override
void initState() {
super.initState();
viewModel = context.read<SymptomsCheckerViewModel>();
dialogService = getIt.get<DialogService>();
_appState = getIt.get<AppState>();
// Start triage process when screen loads
WidgetsBinding.instance.addPostFrameCallback((_) {
@ -436,7 +439,8 @@ class _TriagePageState extends State<TriagePage> {
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) {
@ -445,7 +449,7 @@ class _TriagePageState extends State<TriagePage> {
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;

@ -43,13 +43,10 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
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 _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
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 _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
).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<AppState>();
@ -151,7 +163,7 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
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);

@ -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),
),
),
)
],
),
],

@ -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<UserInfoFlowManager> {
late PageController _pageController;
late SymptomsCheckerViewModel _viewModel;
// Page titles
final List<String> _pageTitles = [
"Your Gender",
"Your Birth Date",
"Your Height",
"Your Weight",
];
// Get localized page titles
List<String> _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<UserInfoFlowManager> {
? // 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<UserInfoFlowManager> {
@override
Widget build(BuildContext context) {
final pageTitles = _getPageTitles(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
@ -235,7 +240,7 @@ class _UserInfoFlowManagerState extends State<UserInfoFlowManager> {
Expanded(
child: CollapsingListView(
physics: NeverScrollableScrollPhysics(),
title: _pageTitles[_viewModel.userInfoCurrentPage],
title: pageTitles[_viewModel.userInfoCurrentPage],
isLeading: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -2,6 +2,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
@ -24,8 +26,11 @@ class ConditionCard extends StatelessWidget {
this.onActionPressed,
});
/// Get title from condition
String get title => condition.commonName ?? condition.name ?? '';
/// Get title from condition (localized)
String get title {
final appState = getIt<AppState>();
return condition.getDisplayName(isArabic: appState.isArabic());
}
/// Get percentage from probability (0-1 to 0-100)
int get percentage => ((condition.probability ?? 0) * 100).toInt();
@ -69,14 +74,14 @@ class ConditionCard extends StatelessWidget {
return LocaleKeys.emergency.tr(context: context);
case TriageLevelEnum.consultation24:
case TriageLevelEnum.consultation:
return "Seek Medical Advice".needTranslation;
return LocaleKeys.seekMedicalAdvice.tr(context: context);
case TriageLevelEnum.selfCare:
return LocaleKeys.monitor.tr(context: context);
}
}
// Default based on probability
if (percentage >= 70) {
return "Seek Medical Advice".needTranslation;
return LocaleKeys.seekMedicalAdvice.tr(context: context);
} else {
return LocaleKeys.monitor.tr(context: context);
}
@ -85,7 +90,7 @@ class ConditionCard extends StatelessWidget {
/// Get monitor note if applicable
String? getMonitorNote(BuildContext context) {
if (severityEnum == PossibleConditionsSeverityEnum.monitorOnly) {
return "No need to visit doctor".needTranslation;
return LocaleKeys.noNeedToVisitDoctor.tr(context: context);
}
return null;
}
@ -236,7 +241,7 @@ class ConditionCard extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Common Symptom".needTranslation.toText14(weight: FontWeight.w600, color: AppColors.textColor),
LocaleKeys.commonSymptom.tr(context: context).toText14(weight: FontWeight.w600, color: AppColors.textColor),
_buildSymptomsRow(),
SizedBox(height: 16.h),
LocaleKeys.description.tr(context: context).toText14(weight: FontWeight.bold, color: AppColors.textColor),
@ -244,7 +249,7 @@ class ConditionCard extends StatelessWidget {
description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
if (severityEnum != PossibleConditionsSeverityEnum.monitorOnly)
CustomButton(
text: "Book Appointment".needTranslation,
text: LocaleKeys.bookAppointment.tr(context: context),
onPressed: () {
if (onActionPressed != null) {
onActionPressed!();

@ -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<InteractiveBodyWidget> {
(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),
);
},
),
],

@ -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)

@ -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<VitalSignPage> {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: 'Vital Signs',
title: LocaleKeys.vitalSigns.tr(context: context),
child: Consumer<HmgServicesViewModel>(
builder: (context, viewModel, child) {
@ -70,14 +72,14 @@ class _VitalSignPageState extends State<VitalSignPage> {
// 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<VitalSignPage> {
// 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<VitalSignPage> {
// 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<VitalSignPage> {
// 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<VitalSignPage> {
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<VitalSignPage> {
// 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<VitalSignPage> {
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<VitalSignPage> {
// 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,

@ -212,7 +212,7 @@ Widget exceptionBottomSheetWidget(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.cancel.tr(),
text: LocaleKeys.cancel.tr(context: context),
onPressed: () {
Navigator.of(context).pop();
},
@ -226,7 +226,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,
@ -240,7 +240,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();
@ -266,7 +266,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,
@ -280,14 +280,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,

@ -48,7 +48,7 @@ class _AppLanguageChangeState extends State<AppLanguageChange> {
),
),
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);

@ -74,15 +74,18 @@ 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: Text(
if (text.isNotEmpty)
Text(
text,
overflow: textOverflow,
overflow: textOverflow ?? TextOverflow.ellipsis,
maxLines: 1,
textAlign: TextAlign.center,
style: context.dynamicTextStyle(
fontSize: fontS,
color: isDisabled ? AppColors.greyTextColor : textColor,
@ -90,7 +93,6 @@ class CustomButton extends StatelessWidget {
fontWeight: fontWeight,
),
),
),
],
),
));

@ -42,13 +42,13 @@ class BottomSheetUtils{
Future<void> _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,

@ -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,
);
}
}

@ -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<AppState>();
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),

Loading…
Cancel
Save