From 77dcc95baca4fc39d8ac48a5df6e0df2730b00e8 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Tue, 21 Jan 2025 18:21:04 +0300 Subject: [PATCH] WD: vital sign result screen modified. --- assets/images/svg/bloodpressure.svg | 1 + assets/images/svg/bmi.svg | 1 + assets/images/svg/breathing.svg | 2 + assets/images/svg/facialSkin.svg | 1 + assets/images/svg/heartrate.svg | 1 + assets/images/svg/oxygen.svg | 1 + assets/images/svg/stress.svg | 68 +++ assets/images/svg/wellness.svg | 62 +++ lib/config/localized_values.dart | 15 + lib/pages/landing/widgets/services_view.dart | 8 +- lib/uitl/translations_delegate_base.dart | 43 +- .../components/health_result_widget.dart | 444 ++++++++-------- .../components/scan_condition.dart | 2 +- .../components/scan_condition_checklist.dart | 114 ++-- lib/vital_signs/components/start_button.dart | 13 +- .../components/vital_sign_widget.dart | 214 +++++++- lib/vital_signs/data/vitals_benchmark.dart | 354 +++++++++++++ lib/vital_signs/result_screen.dart | 498 ++++++++++-------- lib/vital_signs/vital_sign.dart | 229 +++++--- lib/widgets/others/app_scaffold_widget.dart | 6 +- 20 files changed, 1477 insertions(+), 600 deletions(-) create mode 100644 assets/images/svg/bloodpressure.svg create mode 100644 assets/images/svg/bmi.svg create mode 100644 assets/images/svg/breathing.svg create mode 100644 assets/images/svg/facialSkin.svg create mode 100644 assets/images/svg/heartrate.svg create mode 100644 assets/images/svg/oxygen.svg create mode 100644 assets/images/svg/stress.svg create mode 100644 assets/images/svg/wellness.svg create mode 100644 lib/vital_signs/data/vitals_benchmark.dart diff --git a/assets/images/svg/bloodpressure.svg b/assets/images/svg/bloodpressure.svg new file mode 100644 index 00000000..29de9a12 --- /dev/null +++ b/assets/images/svg/bloodpressure.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/svg/bmi.svg b/assets/images/svg/bmi.svg new file mode 100644 index 00000000..bcf04b5e --- /dev/null +++ b/assets/images/svg/bmi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/svg/breathing.svg b/assets/images/svg/breathing.svg new file mode 100644 index 00000000..9e2d7ab3 --- /dev/null +++ b/assets/images/svg/breathing.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/images/svg/facialSkin.svg b/assets/images/svg/facialSkin.svg new file mode 100644 index 00000000..472a81ed --- /dev/null +++ b/assets/images/svg/facialSkin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/svg/heartrate.svg b/assets/images/svg/heartrate.svg new file mode 100644 index 00000000..76e8197d --- /dev/null +++ b/assets/images/svg/heartrate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/svg/oxygen.svg b/assets/images/svg/oxygen.svg new file mode 100644 index 00000000..acf1293b --- /dev/null +++ b/assets/images/svg/oxygen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/svg/stress.svg b/assets/images/svg/stress.svg new file mode 100644 index 00000000..411e1db6 --- /dev/null +++ b/assets/images/svg/stress.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/svg/wellness.svg b/assets/images/svg/wellness.svg new file mode 100644 index 00000000..d9316128 --- /dev/null +++ b/assets/images/svg/wellness.svg @@ -0,0 +1,62 @@ + + + + diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 7bfb0397..60db6024 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -2140,4 +2140,19 @@ const Map localizedValues = { "download": {"en": "Download", "ar": "تحميل"}, "share": {"en": "Share", "ar": "يشارك"}, + "stress": {"en": "Stress", "ar": "ضغط"}, + "cvd": {"en": "Cardiovascular Disease (CVD) Risk", "ar": "مخاطر أمراض القلب والأوعية الدموية (CVD)"}, + "generalWellness": {"en": "General Wellness", "ar": "العافية العامة"}, + "BMI": {"en": "BMI", "ar": "مؤشر كتله الجسم"}, + "respiratoryRate": {"en": "Respiratory Rate", "ar": "معدل التنفس"}, + "oxygenSaturation": {"en": "Oxygen Saturation", "ar": "تشبع الأكسجين"}, + "scanning": {"en": "Scanning", "ar": "المسح الضوئي"}, + "normal": {"en": "Normal", "ar": "عادي"}, + "poor": {"en": "Poor", "ar": "فقير"}, + "low": {"en": "Low", "ar": "منخفض"}, + "atRisk": {"en": "At Risk", "ar": "في خطر"}, + "high": {"en": "High", "ar": "عال"}, + "moderatelyHigh": {"en": "Moderately high", "ar": "مرتفع بشكل معتدل"}, + "possiblyLow": {"en": "Possibly low", "ar": "ربما منخفض"}, + "slightylyHigh": {"en": "Slightly high", "ar": "مرتفع قليلا"}, }; diff --git a/lib/pages/landing/widgets/services_view.dart b/lib/pages/landing/widgets/services_view.dart index 1ca31655..752f9b93 100644 --- a/lib/pages/landing/widgets/services_view.dart +++ b/lib/pages/landing/widgets/services_view.dart @@ -41,6 +41,7 @@ import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/vital_signs/result_screen.dart'; import 'package:diplomaticquarterapp/vital_signs/vital_sign.dart'; import 'package:diplomaticquarterapp/widgets/dialogs/covid_consent_dialog.dart'; import 'package:diplomaticquarterapp/widgets/dialogs/location_selection_dialog.dart'; @@ -50,6 +51,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:vital_sign_camera/vital_sign_camera.dart'; import '../../../locator.dart'; import '../landing_page_pharmcy.dart'; @@ -230,9 +232,11 @@ class ServicesView extends StatelessWidget { } else if (hmgServices.action == 1) { openLiveCare(context); } else if (hmgServices.action == 2) { - - //todo for temporary basis Navigator.push(context, FadePage(page: VitalSigns())); + //todo for temporary basis + // Navigator.push(context, FadePage(page: ResultScreen( + // healthResult: Health(null, null, VitalSign(92,1, 1, null,null,null,null,null,null,null,null,null, null,null,null,null), null,null,), + // ))); // initPenguinSDK(); diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 3ce068fb..1c56d66b 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -3044,7 +3044,48 @@ class TranslationBase { String get download => localizedValues["download"][locale.languageCode]; String get share => localizedValues["share"][locale.languageCode]; - + String get scanning => localizedValues["scanning"][locale.languageCode]; + String get normal => localizedValues["normal"][locale.languageCode]; + String get poor => localizedValues["poor"][locale.languageCode]; + String get high => localizedValues["high"][locale.languageCode]; + String get low => localizedValues["low"][locale.languageCode]; + String get atRisk => localizedValues["atRisk"][locale.languageCode]; + String get slightlyHigh => localizedValues["slightlyHigh"][locale.languageCode]; + String get possiblyLow => localizedValues["possiblyLow"][locale.languageCode]; + String get moderatelyHigh => localizedValues["moderatelyHigh"][locale.languageCode]; + String get oxygenSaturation => localizedValues["oxygenSaturation"][locale.languageCode]; + String get stress => localizedValues["stress"][locale.languageCode]; + String get respiratoryRate => localizedValues["respiratoryRate"][locale.languageCode]; + String get BMI => localizedValues["respiratoryRate"][locale.languageCode]; + String get generalWellness => localizedValues["generalWellness"][locale.languageCode]; + String get cvd => localizedValues["cvd"][locale.languageCode]; + + String getValue(String name) { + switch (name) { + case 'normal': + return normal; + case 'poor': + return poor; + case 'good': + return good; + case 'excellent': + return excellent; + case 'high': + return high; + case 'low': + return low; + case 'atRisk': + return atRisk; + case 'slightlyHigh': + return slightlyHigh; + case 'possiblyLow': + return possiblyLow; + case 'moderatelyHigh': + return moderatelyHigh; + default: + throw ArgumentError('Invalid name: $name'); + } + } } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/vital_signs/components/health_result_widget.dart b/lib/vital_signs/components/health_result_widget.dart index ce198e50..9f7544cc 100644 --- a/lib/vital_signs/components/health_result_widget.dart +++ b/lib/vital_signs/components/health_result_widget.dart @@ -1,222 +1,222 @@ -import 'package:flutter/material.dart'; -import 'package:vital_sign_camera/vital_sign_camera.dart'; -import 'vital_sign_widget.dart'; - -class HealthResultWidget extends StatelessWidget { - final Size deviceSize; - final void Function() onTap; - final Health? healthResult; - - late final VitalSign? _vitalSign; - late final HolisticAnalysis? _holisticAnalysis; - late final CardiovascularRisks? _cardiovascularRisks; - late final CovidRisk? _covidRisk; - late final ScanParameters? _scanParameters; - - HealthResultWidget({ - Key? key, - required this.deviceSize, - required this.onTap, - required this.healthResult, - }) : super(key: key) { - _vitalSign = healthResult?.vitalSigns; - _holisticAnalysis = healthResult?.holisticHealth; - _cardiovascularRisks = healthResult?.risks?.cardiovascularRisks; - _covidRisk = healthResult?.risks?.covidRisk; - _scanParameters = healthResult?.scanParameters; - } - - @override - Widget build(BuildContext context) { - return Positioned( - top: deviceSize.height * 0.07, - left: deviceSize.width * 0.05, - child: GestureDetector( - onTap: onTap, - child: SizedBox( - width: deviceSize.width * 0.9, - child: Container( - color: Colors.black38, - child: Padding( - padding: const EdgeInsets.all(15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: const EdgeInsets.fromLTRB(0, 0, 0, 10), - child: const Text( - "Vital Signs", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - VitalSignWidget( - vitalSignName: "Heart Rate", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.heartRate)), - VitalSignWidget( - vitalSignName: "SPO2", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.spo2)), - VitalSignWidget( - vitalSignName: "IBI", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.ibi)), - if (_vitalSign?.stress != null) - VitalSignWidget( - vitalSignName: "Stress", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.stress)), - if (_vitalSign?.respiratoryRate != null) - VitalSignWidget( - vitalSignName: "Respiratory Rate", - vitalSignValue: formatValueToTwoDp( - healthResult - ?.vitalSigns.respiratoryRate)), - if (_vitalSign?.hrvRmssd != null) - VitalSignWidget( - vitalSignName: "HRV RMSSD", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.hrvRmssd)), - if (_vitalSign?.hrvSdnn != null) - VitalSignWidget( - vitalSignName: "HRV SDNN", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.hrvSdnn)), - if (_vitalSign?.temperature != null) - VitalSignWidget( - vitalSignName: "Temperature", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.temperature)), - if (_vitalSign?.bloodPressure != null) - VitalSignWidget( - vitalSignName: "Blood Pressure", - vitalSignValue: - healthResult?.vitalSigns.bloodPressure ?? - ""), - if (_vitalSign?.bloodPressureSystolic != null) - VitalSignWidget( - vitalSignName: "Blood Pressure Systolic", - vitalSignValue: formatValueToTwoDp( - healthResult - ?.vitalSigns.bloodPressureSystolic)), - if (_vitalSign?.bloodPressureDiastolic != null) - VitalSignWidget( - vitalSignName: "Blood Pressure Diastolic", - vitalSignValue: formatValueToTwoDp( - healthResult - ?.vitalSigns.bloodPressureDiastolic)), - if (_holisticAnalysis != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Holistic Analysis", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_holisticAnalysis != null && - _holisticAnalysis?.bmi != null) - VitalSignWidget( - vitalSignName: "BMI", - vitalSignValue: formatValueToTwoDp( - healthResult?.holisticHealth?.bmi)), - if (_holisticAnalysis != null && - _holisticAnalysis?.generalWellness != null) - VitalSignWidget( - vitalSignName: "General Wellness", - vitalSignValue: formatValueToTwoDp( - healthResult - ?.holisticHealth?.generalWellness)), - if (_cardiovascularRisks != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Cardiovascular Risks", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_cardiovascularRisks != null) - VitalSignWidget( - vitalSignName: "General", - vitalSignValue: formatValueToTwoDp( - healthResult?.risks?.cardiovascularRisks - ?.generalRisk)), - if (_cardiovascularRisks != null) - VitalSignWidget( - vitalSignName: "Congestive Heart Failure", - vitalSignValue: formatValueToTwoDp( - healthResult?.risks?.cardiovascularRisks - ?.congestiveHeartFailure)), - if (_cardiovascularRisks != null) - VitalSignWidget( - vitalSignName: "Coronary Heart Disease", - vitalSignValue: formatValueToTwoDp( - healthResult?.risks?.cardiovascularRisks - ?.coronaryHeartDisease)), - if (_cardiovascularRisks != null) - VitalSignWidget( - vitalSignName: "Intermittent Claudication", - vitalSignValue: formatValueToTwoDp( - healthResult?.risks?.cardiovascularRisks - ?.intermittentClaudication)), - if (_cardiovascularRisks != null) - VitalSignWidget( - vitalSignName: "Stroke", - vitalSignValue: formatValueToTwoDp( - healthResult?.risks?.cardiovascularRisks - ?.stroke)), - if (_covidRisk != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Covid Risks", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_covidRisk != null) - VitalSignWidget( - vitalSignName: "Risk", - vitalSignValue: formatValueToTwoDp( - healthResult - ?.risks?.covidRisk?.covidRisk)), - if (_scanParameters != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Scan Parameters", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_scanParameters != null) - VitalSignWidget( - vitalSignName: "Signal Quality", - vitalSignValue: formatValueToTwoDp( - healthResult - ?.scanParameters?.signalQuality)), - ])))), - )); - } - - String formatValueToTwoDp(double? value) { - return (value != null) ? value.toStringAsFixed(2) : ""; - } -} +// import 'package:flutter/material.dart'; +// import 'package:vital_sign_camera/vital_sign_camera.dart'; +// import 'vital_sign_widget.dart'; +// +// class HealthResultWidget extends StatelessWidget { +// final Size deviceSize; +// final void Function() onTap; +// final Health? healthResult; +// +// late final VitalSign? _vitalSign; +// late final HolisticAnalysis? _holisticAnalysis; +// late final CardiovascularRisks? _cardiovascularRisks; +// late final CovidRisk? _covidRisk; +// late final ScanParameters? _scanParameters; +// +// HealthResultWidget({ +// Key? key, +// required this.deviceSize, +// required this.onTap, +// required this.healthResult, +// }) : super(key: key) { +// _vitalSign = healthResult?.vitalSigns; +// _holisticAnalysis = healthResult?.holisticHealth; +// _cardiovascularRisks = healthResult?.risks?.cardiovascularRisks; +// _covidRisk = healthResult?.risks?.covidRisk; +// _scanParameters = healthResult?.scanParameters; +// } +// +// @override +// Widget build(BuildContext context) { +// return Positioned( +// top: deviceSize.height * 0.07, +// left: deviceSize.width * 0.05, +// child: GestureDetector( +// onTap: onTap, +// child: SizedBox( +// width: deviceSize.width * 0.9, +// child: Container( +// color: Colors.black38, +// child: Padding( +// padding: const EdgeInsets.all(15), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// margin: const EdgeInsets.fromLTRB(0, 0, 0, 10), +// child: const Text( +// "Vital Signs", +// style: TextStyle( +// fontSize: 15, +// color: Colors.amber, +// fontWeight: FontWeight.bold, +// ), +// ), +// ), +// VitalSignWidget( +// vitalSignName: "Heart Rate", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.heartRate)), +// VitalSignWidget( +// vitalSignName: "SPO2", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.spo2)), +// VitalSignWidget( +// vitalSignName: "IBI", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.ibi)), +// if (_vitalSign?.stress != null) +// VitalSignWidget( +// vitalSignName: "Stress", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.stress)), +// if (_vitalSign?.respiratoryRate != null) +// VitalSignWidget( +// vitalSignName: "Respiratory Rate", +// vitalSignValue: formatValueToTwoDp( +// healthResult +// ?.vitalSigns.respiratoryRate)), +// if (_vitalSign?.hrvRmssd != null) +// VitalSignWidget( +// vitalSignName: "HRV RMSSD", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.hrvRmssd)), +// if (_vitalSign?.hrvSdnn != null) +// VitalSignWidget( +// vitalSignName: "HRV SDNN", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.hrvSdnn)), +// if (_vitalSign?.temperature != null) +// VitalSignWidget( +// vitalSignName: "Temperature", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.vitalSigns.temperature)), +// if (_vitalSign?.bloodPressure != null) +// VitalSignWidget( +// vitalSignName: "Blood Pressure", +// vitalSignValue: +// healthResult?.vitalSigns.bloodPressure ?? +// ""), +// if (_vitalSign?.bloodPressureSystolic != null) +// VitalSignWidget( +// vitalSignName: "Blood Pressure Systolic", +// vitalSignValue: formatValueToTwoDp( +// healthResult +// ?.vitalSigns.bloodPressureSystolic)), +// if (_vitalSign?.bloodPressureDiastolic != null) +// VitalSignWidget( +// vitalSignName: "Blood Pressure Diastolic", +// vitalSignValue: formatValueToTwoDp( +// healthResult +// ?.vitalSigns.bloodPressureDiastolic)), +// if (_holisticAnalysis != null) +// Container( +// margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), +// child: const Text( +// "Holistic Analysis", +// style: TextStyle( +// fontSize: 15, +// color: Colors.amber, +// fontWeight: FontWeight.bold, +// ), +// ), +// ), +// if (_holisticAnalysis != null && +// _holisticAnalysis?.bmi != null) +// VitalSignWidget( +// vitalSignName: "BMI", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.holisticHealth?.bmi)), +// if (_holisticAnalysis != null && +// _holisticAnalysis?.generalWellness != null) +// VitalSignWidget( +// vitalSignName: "General Wellness", +// vitalSignValue: formatValueToTwoDp( +// healthResult +// ?.holisticHealth?.generalWellness)), +// if (_cardiovascularRisks != null) +// Container( +// margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), +// child: const Text( +// "Cardiovascular Risks", +// style: TextStyle( +// fontSize: 15, +// color: Colors.amber, +// fontWeight: FontWeight.bold, +// ), +// ), +// ), +// if (_cardiovascularRisks != null) +// VitalSignWidget( +// vitalSignName: "General", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.risks?.cardiovascularRisks +// ?.generalRisk)), +// if (_cardiovascularRisks != null) +// VitalSignWidget( +// vitalSignName: "Congestive Heart Failure", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.risks?.cardiovascularRisks +// ?.congestiveHeartFailure)), +// if (_cardiovascularRisks != null) +// VitalSignWidget( +// vitalSignName: "Coronary Heart Disease", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.risks?.cardiovascularRisks +// ?.coronaryHeartDisease)), +// if (_cardiovascularRisks != null) +// VitalSignWidget( +// vitalSignName: "Intermittent Claudication", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.risks?.cardiovascularRisks +// ?.intermittentClaudication)), +// if (_cardiovascularRisks != null) +// VitalSignWidget( +// vitalSignName: "Stroke", +// vitalSignValue: formatValueToTwoDp( +// healthResult?.risks?.cardiovascularRisks +// ?.stroke)), +// if (_covidRisk != null) +// Container( +// margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), +// child: const Text( +// "Covid Risks", +// style: TextStyle( +// fontSize: 15, +// color: Colors.amber, +// fontWeight: FontWeight.bold, +// ), +// ), +// ), +// if (_covidRisk != null) +// VitalSignWidget( +// vitalSignName: "Risk", +// vitalSignValue: formatValueToTwoDp( +// healthResult +// ?.risks?.covidRisk?.covidRisk)), +// if (_scanParameters != null) +// Container( +// margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), +// child: const Text( +// "Scan Parameters", +// style: TextStyle( +// fontSize: 15, +// color: Colors.amber, +// fontWeight: FontWeight.bold, +// ), +// ), +// ), +// if (_scanParameters != null) +// VitalSignWidget( +// vitalSignName: "Signal Quality", +// vitalSignValue: formatValueToTwoDp( +// healthResult +// ?.scanParameters?.signalQuality)), +// ])))), +// )); +// } +// +// String formatValueToTwoDp(double? value) { +// return (value != null) ? value.toStringAsFixed(2) : ""; +// } +// } diff --git a/lib/vital_signs/components/scan_condition.dart b/lib/vital_signs/components/scan_condition.dart index 59fca530..df368a22 100644 --- a/lib/vital_signs/components/scan_condition.dart +++ b/lib/vital_signs/components/scan_condition.dart @@ -25,7 +25,7 @@ class ScanCondition extends StatelessWidget { scanConditionName, style: const TextStyle( fontSize: 14, - color: Colors.white, + color: Colors.black, fontWeight: FontWeight.bold, ), ), diff --git a/lib/vital_signs/components/scan_condition_checklist.dart b/lib/vital_signs/components/scan_condition_checklist.dart index 043430ca..bbc281b5 100644 --- a/lib/vital_signs/components/scan_condition_checklist.dart +++ b/lib/vital_signs/components/scan_condition_checklist.dart @@ -1,3 +1,4 @@ +import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:flutter/material.dart'; import 'package:vital_sign_camera/vital_sign_camera.dart'; import 'scan_condition.dart'; @@ -15,60 +16,71 @@ class ScanConditionChecklist extends StatelessWidget { @override Widget build(BuildContext context) { - return Positioned( - top: deviceSize.height * 0.12, - left: deviceSize.width * 0.05, - child: SizedBox( - width: deviceSize.width * 0.9, - child: Container( - color: Colors.black38, - child: Padding( - padding: const EdgeInsets.all(15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Scanning Conditions", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, + return SizedBox( + height: deviceSize.width*0.35, + child: Material( + color:Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Scanning Conditions", + style: TextStyle( + fontSize: 15, + color: CustomColors.accentColor, + fontWeight: FontWeight.bold, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Row( + children: [ + Expanded( + child: Column( + children: [ + ScanCondition( + scanConditionName: "Lighting", + isConditionSatisfied: conditions.lighting, + ), + ScanCondition( + scanConditionName: "Distance", + isConditionSatisfied: conditions.distance, + ), + ScanCondition( + scanConditionName: "Centered", + isConditionSatisfied: conditions.centered, + ), + ], + ), ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), - child: Column( - children: [ - ScanCondition( - scanConditionName: "Lighting", - isConditionSatisfied: conditions.lighting, - ), - ScanCondition( - scanConditionName: "Distance", - isConditionSatisfied: conditions.distance, - ), - ScanCondition( - scanConditionName: "Centered", - isConditionSatisfied: conditions.centered, - ), - ScanCondition( - scanConditionName: "Movement", - isConditionSatisfied: conditions.movement, - ), - ScanCondition( - scanConditionName: "FrameRate", - isConditionSatisfied: conditions.frameRate, - ), - ScanCondition( - scanConditionName: "Server Ready", - isConditionSatisfied: conditions.serverReady, - ), - ], + + Expanded( + child: Column( + children: [ + ScanCondition( + scanConditionName: "Movement", + isConditionSatisfied: conditions.movement, + ), + ScanCondition( + scanConditionName: "FrameRate", + isConditionSatisfied: conditions.frameRate, + ), + ScanCondition( + scanConditionName: "Server Ready", + isConditionSatisfied: conditions.serverReady, + ), + ], + ), ), - ), - ], + + ], + ), ), - )), + ], + ), + ), ), ); } diff --git a/lib/vital_signs/components/start_button.dart b/lib/vital_signs/components/start_button.dart index 8cf577f5..b0001881 100644 --- a/lib/vital_signs/components/start_button.dart +++ b/lib/vital_signs/components/start_button.dart @@ -1,3 +1,4 @@ +import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:flutter/material.dart'; class StartButton extends StatelessWidget { @@ -13,21 +14,21 @@ class StartButton extends StatelessWidget { @override Widget build(BuildContext context) { return Align( - alignment: Alignment.bottomCenter, - child: Container( - margin: const EdgeInsets.fromLTRB(0, 0, 0, 50), + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.only(right: 16.0, bottom: 32), child: ElevatedButton( onPressed: (disabled) ? () {} : onPressed, style: ElevatedButton.styleFrom( - fixedSize: const Size(100, 100), + fixedSize: const Size(100, 70), shape: const CircleBorder(), - backgroundColor: (disabled) ? Colors.grey : Colors.orangeAccent, + backgroundColor: (disabled) ? Colors.grey : CustomColors.accentColor, elevation: 8, ), child: const Text( "START", style: TextStyle( - fontSize: 16, + fontSize: 14, ), ), ), diff --git a/lib/vital_signs/components/vital_sign_widget.dart b/lib/vital_signs/components/vital_sign_widget.dart index 7174323c..3176fdf2 100644 --- a/lib/vital_signs/components/vital_sign_widget.dart +++ b/lib/vital_signs/components/vital_sign_widget.dart @@ -1,8 +1,15 @@ +import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/vital_signs/data/vitals_benchmark.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; class VitalSignWidget extends StatelessWidget { final String vitalSignName; final String vitalSignValue; + final String vectorUrl; + final RangeConditionWithTitle condition; final Color? textColor; const VitalSignWidget({ @@ -10,32 +17,199 @@ class VitalSignWidget extends StatelessWidget { required this.vitalSignName, required this.vitalSignValue, this.textColor, + required this.condition, + required this.vectorUrl, }) : super(key: key); @override Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.fromLTRB(0, 0, 0, 2), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - vitalSignName, - style: TextStyle( - fontSize: 14, - color: textColor ?? Colors.white, - ), - ), - Text( - vitalSignValue, - style: TextStyle( - fontSize: 14, - color: textColor ?? Colors.white, - fontWeight: FontWeight.bold, - ), + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + color: Colors.white, + elevation: 2, + shadowColor: CustomColors.lightGreyColor, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + SvgPicture.asset(vectorUrl, width: 36.0, height: 36.0), + SizedBox( + width: 16, + ), + Text( + vitalSignName, + textAlign: TextAlign.start, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: textColor ?? Colors.white, + ), + ), + ], + ), + SizedBox( + height: 8, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "$vitalSignValue ${condition.unit}", + style: TextStyle( + fontSize: 14, + color: textColor ?? Colors.white, + fontWeight: FontWeight.w500, + ), + ), + SizedBox( + width: 8, + ), + + Status( + status: + "${TranslationBase.of(context).getValue(condition.current?.quantitativeInterpretation ?? '')}") + // Text( + // "${TranslationBase.of(context).getValue(condition.current?.quantitativeInterpretation ?? '')}", + // style: TextStyle( + // fontSize: 14, + // color: textColor ?? Colors.white, + // fontWeight: FontWeight.w500, + // ), + // ), + ], + ), + SizedBox( + height: 8, + ), + SizedBox( + height: 32, + child: Row(mainAxisSize: MainAxisSize.max, children: [ + Expanded( + flex: 1, + child: ListView.separated( + separatorBuilder: (_, __) => SizedBox( + width: 8, + ), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemCount: condition.condition?.length ?? 0, + itemBuilder: (_, index) => RangeWidget( + title: condition.condition?[index].title ?? 'test', + isSelected: condition.condition?[index] + .isInRange(vitalSignValue) == + true, + ), + ), + ), + ]), + ), + SizedBox( + height: 8, + ), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text( + // TranslationBase.of(context).getValue( + // condition.condition?.first.interpretation ?? ''), + // style: TextStyle( + // fontSize: 14, + // color: textColor ?? Colors.white, + // fontWeight: FontWeight.w500, + // ), + // ), + // Text( + // TranslationBase.of(context).getValue( + // condition.condition?.last.interpretation ?? ''), + // style: TextStyle( + // fontSize: 14, + // color: textColor ?? Colors.white, + // fontWeight: FontWeight.w500, + // ), + // ), + // ], + // ), + // SizedBox( + // height: 8, + // ), + ]), + ), + ); + } +} + +class RangeWidget extends StatelessWidget { + final String title; + final bool isSelected; + + const RangeWidget({super.key, required this.title, required this.isSelected}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 23, + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(3), + ), + // color: Color(0xFF359846), + color: (isSelected) + ? CustomColors.accentColor + : CustomColors.lightGreyColor, + child: Padding( + padding: EdgeInsets.all(8), + child: Text( + title, + textAlign: TextAlign.center, + style: + TextStyle(color: (isSelected) ? Colors.white : Colors.black), ), - ], + ), ), ); } } + +class Status extends StatelessWidget { + final String status; + + const Status({super.key, required this.status}); + + @override + Widget build(BuildContext context) { + return Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(3), + ), + // color: Color(0xFF359846), + color: (status.toLowerCase() == 'good' || + status.toLowerCase() == 'excellent' || + status.toLowerCase() == 'normal') + ? Color(0xFFD8E8DB) + : (status.toLowerCase() == 'poor' || status.toLowerCase() == 'low') + ? Color(0xFFD3D37E) + : Color(0x98d02127), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + child: Text(status, + style: TextStyle( + color: (status.toLowerCase() == 'good' || + status.toLowerCase() == 'excellent' || + status.toLowerCase() == 'normal') + ? Color(0xFF359846) + : (status.toLowerCase() == 'poor' || + status.toLowerCase() == 'low') + ? Colors.white + : Colors.white, + fontSize: 8, + fontWeight: FontWeight.w600, + )), + )); + } +} diff --git a/lib/vital_signs/data/vitals_benchmark.dart b/lib/vital_signs/data/vitals_benchmark.dart new file mode 100644 index 00000000..6279a4e8 --- /dev/null +++ b/lib/vital_signs/data/vitals_benchmark.dart @@ -0,0 +1,354 @@ +var vital = { + "HR": { + "unit": "bpm", + "values": [ + { + "min": 0, + "max": 60, + "interpretation": "atRisk", + "quantitativeInterpretation": "low", + "title": "< 60" + }, + { + "min": 80, + "max": 100, + "interpretation": "poor", + "quantitativeInterpretation": "normal", + "title": "80-100" + }, + { + "min": 60, + "max": 80, + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "60-80" + }, + { + "min": 100, + "max": 0, + "interpretation": "atRisk", + "quantitativeInterpretation": "high", + "title": "≥ 100" + }, + + ] + },"hrvv": { + "unit": "bpm", + "values":[ + { + "min": 0, + "max": 10.8, + "interpretation": "atRisk", + "quantitativeInterpretation": "low", + "title": "< 10.8" + }, + { + "min": 10.8, + "max": 16.4, + "interpretation": "poor", + "quantitativeInterpretation": "low", + "title": "10.8-16.4" + }, + { + "min": 16.4, + "max": 35.0, + "interpretation": "poor", + "quantitativeInterpretation": "low", + "title": "16.4-35.0" + }, + { + "min": 35.0, + "max": 51.5, + "interpretation": "good", + "quantitativeInterpretation": "normal", + "title": "35.0-51.5" + }, + { + "min": 51.5, + "max": 0, + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "≥ 51.5" + } + ] + }, + "Sp02": { + "unit": "%", + "values": [ + { + "min": 0, + "max": 90, + "interpretation": "atRisk", + "quantitativeInterpretation": "low", + "title": "≥ 90" + }, + { + "min": 90, + "max": 95, + "interpretation": "poor", + "quantitativeInterpretation": "possiblyLow", + "title": "90-95" + }, + { + "min": 95, + "max": 97, + "interpretation": "good", + "quantitativeInterpretation": "normal", + "title": "95-97" + }, + { + "min": 97, + "max": 100, + "interpretation": "good", + "quantitativeInterpretation": "normal", + "isMaxIncluded": true, + "title": "97-100" + } + ] + }, + "blood_pressure": { + "unit": "mmHg", + "values": [ + { + "min": 0, + "max": (90 / 60), + "interpretation": "atRisk", + "quantitativeInterpretation": "low", + "title": "< 90/60" + }, + { + "min": (90 / 60), + "max": (120 / 70), + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "90/60 - 120/70" + }, + { + "min": (120 / 70), + "max": (130 / 80), + "interpretation": "good", + "quantitativeInterpretation": "normal", + "title": "120/70 - 130/80" + }, + { + "min": (130 / 80), + "max": (140 / 90), + "interpretation": "poor", + "quantitativeInterpretation": "slightlyHigh", + "title": "130/80-140/90" + }, + { + "min": (140 / 90), + "max": 0, + "interpretation": "atRisk", + "quantitativeInterpretation": "high", + "title": "≥ 140/90" + } + ] + }, + "bmi": { + "unit": "", + "values": [ + { + "min": 0, + "max": 18.5, + "interpretation": "poor", + "quantitativeInterpretation": "normal", + "title": "< 18.5" + }, + { + "min": 18.5, + "max": 25, + "interpretation": "poor", + "quantitativeInterpretation": "normal", + "title": "25-30" + },{ + "min": 25, + "max": 30, + "interpretation": "poor", + "quantitativeInterpretation": "normal", + "title": "25-30" + }, + { + "min": 30, + "max": 40, + "interpretation": "atRisk", + "quantitativeInterpretation": "high", + "title": "30-40" + }, + { + "min": 40, + "max": 0, + "interpretation": "atRisk", + "quantitativeInterpretation": "high", + "title": "≥40" + }, + ] + }, + "respiratoryRate": { + "unit": "bpm", + "values": [ + { + "min": 0, + "max": 12, + "interpretation": "poor", + "quantitativeInterpretation": "low", + "title": "< 12" + }, + { + "min": 12, + "max": 20, + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "25-30" + }, + { + "min": 20, + "max": 0, + "interpretation": "poor", + "quantitativeInterpretation": "high", + "title": "≥ 20" + }, + ] + }, + "cvd": { + "unit": "%", + "values": [ + { + "min": 0, + "max": 1, + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "< 1" + }, + { + "min": 1, + "max": 10, + "interpretation": "Average", + "quantitativeInterpretation": "slightlyHigh", + "title": "1-10" + }, + { + "min": 10, + "max": 20, + "interpretation": "poor", + "quantitativeInterpretation": "moderatelyHigh", + "title": "10-20" + }, + { + "min": 20, + "max": 0, + "interpretation": "atRisk", + "quantitativeInterpretation": " high", + "title": "≥ 20" + }, + ] + }, + "generalWellness": { + "unit": "", + "values": [ + { + "min": 0, + "max": 40, + "interpretation": "poor", + "quantitativeInterpretation": "low", + "title": "< 40" + }, + { + "min": 40, + "max": 80, + "interpretation": "good", + "quantitativeInterpretation": "normal", + "title": "40-80" + }, + { + "min": 80, + "max": 100, + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "80-100", + "isMaxIncluded": true + }, + ] + }, + "stressLevel": { + "unit": "", + "values": [ + { + "min": 0, + "max": 2, + "interpretation": "excellent", + "quantitativeInterpretation": "normal", + "title": "0-2" + }, + { + "min": 2, + "max": 3, + "interpretation": "good", + "quantitativeInterpretation": "normal", + "title": "2-3" + }, + { + "min": 3, + "max": 0, + "interpretation": "poor", + "quantitativeInterpretation": "high", + "title": "80-100", + }, + ] + }, +}; + +class RangeConditionWithTitle { + String? unit; + List? condition; + + RangeCondition? current; + RangeConditionWithTitle({this.unit, this.condition}); + + RangeConditionWithTitle.fromJson(Map json, String formatValueToTwoDp) { + this.unit = json['unit']; + var conditions = json['values'] as List?; + this.condition = + conditions?.map((item) => RangeCondition.fromJson(item,formatValueToTwoDp)).toList(); + print("the value is $formatValueToTwoDp"); + current = condition?.where((element)=>element.isSelected == true).first; + } +} + +class RangeCondition { + double? min; + double? max; + bool? isMaxIncluded; + String? interpretation; + String? quantitativeInterpretation; + String? title; + bool? isSelected; + + RangeCondition(this.min, this.max, this.interpretation, + this.quantitativeInterpretation, this.isMaxIncluded); + + RangeCondition.fromJson(Map json, String selectedValue) { + min = json['min'].toDouble(); + max = json['max'].toDouble(); + interpretation = json['interpretation']; + quantitativeInterpretation = json['quantitativeInterpretation']; + isMaxIncluded = json['isMaxIncluded']; + title = json['title']; + isSelected = isInRange(selectedValue); + } + + bool isInRange(String data) { + + double value = 0.0; + if(data.contains('/')){ + value = double.parse(data.split("/")[0])/double.parse(data.split("/")[1]); + }else{ + value = double.parse(data); + } + if (max == 0 && min != 0) return value >= min!; + if (min == 0 && max != 0) return value < max!; + if (isMaxIncluded == true) return value >= min! && value <= max!; + return value >= min! && value < max!; + } +} diff --git a/lib/vital_signs/result_screen.dart b/lib/vital_signs/result_screen.dart index 2a101e06..bcbb7d27 100644 --- a/lib/vital_signs/result_screen.dart +++ b/lib/vital_signs/result_screen.dart @@ -1,3 +1,6 @@ +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/vital_signs/data/vitals_benchmark.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; import 'package:vital_sign_camera/vital_sign_camera.dart'; @@ -28,237 +31,288 @@ class ResultScreen extends StatelessWidget { final deviceSize = MediaQuery.of(context).size; const textColor = Color.fromARGB(255, 0, 0, 0); - return Scaffold( - appBar: AppBar( - title: const Text('Result'), - ), - body: SingleChildScrollView( - child: Center( - child: SizedBox( - width: deviceSize.width * 0.9, - child: Container( - color: const Color.fromARGB(0, 255, 255, 255), - child: Padding( - padding: const EdgeInsets.all(15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: const EdgeInsets.fromLTRB(0, 0, 0, 10), - child: const Text( - "Vital Signs", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), + print('the age is ${healthResult?.vitalSigns?.facialSkinAge}'); + return AppScaffold( + isShowAppBar: true, + appBarTitle: TranslationBase.of(context).result, + showNewAppBar: true, + showNewAppBarTitle: true, + overrideUserLogin: true, + backgroundColor: Color(0xffF8F8F8), + body: Padding( + padding: const EdgeInsets.all(15), + child: ListView( + shrinkWrap: true, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_holisticAnalysis != null && + _holisticAnalysis?.generalWellness != null) VitalSignWidget( - textColor: textColor, - vitalSignName: "Heart Rate", - vitalSignValue: formatValueToTwoDp( + textColor: textColor, + vitalSignName: + TranslationBase.of(context).generalWellness, + condition: RangeConditionWithTitle.fromJson( + vital['generalWellness']!, + formatValueToTwoDp( + healthResult?.holisticHealth?.generalWellness)), + vitalSignValue: formatValueToTwoDp( + healthResult?.holisticHealth?.generalWellness), + vectorUrl: 'assets/images/svg/wellness.svg', + ),//wellness + if (_vitalSign?.stress != null) + VitalSignWidget( + textColor: textColor, + vitalSignName: TranslationBase.of(context).stress, + condition: RangeConditionWithTitle.fromJson( + vital['stressLevel']!, + formatValueToTwoDp( + healthResult?.vitalSigns.stress)), + vitalSignValue: + formatValueToTwoDp(healthResult?.vitalSigns.stress), + vectorUrl: 'assets/images/svg/stress.svg', + ), + VitalSignWidget( + textColor: textColor, + vitalSignName: TranslationBase.of(context).pulseTitle, + condition: RangeConditionWithTitle.fromJson( + vital['HR']!, + formatValueToTwoDp( healthResult?.vitalSigns.heartRate)), + vitalSignValue: formatValueToTwoDp( + healthResult?.vitalSigns.heartRate), + vectorUrl: 'assets/images/svg/heartrate.svg', + ), + //heart rate + if (_vitalSign?.bloodPressure != null) + VitalSignWidget( + textColor: textColor, + vitalSignName: "Blood Pressure", + condition: RangeConditionWithTitle.fromJson( + vital['blood_pressure']!, + healthResult?.vitalSigns.bloodPressure ?? ""), + vitalSignValue: + healthResult?.vitalSigns.bloodPressure ?? "", + vectorUrl: 'assets/images/svg/bloodpressure.svg', + ), + if (_vitalSign?.hrvSdnn != null) VitalSignWidget( + vectorUrl: 'assets/images/svg/heartrate.svg', textColor: textColor, - vitalSignName: "SPO2", + vitalSignName: "HRV SDNN", + condition: RangeConditionWithTitle.fromJson( + vital['hrvv']!, + formatValueToTwoDp( + healthResult?.vitalSigns.hrvSdnn)), vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.spo2)), + healthResult?.vitalSigns.hrvSdnn)), + + //oxygen + VitalSignWidget( + textColor: textColor, + vitalSignName: + TranslationBase.of(context).oxygenSaturation, + condition: RangeConditionWithTitle.fromJson( + vital['Sp02']!, + formatValueToTwoDp(healthResult?.vitalSigns.spo2)), + vitalSignValue: + formatValueToTwoDp(healthResult?.vitalSigns.spo2), + vectorUrl: 'assets/images/svg/oxygen.svg', + ), + if (_vitalSign?.respiratoryRate != null) VitalSignWidget( - textColor: textColor, - vitalSignName: "IBI", - vitalSignValue: - formatValueToTwoDp(healthResult?.vitalSigns.ibi)), - if (_vitalSign?.stress != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Stress", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.stress)), - if (_vitalSign?.respiratoryRate != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Respiratory Rate", - vitalSignValue: formatValueToTwoDp( + textColor: textColor, + vitalSignName: + TranslationBase.of(context).respiratoryRate, + condition: RangeConditionWithTitle.fromJson( + vital['respiratoryRate']!, + formatValueToTwoDp( healthResult?.vitalSigns.respiratoryRate)), - if (_vitalSign?.hrvRmssd != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "HRV RMSSD", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.hrvRmssd)), - if (_vitalSign?.hrvSdnn != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "HRV SDNN", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.hrvSdnn)), - if (_vitalSign?.temperature != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Temperature", - vitalSignValue: formatValueToTwoDp( - healthResult?.vitalSigns.temperature)), - if (_vitalSign?.bloodPressure != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Blood Pressure", - vitalSignValue: - healthResult?.vitalSigns.bloodPressure ?? ""), - if (_vitalSign?.bloodPressureSystolic != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Blood Pressure Systolic", - vitalSignValue: formatValueToTwoDp(healthResult - ?.vitalSigns.bloodPressureSystolic)), - if (_vitalSign?.bloodPressureDiastolic != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Blood Pressure Diastolic", - vitalSignValue: formatValueToTwoDp(healthResult - ?.vitalSigns.bloodPressureDiastolic)), - if (_holisticAnalysis != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Holistic Analysis", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_holisticAnalysis != null && - _holisticAnalysis?.bmi != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "BMI", - vitalSignValue: formatValueToTwoDp( + vitalSignValue: formatValueToTwoDp( + healthResult?.vitalSigns.respiratoryRate), + vectorUrl: 'assets/images/svg/breathing.svg', + ), + if (_holisticAnalysis != null && + _holisticAnalysis?.bmi != null) + VitalSignWidget( + textColor: textColor, + vitalSignName: TranslationBase.of(context).BMI, + condition: RangeConditionWithTitle.fromJson( + vital['bmi']!, + formatValueToTwoDp( healthResult?.holisticHealth?.bmi)), - if (_holisticAnalysis != null && - _holisticAnalysis?.generalWellness != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "General Wellness", - vitalSignValue: formatValueToTwoDp( - healthResult?.holisticHealth?.generalWellness)), - if (_holisticAnalysis != null && - _holisticAnalysis?.absi != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "ABSI", - vitalSignValue: formatValueToTwoDp( - healthResult?.holisticHealth?.absi)), - if (_holisticAnalysis != null && - _holisticAnalysis?.cardiacWorkload != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Cardiac Workload", - vitalSignValue: formatValueToTwoDp( - healthResult?.holisticHealth?.cardiacWorkload)), - if (_holisticAnalysis != null && - _holisticAnalysis?.pulseRespiratoryQuotient != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Pulse Respiratory Quotient", - vitalSignValue: formatValueToTwoDp(healthResult - ?.holisticHealth?.pulseRespiratoryQuotient)), - if (_holisticAnalysis != null && - _holisticAnalysis?.waistToHeightRatio != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Waist to Height Ratio", - vitalSignValue: formatValueToTwoDp(healthResult - ?.holisticHealth?.waistToHeightRatio)), - if (_cardiovascularRisks != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Cardiovascular Risks", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_cardiovascularRisks != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "General", - vitalSignValue: formatValueToTwoDp(healthResult - ?.risks?.cardiovascularRisks?.generalRisk)), - if (_cardiovascularRisks != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Congestive Heart Failure", - vitalSignValue: formatValueToTwoDp(healthResult - ?.risks - ?.cardiovascularRisks - ?.congestiveHeartFailure)), - if (_cardiovascularRisks != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Coronary Heart Disease", - vitalSignValue: formatValueToTwoDp(healthResult - ?.risks - ?.cardiovascularRisks - ?.coronaryHeartDisease)), - if (_cardiovascularRisks != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Intermittent Claudication", - vitalSignValue: formatValueToTwoDp(healthResult - ?.risks - ?.cardiovascularRisks - ?.intermittentClaudication)), - if (_cardiovascularRisks != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Stroke", - vitalSignValue: formatValueToTwoDp(healthResult - ?.risks?.cardiovascularRisks?.stroke)), - if (_covidRisk != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Covid Risks", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_covidRisk != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Risk", - vitalSignValue: formatValueToTwoDp( - healthResult?.risks?.covidRisk?.covidRisk)), - if (_scanParameters != null) - Container( - margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), - child: const Text( - "Scan Parameters", - style: TextStyle( - fontSize: 15, - color: Colors.amber, - fontWeight: FontWeight.bold, - ), - ), - ), - if (_scanParameters != null) - VitalSignWidget( - textColor: textColor, - vitalSignName: "Signal Quality", - vitalSignValue: formatValueToTwoDp( - healthResult?.scanParameters?.signalQuality)), - ]), - ), + vitalSignValue: formatValueToTwoDp( + healthResult?.holisticHealth?.bmi), + vectorUrl: 'assets/images/svg/bmi.svg', + ), + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "IBI", + // condition: RangeConditionWithTitle.fromJson(vital['HR']!), + // vitalSignValue: + // formatValueToTwoDp(healthResult?.vitalSigns.ibi)), + + + // if (_vitalSign?.hrvRmssd != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "HRV RMSSD", + // vitalSignValue: formatValueToTwoDp( + // healthResult?.vitalSigns.hrvRmssd)), + + // if (_vitalSign?.temperature != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Temperature", + // vitalSignValue: formatValueToTwoDp( + // healthResult?.vitalSigns.temperature)), + + // if (_vitalSign?.bloodPressureSystolic != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Blood Pressure Systolic", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.vitalSigns.bloodPressureSystolic)), + // if (_vitalSign?.bloodPressureDiastolic != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Blood Pressure Diastolic", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.vitalSigns.bloodPressureDiastolic)), + // if (_holisticAnalysis != null) + // Container( + // margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), + // child: const Text( + // "Holistic Analysis", + // style: TextStyle( + // fontSize: 15, + // color: Colors.amber, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + + + // if (_holisticAnalysis != null && + // _holisticAnalysis?.absi != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "ABSI", + // vitalSignValue: formatValueToTwoDp( + // healthResult?.holisticHealth?.absi)), + // if (_holisticAnalysis != null && + // _holisticAnalysis?.cardiacWorkload != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Cardiac Workload", + // vitalSignValue: formatValueToTwoDp( + // healthResult?.holisticHealth?.cardiacWorkload)), + // if (_holisticAnalysis != null && + // _holisticAnalysis?.pulseRespiratoryQuotient != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Pulse Respiratory Quotient", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.holisticHealth?.pulseRespiratoryQuotient)), + // if (_holisticAnalysis != null && + // _holisticAnalysis?.waistToHeightRatio != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Waist to Height Ratio", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.holisticHealth?.waistToHeightRatio)), + // if (_cardiovascularRisks != null) + // Container( + // margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), + // child: const Text( + // "Cardiovascular Risks", + // style: TextStyle( + // fontSize: 15, + // color: Colors.amber, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // if (_cardiovascularRisks != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: TranslationBase.of(context).cvd, + // condition: RangeConditionWithTitle.fromJson(vital['cvd']!, formatValueToTwoDp(healthResult + // ?.risks?.cardiovascularRisks?.generalRisk)), + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.risks?.cardiovascularRisks?.generalRisk), + // vectorUrl: 'assets/images/svg/heartrate.svg',), + // if (_cardiovascularRisks != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Congestive Heart Failure", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.risks + // ?.cardiovascularRisks + // ?.congestiveHeartFailure)), + // if (_cardiovascularRisks != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Coronary Heart Disease", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.risks + // ?.cardiovascularRisks + // ?.coronaryHeartDisease)), + // if (_cardiovascularRisks != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Intermittent Claudication", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.risks + // ?.cardiovascularRisks + // ?.intermittentClaudication)), + // if (_cardiovascularRisks != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Stroke", + // vitalSignValue: formatValueToTwoDp(healthResult + // ?.risks?.cardiovascularRisks?.stroke)), + // if (_covidRisk != null) + // Container( + // margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), + // child: const Text( + // "Covid Risks", + // style: TextStyle( + // fontSize: 15, + // color: Colors.amber, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // if (_covidRisk != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Risk", + // vitalSignValue: formatValueToTwoDp( + // healthResult?.risks?.covidRisk?.covidRisk)), + // if (_scanParameters != null) + // Container( + // margin: const EdgeInsets.fromLTRB(0, 25, 0, 10), + // child: const Text( + // "Scan Parameters", + // style: TextStyle( + // fontSize: 15, + // color: Colors.amber, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // if (_scanParameters != null) + // VitalSignWidget( + // textColor: textColor, + // vitalSignName: "Signal Quality", + // vitalSignValue: formatValueToTwoDp( + // healthResult?.scanParameters?.signalQuality)), + ]), ), - ), + ], ), ), ); diff --git a/lib/vital_signs/vital_sign.dart b/lib/vital_signs/vital_sign.dart index 243ee2fe..e297bd59 100644 --- a/lib/vital_signs/vital_sign.dart +++ b/lib/vital_signs/vital_sign.dart @@ -1,7 +1,9 @@ +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; import 'package:vital_sign_camera/vital_sign_camera.dart'; // import 'package:wakelock/wakelock.dart'; +import '../uitl/translations_delegate_base.dart'; import 'components/bounding_box_widget.dart'; import 'components/error.dart'; import 'components/scan_condition_checklist.dart'; @@ -95,83 +97,133 @@ class _VitalSignsState extends State with RouteAware { @override Widget build(BuildContext context) { final deviceSize = MediaQuery.of(context).size; - - return Scaffold( - body: Stack( + return AppScaffold( + isShowAppBar: true, + appBarTitle: TranslationBase.of(context).scanning, + showNewAppBar: true, + showNewAppBarTitle: true, + overrideUserLogin: true, + backgroundColor: Color(0xffF8F8F8), + body: Column( children: [ - VitalSignCamera( - onCreated: _onVitalSignCameraCreated, - isActive: isCameraActive, - userInfo: userInfo, - config: config, - device: cameraDevice, - onVideoFrameProcessed: _onVideoFrameProcessed), - // A back button to navigate back to previous screen - if (_scanningStage == GetHealthStage.idle && !startedScanning) - BackHomeButton( - onPressed: () { - setState(() { - isCameraActive = false; - }); - Navigator.pop(context); - }, - deviceSize: deviceSize), - // A button to toggle isCameraActive - if (_scanningStage == GetHealthStage.idle && !startedScanning) - Button( - onPressed: () { - setState(() { - isCameraActive = !isCameraActive; - }); - }, - deviceSize: deviceSize, - title: "Toggle isCameraActive", - alignment: Alignment.topRight, - margin: EdgeInsets.fromLTRB( - 0, deviceSize.height * 0.05, deviceSize.width * 0.05, 0)), - if (!isCameraActive) - const Center( - child: Text( - "Camera is not active.", - textAlign: TextAlign.center, - )) - else - Stack(children: [ - if (_scanningStage == GetHealthStage.idle && - isCameraActive) // show start button only when it is not scanning - StartButton( - onPressed: () { - setState(() { - _vitalSignCameraController.startScanning(); - startedScanning = true; - _healthResult = null; - _showedHealthResult = false; - }); - }, - disabled: !isAllConditionsMet, + if (_conditions != null) + ScanConditionChecklist( + deviceSize: deviceSize, conditions: _conditions!), + Expanded( + child: Stack( + children: [ + VitalSignCamera( + onCreated: _onVitalSignCameraCreated, + isActive: isCameraActive, + userInfo: userInfo, + config: config, + device: cameraDevice, + onVideoFrameProcessed: _onVideoFrameProcessed), + Positioned.fill( + child: CustomPaint( + painter: OvalOverlayPainter(), + ), ), - if (_conditions != null && - _scanningStage == GetHealthStage.idle && - !startedScanning) // show scan conditions checking only when it is not scanning or showing health result - ScanConditionChecklist( - deviceSize: deviceSize, conditions: _conditions!), - if (_scanningStage != - GetHealthStage - .idle) // show remaining time count down during scan - ScanStatus( - stage: _scanningStage, remainingTime: _remainingTime), - if (!startedScanning || - _healthResult == - null) // show bounding box before and during scan, but not when health result is shown - BoundingBoxWidget( - deviceSize: deviceSize, - facebox: _normalizedFaceBox, - videoFrameInfo: _videoFrameInfo), - if (_error != null) Error(error: _error, errorCode: _errorCode), - ]) + if (_scanningStage != + GetHealthStage + .idle) // show remaining time count down during scan + ScanStatus( + stage: _scanningStage, remainingTime: _remainingTime), + if (_scanningStage == GetHealthStage.idle && + isCameraActive) // show start button only when it is not scanning + StartButton( + onPressed: () { + setState(() { + _vitalSignCameraController.startScanning(); + startedScanning = true; + _healthResult = null; + _showedHealthResult = false; + }); + }, + disabled: !isAllConditionsMet, + ), + ], + ), + ), ], ), ); + // return Scaffold( + // body: Stack( + // children: [ + // VitalSignCamera( + // onCreated: _onVitalSignCameraCreated, + // isActive: isCameraActive, + // userInfo: userInfo, + // config: config, + // device: cameraDevice, + // onVideoFrameProcessed: _onVideoFrameProcessed), + // // A back button to navigate back to previous screen + // if (_scanningStage == GetHealthStage.idle && !startedScanning) + // BackHomeButton( + // onPressed: () { + // setState(() { + // isCameraActive = false; + // }); + // Navigator.pop(context); + // }, + // deviceSize: deviceSize), + // // A button to toggle isCameraActive + // if (_scanningStage == GetHealthStage.idle && !startedScanning) + // Button( + // onPressed: () { + // setState(() { + // isCameraActive = !isCameraActive; + // }); + // }, + // deviceSize: deviceSize, + // title: "Toggle isCameraActive", + // alignment: Alignment.topRight, + // margin: EdgeInsets.fromLTRB( + // 0, deviceSize.height * 0.05, deviceSize.width * 0.05, 0)), + // if (!isCameraActive) + // const Center( + // child: Text( + // "Camera is not active.", + // textAlign: TextAlign.center, + // )) + // else + // Stack(children: [ + // if (_scanningStage == GetHealthStage.idle && + // isCameraActive) // show start button only when it is not scanning + // StartButton( + // onPressed: () { + // setState(() { + // _vitalSignCameraController.startScanning(); + // startedScanning = true; + // _healthResult = null; + // _showedHealthResult = false; + // }); + // }, + // disabled: !isAllConditionsMet, + // ), + // if (_conditions != null && + // _scanningStage == GetHealthStage.idle && + // !startedScanning) // show scan conditions checking only when it is not scanning or showing health result + // ScanConditionChecklist( + // deviceSize: deviceSize, conditions: _conditions!), + // if (_scanningStage != + // GetHealthStage + // .idle) // show remaining time count down during scan + // ScanStatus( + // stage: _scanningStage, remainingTime: _remainingTime), + // if (!startedScanning || + // _healthResult == + // null) // show bounding box before and during scan, but not when health result is shown + // BoundingBoxWidget( + // deviceSize: deviceSize, + // facebox: _normalizedFaceBox, + // videoFrameInfo: _videoFrameInfo), + // if (_error != null) Error(error: _error, errorCode: _errorCode), + // ]) + // ], + // ), + // ); } void _onVideoFrameProcessed(VideoFrameProcessedEvent event) { @@ -221,8 +273,39 @@ class _VitalSignsState extends State with RouteAware { } } - // load default void _onVitalSignCameraCreated(VitalSignCameraController controller) { _vitalSignCameraController = controller; } } + +class OvalOverlayPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Paint overlayPaint = Paint() + ..color = Colors.white.withOpacity(0.7) + ..style = PaintingStyle.fill; + + canvas.drawRect( + Rect.fromLTWH(0, 0, size.width, size.height), + overlayPaint, + ); + + final Rect ovalRect = Rect.fromCenter( + center: Offset(size.width / 2, size.height / 2), + width: size.width * 0.9, + height: size.height * 0.7, + ); + final Path ovalPath = Path()..addOval(ovalRect); + + canvas.clipPath(ovalPath, doAntiAlias: true); + canvas.drawRect( + Rect.fromLTWH(0, 0, size.width, size.height), + Paint()..blendMode = BlendMode.clear, + ); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} \ No newline at end of file diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index 1103b31b..214359f6 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -83,6 +83,7 @@ class AppScaffold extends StatefulWidget { final int? currentTab; final bool isShowPharmacyAppbar; final Widget? customAppBar; + final bool overrideUserLogin; AppScaffold setOnAppBarCartClick(VoidCallback onClick) { _onCartClick = onClick; @@ -130,7 +131,8 @@ class AppScaffold extends StatefulWidget { this.backButtonTab, this.changeCurrentTab, this.currentTab, - this.isShowPharmacyAppbar = false}); + this.isShowPharmacyAppbar = false, + this.overrideUserLogin= false}); @override _AppScaffoldState createState() => _AppScaffoldState(); @@ -216,7 +218,7 @@ class _AppScaffoldState extends State { AppGlobal.context = context; PharmacyPagesViewModel pagesViewModel = Provider.of(context); - bool isUserNotLogin = (!Provider.of(context, listen: false).isLogin && widget.isShowDecPage); + bool isUserNotLogin = (widget.overrideUserLogin)?false:(!Provider.of(context, listen: false).isLogin && widget.isShowDecPage); return Scaffold( backgroundColor: widget.backgroundColor ?? CustomColors.appBackgroudGrey2Color,