Compare commits

...

20 Commits

Author SHA1 Message Date
Syed Taha Alam 2824abcc87 WD: lab result changed.
* value to show graph is changed and from type to resultID if it is null or 6 then it will not be visible.
* list reversed for showing the graph and lab results.
* actual value is being displayed on the spots clicked.
7 months ago
Syed Taha Alam 656d8dd6b4 Wd: Full portrait graph added. 7 months ago
Syed Taha Alam c09170b506 Wd: Lab result graph completed. 7 months ago
Syed Taha Alam 5461d78a1b Wd: graph added with the threshold 7 months ago
Syed Taha Alam e79c521ea9 Wd: Result type id 5 is toggle the visibility of the graph of the lab result screen. 8 months ago
haroon amjad dbfe9663a5 Merge branch 'dev_v3.13.6' into dev_v3.13.6_CR_7211_Lab_report_changes
# Conflicts:
#	lib/config/config.dart
#	lib/config/localized_values.dart
#	lib/uitl/translations_delegate_base.dart
#	lib/widgets/data_display/medical/LabResult/laboratory_result_widget.dart
#	pubspec.yaml
9 months ago
taha.alam 2c5ed4ffe7 WD:button color changed 1 year ago
taha.alam fa1bb291b9 WD: issues fixed of description not showing 1 year ago
taha.alam eba3ab2cf8 Merge branch 'dev_v3.13.6' of http://34.17.52.180/Haroon6138/diplomatic-quarter into dev_v3.13.6_CR_7211_Lab_report_changes
# Conflicts:
#	lib/config/config.dart
#	lib/core/viewModels/medical/labs_view_model.dart
#	lib/uitl/translations_delegate_base.dart
#	lib/widgets/data_display/medical/LabResult/laboratory_result_widget.dart
#	lib/widgets/new_design/doctor_header.dart
1 year ago
taha.alam eafb7f5f7b WD: lab report changes along with the cross added to the FlowChartPage.dart 1 year ago
taha.alam 636a67b720 WD: lab result changes of IRR. 1 year ago
taha.alam 9047ebf723 Merge branch 'dev_v3.13.6' of http://34.17.52.180/Haroon6138/diplomatic-quarter into dev_v3.13.6_CR_7211_Lab_report_changes
# Conflicts:
#	android/app/build.gradle
#	android/app/src/main/AndroidManifest.xml
#	android/build.gradle
#	android/gradle.properties
#	android/settings.gradle
#	lib/config/localized_values.dart
#	lib/pages/medical/labs/laboratory_result_page.dart
#	lib/uitl/translations_delegate_base.dart
#	lib/widgets/data_display/medical/LabResult/Lab_Result_details_wideget.dart
#	lib/widgets/data_display/medical/LabResult/laboratory_result_widget.dart
#	pubspec.yaml
1 year ago
taha.alam fa87e74b02 WD: Border Added for the directional for multilingual 1 year ago
taha.alam 4c4ae6caef WD: Translation of words added and download button added 1 year ago
taha.alam 3d27fbdea8 WD: lab report changes 1 year ago
Aamir 3d2e0a5442 cr 7211 lab report new ui changes 1 year ago
Aamir b74a433798 cr 7211 lab report new ui changes 1 year ago
Aamir 0f0b541563 Merge remote-tracking branch 'origin/dev_v3.13.6' into dev_v3.13.6 1 year ago
Aamir 45bc6a91a4 Merge remote-tracking branch 'origin/dev_v3.13.6' into dev_v3.13.6
# Conflicts:
#	android/app/build.gradle
1 year ago
Aamir da3e266989 local 1 year ago

@ -55,7 +55,7 @@ configurations.all {
android {
compileSdkVersion 34
// ndkVersion "24.0.8215888"
namespace = "com.ejada.hmg"
buildFeatures {
viewBinding true
dataBinding true
@ -133,7 +133,7 @@ android {
compileOptions {
// coreLibraryDesugaringEnabled true
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -147,7 +147,7 @@ flutter {
}
dependencies {
// coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.google.firebase:firebase-messaging:21.0.0"

@ -1,7 +0,0 @@
#Sun Sep 20 09:53:06 EEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
#distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

@ -5,4 +5,4 @@
# For customization when using a Version Control System, please read the
# header note.
#Sun Sep 20 09:53:03 EEST 2020
sdk.dir=/Users/erababah/Library/Android/sdk
sdk.dir=/Users/amir/Library/Android/sdk

@ -1,5 +1,7 @@
buildscript {
ext.kotlin_version = '1.8.0'
ext.kotlin_version = '1.9.23'
ext.anko_version='0.10.8'
// if (System.properties['os.arch'] == "aarch64") {
// // For M1 Users we need to use the NDK 24 which added support for aarch64
@ -48,6 +50,7 @@ buildscript {
}
}
allprojects {
repositories {
google()
@ -77,6 +80,18 @@ allprojects {
}
}
}
subprojects {
afterEvaluate { project ->
if (project.hasProperty('android')) {
project.android {
if (namespace == null) {
namespace project.group
}
}
}
}
}
}
rootProject.buildDir = '../build'
@ -87,10 +102,14 @@ subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
configurations.all {
resolutionStrategy {
force 'androidx.core:core-ktx:1.6.0'

@ -2,7 +2,9 @@ org.gradle.jvmargs=-Xmx4096m
#android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.suppressUnsupportedCompileSdk=33
MAPBOX_USER_NAME = "mapbox"
MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
#MAPBOX_DOWNLOADS_TOKEN="pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ"
#MAPBOX_DOWNLOADS_TOKEN="pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ"
kotlin.jvm.target.validation.mode=IGNORE

@ -1,6 +1,6 @@
#Wed Jul 14 15:55:18 AST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

@ -1,17 +1,28 @@
include ':app'
include ':vital-sign-engine'
project(':vital-sign-engine').projectDir = new File('/Users/mohamedmekawy/Documents/Work/DiplomaticQuarter_3.16/packages/vital_sign_camera/android/libs')
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '8.1.0' apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
id "com.google.protobuf" version "0.9.1" apply false
}
include ":app"

@ -0,0 +1,4 @@
<svg height="1792" id="download" width="1792" xmlns="http://www.w3.org/2000/svg">
<path
d="M1344 1344q0-26-19-45t-45-19-45 19-19 45 19 45 45 19 45-19 19-45zm256 0q0-26-19-45t-45-19-45 19-19 45 19 45 45 19 45-19 19-45zm128-224v320q0 40-28 68t-68 28H160q-40 0-68-28t-28-68v-320q0-40 28-68t68-28h465l135 136q58 56 136 56t136-56l136-136h464q40 0 68 28t28 68zm-325-569q17 41-14 70l-448 448q-18 19-45 19t-45-19L403 621q-31-29-14-70 17-39 59-39h256V64q0-26 19-45t45-19h256q26 0 45 19t19 45v448h256q42 0 59 39z"></path>
</svg>

After

Width:  |  Height:  |  Size: 531 B

@ -0,0 +1,5 @@
<svg id="Download" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path
class="color000000 svgShape"
d="M1344 1344q0-26-19-45t-45-19-45 19-19 45 19 45 45 19 45-19 19-45zm256 0q0-26-19-45t-45-19-45 19-19 45 19 45 45 19 45-19 19-45zm128-224v320q0 40-28 68t-68 28H160q-40 0-68-28t-28-68v-320q0-40 28-68t68-28h465l135 136q58 56 136 56t136-56l136-136h464q40 0 68 28t28 68zm-325-569q17 41-14 70l-448 448q-18 19-45 19t-45-19L403 621q-31-29-14-70 17-39 59-39h256V64q0-26 19-45t45-19h256q26 0 45 19t19 45v448h256q42 0 59 39z" fill="#ffffff"></path>
</svg>

After

Width:  |  Height:  |  Size: 580 B

@ -2141,6 +2141,15 @@ const Map localizedValues = {
"EROnlineCheckInTapOnCheckIn": {"en": "Tap on the check-in button within the app", "ar": "اضغط على زر تسجيل الدخول داخل التطبيق"},
"download": {"en": "Download", "ar": "تحميل"},
"share": {"en": "Share", "ar": "يشارك"},
"readMore": {"en": "Read More", "ar": "اقرأ أكثر"},
"showLess": {"en": "Show Less", "ar": "عرض أقل"},
"change": {"en": "Change", "ar": "فرق"},
"referenceRange": {"en": "Reference Range", "ar": "النطاق المرجعي"},
"criticalLow": {"en": "Critical Low", "ar": "النطاق المرجعي"},
"criticalHigh": {"en": "Critical High", "ar": "حرج مرتفع"},
"high": {"en": "High", "ar": "مرتفع"},
"normal": {"en": "Normal", "ar": "عادي"},
"low": {"en": "Low", "ar": "منخفض"},
"nearest": {"en": "Nearest", "ar": "الأقرب"},
"selectRegion": {"en": "Select Region", "ar": "اختر المنطقة"},
"selectFacitlity": {"en": "Select Facility", "ar": "اختر المنشأة"},
@ -2327,4 +2336,6 @@ const Map localizedValues = {
"liveCareTermsConditions47": {"en": "Our Telehealth Services will be for specific medical specialties or follow-up or medication refill appointments.", "ar": "خدمات الرعاية الصحية عن بُعد الخاصة بنا سوف تكون لتخصصات طبية محددة أو لمواعيد المتابعة أو إعادة صرف الدواء. "},
"liveCareTermsConditions48": {"en": "If you have any complaints or concerns about the Application and or the Website, Our Services, or how we handle your personal information please contact us on: EServices.HMG@drsulaimanalhabib.com or call 011 525 9553", "ar": "إذا كانت لديك أي شكاوى أو مخاوف بشأن التطبيق و/أو موقع الويب أو خدماتنا أو كيفية تعاملنا مع معلوماتك الشخصية، فيرجى التواصل معنا على: EServices.HMG@drsulaimanalhabib.com أو الاتصال على الرقم: 9553 525 011"},
"clickPrivacyPolicy": {"en": "Please click here to view the privacy policy", "ar": "الرجاء الضغط هنا لعرض سياسة الخصوصية"},
"thisResult" : {"en": "This Result", "ar": "هذه النتيجة"},
"seeAllGraphValues" : {"en": "See all values", "ar": "شاهد جميع القيم"},
};

@ -18,6 +18,12 @@ class LabOrderResult {
String? uOM;
String? verifiedOn;
String? verifiedOnDateTime;
String? changeResult;
String? calculatedResultFlag;
String? criticalHigh;
String? referenceHigh;
String? criticalLow;
String? referenceLow;
LabOrderResult(
{this.description,
@ -38,7 +44,13 @@ class LabOrderResult {
this.testCode,
this.uOM,
this.verifiedOn,
this.verifiedOnDateTime});
this.calculatedResultFlag,
this.verifiedOnDateTime,
this.criticalHigh,
this.referenceHigh,
this.criticalLow,
this.referenceLow,
});
LabOrderResult.fromJson(Map<String, dynamic> json) {
description = json['Description'];
@ -60,6 +72,12 @@ class LabOrderResult {
uOM = json['UOM'];
verifiedOn = json['VerifiedOn'];
verifiedOnDateTime = json['VerifiedOnDateTime'];
changeResult = json['ChangeResult'];
calculatedResultFlag = json['CalculatedResultFlag'];
criticalHigh = json['CriticalHigh'];
referenceHigh = json['ReferenceHigh'];
criticalLow = json['CriticalLow'];
referenceLow = json['ReferenceLow'];
}
Map<String, dynamic> toJson() {
@ -83,6 +101,16 @@ class LabOrderResult {
data['UOM'] = this.uOM;
data['VerifiedOn'] = this.verifiedOn;
data['VerifiedOnDateTime'] = this.verifiedOnDateTime;
data['ChangeResult'] = this.changeResult;
data['CriticalHigh'] = this.criticalHigh;
data['ReferenceHigh'] = this.referenceHigh;
data['CriticalLow'] = this.criticalLow;
data['ReferenceLow'] = this.referenceLow;
return data;
}
@override
String toString() {
return 'LabOrderResult(flag: $calculatedResultFlag, value: $resultValue, verifiedOn: $verifiedOnDateTime)';
}
}

@ -1,12 +1,96 @@
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/newUI/labWidgets.dart';
class LabResultList {
String? filterName = "";
String? description = "";
List<LabResult>? patientLabResultList = [];
LabResultList({this.filterName, LabResult? lab}) {
LabResultList({this.filterName, this.description, LabResult? lab}) {
patientLabResultList!.add(lab!);
}
}
enum ResultFlag {
N('normal'),
H('high'),
L('low'),
CL('criticalLow'),
CH('criticalHigh'),
HCH('highCriticalHigh'),
LCL('lowCriticalLow'),
IRR('interpretive');
final String value;
const ResultFlag(this.value);
static ResultFlag? fromJson(String key, num? resultValueFlag) {
// if(resultValueFlag == null) return ResultFlag.IRR;
// if(resultValueFlag == 5) return ResultFlag.IRR;
switch (key) {
case 'N':
return ResultFlag.N;
case 'H':
return ResultFlag.H;
case 'L':
return ResultFlag.L;
case 'CL':
return ResultFlag.CL;
case 'CH':
return ResultFlag.CH;
case 'HCH':
return ResultFlag.HCH;
case 'LCL':
return ResultFlag.LCL;
case '':
return ResultFlag.IRR;
default:
return null;
}
}
String toJson() {
switch (this) {
case ResultFlag.N:
return 'N';
case ResultFlag.H:
return 'H';
case ResultFlag.L:
return 'L';
case ResultFlag.CL:
return 'CL';
case ResultFlag.CH:
return 'CH';
case ResultFlag.HCH:
return 'HCH';
case ResultFlag.LCL:
return 'LCL';
case ResultFlag.IRR:
return '';
}
}
ResultTypes getType() {
switch (this) {
case ResultFlag.N:
return ResultTypes.normal;
case ResultFlag.H:
return ResultTypes.high;
case ResultFlag.L:
return ResultTypes.low;
case ResultFlag.CL:
return ResultTypes.criticalLow;
case ResultFlag.CH:
return ResultTypes.criticalHigh;
case ResultFlag.HCH:
return ResultTypes.highCriticalHigh;
case ResultFlag.LCL:
return ResultTypes.lowCriticalLow;
case ResultFlag.IRR:
return ResultTypes.IRR;
}
}
}
class LabResult {
String? description;
dynamic femaleInterpretativeData;
@ -31,7 +115,14 @@ class LabResult {
String? testCode;
String? uOM;
String? verifiedOn;
String? packageShortDescription;
String? testShortDescription;
ResultFlag? calculatedResultFlag;
dynamic verifiedOnDateTime;
num? percentage;
num? width;
num? resultTypeID;
LabResult(
{this.description,
@ -59,7 +150,7 @@ class LabResult {
this.verifiedOn,
this.verifiedOnDateTime});
LabResult.fromJson(Map<String, dynamic> json) {
LabResult.fromJson(Map<String, dynamic> json, {String? flag}) {
description = json['Description'];
femaleInterpretativeData = json['FemaleInterpretativeData'];
gender = json['Gender'];
@ -84,6 +175,11 @@ class LabResult {
uOM = json['UOM'];
verifiedOn = json['VerifiedOn'];
verifiedOnDateTime = json['VerifiedOnDateTime'];
packageShortDescription = json['PackageShortDescription'];
testShortDescription = json['TestShortDescription'];
resultTypeID = json['ResultTypeID'];
calculatedResultFlag =
ResultFlag.fromJson(flag ?? json['CalculatedResultFlag'],resultTypeID);
}
Map<String, dynamic> toJson() {
@ -112,6 +208,17 @@ class LabResult {
data['UOM'] = this.uOM;
data['VerifiedOn'] = this.verifiedOn;
data['VerifiedOnDateTime'] = this.verifiedOnDateTime;
data['PackageShortDescription'] = this.packageShortDescription;
data['TestShortDescription'] = this.testShortDescription;
data['CalculatedResultFlag'] = this.calculatedResultFlag?.toJson() ?? '';
return data;
}
bool shouldShowResultBarAndGraph() {
if(resultTypeID == null) return false;
if(resultTypeID == 6) return false;
return true;
}
}

@ -187,8 +187,8 @@ class BaseAppClient {
// body['IdentificationNo'] = 1023854217;
// body['MobileNo'] = "531940021"; //0560717232
// body['PatientID'] = 5690832; //4609100
// body['TokenID'] = "@dm!n";
body['PatientID'] = 1231755; //4609100
body['TokenID'] = "@dm!n";
// Patient ID: 3027574
// Mobile no.: 0502303285

@ -1,3 +1,5 @@
import 'dart:ui';
import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/core/model/labs/LabOrderResult.dart';
import 'package:diplomaticquarterapp/core/model/labs/lab_result.dart';
@ -7,6 +9,8 @@ import 'package:diplomaticquarterapp/core/model/labs/request_patient_lab_special
import 'package:diplomaticquarterapp/core/model/labs/request_send_lab_report_email.dart';
import 'package:diplomaticquarterapp/core/service/base_service.dart';
import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/lab_result_graph.dart';
class LabsService extends BaseService {
List<PatientLabOrders> patientLabOrdersList = [];
@ -17,7 +21,8 @@ class LabsService extends BaseService {
hasError = false;
Map<String, dynamic> body = Map();
body['isDentalAllowedBackend'] = false;
await baseAppClient.post(GET_Patient_LAB_ORDERS, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(GET_Patient_LAB_ORDERS,
onSuccess: (dynamic response, int statusCode) {
patientLabOrdersList.clear();
response['ListPLO'].forEach((hospital) {
patientLabOrdersList.add(PatientLabOrders.fromJson(hospital));
@ -28,13 +33,21 @@ class LabsService extends BaseService {
}, body: body);
}
RequestPatientLabSpecialResult _requestPatientLabSpecialResult = RequestPatientLabSpecialResult();
RequestPatientLabSpecialResult _requestPatientLabSpecialResult =
RequestPatientLabSpecialResult();
List<PatientLabSpecialResult> patientLabSpecialResult = [];
List<LabResult> labResultList = [];
List<LabOrderResult> labOrdersResultsList = [];
Future getLaboratoryResult({String? projectID, int? clinicID, String? invoiceNo, String? invoiceType, String? orderNo, String? setupID, bool? isVidaPlus}) async {
Future getLaboratoryResult(
{String? projectID,
int? clinicID,
String? invoiceNo,
String? invoiceType,
String? orderNo,
String? setupID,
bool? isVidaPlus}) async {
hasError = false;
_requestPatientLabSpecialResult.projectID = projectID;
_requestPatientLabSpecialResult.clinicID = clinicID;
@ -47,7 +60,8 @@ class LabsService extends BaseService {
_requestPatientLabSpecialResult.orderNo = orderNo;
_requestPatientLabSpecialResult.setupID = setupID;
await baseAppClient.post(GET_Patient_LAB_SPECIAL_RESULT, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(GET_Patient_LAB_SPECIAL_RESULT,
onSuccess: (dynamic response, int statusCode) {
patientLabSpecialResult.clear();
response['ListPLSR'].forEach((hospital) {
patientLabSpecialResult.add(PatientLabSpecialResult.fromJson(hospital));
@ -58,7 +72,8 @@ class LabsService extends BaseService {
}, body: _requestPatientLabSpecialResult.toJson());
}
Future getPatientLabResult({PatientLabOrders? patientLabOrder, bool? isVidaPlus}) async {
Future getPatientLabResult(
{PatientLabOrders? patientLabOrder, bool? isVidaPlus}) async {
hasError = false;
Map<String, dynamic> body = Map();
body['InvoiceNo_VP'] = isVidaPlus! ? patientLabOrder!.invoiceNo : "0";
@ -69,11 +84,14 @@ class LabsService extends BaseService {
body['SetupID'] = patientLabOrder.setupID;
body['ProjectID'] = patientLabOrder.projectID;
body['ClinicID'] = patientLabOrder.clinicID;
await baseAppClient.post(GET_Patient_LAB_RESULT, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(GET_Patient_LAB_RESULT,
onSuccess: (dynamic response, int statusCode) {
patientLabSpecialResult.clear();
labResultList.clear();
response['ListPLR'].forEach((lab) {
labResultList.add(LabResult.fromJson(lab));
labResultList.add(
LabResult.fromJson(lab),
);
});
}, onFailure: (String error, int statusCode) {
hasError = true;
@ -81,7 +99,8 @@ class LabsService extends BaseService {
}, body: body);
}
Future generateCovidLabReport(LabResult covidLabResult, String isOutsideKSA) async {
Future generateCovidLabReport(
LabResult covidLabResult, String isOutsideKSA) async {
hasError = false;
Map<String, dynamic> body = Map();
@ -98,7 +117,8 @@ class LabsService extends BaseService {
dynamic localRes;
await baseAppClient.post(SEND_COVID_LAB_RESULT_EMAIL, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(SEND_COVID_LAB_RESULT_EMAIL,
onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
@ -115,7 +135,8 @@ class LabsService extends BaseService {
dynamic localRes;
await baseAppClient.post(COVID_PASSPORT_UPDATE, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(COVID_PASSPORT_UPDATE,
onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
@ -124,7 +145,14 @@ class LabsService extends BaseService {
return Future.value(localRes);
}
Future updateWorkplaceName(String workplaceName, String workplaceNameAR, String occupation, String occupationAR, int requestNumber, String setupID, int projectID) async {
Future updateWorkplaceName(
String workplaceName,
String workplaceNameAR,
String occupation,
String occupationAR,
int requestNumber,
String setupID,
int projectID) async {
// Future updateWorkplaceName(String workplaceName, String workplaceNameAR, int requestNumber, String setupID, int projectID) async {
hasError = false;
Map<String, dynamic> body = Map();
@ -141,7 +169,8 @@ class LabsService extends BaseService {
dynamic localRes;
await baseAppClient.post(UPDATE_WORKPLACE_NAME, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(UPDATE_WORKPLACE_NAME,
onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
@ -156,7 +185,8 @@ class LabsService extends BaseService {
dynamic localRes;
await baseAppClient.post(GET_PATIENT_PASSPORT_NUMBER, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(GET_PATIENT_PASSPORT_NUMBER,
onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
@ -174,7 +204,8 @@ class LabsService extends BaseService {
dynamic localRes;
await baseAppClient.post(GET_SICKLEAVE_STATUS_ADMISSION_NO, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(GET_SICKLEAVE_STATUS_ADMISSION_NO,
onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
@ -183,7 +214,10 @@ class LabsService extends BaseService {
return Future.value(localRes);
}
Future getPatientLabOrdersResults({PatientLabOrders? patientLabOrder, String? procedure, bool isVidaPlus = false}) async {
Future getPatientLabOrdersResults(
{PatientLabOrders? patientLabOrder,
String? procedure,
bool isVidaPlus = false}) async {
hasError = false;
Map<String, dynamic> body = Map();
body['InvoiceNo_VP'] = isVidaPlus ? patientLabOrder!.invoiceNo : "0";
@ -196,31 +230,45 @@ class LabsService extends BaseService {
body['Procedure'] = procedure;
body['Procedure'] = procedure;
body['LanguageID'] = 1;
await baseAppClient.post(GET_Patient_LAB_ORDERS_RESULT, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(GET_Patient_LAB_ORDERS_RESULT,
onSuccess: (dynamic response, int statusCode) {
labOrdersResultsList.clear();
response['ListPLR'].forEach((lab) {
labOrdersResultsList.add(LabOrderResult.fromJson(lab));
});
labOrdersResultsList = labOrdersResultsList.reversed.toList();
}, onFailure: (String error, int statusCode) {
labOrdersResultsList.clear();
hasError = true;
super.error = error;
}, body: body);
}
RequestSendLabReportEmail _requestSendLabReportEmail = RequestSendLabReportEmail();
RequestSendLabReportEmail _requestSendLabReportEmail =
RequestSendLabReportEmail();
Future sendLabReportEmail({PatientLabOrders? patientLabOrder, AuthenticatedUser? userObj, bool isVidaPlus = false, bool isDownload = false, int languageID = 1}) async {
Future sendLabReportEmail(
{PatientLabOrders? patientLabOrder,
AuthenticatedUser? userObj,
bool isVidaPlus = false,
bool isDownload = false,
int languageID = 1}) async {
_requestSendLabReportEmail.projectID = patientLabOrder!.projectID;
_requestSendLabReportEmail.invoiceNo = isVidaPlus ? "0" : patientLabOrder.invoiceNo;
_requestSendLabReportEmail.invoiceNoVP = isVidaPlus ? patientLabOrder.invoiceNo : "0";
_requestSendLabReportEmail.invoiceNo =
isVidaPlus ? "0" : patientLabOrder.invoiceNo;
_requestSendLabReportEmail.invoiceNoVP =
isVidaPlus ? patientLabOrder.invoiceNo : "0";
_requestSendLabReportEmail.invoiceType = patientLabOrder.invoiceType;
_requestSendLabReportEmail.doctorName = patientLabOrder.doctorName;
_requestSendLabReportEmail.clinicName = patientLabOrder.clinicDescription;
_requestSendLabReportEmail.patientName = userObj!.firstName! + " " + userObj.lastName!;
_requestSendLabReportEmail.patientIditificationNum = userObj.patientIdentificationNo;
_requestSendLabReportEmail.patientName =
userObj!.firstName! + " " + userObj.lastName!;
_requestSendLabReportEmail.patientIditificationNum =
userObj.patientIdentificationNo;
_requestSendLabReportEmail.dateofBirth = userObj.dateofBirth;
_requestSendLabReportEmail.to = userObj.emailAddress;
_requestSendLabReportEmail.orderDate = '${patientLabOrder.orderDate!.year}-${patientLabOrder.orderDate!.month}-${patientLabOrder.orderDate!.day}';
_requestSendLabReportEmail.orderDate =
'${patientLabOrder.orderDate!.year}-${patientLabOrder.orderDate!.month}-${patientLabOrder.orderDate!.day}';
_requestSendLabReportEmail.patientMobileNumber = userObj.mobileNumber;
_requestSendLabReportEmail.projectName = patientLabOrder.projectName;
_requestSendLabReportEmail.setupID = patientLabOrder.setupID;
@ -231,13 +279,530 @@ class LabsService extends BaseService {
_requestSendLabReportEmail.languageID = languageID;
// await baseAppClient.post(SEND_LAB_RESULT_EMAIL, onSuccess: (dynamic response, int statusCode) {
await baseAppClient.post(isVidaPlus ? SEND_LAB_RESULT_EMAIL : SEND_LAB_RESULT_EMAIL_NEW, onSuccess: (dynamic response, int statusCode) {
await baseAppClient
.post(isVidaPlus ? SEND_LAB_RESULT_EMAIL : SEND_LAB_RESULT_EMAIL_NEW,
onSuccess: (dynamic response, int statusCode) {
if (isDownload) {
labReportPDF = isVidaPlus ? response['LabReportsPDFContent'] : response['PdfContent'];
labReportPDF = isVidaPlus
? response['LabReportsPDFContent']
: response['PdfContent'];
}
}, onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
}, body: _requestSendLabReportEmail.toJson());
}
List<LabOrderResult> sortByFlagAndValue(List<LabOrderResult> original) {
const priorityOrder = ['LCL', 'CL', 'L', 'N', 'H', 'CH', 'HCH'];
int getFlagPriority(String? flag) {
if (flag == null) return priorityOrder.length;
final index = priorityOrder.indexOf(flag);
return index == -1 ? priorityOrder.length : index;
}
double parseResultValue(String? value) {
if (value == null) return double.nan;
return double.tryParse(value) ?? double.nan;
}
final copy = List<LabOrderResult>.from(original);
copy.sort((a, b) {
final aFlagPriority = getFlagPriority(a.calculatedResultFlag);
final bFlagPriority = getFlagPriority(b.calculatedResultFlag);
if (aFlagPriority != bFlagPriority) {
return aFlagPriority.compareTo(bFlagPriority);
}
final aValue = parseResultValue(a.resultValue);
final bValue = parseResultValue(b.resultValue);
return aValue.compareTo(bValue);
});
return copy;
}
Map<String, LabOrderResult> mapFirstItemByPriority(
List<LabOrderResult> sortedResults) {
final Map<String, LabOrderResult> priorityMap = {};
const priorityOrder = ['LCL', 'CL', 'L', 'N', 'H', 'CH', 'HCH'];
for (final result in sortedResults) {
final priority = result.calculatedResultFlag?.trim();
if (priority != null &&
priorityOrder.contains(priority) &&
!priorityMap.containsKey(priority)) {
priorityMap[priority] = result;
}
// Early exit if all priorities are found
if (priorityMap.length == priorityOrder.length) break;
}
print("the map of priority is :\n $priorityMap");
return priorityMap;
}
List<LabOrderResult> getMostRecentThree(List<LabOrderResult> original) {
DateTime? parseVerifiedDate(String? raw) {
if (raw == null) return null;
final regex = RegExp(r'\/Date\((\d+)\)\/');
final match = regex.firstMatch(raw);
if (match != null) {
print("the match iss not null");
final millis = int.tryParse(match.group(1)!);
if (millis != null) {
print(
"the data and time is ${DateTime.fromMillisecondsSinceEpoch(millis)}");
return DateTime.fromMillisecondsSinceEpoch(millis);
}
}
return null;
}
final copy = List<LabOrderResult>.from(original);
copy.sort((a, b) {
final aDate = DateUtil.convertStringToDate(a.verifiedOnDateTime);
final bDate = DateUtil.convertStringToDate(b.verifiedOnDateTime);
if (aDate == null && bDate == null) return 0;
if (aDate == null) return 1;
if (bDate == null) return -1;
return bDate.compareTo(aDate); // descending
});
print("the copied item are $copy");
labOrdersResultsList = copy;
return copy.take(3).toList();
}
List<ThresholdRange> buildThresholdList(List<LabOrderResult> topResults) {
var mapOfPriority = mapFirstItemByPriority(topResults);
return mapResultToThreshold(topResults, mapOfPriority);
}
List<ThresholdRange> mapResultToThreshold(
List<LabOrderResult> results, Map<String, LabOrderResult> mapOfPriority) {
// Extract valid numeric results
List<double> actualValues = results
.map((e) => double.tryParse(e.resultValue ?? ''))
.where((v) => v != null)
.cast<double>()
.toList();
if (actualValues.isEmpty) return [];
actualValues.sort();
double min = actualValues.first;
double max = actualValues.last;
double baseRange = max - min;
// Handle single value or equal values
if (baseRange == 0) {
baseRange = max * 0.2; // ±10%
min = max - baseRange / 2;
max = max + baseRange / 2;
}
// Adjust range scale based on number of actual values
// >5 = compress thresholds; <5 = expand thresholds
int valueCount = actualValues.length;
double scalingFactor = valueCount >= 5 ? 1.0 : (5 / valueCount);
double adjustedRange = baseRange * scalingFactor;
// Recalculate thresholds based on adjusted range
// double criticalLow = min;
// double low = min + 0.25 * adjustedRange;
// double normal = min + 0.5 * adjustedRange;
// double high = min + 0.75 * adjustedRange;
// double criticalHigh = min + adjustedRange;
const priorityOrder = ['LCL', 'CL', 'L', 'N', 'H', 'CH', 'HCH'];
var mapOfValues = inferThresholds(mapOfPriority);
var item = results.first;
String? realCriticalLow =
(item.criticalLow == "0") ? null : item.criticalLow;
String? realReferenceHigh =
(item.referenceHigh == "0") ? null : item.referenceHigh;
String? realCriticalHigh =
(item.criticalHigh == "0") ? null : item.criticalHigh;
String? realReferenceLow =
(item.referenceLow == "0") ? null : item.referenceLow;
final adjustedValues = adjustValues(
criticalLow: mapOfValues['criticalLow'],
low: mapOfValues['low'],
normal: mapOfValues['normal'],
high: mapOfValues['high'],
criticalHigh: mapOfValues['criticalHigh'],
);
return [
ThresholdRange(
label: 'Critical Low',
value: adjustedValues["criticalLow"]!,
color: Color(0xffffffff),
lineColor: Color(0xFFe9a2a4),
actualValue: realCriticalLow),
ThresholdRange(
label: 'Low',
value: adjustedValues['low']!,
color: Color(0xFFf2fbf5),
lineColor: Color(0xFFefc481),
actualValue: realReferenceLow),
ThresholdRange(
label: 'Normal',
value: adjustedValues['normal']!,
color: Color(0xFFf2fbf5),
lineColor: Color(0xFF5dc36b)),
ThresholdRange(
label: 'High',
value: adjustedValues['high']!,
color: Color(0xffffffff),
lineColor: Color(0xFFefc481),
actualValue: realReferenceHigh),
ThresholdRange(
label: 'Critical High',
value: adjustedValues['criticalHigh']!,
color: Color(0xffffffff),
lineColor: Color(0xFFe9a2a4),
actualValue: realCriticalHigh),
];
}
Map<String, double> inferThresholds(
Map<String, LabOrderResult> mapOfPriority) {
double? parse(String? v) {
final parsed = double.tryParse(v ?? '');
return (parsed == null || parsed < 0) ? null : parsed;
}
// Parse inputs
double? criticalLow = parse(
mapOfPriority['LCL']?.resultValue ?? mapOfPriority['CL']?.resultValue);
double? low = parse(mapOfPriority['L']?.resultValue);
double? normal = parse(mapOfPriority['N']?.resultValue);
double? high = parse(mapOfPriority['H']?.resultValue);
double? criticalHigh = parse(
mapOfPriority['CH']?.resultValue ?? mapOfPriority['HCH']?.resultValue);
const step = 5.0;
List<double?> values = [criticalLow, low, normal, high, criticalHigh];
// Find the index of the known value (priority: central -> left -> right)
int anchorIndex = values.indexWhere((v) => v != null);
double anchorValue = values[anchorIndex] ?? 50;
// Infer all values around the anchor
List<double> inferred = List.generate(5, (i) {
double v = anchorValue + (i - anchorIndex) * step;
return v < 0 ? 0 : v;
});
var mapresult = {
'criticalLow': values[0]??-1,
'low': values[1]??-1,
'normal': values[2]??-1,
'high': values[3]??-1,
'criticalHigh': values[4]??-1,
};
print("the result is $mapresult");
return mapresult;
}
Map<String, double> adjustValues({
double? criticalLow,
double? low,
double? normal,
double? high,
double? criticalHigh,
double step = 10,
}) {
bool criticalLowHasValue = true;
bool lowHasValue = true;
bool normaHasValue = true;
bool highHasValue = true;
bool criticalHighHasValue = true;
if (criticalLow == null || criticalLow == -1) criticalLowHasValue = false;
if (low == null || low == -1) lowHasValue = false;
if (normal == null ||normal ==-1) normaHasValue = false;
if (high == null ||high ==-1) highHasValue = false;
if (criticalHigh == null ||criticalHigh ==-1) criticalHighHasValue = false;
print("the values arre $criticalLowHasValue $lowHasValue $normaHasValue $highHasValue $criticalHighHasValue");
if (!criticalLowHasValue) {
criticalLow = 0;
if (lowHasValue) {
low = low! - step;
} if (normaHasValue && (criticalLow!= 0 || criticalLow != -1)) {
low = normal! - step * 2;
} if (highHasValue && (criticalLow!= 0 || criticalLow != -1)) {
low = high! - step * 3;
} if (criticalHighHasValue && (criticalLow!= 0 || criticalLow != -1)) {
low = criticalHigh! - step * 4;
}
}
if (!lowHasValue) {
print("the low value is not set");
low = 0;
if (criticalLowHasValue && (low != 0 || low != -1)) {
low = criticalLow! + step;
} if (normaHasValue && (low != 0 || low != -1)) {
low = normal! - step;
} if (highHasValue && (low != 0 || low != -1)) {
low = high! - step * 2;
} if (criticalHighHasValue && (low != 0 || low != -1)) {
low = criticalHigh! - step * 3;
}
}
if (!normaHasValue) {
normal = 0;
if (criticalLowHasValue && (normal != 0 || normal != -1)) {
normal = criticalLow! + step * 2;
} if (lowHasValue) {
normal = low! + step;
} if (highHasValue) {
normal = high! - step;
} if (criticalHighHasValue) {
normal = criticalHigh! - step * 2;
}
}
if (!highHasValue) {
high = 0;
if (criticalLowHasValue) {
high = criticalLow! + step * 3;
} if (lowHasValue) {
high = low! + step * 2;
} if (normaHasValue) {
high = normal! + step;
} if (criticalHighHasValue) {
high = criticalHigh! - step;
}
}
if (!criticalHighHasValue) {
criticalHigh = 0;
if (criticalLowHasValue) {
criticalHigh = criticalLow! + step * 4;
} if (lowHasValue) {
criticalHigh = low! + step * 3;
} if (normaHasValue) {
criticalHigh = normal! + step * 2;
} if (highHasValue) {
criticalHigh = high! + step;
}
}
if(((criticalLow??0)<0) == true){
var mod = ((low ?? 0) + (normal??0) )/2;
criticalLow = mod;
}
if(((low??0)<0) == true){
var mod = ((criticalLow ?? 0) + (normal??0) )/2;
low = mod;
}
if(((normal??0)<0) == true){
var mod = ((low ?? 0) + (high??0) )/2;
normal = mod;
}
if(((high??0)<0) == true){
var mod = ((normal ?? 0) + (criticalHigh??0) )/2;
high = mod;
}
if(((criticalHigh??0)<0) == true){
criticalHigh = (high??0)+step;
}
Map<String, double?> values = {
'criticalLow':criticalLow ,
'low': low,
'normal': normal ,
'high': high ,
'criticalHigh': criticalHigh,
};
print("thee adjusted values `are $values");
// // Find the first known value
// int firstKnownIndex = values.values.toList().indexWhere((v) => v != null);
//
// if (firstKnownIndex == -1) {
// // No values at all, start from 0
// values = {
// 'criticalLow': 0,
// 'low': step,
// 'normal': step * 2,
// 'high': step * 3,
// 'criticalHigh': step * 4,
// };
// } else {
// // Fill backward
// for (int i = firstKnownIndex - 1; i >= 0; i--) {
// values[values.keys.elementAt(i)] =
// (values.values.elementAt(i + 1)! - step).clamp(0, double.infinity);
// }
//
// // Fill forward
// for (int i = firstKnownIndex + 1; i < values.length; i++) {
// values[values.keys.elementAt(i)] =
// values.values.elementAt(i - 1)! + step;
// }
// }
//
// // Ensure strictly increasing sequence
// double prev = -double.infinity;
// values.forEach((key, val) {
// if (val! <= prev) {
// values[key] = prev + step;
// }
// prev = values[key]!;
// });
return values.map((k, v) => MapEntry(k, v!));
}
void adjustLabOrderResults(List<LabOrderResult> results) {
const priorityOrder = ['LCL', 'CL', 'L', 'N', 'H', 'CH', 'HCH'];
// Sort results by priority order
results.sort((a, b) => priorityOrder
.indexOf(a.calculatedResultFlag ?? '')
.compareTo(priorityOrder.indexOf(b.calculatedResultFlag ?? '')));
// Extract values
List<double?> values = results.map((r) {
double? v = double.tryParse(r.resultValue ?? '');
return (v != null && v >= 0) ? v : null;
}).toList();
// Find first non-null index
int? firstIdx = values.indexWhere((v) => v != null);
if (firstIdx == -1) return; // All values missing
// Fill before first known value (decreasing with step 5, not less than 0)
for (int i = firstIdx - 1; i >= 0; i--) {
values[i] = (values[i + 1]! - 5).clamp(0, double.infinity);
}
// Fill after first known value (increasing with step 5)
for (int i = firstIdx + 1; i < values.length; i++) {
if (values[i] == null) {
values[i] = values[i - 1]! + 5;
}
}
// For gaps in the middle, interpolate
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
// find next non-null
int j = i + 1;
while (j < values.length && values[j] == null) j++;
if (j < values.length) {
double start = values[i - 1]!;
double end = values[j]!;
double step = (end - start) / (j - i + 1);
for (int k = i; k < j; k++) {
values[k] = start + step * (k - i + 1);
}
}
}
}
// Update results list directly
for (int i = 0; i < results.length; i++) {
results[i].resultValue = values[i]?.toStringAsFixed(2) ?? '0.00';
}
}
double transformValueInRange(double inputValue, String flag) {
// Define range boundaries
double rangeStart, rangeEnd;
switch (flag) {
case 'CL':
rangeStart = 0.0;
rangeEnd = 19.0;
break;
case 'L':
rangeStart = 20.0;
rangeEnd = 39.0;
break;
case 'N':
rangeStart = 40.0;
rangeEnd = 59.0;
break;
case 'H':
rangeStart = 60.0;
rangeEnd = 79.0;
break;
case 'CH':
rangeStart = 80.0;
rangeEnd = 100.0;
break;
default:
throw ArgumentError('Invalid flag: $flag');
}
// Clamp input value to 0-100 and map it to the range bounds
final clampedValue = inputValue.clamp(0.0, 100.0);
final normalizedValue = clampedValue / 100.0; // Normalize input to 0-1
print("the normalized value is $normalizedValue");
// Map the normalized value to the target range bounds
final transformedValue = rangeStart + (normalizedValue * (rangeEnd - rangeStart));
return transformedValue;
}
List<ThresholdRange> getThresholdValue() {
return [
ThresholdRange(
label: 'criticalLow',
value: 0,
color: Color(0xffffffff),
lineColor: Color(0xFFe9a2a4)),
ThresholdRange(
label: 'low',
value: 20,
color: Color(0xFFf2fbf5),
lineColor: Color(0xFFeecd94)),
ThresholdRange(
label: 'normal',
value: 40,
color: Color(0xFFf2fbf5),
lineColor: Color(0xFF5dc36b)),
ThresholdRange(
label: 'high',
value: 60,
color: Color(0xffffffff),
lineColor: Color(0xFFeecd94)),
ThresholdRange(
label: 'criticalHigh',
value: 80,
color: Color(0xffffffff),
lineColor: Color(0xFFe9a2a4)),
];
}
}

@ -13,6 +13,8 @@ import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.da
import 'package:diplomaticquarterapp/uitl/app_toast.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:diplomaticquarterapp/widgets/charts/app_time_series_chart.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/lab_result_graph.dart';
import 'package:flutter/material.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
@ -24,7 +26,11 @@ class LabsViewModel extends BaseViewModel {
LabsService _labsService = locator<LabsService>();
List<LabOrderResult> get labOrdersResultsList => _labsService.labOrdersResultsList;
List<TimeSeriesSales2> timeSeries = [];
List<DataPoint> threePointGraphValue = [];
List<DataPoint> completeeGraphValues = [];
List<ThresholdRange> threshold = [];
List months = ['Jan','Feb','Mar','April','May','Jun','July','Aug','Sep','Oct','Nov','Dec'];
String get labReportPDF => _labsService.labReportPDF;
@ -100,24 +106,53 @@ class LabsViewModel extends BaseViewModel {
} else {
_labsService.labResultList.forEach((element) {
List<LabResultList> patientLabOrdersClinic = labResultLists.where((elementClinic) => elementClinic.filterName == element.testCode).toList();
element.percentage =
getPercentage(element.calculatedResultFlag ?? ResultFlag.N);
if (patientLabOrdersClinic.length != 0) {
// var value = labResultLists[labResultLists.indexOf(patientLabOrdersClinic[0])]
// .patientLabResultList!
// .where((e) {
// return e.sampleCollectedOn == element.sampleCollectedOn && e.resultValue == element.resultValue;
// })
// .toList();
// if (value.isEmpty)
labResultLists[labResultLists.indexOf(patientLabOrdersClinic[0])].patientLabResultList!.add(element);
labResultLists[labResultLists.indexOf(patientLabOrdersClinic[0])].patientLabResultList!.add(element);
} else {
labResultLists.add(LabResultList(filterName: element.testCode, lab: element));
labResultLists.add(LabResultList(
filterName: element.testCode,
description: element.packageShortDescription,
lab: element));
}
});
setState(ViewState.Idle);
}
}
double getPercentage(ResultFlag flag) {
double percentage = 0.0;
final division = 0.2;
switch (flag) {
case ResultFlag.N: //4
percentage = division * 1.75;
break;
case ResultFlag.H: //5
percentage = division * 2.8;
break;
case ResultFlag.L: //3
percentage = division * .7;
break;
case ResultFlag.CL: //2
case ResultFlag.LCL: //
percentage = division * .07;
break;
case ResultFlag.HCH: //7
case ResultFlag.CH: //6
percentage = division * 3.4;
break;
case ResultFlag.IRR:
percentage = 0;
break;
}
return percentage * 100;
}
getPatientLabOrdersResults({PatientLabOrders? patientLabOrder, String? procedure, bool? isVidaPlus}) async {
setState(ViewState.Busy);
await _labsService.getPatientLabOrdersResults(
@ -129,6 +164,7 @@ class LabsViewModel extends BaseViewModel {
error = _labsService.error!;
setState(ViewState.Error);
} else {
/// commented out based on PAP-304
// bool isShouldClear = false;
// if (_labsService.labOrdersResultsList.length == 1) {
@ -141,17 +177,65 @@ class LabsViewModel extends BaseViewModel {
//
// _labsService.labOrdersResultsList.clear();
_labsService.labOrdersResultsList.forEach((element) {
var sortedResponse = _labsService.sortByFlagAndValue(_labsService.labOrdersResultsList);
print("the sorted list is ${sortedResponse}");
var recentThree = _labsService.getMostRecentThree(sortedResponse);
print("the recentThree list is ${recentThree}");
var mappedToThresholdValue = _labsService.getThresholdValue();
// var mappedToThresholdValue = _labsService.buildThresholdList(recentThree);
// _labsService.adjustLabOrderResults(sortedResponse);
print("the recentThree list is ${mappedToThresholdValue}");
threshold = mappedToThresholdValue;
double counter = 1;
recentThree.reversed.forEach((element) {
try {
timeSeries.add(new TimeSeriesSales2(DateUtil.convertStringToDate(element.verifiedOnDateTime!), double.parse(element.resultValue!)));
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
threePointGraphValue.add(DataPoint( labelValue: counter,value : _labsService.transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??""), actualValue: element.resultValue!,label: "${months[dateTime.month-1]} ${dateTime.year}", date: dateTime));
counter++;
} catch (e) {}
});
threePointGraphValue.last.label = "thisResult";
threePointGraphValue.last.isStringResource = true;
setState(ViewState.Idle);
}
}
sendLabReportEmail({PatientLabOrders? patientLabOrder, String? mes, AuthenticatedUser? userObj, required bool isVidaPlus, bool isDownload = false, int languageID = 1}) async {
await _labsService.sendLabReportEmail(patientLabOrder: patientLabOrder, userObj: userObj, isVidaPlus: isVidaPlus, isDownload: isDownload, languageID: languageID);
/// This function is used to create a full graph data points for the lab results.
/// @param onComplete: A callback function that is called when the data points are created.
createFullGraphDatPoints(
VoidCallback onComplete
){
completeeGraphValues.clear();
setState(ViewState.Busy);
double counter = 1;
threshold = _labsService.getThresholdValue();
_labsService.labOrdersResultsList.reversed.forEach((element) {
try {
print("the mapping is being done");
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
completeeGraphValues.add(DataPoint( labelValue: counter,value : _labsService.transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag??""), label: "${months[dateTime.month-1]} ${dateTime.year}", date: dateTime,actualValue: element.resultValue!));
} catch (e) {
print("the mapping is having exception $e");
}
++counter;
});
print("the label values are $counter");
print("the completeeGraphValues length are ${completeeGraphValues.length}");
print("the completeeGraphValues last value of label ias ${completeeGraphValues.last.labelValue}");
completeeGraphValues.last.label = "thisResult";
completeeGraphValues.last.isStringResource = true;
setState(ViewState.Idle);
onComplete();
}
sendLabReportEmail({PatientLabOrders? patientLabOrder, String? mes, AuthenticatedUser? userObj, required bool isVidaPlus, bool isDownload = false}) async {
setState(ViewState.Busy);
await _labsService.sendLabReportEmail(patientLabOrder: patientLabOrder, userObj: userObj, isVidaPlus: isVidaPlus, isDownload: isDownload);
setState(ViewState.Idle);
if (_labsService.hasError) {
error = _labsService.error!;
} else {
@ -173,7 +257,8 @@ class LabsViewModel extends BaseViewModel {
Future<String> _createFileFromString(String encodedStr, String ext) async {
Uint8List bytes = base64.decode(encodedStr);
String dir = (await getApplicationDocumentsDirectory()).path;
File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext);
File file = File(
"$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext);
await file.writeAsBytes(bytes);
return file.path;
}

@ -37,7 +37,6 @@ import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:diplomaticquarterapp/widgets/others/not_auh_page.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
// import 'package:flutter_app_icon_badge/flutter_app_icon_badge.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';

@ -1,22 +1,13 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:diplomaticquarterapp/core/model/labs/patient_lab_orders.dart';
import 'package:diplomaticquarterapp/core/viewModels/medical/labs_view_model.dart';
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/uitl/app_toast.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/laboratory_result_widget.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
class LaboratoryResultPage extends StatefulWidget {
@ -52,39 +43,27 @@ class _LaboratoryResultPageState extends State<LaboratoryResultPage> {
body: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
addAutomaticKeepAlives: true,
physics: BouncingScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.only(bottom: 12),
itemBuilder: (context, index) => LaboratoryResultWidget(
onTap: () async {
GifLoaderDialogUtils.showMyDialog(context);
await model.sendLabReportEmail(
LaboratoryResultWidget(
onTap: () async {
await model.sendLabReportEmail(
patientLabOrder: widget.patientLabOrders,
mes: TranslationBase.of(context).sendSuc,
userObj: projectViewModel.user,
languageID: projectViewModel.isArabic ? 1 : 2,
isDownload: true,
isVidaPlus: Utils.isVidaPlusProject(
projectViewModel,
int.parse(widget.patientLabOrders!.projectID!),
),
);
GifLoaderDialogUtils.hideDialog(context);
},
billNo: widget.patientLabOrders!.invoiceNo,
// details: model.patientLabSpecialResult[index].resultDataHTML,
details: model.patientLabSpecialResult.isEmpty ? null : getSpecialResults(model),
orderNo: widget.patientLabOrders!.orderNo,
patientLabOrder: widget.patientLabOrders,
projectName: widget.patientLabOrders!.projectName,
),
itemCount: 1,
isDownload: true);
},
showConfirmMessageDialog: false,
billNo: widget.patientLabOrders!.invoiceNo,
// details: model.patientLabSpecialResult[index].resultDataHTML,
details: model.patientLabSpecialResult.isEmpty
? null
: getSpecialResults(model),
orderNo: widget.patientLabOrders!.orderNo,
patientLabOrder: widget.patientLabOrders,
),
SizedBox(
height: 120.0,
)
],
),
),

@ -168,7 +168,7 @@ class PayfortService extends BaseService {
/// Step 4: Processing Payment [Don't multiply with 100]
/// Amount value send always round ex. [100] not [100.00, 100.21]
FortRequest request = FortRequest(
command: FortCommand.purchase,
// command: FortCommand.purchase,
amount: orderAmount!,
customerName: customerName!,
customerEmail: customerEmail!,

@ -13,6 +13,7 @@ import 'package:diplomaticquarterapp/uitl/LocalNotification.dart';
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/push-notification-handler.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/lab_result_graph.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

@ -70,7 +70,7 @@ class AppToast {
child: toast,
gravity: ToastGravity.TOP,
toastDuration: Duration(seconds: timeInSeconds),
positionedToastBuilder: (context, child) {
positionedToastBuilder: (context, child,_) {
return Positioned(top: 50, left: 10, right: 10, child: child);
});
// Fluttertoast.showToast(msg: message, toastLength: toastLength, gravity: toastGravity, timeInSecForIosWeb: timeInSeconds, backgroundColor: Colors.red, textColor: textColor, fontSize: fontSize);

File diff suppressed because it is too large Load Diff

@ -1,18 +1,18 @@
import 'package:diplomaticquarterapp/core/enum/viewstate.dart';
import 'package:diplomaticquarterapp/core/model/labs/patient_lab_orders.dart';
import 'package:diplomaticquarterapp/core/viewModels/medical/labs_view_model.dart';
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/theme/colors.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/widgets/Loader/gif_loader_container.dart';
import 'package:diplomaticquarterapp/widgets/charts/show_chart.dart';
import 'package:diplomaticquarterapp/widgets/data_display/text.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/full_screen_lab_result_graph.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/lab_result_graph.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'LineChartCurved.dart';
import 'lab_result_chart_and_detials.dart';
class FlowChartPage extends StatelessWidget {
@ -27,65 +27,125 @@ class FlowChartPage extends StatelessWidget {
Widget build(BuildContext context) {
projectViewModel = Provider.of(context);
return BaseView<LabsViewModel>(
onModelReady: (model) =>
model.getPatientLabOrdersResults(patientLabOrder: patientLabOrder, procedure: filterName, isVidaPlus: Utils.isVidaPlusProject(projectViewModel!, int.parse(patientLabOrder!.projectID!))),
builder: (context, model, w) => AppScaffold(
isShowAppBar: true,
appBarTitle: filterName!,
baseViewModel: model,
showNewAppBar: true,
showNewAppBarTitle: true,
backgroundColor: CustomColors.appBackgroudGrey2Color,
body: SingleChildScrollView(
child: model.labOrdersResultsList.isNotEmpty
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: double.infinity,
padding: EdgeInsets.only(left: 17, top: 12, right: 13, bottom: 12),
margin: EdgeInsets.only(left: 21, right: 21, top: 21),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(.05),
//spreadRadius: 5,
blurRadius: 27,
offset: Offset(0, -3),
onModelReady: (model) => model.getPatientLabOrdersResults(
patientLabOrder: patientLabOrder,
procedure: filterName,
isVidaPlus: Utils.isVidaPlusProject(
projectViewModel!, int.parse(patientLabOrder!.projectID!))),
builder: (context, model, w) => SizedBox(
height: MediaQuery.sizeOf(context).height * .75,
child: (model.state == ViewState.Busy)
? Material(
color: Colors.grey.withOpacity(0.6),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
child: Center(
child: Container(
child: GifLoaderContainer(),
margin: EdgeInsets.only(
bottom: MediaQuery.of(context).size.height * 0.09)),
),
)
: SingleChildScrollView(
child: model.labOrdersResultsList.isNotEmpty
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(
top: 16.0, right: 16.0, bottom: 10),
child: GestureDetector(
onTap: () => Navigator.pop(context),
child: Align(
alignment: Alignment.centerRight,
child: Icon(
Icons.close,
color: Colors.black,
size: 28,
),
),
),
),
Container(
width: double.infinity,
padding: EdgeInsets.only(
left: 17, top: 12, right: 13, bottom: 12),
margin:
EdgeInsets.only(left: 21, right: 21, top: 21),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(.05),
//spreadRadius: 5,
blurRadius: 27,
offset: Offset(0, -3),
),
],
),
// child: LineChartCurved(
// title: filterName,
// labResult: model.labOrdersResultsList,
// ),
// child: ShowChart(
// title: filterName!,
// timeSeries: model.timeSeries,
// indexes: model.timeSeries.length ~/ 5.5 ?? 0,
// ),
child: Column(
children: [
SizedBox(
height: MediaQuery.sizeOf(context).height / 4,
child: DynamicResultChart(
dataPoints: model.threePointGraphValue,
thresholds: model.threshold,
width: MediaQuery.sizeOf(context).width - 77,
scrollDirection: Axis.horizontal,
height: MediaQuery.sizeOf(context).height / 4,
),
),
InkWell(
onTap: () {
model.createFullGraphDatPoints(() {
Navigator.push(context,
MaterialPageRoute(builder: (_) {
return FullScreenGraph(
completeeGraphValues: model.completeeGraphValues,
threshold: model.threshold,
);
}));
});
},
child: Text(TranslationBase.of(context)
.seeAllGraphValues),
)
],
),
),
LabResultChartAndDetails(
name: filterName!,
labResult: model.labOrdersResultsList.reversed.toList(),
),
],
)
: Center(
child: Container(
padding: EdgeInsets.only(
top: MediaQuery.of(context).size.height * 0.32),
child: Center(
child: getNoDataWidget(context),
),
),
),
// child: LineChartCurved(
// title: filterName,
// labResult: model.labOrdersResultsList,
// ),
child: ShowChart(
title: filterName!,
timeSeries: model.timeSeries,
indexes: model.timeSeries.length ~/ 5.5 ?? 0,
),
),
LabResultChartAndDetails(
name: filterName!,
labResult: model.labOrdersResultsList,
),
],
)
: Center(
child: Container(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.32),
child: Center(
child: getNoDataWidget(context),
),
),
),
),
),
),
);
}

@ -3,7 +3,6 @@ import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -29,6 +28,7 @@ class _VitalSignDetailsWidgetState extends State<LabResultDetailsWidget> {
columnWidths: {
0: FlexColumnWidth(2),
1: FlexColumnWidth(1),
2: FlexColumnWidth(1),
},
children: fullData(widget.labResult!, context),
);
@ -41,6 +41,7 @@ class _VitalSignDetailsWidgetState extends State<LabResultDetailsWidget> {
children: [
Utils.tableColumnTitle(TranslationBase.of(context).date),
Utils.tableColumnTitle(TranslationBase.of(context).labResults),
Utils.tableColumnTitle(TranslationBase.of(context).change),
],
),
);
@ -51,9 +52,34 @@ class _VitalSignDetailsWidgetState extends State<LabResultDetailsWidget> {
children: [
Utils.tableColumnValue(DateUtil.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(labOrderResultList![i].verifiedOnDateTime!)), isLast: i == (labOrderResultList.length - 1), mProjectViewModel: projectViewModel),
Utils.tableColumnValue(labOrderResultList[i].resultValue!, isLast: i == (labOrderResultList.length - 1), mProjectViewModel: projectViewModel),
changeResult(labOrderResultList[i].changeResult ?? '8%')
],
),
);
return tableRow;
}
Widget changeResult(String changeValue) => Padding(
padding: const EdgeInsets.all(4.0),
child: Material(
color: (changeValue.contains("-")) ? Colors.black : Color(0xffcecbcb),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: Center(
child: Text(
changeValue,
style: TextStyle(
color: (changeValue.contains("-"))
? Colors.white
: Colors.black,
fontSize: 11,
letterSpacing: -.64,
fontWeight: FontWeight.w400),
),
),
),
),
);
}

@ -0,0 +1,59 @@
import 'package:diplomaticquarterapp/core/viewModels/medical/labs_view_model.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/lab_result_graph.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:flutter/material.dart';
class FullScreenGraph extends StatelessWidget {
final List<DataPoint> completeeGraphValues ;
final List<ThresholdRange> threshold ;
const FullScreenGraph({super.key, required this.completeeGraphValues, required this.threshold});
@override
Widget build(BuildContext context) {
return AppScaffold(
isShowAppBar: true,
appBarTitle: TranslationBase.of(context).labResult,
showNewAppBar: true,
showNewAppBarTitle: true,
backgroundColor: Color(0xffF8F8F8),
body: RotatedBox(
quarterTurns: 1,
child: SizedBox(
// width: MediaQuery.sizeOf(context).height,
height: MediaQuery.sizeOf(context).width,
child: Material(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
child: DynamicResultChart(
dataPoints: completeeGraphValues,
thresholds: threshold,
// width:((completeeGraphValues.length <=2)? MediaQuery.sizeOf(context).height : (MediaQuery.sizeOf(context).height* (
// completeeGraphValues.length <= 3
// ? 1
// : (completeeGraphValues.length/3))
// ) )-77,
width: MediaQuery.sizeOf(context).height-100,
maxX: completeeGraphValues.length.toDouble(),
scrollDirection: Axis.horizontal,
height: MediaQuery.sizeOf(context).width,
isFullScreenGraph: true,
),
),
),
),
),
);
}
// double getMax(List<DataPoint> dataPoints) {
// double max = double.negativeInfinity;
// for (var point in dataPoints) {
// if (point.value > max) {
// max = point.y;
// }
// }
// return max;
// }
}

@ -0,0 +1,321 @@
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:intl/intl.dart';
class DynamicResultChart extends StatelessWidget {
final List<DataPoint> dataPoints;
final List<ThresholdRange> thresholds;
final double? width;
final double height;
final double? maxX;
final Axis scrollDirection;
final bool isFullScreenGraph;
const DynamicResultChart(
{super.key, required this.dataPoints, required this.thresholds,required this.width,required this.scrollDirection, required this.height, this.maxX, this.isFullScreenGraph = false});
@override
Widget build(BuildContext context) {
var minY = 0.0;
var maxY = 0.0;
if(thresholds.isNotEmpty) {
print("the thresholds are $thresholds");
minY = thresholds.first.value;
maxY = thresholds.last.value + 1;
}else{
return SizedBox.shrink();
}
final spots = dataPoints.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.value);
}).toList();
final widthPerPoint = 30.0; // Customize as needed
final chartWidth = (dataPoints.length + 1) * widthPerPoint;
return Material(
color: Colors.white,
child: SizedBox(
width: width,
height: height,
child: Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: LineChart(
LineChartData(
minY: minY,
maxY: maxY,
minX: dataPoints.first.labelValue-1,
maxX: maxX,
lineTouchData:
LineTouchData(touchTooltipData: LineTouchTooltipData(
getTooltipItems: (touchedSpots) {
if (touchedSpots.isEmpty) return [];
// Only show tooltip for the first touched spot, hide others
return touchedSpots.map((spot) {
if (spot == touchedSpots.first) {
final dataPoint = dataPoints[spot.x.toInt()];
if(dataPoint.isStringResource){
return LineTooltipItem(
'${double.parse(dataPoint.actualValue).toStringAsFixed(2)}',
const TextStyle(color: Colors.white),
);
}
return LineTooltipItem(
'${dataPoint.label} ${double.parse(dataPoint.actualValue).toStringAsFixed(2)}',
const TextStyle(color: Colors.white),
);
}
return null; // hides the rest
}).toList();
}
)),
titlesData: FlTitlesData(
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 77,
interval: .1, // Let fl_chart handle it
getTitlesWidget: (value, _) {
// print("the value is ======== ${value}");
// Compare with 2-decimal precision to avoid close duplicates
final matchingThreshold = thresholds.firstWhere(
(t) =>
t.value.toStringAsFixed(1) ==
value.toStringAsFixed(1),
orElse: () => ThresholdRange(
label: '',
value: 0,
color: Colors.transparent,
lineColor: Colors.transparent),
);
var actualValue = (matchingThreshold.actualValue !=
null)
? "${TranslationBase.of(context).getTranslation(matchingThreshold.label)} (${matchingThreshold.actualValue})"
: '${TranslationBase.of(context).getTranslation(matchingThreshold.label)}';
if (matchingThreshold.label.isNotEmpty) {
return Text(
actualValue,
style: const TextStyle(fontSize: 10),
);
}
return const SizedBox.shrink();
},
),
),
bottomTitles: AxisTitles(
axisNameSize: 60,
sideTitles: SideTitles(
showTitles: !isFullScreenGraph,
reservedSize: 50,
getTitlesWidget: (value, _) {
if (value.toInt() >= 0 &&
value.toInt() < dataPoints.length) {
var label = dataPoints[value.toInt()].label;
if (dataPoints[value.toInt()].isStringResource) {
label = TranslationBase.of(context)
.getTranslation(
dataPoints[value.toInt()].label);
}
return Padding(
padding: EdgeInsetsDirectional.only(top: 8.0,),
child: Text(
label,
style: const TextStyle(fontSize: 12),
),
);
}
return const SizedBox.shrink();
},
interval: 1, // ensures 1:1 mapping with spots
),
),
topTitles: AxisTitles(),
rightTitles: AxisTitles(),
),
borderData: FlBorderData(show: false),
lineBarsData:
_buildColoredLineSegments(dataPoints, thresholds),
gridData: FlGridData(show: false),
extraLinesData: ExtraLinesData(
horizontalLines: thresholds.map((t) {
return HorizontalLine(
y: t.value,
color: t.lineColor,
strokeWidth: 2,
// label: HorizontalLineLabel(
// show: true,
// alignment: Alignment.centerLeft,
// style: const TextStyle(fontSize: 10),
// labelResolver: (_) => '${t.label} (${t.value.toStringAsFixed(2)})',
// ),
);
}).toList(),
),
rangeAnnotations: RangeAnnotations(
horizontalRangeAnnotations: _buildRangeShades(thresholds),
),
),
),
),
));
}
List<LineChartBarData> _buildColoredLineSegments(
List<DataPoint> dataPoints, List<ThresholdRange> thresholds) {
List<LineChartBarData> segments = [];
Color getColor(double value) {
for (int i = thresholds.length - 1; i >= 0; i--) {
if (value >= thresholds[i].value) {
return thresholds[i].lineColor;
}
}
return Colors.grey;
}
for (int i = 0; i < dataPoints.length - 1; i++) {
final dp1 = dataPoints[i];
final dp2 = dataPoints[i + 1];
final spot1 = FlSpot(i.toDouble(), dp1.value);
final spot2 = FlSpot((i + 1).toDouble(), dp2.value);
final color1 = getColor(dp1.value);
final color2 = getColor(dp2.value);
segments.add(LineChartBarData(
spots: [spot1, spot2],
isCurved: false,
barWidth: 2,
gradient: LinearGradient(
colors: [color1, color2],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
dotData: FlDotData(show: false), // We'll handle dots separately
));
}
// Add dot markers separately so they are on top
final List<FlSpot> allSpots = dataPoints.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.value);
}).toList();
print("the spots are $allSpots");
var data = [
...segments,
LineChartBarData(
spots: allSpots,
isCurved: false,
barWidth: 0, // invisible line
dotData: FlDotData(
show: true,
getDotPainter: (spot, _, __, index) {
final value = spot.y;
final color = getColor(value);
return FlDotCirclePainter(
radius: 4,
color: color,
strokeWidth: 1,
strokeColor: Colors.white,
);
},
),
)
];
var max = LineChartHelper.calculateMaxAxisValues(data).maxX;
print("the maxX is the -------> $max");
return data;
}
List<HorizontalRangeAnnotation> _buildRangeShades(
List<ThresholdRange> thresholds) {
List<HorizontalRangeAnnotation> ranges = [];
for (int i = 0; i < thresholds.length - 1; i++) {
ranges.add(HorizontalRangeAnnotation(
y1: thresholds[i].value,
y2: thresholds[i + 1].value,
color: thresholds[i].color,
));
}
return ranges;
}
}
final List<DataPoint> sampleData = [
DataPoint(value: 1.4, label: 'Jan 2024', date: DateTime(2024, 1, 1)),
DataPoint(value: 3.6, label: 'Feb 2024', date: DateTime(2024, 2, 1)),
DataPoint(value: 1.96, label: 'This result', date: DateTime(2024, 3, 1)),
];
final List<ThresholdRange> thresholdLevels = [
ThresholdRange(
label: 'Critical Low',
value: 1.4,
color: Color(0xfff6e9e9),
lineColor: Color(0xFFe9a2a4)),
ThresholdRange(
label: 'Low',
value: 3.6,
color: Color(0xFFf2fbf5),
lineColor: Color(0xFFeecd94)),
ThresholdRange(
label: 'Normal',
value: 5.96,
color: Color(0xFFf2fbf5),
lineColor: Color(0xFF5dc36b)),
ThresholdRange(
label: 'High',
value: 7.15,
color: Color(0xfff6e9e9),
lineColor: Color(0xFFeecd94)),
ThresholdRange(
label: 'Critical High',
value: 10.15,
color: Color(0xfff6e9e9),
lineColor: Color(0xFFe9a2a4)),
];
class DataPoint {
final double value;
double labelValue;
String label;
String actualValue;
final DateTime date;
bool isStringResource;
DataPoint(
{required this.value,
required this.label,
required this.date,
this.actualValue = "",
this.isStringResource = false,
this.labelValue = 0.0});
}
class ThresholdRange {
final String label;
final double value;
final Color color;
final Color lineColor;
final String? actualValue;
ThresholdRange(
{required this.label,
required this.value,
required this.color,
required this.lineColor,
this.actualValue});
@override
String toString() {
return 'ThresholdRange(label: $label, value: $value, color: ${color.value.toRadixString(16)}, lineColor: ${lineColor.value.toRadixString(16)})';
}
}

@ -1,3 +1,4 @@
import 'package:diplomaticquarterapp/core/model/labs/patient_lab_orders.dart';
import 'package:diplomaticquarterapp/core/viewModels/medical/labs_view_model.dart';
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
@ -5,15 +6,13 @@ import 'package:diplomaticquarterapp/models/header_model.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/newUI/LabItem.dart';
import 'package:diplomaticquarterapp/widgets/new_design/doctor_header.dart';
import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:provider/provider.dart';
import 'LabResultWidget.dart';
class LaboratoryResultWidget extends StatefulWidget {
final GestureTapCallback? onTap;
@ -22,8 +21,18 @@ class LaboratoryResultWidget extends StatefulWidget {
final String? orderNo;
final String? projectName;
final PatientLabOrders? patientLabOrder;
final bool showConfirmMessageDialog;
const LaboratoryResultWidget({Key? key, this.onTap, this.billNo, this.details, this.orderNo, this.projectName, this.patientLabOrder}) : super(key: key);
const LaboratoryResultWidget(
{Key? key,
this.onTap,
this.billNo,
this.details,
this.orderNo,
this.projectName,
this.patientLabOrder,
this.showConfirmMessageDialog = true})
: super(key: key);
@override
_LaboratoryResultWidgetState createState() => _LaboratoryResultWidgetState();
@ -31,14 +40,13 @@ class LaboratoryResultWidget extends StatefulWidget {
class _LaboratoryResultWidgetState extends State<LaboratoryResultWidget> {
bool _isShowMore = true;
bool _isShowMoreGeneral = true;
late ProjectViewModel projectViewModel;
late String labSpecialResult;
late String? labSpecialResult;
@override
void initState() {
super.initState();
labSpecialResult = widget.details ?? TranslationBase.of(context).noDataAvailable;
labSpecialResult = widget.details!;
}
@override
@ -50,147 +58,129 @@ class _LaboratoryResultWidgetState extends State<LaboratoryResultWidget> {
builder: (_, model, w) => NetworkBaseView(
baseViewModel: model,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DoctorHeader(
headerModel: HeaderModel(
widget.patientLabOrder!.doctorName!,
widget.patientLabOrder!.doctorID ?? 0,
widget.patientLabOrder!.doctorImageURL!,
widget.patientLabOrder!.speciality ?? [""],
widget.billNo!,
widget.patientLabOrder!.projectName ?? "",
widget.patientLabOrder!.orderDate!,
"",
widget.patientLabOrder!.nationalityFlagURL ?? "",
widget.patientLabOrder!.doctorRate!,
widget.patientLabOrder!.actualDoctorRate!,
widget.patientLabOrder!.noOfPatientsRate!,
projectViewModel.user.emailAddress!),
buttonTitle: TranslationBase.of(context).download,
buttonIcon: "assets/images/new/download_1.svg",
showConfirmMessageDialog: false,
isDownload: true,
onTap: widget.onTap!,
),
mainAxisSize: MainAxisSize.max,
children: [
_buildDoctorHeader(),
SizedBox(height: 10),
if (model.labResultLists.isNotEmpty)
Container(
child: Column(
children: [
InkWell(
onTap: () {
setState(
() {
_isShowMoreGeneral = !_isShowMoreGeneral;
},
);
},
child: Container(
padding: EdgeInsets.only(left: 17, top: 12, right: 13, bottom: 12),
margin: EdgeInsets.only(left: 21, right: 21, top: 12),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(.05),
//spreadRadius: 5,
blurRadius: 27,
offset: Offset(0, -3),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Text(
TranslationBase.of(context).generalResult,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.64, height: 25 / 16),
),
),
Icon(
_isShowMoreGeneral ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Color(0xff575757),
size: 22,
)
],
),
if (_isShowMoreGeneral)
...List.generate(
model.labResultLists.length,
(index) => LabResultWidget(
patientLabOrder: widget.patientLabOrder,
filterName: model.labResultLists[index].filterName,
patientLabResultList: model.labResultLists[index].patientLabResultList,
),
)
],
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(21.0),
child: _buildLabResultsList(model),
),
InkWell(
onTap: () {
setState(() {
_isShowMore = !_isShowMore;
});
},
child: Container(
padding: EdgeInsets.only(left: 17, top: 14, right: 13, bottom: 10),
margin: EdgeInsets.only(left: 21, right: 21, top: 12),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(.05),
//spreadRadius: 5,
blurRadius: 27,
offset: Offset(0, -3),
// Expanded(
// child: _buildLabResultsList(model),
// ),
_buildSpecialResultsToggle(),
SizedBox(height: 16),
],
),
),
);
}
Widget _buildDoctorHeader() {
return DoctorHeader(
headerModel: HeaderModel(
widget.patientLabOrder!.doctorName!,
widget.patientLabOrder!.doctorID ?? 0,
widget.patientLabOrder!.doctorImageURL!,
widget.patientLabOrder!.speciality ?? [""],
widget.billNo!,
widget.patientLabOrder!.projectName ?? "",
widget.patientLabOrder!.orderDate!,
"",
widget.patientLabOrder!.nationalityFlagURL ?? "",
widget.patientLabOrder!.doctorRate!,
widget.patientLabOrder!.actualDoctorRate!,
widget.patientLabOrder!.noOfPatientsRate!,
projectViewModel.user.emailAddress!,
),
onTap: widget.onTap!,
buttonColor: Color(0xFF09AA28),
buttonTitle: TranslationBase.of(context).download,
buttonIcon: "assets/images/svg/download_1.svg",
showConfirmMessageDialog: widget.showConfirmMessageDialog,
isDownload: true,
);
}
Widget _buildLabResultsList(LabsViewModel model) {
return ListView.separated(
shrinkWrap: true,
itemCount: model.labResultLists.length,
physics: NeverScrollableScrollPhysics(),
separatorBuilder: (_, __) => SizedBox(
height: 26,
),
itemBuilder: (context, index) {
var data = model.labResultLists[index];
return LabItem(
key: ValueKey(data.filterName),
item: data,
patientLabOrders: widget.patientLabOrder);
},
);
}
Widget _buildSpecialResultsToggle() {
return InkWell(
onTap: () {
setState(() {
_isShowMore = !_isShowMore;
});
},
child: Container(
padding: EdgeInsets.only(left: 17, top: 14, right: 13, bottom: 10),
margin: EdgeInsets.only(left: 21, right: 21, top: 12),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(.05),
blurRadius: 27,
offset: Offset(0, -3),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: <Widget>[
Expanded(
child: Text(
TranslationBase.of(context).specialResult,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color(0xff2E303A),
letterSpacing: -0.64,
height: 25 / 16,
),
],
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: <Widget>[
Expanded(
child: Text(
TranslationBase.of(context).specialResult,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.64, height: 25 / 16),
),
),
Icon(
_isShowMore ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Color(0xff575757),
size: 22,
)
],
),
if (_isShowMore)
Container(
width: MediaQuery.of(context).size.width * 0.9,
child: HtmlWidget(labSpecialResult),
),
],
Icon(
_isShowMore
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Color(0xff575757),
size: 22,
),
),
],
),
if (_isShowMore)
Container(
width: double.infinity,
child: Html(
data: labSpecialResult ??
TranslationBase.of(context).noDataAvailable,
),
),
],
),
),

@ -0,0 +1,167 @@
import 'package:diplomaticquarterapp/core/model/labs/lab_result.dart';
import 'package:diplomaticquarterapp/core/model/labs/patient_lab_orders.dart';
import 'package:diplomaticquarterapp/theme/colors.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/data_display/medical/LabResult/newUI/labWidgets.dart';
import 'package:flutter/material.dart';
import 'package:readmore/readmore.dart';
import '../FlowChartPage.dart';
class LabItem extends StatefulWidget {
final LabResultList item;
PatientLabOrders? patientLabOrders;
LabItem({super.key, required this.item, this.patientLabOrders});
@override
State<LabItem> createState() => _LabItemState();
}
class _LabItemState extends State<LabItem> {
bool _isShowMoreGeneral = false;
bool showBottomSheet = false;
@override
void initState() {
super.initState();
if (showBottomSheet) {
print('the bottom sheet is showing');
openFlowChart(context, '');
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: () {
setState(() {
_isShowMoreGeneral = !_isShowMoreGeneral;
});
},
behavior: HitTestBehavior.opaque,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Text(
widget.item.filterName ?? '',
style: TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
color: Color(0xff2B353E),
letterSpacing: -0.64,
height: 25 / 16),
),
),
Icon(
_isShowMoreGeneral
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Color(0xff2B353E),
size: 26,
)
],
),
),
SizedBox(
height: 12,
),
ReadMoreText(
widget.item.description ?? '',
trimMode: TrimMode.Line,
trimLines: 3,
style: const TextStyle(color: Color(0xff575757), fontSize: 11),
colorClickableText: CustomColors.accentColor,
trimCollapsedText: '${TranslationBase.of(context).readMore}',
trimExpandedText: ' show less',
),
SizedBox(
height: 8,
),
if (_isShowMoreGeneral)
...List.generate(widget.item.patientLabResultList?.length ?? 0,
(index) {
var data = widget.item.patientLabResultList?[index];
return Column(
children: [
ItemResultCardWidgetWithParams(
title: data?.description ?? '',
subTitle: data?.resultValue ?? '',
referenceRange: data?.referanceRange ?? '',
percentage: data?.percentage ?? 0.0,
note: data?.testShortDescription ?? '',
source: "",
buttonText: "",
type: data?.calculatedResultFlag?.getType() ??
ResultTypes.unknown,
shouldShowResultBarAndGraph: data?.shouldShowResultBarAndGraph()??true,
onButtonPressed: () {
openFlowChart(context, data?.description ?? '');
},
),
SizedBox(
height: 13,
),
],
);
})
// Expanded(
// child: ListView.builder(
// itemCount: widget.item.patientLabResultList?.length ?? 0,
// itemBuilder: (context, index) {
// var data = widget.item.patientLabResultList?[index];
// Column(
// children: [
// EllipsisTextWithMore(
// text: data?.packageShortDescription ?? '',
// ),
// SizedBox(
// height: 8,
// ),
// ItemResultCardWidgetWithParams(
// title: data?.description ?? '',
// subTitle: data?.resultValue ?? '',
// referenceRange: data?.referanceRange ?? '',
// percentage: 20,
// note: data?.testShortDescription ?? '',
// source: "",
// buttonText: "",
// type: data?.calculatedResultFlag?.getType() ??
// ResultTypes.unknown),
// ],
// );
// }))
],
);
}
openFlowChart(BuildContext context, String procedure) {
print('openFlowChart: the bottom sheet is showing');
showModalBottomSheet(
backgroundColor: Colors.white,
isScrollControlled: true,
context: context,
scrollControlDisabledMaxHeightRatio: .75,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20))),
builder: (context) {
print('builder: the bottom sheet is showing');
return FlowChartPage(
filterName: procedure,
patientLabOrder: widget.patientLabOrders,
);
}).then((value) {
setState(() {
showBottomSheet = false;
});
});
}
}

@ -0,0 +1,543 @@
import 'dart:math';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:flutter/material.dart';
///@author
///
enum ResultTypes {
lowCriticalLow,
criticalLow,
low,
normal,
high,
criticalHigh,
highCriticalHigh,
IRR,
unknown
}
class ItemResultCardWidget extends StatelessWidget {
final Widget child;
const ItemResultCardWidget({
Key? key,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12, bottom: 12),
child: child,
),
),
],
);
}
}
class CustomResultProgressBar extends StatelessWidget {
final num percentage;
final String value;
final ResultTypes type;
CustomResultProgressBar(
{Key? key,
required this.percentage,
required this.value,
required this.type})
: super(key: key);
final GlobalKey lcl = GlobalKey();
final GlobalKey cl = GlobalKey();
final GlobalKey l = GlobalKey();
final GlobalKey n = GlobalKey();
final GlobalKey h = GlobalKey();
final GlobalKey ch = GlobalKey();
final GlobalKey hch = GlobalKey();
OverlayEntry? overlayEntry;
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final double totalWidth = constraints.maxWidth;
final double spacing = 2;
final double tooltipPosition = (totalWidth * (percentage / 100)).clamp(0, totalWidth - 50);
return Stack(
children: [
Row(
children: [
_buildResultBar(
key: cl,
flex: 3,
color: Color(0xFFDE7676),
title: TranslationBase.of(context).criticalLow,
),
SizedBox(
width: 2,
),
_buildResultBar(
key: l,
flex: 2,
color: Color(0xFFEAB157),
title: TranslationBase.of(context).low,
),
SizedBox(
width: 2,
),
_buildResultBar(
key: n,
flex: 5,
color: Color(0xFF09AA28),
title: TranslationBase.of(context).normal,
),
SizedBox(
width: 2,
),
_buildResultBar(
key: h,
flex: 2,
color: Color(0xFFEAB157),
title: TranslationBase.of(context).high,
),
SizedBox(
width: 2,
),
_buildResultBar(
key: ch,
flex: 3,
color: Color(0xFFDE7676),
title: TranslationBase.of(context).criticalHigh,
),
],
),
if (!percentage.isNegative)
Positioned(
left: tooltipPosition,
top: 33,
child: Column(
children: [
TextCloud(
text: "${value}",
color: getColorForResultType(type),
width: 100,
height: 20,
padding: EdgeInsets.zero,
axisDirection: AxisDirection.up,
),
],
),
),
],
);
});
}
Color getColorForResultType(ResultTypes type) {
switch (type) {
case ResultTypes.lowCriticalLow:
case ResultTypes.highCriticalHigh:
case ResultTypes.criticalLow:
case ResultTypes.criticalHigh:
return Color(0xFFDE7676);
case ResultTypes.low:
case ResultTypes.high:
return Color(0xFFEAB157);
case ResultTypes.normal:
return Color(0xFF09AA28);
default:
return Color(0xFF09AA28);
}
}
Widget _buildResultBar({
required int flex,
required Color color,
required String title,
Key? key}) {
return Expanded(
key: key,
flex: flex,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
title,
style: TextStyle(
fontSize: 8,
fontFamily: 'Poppins',
letterSpacing: -0.3,
color: color,
fontWeight: FontWeight.w400,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 5),
Container(
height: 5,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
),
],
),
);
}
}
class TextCloud extends StatelessWidget {
final String text; // write here box content
final Color color; // Set box Color
final EdgeInsets padding; // Set content padding
final double width; // Box width
final double height; // Box Height
final AxisDirection axisDirection; // Set triangle location up,left,right,down
final double locationOfArrow; // set between 0 and 1, If 0.5 is set triangle position will be centered
const TextCloud({
super.key,
required this.text,
this.color = Colors.white,
this.padding = const EdgeInsets.all(10),
this.width = 200,
this.height = 100,
this.axisDirection = AxisDirection.down,
this.locationOfArrow = 0.5,
});
@override
Widget build(BuildContext context) {
Size arrowSize = const Size(12, 12);
return Stack(
clipBehavior: Clip.none,
children: [
Container(
width: width,
height: height,
padding: padding,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
text,
style: TextStyle(color: Colors.white, fontSize: 9, letterSpacing: -.3),
)),
),
Builder(builder: (context) {
double angle = 0;
switch (axisDirection) {
case AxisDirection.left:
angle = pi * -0.5;
break;
case AxisDirection.up:
angle = pi * -2;
break;
case AxisDirection.right:
angle = pi * 0.5;
break;
case AxisDirection.down:
angle = pi;
break;
default:
angle = 0;
}
return Positioned(
left: axisDirection == AxisDirection.left
? -arrowSize.width + 5
: (axisDirection == AxisDirection.up || axisDirection == AxisDirection.down ? width * locationOfArrow - arrowSize.width / 2 : null),
right: axisDirection == AxisDirection.right ? -arrowSize.width + 5 : null,
top: axisDirection == AxisDirection.up
? -arrowSize.width + 5
: (axisDirection == AxisDirection.right || axisDirection == AxisDirection.left ? height * locationOfArrow - arrowSize.width / 2 : null),
bottom: axisDirection == AxisDirection.down ? -arrowSize.width + 5 : null,
child: Transform.rotate(
angle: angle,
child: CustomPaint(
size: arrowSize,
painter: ArrowPaint(color: color),
),
),
);
})
],
);
}
}
class ArrowPaint extends CustomPainter {
final Color color;
ArrowPaint({required this.color});
@override
void paint(Canvas canvas, Size size) {
Path path_0 = Path();
path_0.moveTo(size.width * 0.5745375, size.height * 0.06573708);
path_0.lineTo(size.width * 0.9813667, size.height * 0.8794000);
path_0.cubicTo(size.width * 1.001950, size.height * 0.9205625, size.width * 0.9852625, size.height * 0.9706208, size.width * 0.9441000, size.height * 0.9912000);
path_0.cubicTo(size.width * 0.9325250, size.height * 0.9969875, size.width * 0.9197667, size.height, size.width * 0.9068292, size.height);
path_0.lineTo(size.width * 0.09316958, size.height);
path_0.cubicTo(size.width * 0.04714583, size.height, size.width * 0.009836208, size.height * 0.9626917, size.width * 0.009836208, size.height * 0.9166667);
path_0.cubicTo(size.width * 0.009836208, size.height * 0.9037292, size.width * 0.01284829, size.height * 0.8909708, size.width * 0.01863392, size.height * 0.8794000);
path_0.lineTo(size.width * 0.4254625, size.height * 0.06573708);
path_0.cubicTo(size.width * 0.4460458, size.height * 0.02457225, size.width * 0.4961042, size.height * 0.007886875, size.width * 0.5372667, size.height * 0.02846929);
path_0.cubicTo(size.width * 0.5533958, size.height * 0.03653296, size.width * 0.5664708, size.height * 0.04961000, size.width * 0.5745375, size.height * 0.06573708);
path_0.close();
Paint paint_0_fill = Paint()..style = PaintingStyle.fill;
paint_0_fill.color = color;
canvas.drawPath(path_0, paint_0_fill);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class ItemResultCardWidgetWithParams extends StatelessWidget {
final String title;
final String subTitle;
final String note;
final String source;
final String referenceRange;
final num percentage;
final String buttonText;
final ResultTypes type;
final bool isArabic;
final bool shouldShowResultBarAndGraph;
final Function()? onButtonPressed;
const ItemResultCardWidgetWithParams({
Key? key,
required this.title,
required this.subTitle,
required this.referenceRange,
required this.percentage,
required this.note,
required this.source,
required this.buttonText,
required this.type,
this.onButtonPressed,
this.isArabic = false,
this.shouldShowResultBarAndGraph = true,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final fontFamily = isArabic ? 'Cairo' : 'Poppins';
return Container(
margin: const EdgeInsets.only(top: 21),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: BorderDirectional(
start: BorderSide(
color: getColorForResultType(type),
width: MediaQuery.of(context).size.width * 0.015,
),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
// Title Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w600,
color: const Color(0xff2E303A),
letterSpacing: -.64),
),
),
Visibility(
visible: shouldShowResultBarAndGraph,
child: GestureDetector(
onTap: onButtonPressed,
child: Utils.tableColumnValueWithUnderLine(TranslationBase.of(context).viewFlowChart, isLast: true, isCapitable: false),
),
),
],
),
const SizedBox(height: 8),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ResultStatusWidget(type: type),
SizedBox(width: 5),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
subTitle,
style: TextStyle(fontSize: 14, fontFamily: fontFamily, fontWeight: FontWeight.w600, color: const Color(0xff2E303A), letterSpacing: -0.56),
),
Text(
"${TranslationBase.of(context).referenceRange} \n $referenceRange",
style: TextStyle(
fontSize: 10,
fontFamily: fontFamily,
fontWeight: FontWeight.w600,
color: const Color(0xff2E303A),
letterSpacing: -0.4,
),
),
],
),
],
),
const SizedBox(height: 10),
// Progress Bar
Visibility(
visible: shouldShowResultBarAndGraph,
child: Column(
children: [
SizedBox(
height: 55,
child: CustomResultProgressBar(
percentage: percentage,
value: subTitle,
type: type,
),
),
const SizedBox(height: 12),
],
),
),
// Note Section
if (note.isNotEmpty)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(color: Color(0xFFEFEFEF), thickness: 1),
const SizedBox(height: 10),
Text(
"${TranslationBase.of(context).notes}:",
style: TextStyle(
fontSize: 12,
color: const Color(0xFF2E303A),
letterSpacing: -0.4,
fontWeight: FontWeight.bold,
),
),
Text(
note,
style: TextStyle(
fontSize: 12,
color: const Color(0xFF575757),
letterSpacing: -0.4,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 3),
],
),
),
);
}
Color getColorForResultType(ResultTypes type) {
switch (type) {
case ResultTypes.criticalLow:
case ResultTypes.criticalHigh:
case ResultTypes.lowCriticalLow:
case ResultTypes.highCriticalHigh:
return Color(0xFFDE7676);
case ResultTypes.low:
case ResultTypes.high:
return Color(0xFFEAB157);
case ResultTypes.normal:
return Color(0xFF09AA28);
//todo handle irr here
default:
return Color(0xFF09AA28);
}
}
}
class ResultStatusWidget extends StatelessWidget {
final ResultTypes type;
const ResultStatusWidget({
Key? key,
required this.type,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Color? color;
IconData? icon;
switch (type) {
case ResultTypes.criticalLow:
case ResultTypes.lowCriticalLow:
color = const Color(0xFFDE7676);
icon = Icons.arrow_circle_down;
break;
case ResultTypes.low:
color = const Color(0xFFEAB157);
icon = Icons.arrow_circle_down;
break;
case ResultTypes.criticalHigh:
case ResultTypes.highCriticalHigh:
color = const Color(0xFFDE7676);
icon = Icons.arrow_circle_up;
break;
case ResultTypes.high:
color = const Color(0xFFEAB157);
icon = Icons.arrow_circle_up;
break;
case ResultTypes.normal:
color = const Color(0xFF09AA28);
icon = Icons.check_circle;
break;
case ResultTypes.unknown:
case ResultTypes.IRR:
color = Color(0xFF09AA28);
icon = Icons.check_circle;
break;
}
// Return the icon if defined, otherwise a placeholder widget
return icon != null
? Icon(
icon,
color: color,
)
: const SizedBox(); // Use SizedBox to keep the layout consistent
}
}

@ -8,7 +8,6 @@ import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/avatar/large_avatar.dart';
import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
import 'package:diplomaticquarterapp/widgets/dialogs/confirm_send_email_dialog.dart';
import 'package:diplomaticquarterapp/widgets/my_rich_text.dart';
import 'package:flutter/material.dart';
@ -23,6 +22,7 @@ class DoctorHeader extends StatelessWidget {
final bool showConfirmMessageDialog;
final String? buttonTitle;
final String? buttonIcon;
final Color? buttonColor;
final bool isNeedToShowButton;
final bool isShowName;
final bool isDownload;
@ -35,6 +35,7 @@ class DoctorHeader extends StatelessWidget {
this.isNeedToShowButton = true,
this.isShowName = false,
this.buttonIcon,
this.buttonColor,
this.showConfirmMessageDialog = true,
this.isDownload = false,
this.onRatingAndReviewTap})
@ -177,7 +178,7 @@ class DoctorHeader extends StatelessWidget {
if (showConfirmMessageDialog)
showConfirmMessage(context, onTap!, headerModel.email);
else
onTap!();
onTap?.call();
},
child: Container(
padding: EdgeInsets.only(top: 10, bottom: 10, right: 15, left: 15),
@ -190,7 +191,8 @@ class DoctorHeader extends StatelessWidget {
SvgPicture.asset(buttonIcon ?? 'assets/images/new/email.svg', width: 19.0),
SizedBox(width: 4),
Text(
buttonTitle == null ? TranslationBase.of(context).sendEmail : buttonTitle!,
buttonTitle ??
TranslationBase.of(context).sendEmail,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white, letterSpacing: -0.64, height: 1),
),
],

@ -66,7 +66,7 @@ dependencies:
shared_preferences: ^2.0.0
# flutter_flexible_toast: ^0.1.4
fluttertoast: ^8.0.8
firebase_messaging: 14.1.0
firebase_messaging: 14.7.0
firebase_analytics: ^10.0.5
# Progress bar
flutter_progress_hud: ^2.0.2
@ -191,6 +191,7 @@ dependencies:
cloudflare_turnstile: ^2.0.1
app_links: ^6.4.0
device_info_plus: ^10.1.2
readmore: ^3.0.0
# app_links: ^6.4.0
# vital_sign_camera:
# path: ./packages/vital_sign_camera

Loading…
Cancel
Save