diff --git a/AuthKey_JG87SJ23A4.p8 b/AuthKey_JG87SJ23A4.p8
new file mode 100644
index 00000000..6a3c2a53
--- /dev/null
+++ b/AuthKey_JG87SJ23A4.p8
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgaPetsOq3tqUlswBN
+BFUWIIdEg4dcTCGRUKbAEx8ViFygCgYIKoZIzj0DAQehRANCAAS6IKkZ4tCeBlN6
+DtXiBekCiIbgHxWk8AWppP0H3mJ+I2s8cIEaquL4/yeLDcHzAHf8tHcYhF/TvggT
+nc30yDLv
+-----END PRIVATE KEY-----
\ No newline at end of file
diff --git a/android/app/libs/PenNavUI.aar b/android/app/libs/PenNavUI.aar
index 7832df8c..a5658605 100644
Binary files a/android/app/libs/PenNavUI.aar and b/android/app/libs/PenNavUI.aar differ
diff --git a/android/app/libs/PenguinRenderer.aar b/android/app/libs/PenguinRenderer.aar
index 2926e9ad..b498726f 100644
Binary files a/android/app/libs/PenguinRenderer.aar and b/android/app/libs/PenguinRenderer.aar differ
diff --git a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt b/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt
index 6c7306d8..3925ca56 100644
--- a/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt
+++ b/android/app/src/main/kotlin/com/ejada/hmg/penguin/PenguinView.kt
@@ -320,6 +320,7 @@ internal class PenguinView(
if(clinicId.isEmpty()) return
navigateTo(clinicId)
+// navigateTo("3-1")
}
/**
diff --git a/assets/images/svg/ai_overview.svg b/assets/images/svg/ai_overview.svg
new file mode 100644
index 00000000..95c29aac
--- /dev/null
+++ b/assets/images/svg/ai_overview.svg
@@ -0,0 +1,19 @@
+
diff --git a/assets/images/svg/calculator_icon.svg b/assets/images/svg/calculator_icon.svg
new file mode 100644
index 00000000..989a4db8
--- /dev/null
+++ b/assets/images/svg/calculator_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/guard_icon.svg b/assets/images/svg/guard_icon.svg
new file mode 100644
index 00000000..e3a68d9d
--- /dev/null
+++ b/assets/images/svg/guard_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/high_caution.svg b/assets/images/svg/high_caution.svg
new file mode 100644
index 00000000..d268468f
--- /dev/null
+++ b/assets/images/svg/high_caution.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/information-circle.svg b/assets/images/svg/information-circle.svg
new file mode 100644
index 00000000..f1a850e4
--- /dev/null
+++ b/assets/images/svg/information-circle.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index dd576900..5742fc6c 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -1522,8 +1522,56 @@
"trackerAndOthers": "المتتبع وأخرى",
"bmi": "مؤشر كتلة الجسم",
"yesPleaseINeedHelp": "نعم، من فضلك أريد المساعدة",
- "noThanksIKnowTheClinic": "لا شكراً، أعرف العيادة",
- "unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة",
+ "aiOverView": "AI ملخص",
+ "generateAiAnalysis": "قم بإجراء تحليل لهذا الطلب AI",
+ "aiAnalysis": "AI تحليل",
+ "prediction": "تنبؤ",
+ "prevention": "وقاية",
+ "disclaimer": "تنصل",
+ "thisAboveInfo": "المعلومات المذكورة أعلاه تم إنشاؤها بواسطة AI",
+ "aiDisclaimer": "سيتم مشاركة بيانات نتائج تحاليلك المخبرية بشكل آمن مع خدمة الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في تقديم رؤى صحية مُخصصة. هل ترغب في المتابعة؟",
+ "consent": "موافقة",
+ "bmiNormalDescription": "مؤشر كتلة جسمك ضمن المعدل الصحي. استمر في اتباع نظام غذائي متوازن، وممارسة النشاط البدني بانتظام، وإجراء الفحوصات الدورية للحفاظ على صحة جيدة. راقب أي تغييرات ملحوظة مع مرور الوقت.",
+ "bmiUnderweightDescription": "يشير مؤشر كتلة الجسم إلى أنك تعاني من نقص الوزن. لذا، يُنصح بزيادة السعرات الحرارية المتناولة من خلال تناول الأطعمة الغنية بالعناصر الغذائية، وممارسة تمارين المقاومة لبناء العضلات، واستشارة أخصائي رعاية صحية للتحقق من وجود أسباب كامنة.",
+ "bmiOverweightDescription": "يشير مؤشر كتلة الجسم إلى زيادة الوزن. لذا، يُنصح بالسعي إلى إنقاص الوزن تدريجياً وبشكل مستدام من خلال تقليل السعرات الحرارية بشكل معتدل، وممارسة النشاط البدني بانتظام، واختيار الأطعمة الصحية. استشر طبيبك قبل إجراء أي تغييرات جذرية في نمط حياتك.",
+ "caloriesMaintenanceDescription": "السعرات الحرارية اليومية المُقدَّرة للحفاظ على وزنك الحالي بناءً على مستوى نشاطك ومعدل الأيض لديك. استخدم هذه الكمية كخط أساس: زدها قليلاً لزيادة الكتلة العضلية، أو قللها قليلاً لإنقاص الوزن تدريجياً. تابع تقدمك وعدّل الخطة كل أسبوعين إلى أربعة أسابيع.",
+ "caloriesModerateDeficitDescription": "نظام غذائي معتدل لتقليل السعرات الحرارية مصمم لإنقاص الوزن بشكل ثابت ومستدام (عادةً من 0.25 إلى 0.5 كيلوغرام أسبوعيًا). يُنصح بدمجه مع تمارين المقاومة وتناول كمية كافية من البروتين للحفاظ على الكتلة العضلية. تجنب التخفيضات الحادة في السعرات الحرارية واستشر طبيبًا مختصًا إذا كنت تعاني من أي حالة صحية.",
+ "caloriesAggressiveDeficitDescription": "يؤدي خفض السعرات الحرارية بشكل كبير إلى فقدان الوزن بشكل أسرع، ولكنه قد يصعب الاستمرار عليه ويزيد من خطر نقص العناصر الغذائية والإرهاق وفقدان الكتلة العضلية. لا يُنصح باتباعه على المدى الطويل؛ استشر طبيبًا أو أخصائي تغذية قبل الاستمرار.",
+ "bodyFatEssentialDescription": "نسبة الدهون في جسمك ضمن النطاق الأساسي/الرياضي. هذا المستوى شائع لدى الرياضيين ويشير إلى انخفاض نسبة الدهون في الجسم. مع أن هذا قد يكون مثاليًا للأداء، تأكد من الحفاظ على تغذية سليمة ووظائف هرمونية متوازنة. استشر طبيبًا إذا شعرت بالتعب، أو واجهت مشاكل هرمونية، أو أي مخاوف صحية أخرى.",
+ "bodyFatFitnessDescription": "نسبة الدهون في جسمك ضمن النطاق الصحي. وهذا يدل على مستوى صحي من الدهون في الجسم يرتبط بلياقة بدنية جيدة. حافظ على نمط حياتك الحالي، بما في ذلك ممارسة الرياضة بانتظام واتباع نظام غذائي متوازن، للحفاظ على هذا المستوى الصحي.",
+ "bodyFatAverageDescription": "نسبة الدهون في جسمك ضمن المعدل الطبيعي/المقبول، وهي نسبة تُعتبر صحية لعموم الناس. لتحسين تكوين جسمك، يُنصح بممارسة تمارين القوة، وتمارين القلب والأوعية الدموية، واتباع نظام غذائي متوازن. ركّز على التغييرات التدريجية والمستدامة للحفاظ على صحتك على المدى الطويل.",
+ "bodyFatObeseDescription": "نسبة الدهون في جسمك أعلى من المعدل الصحي الموصى به. قد يزيد هذا من المخاطر الصحية، بما في ذلك أمراض القلب والأوعية الدموية، والسكري، ومشاكل المفاصل. يُنصح باستشارة طبيب أو أخصائي تغذية معتمد لوضع خطة علاجية شخصية تشمل التغذية المتوازنة، والنشاط البدني المنتظم، وتعديلات نمط الحياة لتحقيق إدارة مستدامة للوزن.",
+ "bmrNormalDescription": "معدل الأيض الأساسي لديك ضمن النطاق المتوقع لحالتك. معدل الأيض الأساسي هو الطاقة التي يحتاجها جسمك في حالة الراحة للحفاظ على وظائفه الحيوية (التنفس، الدورة الدموية، درجة الحرارة). استخدم هذه القيمة كأساس لتقدير إجمالي احتياجاتك اليومية من الطاقة من خلال تطبيق مُعامل النشاط. حافظ على نظام غذائي متوازن وممارسة النشاط البدني بانتظام لدعم صحة التمثيل الغذائي.",
+ "bmrLowDescription": "معدل الأيض الأساسي لديك أقل من المعدل الطبيعي لحالتك. تشمل الأسباب المحتملة انخفاض كتلة العضلات، أو تراجع التمثيل الغذائي المرتبط بالتقدم في السن، أو التكيف الأيضي الناتج عن تقييد السعرات الحرارية لفترة طويلة. يُنصح بالتركيز على تمارين المقاومة لبناء العضلات والحفاظ عليها، والتأكد من تناول كميات كافية من البروتين والمغذيات الدقيقة، واستشارة أخصائي رعاية صحية إذا كان هذا الأمر غير متوقع.",
+ "bmrHighDescription": "معدل الأيض الأساسي لديك أعلى من المتوسط \u200B\u200Bبالنسبة لحالتك. قد يعكس هذا زيادة في كتلة العضلات، أو صغر السن، أو ارتفاع معدل الأيض لديك بشكل طبيعي، مما يعني أنك تحرق طاقة أكبر أثناء الراحة. استخدم هذه المعلومات لتحديد احتياجاتك من السعرات الحرارية: احتياجات أعلى للحفاظ على الوزن أو بناء العضلات، ونقص معتدل في السعرات الحرارية لإنقاص الوزن. استشر طبيبك إذا لاحظت أي تغيرات سريعة غير مبررة.",
+ "ibwAtTargetDescription": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.",
+ "ibwBelowTargetDescription": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.",
+ "ibwAboveTargetDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.",
+ "ibwCloseToRangeDescription": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.",
+ "ibwUnderweightDescription": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.",
+ "ibwUnderweightGenericDescription": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.",
+ "ibwOverweightDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.",
+ "ibwOverweightGenericDescription": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.",
+ "dietVeryLowCarbsDescription": "Very low‑carb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for long‑term use.",
+ "dietLowCarbsDescription": "Low‑carb, higher‑protein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.",
+ "dietModerateCarbsDescription": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.",
+ "dietUSDAGuidelinesDescription": "USDA‑based balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidence‑based framework for general health, nutrient adequacy, and chronic disease prevention.",
+ "dietZoneDietDescription": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.",
+ "contextDependent": "يعتمد السياق",
+ "calculatedValue": "القيمة المحسوبة",
+ "calculationFormula": "صيغة الحساب"
+
+
+
+ "confirmYourLocation": "قم بتأكيد موقعك",
+ "confirmYourLocationDesc": "يرجى تأكيد موقعك الحالي لعرض الاتجاهات المناسبة.",
+ "insideHospital": "أنا داخل المستشفى",
+ "outsideHospital": "أنا خارج المستشفى",
+ "servicePriceList": "قائمة أسعار الخدمات",
+ "servicePriceListDesc": "توضح قائمة أسعار الخدمات أدناه رسوم الخدمات الصحية المقدمة للمرضى بنظام الدفع النقدي. أما فيما يتعلق بالخدمات المشمولة بالتأمين، فسيتم تطبيق التغطية التأمينية والتحقق من الأهلية واحتساب نسب التحمل وفقًا لشروط وثيقة التأمين وجدول المنافع المعتمد لكل شركة تأمين.",
+ "servicePriceListRights": "يحق للمريض الحصول على متابعة مجانية في غضون 14 يومًا من الزيارة الأولى",
+ "serviceName": "اسم الخدمة",
+ "noFreeSlot": "لا توجد مواعيد متاحة في التاريخ المحدد. يرجى اختيار تاريخ آخر أو إعادة المحاولة لاحقاً.",
"applewatch": "ساعة آبل",
"applehealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Apple Health على هاتفك",
"unabletodetectapplicationinstalledpleasecomebackonceinstalled": "لا يمكننا اكتشاف التطبيق المثبت على جهازك. يرجى العودة إلى هنا بمجرد تثبيت هذا التطبيق.",
@@ -1538,5 +1586,4 @@
"whoophealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Whoop Health على هاتفك",
"whoopwatchshouldbeconnected": "يجب توصيل ساعة Whoop",
"updatetheinformation": "سيتيح ذلك جمع أحدث المعلومات من ساعة آبل الخاصة بك"
-
}
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index ef7fcb9f..3ffe74fa 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -1475,7 +1475,6 @@
"remindersSet": "Reminders Set!",
"dailyWaterRemindersScheduledAt": "Daily water reminders scheduled at:",
"waterConsumption": "Water Consumption",
- "selectActivityLevel": "Select Activity Level",
"selectNumberOfReminders": "Select Number of Reminders",
"h2oSettings": "H20 Settings",
"settingsSavedSuccessfully": "Settings saved successfully",
@@ -1515,8 +1514,55 @@
"trackerAndOthers": "Tracker & Others",
"bmi": "BMI",
"yesPleaseINeedHelp": "Yes, Please I need help",
+ "confirmYourLocation": "Confirm Your Location",
+ "confirmYourLocationDesc": "Please confirm your present location to view appropriate directions.",
+ "insideHospital": "I am inside the hospital",
+ "outsideHospital": "I am outside the hospital",
+ "servicePriceList": "Services Price List",
+ "servicePriceListDesc": "Below is the services price list outline the healthcare services fees for cash payments, where the insurance coverage, eligibility, and co-payment deductions will be processed in accordance with the insurance policy terms and the table of benefits of each insurance providers:",
+ "servicePriceListRights": "The patient has the right to a free follow-up within 14 days of initial visit",
+ "serviceName": "Service Name",
+ "noFreeSlot": "No free slot available for the selected date. Please select another date or check back later."
"noThanksIKnowTheClinic": "No, Thanks. I Know the clinic",
"unableToSendOTP": "Unable to send Verification OTP",
+ "aiOverView": "AI Overview",
+ "generateAiAnalysis": "Generate AI analysis for this order",
+ "aiAnalysis": "AI Analysis",
+ "prediction": "Prediction",
+ "prevention": "Prevention",
+ "disclaimer": "Disclaimer",
+ "thisAboveInfo": "The above information is generated by",
+ "aiDisclaimer": "Your lab result data will be securely shared with our AI service for analysis. This helps provide personalized health insights. Do you want to proceed?",
+ "consent": "Consent",
+ "bmiNormalDescription": "Your BMI is within the healthy range. Continue a balanced diet, regular physical activity, and routine checkups to maintain good health. Monitor any significant changes over time.",
+ "bmiUnderweightDescription": "BMI suggests you are underweight. Consider increasing calorie intake with nutrient-dense foods, include resistance training to build muscle, and consult a healthcare professional to check for underlying causes.",
+ "bmiOverweightDescription": "BMI indicates overweight. Aim for gradual, sustainable weight loss through a modest calorie deficit, regular physical activity, and healthier food choices. Seek medical advice before major lifestyle changes.",
+ "caloriesMaintenanceDescription": "Estimated daily calories to maintain your current weight given your activity level and metabolism. Use this as a baseline: increase slightly for muscle gain, or create a small deficit for gradual weight loss. Track progress and adjust every 2–4 weeks.",
+ "caloriesModerateDeficitDescription": "A moderate calorie reduction designed for steady, sustainable weight loss (typically 0.25–0.5 kg per week). Combine with resistance training and adequate protein to preserve muscle. Avoid extreme cuts and consult a professional if you have medical conditions.",
+ "caloriesAggressiveDeficitDescription": "A large calorie reduction that may produce faster weight loss but can be hard to sustain and increase risk of nutrient deficiencies, fatigue, or muscle loss. Not recommended long-term; seek guidance from a healthcare or nutrition professional before continuing.",
+ "bodyFatEssentialDescription": "Your body fat percentage is in the essential/athletic range. This level is typical for athletes and indicates very low body fat. While this may be optimal for performance, ensure you maintain adequate nutrition and hormone function. Consult a healthcare professional if you experience fatigue, hormonal issues, or other health concerns.",
+ "bodyFatFitnessDescription": "Your body fat percentage is in the fitness range. This indicates a healthy level of body fat associated with good physical conditioning. Maintain your current lifestyle habits including regular exercise and balanced nutrition to sustain this healthy range.",
+ "bodyFatAverageDescription": "Your body fat percentage is in the average/acceptable range. This is considered a healthy range for general population. To improve body composition, consider incorporating strength training, cardiovascular exercise, and a balanced diet. Focus on gradual, sustainable changes for long-term health.",
+ "bodyFatObeseDescription": "Your body fat percentage is above the recommended healthy range. This may increase health risks including cardiovascular disease, diabetes, and joint problems. Consider consulting a healthcare provider or registered dietitian to develop a personalized plan that includes balanced nutrition, regular physical activity, and lifestyle modifications for sustainable weight management.",
+ "bmrNormalDescription": "Your Basal Metabolic Rate (BMR) is within the expected range for your profile. BMR is the energy your body needs at rest to maintain vital functions (breathing, circulation, temperature). Use this value as the baseline for estimating total daily energy needs by applying an activity multiplier. Maintain a balanced diet and regular physical activity to support metabolic health.",
+ "bmrLowDescription": "Your BMR is lower than typical for your profile. Possible causes include lower lean muscle mass, age-related metabolic decline, or metabolic adaptation from prolonged calorie restriction. Consider focusing on resistance training to build/maintain muscle, ensure adequate protein and micronutrient intake, and consult a healthcare professional if this is unexpected.",
+ "bmrHighDescription": "Your BMR is higher than average for your profile. This can reflect greater lean mass, younger age, or a naturally higher metabolic rate, meaning you burn more energy at rest. Use this information to tailor calorie targets: higher needs for maintenance or muscle gain, moderate deficit for weight loss. Seek medical advice if you notice rapid unexplained changes.",
+ "ibwAtTargetDescription": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.",
+ "ibwBelowTargetDescription": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.",
+ "ibwAboveTargetDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.",
+ "ibwCloseToRangeDescription": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.",
+ "ibwUnderweightDescription": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.",
+ "ibwUnderweightGenericDescription": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.",
+ "ibwOverweightDescription": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.",
+ "ibwOverweightGenericDescription": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.",
+ "dietVeryLowCarbsDescription": "Very low‑carb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for long‑term use.",
+ "dietLowCarbsDescription": "Low‑carb, higher‑protein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.",
+ "dietModerateCarbsDescription": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.",
+ "dietUSDAGuidelinesDescription": "USDA‑based balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidence‑based framework for general health, nutrient adequacy, and chronic disease prevention.",
+ "dietZoneDietDescription": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.",
+ "contextDependent": "Context Dependent",
+ "calculatedValue": "Calculated Value",
+ "calculationFormula": "Calculation Formula",
"applewatch": "Apple Watch",
"applehealthapplicationshouldbeinstalledinyourphone": "Apple Health application should be installed in your phone",
"unabletodetectapplicationinstalledpleasecomebackonceinstalled": "We are unable to detect the application installed in your device. Please come back here once you have installed this application.",
diff --git a/icon.jpg b/icon.jpg
new file mode 100644
index 00000000..65ca5c05
Binary files /dev/null and b/icon.jpg differ
diff --git a/ios/GoogleService-Info.plist b/ios/GoogleService-Info.plist
index 633037cb..a9b1f53a 100644
--- a/ios/GoogleService-Info.plist
+++ b/ios/GoogleService-Info.plist
@@ -2,10 +2,6 @@
- CLIENT_ID
- 815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com
- REVERSED_CLIENT_ID
- com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt
ANDROID_CLIENT_ID
815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com
API_KEY
@@ -15,11 +11,11 @@
PLIST_VERSION
1
BUNDLE_ID
- com.HMG.HMG-Smartphone
+ com.cloudsolutions.HMGPatientApp
PROJECT_ID
api-project-815750722565
STORAGE_BUCKET
- api-project-815750722565.appspot.com
+ api-project-815750722565.firebasestorage.app
IS_ADS_ENABLED
IS_ANALYTICS_ENABLED
@@ -31,7 +27,7 @@
IS_SIGNIN_ENABLED
GOOGLE_APP_ID
- 1:815750722565:ios:328ec247a81a2ca23c186c
+ 1:815750722565:ios:34ec03c09e02e21f3c186c
DATABASE_URL
https://api-project-815750722565.firebaseio.com
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
index 08f3422c..1eb27a20 100644
--- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -109,7 +109,7 @@
"size" : "83.5x83.5"
},
{
- "filename" : "icon 1.jpg",
+ "filename" : "icon.jpg",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index ab9828e6..9c805ac5 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- Dr. Alhabib
+ Dr. Alhabib Beta
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/ios/Runner/Penguin/PenguinView.swift b/ios/Runner/Penguin/PenguinView.swift
index 508fb74a..e683a35a 100644
--- a/ios/Runner/Penguin/PenguinView.swift
+++ b/ios/Runner/Penguin/PenguinView.swift
@@ -309,22 +309,13 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
PenNavUIManager.shared.eventsDelegate = self
-
-
- print("====== after eventsDelegate onPenNavSuccess =========")
-
- PenNavUIManager.shared.navigate(to: "108")
-
-
+// print("====== after onPenNavSuccess navigate =========")
+// PenNavUIManager.shared.navigate(to: "3-1")
// Present the Penguin UI on top of the Flutter view controller
-
+ print("====== after onPenNavSuccess present =========")
PenNavUIManager.shared.present(root: controller, view: _view)
-
-
-
-
print("====== after present onPenNavSuccess =========")
print(model?.clinicID)
@@ -347,11 +338,21 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
let clientID = self.model?.clientID, !clientID.isEmpty else {
- print("Error: Config Client ID is nil or empty")
+ print("Error: Config Clinic ID is nil or empty")
return
}
+
+ print("====== after onPenNavSuccess navigate =========")
+// PenNavUIManager.shared.navigate(to: "3-1") { success, error in
+ PenNavUIManager.shared.navigate(to: clinicID) { success, error in
+ if success {
+ print("Nav Success")
+ } else {
+ print("Nav Error")
+ }
+ }
@@ -373,20 +374,20 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
- guard let token = token else {
-
- print("Token is nil")
-
- return
-
- }
-
- print("Token Generated")
-
- print(token);
+// guard let token = token else {
+//
+// print("Token is nil")
+//
+// return
+//
+// }
+//
+// print("Token Generated")
+//
+// print(token);
-
+//
// self?.handleNavigation(clinicID: clinicID, token: token) { success, errorMessage in
//
// if success {
@@ -425,7 +426,8 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
PenNavUIManager.shared.setToken(token: token)
- PenNavUIManager.shared.navigate(to: clinicID)
+// PenNavUIManager.shared.navigate(to: clinicID)
+ PenNavUIManager.shared.navigate(to: "3-1")
completion(true,nil)
diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart
index 4286618b..ea8062d0 100644
--- a/lib/core/api/api_client.dart
+++ b/lib/core/api/api_client.dart
@@ -188,7 +188,9 @@ class ApiClientImp implements ApiClient {
// body['SessionID'] = "45786230487560q";
}
- // body['IsNewFlutterApp'] = true;
+ if(!url.contains("/paymentApi")) {
+ body['IsNewFlutterApp'] = true;
+ }
body.removeWhere((key, value) => value == null);
}
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index 87ca2f8c..c08cdda9 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -380,6 +380,8 @@ var GET_PATIENT_SICK_LEAVE = 'Services/Patients.svc/REST/GetPatientSickLeave';
var GET_PATIENT_SICK_LEAVE_STATUS = 'Services/Patients.svc/REST/GetPatientSickLeave_Status';
+var GET_SERVICES_PRICE_LIST = 'Services/OUTPs.svc/REST/GetServicesPriceList';
+
var SendSickLeaveEmail = 'Services/Notifications.svc/REST/SendSickLeaveEmail';
var GET_PATIENT_AdVANCE_BALANCE_AMOUNT = 'Services/Patients.svc/REST/GetPatientAdvanceBalanceAmount';
@@ -681,7 +683,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts {
static const maxSmallScreen = 660;
- static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
+ static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@@ -902,9 +904,11 @@ class ApiConsts {
static String getPatientBloodGroup = "services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails";
static String getPatientBloodAgreement = "Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation";
+ static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API";
+ static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
// ************ static values for Api ****************
- static final double appVersionID = 50.3;
+ static final double appVersionID = 19.7;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";
static final String appGeneralId = "Cs2020@2016\$2958";
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index 019bd144..c2fd44be 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -266,6 +266,10 @@ class AppAssets {
static const String alertSquare = '$svgBasePath/alert-square.svg';
static const String arrowRight = '$svgBasePath/arrow-right.svg';
static const String tickIcon = '$svgBasePath/tick.svg';
+ static const String guradIcon = '$svgBasePath/guard_icon.svg';
+ static const String calculatorIcon = '$svgBasePath/calculator_icon.svg';
+ static const String informationIcon = '$svgBasePath/information-circle.svg';
+ static const String highCautionIcon = '$svgBasePath/high_caution.svg';
// Symptoms Checker
static const String calendarGrey = '$svgBasePath/calendar-grey.svg';
@@ -337,6 +341,7 @@ class AppAssets {
static const String doctorResponseIcon = '$svgBasePath/doctor_response_icon.svg';
static const String changeLanguageHomePageIcon = '$svgBasePath/change_language_home_page.svg';
+ static const String aiOverView = '$svgBasePath/ai_overview.svg';
// PNGS //
static const String hmgLogo = '$pngBasePath/hmg_logo.png';
diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart
index 0560ff9e..e7ac0515 100644
--- a/lib/core/dependencies.dart
+++ b/lib/core/dependencies.dart
@@ -54,6 +54,8 @@ import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_v
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
+import 'package:hmg_patient_app_new/features/services_price_list/services_price_list_repo.dart';
+import 'package:hmg_patient_app_new/features/services_price_list/services_price_list_view_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_repo.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
@@ -169,6 +171,7 @@ class AppDependencies {
getIt.registerLazySingleton(() => QrParkingRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => NotificationsRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => AskDoctorRepoImp(loggerService: getIt(), apiClient: getIt()));
+ getIt.registerLazySingleton(() => ServicesPriceListRepoImp(loggerService: getIt(), apiClient: getIt()));
// ViewModels
// Global/shared VMs → LazySingleton
@@ -311,5 +314,6 @@ class AppDependencies {
getIt.registerLazySingleton(() => AskDoctorViewModel(askDoctorRepo: getIt(), errorHandlerService: getIt()));
+ getIt.registerLazySingleton(() => ServicesPriceListViewModel(servicesPriceListRepo: getIt(), errorHandlerService: getIt()));
}
}
diff --git a/lib/core/utils/date_util.dart b/lib/core/utils/date_util.dart
index 746d2a7a..2b134735 100644
--- a/lib/core/utils/date_util.dart
+++ b/lib/core/utils/date_util.dart
@@ -110,7 +110,7 @@ class DateUtil {
}
static String formatDateToTime(DateTime date) {
- return DateFormat('hh:mm a').format(date);
+ return DateFormat('hh:mm a', "en-US").format(date);
}
static String yearMonthDay(DateTime dateTime) {
@@ -487,7 +487,9 @@ class DateUtil {
}
static String getFormattedDate(DateTime dateTime, String formattedString) {
- return DateFormat(formattedString).format(dateTime);
+ String formattedDate = DateFormat(formattedString, "en-US").format(dateTime);
+ print(formattedDate);
+ return formattedDate;
}
static convertISODateToJsonDate(String isoDate) {
diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart
index 88e8cc84..aef18f73 100644
--- a/lib/core/utils/push_notification_handler.dart
+++ b/lib/core/utils/push_notification_handler.dart
@@ -372,6 +372,14 @@ class PushNotificationHandler {
}
});
+ if (Platform.isIOS) {
+ FirebaseMessaging.instance.getAPNSToken().then((String? token) {
+ print("Push Notification getAPNSToken: ${token!}");
+ }).catchError((err) {
+ print("Push Notification getAPNSToken ERR: ${err.toString()}");
+ });
+ }
+
FirebaseMessaging.instance.getToken().then((String? token) {
print("Push Notification getToken: ${token!}");
onToken(token!);
diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart
index e57039cb..dd81a13c 100644
--- a/lib/core/utils/request_utils.dart
+++ b/lib/core/utils/request_utils.dart
@@ -210,8 +210,8 @@ class RequestUtils {
List names = fullName != null ? fullName.split(" ") : [];
var dob = appState.getUserRegistrationPayload.dob;
- final DateFormat dateFormat1 = DateFormat('MM/dd/yyyy');
- final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy');
+ final DateFormat dateFormat1 = DateFormat('MM/dd/yyyy', "en-US");
+ final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy', "en-US");
DateTime gregorianDate = dateFormat2.parse(dob!);
HijriGregDate hijriDate = HijriGregConverter.gregorianToHijri(gregorianDate);
String? date = "${hijriDate.day}/${hijriDate.month}/${hijriDate.year}";
diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart
index 673ef738..60925bca 100644
--- a/lib/core/utils/utils.dart
+++ b/lib/core/utils/utils.dart
@@ -128,7 +128,7 @@ class Utils {
static String convertStringToDateTime(String dateTimeString) {
String timeString = dateTimeString;
// Parse the time string using DateFormat
- DateFormat format = DateFormat.Hms(); // 'Hms' = 'HH:mm:ss'
+ DateFormat format = DateFormat.Hms(["en-US"]); // 'Hms' = 'HH:mm:ss'
DateTime time = format.parse(timeString);
DateTime now = DateTime.now();
@@ -987,4 +987,17 @@ class Utils {
return isAllowed;
}
+
+ static String toEnglishNumbers(String input) {
+ const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+ const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
+ const persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
+
+ String result = input;
+ for (int i = 0; i < 10; i++) {
+ result = result.replaceAll(arabic[i], english[i]);
+ result = result.replaceAll(persian[i], english[i]);
+ }
+ return result;
+ }
}
diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart
index 30b0f7e6..6a009428 100644
--- a/lib/extensions/string_extensions.dart
+++ b/lib/extensions/string_extensions.dart
@@ -23,8 +23,7 @@ extension CapExtension on String {
extension EmailValidator on String {
Widget get toWidget => Text(this);
- Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) =>
- Text(
+ Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@@ -38,7 +37,8 @@ extension EmailValidator on String {
);
Widget toText10(
- {Color? color,
+ {bool isEnglishOnly = false,
+ Color? color,
FontWeight? weight,
bool isBold = false,
bool isUnderLine = false,
@@ -59,19 +59,20 @@ extension EmailValidator on String {
color: color ?? AppColors.blackColor,
letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null,
+ fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: color ?? AppColors.blackColor),
);
Widget toText9(
- {Color? color,
- FontWeight? weight,
- bool isBold = false,
- bool isUnderLine = false,
- bool isCenter = false,
- int? maxlines,
- FontStyle? fontStyle,
- TextOverflow? textOverflow,
- double letterSpacing = 0}) =>
+ {Color? color,
+ FontWeight? weight,
+ bool isBold = false,
+ bool isUnderLine = false,
+ bool isCenter = false,
+ int? maxlines,
+ FontStyle? fontStyle,
+ TextOverflow? textOverflow,
+ double letterSpacing = 0}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
@@ -87,15 +88,7 @@ extension EmailValidator on String {
decorationColor: color ?? AppColors.blackColor),
);
- Widget toText11(
- {Color? color,
- FontWeight? weight,
- bool isUnderLine = false,
- bool isCenter = false,
- bool isBold = false,
- int maxLine = 0,
- double letterSpacing = 0}) =>
- Text(
+ Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@@ -110,7 +103,7 @@ extension EmailValidator on String {
);
Widget toText12(
- {Color? color,
+ {bool isEnglishOnly = false, Color? color,
bool isUnderLine = false,
TextAlign textAlignment = TextAlign.start,
bool isBold = false,
@@ -131,6 +124,7 @@ extension EmailValidator on String {
height: height,
decorationColor: isUnderLine ? AppColors.blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null,
+ fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
),
);
@@ -176,15 +170,7 @@ extension EmailValidator on String {
),
);
- Widget toText13(
- {Color? color,
- bool isUnderLine = false,
- bool isBold = false,
- bool isCenter = false,
- int maxLine = 0,
- FontWeight? weight,
- double? letterSpacing = 0}) =>
- Text(
+ Widget toText13({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0, FontWeight? weight, double? letterSpacing = 0}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@@ -197,6 +183,7 @@ extension EmailValidator on String {
);
Widget toText14({
+ bool isEnglishOnly = false,
Color? color,
bool isUnderLine = false,
bool isBold = false,
@@ -219,18 +206,11 @@ extension EmailValidator on String {
height: height,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null,
+ fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: color ?? AppColors.blackColor),
);
- Widget toText15(
- {Color? color,
- bool isUnderLine = false,
- bool isBold = false,
- bool isCenter = false,
- FontWeight? weight,
- int? maxlines,
- double? letterSpacing = -1}) =>
- Text(
+ Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines, double? letterSpacing = -1}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
@@ -242,8 +222,7 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
- Widget toText16(
- {Color? color,
+ Widget toText16({bool isEnglishOnly = false, Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
@@ -258,6 +237,7 @@ extension EmailValidator on String {
this,
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
+ // locale: Locale('en', 'US'),
style: TextStyle(
color: color ?? AppColors.blackColor,
fontSize: 16.f,
@@ -266,14 +246,14 @@ extension EmailValidator on String {
overflow: textOverflow,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null,
+ fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: decorationColor),
);
- Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text(
+ Widget toText17({bool isEnglishOnly = false, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(
- color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),
);
Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow}) => Text(
@@ -281,17 +261,12 @@ extension EmailValidator on String {
textAlign: isCenter ? TextAlign.center : null,
this,
overflow: textOverflow,
- style: TextStyle(
- fontSize: 18.f,
- fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
- color: color ?? AppColors.blackColor,
- letterSpacing: -0.4),
+ style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText19({Color? color, bool isBold = false}) => Text(
this,
- style: TextStyle(
- fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
+ style: TextStyle(fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText20({
@@ -301,86 +276,51 @@ extension EmailValidator on String {
}) =>
Text(
this,
- style: TextStyle(
- fontSize: 20.f,
- fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
- color: color ?? AppColors.blackColor,
- letterSpacing: -0.4),
+ style: TextStyle(fontSize: 20.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this,
maxLines: maxlines,
- style: TextStyle(
- color: color ?? AppColors.blackColor,
- fontSize: 21.f,
- letterSpacing: -1,
- fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
+ style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.f, letterSpacing: -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(
- height: 1,
- color: color ?? AppColors.blackColor,
- fontSize: 22.f,
- letterSpacing: -1,
- fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
- height: 23 / 24,
- color: color ?? AppColors.blackColor,
- fontSize: 24.f,
- letterSpacing: letterSpacing ?? -1,
- fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
+ height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
);
Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
- height: height ?? 23 / 26,
- color: color ?? AppColors.blackColor,
- fontSize: 26.f,
- letterSpacing: letterSpacing ?? -1,
- fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
+ height: height ?? 23 / 26, color: color ?? AppColors.blackColor, fontSize: 26.f, letterSpacing: letterSpacing ?? -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
- Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
+ Widget toText28({bool isEnglishOnly = false, Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(
- height: height ?? 23 / 28,
- color: color ?? AppColors.blackColor,
- fontSize: 28.f,
- letterSpacing: letterSpacing ?? -1,
- fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: height ?? 23 / 28, color: color ?? AppColors.blackColor, fontSize: 28.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),
);
- Widget toText32({FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text(
+ Widget toText32({bool isEnglishOnly = false, FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
- height: 32 / 32,
- color: color ?? AppColors.blackColor,
- fontSize: 32.f,
- letterSpacing: -1,
- fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
+ height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
);
Widget toText44({Color? color, bool isBold = false}) => Text(
this,
- style: TextStyle(
- height: 32 / 32,
- color: color ?? AppColors.blackColor,
- fontSize: 44.f,
- letterSpacing: -1,
- fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@@ -416,9 +356,7 @@ extension EmailValidator on String {
}
bool isValidEmail() {
- return RegExp(
- r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
- .hasMatch(this);
+ return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
}
String toFormattedDate() {
diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart
index b48912de..50bd1cae 100644
--- a/lib/features/authentication/authentication_view_model.dart
+++ b/lib/features/authentication/authentication_view_model.dart
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:get_it/get_it.dart';
import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart';
+import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
@@ -74,6 +75,8 @@ class AuthenticationViewModel extends ChangeNotifier {
dobController = TextEditingController(),
nameController = TextEditingController(),
emailController = TextEditingController();
+
+
CountryEnum selectedCountrySignup = CountryEnum.saudiArabia;
MaritalStatusTypeEnum? maritalStatus;
GenderTypeEnum? genderType;
@@ -279,9 +282,10 @@ class AuthenticationViewModel extends ChangeNotifier {
loginTypeEnum = otpTypeEnum == OTPTypeEnum.sms ? LoginTypeEnum.sms : LoginTypeEnum.whatsapp;
- if (phoneNumberController.text.isEmpty) {
- phoneNumberController.text = "504278212";
- }
+ // if (phoneNumberController.text.isEmpty) {
+ // phoneNumberController.text = "504278212";
+ // }
+
bool isValidated = ValidationUtils.isValidatePhoneAndId(phoneNumber: phoneNumberController.text, nationalId: nationalIdController.text);
if (!isValidated) {
@@ -404,7 +408,6 @@ class AuthenticationViewModel extends ChangeNotifier {
return;
}
patientShareRequestID = apiResponse.data['PatientShareRequestID'];
- print("PatientShareRequestID ==============: $patientShareRequestID");
_appState.setFamilyFileTokenID = apiResponse.data['LogInTokenID'];
}
if (apiResponse.messageStatus == 2) {
@@ -1045,6 +1048,7 @@ class AuthenticationViewModel extends ChangeNotifier {
}
Future getServicePrivilege() async {
+ ApiConsts.setBackendURLs();
final resultEither = await _authenticationRepo.getServicePrivilege();
List privilegeModelList = [];
List vidaPlusProjectListModel = [];
diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart
index cab79ad7..fc541d2e 100644
--- a/lib/features/book_appointments/book_appointments_repo.dart
+++ b/lib/features/book_appointments/book_appointments_repo.dart
@@ -185,7 +185,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
- onError!(error);
+ // onError!(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart
index 34858b47..9b53a133 100644
--- a/lib/features/book_appointments/book_appointments_view_model.dart
+++ b/lib/features/book_appointments/book_appointments_view_model.dart
@@ -103,6 +103,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
String selectedAppointmentDate = "";
String selectedAppointmentTime = "";
+ String selectedAppointmentDisplayDate = "";
dynamic freeSlotsResponse;
@@ -385,9 +386,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
- setSelectedAppointmentDateTime(String date, String time) {
+ setSelectedAppointmentDateTime(String date, String time, String displayDate) {
selectedAppointmentDate = date;
selectedAppointmentTime = time;
+ selectedAppointmentDisplayDate = displayDate;
notifyListeners();
}
@@ -581,7 +583,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
- onError?.call(LocaleKeys.noDoctorFound.tr());
+ onError?.call(selectedClinic.clinicID == 23 ? failure.message : LocaleKeys.noDoctorFound.tr());
},
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
@@ -721,7 +723,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
Future getLiveCareDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear();
DateTime date;
- final DateFormat formatter = DateFormat('HH:mm');
+ final DateFormat formatter = DateFormat('HH:mm', "en-US");
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map _eventsParsed;
@@ -806,6 +808,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
print(failure);
+ onError!(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
diff --git a/lib/features/hmg_services/hmg_services_view_model.dart b/lib/features/hmg_services/hmg_services_view_model.dart
index daddbff4..5bf450ba 100644
--- a/lib/features/hmg_services/hmg_services_view_model.dart
+++ b/lib/features/hmg_services/hmg_services_view_model.dart
@@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.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/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart';
@@ -17,6 +18,7 @@ import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/search_e_referral_resp_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/features/my_appointments/models/resp_models/hospital_model.dart';
+import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@@ -31,8 +33,7 @@ class HmgServicesViewModel extends ChangeNotifier {
final ErrorHandlerService errorHandlerService;
final NavigationService navigationService;
- HmgServicesViewModel(
- {required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
+ HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
bool isCmcOrdersLoading = false;
bool isCmcServicesLoading = false;
@@ -55,9 +56,11 @@ class HmgServicesViewModel extends ChangeNotifier {
// Vital Sign PageView Controller
PageController _vitalSignPageController = PageController();
+
PageController get vitalSignPageController => _vitalSignPageController;
int _vitalSignCurrentPage = 0;
+
int get vitalSignCurrentPage => _vitalSignCurrentPage;
void setVitalSignCurrentPage(int page) {
@@ -65,7 +68,6 @@ class HmgServicesViewModel extends ChangeNotifier {
notifyListeners();
}
-
// HHC specific lists
List hhcOrdersList = [];
List hhcServicesList = [];
@@ -82,9 +84,8 @@ class HmgServicesViewModel extends ChangeNotifier {
List searchReferralList = [];
List covidTestProcedureList = [];
Covid19GetPaymentInfo? covidPaymentInfo;
- Future getOrdersList() async {}
-
+ Future getOrdersList() async {}
// HHC multiple services selection
List selectedHhcServices = [];
@@ -792,22 +793,20 @@ class HmgServicesViewModel extends ChangeNotifier {
},
);
}
+
List getQuestionsFromJson() {
- final String questionsJson = '''[ { "id": 1, "questionEN": "Is the test intended for travel?", "questionAR": "هل تجري التحليل بغرض السفر؟", "ans": 2 }, { "id": 2, "questionEN": "Coming from outside KSA within last 2 weeks?", "questionAR": "هل قدمت من خارج المملكة خلال الأسبوعين الماضيين؟", "ans": 2 }, { "id": 3, "questionEN": "Do you currently have fever?", "questionAR": "هل تعاني حاليا من حرارة؟", "ans": 2 }, { "id": 4, "questionEN": "Did you have fever in last 2 weeks?", "questionAR": "هل عانيت من حرارة في الأسبوعين الماضيين؟", "ans": 2 }, { "id": 5, "questionEN": "Do you have a sore throat?", "questionAR": "هل لديك التهاب في الحلق؟", "ans": 2 }, { "id": 6, "questionEN": "Do you have a runny nose?", "questionAR": "هل لديك سيلان بالأنف؟" }, { "id": 7, "questionEN": "Do you have a cough?", "questionAR": "هل لديك سعال؟", "ans": 2 }, { "id": 8, "questionEN": "Do you have shortness of breath?", "questionAR": "هل تعاني من ضيق في التنفس؟", "ans": 2 }, { "id": 9, "questionEN": "Do you have nausea?", "questionAR": "هل تعاني من غثيان؟", "ans": 2 }, { "id": 10, "questionEN": "Do you have vomiting?", "questionAR": "هل تعاني من القيء؟", "ans": 2 }, { "id": 11, "questionEN": "Do you have a headache?", "questionAR": "هل تعاني من صداع في الرأس؟", "ans": 2 }, { "id": 12, "questionEN": "Do you have muscle pain?", "questionAR": "هل تعانين من آلام عضلية؟", "ans": 2 }, { "id": 13, "questionEN": "Do you have joint pain?", "questionAR": "هل تعاني من آلام المفاصل؟", "ans": 2 }, { "id": 14, "questionEN": "Do you have diarrhea?", "questionAR": "هل لديك اسهال؟", "ans": 2 } ]''';
+ final String questionsJson =
+ '''[ { "id": 1, "questionEN": "Is the test intended for travel?", "questionAR": "هل تجري التحليل بغرض السفر؟", "ans": 2 }, { "id": 2, "questionEN": "Coming from outside KSA within last 2 weeks?", "questionAR": "هل قدمت من خارج المملكة خلال الأسبوعين الماضيين؟", "ans": 2 }, { "id": 3, "questionEN": "Do you currently have fever?", "questionAR": "هل تعاني حاليا من حرارة؟", "ans": 2 }, { "id": 4, "questionEN": "Did you have fever in last 2 weeks?", "questionAR": "هل عانيت من حرارة في الأسبوعين الماضيين؟", "ans": 2 }, { "id": 5, "questionEN": "Do you have a sore throat?", "questionAR": "هل لديك التهاب في الحلق؟", "ans": 2 }, { "id": 6, "questionEN": "Do you have a runny nose?", "questionAR": "هل لديك سيلان بالأنف؟" }, { "id": 7, "questionEN": "Do you have a cough?", "questionAR": "هل لديك سعال؟", "ans": 2 }, { "id": 8, "questionEN": "Do you have shortness of breath?", "questionAR": "هل تعاني من ضيق في التنفس؟", "ans": 2 }, { "id": 9, "questionEN": "Do you have nausea?", "questionAR": "هل تعاني من غثيان؟", "ans": 2 }, { "id": 10, "questionEN": "Do you have vomiting?", "questionAR": "هل تعاني من القيء؟", "ans": 2 }, { "id": 11, "questionEN": "Do you have a headache?", "questionAR": "هل تعاني من صداع في الرأس؟", "ans": 2 }, { "id": 12, "questionEN": "Do you have muscle pain?", "questionAR": "هل تعانين من آلام عضلية؟", "ans": 2 }, { "id": 13, "questionEN": "Do you have joint pain?", "questionAR": "هل تعاني من آلام المفاصل؟", "ans": 2 }, { "id": 14, "questionEN": "Do you have diarrhea?", "questionAR": "هل لديك اسهال؟", "ans": 2 } ]''';
try {
final parsed = json.decode(questionsJson) as List;
- return parsed
- .map((e) => CovidQuestionnaireModel.fromJson(Map.from(e)))
- .toList();
+ return parsed.map((e) => CovidQuestionnaireModel.fromJson(Map.from(e))).toList();
} catch (_) {
return [];
}
- }
-
+ }
Future getCovidProcedureList({
-
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
@@ -816,14 +815,14 @@ class HmgServicesViewModel extends ChangeNotifier {
final result = await hmgServicesRepo.getCovidTestProcedures();
result.fold(
- (failure) async {
+ (failure) async {
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
- (apiResponse) {
+ (apiResponse) {
if (apiResponse.messageStatus == 1) {
covidTestProcedureList = apiResponse.data ?? [];
notifyListeners();
@@ -840,7 +839,6 @@ class HmgServicesViewModel extends ChangeNotifier {
);
}
-
Future getPaymentInfo({
String? procedureID,
int? projectID,
@@ -852,14 +850,14 @@ class HmgServicesViewModel extends ChangeNotifier {
final result = await hmgServicesRepo.getCovidPaymentInfo(procedureID!, projectID!);
result.fold(
- (failure) async {
+ (failure) async {
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
- (apiResponse) {
+ (apiResponse) {
if (apiResponse.messageStatus == 1) {
covidPaymentInfo = apiResponse.data;
notifyListeners();
@@ -900,6 +898,8 @@ class HmgServicesViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1) {
vitalSignList = apiResponse.data ?? [];
hasVitalSignDataLoaded = true;
+ getIt.get().setSelectedHeight(vitalSignList.first.heightCm);
+ getIt.get().setSelectedWeight(vitalSignList.first.weightKg);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
diff --git a/lib/features/hospital/hospital_selection_view_model.dart b/lib/features/hospital/hospital_selection_view_model.dart
index 57bd3601..24c7b9b0 100644
--- a/lib/features/hospital/hospital_selection_view_model.dart
+++ b/lib/features/hospital/hospital_selection_view_model.dart
@@ -97,7 +97,7 @@ class HospitalSelectionBottomSheetViewModel extends ChangeNotifier {
initPenguinSDK(hospital.iD, clinicID: clinicID);
}
- initPenguinSDK(int projectID, {String clinicID = "1"}) async {
+ initPenguinSDK(int projectID, {String clinicID = ""}) async {
NavigationClinicDetails data = NavigationClinicDetails();
data.projectId = projectID.toString();
data.clinicId = clinicID;
diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart
index e661157d..a4cdcf1c 100644
--- a/lib/features/lab/lab_repo.dart
+++ b/lib/features/lab/lab_repo.dart
@@ -5,6 +5,8 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
+import 'package:hmg_patient_app_new/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart';
+import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_special_result.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
@@ -13,6 +15,7 @@ import 'models/resp_models/lab_result.dart' show LabResult;
abstract class LabRepo {
Future>>> getPatientLabOrders();
+
Future>>> getPatientLabResults(PatientLabOrdersResponseModel laborder, bool isVidaPlus, String procedureName);
Future>>> getPatientLabResultsByHospitals(PatientLabOrdersResponseModel laborder, bool isVidaPlus);
@@ -22,6 +25,10 @@ abstract class LabRepo {
Future>> getLabResultReportPDF({required PatientLabOrdersResponseModel labOrder});
Future>> getLabResultsByAppointmentNo({required num appointmentNo, required num projectID, required num clinicID});
+
+ Future>> getPatientAiOverViewLabOrders(var payload);
+
+ Future>> getPatientAiOverViewLabOrder(var payload);
}
class LabRepoImp implements LabRepo {
@@ -71,10 +78,7 @@ class LabRepoImp implements LabRepo {
}
@override
- Future>>> getPatientLabResults(
- PatientLabOrdersResponseModel laborder, bool isVidaPlus, String procedureName
- ) async {
-
+ Future>>> getPatientLabResults(PatientLabOrdersResponseModel laborder, bool isVidaPlus, String procedureName) async {
Map request = Map();
request['InvoiceNo_VP'] = isVidaPlus ? laborder!.invoiceNo : "0";
request['InvoiceNo'] = isVidaPlus ? "0" : laborder!.invoiceNo;
@@ -100,10 +104,7 @@ class LabRepoImp implements LabRepo {
throw Exception("lab list is empty");
}
- final labOrders = list
- .map((item) => LabResult.fromJson(item as Map))
- .toList()
- .cast();
+ final labOrders = list.map((item) => LabResult.fromJson(item as Map)).toList().cast();
apiResponse = GenericApiModel>(
messageStatus: messageStatus,
@@ -125,9 +126,7 @@ class LabRepoImp implements LabRepo {
}
@override
- Future>>>
- getPatientLabResultsByHospitals(
- PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
+ Future>>> getPatientLabResultsByHospitals(PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
Map request = Map();
request['InvoiceNo_VP'] = isVidaPlus ? laborder!.invoiceNo : "0";
request['InvoiceNo'] = isVidaPlus ? "0" : laborder!.invoiceNo;
@@ -175,9 +174,7 @@ class LabRepoImp implements LabRepo {
}
@override
- Future>>>
- getSpecialLabResult(
- PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
+ Future>>> getSpecialLabResult(PatientLabOrdersResponseModel laborder, bool isVidaPlus) async {
Map request = Map();
request['InvoiceNo_VP'] = isVidaPlus ? laborder!.invoiceNo : "0";
request['InvoiceNo'] = isVidaPlus ? "0" : laborder!.invoiceNo;
@@ -203,11 +200,7 @@ class LabRepoImp implements LabRepo {
throw Exception("lab list is empty");
}
- final labOrders = list
- .map((item) => PatientLabSpecialResult.fromJson(
- item as Map))
- .toList()
- .cast();
+ final labOrders = list.map((item) => PatientLabSpecialResult.fromJson(item as Map)).toList().cast();
apiResponse = GenericApiModel>(
messageStatus: messageStatus,
@@ -318,4 +311,76 @@ class LabRepoImp implements LabRepo {
return Left(UnknownFailure(e.toString()));
}
}
+
+ @override
+ Future>> getPatientAiOverViewLabOrder(var labOrder) async {
+ try {
+ GenericApiModel? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ ApiConsts.getAiOverViewLabOrder,
+ body: labOrder,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ var res;
+ if (response["analysis_result"] != null) {
+ res = response["analysis_result"];
+ }
+ apiResponse = GenericApiModel(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: LabOrderResponseByAi.fromJson(res),
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+
+ @override
+ Future>> getPatientAiOverViewLabOrders(var labOrder) async {
+ try {
+ GenericApiModel? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ ApiConsts.getAiOverViewLabOrders,
+ body: {"lab_results": labOrder},
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ var res;
+ if (response["lab_analysis_result"] != null) {
+ res = response["lab_analysis_result"];
+ }
+ apiResponse = GenericApiModel(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: LabOrdersResponseByAi.fromJson(res),
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
}
diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart
index 1047dbc0..04c945df 100644
--- a/lib/features/lab/lab_view_model.dart
+++ b/lib/features/lab/lab_view_model.dart
@@ -1,16 +1,24 @@
import 'dart:collection';
+import 'dart:convert';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
+import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
+import 'package:hmg_patient_app_new/features/lab/models/ai_overview_labresult_model_payload.dart';
+import 'package:hmg_patient_app_new/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/lab_result.dart';
+import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_results/lab_result_details.dart';
+import 'package:hmg_patient_app_new/presentation/labAiAnalysis/lab_ai_analysis_detailed_page.dart';
+import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@@ -53,20 +61,7 @@ class LabViewModel extends ChangeNotifier {
List mainLabResults = [];
List mainGraphPoints = [];
List filteredGraphValues = [];
- List months = [
- 'Jan',
- 'Feb',
- 'Mar',
- 'April',
- 'May',
- 'Jun',
- 'July',
- 'Aug',
- 'Sep',
- 'Oct',
- 'Nov',
- 'Dec'
- ];
+ List months = ['Jan', 'Feb', 'Mar', 'April', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
late List _labSuggestionsList = [];
@@ -86,22 +81,22 @@ class LabViewModel extends ChangeNotifier {
List> patientLabOrdersByHospital = [];
List> patientLabOrdersViewList = [];
- LabViewModel(
- {required this.labRepo,
- required this.errorHandlerService,
- required this.navigationService});
+ LabOrderResponseByAi? labOrderResponseByAi;
+ LabOrdersResponseByAi? labOrdersResponseByAi;
+
+ LabViewModel({required this.labRepo, required this.errorHandlerService, required this.navigationService});
initLabProvider() {
// if (isLabNeedToLoad) {
- patientLabOrders.clear();
- filteredLabOrders.clear();
- labOrderTests.clear();
- isLabOrdersLoading = true;
- isLabResultsLoading = true;
- patientLabOrdersByClinic.clear();
- patientLabOrdersByHospital.clear();
- patientLabOrdersViewList.clear();
- getPatientLabOrders();
+ patientLabOrders.clear();
+ filteredLabOrders.clear();
+ labOrderTests.clear();
+ isLabOrdersLoading = true;
+ isLabResultsLoading = true;
+ patientLabOrdersByClinic.clear();
+ patientLabOrdersByHospital.clear();
+ patientLabOrdersViewList.clear();
+ getPatientLabOrders();
// }
notifyListeners();
}
@@ -133,13 +128,13 @@ class LabViewModel extends ChangeNotifier {
final result = await labRepo.getPatientLabOrders();
result.fold(
- (failure) async {
- isLabOrdersLoading = false;
- isLabResultsLoading = false;
- notifyListeners();
- },
- // => await errorHandler_service.handleError(failure: failure),
- (apiResponse) {
+ (failure) async {
+ isLabOrdersLoading = false;
+ isLabResultsLoading = false;
+ notifyListeners();
+ },
+ // => await errorHandler_service.handleError(failure: failure),
+ (apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@@ -203,11 +198,7 @@ class LabViewModel extends ChangeNotifier {
}
filterSuggestions() {
- final List labels = patientLabOrders
- .expand((order) => order.testDetails ?? [])
- .map((detail) => detail.description)
- .whereType()
- .toList();
+ final List labels = patientLabOrders.expand((order) => order.testDetails ?? []).map((detail) => detail.description).whereType().toList();
_labSuggestionsList = labels.toSet().toList();
notifyListeners();
@@ -322,14 +313,12 @@ class LabViewModel extends ChangeNotifier {
);
}
- Future getPatientLabResultByHospital(
- PatientLabOrdersResponseModel laborder) async {
+ Future getPatientLabResultByHospital(PatientLabOrdersResponseModel laborder) async {
isLabResultByHospitalLoading = true;
notifyListeners();
mainLabResultsByHospitals.clear();
- final result = await labRepo.getPatientLabResultsByHospitals(laborder,
- Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")));
+ final result = await labRepo.getPatientLabResultsByHospitals(laborder, Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")));
result.fold(
(failure) async {
@@ -353,12 +342,9 @@ class LabViewModel extends ChangeNotifier {
mainLabResults.clear();
filteredGraphValues.clear();
maxY = double.negativeInfinity;
- minY = double.infinity;
- maxX = double.infinity;
- final result = await labRepo.getPatientLabResults(
- laborder,
- Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")),
- procedureName);
+ minY = double.infinity;
+ maxX = double.infinity;
+ final result = await labRepo.getPatientLabResults(laborder, Utils.isVidaPlusProject(int.parse(laborder.projectID ?? "0")), procedureName);
result.fold(
(failure) async {
@@ -372,7 +358,6 @@ class LabViewModel extends ChangeNotifier {
var recentThree = sort(apiResponse.data!);
mainLabResults = recentThree;
-
double highRefrenceValue = double.negativeInfinity;
String? flagForHighReferenceRange;
double lowRefenceValue = double.infinity;
@@ -380,11 +365,10 @@ class LabViewModel extends ChangeNotifier {
recentThree.reversed.forEach((element) {
try {
- var dateTime =
- DateUtil.convertStringToDate(element.verifiedOnDateTime!);
+ var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
- var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
- if (resultValue>maxY) {
+ var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
+ if (resultValue > maxY) {
maxY = resultValue;
maxX = maxY;
}
@@ -401,14 +385,13 @@ class LabViewModel extends ChangeNotifier {
}
filteredGraphValues.add(DataPoint(
- value: transformedValue,
- actualValue:element.resultValue!,
- label: formatDateAsMMYY(dateTime),
- unitOfMeasurement: element.uOM,
- displayTime: resultDate(dateTime),
- time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
- referenceValue: element.calculatedResultFlag ?? "",
-
+ value: transformedValue,
+ actualValue: element.resultValue!,
+ label: formatDateAsMMYY(dateTime),
+ unitOfMeasurement: element.uOM,
+ displayTime: resultDate(dateTime),
+ time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
+ referenceValue: element.calculatedResultFlag ?? "",
));
} catch (e) {}
});
@@ -424,7 +407,7 @@ class LabViewModel extends ChangeNotifier {
this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1));
this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1));
- if(maxY< highRefrenceValue) {
+ if (maxY < highRefrenceValue) {
maxY = highRefrenceValue;
}
maxY += 25;
@@ -434,7 +417,9 @@ class LabViewModel extends ChangeNotifier {
checkIfGraphShouldBeDisplayed(recentResult);
recentResult.verifiedOn = resultDate(DateUtil.convertStringToDate(recentResult.verifiedOnDateTime!));
// filteredGraphValues = [filteredGraphValues.first];
- navigationService.push(MaterialPageRoute(
+ labOrderResponseByAi = null;
+ navigationService.push(
+ MaterialPageRoute(
builder: (_) => LabResultDetails(recentLabResult: recentResult, testDescription: testDescription),
),
);
@@ -444,14 +429,13 @@ class LabViewModel extends ChangeNotifier {
);
}
- void checkIfGraphShouldBeDisplayed(LabResult recentResult){
+ void checkIfGraphShouldBeDisplayed(LabResult recentResult) {
shouldShowGraph = recentResult.checkIfGraphShouldBeDisplayed();
isGraphVisible = shouldShowGraph;
notifyListeners();
}
- Future getPatientSpecialResult(
- PatientLabOrdersResponseModel laborder) async {
+ Future getPatientSpecialResult(PatientLabOrdersResponseModel laborder) async {
isSpecialResultsLoading = true;
labSpecialResult = "";
notifyListeners();
@@ -473,8 +457,7 @@ class LabViewModel extends ChangeNotifier {
StringBuffer htmlbuffer = StringBuffer("");
apiResponse.data?.forEach((element) {
- if(element.resultDataHTML != null && element.resultDataHTML?.isNotEmpty == true)
- htmlbuffer.write("${element.resultDataHTML}
");
+ if (element.resultDataHTML != null && element.resultDataHTML?.isNotEmpty == true) htmlbuffer.write("${element.resultDataHTML}
");
});
labSpecialResult = htmlbuffer.toString();
@@ -486,10 +469,8 @@ class LabViewModel extends ChangeNotifier {
);
}
- String resultDate(DateTime date){
-
-
- return '${date.day} ${months[date.month-1]},${date.year}';
+ String resultDate(DateTime date) {
+ return '${date.day} ${months[date.month - 1]},${date.year}';
}
double transformValueInRange(double inputValue, String flag) {
@@ -497,7 +478,7 @@ class LabViewModel extends ChangeNotifier {
double rangeStart, rangeEnd;
switch (flag) {
- case'LCL':
+ case 'LCL':
case 'CL':
rangeStart = 0.0;
rangeEnd = 19.0;
@@ -534,16 +515,17 @@ class LabViewModel extends ChangeNotifier {
debugPrint("the transformed value is $transformedValue");
return transformedValue;
}
+
void getSelectedDateRange(DateTime? start, DateTime? end) {
maxY = double.negativeInfinity;
- if(start == null && end == null) {
+ if (start == null && end == null) {
mainLabResults.forEach((element) {
final time = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
- try{
+ try {
var resultValue = double.parse(element.resultValue!);
- var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
+ var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
if (resultValue > maxY) {
maxY = resultValue;
}
@@ -552,54 +534,43 @@ class LabViewModel extends ChangeNotifier {
actualValue: element.resultValue!,
label: formatDateAsMMYY(time),
unitOfMeasurement: element.uOM,
-
displayTime: resultDate(time),
time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? "",
));
- }catch(e){
-
- }
+ } catch (e) {}
});
-
- }else {
+ } else {
filteredGraphValues.clear();
mainLabResults.forEach((element) {
try {
- var dateTime =
- DateUtil.convertStringToDate(element.verifiedOnDateTime!);
+ var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
- var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??"");
+ var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
if (resultValue > maxY) {
maxY = resultValue;
}
if (start != null && end == null) {
if (dateTime.isAtSameMomentAs(start)) {
-
filteredGraphValues.add(DataPoint(
value: transformedValue,
actualValue: element.resultValue!,
unitOfMeasurement: element.uOM,
-
label: formatDateAsMMYY(dateTime),
displayTime: resultDate(dateTime),
- time:
- DateUtil.convertStringToDate(element.verifiedOnDateTime),
+ time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? ""));
}
} else if (start != null && end != null) {
if ((dateTime.isAfter(start)) && (dateTime.isBefore(end))) {
-
filteredGraphValues.add(DataPoint(
value: transformedValue,
actualValue: element.resultValue!,
label: formatDateAsMMYY(dateTime),
unitOfMeasurement: element.uOM,
-
displayTime: resultDate(dateTime),
- time:
- DateUtil.convertStringToDate(element.verifiedOnDateTime),
+ time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? ""));
}
}
@@ -608,16 +579,13 @@ class LabViewModel extends ChangeNotifier {
}
filteredGraphValues = sortFilteredList(filteredGraphValues).reversed.toList();
-
notifyListeners();
}
String formatDateAsMMYY(DateTime date) {
-
- return '${months[date.month-1]}, ${date.year}';
+ return '${months[date.month - 1]}, ${date.year}';
}
-
List sortByFlagAndValue(List original) {
const priorityOrder = ['LCL', 'CL', 'L', 'N', 'H', 'CH', 'HCH'];
@@ -651,7 +619,6 @@ class LabViewModel extends ChangeNotifier {
}
List sort(List original) {
-
final copy = List.from(original);
copy.sort((a, b) {
final aDate = DateUtil.convertStringToDate(a.verifiedOnDateTime);
@@ -666,8 +633,6 @@ class LabViewModel extends ChangeNotifier {
}
List sortFilteredList(List original) {
-
-
final copy = List.from(original);
copy.sort((a, b) {
final aDate = a.time;
@@ -702,7 +667,7 @@ class LabViewModel extends ChangeNotifier {
}
}
- String getFormattedDate(DateTime date){
+ String getFormattedDate(DateTime date) {
return DateFormat('EEEE, dd MMMM. yyyy').format(date);
}
@@ -716,7 +681,7 @@ class LabViewModel extends ChangeNotifier {
case 'N':
return AppAssets.ic_normal_result;
case 'H':
- return AppAssets.ic_low_result;
+ return AppAssets.ic_low_result;
case 'CH':
case 'HCH':
return AppAssets.ic_critical_low_result;
@@ -758,8 +723,80 @@ class LabViewModel extends ChangeNotifier {
}
}
- alterGraphVisibility(){
+ alterGraphVisibility() {
isGraphVisible = !isGraphVisible;
notifyListeners();
}
+
+ Future getAiOverviewLabOrders({required PatientLabOrdersResponseModel labOrder}) async {
+ LoadingUtils.showFullScreenLoader(loadingText: "Loading and analysing your data,\nPlease be patient and let the AI do the magic");
+ List