Merge branch 'master' into dev_aamir

# Conflicts:
#	lib/presentation/profile_settings/profile_settings.dart
pull/166/head
aamir-csol 2 weeks ago
commit 2bbfe1f131

@ -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,5 @@
<svg width="24" height="22" viewBox="0 0 24 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="7" cy="7" r="7" fill="#0B85F7" fill-opacity="0.75"/>
<circle cx="17" cy="7" r="7" fill="#18C273" fill-opacity="0.75"/>
<circle cx="12" cy="15" r="7" fill="#ED1C2B" fill-opacity="0.75"/>
</svg>

After

Width:  |  Height:  |  Size: 301 B

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

@ -841,7 +841,7 @@ class ApiConsts {
static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors';
static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion';
static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis';
static final String explain = '$symptomsCheckerApi/explain';
static final String explain = '$symptomsCheckerApi/ExplainDiagnosisResult';
//E-REFERRAL SERVICES
static final getAllRelationshipTypes = "Services/Patients.svc/REST/GetAllRelationshipTypes";

@ -254,6 +254,7 @@ class AppAssets {
static const String homeBorderedIcon = '$svgBasePath/home_bordered.svg';
static const String symptomCheckerIcon = '$svgBasePath/symptom_checker_icon.svg';
static const String symptomCheckerBottomIcon = '$svgBasePath/symptom_bottom_icon.svg';
static const String coloredDotsIcon = '$svgBasePath/colored_dots_icon.svg';
// Water Monitor
static const String waterBottle = '$svgBasePath/water_bottle.svg';
@ -306,6 +307,9 @@ class AppAssets {
static const String bloodPressure = '$svgBasePath/blood_pressure.svg';
static const String temperature = '$svgBasePath/temperature.svg';
static const String arLangIcon = '$svgBasePath/ar_lang_icon.svg';
static const String enLangIcon = '$svgBasePath/en_lang_icon.svg';
// PNGS //
static const String hmgLogo = '$pngBasePath/hmg_logo.png';
static const String liveCareService = '$pngBasePath/livecare_service.png';
@ -353,4 +357,3 @@ class AppAnimations {
static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json';
static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json';
}

@ -311,3 +311,150 @@ extension ServiceTypeEnumExt on ServiceTypeEnum {
enum PossibleConditionsSeverityEnum { seekMedicalAdvice, monitorOnly, emergency }
enum HealthTrackerTypeEnum { bloodSugar, bloodPressure, weightTracker }
// Severity Enum
enum SeverityEnum { mild, moderate, severe }
extension SeverityEnumExtension on SeverityEnum {
int get toInt {
switch (this) {
case SeverityEnum.mild:
return 0;
case SeverityEnum.moderate:
return 1;
case SeverityEnum.severe:
return 2;
}
}
String get displayName {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case SeverityEnum.mild:
return isArabic ? 'خفيف' : 'Mild';
case SeverityEnum.moderate:
return isArabic ? 'متوسط' : 'Moderate';
case SeverityEnum.severe:
return isArabic ? 'شديد' : 'Severe';
}
}
static SeverityEnum? fromInt(int value) {
switch (value) {
case 0:
return SeverityEnum.mild;
case 1:
return SeverityEnum.moderate;
case 2:
return SeverityEnum.severe;
default:
return null;
}
}
}
// Triage Level Enum
enum TriageLevelEnum { emergencyAmbulance, emergency, consultation24, consultation, selfCare }
extension TriageLevelEnumExtension on TriageLevelEnum {
int get toInt {
switch (this) {
case TriageLevelEnum.emergencyAmbulance:
return 0;
case TriageLevelEnum.emergency:
return 1;
case TriageLevelEnum.consultation24:
return 2;
case TriageLevelEnum.consultation:
return 3;
case TriageLevelEnum.selfCare:
return 4;
}
}
String get displayName {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case TriageLevelEnum.emergencyAmbulance:
return isArabic ? 'طوارئ - إسعاف' : 'Emergency - Ambulance';
case TriageLevelEnum.emergency:
return isArabic ? 'طوارئ' : 'Emergency';
case TriageLevelEnum.consultation24:
return isArabic ? 'استشارة خلال 24 ساعة' : 'Consultation within 24 hours';
case TriageLevelEnum.consultation:
return isArabic ? 'استشارة' : 'Consultation';
case TriageLevelEnum.selfCare:
return isArabic ? 'رعاية ذاتية' : 'Self Care';
}
}
static TriageLevelEnum? fromInt(int value) {
switch (value) {
case 0:
return TriageLevelEnum.emergencyAmbulance;
case 1:
return TriageLevelEnum.emergency;
case 2:
return TriageLevelEnum.consultation24;
case 3:
return TriageLevelEnum.consultation;
case 4:
return TriageLevelEnum.selfCare;
default:
return null;
}
}
}
// Question Type Enum
enum QuestionTypeEnum { single, groupSingle, groupMultiple, duration }
extension QuestionTypeEnumExtension on QuestionTypeEnum {
int get toInt {
switch (this) {
case QuestionTypeEnum.single:
return 0;
case QuestionTypeEnum.groupSingle:
return 1;
case QuestionTypeEnum.groupMultiple:
return 2;
case QuestionTypeEnum.duration:
return 3;
}
}
String get displayName {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case QuestionTypeEnum.single:
return isArabic ? 'سؤال واحد' : 'Single';
case QuestionTypeEnum.groupSingle:
return isArabic ? 'مجموعة - اختيار واحد' : 'Group Single';
case QuestionTypeEnum.groupMultiple:
return isArabic ? 'مجموعة - اختيار متعدد' : 'Group Multiple';
case QuestionTypeEnum.duration:
return isArabic ? 'المدة' : 'Duration';
}
}
static QuestionTypeEnum? fromInt(int value) {
switch (value) {
case 0:
return QuestionTypeEnum.single;
case 1:
return QuestionTypeEnum.groupSingle;
case 2:
return QuestionTypeEnum.groupMultiple;
case 3:
return QuestionTypeEnum.duration;
default:
return null;
}
}
}

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

@ -1,97 +1,97 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
class ConditionsModel {
final IconData icon;
final String title;
final int percentage;
final String tagText;
final String clinic;
final List<String> symptoms;
final String description;
final String? monitorNote;
final String? appointmentLabel;
final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum;
ConditionsModel({
required this.icon,
required this.title,
required this.percentage,
required this.tagText,
required this.clinic,
required this.symptoms,
required this.description,
required this.possibleConditionsSeverityEnum,
this.monitorNote,
this.appointmentLabel,
});
}
List<ConditionsModel> dummyConditions = [
ConditionsModel(
icon: Icons.psychology_alt,
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice,
title: "Migraine",
percentage: 87,
tagText: "Seek Medical Advice",
clinic: "Internal Medicine Clinic",
symptoms: ["Headache", "Nausea", "Sensitivity to light"],
description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.",
appointmentLabel: "Book Appointment",
),
ConditionsModel(
icon: Icons.deblur,
title: "Tension Headache",
percentage: 37,
tagText: "Monitor",
monitorNote: "No need to visit doctor",
clinic: "GP Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly,
),
ConditionsModel(
icon: Icons.medication_liquid,
title: "Meningitis",
percentage: 28,
tagText: "Emergency",
clinic: "Neurology Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
appointmentLabel: "Book Appointment",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency,
),
ConditionsModel(
icon: Icons.psychology_alt,
title: "Migraine",
percentage: 87,
tagText: "Seek Medical Advice",
clinic: "Internal Medicine Clinic",
symptoms: ["Headache", "Nausea", "Sensitivity to light"],
description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.",
appointmentLabel: "Book Appointment",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice,
),
ConditionsModel(
icon: Icons.deblur,
title: "Tension Headache",
percentage: 37,
tagText: "Monitor",
monitorNote: "No need to visit doctor",
clinic: "GP Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly,
),
ConditionsModel(
icon: Icons.medication_liquid,
title: "Meningitis",
percentage: 28,
tagText: "Emergency",
clinic: "Neurology Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
appointmentLabel: "Book Appointment",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency,
),
];
// import 'package:flutter/material.dart';
// import 'package:hmg_patient_app_new/core/enums.dart';
//
// class ConditionsModel {
// final IconData icon;
// final String title;
// final int percentage;
// final String tagText;
// final String clinic;
// final List<String> symptoms;
// final String description;
// final String? monitorNote;
// final String? appointmentLabel;
// final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum;
//
// ConditionsModel({
// required this.icon,
// required this.title,
// required this.percentage,
// required this.tagText,
// required this.clinic,
// required this.symptoms,
// required this.description,
// required this.possibleConditionsSeverityEnum,
// this.monitorNote,
// this.appointmentLabel,
// });
// }
//
// List<ConditionsModel> dummyConditions = [
// ConditionsModel(
// icon: Icons.psychology_alt,
// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice,
// title: "Migraine",
// percentage: 87,
// tagText: "Seek Medical Advice",
// clinic: "Internal Medicine Clinic",
// symptoms: ["Headache", "Nausea", "Sensitivity to light"],
// description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.",
// appointmentLabel: "Book Appointment",
// ),
// ConditionsModel(
// icon: Icons.deblur,
// title: "Tension Headache",
// percentage: 37,
// tagText: "Monitor",
// monitorNote: "No need to visit doctor",
// clinic: "GP Clinic",
// symptoms: ["Mild head pressure", "Scalp tenderness"],
// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly,
// ),
// ConditionsModel(
// icon: Icons.medication_liquid,
// title: "Meningitis",
// percentage: 28,
// tagText: "Emergency",
// clinic: "Neurology Clinic",
// symptoms: ["Mild head pressure", "Scalp tenderness"],
// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
// appointmentLabel: "Book Appointment",
// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency,
// ),
// ConditionsModel(
// icon: Icons.psychology_alt,
// title: "Migraine",
// percentage: 87,
// tagText: "Seek Medical Advice",
// clinic: "Internal Medicine Clinic",
// symptoms: ["Headache", "Nausea", "Sensitivity to light"],
// description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.",
// appointmentLabel: "Book Appointment",
// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice,
// ),
// ConditionsModel(
// icon: Icons.deblur,
// title: "Tension Headache",
// percentage: 37,
// tagText: "Monitor",
// monitorNote: "No need to visit doctor",
// clinic: "GP Clinic",
// symptoms: ["Mild head pressure", "Scalp tenderness"],
// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly,
// ),
// ConditionsModel(
// icon: Icons.medication_liquid,
// title: "Meningitis",
// percentage: 28,
// tagText: "Emergency",
// clinic: "Neurology Clinic",
// symptoms: ["Mild head pressure", "Scalp tenderness"],
// description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
// appointmentLabel: "Book Appointment",
// possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency,
// ),
// ];

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

@ -1,3 +1,5 @@
import 'package:hmg_patient_app_new/core/enums.dart';
class TriageDataDetails {
final TriageQuestion? question;
final List<TriageCondition>? conditions;
@ -170,13 +172,17 @@ class TriageCondition {
final String? id;
final String? name;
final String? commonName;
final String? nameAr;
final String? commonNameAr;
final double? probability;
final dynamic conditionDetails;
final ConditionDetails? conditionDetails;
TriageCondition({
this.id,
this.name,
this.commonName,
this.nameAr,
this.commonNameAr,
this.probability,
this.conditionDetails,
});
@ -186,8 +192,10 @@ class TriageCondition {
id: json['id'],
name: json['name'],
commonName: json['common_name'],
nameAr: json['nameAr'],
commonNameAr: json['common_nameAr'],
probability: json['probability']?.toDouble(),
conditionDetails: json['condition_details'],
conditionDetails: json['condition_details'] != null ? ConditionDetails.fromJson(json['condition_details']) : null,
);
}
@ -196,14 +204,96 @@ class TriageCondition {
'id': id,
'name': name,
'common_name': commonName,
'nameAr': nameAr,
'common_nameAr': commonNameAr,
'probability': probability,
'condition_details': conditionDetails,
'condition_details': conditionDetails?.toJson(),
};
}
/// Get display name based on locale
String getDisplayName({bool isArabic = false}) {
if (isArabic) {
return commonNameAr ?? nameAr ?? commonName ?? name ?? '';
}
return commonName ?? name ?? '';
}
/// Get probability as percentage
String getProbabilityPercentage() {
if (probability == null) return '0%';
return '${(probability! * 100).toStringAsFixed(1)}%';
}
}
class ConditionDetails {
final String? icd10Code;
final ConditionCategory? category;
final SeverityEnum? severity;
final TriageLevelEnum? triageLevel;
final String? hint;
final bool? hasPatientEducation;
final String? prevalence;
final String? acuteness;
ConditionDetails({
this.icd10Code,
this.category,
this.severity,
this.triageLevel,
this.hint,
this.hasPatientEducation,
this.prevalence,
this.acuteness,
});
factory ConditionDetails.fromJson(Map<String, dynamic> json) {
return ConditionDetails(
icd10Code: json['icd10_code'],
category: json['category'] != null ? ConditionCategory.fromJson(json['category']) : null,
severity: json['severity'] != null ? SeverityEnumExtension.fromInt(json['severity']) : null,
triageLevel: json['triage_level'] != null ? TriageLevelEnumExtension.fromInt(json['triage_level']) : null,
hint: json['hint'],
hasPatientEducation: json['has_patient_education'],
prevalence: json['prevalence'],
acuteness: json['acuteness'],
);
}
Map<String, dynamic> toJson() {
return {
'icd10_code': icd10Code,
'category': category?.toJson(),
'severity': severity?.toInt,
'triage_level': triageLevel?.toInt,
'hint': hint,
'has_patient_education': hasPatientEducation,
'prevalence': prevalence,
'acuteness': acuteness,
};
}
}
class ConditionCategory {
final String? id;
final String? name;
ConditionCategory({
this.id,
this.name,
});
factory ConditionCategory.fromJson(Map<String, dynamic> json) {
return ConditionCategory(
id: json['id'],
name: json['name'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
};
}
}

@ -12,50 +12,42 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class SymptomsCheckerRepo {
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>>
getUserDetails({
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> getUserDetails({
required String userName,
required String password,
});
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>>
getBodySymptomsByName({
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({
required List<String> organNames,
required String userSessionToken,
required int gender,
});
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getRiskFactors({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getRiskFactors({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
});
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getSuggestions({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getSuggestions({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required String sessionId,
required int gender,
});
Future<Either<Failure, GenericApiModel<TriageDataDetails>>>
getDiagnosisForTriage({
Future<Either<Failure, GenericApiModel<TriageDataDetails>>> getDiagnosisForTriage({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
List<Map<String, String>>? triageEvidence,
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
});
}
@ -64,16 +56,14 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
final ApiClient apiClient;
final LoggerService loggerService;
SymptomsCheckerRepoImp(
{required this.apiClient, required this.loggerService});
SymptomsCheckerRepoImp({required this.apiClient, required this.loggerService});
@override
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>>
getUserDetails({
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> getUserDetails({
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;
@ -92,11 +82,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// Parse response if it's a string
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel =
SymptomsUserDetailsResponseModel.fromJson(responseData);
SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel = SymptomsUserDetailsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<SymptomsUserDetailsResponseModel>(
messageStatus: messageStatus ?? 1,
@ -123,8 +111,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
}
@override
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>>
getBodySymptomsByName({
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({
required List<String> organNames,
required String userSessionToken,
required int gender,
@ -154,8 +141,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
BodySymptomResponseModel bodySymptomResponse =
BodySymptomResponseModel.fromJson(response);
BodySymptomResponseModel bodySymptomResponse = BodySymptomResponseModel.fromJson(response);
apiResponse = GenericApiModel<BodySymptomResponseModel>(
messageStatus: messageStatus ?? 1,
@ -164,8 +150,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
data: bodySymptomResponse,
);
} catch (e, stackTrace) {
loggerService
.logError("Error parsing GetBodySymptomsByName response: $e");
loggerService.logError("Error parsing GetBodySymptomsByName response: $e");
loggerService.logError("StackTrace: $stackTrace");
failure = DataParsingFailure(e.toString());
}
@ -183,21 +168,19 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
}
@override
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getRiskFactors({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getRiskFactors({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
}) async {
final Map<String, dynamic> body = {
"age": {
"value": age,
},
"sex": sex,
"gender": gender,
"evidence": evidenceIds.map((id) => {"id": id}).toList(),
"language": language,
"generalId": sessionId,
@ -225,11 +208,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// Parse response if it's a string
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
RiskAndSuggestionsResponseModel riskFactorsResponse =
RiskAndSuggestionsResponseModel.fromJson(responseData);
RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>(
messageStatus: messageStatus ?? 1,
@ -255,16 +236,14 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
}
}
Future<Either<Failure, GenericApiModel<TriageDataDetails>>>
getDiagnosisForTriage({
@override
Future<Either<Failure, GenericApiModel<TriageDataDetails>>> getDiagnosisForTriage({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
List<Map<String, String>>?
triageEvidence, // Additional triage-specific evidence
List<Map<String, String>>? triageEvidence, // Additional triage-specific evidence
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
}) async {
// Build evidence list: combine initial symptoms with triage evidence
@ -284,7 +263,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
"age": {
"value": age,
},
"sex": sex,
"gender": gender,
"evidence": evidenceList,
"language": language,
"suggest_method": "diagnosis",
@ -313,13 +292,11 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// Parse response if it's a string
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
final updatedResponseData = responseData['dataDetails'];
TriageDataDetails riskFactorsResponse =
TriageDataDetails.fromJson(updatedResponseData);
TriageDataDetails riskFactorsResponse = TriageDataDetails.fromJson(updatedResponseData);
apiResponse = GenericApiModel<TriageDataDetails>(
messageStatus: messageStatus ?? 1,
@ -328,8 +305,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
data: riskFactorsResponse,
);
} catch (e, stackTrace) {
loggerService
.logError("Error parsing getDiagnosisForTriage response: $e");
loggerService.logError("Error parsing getDiagnosisForTriage response: $e");
loggerService.logError("StackTrace: $stackTrace");
failure = DataParsingFailure(e.toString());
}
@ -347,21 +323,19 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
}
@override
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getSuggestions({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getSuggestions({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required String sessionId,
required int gender,
}) async {
final Map<String, dynamic> body = {
"age": {
"value": age,
},
"sex": sex,
"gender": gender,
"evidence": evidenceIds.map((id) => {"id": id}).toList(),
"language": language,
"generalId": sessionId,
@ -389,11 +363,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// Parse response if it's a string
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
RiskAndSuggestionsResponseModel riskFactorsResponse =
RiskAndSuggestionsResponseModel.fromJson(responseData);
RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>(
messageStatus: messageStatus ?? 1,

@ -1,6 +1,6 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/data/organ_mapping_data.dart';
@ -23,6 +23,23 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
required this.appState,
});
// Gender constants for both English and Arabic
static const String _maleEn = "male";
static const String _femaleEn = "female";
static const String _maleAr = "ذكر";
static const String _femaleAr = "أنثى";
/// Convert gender string to integer (1 for male, 2 for female)
/// Handles both English and Arabic values
int _getGenderAsInt(String? gender) {
if (gender == null) return 1; // Default to male
final lowerGender = gender.toLowerCase();
if (lowerGender == _maleEn || gender == _maleAr) {
return 1;
}
return 2; // Female or any other value
}
// State variables
bool isBodyHidden = false;
BodyView _currentView = BodyView.front;
@ -47,12 +64,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
TriageDataDetails? triageDataDetails;
// Triage state
int?
_selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility
final Map<String, int> _selectedTriageChoicesByItemId =
{}; // Map of itemId -> choiceIndex for multi-item questions
final List<Map<String, String>> _triageEvidenceList =
[]; // Store triage evidence with proper format
int? _selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility
final Map<String, int> _selectedTriageChoicesByItemId = {}; // Map of itemId -> choiceIndex for multi-item questions
final List<Map<String, String>> _triageEvidenceList = []; // Store triage evidence with proper format
int _triageQuestionCount = 0; // Track number of triage questions answered
// Selected risk factors tracking
@ -66,8 +80,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// User Info Flow State
int _userInfoCurrentPage = 0;
bool _isSinglePageEditMode =
false; // Track if editing single page or full flow
bool _isSinglePageEditMode = false; // Track if editing single page or full flow
String? _selectedGender;
DateTime? _dateOfBirth;
int? _selectedAge;
@ -107,17 +120,14 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
String? get tooltipOrganId => _tooltipOrganId;
String get currentSessionAuthToken =>
symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? "";
String get currentSessionAuthToken => symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? "";
String get currentSessionId =>
symptomsUserDetailsResponseModel?.sessionId ?? "";
String get currentSessionId => symptomsUserDetailsResponseModel?.sessionId ?? "";
// Triage-related getters
bool get shouldStopTriage => triageDataDetails?.shouldStop ?? false;
bool get hasEmergencyEvidence =>
triageDataDetails?.hasEmergencyEvidence ?? false;
bool get hasEmergencyEvidence => triageDataDetails?.hasEmergencyEvidence ?? false;
String? get currentInterviewToken => triageDataDetails?.interviewToken;
@ -137,15 +147,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Check if all items in current question have been answered
bool get areAllTriageItemsAnswered {
if (currentTriageQuestion?.items == null ||
currentTriageQuestion!.items!.isEmpty) {
if (currentTriageQuestion?.items == null || currentTriageQuestion!.items!.isEmpty) {
return false;
}
// Check if we have an answer for each item
for (var item in currentTriageQuestion!.items!) {
if (item.id != null &&
!_selectedTriageChoicesByItemId.containsKey(item.id)) {
if (item.id != null && !_selectedTriageChoicesByItemId.containsKey(item.id)) {
return false;
}
}
@ -153,8 +161,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
/// Get organs for current view
List<OrganModel> get currentOrgans =>
OrganData.getOrgansForView(_currentView);
List<OrganModel> get currentOrgans => OrganData.getOrgansForView(_currentView);
/// Get all selected organs from both views
List<OrganModel> get selectedOrgans {
@ -162,9 +169,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
...OrganData.frontViewOrgans,
...OrganData.backViewOrgans,
];
return allOrgans
.where((organ) => _selectedOrganIds.contains(organ.id))
.toList();
return allOrgans.where((organ) => _selectedOrganIds.contains(organ.id)).toList();
}
/// Check if any organs are selected
@ -181,13 +186,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
int get totalSelectedSymptomsCount {
return _selectedSymptomsByOrgan.values
.fold(0, (sum, symptomIds) => sum + symptomIds.length);
return _selectedSymptomsByOrgan.values.fold(0, (sum, symptomIds) => sum + symptomIds.length);
}
bool get hasSelectedSymptoms {
return _selectedSymptomsByOrgan.values
.any((symptomIds) => symptomIds.isNotEmpty);
return _selectedSymptomsByOrgan.values.any((symptomIds) => symptomIds.isNotEmpty);
}
/// Get risk factors list
@ -213,8 +216,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
void toggleView() {
_currentView =
_currentView == BodyView.front ? BodyView.back : BodyView.front;
_currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front;
notifyListeners();
}
@ -317,8 +319,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
return;
}
List<String> organNames =
selectedOrgans.map((organ) => organ.name).toList();
List<String> organNames = selectedOrgans.map((organ) => organ.name).toList();
await getBodySymptomsByName(
organNames: organNames,
@ -368,8 +369,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
}
if (matchingOrganId != null &&
_selectedSymptomsByOrgan.containsKey(matchingOrganId)) {
if (matchingOrganId != null && _selectedSymptomsByOrgan.containsKey(matchingOrganId)) {
final selectedIds = _selectedSymptomsByOrgan[matchingOrganId]!;
if (organResult.bodySymptoms != null) {
@ -420,10 +420,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Get all selected risk factors
List<RiskAndSuggestionsItemModel> getAllSelectedRiskFactors() {
return riskFactorsList
.where((factor) =>
factor.id != null && _selectedRiskFactorIds.contains(factor.id))
.toList();
return riskFactorsList.where((factor) => factor.id != null && _selectedRiskFactorIds.contains(factor.id)).toList();
}
/// Clear all risk factor selections
@ -456,12 +453,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
// Extract symptom IDs
List<String> evidenceIds =
selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
List<String> evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
await getRiskFactors(
age: _selectedAge!,
sex: _selectedGender!.toLowerCase(),
gender: _getGenderAsInt(_selectedGender),
evidenceIds: evidenceIds,
sessionId: currentSessionId,
language: appState.isArabic() ? 'ar' : 'en',
@ -481,7 +477,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Call Risk Factors API
Future<void> getRiskFactors({
required int age,
required String sex,
required int gender,
required String sessionId,
required List<String> evidenceIds,
required String language,
@ -493,12 +489,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getRiskFactors(
age: age,
sex: sex,
gender: gender,
evidenceIds: evidenceIds,
language: language,
sessionId: sessionId,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(
@ -515,13 +510,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
riskFactorsResponse = apiResponse.data;
if (riskFactorsResponse != null &&
riskFactorsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem =
RiskAndSuggestionsItemModel(
if (riskFactorsResponse != null && riskFactorsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel(
id: "not_applicable",
commonName: "Not Applicable",
name: "Not Applicable",
commonNameAr: "لا ينطبق",
nameAr: "لا ينطبق",
language: appState.isArabic() ? 'ar' : 'en',
type: null,
);
@ -572,10 +567,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Get all selected risk factors
List<RiskAndSuggestionsItemModel> getAllSelectedSuggestions() {
return suggestionsList
.where((factor) =>
factor.id != null && _selectedSuggestionsIds.contains(factor.id))
.toList();
return suggestionsList.where((factor) => factor.id != null && _selectedSuggestionsIds.contains(factor.id)).toList();
}
/// Clear all risk factor selections
@ -590,20 +582,15 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// Add selected symptoms
final selectedSymptoms = getAllSelectedSymptoms();
evidenceIds
.addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!));
evidenceIds.addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!));
// Add selected risk factors (excluding "not_applicable")
final selectedRiskFactors = getAllSelectedRiskFactors();
evidenceIds.addAll(selectedRiskFactors
.where((rf) => rf.id != null && rf.id != "not_applicable")
.map((rf) => rf.id!));
evidenceIds.addAll(selectedRiskFactors.where((rf) => rf.id != null && rf.id != "not_applicable").map((rf) => rf.id!));
// Add selected suggestions (excluding "not_applicable")
final selectedSuggestions = getAllSelectedSuggestions();
evidenceIds.addAll(selectedSuggestions
.where((s) => s.id != null && s.id != "not_applicable")
.map((s) => s.id!));
evidenceIds.addAll(selectedSuggestions.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!));
return evidenceIds;
}
@ -632,23 +619,19 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
// Extract symptom IDs
List<String> evidenceIds =
selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
List<String> evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
// Get all selected symptoms
final selectedRisks = getAllSelectedRiskFactors();
if (selectedRisks.isNotEmpty) {
List<String> evidenceRisksIds = selectedRisks
.where((s) => s.id != null && s.id != "not_applicable")
.map((s) => s.id!)
.toList();
List<String> evidenceRisksIds = selectedRisks.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!).toList();
evidenceIds.addAll(evidenceRisksIds);
}
await getSuggestions(
age: _selectedAge!,
sex: _selectedGender!.toLowerCase(),
gender: _getGenderAsInt(_selectedGender),
evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) {
@ -667,7 +650,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Call Suggestions API
Future<void> getSuggestions({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
required String language,
Function(RiskAndSuggestionsResponseModel)? onSuccess,
@ -678,12 +661,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getSuggestions(
age: age,
sex: sex,
gender: gender,
evidenceIds: evidenceIds,
language: language,
sessionId: currentSessionId,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(
@ -700,13 +682,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
suggestionsResponse = apiResponse.data;
if (suggestionsResponse != null &&
suggestionsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem =
RiskAndSuggestionsItemModel(
if (suggestionsResponse != null && suggestionsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel(
id: "not_applicable",
commonName: "Not Applicable",
name: "Not Applicable",
commonNameAr: "لا ينطبق",
nameAr: "لا ينطبق",
language: appState.isArabic() ? 'ar' : 'en',
type: null,
);
@ -730,7 +712,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Call Diagnosis API for Triage - This is called iteratively until shouldStop is true
Future<void> getDiagnosisForTriage({
required int age,
required String sex,
required int gender,
required List<String> evidenceIds,
List<Map<String, String>>? triageEvidence,
required String language,
@ -742,13 +724,12 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getDiagnosisForTriage(
age: age,
sex: sex,
gender: gender,
evidenceIds: evidenceIds,
triageEvidence: triageEvidence,
language: language,
sessionId: currentSessionId,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(
@ -804,7 +785,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
await getDiagnosisForTriage(
age: _selectedAge!,
sex: _selectedGender!.toLowerCase(),
gender: _getGenderAsInt(_selectedGender),
evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) {
@ -941,8 +922,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// Calculate age from date of birth
final now = DateTime.now();
int age = now.year - dateOfBirth.year;
if (now.month < dateOfBirth.month ||
(now.month == dateOfBirth.month && now.day < dateOfBirth.day)) {
if (now.month < dateOfBirth.month || (now.month == dateOfBirth.month && now.day < dateOfBirth.day)) {
age--;
}
_selectedAge = age;
@ -968,6 +948,22 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
bool get isUserInfoFirstPage => _userInfoCurrentPage == 0;
/// Check if current user info page has valid selection
bool get isCurrentUserInfoPageValid {
switch (_userInfoCurrentPage) {
case 0: // Gender page
return _selectedGender != null && _selectedGender!.isNotEmpty;
case 1: // Age/Birth date page
return _dateOfBirth != null || (_selectedAge != null && _selectedAge! > 0);
case 2: // Height page
return _selectedHeight > 0;
case 3: // Weight page
return _selectedWeight > 0;
default:
return false;
}
}
/// Validate and submit user info
Map<String, dynamic> getUserInfoData() {
return {
@ -989,8 +985,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}) async {
isBodySymptomsLoading = true;
notifyListeners();
final result = await symptomsCheckerRepo.getUserDetails(
userName: userName, password: password);
final result = await symptomsCheckerRepo.getUserDetails(userName: userName, password: password);
result.fold(
(failure) async {
@ -1030,7 +1025,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getBodySymptomsByName(
organNames: organNames,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
gender: _getGenderAsInt(selectedGender ?? "Male"),
);
result.fold(

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

@ -50,7 +50,14 @@ class ServicesPage extends StatelessWidget {
late MedicalFileViewModel medicalFileViewModel;
late final List<HmgServicesComponentModel> hmgServices = [
HmgServicesComponentModel(11, LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, bgColor: AppColors.primaryRedColor, true, route: null, onTap: () async {
HmgServicesComponentModel(
11,
LocaleKeys.emergencyServices.tr(),
"",
AppAssets.emergency_services_icon,
bgColor: AppColors.primaryRedColor,
true,
route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<EmergencyServicesViewModel>().flushData();
getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
@ -59,7 +66,7 @@ class ServicesPage extends StatelessWidget {
getIt.get<EmergencyServicesViewModel>().getRRTOrders(
showLoader: false,
);
Navigator.of(GetIt.instance<NavigationService>().navigatorKey.currentContext!).push(
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'),
@ -78,7 +85,8 @@ class ServicesPage extends StatelessWidget {
true,
route: AppRoutes.bookAppointmentPage,
),
HmgServicesComponentModel(5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async {
HmgServicesComponentModel(
5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.comprehensiveCheckupPage);
} else {
@ -131,7 +139,7 @@ class ServicesPage extends StatelessWidget {
},
),
HmgServicesComponentModel(
11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async {
11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.eReferralPage);
} else {
@ -387,19 +395,19 @@ class ServicesPage extends StatelessWidget {
? CustomButton(
height: 40.h,
icon: AppAssets.recharge_icon,
iconSize: 16.w,
iconColor: AppColors.infoColor,
textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 12.f,
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
},
iconSize: 16.w,
iconColor: AppColors.infoColor,
textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 12.f,
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
},
)
: SizedBox.shrink(),
],
@ -438,60 +446,60 @@ class ServicesPage extends StatelessWidget {
getIt.get<AppState>().isAuthenticated
? Wrap(
spacing: -8.h,
// runSpacing: 0.h,
children: [
Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg,
height: 28.h,
width: 28.w,
border: 1,
fit: BoxFit.contain,
borderRadius: 50.r,
),
Utils.buildImgWithAssets(
icon: AppAssets.femaleImg,
height: 28.h,
width: 28.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
Utils.buildImgWithAssets(
icon: AppAssets.maleImg,
height: 28.h,
width: 28.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
],
// runSpacing: 0.h,
children: [
Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg,
height: 28.h,
width: 28.w,
border: 1,
fit: BoxFit.contain,
borderRadius: 50.r,
),
Utils.buildImgWithAssets(
icon: AppAssets.femaleImg,
height: 28.h,
width: 28.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
Utils.buildImgWithAssets(
icon: AppAssets.maleImg,
height: 28.h,
width: 28.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
],
)
: LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.add_icon,
iconSize: 16.w,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 12.f,
onPressed: () {
DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
});
},
icon: AppAssets.add_icon,
iconSize: 16.w,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 12.f,
onPressed: () {
DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
});
},
)
: SizedBox.shrink(),
],

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

@ -28,7 +28,6 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart';
@ -62,8 +61,6 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart';
import 'package:provider/provider.dart';
import '../active_medication/active_medication_page.dart';
import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
class LandingPage extends StatefulWidget {
@ -198,10 +195,11 @@ class _LandingPageState extends State<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(
@ -236,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);
}),
@ -249,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()
],
);
}),
@ -305,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),
@ -394,22 +398,23 @@ class _LandingPageState extends State<LandingPage> {
layout: SwiperLayout.STACK,
loop: true,
itemWidth: MediaQuery.of(context).size.width - 48.h,
indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right,
controller: _controller,
itemHeight: 255.h,
pagination: SwiperPagination(
alignment: Alignment.bottomCenter,
margin: EdgeInsets.only(top: 240.h + 8 + 24),
builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor),
),
itemBuilder: (BuildContext context, int index) {
return getIndexSwiperCard(index);
},
)
indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right,
controller: _controller,
itemHeight: 255.h,
pagination: SwiperPagination(
alignment: Alignment.bottomCenter,
margin: EdgeInsets.only(top: 240.h + 8 + 24),
builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor),
),
itemBuilder: (BuildContext context, int index) {
return getIndexSwiperCard(index);
},
)
: Container(
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
@ -465,11 +470,15 @@ class _LandingPageState extends State<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,
),
Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor),
Utils.buildSvgWithAssets(
icon: AppAssets.appointment_checkin_icon,
width: 24.h,
height: 24.h,
iconColor: AppColors.primaryRedColor),
],
),
SizedBox(height: 8.h),
@ -597,10 +606,10 @@ class _LandingPageState extends State<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),
],
@ -690,10 +699,18 @@ class _LandingPageState extends State<LandingPage> {
myAppointmentsViewModel.patientQueueDetailsList.first.queueNo!.toText12(isBold: true),
SizedBox(width: 8.w),
AppCustomChipWidget(
deleteIcon: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppAssets.call_for_vitals : AppAssets.call_for_doctor,
labelText: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? LocaleKeys.callForVitalSigns.tr() : LocaleKeys.callForDoctor.tr(),
iconColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor : AppColors.successColor,
textColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor : AppColors.successColor,
deleteIcon: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppAssets.call_for_vitals
: AppAssets.call_for_doctor,
labelText: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? LocaleKeys.callForVitalSigns.tr()
: LocaleKeys.callForDoctor.tr(),
iconColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppColors.primaryRedColor
: AppColors.successColor,
textColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppColors.primaryRedColor
: AppColors.successColor,
iconSize: 14.w,
backgroundColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppColors.primaryRedColor.withValues(alpha: 0.1)
@ -707,7 +724,8 @@ class _LandingPageState extends State<LandingPage> {
: SizedBox(height: 12.h),
SizedBox(height: 5.h),
CustomButton(
text: Utils.getCardButtonText(myAppointmentsViewModel.currentQueueStatus, myAppointmentsViewModel.currentPatientQueueDetails.roomNo ?? ""),
text: Utils.getCardButtonText(
myAppointmentsViewModel.currentQueueStatus, myAppointmentsViewModel.currentPatientQueueDetails.roomNo ?? ""),
onPressed: () {},
backgroundColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus),
borderColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus).withValues(alpha: 0.01),
@ -761,7 +779,8 @@ class _LandingPageState extends State<LandingPage> {
SizedBox(width: 8.w),
AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)),
labelText: DateUtil.formatDateToDate(
DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h),
@ -769,9 +788,12 @@ class _LandingPageState extends State<LandingPage> {
],
),
SizedBox(height: 10.h),
LocaleKeys.halaFirstName.tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context).toText16(isBold: true),
LocaleKeys.halaFirstName
.tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context).toText16(isBold: true),
SizedBox(height: 8.h),
LocaleKeys.yourTurnIsAfterPatients.tr(namedArgs: {'count': immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount.toString()}, context: context).toText14(isBold: true),
LocaleKeys.yourTurnIsAfterPatients.tr(
namedArgs: {'count': immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount.toString()},
context: context).toText14(isBold: true),
SizedBox(height: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -840,7 +862,7 @@ class _LandingPageState extends State<LandingPage> {
hasShadow: true,
),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.first,
patientAppointmentHistoryResponseModel: myAppointmentsViewModel.patientAppointmentsHistoryList.first,
myAppointmentsViewModel: myAppointmentsViewModel,
bookAppointmentsViewModel: bookAppointmentsViewModel,
isLoading: false,
@ -886,7 +908,7 @@ class _LandingPageState extends State<LandingPage> {
}
} else if (index == 2) {
if ((myAppointmentsViewModel.isPatientHasQueueAppointment || immediateLiveCareViewModel.patientHasPendingLiveCareRequest) &&
myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.isNotEmpty) {
todoSectionViewModel.patientAncillaryOrdersList.isNotEmpty) {
return AncillaryOrderCard(
order: todoSectionViewModel.patientAncillaryOrdersList.first,
isLoading: false,
@ -978,7 +1000,6 @@ class _LandingPageState extends State<LandingPage> {
isCloseButtonVisible: true,
child: StatefulBuilder(
builder: (context, setState) {
return RateAppointmentDoctor();
},
),

@ -8,11 +8,8 @@ import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/hmg_services/services_page.dart';
import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/user_info_selection.dart';
import 'package:hmg_patient_app_new/presentation/todo_section/todo_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class LandingNavigation extends StatefulWidget {
const LandingNavigation({super.key});
@ -53,11 +50,7 @@ class _LandingNavigationState extends State<LandingNavigation> {
}
if (_currentIndex == 3) {
if (appState.isAuthenticated) {
Navigator.of(context).push(
CustomPageRoute(
page: UserInfoSelectionScreen(),
),
);
context.navigateWithName(AppRoutes.userInfoSelection);
} else {
Utils.openWebView(
url: 'https://x.com/HMG',

@ -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}"
: '--',

@ -117,8 +117,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);
});
@ -199,18 +199,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,
@ -220,7 +220,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 +231,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 +245,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 +262,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),
],
@ -345,7 +345,8 @@ class FamilyCardWidget extends StatelessWidget {
),
],
).expanded,
Icon(Icons.qr_code, size: 56.h)
// Icon(Icons.qr_code, size: 56.h)
Image.network("https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${profile.responseId.toString()}", fit: BoxFit.contain, height: 56.h, width: 56.w)
],
),
SizedBox(height: 4.h),
@ -420,7 +421,7 @@ class FamilyCardWidget extends StatelessWidget {
),
],
).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 12.h),
1.divider,
1.divider.paddingSymmetrical(16.w, 0.h),
_buildActionButton(appState),
],
),
@ -444,7 +445,7 @@ class FamilyCardWidget extends StatelessWidget {
return CustomButton(
icon: canSwitch ? AppAssets.switch_user : AppAssets.add_family,
text: canSwitch ? LocaleKeys.switchFamilyFile.tr() : LocaleKeys.addANewFamilyMember.tr(),
text: canSwitch ? LocaleKeys.switchAccount.tr() : LocaleKeys.addANewFamilyMember.tr(),
onPressed: canSwitch ? () => onFamilySwitchPress(profile) : onAddFamilyMemberPress,
backgroundColor: canSwitch ? AppColors.secondaryLightRedColor : AppColors.primaryRedColor,
borderColor: canSwitch ? AppColors.secondaryLightRedColor : AppColors.primaryRedColor,
@ -460,7 +461,7 @@ class FamilyCardWidget extends StatelessWidget {
return CustomButton(
icon: AppAssets.switch_user,
text: canSwitchBack ? LocaleKeys.switchBackFamilyFile.tr() : LocaleKeys.switchLogin.tr(),
text: canSwitchBack ? LocaleKeys.switchBackFamilyFile.tr() : LocaleKeys.switchAccount.tr(),
backgroundColor: canSwitchBack ? AppColors.primaryRedColor : Colors.grey.shade200,
borderColor: canSwitchBack ? AppColors.primaryRedColor : Colors.grey.shade200,
textColor: canSwitchBack ? AppColors.whiteColor : AppColors.greyTextColor,

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

@ -3,13 +3,14 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/conditions_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/condition_card.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -45,7 +46,7 @@ class PossibleConditionsPage extends StatelessWidget {
);
}
Widget _buildPredictionsList(BuildContext context, List<ConditionsModel> conditions) {
Widget _buildPredictionsList(BuildContext context, List<TriageCondition> conditions, List<String> symptoms) {
if (conditions.isEmpty) {
return Center(
child: Padding(
@ -74,19 +75,13 @@ class PossibleConditionsPage extends StatelessWidget {
physics: NeverScrollableScrollPhysics(),
separatorBuilder: (context, index) => SizedBox(height: 16.h),
itemBuilder: (context, index) {
final conditionModel = conditions[index];
final condition = conditions[index];
return ConditionCard(
icon: conditionModel.icon,
title: conditionModel.title,
percentage: conditionModel.percentage,
tagText: conditionModel.tagText,
clinic: conditionModel.clinic,
symptoms: conditionModel.symptoms,
description: conditionModel.description,
possibleConditionsSeverityEnum: conditionModel.possibleConditionsSeverityEnum,
condition: condition,
symptoms: symptoms,
onActionPressed: () {
dialogService.showErrorBottomSheet(
message: 'We are not available for a week. May you Rest In Peace :(',
message: 'icd10 Code is ${condition.conditionDetails?.icd10Code}. We need to get the clinics mapped against this code.',
);
},
);
@ -102,7 +97,7 @@ class PossibleConditionsPage extends StatelessWidget {
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.areYouSureYouWantToRestartOrganSelection.tr(context: context),
loadingText: LocaleKeys.areYouSureYouWantToExitProgress.tr(context: context),
isShowActionButtons: true,
onCancelTap: () => Navigator.pop(context),
onConfirmTap: () => onConfirm(),
@ -113,47 +108,88 @@ class PossibleConditionsPage extends StatelessWidget {
);
}
_restartOrganSelection(BuildContext context) async {
final symptomsCheckerVm = context.read<SymptomsCheckerViewModel>();
symptomsCheckerVm.reset();
context.pop();
await Future.delayed(Duration(seconds: 1)).whenComplete(() => context.pop());
}
Widget _buildInfoTile({required PossibleConditionsSeverityEnum severityEnum, required BuildContext context}) {
String title;
String description;
Color dotColor;
_navigateToLandingPage() {
NavigationService navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
}
switch (severityEnum) {
case PossibleConditionsSeverityEnum.monitorOnly:
title = LocaleKeys.monitor.tr(context: context);
description = LocaleKeys.monitorDescription.tr(context: context);
dotColor = AppColors.chipColorMonitor;
break;
case PossibleConditionsSeverityEnum.seekMedicalAdvice:
title = LocaleKeys.seekMedicalAdvice.tr(context: context);
description = LocaleKeys.seekMedicalAdviceDescription.tr(context: context);
dotColor = AppColors.chipColorSeekMedicalAdvice;
break;
case PossibleConditionsSeverityEnum.emergency:
title = LocaleKeys.emergency.tr(context: context);
description = LocaleKeys.emergencyDescription.tr(context: context);
dotColor = AppColors.chipColorEmergency;
break;
}
_buildTrailingSection(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 40.h,
padding: EdgeInsets.all(8.w),
child: Center(
child: Utils.buildSvgWithAssets(
icon: AppAssets.refreshIcon,
height: 20.h,
width: 20.w,
iconColor: AppColors.textColor,
),
height: 14.h,
width: 14.w,
decoration: BoxDecoration(shape: BoxShape.circle, color: dotColor),
).paddingOnly(top: 3.h),
SizedBox(width: 8.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText14(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 4.h),
description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
],
),
).onPress(() => _buildConfirmationBottomSheet(context: context, onConfirm: () => _restartOrganSelection(context))),
Container(
height: 40.h,
padding: EdgeInsets.all(8.w),
child: Center(
child: Utils.buildSvgWithAssets(
icon: AppAssets.homeBorderedIcon,
height: 20.h,
width: 20.w,
iconColor: AppColors.textColor,
),
),
).onPress(() => _buildConfirmationBottomSheet(context: context, onConfirm: () => _navigateToLandingPage())),
),
],
).paddingSymmetrical(20.w, 0);
);
}
_buildSeverityDetailsBottomsheet({required BuildContext context}) {
return showCommonBottomSheetWithoutHeight(
title: LocaleKeys.colorScience.tr(context: context),
context,
child: Container(
padding: EdgeInsets.all(16.w),
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
children: [
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.monitorOnly, context: context),
Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, context: context),
Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.emergency, context: context),
],
),
),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
_buildTrailingSection(BuildContext context) {
return Container(
height: 40.h,
padding: EdgeInsets.all(8.w),
child: Center(
child: Utils.buildSvgWithAssets(
icon: AppAssets.coloredDotsIcon,
height: 20.h,
width: 20.w,
),
),
).onPress(() => _buildSeverityDetailsBottomsheet(context: context));
}
@override
@ -162,13 +198,32 @@ class PossibleConditionsPage extends StatelessWidget {
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.possibleConditions.tr(context: context),
leadingCallback: () => _buildConfirmationBottomSheet(
context: context,
onConfirm: () {
context.pop();
final SymptomsCheckerViewModel symptomsCheckerViewModel = context.read<SymptomsCheckerViewModel>();
symptomsCheckerViewModel.reset(); // Clear all symptoms checker data
final navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
},
),
trailing: _buildTrailingSection(context),
child: Consumer<SymptomsCheckerViewModel>(
builder: (context, symptomsCheckerViewModel, child) {
if (symptomsCheckerViewModel.isPossibleConditionsLoading || symptomsCheckerViewModel.isPossibleConditionsLoading) {
if (symptomsCheckerViewModel.isPossibleConditionsLoading || symptomsCheckerViewModel.isTriageDiagnosisLoading) {
return _buildLoadingShimmer();
}
return _buildPredictionsList(context, dummyConditions);
// Get conditions directly from ViewModel
final conditions = symptomsCheckerViewModel.currentConditions ?? [];
// Get selected symptoms names for display
final symptoms = symptomsCheckerViewModel
.getAllSelectedSymptoms()
.map((s) => s.commonName ?? s.name ?? '')
.where((name) => name.isNotEmpty)
.take(3)
.toList();
return _buildPredictionsList(context, conditions, symptoms);
},
),
),

@ -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(
@ -196,7 +201,7 @@ class _RiskFactorsScreenState extends State<RiskFactorsScreen> {
border: Border.all(color: AppColors.bottomNAVBorder, width: 1),
),
child: Text(
'Not Applicable Risk Factor',
'Not Applicable Risk Factor'.needTranslation,
style: TextStyle(fontSize: 14.f, color: AppColors.textColor),
),
).toShimmer2(isShow: true, radius: 24.r);

@ -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,15 +1,16 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -26,11 +27,13 @@ class SymptomsSelectorPage extends StatefulWidget {
class _SymptomsSelectorPageState extends State<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>();
@ -82,10 +85,12 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
title: LocaleKeys.symptomsSelector.tr(),
leadingCallback: () => _buildConfirmationBottomSheet(
context: context,
onConfirm: () => {
context.pop(),
context.pop(),
}),
onConfirm: () {
context.pop();
viewModel.reset(); // Clear all symptoms checker data
final navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
}),
child: viewModel.isBodySymptomsLoading
? _buildLoadingShimmer()
: viewModel.organSymptomsResults.isEmpty
@ -98,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;
}
}
@ -139,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),
@ -152,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),
),
),
@ -164,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),
@ -304,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';
@ -14,6 +15,7 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_v
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -31,12 +33,14 @@ class TriagePage extends StatefulWidget {
class _TriagePageState extends State<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((_) {
@ -119,12 +123,14 @@ class _TriagePageState extends State<TriagePage> {
SizedBox(height: 8.h),
LocaleKeys.emergencyTriage.tr(context: context).toText28(color: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.emergencyEvidenceDetected.tr(context: context)
.toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
LocaleKeys.emergencyEvidenceDetected.tr(context: context).toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async => Navigator.of(context).pop(),
onPressed: () {
context.pop();
context.navigateWithName(AppRoutes.possibleConditionsPage);
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor,
textColor: AppColors.primaryRedColor,
@ -197,7 +203,7 @@ class _TriagePageState extends State<TriagePage> {
// Call API with updated evidence
viewModel.getDiagnosisForTriage(
age: viewModel.selectedAge!,
sex: viewModel.selectedGender!.toLowerCase(),
gender: viewModel.selectedGender!.toLowerCase() == "male" ? 1 : 2,
evidenceIds: initialEvidenceIds,
triageEvidence: triageEvidence,
language: viewModel.appState.isArabic() ? 'ar' : 'en',
@ -307,8 +313,10 @@ class _TriagePageState extends State<TriagePage> {
isShowActionButtons: true,
onCancelTap: () => Navigator.pop(context),
onConfirmTap: () {
Navigator.pop(context);
context.pop();
viewModel.reset(); // Clear all symptoms checker data
final navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
},
),
callBackFunc: () {},
@ -431,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) {
@ -440,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;

@ -16,14 +16,14 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart';
class UserInfoSelectionScreen extends StatefulWidget {
const UserInfoSelectionScreen({super.key});
class UserInfoSelectionPage extends StatefulWidget {
const UserInfoSelectionPage({super.key});
@override
State<UserInfoSelectionScreen> createState() => _UserInfoSelectionScreenState();
State<UserInfoSelectionPage> createState() => _UserInfoSelectionPageState();
}
class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
@override
void initState() {
super.initState();
@ -43,13 +43,10 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
if (user == null) return;
// Populate gender (gender is int: 1=Male, 2=Female)
// Use internal keys (male/female) for storage
if (user.gender != null) {
String genderStr = user.gender == 1
? "Male"
: user.gender == 2
? "Female"
: "Other";
viewModel.setGender(genderStr);
String genderKey = user.gender == 1 ? "male" : user.gender == 2 ? "female" : "other";
viewModel.setGender(genderKey);
}
if (user.dateofBirth != null && user.dateofBirth!.isNotEmpty) {
@ -84,12 +81,13 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
child: Row(
children: [
Container(
height: 40.h,
width: 40.h,
margin: EdgeInsets.only(right: 10.h),
padding: EdgeInsets.all(8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 12.r, color: AppColors.greyColor),
child: Utils.buildSvgWithAssets(icon: leadingIcon, iconColor: iconColor)),
height: 40.h,
width: 40.h,
margin: EdgeInsetsDirectional.only(end: 10.h),
padding: EdgeInsets.all(8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 12.r, color: AppColors.greyColor),
child: Utils.buildSvgWithAssets(icon: leadingIcon, iconColor: iconColor),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -112,6 +110,20 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
).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,14 +163,16 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
viewModel.selectedWeight == null;
// Get display values
String genderText = viewModel.selectedGender ?? LocaleKeys.notSet.tr(context: context);
String genderText = _getLocalizedGender(viewModel.selectedGender, context);
// Show age calculated from DOB (prefer viewModel's age, fallback to calculated from user's DOB)
int? displayAge = viewModel.selectedAge ?? userAgeFromDOB;
String ageText = displayAge != null ? "$displayAge ${LocaleKeys.years.tr(context: context)}" : LocaleKeys.notSet.tr(context: context);
String heightText =
viewModel.selectedHeight != null ? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}" : LocaleKeys.notSet.tr(context: context);
String weightText =
viewModel.selectedWeight != null ? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}" : LocaleKeys.notSet.tr(context: context);
String heightText = viewModel.selectedHeight != null
? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}"
: LocaleKeys.notSet.tr(context: context);
String weightText = viewModel.selectedWeight != null
? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}"
: LocaleKeys.notSet.tr(context: context);
return Column(
children: [
@ -176,9 +190,9 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
child: Column(
children: [
LocaleKeys.helloIsYourInformationUpToDate.tr(namedArgs: {'name': name}).toText16(
weight: FontWeight.w600,
color: AppColors.textColor,
),
weight: FontWeight.w600,
color: AppColors.textColor,
),
SizedBox(height: 32.h),
_buildEditInfoTile(
context: context,

@ -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,9 +2,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -12,33 +15,131 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class ConditionCard extends StatelessWidget {
final IconData icon;
final String title;
final int percentage;
final String tagText;
final String clinic;
final TriageCondition condition;
final List<String> symptoms;
final String description;
final String? monitorNote;
final String? appointmentLabel;
final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum;
final VoidCallback? onActionPressed;
const ConditionCard({
super.key,
required this.icon,
required this.title,
required this.percentage,
required this.tagText,
required this.clinic,
required this.condition,
required this.symptoms,
required this.description,
this.monitorNote,
this.appointmentLabel,
required this.possibleConditionsSeverityEnum,
this.onActionPressed,
});
/// Get title from condition (localized)
String get title {
final appState = getIt<AppState>();
return condition.getDisplayName(isArabic: appState.isArabic());
}
/// Get percentage from probability (0-1 to 0-100)
int get percentage => ((condition.probability ?? 0) * 100).toInt();
/// Get clinic name from category
String get clinic => condition.conditionDetails?.category?.name ?? '';
/// Get description from hint
String get description => condition.conditionDetails?.hint ?? '';
/// Get severity enum based on triage level
PossibleConditionsSeverityEnum get severityEnum {
final triageLevel = condition.conditionDetails?.triageLevel;
if (triageLevel != null) {
switch (triageLevel) {
case TriageLevelEnum.emergencyAmbulance:
case TriageLevelEnum.emergency:
return PossibleConditionsSeverityEnum.emergency;
case TriageLevelEnum.consultation24:
case TriageLevelEnum.consultation:
return PossibleConditionsSeverityEnum.seekMedicalAdvice;
case TriageLevelEnum.selfCare:
return PossibleConditionsSeverityEnum.monitorOnly;
}
}
// Default based on probability
if (percentage >= 70) {
return PossibleConditionsSeverityEnum.seekMedicalAdvice;
} else {
return PossibleConditionsSeverityEnum.monitorOnly;
}
}
/// Get tag text based on triage level
String getTagText(BuildContext context) {
final triageLevel = condition.conditionDetails?.triageLevel;
if (triageLevel != null) {
switch (triageLevel) {
case TriageLevelEnum.emergencyAmbulance:
case TriageLevelEnum.emergency:
return LocaleKeys.emergency.tr(context: context);
case TriageLevelEnum.consultation24:
case TriageLevelEnum.consultation:
return LocaleKeys.seekMedicalAdvice.tr(context: context);
case TriageLevelEnum.selfCare:
return LocaleKeys.monitor.tr(context: context);
}
}
// Default based on probability
if (percentage >= 70) {
return LocaleKeys.seekMedicalAdvice.tr(context: context);
} else {
return LocaleKeys.monitor.tr(context: context);
}
}
/// Get monitor note if applicable
String? getMonitorNote(BuildContext context) {
if (severityEnum == PossibleConditionsSeverityEnum.monitorOnly) {
return LocaleKeys.noNeedToVisitDoctor.tr(context: context);
}
return null;
}
/// Get icon based on category name from API
IconData get icon {
final categoryName = condition.conditionDetails?.category?.name?.toLowerCase() ?? '';
if (categoryName.contains('cardio') || categoryName.contains('heart')) {
return Icons.favorite;
} else if (categoryName.contains('neuro') || categoryName.contains('brain')) {
return Icons.psychology_alt;
} else if (categoryName.contains('psychiatr') || categoryName.contains('mental')) {
return Icons.psychology;
} else if (categoryName.contains('eye') || categoryName.contains('ophthalmo')) {
return Icons.remove_red_eye;
} else if (categoryName.contains('ent') || categoryName.contains('ear')) {
return Icons.hearing;
} else if (categoryName.contains('derma') || categoryName.contains('skin')) {
return Icons.face;
} else if (categoryName.contains('ortho') || categoryName.contains('bone')) {
return Icons.accessibility_new;
} else if (categoryName.contains('gyneco') || categoryName.contains('obstet')) {
return Icons.pregnant_woman;
} else if (categoryName.contains('pediatr') || categoryName.contains('child')) {
return Icons.child_care;
} else if (categoryName.contains('surg')) {
return Icons.local_hospital;
} else if (categoryName.contains('pulmo') || categoryName.contains('lung') || categoryName.contains('respiratory')) {
return Icons.air;
} else if (categoryName.contains('gastro') || categoryName.contains('digest')) {
return Icons.restaurant;
} else if (categoryName.contains('nephro') || categoryName.contains('kidney')) {
return Icons.water_drop;
} else if (categoryName.contains('hemato') || categoryName.contains('blood')) {
return Icons.bloodtype;
} else if (categoryName.contains('infect') || categoryName.contains('virus')) {
return Icons.coronavirus;
} else if (categoryName.contains('emergency')) {
return Icons.emergency;
} else if (categoryName.contains('geriatr') || categoryName.contains('elder')) {
return Icons.elderly;
} else if (categoryName.contains('internal')) {
return Icons.medical_services;
}
return Icons.medical_services;
}
Color getChipColorBySeverityEnum(PossibleConditionsSeverityEnum possibleConditionsSeverityEnum) {
switch (possibleConditionsSeverityEnum) {
case PossibleConditionsSeverityEnum.seekMedicalAdvice:
@ -67,7 +168,7 @@ class ConditionCard extends StatelessWidget {
crossAxisAlignment: WrapCrossAlignment.center,
children: [
for (int i = 0; i < symptoms.length; i++) ...[
Text(symptoms[i], style: TextStyle(color: AppColors.greyTextColor, fontWeight: FontWeight.w500, fontSize: 12.f)),
"${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
if (i != symptoms.length - 1)
Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w),
@ -80,9 +181,12 @@ class ConditionCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
// final monitorNote = getMonitorNote(context);
final tagText = getTagText(context);
return Container(
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -90,14 +194,14 @@ class ConditionCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 48.w,
height: 48.w,
width: 32.w,
height: 32.w,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum).withValues(alpha: 0.2),
borderRadius: 12.r,
color: getChipColorBySeverityEnum(severityEnum).withValues(alpha: 0.2),
borderRadius: 8.r,
hasShadow: false,
),
child: Icon(icon, color: getChipTextColorBySeverityEnum(possibleConditionsSeverityEnum), size: 24.f),
child: Icon(icon, color: getChipTextColorBySeverityEnum(severityEnum), size: 16.f),
),
SizedBox(width: 12.w),
Expanded(
@ -108,34 +212,23 @@ class ConditionCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
title,
style: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, color: AppColors.textColor),
overflow: TextOverflow.ellipsis,
),
child: title.toText18(weight: FontWeight.w600, color: AppColors.textColor),
),
AppCustomChipWidget(
labelText: tagText,
backgroundColor: getChipColorBySeverityEnum(possibleConditionsSeverityEnum).withValues(alpha: 0.2),
textColor: getChipTextColorBySeverityEnum(possibleConditionsSeverityEnum),
backgroundColor: getChipColorBySeverityEnum(severityEnum).withValues(alpha: 0.2),
textColor: getChipTextColorBySeverityEnum(severityEnum),
),
],
),
CustomRoundedProgressBar(
percentage: percentage,
height: 6.h,
color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum),
color: getChipColorBySeverityEnum(severityEnum),
backgroundColor: AppColors.scaffoldBgColor,
titleWidget: Row(
children: [
Text(
"$percentage%",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12.f,
color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum),
),
),
"$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum)),
],
).paddingSymmetrical(0, 4.h),
),
@ -148,50 +241,42 @@ class ConditionCard extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
clinic,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.f,
color: AppColors.textColor,
),
),
LocaleKeys.commonSymptom.tr(context: context).toText14(weight: FontWeight.w600, color: AppColors.textColor),
_buildSymptomsRow(),
SizedBox(height: 16.h),
Text(LocaleKeys.description.tr(context: context), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14.f, color: AppColors.textColor)),
LocaleKeys.description.tr(context: context).toText14(weight: FontWeight.bold, color: AppColors.textColor),
SizedBox(height: 2.h),
Text(description, style: TextStyle(color: AppColors.greyTextColor, fontWeight: FontWeight.w500, fontSize: 12.f)),
if (possibleConditionsSeverityEnum == PossibleConditionsSeverityEnum.emergency)
description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
if (severityEnum != PossibleConditionsSeverityEnum.monitorOnly)
CustomButton(
text: appointmentLabel ?? LocaleKeys.bookAppointment.tr(context: context),
text: LocaleKeys.bookAppointment.tr(context: context),
onPressed: () {
if (onActionPressed != null) {
onActionPressed!();
}
},
backgroundColor: AppColors.lightRedButtonColor,
backgroundColor: AppColors.primaryRedColor,
borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor,
fontSize: 16.f,
textColor: AppColors.whiteColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 48.h,
icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 18.h,
height: 48.h,
iconColor: AppColors.whiteColor,
).paddingOnly(top: 16.w),
if (monitorNote != null)
Container(
margin: EdgeInsets.only(top: 12.h),
child: AppCustomChipWidget(
labelText: monitorNote!,
backgroundColor: AppColors.whiteColor,
textColor: AppColors.textColor,
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
),
),
// if (monitorNote != null)
// Container(
// margin: EdgeInsets.only(top: 12.h),
// child: AppCustomChipWidget(
// labelText: monitorNote,
// backgroundColor: AppColors.whiteColor,
// textColor: AppColors.textColor,
// padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h),
// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
// ),
// ),
],
).paddingAll(16.w),
],

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

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/presentation/child_vaccine/my_child_vaccine_
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart';
import 'package:hmg_patient_app_new/presentation/covid19test/covid19_landing_page.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/emergency_services_page.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculators_page.dart';
import 'package:hmg_patient_app_new/presentation/health_trackers/add_health_tracker_entry_page.dart';
import 'package:hmg_patient_app_new/presentation/health_trackers/health_tracker_detail_page.dart';
@ -31,16 +32,14 @@ import 'package:hmg_patient_app_new/presentation/vital_sign/vital_sign_page.dart
import 'package:hmg_patient_app_new/presentation/water_monitor/water_consumption_page.dart';
import 'package:hmg_patient_app_new/presentation/water_monitor/water_monitor_settings_page.dart';
import 'package:hmg_patient_app_new/splashPage.dart';
import '../features/qr_parking/qr_parking_view_model.dart';
import '../presentation/covid19test/covid19_landing_page.dart';
import 'package:provider/provider.dart';
import '../core/dependencies.dart';
import '../features/monthly_reports/monthly_reports_repo.dart';
import '../features/monthly_reports/monthly_reports_view_model.dart';
import '../features/qr_parking/qr_parking_view_model.dart';
import '../presentation/parking/paking_page.dart';
import '../services/error_handler_service.dart';
import 'package:provider/provider.dart';
class AppRoutes {
static const String initialRoute = '/initialRoute';
@ -86,8 +85,10 @@ class AppRoutes {
static const String addHealthTrackerEntryPage = '/addHealthTrackerEntryPage';
static const String healthTrackerDetailPage = '/healthTrackerDetailPage';
static Map<String, WidgetBuilder> get routes =>
{
// Emergency Services
static const String emergencyServicesPage = '/emergencyServicesPage';
static Map<String, WidgetBuilder> get routes => {
initialRoute: (context) => SplashPage(),
loginScreen: (context) => LoginScreen(),
landingScreen: (context) => LandingNavigation(),
@ -107,7 +108,7 @@ class AppRoutes {
bloodDonationPage: (context) => BloodDonationPage(),
myChildVaccine: (context) => MyChildVaccinePage(),
bookAppointmentPage: (context) => BookAppointmentPage(),
userInfoSelection: (context) => UserInfoSelectionScreen(),
userInfoSelection: (context) => UserInfoSelectionPage(),
userInfoFlowManager: (context) => UserInfoFlowManager(),
smartWatches: (context) => SmartwatchInstructionsPage(),
huaweiHealthExample: (context) => HuaweiHealthExample(),
@ -118,34 +119,28 @@ class AppRoutes {
healthConvertersPage: (context) => HealthCalculatorsPage(type: HealthCalConEnum.converter),
healthTrackersPage: (context) => HealthTrackersPage(),
vitalSign: (context) => VitalSignPage(),
emergencyServicesPage: (context) => EmergencyServicesPage(),
addHealthTrackerEntryPage: (context) {
final args = ModalRoute
.of(context)
?.settings
.arguments as HealthTrackerTypeEnum?;
final args = ModalRoute.of(context)?.settings.arguments as HealthTrackerTypeEnum?;
return AddHealthTrackerEntryPage(
trackerType: args ?? HealthTrackerTypeEnum.bloodSugar,
);
},
healthTrackerDetailPage: (context) {
final args = ModalRoute
.of(context)
?.settings
.arguments as HealthTrackerTypeEnum?;
final args = ModalRoute.of(context)?.settings.arguments as HealthTrackerTypeEnum?;
return HealthTrackerDetailPage(
trackerType: args ?? HealthTrackerTypeEnum.bloodSugar,
);
},
monthlyReports: (context) => ChangeNotifierProvider(
create: (_) => MonthlyReportsViewModel(
monthlyReportsRepo: getIt<MonthlyReportsRepo>(),
errorHandlerService: getIt<ErrorHandlerService>(),
),
),
qrParking: (context) => ChangeNotifierProvider<QrParkingViewModel>(
create: (_) => getIt<QrParkingViewModel>(),
child: const ParkingPage(),
monthlyReports: (context) => ChangeNotifierProvider(
create: (_) => MonthlyReportsViewModel(
monthlyReportsRepo: getIt<MonthlyReportsRepo>(),
errorHandlerService: getIt<ErrorHandlerService>(),
),
),
qrParking: (context) => ChangeNotifierProvider<QrParkingViewModel>(
create: (_) => getIt<QrParkingViewModel>(),
child: const ParkingPage(),
)
};
}

@ -230,7 +230,7 @@ Widget exceptionBottomSheetWidget(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.cancel.tr(),
text: LocaleKeys.cancel.tr(context: context),
onPressed: () {
Navigator.of(context).pop();
},
@ -244,7 +244,7 @@ Widget exceptionBottomSheetWidget(
SizedBox(width: 10.h),
Expanded(
child: CustomButton(
text: LocaleKeys.confirm.tr(),
text: LocaleKeys.confirm.tr(context: context),
onPressed: onOkPressed,
backgroundColor: AppColors.bgGreenColor,
borderColor: AppColors.bgGreenColor,
@ -258,7 +258,7 @@ Widget exceptionBottomSheetWidget(
Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: CustomButton(
text: LocaleKeys.cancel.tr(),
text: LocaleKeys.cancel.tr(context: context),
onPressed: (onCancelPressed == null)
? () {
context.pop();
@ -286,7 +286,7 @@ Widget showPhoneNumberPickerWidget(
Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: CustomButton(
text: LocaleKeys.sendOTPSMS.tr(),
text: LocaleKeys.sendOTPSMS.tr(context: context),
onPressed: onSMSPress,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedBorderColor,
@ -300,14 +300,14 @@ Widget showPhoneNumberPickerWidget(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.h),
child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor),
child: LocaleKeys.oR.tr(context: context).toText16(color: AppColors.textColor),
),
],
),
Padding(
padding: EdgeInsets.only(bottom: 10.h, top: 10.h),
child: CustomButton(
text: LocaleKeys.sendOTPWHATSAPP.tr(),
text: LocaleKeys.sendOTPWHATSAPP.tr(context: context),
onPressed: onWhatsappPress,
backgroundColor: Colors.white,
borderColor: AppColors.borderOnlyColor,

@ -92,7 +92,7 @@ class AppColors {
// SymptomsChecker
static const Color chipColorSeekMedicalAdvice = Color(0xFFFFAF15); // #FFAF15
static const Color chipTextColorSeekMedicalAdvice = Color(0xFFAB7103); // #AB7103
static const Color chipTextColorSeekMedicalAdvice = Color(0xFFD48D05); // #AB7103
static const Color chipColorMonitor = Color(0xFF18C273); // #18C273
static const Color chipColorEmergency = Color(0xFFED1C2B); // #ED1C2B

@ -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,26 +74,25 @@ class CustomButton extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null)
Padding(
padding: text.isNotEmpty ? EdgeInsets.only(right: 8.w, left: 8.w) : EdgeInsets.zero,
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconS, height: iconS),
Flexible(
child: Padding(
padding: text.isNotEmpty ? EdgeInsets.only(right: 4.w, left: 4.w) : EdgeInsets.zero,
child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconS, height: iconS),
),
),
Visibility(
visible: text.isNotEmpty,
child: Padding(
padding: EdgeInsets.only(top: 0),
child: Text(
text,
overflow: textOverflow,
style: context.dynamicTextStyle(
fontSize: fontS,
color: isDisabled ? AppColors.greyTextColor : textColor,
letterSpacing: 0,
fontWeight: fontWeight,
),
if (text.isNotEmpty)
Text(
text,
overflow: textOverflow ?? TextOverflow.ellipsis,
maxLines: 1,
textAlign: TextAlign.center,
style: context.dynamicTextStyle(
fontSize: fontS,
color: isDisabled ? AppColors.greyTextColor : textColor,
letterSpacing: 0,
fontWeight: fontWeight,
),
),
),
],
),
));

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