From 8424e92c4b6cc457d8585a562e324730545092ff Mon Sep 17 00:00:00 2001 From: mosazaid Date: Thu, 14 Jan 2021 16:25:00 +0200 Subject: [PATCH] working on vital Sign feature with Charts --- lib/config/localized_values.dart | 8 + .../patient-vital-sign-viewmodel.dart | 36 -- lib/lookups/patient_lookup.dart | 17 +- .../vital_sign/patient-vital-sign-data.dart | 349 +++++++++----- lib/routes.dart | 2 +- .../profile/vital_sign/LineChartCurved.dart | 217 +++++++++ .../LineChartCurvedBloodPressure.dart | 257 ++++++++++ .../vital_sign/vital-signs-screen.dart | 8 +- ...al_sign_details_blood_pressurewideget.dart | 145 ++++++ .../vital_sign/vital_sign_details_screen.dart | 442 ++++++++---------- .../vital_sign_details_wideget.dart | 121 +++++ .../profile/vital_sign/vital_sign_item.dart | 101 ++-- .../vital_sign_item_details_screen.dart | 196 +++++++- .../vital_sing_chart_and_detials.dart | 51 +- .../vital_sing_chart_blood_pressure.dart | 84 ++++ lib/util/date-utils.dart | 133 ++++++ lib/util/translations_delegate_base.dart | 3 + lib/widgets/charts/app_bar_chart.dart | 43 ++ lib/widgets/charts/app_line_chart.dart | 44 ++ lib/widgets/charts/app_time_series_chart.dart | 71 +++ .../data_display/list/custom_Item.dart | 93 ++++ .../data_display/list/flexible_container.dart | 50 ++ .../profile/profile_medical_info_widget.dart | 3 +- lib/widgets/transitions/fade_page.dart | 32 ++ lib/widgets/transitions/slide_up_page.dart | 43 ++ pubspec.lock | 48 +- pubspec.yaml | 3 + 27 files changed, 2115 insertions(+), 485 deletions(-) create mode 100644 lib/screens/patients/profile/vital_sign/LineChartCurved.dart create mode 100644 lib/screens/patients/profile/vital_sign/LineChartCurvedBloodPressure.dart create mode 100644 lib/screens/patients/profile/vital_sign/vital_sign_details_blood_pressurewideget.dart create mode 100644 lib/screens/patients/profile/vital_sign/vital_sign_details_wideget.dart create mode 100644 lib/screens/patients/profile/vital_sign/vital_sing_chart_blood_pressure.dart create mode 100644 lib/widgets/charts/app_bar_chart.dart create mode 100644 lib/widgets/charts/app_line_chart.dart create mode 100644 lib/widgets/charts/app_time_series_chart.dart create mode 100644 lib/widgets/data_display/list/custom_Item.dart create mode 100644 lib/widgets/data_display/list/flexible_container.dart create mode 100644 lib/widgets/transitions/fade_page.dart create mode 100644 lib/widgets/transitions/slide_up_page.dart diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 030f42cc..9df06621 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -546,4 +546,12 @@ const Map> localizedValues = { 'en': "There is no detail for this patient", 'ar': "لا توجد تفاصيل لهذا المريض" }, + "systolic-lng": { + "en": "Systolic", + "ar": "الإنقباض" + }, + "diastolic-lng": { + "en": "Diastolic", + "ar": "الإنبساط" + }, }; diff --git a/lib/core/viewModel/patient-vital-sign-viewmodel.dart b/lib/core/viewModel/patient-vital-sign-viewmodel.dart index 5674030c..b4a49a86 100644 --- a/lib/core/viewModel/patient-vital-sign-viewmodel.dart +++ b/lib/core/viewModel/patient-vital-sign-viewmodel.dart @@ -27,42 +27,6 @@ class VitalSignsViewModel extends BaseViewModel { } } - makeVitalSignDemoData(){ - _vitalSignService.patientVitalSigns = VitalSignData( - appointmentNo: 2016053265, - bloodPressureCuffLocation: 0, - bloodPressureCuffSize: 0, - bloodPressureHigher: 38, - bloodPressureLower: 32, - bloodPressurePatientPosition: 1, - bodyMassIndex: 31.11, - fio2: 0, - headCircumCm: 0, - heightCm: 150, - idealBodyWeightLbs: -2, - isPainManagementDone: false, - isVitalsRequired: true, - leanBodyWeightLbs: 0, - painCharacter: null, - painDuration: null, - painFrequency: null, - painLocation: null, - painScore: 0, - patientMRN: 3333274, - patientType: 1, - pulseBeatPerMinute: 0, - pulseRhythm: 0, - respirationBeatPerMinute: 0, - respirationPattern: 0, - sao2: 0, - status: 47, - temperatureCelcius: 40, - temperatureCelciusMethod: 1, - waistSizeInch: 39, - weightKg: 70, - ); - } - String getBMI(var bodyMassIndex) { if (bodyMassIndex <= 18.5) { return "Underweight"; diff --git a/lib/lookups/patient_lookup.dart b/lib/lookups/patient_lookup.dart index dfcaa305..fa75abaa 100644 --- a/lib/lookups/patient_lookup.dart +++ b/lib/lookups/patient_lookup.dart @@ -27,11 +27,14 @@ const LOCATIONS = const [ ]; enum vitalSignDetails { - bodyMeasurements, - temperature, - pulse, - pespiration, - bloodPressure, - oxygenation, - painScale + BodyMeasurements, + Temperature, + Pulse, + Prescriptions, + BloodPressure, + Respiration, + heart, + PainScale, + Weight, + Height } diff --git a/lib/models/patient/vital_sign/patient-vital-sign-data.dart b/lib/models/patient/vital_sign/patient-vital-sign-data.dart index c5e503c2..10259fdc 100644 --- a/lib/models/patient/vital_sign/patient-vital-sign-data.dart +++ b/lib/models/patient/vital_sign/patient-vital-sign-data.dart @@ -1,136 +1,257 @@ class VitalSignData { - int appointmentNo; - int bloodPressureCuffLocation; - int bloodPressureCuffSize; - int bloodPressureHigher; - int bloodPressureLower; - int bloodPressurePatientPosition; + var transNo; + var projectID; + var weightKg; + var heightCm; + var temperatureCelcius; + var pulseBeatPerMinute; + var respirationBeatPerMinute; + var bloodPressureLower; + var bloodPressureHigher; + var sAO2; + var fIO2; + var painScore; var bodyMassIndex; - int fio2; - int headCircumCm; - int heightCm; - int idealBodyWeightLbs; + var headCircumCm; + var leanBodyWeightLbs; + var idealBodyWeightLbs; + var temperatureCelciusMethod; + var pulseRhythm; + var respirationPattern; + var bloodPressureCuffLocation; + var bloodPressureCuffSize; + var bloodPressurePatientPosition; + var painLocation; + var painDuration; + var painCharacter; + var painFrequency; bool isPainManagementDone; + var status; bool isVitalsRequired; - int leanBodyWeightLbs; - String painCharacter; - String painDuration; - String painFrequency; - String painLocation; - int painScore; - int patientMRN; - int patientType; - int pulseBeatPerMinute; - int pulseRhythm; - int respirationBeatPerMinute; - int respirationPattern; - int sao2; - int status; - int temperatureCelcius; - int temperatureCelciusMethod; - int waistSizeInch; - int weightKg; + var patientID; + var createdOn; + var doctorID; + var clinicID; + var triageCategory; + var gCScore; + var lineItemNo; + DateTime vitalSignDate; + var actualTimeTaken; + var sugarLevel; + var fBS; + var rBS; + var observationType; + var heartRate; + var muscleTone; + var reflexIrritability; + var bodyColor; + var isFirstAssessment; + var dateofBirth; + var timeOfBirth; + var bloodPressure; + var bloodPressureCuffLocationDesc; + var bloodPressureCuffSizeDesc; + var bloodPressurePatientPositionDesc; + var clinicName; + var doctorImageURL; + var doctorName; + var painScoreDesc; + var pulseRhythmDesc; + var respirationPatternDesc; + var temperatureCelciusMethodDesc; + var time; VitalSignData( - {this.appointmentNo, - this.bloodPressureCuffLocation, - this.bloodPressureCuffSize, - this.bloodPressureHigher, + {this.transNo, + this.projectID, + this.weightKg, + this.heightCm, + this.temperatureCelcius, + this.pulseBeatPerMinute, + this.respirationBeatPerMinute, this.bloodPressureLower, - this.bloodPressurePatientPosition, + this.bloodPressureHigher, + this.sAO2, + this.fIO2, + this.painScore, this.bodyMassIndex, - this.fio2, this.headCircumCm, - this.heightCm, - this.idealBodyWeightLbs, - this.isPainManagementDone, - this.isVitalsRequired, this.leanBodyWeightLbs, - this.painCharacter, - this.painDuration, - this.painFrequency, - this.painLocation, - this.painScore, - this.patientMRN, - this.patientType, - this.pulseBeatPerMinute, + this.idealBodyWeightLbs, + this.temperatureCelciusMethod, this.pulseRhythm, - this.respirationBeatPerMinute, this.respirationPattern, - this.sao2, + this.bloodPressureCuffLocation, + this.bloodPressureCuffSize, + this.bloodPressurePatientPosition, + this.painLocation, + this.painDuration, + this.painCharacter, + this.painFrequency, + this.isPainManagementDone, this.status, - this.temperatureCelcius, - this.temperatureCelciusMethod, - this.waistSizeInch, - this.weightKg}); + this.isVitalsRequired, + this.patientID, + this.createdOn, + this.doctorID, + this.clinicID, + this.triageCategory, + this.gCScore, + this.lineItemNo, + this.vitalSignDate, + this.actualTimeTaken, + this.sugarLevel, + this.fBS, + this.rBS, + this.observationType, + this.heartRate, + this.muscleTone, + this.reflexIrritability, + this.bodyColor, + this.isFirstAssessment, + this.dateofBirth, + this.timeOfBirth, + this.bloodPressure, + this.bloodPressureCuffLocationDesc, + this.bloodPressureCuffSizeDesc, + this.bloodPressurePatientPositionDesc, + this.clinicName, + this.doctorImageURL, + this.doctorName, + this.painScoreDesc, + this.pulseRhythmDesc, + this.respirationPatternDesc, + this.temperatureCelciusMethodDesc, + this.time}); VitalSignData.fromJson(Map json) { - appointmentNo = json['appointmentNo']; - bloodPressureCuffLocation = json['bloodPressureCuffLocation']; - bloodPressureCuffSize = json['bloodPressureCuffSize']; - bloodPressureHigher = json['bloodPressureHigher']; - bloodPressureLower = json['bloodPressureLower']; - bloodPressurePatientPosition = json['bloodPressurePatientPosition']; - bodyMassIndex = json['bodyMassIndex']; - fio2 = json['fio2']; - headCircumCm = json['headCircumCm']; - heightCm = json['heightCm']; - idealBodyWeightLbs = json['idealBodyWeightLbs']; - isPainManagementDone = json['isPainManagementDone']; - isVitalsRequired = json['isVitalsRequired']; - leanBodyWeightLbs = json['leanBodyWeightLbs']; - painCharacter = json['painCharacter']; - painDuration = json['painDuration']; - painFrequency = json['painFrequency']; - painLocation = json['painLocation']; - painScore = json['painScore']; - patientMRN = json['patientMRN']; - patientType = json['patientType']; - pulseBeatPerMinute = json['pulseBeatPerMinute']; - pulseRhythm = json['pulseRhythm']; - respirationBeatPerMinute = json['respirationBeatPerMinute']; - respirationPattern = json['respirationPattern']; - sao2 = json['sao2']; - status = json['status']; - temperatureCelcius = json['temperatureCelcius']; - temperatureCelciusMethod = json['temperatureCelciusMethod']; - waistSizeInch = json['waistSizeInch']; - weightKg = json['weightKg']; + transNo = json['TransNo']; + projectID = json['ProjectID']; + weightKg = json['WeightKg']; + heightCm = json['HeightCm']; + temperatureCelcius = json['TemperatureCelcius']; + pulseBeatPerMinute = json['PulseBeatPerMinute']; + respirationBeatPerMinute = json['RespirationBeatPerMinute']; + bloodPressureLower = json['BloodPressureLower']; + bloodPressureHigher = json['BloodPressureHigher']; + sAO2 = json['SAO2']; + fIO2 = json['FIO2']; + painScore = json['PainScore']; + bodyMassIndex = json['BodyMassIndex']; + headCircumCm = json['HeadCircumCm']; + leanBodyWeightLbs = json['LeanBodyWeightLbs']; + idealBodyWeightLbs = json['IdealBodyWeightLbs']; + temperatureCelciusMethod = json['TemperatureCelciusMethod']; + pulseRhythm = json['PulseRhythm']; + respirationPattern = json['RespirationPattern']; + bloodPressureCuffLocation = json['BloodPressureCuffLocation']; + bloodPressureCuffSize = json['BloodPressureCuffSize']; + bloodPressurePatientPosition = json['BloodPressurePatientPosition']; + painLocation = json['PainLocation']; + painDuration = json['PainDuration']; + painCharacter = json['PainCharacter']; + painFrequency = json['PainFrequency']; + isPainManagementDone = json['IsPainManagementDone']; + status = json['Status']; + isVitalsRequired = json['IsVitalsRequired']; + patientID = json['PatientID']; + createdOn = json['CreatedOn']; + doctorID = json['DoctorID']; + clinicID = json['ClinicID']; + triageCategory = json['TriageCategory']; + gCScore = json['GCScore']; + lineItemNo = json['LineItemNo']; + vitalSignDate = json['VitalSignDate']; + actualTimeTaken = json['ActualTimeTaken']; + sugarLevel = json['SugarLevel']; + fBS = json['FBS']; + rBS = json['RBS']; + observationType = json['ObservationType']; + heartRate = json['HeartRate']; + muscleTone = json['MuscleTone']; + reflexIrritability = json['ReflexIrritability']; + bodyColor = json['BodyColor']; + isFirstAssessment = json['IsFirstAssessment']; + dateofBirth = json['DateofBirth']; + timeOfBirth = json['TimeOfBirth']; + bloodPressure = json['BloodPressure']; + bloodPressureCuffLocationDesc = json['BloodPressureCuffLocationDesc']; + bloodPressureCuffSizeDesc = json['BloodPressureCuffSizeDesc']; + bloodPressurePatientPositionDesc = json['BloodPressurePatientPositionDesc']; + clinicName = json['ClinicName']; + doctorImageURL = json['DoctorImageURL']; + doctorName = json['DoctorName']; + painScoreDesc = json['PainScoreDesc']; + pulseRhythmDesc = json['PulseRhythmDesc']; + respirationPatternDesc = json['RespirationPatternDesc']; + temperatureCelciusMethodDesc = json['TemperatureCelciusMethodDesc']; + time = json['Time']; } Map toJson() { final Map data = new Map(); - data['appointmentNo'] = this.appointmentNo; - data['bloodPressureCuffLocation'] = this.bloodPressureCuffLocation; - data['bloodPressureCuffSize'] = this.bloodPressureCuffSize; - data['bloodPressureHigher'] = this.bloodPressureHigher; - data['bloodPressureLower'] = this.bloodPressureLower; - data['bloodPressurePatientPosition'] = this.bloodPressurePatientPosition; - data['bodyMassIndex'] = this.bodyMassIndex; - data['fio2'] = this.fio2; - data['headCircumCm'] = this.headCircumCm; - data['heightCm'] = this.heightCm; - data['idealBodyWeightLbs'] = this.idealBodyWeightLbs; - data['isPainManagementDone'] = this.isPainManagementDone; - data['isVitalsRequired'] = this.isVitalsRequired; - data['leanBodyWeightLbs'] = this.leanBodyWeightLbs; - data['painCharacter'] = this.painCharacter; - data['painDuration'] = this.painDuration; - data['painFrequency'] = this.painFrequency; - data['painLocation'] = this.painLocation; - data['painScore'] = this.painScore; - data['patientMRN'] = this.patientMRN; - data['patientType'] = this.patientType; - data['pulseBeatPerMinute'] = this.pulseBeatPerMinute; - data['pulseRhythm'] = this.pulseRhythm; - data['respirationBeatPerMinute'] = this.respirationBeatPerMinute; - data['respirationPattern'] = this.respirationPattern; - data['sao2'] = this.sao2; - data['status'] = this.status; - data['temperatureCelcius'] = this.temperatureCelcius; - data['temperatureCelciusMethod'] = this.temperatureCelciusMethod; - data['waistSizeInch'] = this.waistSizeInch; - data['weightKg'] = this.weightKg; + data['TransNo'] = this.transNo; + data['ProjectID'] = this.projectID; + data['WeightKg'] = this.weightKg; + data['HeightCm'] = this.heightCm; + data['TemperatureCelcius'] = this.temperatureCelcius; + data['PulseBeatPerMinute'] = this.pulseBeatPerMinute; + data['RespirationBeatPerMinute'] = this.respirationBeatPerMinute; + data['BloodPressureLower'] = this.bloodPressureLower; + data['BloodPressureHigher'] = this.bloodPressureHigher; + data['SAO2'] = this.sAO2; + data['FIO2'] = this.fIO2; + data['PainScore'] = this.painScore; + data['BodyMassIndex'] = this.bodyMassIndex; + data['HeadCircumCm'] = this.headCircumCm; + data['LeanBodyWeightLbs'] = this.leanBodyWeightLbs; + data['IdealBodyWeightLbs'] = this.idealBodyWeightLbs; + data['TemperatureCelciusMethod'] = this.temperatureCelciusMethod; + data['PulseRhythm'] = this.pulseRhythm; + data['RespirationPattern'] = this.respirationPattern; + data['BloodPressureCuffLocation'] = this.bloodPressureCuffLocation; + data['BloodPressureCuffSize'] = this.bloodPressureCuffSize; + data['BloodPressurePatientPosition'] = this.bloodPressurePatientPosition; + data['PainLocation'] = this.painLocation; + data['PainDuration'] = this.painDuration; + data['PainCharacter'] = this.painCharacter; + data['PainFrequency'] = this.painFrequency; + data['IsPainManagementDone'] = this.isPainManagementDone; + data['Status'] = this.status; + data['IsVitalsRequired'] = this.isVitalsRequired; + data['PatientID'] = this.patientID; + data['CreatedOn'] = this.createdOn; + data['DoctorID'] = this.doctorID; + data['ClinicID'] = this.clinicID; + data['TriageCategory'] = this.triageCategory; + data['GCScore'] = this.gCScore; + data['LineItemNo'] = this.lineItemNo; + data['VitalSignDate'] = this.vitalSignDate; + data['ActualTimeTaken'] = this.actualTimeTaken; + data['SugarLevel'] = this.sugarLevel; + data['FBS'] = this.fBS; + data['RBS'] = this.rBS; + data['ObservationType'] = this.observationType; + data['HeartRate'] = this.heartRate; + data['MuscleTone'] = this.muscleTone; + data['ReflexIrritability'] = this.reflexIrritability; + data['BodyColor'] = this.bodyColor; + data['IsFirstAssessment'] = this.isFirstAssessment; + data['DateofBirth'] = this.dateofBirth; + data['TimeOfBirth'] = this.timeOfBirth; + data['BloodPressure'] = this.bloodPressure; + data['BloodPressureCuffLocationDesc'] = this.bloodPressureCuffLocationDesc; + data['BloodPressureCuffSizeDesc'] = this.bloodPressureCuffSizeDesc; + data['BloodPressurePatientPositionDesc'] = + this.bloodPressurePatientPositionDesc; + data['ClinicName'] = this.clinicName; + data['DoctorImageURL'] = this.doctorImageURL; + data['DoctorName'] = this.doctorName; + data['PainScoreDesc'] = this.painScoreDesc; + data['PulseRhythmDesc'] = this.pulseRhythmDesc; + data['RespirationPatternDesc'] = this.respirationPatternDesc; + data['TemperatureCelciusMethodDesc'] = this.temperatureCelciusMethodDesc; + data['Time'] = this.time; return data; } } diff --git a/lib/routes.dart b/lib/routes.dart index e57b56a7..5dabcba2 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -135,7 +135,7 @@ var routes = { REFER_PATIENT_TO_DOCTOR: (_) => PatientMakeReferralScreen(), PATIENT_ORDERS: (_) => PatientsOrdersScreen(), PATIENT_INSURANCE_APPROVALS: (_) => InsuranceApprovalsScreen(), - VITAL_SIGN_DETAILS: (_) => VitalSignDetailsScreen(), + // VITAL_SIGN_DETAILS: (_) => VitalSignDetailsScreen(), PATIENT_VITAL_SIGN: (_) => PatientVitalSignScreen(), PATIENT_ADMISSION_REQUEST: (_) => AdmissionRequestDetailScreen(), PATIENT_ADMISSION_REQUEST_2: (_) => AdmissionRequestSecondScreen(), diff --git a/lib/screens/patients/profile/vital_sign/LineChartCurved.dart b/lib/screens/patients/profile/vital_sign/LineChartCurved.dart new file mode 100644 index 00000000..2f0eafcb --- /dev/null +++ b/lib/screens/patients/profile/vital_sign/LineChartCurved.dart @@ -0,0 +1,217 @@ +import 'package:doctor_app_flutter/widgets/charts/app_time_series_chart.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; + +class LineChartCurved extends StatelessWidget { + final String title; + final List timeSeries; + final int indexes; + + LineChartCurved({this.title, this.timeSeries, this.indexes}); + + List xAxixs = List(); + List yAxixs = List(); + + @override + Widget build(BuildContext context) { + getXaxix(); + getYaxix(); + return AspectRatio( + aspectRatio: 1.1, + child: Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(18)), + // color: Colors.white, + ), + child: Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox( + height: 4, + ), + Text( + title, + style: TextStyle( + color: Colors.black, + fontSize: 15, + letterSpacing: 2), + textAlign: TextAlign.center, + ), + SizedBox(height: 10,), + Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 18.0, left: 16.0), + child: LineChart( + sampleData1(context), + swapAnimationDuration: const Duration(milliseconds: 250), + ), + ), + ), + const SizedBox( + height: 10, + ), + ], + ), + ], + ), + ), + ); + } + + getXaxix() { + for (int index = 0; index < timeSeries.length; index++) { + int mIndex = indexes * index; + if (mIndex < timeSeries.length) { + xAxixs.add(mIndex); + } + } + } + getYaxix() { + int indexess= (timeSeries.length*0.30).toInt(); + for (int index = 0; index < timeSeries.length; index++) { + int mIndex = indexess * index; + if (mIndex < timeSeries.length) { + yAxixs.add(timeSeries[mIndex].sales); + } + } + } + + LineChartData sampleData1(context) { + return LineChartData( + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + tooltipBgColor: Colors.white, + + ), + touchCallback: (LineTouchResponse touchResponse) {}, + handleBuiltInTouches: true, + ), + gridData: FlGridData( + show: true, drawVerticalLine: true, drawHorizontalLine: true), + titlesData: FlTitlesData( + bottomTitles: SideTitles( + showTitles: true, + getTextStyles: (value) => const TextStyle( + color: Colors.black, + fontSize: 10, + ), + rotateAngle:-65, + //rotateAngle:-65, + margin: 22, + getTitles: (value) { + if (timeSeries.length < 15) { + if (timeSeries.length > value.toInt()) { + return '${timeSeries[value.toInt()].time.month}/ ${timeSeries[value.toInt()].time.year}'; + } else + return ''; + } else { + if (value.toInt() == 0) + return '${timeSeries[value.toInt()].time.month}/ ${timeSeries[value.toInt()].time.year}'; + if (value.toInt() == timeSeries.length - 1) + return '${timeSeries[value.toInt()].time.month}/ ${timeSeries[value.toInt()].time.year}'; + if (xAxixs.contains(value.toInt())) { + return '${timeSeries[value.toInt()].time.month}/ ${timeSeries[value.toInt()].time.year}'; + } + } + return ''; + }, + ), + leftTitles: SideTitles( + showTitles: true, + getTextStyles: (value) => const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 10, + ), + getTitles: (value) { + // if (timeSeries.length < 10) { + // return '${value.toInt()}'; + // } else { + // if (value == getMinY()) + // return '${value.toInt()}'; + // if (value == getMaxY()) + // return '${value.toInt()}'; + // if (yAxixs.contains(value)) { + // return '${value.toInt()}'; + // } + // return ''; + // } + return '${value.toInt()}'; + }, + margin: 12, + ), + ), + borderData: FlBorderData( + show: true, + border: const Border( + bottom: BorderSide( + color: Colors.black, + width: 0.5, + ), + left: BorderSide( + color: Colors.black, + ), + right: BorderSide( + color: Colors.black, + ), + top: BorderSide( + color: Colors.transparent, + ), + ), + ), + minX: 0, + maxX: (timeSeries.length - 1).toDouble(), + maxY: getMaxY()+0.3, + minY: getMinY(), + lineBarsData: getData(context), + ); + } + + double getMaxY() { + double max = 0; + timeSeries.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble > max) max = resultValueDouble; + }); + + return max.roundToDouble() ; + } + + double getMinY() { + double min = timeSeries[0].sales; + timeSeries.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble < min) min = resultValueDouble; + }); + int value = min.toInt(); + + return value.toDouble(); + } + + List getData(context) { + List spots = List(); + for (int index = 0; index < timeSeries.length; index++) { + spots.add(FlSpot(index.toDouble(), timeSeries[index].sales)); + } + + final LineChartBarData lineChartBarData1 = LineChartBarData( + spots: spots, + isCurved: true, + colors: [Theme.of(context).primaryColor], + barWidth: 5, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, + ), + belowBarData: BarAreaData( + show: false, + ), + ); + + return [ + lineChartBarData1, + ]; + } +} diff --git a/lib/screens/patients/profile/vital_sign/LineChartCurvedBloodPressure.dart b/lib/screens/patients/profile/vital_sign/LineChartCurvedBloodPressure.dart new file mode 100644 index 00000000..e816c145 --- /dev/null +++ b/lib/screens/patients/profile/vital_sign/LineChartCurvedBloodPressure.dart @@ -0,0 +1,257 @@ +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/charts/app_time_series_chart.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; + +class LineChartCurvedBloodPressure extends StatelessWidget { + final String title; + final List timeSeries1; + final List timeSeries2; + final int indexes; + + LineChartCurvedBloodPressure( + {this.title, this.timeSeries1, this.indexes, this.timeSeries2}); + + List xAxixs = List(); + List yAxixs = List(); + + @override + Widget build(BuildContext context) { + getXaxix(); + return AspectRatio( + aspectRatio: 1.1, + child: Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(18)), + // color: Colors.white, + ), + child: Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox( + height: 15, + ), + Text( + title, + style: TextStyle( + color: Colors.black, fontSize: 15, letterSpacing: 2), + textAlign: TextAlign.center, + ), + SizedBox( + height: 10, + ), + Expanded( + child: Padding( + padding: + const EdgeInsets.only(right: 18.0, left: 16.0, top: 15), + child: LineChart( + sampleData1(context), + swapAnimationDuration: const Duration(milliseconds: 250), + ), + ), + ), + SizedBox( + height: 10, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Theme.of(context).primaryColor), + ), + SizedBox(width: 5,), + AppText(TranslationBase.of(context).systolicLng) + ], + ), + SizedBox(width: 15,), + Row( + children: [ + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.grey), + ), + SizedBox(width: 5,), + AppText(TranslationBase.of(context).diastolicLng) + ], + ), + ], + ) + ], + ), + ], + ), + ), + ); + } + + getXaxix() { + for (int index = 0; index < timeSeries1.length; index++) { + int mIndex = indexes * index; + if (mIndex < timeSeries1.length) { + xAxixs.add(mIndex); + } + } + } + + LineChartData sampleData1(context) { + return LineChartData( + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + tooltipBgColor: Colors.white, + ), + touchCallback: (LineTouchResponse touchResponse) {}, + handleBuiltInTouches: true, + ), + gridData: FlGridData( + show: true, drawVerticalLine: true, drawHorizontalLine: true), + titlesData: FlTitlesData( + bottomTitles: SideTitles( + showTitles: true, + getTextStyles: (value) => const TextStyle( + color: Colors.black, + fontSize: 10, + ), + rotateAngle: -65, + //rotateAngle:-65, + margin: 22, + getTitles: (value) { + if (timeSeries1.length < 15) { + if (timeSeries1.length > value.toInt()) { + return '${timeSeries1[value.toInt()].time.month}/ ${timeSeries1[value.toInt()].time.year}'; + } else + return ''; + } else { + if (value.toInt() == 0) + return '${timeSeries1[value.toInt()].time.month}/ ${timeSeries1[value.toInt()].time.year}'; + if (value.toInt() == timeSeries1.length - 1) + return '${timeSeries1[value.toInt()].time.month}/ ${timeSeries1[value.toInt()].time.year}'; + if (xAxixs.contains(value.toInt())) { + return '${timeSeries1[value.toInt()].time.month}/ ${timeSeries1[value.toInt()].time.year}'; + } + } + return ''; + }, + ), + leftTitles: SideTitles( + showTitles: true, + getTextStyles: (value) => const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 10, + ), + getTitles: (value) { + return '${value.toInt()}'; + }, + margin: 12, + ), + ), + borderData: FlBorderData( + show: true, + border: const Border( + bottom: BorderSide( + color: Colors.black, + width: 0.5, + ), + left: BorderSide( + color: Colors.black, + ), + right: BorderSide( + color: Colors.black, + ), + top: BorderSide( + color: Colors.transparent, + ), + ), + ), + minX: 0, + maxX: (timeSeries1.length - 1).toDouble(), + maxY: getMaxY() + 0.3, + minY: getMinY(), + lineBarsData: getData(context), + ); + } + + double getMaxY() { + double max = 0; + timeSeries1.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble > max) max = resultValueDouble; + }); + timeSeries2.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble > max) max = resultValueDouble; + }); + + return max.roundToDouble(); + } + + double getMinY() { + double min = timeSeries1[0].sales; + timeSeries1.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble < min) min = resultValueDouble; + }); + timeSeries2.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble < min) min = resultValueDouble; + }); + + int value = min.toInt(); + + return value.toDouble(); + } + + List getData(context) { + List spots = List(); + for (int index = 0; index < timeSeries1.length; index++) { + spots.add(FlSpot(index.toDouble(), timeSeries1[index].sales)); + } + + List spots2 = List(); + for (int index = 0; index < timeSeries2.length; index++) { + spots2.add(FlSpot(index.toDouble(), timeSeries2[index].sales)); + } + + final LineChartBarData lineChartBarData1 = LineChartBarData( + spots: spots, + isCurved: true, + colors: [Theme.of(context).primaryColor], + barWidth: 5, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, + ), + belowBarData: BarAreaData( + show: false, + ), + ); + final LineChartBarData lineChartBarData2 = LineChartBarData( + spots: spots2, + isCurved: true, + colors: [Colors.grey], + barWidth: 5, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, + ), + belowBarData: BarAreaData( + show: false, + ), + ); + + return [lineChartBarData1, lineChartBarData2]; + } +} diff --git a/lib/screens/patients/profile/vital_sign/vital-signs-screen.dart b/lib/screens/patients/profile/vital_sign/vital-signs-screen.dart index a53a3619..185b9374 100644 --- a/lib/screens/patients/profile/vital_sign/vital-signs-screen.dart +++ b/lib/screens/patients/profile/vital_sign/vital-signs-screen.dart @@ -115,7 +115,7 @@ class PatientVitalSignScreen extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( + /*Row( children: [ AppText( "${TranslationBase.of(context).waistSize} :", @@ -133,7 +133,7 @@ class PatientVitalSignScreen extends StatelessWidget { fontWeight: FontWeight.normal, ), ], - ), + ),*/ Row( children: [ AppText( @@ -939,7 +939,7 @@ class _OxygenationWidgetState extends State { width: 8, ), AppText( - "${widget.vitalSign.sao2}", + "${widget.vitalSign.sAO2}", fontSize: SizeConfig.textMultiplier * 2, color: Colors.grey.shade800, fontWeight: FontWeight.normal, @@ -958,7 +958,7 @@ class _OxygenationWidgetState extends State { width: 8, ), AppText( - "${widget.vitalSign.fio2}", + "${widget.vitalSign.fIO2}", fontSize: SizeConfig.textMultiplier * 2, color: Colors.grey.shade800, fontWeight: FontWeight.normal, diff --git a/lib/screens/patients/profile/vital_sign/vital_sign_details_blood_pressurewideget.dart b/lib/screens/patients/profile/vital_sign/vital_sign_details_blood_pressurewideget.dart new file mode 100644 index 00000000..09af7991 --- /dev/null +++ b/lib/screens/patients/profile/vital_sign/vital_sign_details_blood_pressurewideget.dart @@ -0,0 +1,145 @@ +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; +import 'package:doctor_app_flutter/util/date-utils.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class VitalSignBloodPressureWidget extends StatefulWidget { + final List vitalList; + final String title1; + final String title2; + final String title3; + final String viewKey1; + final String viewKey2; + + VitalSignBloodPressureWidget( + {Key key, this.vitalList, this.title1, this.title2, this.viewKey1, this.title3, this.viewKey2}); + + @override + _VitalSignDetailsWidgetState createState() => _VitalSignDetailsWidgetState(); +} + +class _VitalSignDetailsWidgetState extends State { + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0)), + border: Border.all(color: Colors.grey, width: 1), + ), + margin: EdgeInsets.all(20), + child: Container( + color: Colors.transparent, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Table( + border: TableBorder.symmetric( + inside: BorderSide(width: 2.0, color: Colors.grey[300]), + ), + children: fullData(projectViewModel), + ), + ], + ), + ), + ); + } + + List fullData(ProjectViewModel projectViewModel) { + List tableRow = []; + tableRow.add(TableRow(children: [ + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft:projectViewModel.isArabic? Radius.circular(0.0):Radius.circular(10.0), + topRight: projectViewModel.isArabic? Radius.circular(10.0):Radius.circular(0.0) + ), + ), + child: Center( + child: AppText( + TranslationBase.of(context).date, + color: Colors.white, + ), + ), + height: 60, + ), + ), + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + + ), + child: Center( + child: AppText(widget.title2, color: Colors.white), + ), + height: 60), + ), + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topRight: projectViewModel.isArabic? Radius.circular(0.0):Radius.circular(10.0), + topLeft: projectViewModel.isArabic? Radius.circular(10.0):Radius.circular(0.0) + ), + ), + child: Center( + child: AppText(widget.title3, color: Colors.white), + ), + height: 60), + ), + ])); + widget.vitalList.forEach((vital) { + var data = vital.toJson()[widget.viewKey1]; + if (data != 0) + tableRow.add(TableRow(children: [ + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: AppText( + '${projectViewModel.isArabic ? DateUtils.getWeekDayArabic(vital.vitalSignDate.weekday) : DateUtils.getWeekDay(vital.vitalSignDate.weekday)}, ${vital.vitalSignDate.day} ${projectViewModel.isArabic ? DateUtils.getMonthArabic(vital.vitalSignDate.month) : DateUtils.getMonth(vital.vitalSignDate.month)}, ${vital.vitalSignDate.year} ', + textAlign: TextAlign.center, + ), + ), + ), + ), + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: AppText( + '${vital.toJson()[widget.viewKey1]}', + textAlign: TextAlign.center, + ), + ), + ), + ), + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: AppText( + '${vital.toJson()[widget.viewKey2]}', + textAlign: TextAlign.center, + ), + ), + ), + ), + ])); + }); + return tableRow; + } +} diff --git a/lib/screens/patients/profile/vital_sign/vital_sign_details_screen.dart b/lib/screens/patients/profile/vital_sign/vital_sign_details_screen.dart index cf8ee839..d382ec3f 100644 --- a/lib/screens/patients/profile/vital_sign/vital_sign_details_screen.dart +++ b/lib/screens/patients/profile/vital_sign/vital_sign_details_screen.dart @@ -1,246 +1,196 @@ -import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart'; -import 'package:doctor_app_flutter/models/patient/vital_sign/vital_sign_req_model.dart'; -import 'package:doctor_app_flutter/screens/base/base_view.dart'; -import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; -import 'package:doctor_app_flutter/widgets/shared/errors/dr_app_embedded_error.dart'; -import 'package:flutter/material.dart'; - -import '../../../../config/shared_pref_kay.dart'; -import '../../../../config/size_config.dart'; -import '../../../../lookups/patient_lookup.dart'; -import '../../../../models/patient/patiant_info_model.dart'; -import '../../../../models/patient/vital_sign/vital_sign_res_model.dart'; -import '../../../../routes.dart'; -import '../../../../screens/patients/profile/vital_sign/vital_sign_item.dart'; -import '../../../../util/dr_app_shared_pref.dart'; -import '../../../../widgets/shared/app_scaffold_widget.dart'; - -DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); - -class VitalSignDetailsScreen extends StatefulWidget { - // VitalSignDetailsScreen({Key key, this.vitalSing}) : super(key: key); - @override - _VitalSignDetailsScreenState createState() => _VitalSignDetailsScreenState(); -} - -class _VitalSignDetailsScreenState extends State { - VitalSignResModel vitalSing; - String url = "assets/images/"; - - - /* - *@author: Elham Rababah - *@Date:28/4/2020 - *@param: context - *@return: - *@desc: getVitalSignList Function - */ - getVitalSignList(BuildContext context, PatientViewModel model) async { - final routeArgs = ModalRoute.of(context).settings.arguments as Map; - PatiantInformtion patient = routeArgs['patient']; - String token = await sharedPref.getString(TOKEN); - String type = await sharedPref.getString(SLECTED_PATIENT_TYPE); - int inOutpatientType = 1; - if (type == '0') { - inOutpatientType = 2; - } - print(type); - VitalSignReqModel vitalSignReqModel = VitalSignReqModel( - patientID: patient.patientId, - projectID: patient.projectId, - tokenID: token, - patientTypeID: patient.patientType, - inOutpatientType: inOutpatientType, - languageID: 2, - transNo: - patient.admissionNo != null ? int.parse(patient.admissionNo) : 0); - model.getPatientVitalSign(vitalSignReqModel.toJson()); - } - - - - final double contWidth = SizeConfig.realScreenWidth * 0.70; - - @override - Widget build(BuildContext context) { - final routeArgs = ModalRoute.of(context).settings.arguments as Map; - vitalSing = routeArgs['vitalSing']; - return BaseView( - onModelReady: (model) => getVitalSignList(context, model), - builder: (_, model, w) => AppScaffold( - baseViewModel: model, - appBarTitle: TranslationBase.of(context).vitalSign, - body: model.patientVitalSignOrderdSubList.length == 0 - ? DrAppEmbeddedError( - error: 'You don\'t have any vital Sings') - : Container( - child: Column( - children: [ - Row( - children: [ - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': TranslationBase.of(context) - .bodyMeasurements, - 'key': - vitalSignDetails.bodyMeasurements - }); - }, - child: Container( - child: VitalSignItem( - des: TranslationBase.of(context) - .bodyMeasurements, - url: url + 'heartbeat.png', - lastVal: model - .patientVitalSignOrderdSubList[0] - .heightCm - .toString(), - unit: 'Cm', - ), - ), - ), - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': TranslationBase.of(context) - .temperature, - 'key': vitalSignDetails.temperature, - }); - }, - child: Container( - child: VitalSignItem( - des: TranslationBase.of(context) - .temperature, - url: url + 'heartbeat.png', - lastVal: model - .patientVitalSignOrderdSubList[0] - .temperatureCelcius - .toString(), - unit: 'C', - ), - ), - ), - ], - ), - Row( - children: [ - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': - TranslationBase.of(context).pulse, - 'key': vitalSignDetails.pulse - }); - }, - child: VitalSignItem( - des: TranslationBase.of(context).pulse, - url: url + 'heartbeat.png', - lastVal: model - .patientVitalSignOrderdSubList[0] - .pulseBeatPerMinute - .toString(), - unit: 'M', - ), - ), - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': TranslationBase.of(context) - .respiration, - 'key': vitalSignDetails.pespiration - }); - }, - child: VitalSignItem( - des: - TranslationBase.of(context).respiration, - url: url + 'heartbeat.png', - lastVal: model - .patientVitalSignOrderdSubList[0] - .respirationBeatPerMinute - .toString(), - unit: 'M', - ), - ), - ], - ), - Row( - children: [ - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': TranslationBase.of(context) - .bloodPressure, - 'key': vitalSignDetails.bloodPressure - }); - }, - child: VitalSignItem( - des: TranslationBase.of(context) - .bloodPressure, - url: url + 'heartbeat.png', - lastVal: model - .patientVitalSignOrderdSubList[0] - .bloodPressure - .toString(), - unit: '', - ), - ), - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': TranslationBase.of(context) - .oxygenation, - 'key': vitalSignDetails.oxygenation - }); - }, - child: VitalSignItem( - des: - TranslationBase.of(context).oxygenation, - url: url + 'heartbeat.png', - lastVal: model - .patientVitalSignOrderdSubList[0].fIO2 - .toString(), - unit: '', - ), - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - onTap: () { - Navigator.of(context).pushNamed( - BODY_MEASUREMENTS, - arguments: { - 'title': TranslationBase.of(context) - .painScale, - 'key': vitalSignDetails.painScale - }); - }, - child: VitalSignItem( - des: TranslationBase - .of(context) - .painScale, - url: url + 'heartbeat.png', - ), - ), - ], - ), - ], - ), - ),),); - } -} +// import 'package:doctor_app_flutter/screens/patients/profile/vital_sign/vital_sign_item.dart'; +// import 'package:doctor_app_flutter/screens/patients/profile/vital_sign/vital_sign_item_details_screen.dart'; +// import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +// import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +// import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +// import 'package:flutter/material.dart'; +// +// class VitalSignDetailsScreen extends StatelessWidget { +// static const String url = "assets/images/"; +// +// int appointmentNo; +// int projectID; +// bool isNotOneAppointment; +// VitalSignDetailsScreen({this.appointmentNo, this.projectID,this.isNotOneAppointment=true}); +// List imagesInfo = List(); +// +// +// @override +// Widget build(BuildContext context) { +// imagesInfo.add(ImagesInfo(imageEn: 'https://hmgwebservices.com/Images/MobileApp/imges-info/my-vital-signs/en/0.png',imageAr: 'https://hmgwebservices.com/Images/MobileApp/imges-info/my-vital-signs/ar/0.png')); +// imagesInfo.add(ImagesInfo(imageEn: 'https://hmgwebservices.com/Images/MobileApp/imges-info/my-vital-signs/en/1.png',imageAr: 'https://hmgwebservices.com/Images/MobileApp/imges-info/my-vital-signs/ar/1.png')); +// return BaseView( +// onModelReady: appointmentNo != null && projectID != null +// ? (model) => model.getPatientVitalSign( +// appointmentNo: appointmentNo, projectID: projectID) +// : (model) => model.getPatientVitalSign(), +// builder: (_, mode, widget) => AppScaffold( +// isShowAppBar: true, +// appBarTitle: TranslationBase.of(context).vitalSigns, +// baseViewModel: mode, +// description: TranslationBase.of(context).infoSigns, +// imagesInfo: imagesInfo, +// body: mode.vitalSignResModelList.length > 0 +// ? Container( +// child: ListView( +// children: [ +// Row( +// children: [ +// InkWell( +// onTap: () =>isNotOneAppointment? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: VitalSignDetails.Height, +// pageTitle: TranslationBase.of(context).height, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ):null, +// child: Container( +// child: VitalSignItem( +// des: TranslationBase.of(context).height, +// icon: DQIcons.height, +// lastVal: mode.heightCm, +// unit: TranslationBase.of(context).cm, +// ), +// ), +// ), +// InkWell( +// onTap: () => isNotOneAppointment ? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: VitalSignDetails.Weight, +// pageTitle: TranslationBase.of(context).weight, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ):null, +// child: VitalSignItem( +// des: TranslationBase.of(context).weight, +// icon: DQIcons.weight_scale, +// unit: TranslationBase.of(context).kg, +// lastVal: mode.weightKg, +// ), +// ), +// ], +// ), +// Row( +// children: [ +// InkWell( +// onTap: () => isNotOneAppointment ? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: vitalSignDetails.BodyMeasurements, +// pageTitle: TranslationBase.of(context) +// .bodyMeasurements, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ): null, +// child: VitalSignItem( +// des: TranslationBase.of(context).body, +// icon: DQIcons.bmi, +// lastVal: mode.bodyMax, +// unit: TranslationBase.of(context).mass, +// ), +// ), +// InkWell( +// onTap: () => isNotOneAppointment ? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: VitalSignDetails.Temperature, +// pageTitle: +// TranslationBase.of(context).temperature, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ):null, +// child: Container( +// child: VitalSignItem( +// des: TranslationBase.of(context).temperature, +// icon: DQIcons.thermometer, +// lastVal: mode.temperatureCelcius, +// unit: TranslationBase.of(context).tempC, +// ), +// ), +// ), +// ], +// ), +// Row( +// children: [ +// InkWell( +// onTap: () => isNotOneAppointment ? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: VitalSignDetails.heart, +// pageTitle: TranslationBase.of(context).heart, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ):null, +// child: VitalSignItem( +// des: TranslationBase.of(context).heart, +// icon: DQIcons.heart, +// lastVal: mode.hartRat, +// unit: TranslationBase.of(context).bpm, +// ), +// ), +// InkWell( +// onTap: () => isNotOneAppointment ? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: VitalSignDetails.Respiration, +// pageTitle: +// TranslationBase.of(context).respirationRate, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ):null, +// child: VitalSignItem( +// des: TranslationBase.of(context).respirationRate, +// icon: DQIcons.outline, +// lastVal: mode.respirationBeatPerMinute, +// unit: TranslationBase.of(context).respirationSigns, +// ), +// ), +// ], +// ), +// Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// InkWell( +// onTap: () => isNotOneAppointment ? Navigator.push( +// context, +// FadePage( +// page: VitalSignItemDetailsScreen( +// pageKey: VitalSignDetails.BloodPressure, +// pageTitle: TranslationBase.of(context).bloodPressure, +// vitalList: mode.vitalSignResModelList, +// ), +// ), +// ):null, +// child: VitalSignItem( +// des: TranslationBase.of(context).bloodPressure, +// icon: DQIcons.blood_pressure, +// lastVal: mode.bloodPressure, +// unit: TranslationBase.of(context).sysDias, +// ), +// ), +// ], +// ), +// ], +// ), +// ) +// : Center( +// child: Texts('No Data'), +// ), +// ), +// ); +// } +// } diff --git a/lib/screens/patients/profile/vital_sign/vital_sign_details_wideget.dart b/lib/screens/patients/profile/vital_sign/vital_sign_details_wideget.dart new file mode 100644 index 00000000..828e320a --- /dev/null +++ b/lib/screens/patients/profile/vital_sign/vital_sign_details_wideget.dart @@ -0,0 +1,121 @@ +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; +import 'package:doctor_app_flutter/util/date-utils.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; + +class VitalSignDetailsWidget extends StatefulWidget { + final List vitalList; + final String title1; + final String title2; + final String viewKey; + + VitalSignDetailsWidget( + {Key key, this.vitalList, this.title1, this.title2, this.viewKey}); + + @override + _VitalSignDetailsWidgetState createState() => _VitalSignDetailsWidgetState(); +} + +class _VitalSignDetailsWidgetState extends State { + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0)), + border: Border.all(color: Colors.grey, width: 1), + ), + margin: EdgeInsets.all(20), + child: Container( + color: Colors.transparent, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Table( + border: TableBorder.symmetric( + inside: BorderSide(width: 2.0, color: Colors.grey[300]), + ), + children: fullData(projectViewModel), + ), + ], + ), + ), + ); + } + + List fullData(ProjectViewModel projectViewModel) { + List tableRow = []; + tableRow.add(TableRow(children: [ + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft:projectViewModel.isArabic? Radius.circular(0.0):Radius.circular(10.0), + topRight: projectViewModel.isArabic? Radius.circular(10.0):Radius.circular(0.0) + ), + ), + child: Center( + child: AppText( + TranslationBase.of(context).date, + color: Colors.white, + ), + ), + height: 60, + ), + ), + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topRight: projectViewModel.isArabic? Radius.circular(0.0):Radius.circular(10.0), + topLeft: projectViewModel.isArabic? Radius.circular(10.0):Radius.circular(0.0) + ), + ), + child: Center( + child: AppText(widget.title2, color: Colors.white), + ), + height: 60), + ) + ])); + widget.vitalList.forEach((vital) { + var data = vital.toJson()[widget.viewKey]; + if (data != 0) + tableRow.add(TableRow(children: [ + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: AppText( + '${projectViewModel.isArabic ? DateUtils.getWeekDayArabic(vital.vitalSignDate.weekday) : DateUtils.getWeekDay(vital.vitalSignDate.weekday)}, ${vital.vitalSignDate.day} ${projectViewModel.isArabic ? DateUtils.getMonthArabic(vital.vitalSignDate.month) : DateUtils.getMonth(vital.vitalSignDate.month)}, ${vital.vitalSignDate.year} ', + textAlign: TextAlign.center, + ), + ), + ), + ), + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: AppText( + '${vital.toJson()[widget.viewKey]}', + textAlign: TextAlign.center, + ), + ), + ), + ), + ])); + }); + return tableRow; + } +} diff --git a/lib/screens/patients/profile/vital_sign/vital_sign_item.dart b/lib/screens/patients/profile/vital_sign/vital_sign_item.dart index 1e0ce2cf..6ed044ab 100644 --- a/lib/screens/patients/profile/vital_sign/vital_sign_item.dart +++ b/lib/screens/patients/profile/vital_sign/vital_sign_item.dart @@ -1,32 +1,23 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; import 'package:flutter/material.dart'; import 'package:hexcolor/hexcolor.dart'; -import '../../../../config/size_config.dart'; -import '../../../../widgets/shared/rounded_container_widget.dart'; - -/* - *@author: Elham Rababah - *@Date:03/6/2020 - *@param: - *@return: - *@desc: VitalSignItem - */ class VitalSignItem extends StatelessWidget { const VitalSignItem( {Key key, - @required this.url, @required this.des, this.lastVal = 'N/A', this.unit = '', this.height, - this.width}) + this.width, + @required this.icon}) : super(key: key); - final String url; final String des; final String lastVal; final String unit; - + final IconData icon; final double height; final double width; @@ -34,52 +25,70 @@ class VitalSignItem extends StatelessWidget { Widget build(BuildContext context) { return RoundedContainer( margin: 0.025 * SizeConfig.realScreenWidth, - height: 0.14 * SizeConfig.realScreenHeight, + height: 0.15 * SizeConfig.realScreenHeight, width: 0.45 * SizeConfig.realScreenWidth, child: Container( padding: EdgeInsets.all(5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - flex: 2, - child: Text( - des, - style: TextStyle( - fontSize: 1.7 * SizeConfig.textMultiplier, - color: HexColor('#B8382C'), - fontWeight: FontWeight.bold), - ), - ), - Expanded( - flex: 1, - child: Column( + Container( + height: 0.10 * SizeConfig.realScreenHeight, + child: Row( children: [ Expanded( - child: Image.asset( - url, - height: SizeConfig.heightMultiplier * 7, - ), - ), - Expanded( - child: RichText( - text: TextSpan( - style: TextStyle(color: Colors.black), - children: [ - new TextSpan(text: lastVal), - new TextSpan( - text: ' ${unit}', + flex: 2, + child: Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + des, style: TextStyle( + fontSize: 1.7 * SizeConfig.textMultiplier, color: HexColor('#B8382C'), + fontWeight: FontWeight.bold, ), ), - ], + ), ), - )) + ), + Expanded( + flex: 1, + child: Container( + child: Icon( + icon, + size: 40, + ), + ), + ) ], ), - ) + ), + Expanded( + child: Container( + width: double.infinity, + child: Align( + alignment: Alignment.topRight, + child: Container( + margin: EdgeInsets.only(left: 5, right: 5), + child: RichText( + text: TextSpan( + style: TextStyle(color: Colors.black), + children: [ + TextSpan(text: lastVal), + TextSpan( + text: unit, + style: TextStyle( + color: HexColor('#B8382C'), + ), + ), + ]), + ), + ), + ), + ), + ), ], ), ), diff --git a/lib/screens/patients/profile/vital_sign/vital_sign_item_details_screen.dart b/lib/screens/patients/profile/vital_sign/vital_sign_item_details_screen.dart index 853bec15..5a2d4901 100644 --- a/lib/screens/patients/profile/vital_sign/vital_sign_item_details_screen.dart +++ b/lib/screens/patients/profile/vital_sign/vital_sign_item_details_screen.dart @@ -1 +1,195 @@ -import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart'; import 'package:doctor_app_flutter/screens/base/base_view.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; import 'package:doctor_app_flutter/widgets/shared/errors/dr_app_embedded_error.dart'; import 'package:flutter/material.dart'; import '../../../../lookups/patient_lookup.dart'; import '../../../../models/patient/vital_sign/vital_sign_res_model.dart'; import '../../../../screens/patients/profile/vital_sign/vital_sing_chart_and_detials.dart'; import '../../../../widgets/shared/app_scaffold_widget.dart'; /* *@author: Elham Rababah *@Date:03/6/2020 *@param: *@return: *@desc: VitalSignItemDetailsScreen */ class VitalSignItemDetailsScreen extends StatelessWidget { VitalSignItemDetailsScreen(); List vitalList = []; String pageTitle; @override Widget build(BuildContext context) { final routeArgs = ModalRoute.of(context).settings.arguments as Map; pageTitle = routeArgs['title']; var pageKey = routeArgs['key']; List VSchart; switch (pageKey) { case vitalSignDetails.bodyMeasurements: VSchart = [ { 'name': 'Highet', 'title1': 'Date', 'title2': 'Cm', 'viewKey': 'HeightCm', }, { 'name': 'Weight Kg', 'title1': 'Date', 'title2': 'Kg', 'viewKey': 'WeightKg', }, { 'name': 'BodyMassIndex', 'title1': 'Date', 'title2': 'BodyMass', 'viewKey': 'BodyMassIndex', }, { 'name': 'HeadCircumCm', 'title1': 'Date', 'title2': 'Cm', 'viewKey': 'HeadCircumCm', }, { 'name': 'Ideal Body Weight (Lbs)', 'title1': 'Date', 'title2': 'Ideal Weight', 'viewKey': 'IdealBodyWeightLbs', }, { 'name': 'LeanBodyWeightLbs (Lbs)', 'title1': 'Date', 'title2': 'Lean Weight', 'viewKey': 'LeanBodyWeightLbs', } ]; break; case vitalSignDetails.temperature: VSchart = [ { 'name': 'Temperature In Celcius', 'title1': 'Date', 'title2': 'C', 'viewKey': 'TemperatureCelcius', }, ]; break; case vitalSignDetails.pulse: VSchart = [ { 'name': 'Pulse Beat Per Minute', 'title1': 'Date', 'title2': 'Minute', 'viewKey': 'PulseBeatPerMinute', }, ]; break; case vitalSignDetails.pespiration: VSchart = [ { 'name': 'Respiration Beat Per Minute', 'title1': 'Date', 'title2': 'Beat Per Minute', 'viewKey': 'RespirationBeatPerMinute', }, ]; break; case vitalSignDetails.bloodPressure: VSchart = [ { 'name': 'Blood Pressure Higher', 'title1': 'Date', 'title2': 'Minute', 'viewKey': 'BloodPressureHigher', }, { 'name': 'Blood Pressure Lower', 'title1': 'Date', 'title2': 'Minute', 'viewKey': 'BloodPressureLower', } ]; break; case vitalSignDetails.oxygenation: VSchart = [ { 'name': 'FIO2', 'title1': 'Date', 'title2': 'Cm', 'viewKey': 'FIO2', }, { 'name': 'SAO2', 'title1': 'Date', 'title2': 'Cm', 'viewKey': 'SAO2', }, ]; break; case vitalSignDetails.painScale: VSchart = [ { 'name': 'PainScore', 'title1': 'Date', 'title2': 'Cm', 'viewKey': 'PainScore', }, ]; break; default: } return BaseView( onModelReady: (model) { vitalList = model.patientVitalSignOrderdSubList; }, builder: (_, model, w) => AppScaffold( baseViewModel: model, appBarTitle: pageTitle, body: ListView( children: VSchart.map((chartInfo) { var vitalListTemp = vitalList.where( (element) => element.toJson()[chartInfo['viewKey']] != null, ); return vitalListTemp.length != 0 ? VitalSingChartAndDetials( vitalList: vitalList, name: chartInfo['name'], title1: chartInfo['title1'], title2: chartInfo['title2'], viewKey: chartInfo['viewKey']) : Center( child: Container( margin: EdgeInsets.only( top: MediaQuery.of(context).size.height * 0.45), child: Center( child: DrAppEmbeddedError( error: TranslationBase.of(context).youDoNotHaveAnyItem), ), )); }).toList(), ), ), ); } } \ No newline at end of file +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/lookups/patient_lookup.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/vital_sign/vital_sing_chart_and_detials.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/vital_sign/vital_sing_chart_blood_pressure.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class VitalSignItemDetailsScreen extends StatelessWidget { + final vitalSignDetails pageKey; + final String pageTitle; + List VSchart; + + VitalSignItemDetailsScreen({this.vitalList, this.pageKey, this.pageTitle}); + + final List vitalList; + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + switch (pageKey) { + case vitalSignDetails.BodyMeasurements: + VSchart = [ + { + 'name': 'BMI', + 'nameAr': 'مؤشر الكتلة', + 'title1': 'Date', + 'title2': 'BMI', + 'title2Ar': 'الكتلة', + 'viewKey': 'BodyMassIndex', + }, + + ]; + + break; + + case vitalSignDetails.Temperature: + VSchart = [ + { + 'name': 'Temperature In Celsius', + 'nameAr': 'درجة الحرارة بالدرجة المئوية', + 'title1': 'Date', + 'title2': 'C', + 'title2Ar': 'ْس', + 'viewKey': 'TemperatureCelcius', + }, + ]; + + break; + case vitalSignDetails.Pulse: + VSchart = [ + { + 'name': 'Pulse Beat Per Minute', + 'nameAr': 'نبضة نبضة في الدقيقة', + 'title1': 'Date', + 'title2': 'Minute', + 'title2Ar': 'دقيقة', + 'viewKey': 'PulseBeatPerMinute', + }, + ]; + + break; + case vitalSignDetails.Prescriptions: + VSchart = [ + { + 'name': 'Respiration Beat Per Minute', + 'nameAr': 'ضربات التنفس في الدقيقة', + 'title1': 'Date', + 'title2': 'Beat Per Minute', + 'title2Ar': 'نفس في الدقيقة', + 'viewKey': 'RespirationBeatPerMinute', + }, + ]; + + break; + case vitalSignDetails.BloodPressure: + VSchart = [ + { + 'name': 'Blood Pressure Systolic Diastolic', + 'nameAr': 'ضغط الدم الإنقباض الإنبساط', + 'title1': 'Date', + 'title2': 'systolic', + 'title3': 'Diastolic', + 'title2Ar': 'الإنقباض', + 'title3Ar': 'الإنبساط', + 'viewKey': 'BloodPressure', + }, + + ]; + + break; + case vitalSignDetails.Respiration: + VSchart = [ + { + 'name': 'Respiration Rate', + 'nameAr': 'معدل التنفس', + 'title1': 'Date', + 'title2': 'bpm', + 'title2Ar': 'نفس', + 'viewKey': 'RespirationBeatPerMinute', + }, + ]; + + break; + case vitalSignDetails.heart: + VSchart = [ + { + 'name': 'Heart rate', + 'nameAr': 'معدل النبض بالدقيقة', + 'title1': 'Date', + 'title2': 'bpm', + 'title2Ar': 'نبضة', + 'viewKey': 'PulseBeatPerMinute', + }, + ]; + + break; + case vitalSignDetails.PainScale: + VSchart = [ + { + 'name': 'PainScore', + 'nameAr': 'نقاط الألم', + 'title1': 'Date', + 'title2': 'Cm', + 'title2Ar': 'سم', + 'viewKey': 'PainScore', + }, + ]; + + break; + case vitalSignDetails.Weight: + VSchart = [ + { + 'name': 'Weight Kg', + 'nameAr': 'الوزن كجم', + 'title1': 'Date', + 'title2': 'Kg', + 'title2Ar': 'كجم', + 'viewKey': 'WeightKg', + }, + ]; + + break; + + case vitalSignDetails.Height: + VSchart = [ + { + 'name': 'Height Cm', + 'nameAr': 'الطول سم', + 'title1': 'Date', + 'title2': 'Cm', + 'title2Ar': 'سم', + 'viewKey': 'HeightCm', + }, + ]; + + break; + default: + } + return AppScaffold( + appBarTitle: pageTitle, + isShowAppBar: true, + body: ListView( + children: VSchart.map((chartInfo) { + var vitalListTemp = vitalList.where( + (element) => element.toJson()[chartInfo['viewKey']] != null, + ); + + if(vitalListTemp.length != 0 && chartInfo['viewKey']=='BloodPressure'){ + return VitalSingChartBloodPressure( + vitalList: vitalList, + name:projectViewModel.isArabic? chartInfo['nameAr']:chartInfo['name'], + title1: chartInfo['title1'], + title2:projectViewModel.isArabic?chartInfo['title2Ar']: chartInfo['title2'], + title3:projectViewModel.isArabic?chartInfo['title3Ar']: chartInfo['title3'], + viewKey1: 'BloodPressureHigher', + viewKey2: 'BloodPressureLower', + + ); + } + + return vitalListTemp.length != 0 + ? VitalSingChartAndDetials( + vitalList: vitalList, + name:projectViewModel.isArabic? chartInfo['nameAr']:chartInfo['name'], + title1: chartInfo['title1'], + title2:projectViewModel.isArabic?chartInfo['title2Ar']: chartInfo['title2'], + viewKey: chartInfo['viewKey']) + : Container(); + }).toList(), + ), + ); + } +} diff --git a/lib/screens/patients/profile/vital_sign/vital_sing_chart_and_detials.dart b/lib/screens/patients/profile/vital_sign/vital_sing_chart_and_detials.dart index 7ae4937a..39b22073 100644 --- a/lib/screens/patients/profile/vital_sign/vital_sing_chart_and_detials.dart +++ b/lib/screens/patients/profile/vital_sign/vital_sing_chart_and_detials.dart @@ -1,16 +1,13 @@ -import 'package:doctor_app_flutter/models/patient/vital_sign/vital_sign_res_model.dart'; -import 'package:doctor_app_flutter/widgets/patients/vital_sign_details_wideget.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/vital_sign/vital_sign_details_wideget.dart'; +import 'package:doctor_app_flutter/widgets/charts/app_time_series_chart.dart'; import 'package:doctor_app_flutter/widgets/shared/app_expandable_notifier.dart'; -import 'package:doctor_app_flutter/widgets/shared/charts/app_time_series_chart.dart'; import 'package:flutter/material.dart'; -/* - *@author: Elham Rababah - *@Date:03/6/2020 - *@param: - *@return: - *@desc: VitalSingChartAndDetials - */ +import 'package:charts_flutter/flutter.dart' as charts; + +import 'LineChartCurved.dart'; + class VitalSingChartAndDetials extends StatelessWidget { VitalSingChartAndDetials({ Key key, @@ -21,30 +18,46 @@ class VitalSingChartAndDetials extends StatelessWidget { @required this.title2, }) : super(key: key); - final List vitalList; + final List vitalList; final String name; final String viewKey; final String title1; final String title2; + List timeSeriesData = []; @override Widget build(BuildContext context) { + generateData(); return Column( children: [ AppExpandableNotifier( - headerWid: AppTimeSeriesChart( + // isExpand: true, + headerWid: LineChartCurved(title: name,timeSeries:timeSeriesData,indexes: timeSeriesData.length~/5.5,), + bodyWid: VitalSignDetailsWidget( vitalList: vitalList, - chartName: name, + title1: title1, + title2: title2, viewKey: viewKey, ), - bodyWid: VitalSignDetailsWidget( - vitalList: vitalList.reversed.toList(), - title1: '${title1}', - title2: '${title2}', - viewKey: '${viewKey}', - ), ), ], ); } + + generateData() { + if (vitalList.length > 0) { + vitalList.reversed.toList().forEach( + (element) { + if( element.toJson()[viewKey]!=null && element.toJson()[viewKey]?.toInt()!=0) + timeSeriesData.add( + TimeSeriesSales2( + new DateTime(element.vitalSignDate.year, element.vitalSignDate.month, element.vitalSignDate.day), + element.toJson()[viewKey].toDouble(), + ), + ); + }, + ); + } + return timeSeriesData.reversed.toList(); + } } diff --git a/lib/screens/patients/profile/vital_sign/vital_sing_chart_blood_pressure.dart b/lib/screens/patients/profile/vital_sign/vital_sing_chart_blood_pressure.dart new file mode 100644 index 00000000..67390082 --- /dev/null +++ b/lib/screens/patients/profile/vital_sign/vital_sing_chart_blood_pressure.dart @@ -0,0 +1,84 @@ +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/vital_sign/vital_sign_details_blood_pressurewideget.dart'; +import 'package:doctor_app_flutter/widgets/charts/app_time_series_chart.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_expandable_notifier.dart'; +import 'package:flutter/material.dart'; + +import 'package:charts_flutter/flutter.dart' as charts; + +import 'LineChartCurved.dart'; +import 'LineChartCurvedBloodPressure.dart'; + +class VitalSingChartBloodPressure extends StatelessWidget { + VitalSingChartBloodPressure({ + Key key, + @required this.vitalList, + @required this.name, + @required this.viewKey1, + @required this.viewKey2, + @required this.title1, + @required this.title2, + @required this.title3, + }) : super(key: key); + + final List vitalList; + final String name; + final String viewKey1; + final String viewKey2; + final String title1; + final String title2; + final String title3; + List timeSeriesData1 = []; + List timeSeriesData2 = []; + + @override + Widget build(BuildContext context) { + generateData(); + return Column( + children: [ + AppExpandableNotifier( + // isExpand: true, + headerWid: LineChartCurvedBloodPressure( + title: name, + timeSeries1: timeSeriesData1, + timeSeries2: timeSeriesData2, + indexes: timeSeriesData1.length ~/ 5.5, + ), + bodyWid: VitalSignBloodPressureWidget( + vitalList: vitalList, + title1: title1, + title2: title2, + title3: title3, + viewKey1: viewKey1, + viewKey2: viewKey2, + ), + ), + ], + ); + } + + generateData() { + if (vitalList.length > 0) { + vitalList.reversed.toList().forEach( + (element) { + if (element.toJson()[viewKey1]?.toInt() != 0) + timeSeriesData1.add( + TimeSeriesSales2( + new DateTime(element.vitalSignDate.year, + element.vitalSignDate.month, element.vitalSignDate.day), + element.toJson()[viewKey1].toDouble(), + ), + ); + if (element.toJson()[viewKey2]?.toInt() != 0) + timeSeriesData2.add( + TimeSeriesSales2( + new DateTime(element.vitalSignDate.year, + element.vitalSignDate.month, element.vitalSignDate.day), + element.toJson()[viewKey2].toDouble(), + ), + ); + }, + ); + } + } +} diff --git a/lib/util/date-utils.dart b/lib/util/date-utils.dart index 5d651bad..df52b1fd 100644 --- a/lib/util/date-utils.dart +++ b/lib/util/date-utils.dart @@ -77,5 +77,138 @@ class DateUtils { int.parse(str.substring(startIndex + start.length, endIndex))); return differenceBetweenDateAndCurrent(date); } + + /// get month by + /// [weekDay] convert week day in int to week day name + static getWeekDay(int weekDay) { + switch (weekDay) { + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday "; + case 7: + return "Sunday"; + } + } + + /// get month by + /// [weekDay] convert week day in int to week day name arabic + static getWeekDayArabic(int weekDay) { + switch (weekDay) { + case 1: + return "الاثنين"; + case 2: + return "الثلاثاء"; + case 3: + return "الاربعاء"; + case 4: + return "الخميس"; + case 5: + return "الجمعه"; + case 6: + return "السبت "; + case 7: + return "الاحد"; + } + } + + /// get month by + /// [month] convert month number in to month name + static getMonth(int month) { + switch (month) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + } + } + + /// get month by + /// [month] convert month number in to month name in Arabic + static getMonthArabic(int month) { + switch (month) { + case 1: + return "يناير"; + case 2: + return " فبراير"; + case 3: + return "مارس"; + case 4: + return "أبريل"; + case 5: + return "مايو"; + case 6: + return "يونيو"; + case 7: + return "يوليو"; + case 8: + return "أغسطس"; + case 9: + return "سبتمبر"; + case 10: + return " اكتوبر"; + case 11: + return " نوفمبر"; + case 12: + return "ديسمبر"; + } + } + + static getMonthByName(String month) { + switch (month.toLowerCase()) { + case 'january': + return 1; + case 'february': + return 2; + case 'march': + return 3; + case 'april': + return 4; + case 'may': + return 5; + case 'june': + return 6; + case 'july': + return 7; + case 'august': + return 8; + case 'september': + return 9; + case 'october': + return 10; + case 'november': + return 11; + case 'december': + return 12; + } + } } diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index c5723402..284712cb 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -560,6 +560,9 @@ class TranslationBase { String get addExamination => localizedValues['addExamination'][locale.languageCode]; String get doc => localizedValues['doc'][locale.languageCode]; String get patientNoDetailErrMsg => localizedValues['patientNoDetailErrMsg'][locale.languageCode]; + String get systolicLng => localizedValues['systolic-lng'][locale.languageCode]; + String get diastolicLng => localizedValues['diastolic-lng'][locale.languageCode]; + } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/charts/app_bar_chart.dart b/lib/widgets/charts/app_bar_chart.dart new file mode 100644 index 00000000..98ef3cfa --- /dev/null +++ b/lib/widgets/charts/app_bar_chart.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:charts_flutter/flutter.dart' as charts; + +class AppBarChart extends StatelessWidget { + const AppBarChart({ + Key key, + @required this.seriesList, + }) : super(key: key); + + final List seriesList; + + @override + Widget build(BuildContext context) { + return Container( + height: 400, + margin: EdgeInsets.only(top: 60), + child: charts.BarChart( + seriesList, + // animate: animate, + + /// Customize the primary measure axis using a small tick renderer. + /// Use String instead of num for ordinal domain axis + /// (typically bar charts). + primaryMeasureAxis: new charts.NumericAxisSpec( + renderSpec: new charts.GridlineRendererSpec( + // Display the measure axis labels below the gridline. + // + // 'Before' & 'after' follow the axis value direction. + // Vertical axes draw 'before' below & 'after' above the tick. + // Horizontal axes draw 'before' left & 'after' right the tick. + labelAnchor: charts.TickLabelAnchor.before, + + // Left justify the text in the axis. + // + // Note: outside means that the secondary measure axis would right + // justify. + labelJustification: + charts.TickLabelJustification.outside, + )), + ), + ); + } +} diff --git a/lib/widgets/charts/app_line_chart.dart b/lib/widgets/charts/app_line_chart.dart new file mode 100644 index 00000000..553afec8 --- /dev/null +++ b/lib/widgets/charts/app_line_chart.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:charts_flutter/flutter.dart' as charts; + +/// chart line +/// [seriesList] charts series +/// [chartTitle] the charts title +/// [animate] enable and disable animate on create chart +/// [includeArea] chart include Area +/// [stacked] stacked chart over the design +class AppLineChart extends StatelessWidget { + final List seriesList; + final String chartTitle; + final bool animate; + final bool includeArea; + final bool stacked; + + AppLineChart( + {Key key, + @required this.seriesList, + this.chartTitle, + this.animate = true, + this.includeArea = false, + this.stacked = true}); + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Text( + chartTitle, + style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold), + ), + Expanded( + child: charts.LineChart(seriesList, + defaultRenderer: charts.LineRendererConfig( + includeArea: false, stacked: true), + animate: animate), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/charts/app_time_series_chart.dart b/lib/widgets/charts/app_time_series_chart.dart new file mode 100644 index 00000000..670284a1 --- /dev/null +++ b/lib/widgets/charts/app_time_series_chart.dart @@ -0,0 +1,71 @@ +import 'package:charts_flutter/flutter.dart' as charts; +import 'package:charts_flutter/flutter.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/widgets/data_display/list/flexible_container.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; + +/// App Time Series Chart +/// [seriesList] the series list +/// [chartName] the name of the chart +/// [startDate] the start date +/// [endDate] the end date +class AppTimeSeriesChart extends StatelessWidget { + AppTimeSeriesChart({ + Key key, + @required this.seriesList, + this.chartName = '', + this.startDate, + this.endDate, + }); + + final String chartName; + final List> seriesList; + final DateTime startDate; + final DateTime endDate; + + @override + Widget build(BuildContext context) { + return FlexibleContainer( + heightFactor: 0.47, + child: Column( + children: [ + AppText(chartName, fontSize: SizeConfig.textMultiplier * 3), + Container( + height: SizeConfig.realScreenHeight * 0.37, + child: Center( + child: Container( + child: charts.TimeSeriesChart( + seriesList, + animate: true, + behaviors: [ + charts.RangeAnnotation( + [ + charts.RangeAnnotationSegment(startDate, endDate, + charts.RangeAnnotationAxisType.domain ), + ], + ), + ], + ), + ), + ), + ), + ], + ), + ); + } +} + +class TimeSeriesSales { + final DateTime time; + final int sales; + + TimeSeriesSales(this.time, this.sales); +} + +class TimeSeriesSales2 { + final DateTime time; + final double sales; + + TimeSeriesSales2(this.time, this.sales); +} diff --git a/lib/widgets/data_display/list/custom_Item.dart b/lib/widgets/data_display/list/custom_Item.dart new file mode 100644 index 00000000..c11af999 --- /dev/null +++ b/lib/widgets/data_display/list/custom_Item.dart @@ -0,0 +1,93 @@ +import 'package:eva_icons_flutter/eva_icons_flutter.dart'; +import 'package:flutter/material.dart'; + +/// Custom Item widget +/// [startIcon] icon at the start of the widget +/// [startIconSize] icon size of start icon +/// [startIconColor] icon color of start icon +/// [endIcon] icon at the end of the widget +/// [endIconSize] icon size of end icon +/// [endIconColor] icon color of end icon +/// [disabled] disabled on tap function +/// [onTap] opTap function +/// [padding] padding of the widget +/// [child] child of the widget +/// [decoration] decoration of the widget +class CustomItem extends StatelessWidget { + final IconData startIcon; + final double startIconSize; + final Color startIconColor; + final IconData endIcon; + final double endIconSize; + final Color endIconColor; + final bool disabled; + final Function onTap; + final EdgeInsets padding; + final Widget child; + final BoxDecoration decoration; + + CustomItem( + {Key key, + this.startIcon, + this.disabled: false, + this.onTap, + this.startIconColor, + this.endIcon = EvaIcons.chevronRight, + this.padding, + this.child, + this.endIconColor, + this.endIconSize = 20, + this.decoration, + this.startIconSize = 19}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return IgnorePointer( + ignoring: disabled, + child: Container( + decoration: decoration != null ? decoration : BoxDecoration(), + child: InkWell( + onTap: () { + if (onTap != null) onTap(); + }, + child: Padding( + padding: padding != null + ? padding + : const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), + child: Row( + children: [ + if (startIcon != null) + Expanded( + flex: 1, + child: Icon( + startIcon, + color: startIconColor ?? Theme.of(context).primaryColor, + size: startIconSize, + ), + ), + if (startIcon != null) SizedBox(width: 18.0), + Expanded( + child: child, + flex: 10, + ), + endIcon == null + ? Expanded(child: Container()) + : Expanded( + flex: 1, + child: Icon( + endIcon, + color: endIconColor != null + ? endIconColor + : Colors.grey[500], + size: endIconSize, + ), + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/data_display/list/flexible_container.dart b/lib/widgets/data_display/list/flexible_container.dart new file mode 100644 index 00000000..a35fa279 --- /dev/null +++ b/lib/widgets/data_display/list/flexible_container.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +/// Flexible container widget +/// [widthFactor] If non-null, the fraction of the incoming width given to the child. +/// If non-null, the child is given a tight width constraint that is the max +/// incoming width constraint multiplied by this factor. +/// If null, the incoming width constraints are passed to the child + +/// [heightFactor]If non-null, the fraction of the incoming height given to the child. +/// If non-null, the child is given a tight height constraint that is the max +/// incoming height constraint multiplied by this factor. +/// If null, the incoming height constraints are passed to the child +/// [padding] add padding to the container +/// [child] child widget inside the container +class FlexibleContainer extends StatelessWidget { + final double widthFactor; + final double heightFactor; + final EdgeInsets padding; + final Widget child; + + FlexibleContainer({ + Key key, + this.widthFactor = 0.9, + this.heightFactor = 1, + this.padding, + this.child, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( +// widthFactor: widthFactor, +// heightFactor: heightFactor, + child: ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: Material( + color: Theme.of(context).backgroundColor, + child: Container( + padding: padding, + width: double.infinity, + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context).dividerColor, width: 2.0), + borderRadius: BorderRadius.circular(8.0)), + child: child, + ), + ), + ), + ); + } +} diff --git a/lib/widgets/patients/profile/profile_medical_info_widget.dart b/lib/widgets/patients/profile/profile_medical_info_widget.dart index 19989ecd..52f2ea47 100644 --- a/lib/widgets/patients/profile/profile_medical_info_widget.dart +++ b/lib/widgets/patients/profile/profile_medical_info_widget.dart @@ -70,12 +70,13 @@ class ProfileMedicalInfoWidget extends StatelessWidget { .episode, route: UPDATE_EPISODE, icon: 'modilfy-episode.png'), + if(int.parse(patientType) ==7) PatientProfileButton( key: key, patient: patient, nameLine1: TranslationBase.of(context).vital, nameLine2: TranslationBase.of(context).signs, - route: (selectedPatientType == 6 || selectedPatientType == 7) ? PATIENT_VITAL_SIGN : VITAL_SIGN_DETAILS, + route: PATIENT_VITAL_SIGN, icon: 'heartbeat.png'), if(selectedPatientType != 7) PatientProfileButton( diff --git a/lib/widgets/transitions/fade_page.dart b/lib/widgets/transitions/fade_page.dart new file mode 100644 index 00000000..97a37ce1 --- /dev/null +++ b/lib/widgets/transitions/fade_page.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +/// FadePage animation +/// [page] +class FadePage extends PageRouteBuilder { + final Widget page; + FadePage({this.page}) + : super( + opaque: false, + fullscreenDialog: true, + barrierDismissible: true, + barrierColor: Colors.black.withOpacity(0.8), + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) => + page, + transitionDuration: Duration(milliseconds: 300), + transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) { + return FadeTransition( + opacity: animation, + child: child + ); + } + ); +} \ No newline at end of file diff --git a/lib/widgets/transitions/slide_up_page.dart b/lib/widgets/transitions/slide_up_page.dart new file mode 100644 index 00000000..2c138b9e --- /dev/null +++ b/lib/widgets/transitions/slide_up_page.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +///Slide Up Page Route +/// [widget] widget we need to slide up +/// [fullscreenDialog] show the widget as full screen dialog +/// [opaque] When an opaque route's entrance transition is complete, the routes behind the opaque route will not be built to save resources. +class SlideUpPageRoute extends PageRouteBuilder { + final Widget widget; + final bool fullscreenDialog; + final bool opaque; + + SlideUpPageRoute( + {this.widget, this.fullscreenDialog = false, this.opaque = true}) + : super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) { + return widget; + }, + fullscreenDialog: fullscreenDialog, + opaque: opaque, + barrierColor: Color.fromRGBO(0, 0, 0, 0.5), + barrierDismissible: true, + transitionDuration: Duration(milliseconds: 800), + transitionsBuilder: ((BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child) { + var begin = Offset(0.0, 1.0); + var end = Offset.zero; + var curve = Curves.easeInOutQuint; + + var tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), child: child); + }), + ); +} diff --git a/pubspec.lock b/pubspec.lock index 2ad55e08..0d5ec4e8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -70,7 +70,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "1.6.0" + version: "1.6.1" build_config: dependency: transitive description: @@ -84,35 +84,35 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.6" build_modules: dependency: transitive description: name: build_modules url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.0.3" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "1.5.1" + version: "1.5.2" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.10.11" + version: "1.10.13" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.5" + version: "6.1.6" build_web_compilers: dependency: "direct dev" description: @@ -189,7 +189,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.5.0" + version: "3.6.0" collection: dependency: transitive description: @@ -281,6 +281,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + equatable: + dependency: transitive + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.5" eva_icons_flutter: dependency: "direct main" description: @@ -323,6 +330,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.10.11" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.2" flutter: dependency: "direct main" description: flutter @@ -468,7 +482,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3-nullsafety.1" + version: "0.6.2" json_annotation: dependency: transitive description: @@ -553,6 +567,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0-nullsafety.1" + path_drawing: + dependency: transitive + description: + name: path_drawing + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.1+1" + path_parsing: + dependency: transitive + description: + name: path_parsing + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" path_provider_linux: dependency: transitive description: @@ -650,7 +678,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "4.3.2+3" + version: "4.3.2+4" pub_semver: dependency: transitive description: @@ -678,7 +706,7 @@ packages: name: scratch_space url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+2" + version: "0.0.4+3" shared_preferences: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2a9f2e73..aba2d876 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,9 @@ dependencies: #Dependency Injection get_it: ^4.0.2 + #chart + fl_chart: ^0.12.1 + #GIF image flutter_gifimage: ^1.0.1