diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 4cf0c849..8f3239ab 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index ad89fbdc..b4401ef1 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id 'dev.flutter.flutter-plugin-loader' version "1.0.0" // apply true id "org.jetbrains.kotlin.android" version "2.0.0" apply false - id 'com.android.application' version "8.3.2" apply false + id 'com.android.application' version "8.9.0" apply false id "com.google.gms.google-services" version "4.4.0" apply false } diff --git a/lib/config/config.dart b/lib/config/config.dart index 9fb4ee51..5aca2da2 100755 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -385,6 +385,7 @@ const IS_INFECTIOUS_DISEASE_PENDING = 'Services/DoctorApplication.svc/REST/IsInt const INFECTIOUS_HISTORY = 'Services/DoctorApplication.svc/REST/InterventionHistory'; const UPDATE_INFECTIOUS_STATUS = 'Services/DoctorApplication.svc/REST/UpdateInterventionStatus'; const GET_NURSING_STATIONS = 'Services/DoctorApplication.svc/REST/GetWards'; +const GET_ATTACHMENT = 'Services/Patients.svc/REST/GetVidaLabResultAttachment'; var selectedPatientType = 1; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 54952544..9a0baa84 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -1289,6 +1289,14 @@ const Map> localizedValues = { "noPreviousDiagnosis":{ "en":"No Previous Diagnosis", "ar":"لا يوجد تشخيص سابق" + }, +"showAttachment":{ + "en":"Show\nAttachment", + "ar":"عرض\nالمرفقات" + }, +"selectAnAttachment":{ + "en":"Select An Attachment", + "ar":"اختر مرفقاً" } }; diff --git a/lib/core/model/labs/lab_attachment_item.dart b/lib/core/model/labs/lab_attachment_item.dart new file mode 100644 index 00000000..f6b60f5c --- /dev/null +++ b/lib/core/model/labs/lab_attachment_item.dart @@ -0,0 +1,28 @@ +class LabAttachmentItem { + String? base64Content; + String? fileName; + int? fileSize; + + LabAttachmentItem({this.base64Content, this.fileName, this.fileSize}); + + LabAttachmentItem.fromJson(Map json) { + base64Content = json['base64Content']; + fileName = json['fileName']; + fileSize = json['fileSize']; + } + + Map toJson() { + final Map data = Map(); + data['base64Content'] = base64Content; + data['fileName'] = fileName; + data['fileSize'] = fileSize; + return data; + } + + static List fromJsonList(List jsonList) { + return jsonList + .map((item) => LabAttachmentItem.fromJson(item as Map)) + .toList(); + } +} + diff --git a/lib/core/model/labs/lab_result.dart b/lib/core/model/labs/lab_result.dart index 4e5df0fc..75040ccb 100644 --- a/lib/core/model/labs/lab_result.dart +++ b/lib/core/model/labs/lab_result.dart @@ -20,6 +20,11 @@ class LabResult { String? uOM; String? verifiedOn; dynamic verifiedOnDateTime; + bool? IsLabTestAttachment; // for the attachment icon in the lab result list + dynamic LabAccessionNo; + List? FileNameWithExtensionList; + dynamic FileHash; + List? UploadedDocuments; LabResult( {this.description, @@ -42,7 +47,12 @@ class LabResult { this.testCode, this.uOM, this.verifiedOn, - this.verifiedOnDateTime}); + this.verifiedOnDateTime, + this.IsLabTestAttachment, + this.LabAccessionNo, + this.FileNameWithExtensionList, + this.FileHash, + this.UploadedDocuments}); LabResult.fromJson(Map json) { description = json['Description']; @@ -66,6 +76,23 @@ class LabResult { uOM = json['UOM']; verifiedOn = json['VerifiedOn']; verifiedOnDateTime = json['VerifiedOnDateTime']; + IsLabTestAttachment = json['IsLabTestAttachment'] ?? false; + + LabAccessionNo = json['LabAccessionNo'] ?? json['AccessionNo']; + + if (json['FileNameWithExtensionList'] != null) { + FileNameWithExtensionList = []; + json['FileNameWithExtensionList'].forEach((v) { + if (v["FileNameWithExtension"] != null) FileNameWithExtensionList?.add(v["FileNameWithExtension"]); + }); + } + FileHash = json['FileHash']; + if (json['UploadedDocuments'] != null) { + UploadedDocuments = []; + json['UploadedDocuments'].forEach((v) { + UploadedDocuments!.add(new UploadedDocument.fromJson(v)); + }); + } } Map toJson() { @@ -91,6 +118,10 @@ class LabResult { data['UOM'] = this.uOM; data['VerifiedOn'] = this.verifiedOn; data['VerifiedOnDateTime'] = this.verifiedOnDateTime; + data['IsLabTestAttachment'] = this.IsLabTestAttachment; + data['LabAccessionNo'] = this.LabAccessionNo; + data['FileNameWithExtension'] = this.IsLabTestAttachment; + data['FileHash'] = this.FileHash; return data; } @@ -124,3 +155,25 @@ class LabResultList { patientLabResultList.add(lab!); } } + +class UploadedDocument { + String? fileData; + String? fileName; + String? fileType; + + UploadedDocument({this.fileData, this.fileName, this.fileType}); + + UploadedDocument.fromJson(Map json) { + fileData = json['FileData']; + fileName = json['FileName']; + fileType = json['FileType']; + } + + Map toJson() { + final Map data = new Map(); + data['FileData'] = this.fileData; + data['FileName'] = this.fileName; + data['FileType'] = this.fileType; + return data; + } +} diff --git a/lib/core/model/labs/patient_lab_orders.dart b/lib/core/model/labs/patient_lab_orders.dart index 16f1ebd7..fc767224 100644 --- a/lib/core/model/labs/patient_lab_orders.dart +++ b/lib/core/model/labs/patient_lab_orders.dart @@ -16,6 +16,7 @@ class PatientLabOrders { int? gender; String? genderDescription; String? invoiceNo; + String? InvoiceNo_VP; bool? isActiveDoctorProfile; bool? isDoctorAllowVedioCall; bool? isExecludeDoctor; @@ -53,6 +54,7 @@ class PatientLabOrders { this.gender, this.genderDescription, this.invoiceNo, + this.InvoiceNo_VP, this.isActiveDoctorProfile, this.isDoctorAllowVedioCall, this.isExecludeDoctor, @@ -90,6 +92,7 @@ class PatientLabOrders { gender = json['Gender']; genderDescription = json['GenderDescription']; invoiceNo = json['InvoiceNo'].toString(); + InvoiceNo_VP = json['InvoiceNo_VP'].toString(); isActiveDoctorProfile = json['IsActiveDoctorProfile']; isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall']; isExecludeDoctor = json['IsExecludeDoctor']; diff --git a/lib/core/model/patient/lab_result/lab_result.dart b/lib/core/model/patient/lab_result/lab_result.dart index f083a6d3..a625b707 100644 --- a/lib/core/model/patient/lab_result/lab_result.dart +++ b/lib/core/model/patient/lab_result/lab_result.dart @@ -27,6 +27,11 @@ class LabResult { dynamic femaleInterpretativeData; String? testCode; String? statusDescription; + bool? IsLabTestAttachment; // for the attachment icon in the lab result list + dynamic LabAccessionNo; + dynamic FileNameWithExtension; + dynamic FileHash; + LabResult( {this.setupID, @@ -56,7 +61,12 @@ class LabResult { this.maleInterpretativeData, this.femaleInterpretativeData, this.testCode, - this.statusDescription}); + this.statusDescription, + this.IsLabTestAttachment, + this.LabAccessionNo, + this.FileNameWithExtension, + this.FileHash + }); LabResult.fromJson(Map json) { setupID = json['SetupID']; @@ -87,6 +97,10 @@ class LabResult { femaleInterpretativeData = json['FemaleInterpretativeData']; testCode = json['TestCode']; statusDescription = json['StatusDescription']; + IsLabTestAttachment = json['IsLabTestAttachment'] ?? false; + FileNameWithExtension = json['FileNameWithExtension'] ; + LabAccessionNo = json['LabAccessionNo'] ; + FileHash = json['FileHash'] ; } Map toJson() { @@ -119,6 +133,10 @@ class LabResult { data['FemaleInterpretativeData'] = this.femaleInterpretativeData; data['TestCode'] = this.testCode; data['StatusDescription'] = this.statusDescription; + data['IsLabTestAttachment'] = this.IsLabTestAttachment; + data['LabAccessionNo'] = this.statusDescription; + data['FileNameWithExtension'] = this.IsLabTestAttachment; + data['FileHash'] = this.FileHash; return data; } } diff --git a/lib/core/service/patient_medical_file/lab_order/labs_service.dart b/lib/core/service/patient_medical_file/lab_order/labs_service.dart index 75a97373..4416921b 100644 --- a/lib/core/service/patient_medical_file/lab_order/labs_service.dart +++ b/lib/core/service/patient_medical_file/lab_order/labs_service.dart @@ -1,6 +1,7 @@ import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/core/model/labs/all_special_lab_result_model.dart'; import 'package:doctor_app_flutter/core/model/labs/all_special_lab_result_request.dart'; +import 'package:doctor_app_flutter/core/model/labs/lab_attachment_item.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_order_result.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_result.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_result_history.dart'; @@ -9,6 +10,7 @@ import 'package:doctor_app_flutter/core/model/labs/patient_lab_special_result.da import 'package:doctor_app_flutter/core/model/labs/request_patient_lab_special_result.dart'; import 'package:doctor_app_flutter/core/model/labs/request_send_lab_report_email.dart'; import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import '../../base/base_service.dart'; @@ -57,6 +59,7 @@ class LabsService extends BaseService { List patientLabSpecialResult = []; List labResultList = []; List labOrdersResultsList = []; + List labAttachment = []; List labOrdersResultHistoryList = []; Future getLaboratoryResult({String? projectID, int? clinicID, String? invoiceNo, String? orderNo, required PatiantInformtion patient, bool isInpatient = false}) async { @@ -92,7 +95,11 @@ class LabsService extends BaseService { } Map body = Map(); - body['InvoiceNo'] = patientLabOrder.invoiceNo; + if(ProjectViewModel.getVidaPlusStatus()){ + body['InvoiceNo_VP'] = patientLabOrder.InvoiceNo_VP; + }else { + body['InvoiceNo'] = patientLabOrder.invoiceNo; + } body['OrderNo'] = patientLabOrder.orderNo; body['isDentalAllowedBackend'] = false; body['SetupID'] = patientLabOrder.setupID; @@ -209,4 +216,28 @@ class LabsService extends BaseService { super.error = error; }, body: _allSpecialLabResultRequestModel.toJson()); } + + Future getLabAttachments(PatiantInformtion patient,{required labAccessNumber, required FileName, required FileHash}) async { + + hasError = false; + Map body = Map(); + body['FileHash'] = [FileHash??FileName??""]; + + if(ProjectViewModel.getVidaPlusStatus()){ + body['Lang'] = "en"??""; + body['Internationalization'] = false; + }else { + body['LabAccessionNumber'] = labAccessNumber??""; + } + await baseAppClient.postPatient(GET_ATTACHMENT, patient: patient, onSuccess: (dynamic response, int statusCode) { + labAttachment.clear(); + response['GetVidaLabAttachment']['data'].forEach((lab) { + labAttachment.add(LabAttachmentItem.fromJson(lab)); + }); + }, onFailure: (String error, int statusCode) { + labAttachment.clear(); + hasError = true; + super.error = error; + }, body: body); + } } diff --git a/lib/core/viewModel/labs_view_model.dart b/lib/core/viewModel/labs_view_model.dart index db524c2c..3a776368 100644 --- a/lib/core/viewModel/labs_view_model.dart +++ b/lib/core/viewModel/labs_view_model.dart @@ -1,6 +1,7 @@ import 'package:doctor_app_flutter/core/enum/filter_type.dart'; import 'package:doctor_app_flutter/core/enum/view_state.dart'; import 'package:doctor_app_flutter/core/model/labs/all_special_lab_result_model.dart'; +import 'package:doctor_app_flutter/core/model/labs/lab_attachment_item.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_order_result.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_result.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_result_history.dart'; @@ -10,7 +11,9 @@ import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/core/service/patient_medical_file/lab_order/labs_service.dart'; import 'package:doctor_app_flutter/locator.dart'; import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:open_filex/open_filex.dart'; +import '../../utils/utils.dart'; import 'base_view_model.dart'; class LabsViewModel extends BaseViewModel { @@ -73,6 +76,8 @@ class LabsViewModel extends BaseViewModel { List labResultLists = []; + List? get attachments => _labsService.labAttachment; + getLaboratoryResult({String? projectID, int? clinicID, String? invoiceNo, String? orderNo, PatiantInformtion? patient, bool? isInpatient}) async { setState(ViewState.Busy); await _labsService.getLaboratoryResult(invoiceNo: invoiceNo, orderNo: orderNo, projectID: projectID, clinicID: clinicID, patient: patient!, isInpatient: isInpatient!); @@ -153,4 +158,34 @@ class LabsViewModel extends BaseViewModel { } else setState(ViewState.Idle); } + + Future getLabAttachments(PatiantInformtion patient,{ dynamic labAccessNumber, dynamic FileName, dynamic FileHash, UploadedDocument? uploadedDocument}) async { + setState(ViewState.Busy); + + await _labsService.getLabAttachments(patient,labAccessNumber: labAccessNumber, FileName: FileName, FileHash:uploadedDocument?.fileData ); + if (_labsService.hasError) { + error = _labsService.error; + setState(ViewState.Error); + } else + setState(ViewState.Idle); + } + + Future openPDF() async { + if (this.attachments?.isEmpty == true) { + Utils.showErrorToast("Unable to show Attachments"); + return; + } + + if(this.attachments?.first.base64Content == null || this.attachments?.first.base64Content?.isEmpty == true){ + Utils.showErrorToast("Unable to show Attachments"); + return; + } + + String path = await Utils.createFileFromString(this.attachments?.first.base64Content??"", "pdf"); + try { + OpenFilex.open(path); + } catch (ex) { + Utils.showErrorToast("Unable to show Attachments"); + } + } } diff --git a/lib/screens/patients/profile/lab_result/laboratory_result/lab_result_widget.dart b/lib/screens/patients/profile/lab_result/laboratory_result/lab_result_widget.dart index 96ad469c..1f794daa 100644 --- a/lib/screens/patients/profile/lab_result/laboratory_result/lab_result_widget.dart +++ b/lib/screens/patients/profile/lab_result/laboratory_result/lab_result_widget.dart @@ -1,14 +1,17 @@ import 'package:doctor_app_flutter/config/size_config.dart'; import 'package:doctor_app_flutter/core/model/labs/lab_result.dart'; import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/viewModel/labs_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/screens/patients/profile/lab_result/laboratory_result/flow_chart_page.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:provider/provider.dart'; class LabResultWidget extends StatelessWidget { @@ -17,8 +20,10 @@ class LabResultWidget extends StatelessWidget { final PatientLabOrders patientLabOrder; final PatiantInformtion patient; final bool isInpatient; + final LabsViewModel model; - LabResultWidget({Key? key, required this.filterName, required this.patientLabResultList, required this.patientLabOrder, required this.patient, required this.isInpatient}) : super(key: key); + LabResultWidget({Key? key, required this.filterName, required this.patientLabResultList, required this.patientLabOrder, required this.patient, required this.isInpatient, required this.model}) + : super(key: key); late ProjectViewModel projectViewModel; @override @@ -177,34 +182,77 @@ class LabResultWidget extends StatelessWidget { ), ), Expanded( - child: Container( - child: InkWell( - onTap: () { - Navigator.push( - context, - FadePage( - page: FlowChartPage( - filterName: patientLabResultList[index].description!, - patientLabOrder: patientLabOrder, - patient: patient, - isInpatient: isInpatient, - ), - ), - ); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AppText( - TranslationBase.of(context).showMoreBtn, - textDecoration: TextDecoration.underline, - color: Colors.red.shade700, - fontSize: SizeConfig.textMultiplier! * 1.8, - fontWeight: FontWeight.w700, + child: Column( + children: [ + Visibility( + visible: patientLabResultList[index].IsLabTestAttachment ?? false, + child: InkWell( + onTap: () async { + var labAccessNumber = patientLabResultList[index].LabAccessionNo; + if (patientLabResultList[index].FileNameWithExtensionList?.isEmpty == true || patientLabResultList[index].FileNameWithExtensionList?.length == 1) { + await model.getLabAttachments(patient, labAccessNumber: labAccessNumber, FileName: patientLabResultList[index].FileNameWithExtensionList?.first); + model.openPDF(); + return; + } + + if (patientLabResultList[index].UploadedDocuments?.isEmpty == true || patientLabResultList[index].UploadedDocuments?.length == 1) { + await model.getLabAttachments(patient, labAccessNumber: labAccessNumber, uploadedDocument: patientLabResultList[index].UploadedDocuments?.first); + model.openPDF(); + return; + } + + showUploadedDocumentsBottomSheet( + context, + documents: patientLabResultList[index].UploadedDocuments, + fileName: patientLabResultList[index].FileNameWithExtensionList, + labAccessNumber: labAccessNumber, + ); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AppText( + TranslationBase.of(context).showAttachment, + textDecoration: TextDecoration.underline, + color: Colors.red.shade700, + fontSize: SizeConfig.textMultiplier! * 1.2, + fontWeight: FontWeight.w700, + ), + ], ), - ], + ), ), - ), + SizedBox( + height: 8, + ), + InkWell( + onTap: () { + Navigator.push( + context, + FadePage( + page: FlowChartPage( + filterName: patientLabResultList[index].description!, + patientLabOrder: patientLabOrder, + patient: patient, + isInpatient: isInpatient, + ), + ), + ); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AppText( + TranslationBase.of(context).showMoreBtn, + textDecoration: TextDecoration.underline, + color: Colors.red.shade700, + fontSize: SizeConfig.textMultiplier! * 1.4, + fontWeight: FontWeight.w700, + ), + ], + ), + ), + ], ), ), ], @@ -306,4 +354,111 @@ class LabResultWidget extends StatelessWidget { }); return tableRow; } + + void showUploadedDocumentsBottomSheet( + BuildContext context, { + List? documents, + List? fileName, + String? labAccessNumber, + }) { + const double kItemHeight = 66.0; // ListTile with contentPadding: 10 + final double screenHeight = MediaQuery.of(context).size.height; + final double maxSheetHeight = screenHeight * 0.5; + final double minSheetHeight = (kItemHeight + 100).clamp(0, maxSheetHeight); + + showModalBottomSheet( + context: context, + isScrollControlled: true, // lets the sheet respect custom height constraints + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (BuildContext context) { + return ConstrainedBox( + constraints: BoxConstraints( + minHeight: minSheetHeight, + maxHeight: maxSheetHeight, + ), + child: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Drag handle + Container( + margin: const EdgeInsets.symmetric(vertical: 8), + width: 40, + height: 4, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(2), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + TranslationBase.of(context).selectAnAttachment, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + Flexible( + child: Padding( + padding: const EdgeInsets.all(16), + child: Material( + color: const Color(0X55F2F2F2), + child: ListView.separated( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: documents?.length ?? fileName?.length ?? 0, + separatorBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: const Divider(height: 1, color: Colors.grey), + ), + itemBuilder: (context, index) { + final docName = documents?[index]?.fileName ?? fileName?[index]; + + return ListTile( + contentPadding: const EdgeInsets.all(10), + title: Text( + docName ?? "Unnamed Document", + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + trailing: const Icon( + Icons.chevron_right, + color: Colors.grey, + ), + onTap: () async { + Navigator.pop(context); + if (documents?.isNotEmpty == true) { + await model.getLabAttachments(patient, uploadedDocument: documents![index]); + model.openPDF(); + } + if (fileName?.isNotEmpty == true) { + await model.getLabAttachments(patient, labAccessNumber: labAccessNumber, FileName: fileName![index]); + model.openPDF(); + } + }, + ); + }, + ), + ), + ), + ), + const SizedBox(height: 8), + ], + ), + ), + ); + }, + ); + } } diff --git a/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_page.dart b/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_page.dart index c531a2f7..f91d3d6c 100644 --- a/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_page.dart +++ b/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_page.dart @@ -30,26 +30,29 @@ class _LaboratoryResultPageState extends State { builder: (_, model, w) => AppScaffold( isShowAppBar: true, appBar: PatientProfileAppBar( - widget.patient, - isInpatient: widget.isInpatient, - isFromLabResult: true, - appointmentDate: widget.patientLabOrders.orderDate!, + widget.patient, + isInpatient: widget.isInpatient, + isFromLabResult: false, + appointmentDate: widget.patientLabOrders.orderDate! ), baseViewModel: model, - body: AppScaffold( - isShowAppBar: false, - body: SingleChildScrollView( - child: LaboratoryResultWidget( - onTap: () async {}, - billNo: widget.patientLabOrders.invoiceNo!, - details: model.patientLabSpecialResult.length > 0 ? model.patientLabSpecialResult[0].resultDataHTML! : "", - orderNo: widget.patientLabOrders.orderNo!, - patientLabOrder: widget.patientLabOrders, - patient: widget.patient, - isInpatient: widget.patientType == "1", - invoiceType: widget.patientLabOrders.invoiceType!), - ), + body: SingleChildScrollView( + child: Column( + children: [ + + LaboratoryResultWidget( + onTap: () async {}, + billNo: widget.patientLabOrders.invoiceNo!, + details: model.patientLabSpecialResult.length > 0 ? model.patientLabSpecialResult[0].resultDataHTML! : "", + orderNo: widget.patientLabOrders.orderNo!, + patientLabOrder: widget.patientLabOrders, + patient: widget.patient, + isInpatient: widget.patientType == "1", + invoiceType: widget.patientLabOrders.invoiceType!), + ], + ), ), + ), ); } diff --git a/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_widget.dart b/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_widget.dart index b2bc5752..27dbd7ab 100644 --- a/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_widget.dart +++ b/lib/screens/patients/profile/lab_result/laboratory_result/laboratory_result_widget.dart @@ -44,183 +44,183 @@ class _LaboratoryResultWidgetState extends State { // patientLabOrder: widget.patientLabOrder, // patient: widget.patient, // isInpatient: widget.isInpatient), - builder: (_, model, w) => NetworkBaseView( - baseViewModel: model, - child: Container( - margin: EdgeInsets.all(15), - child: Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, + builder: (_, model, w) => SingleChildScrollView( + child: NetworkBaseView( + baseViewModel: model, + child: SafeArea( + child: Container( + margin: EdgeInsets.all(15), + child: Column( children: [ - SizedBox( - height: 12, - ), - if (model.labResultLists.isNotEmpty) - Container( - child: Column( - children: [ - InkWell( - onTap: () { - setState( - () { - _isShowMoreGeneral = !_isShowMoreGeneral; + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + if (model.labResultLists.isNotEmpty) + Container( + child: Column( + children: [ + InkWell( + onTap: () { + setState( + () { + _isShowMoreGeneral = !_isShowMoreGeneral; + }, + ); }, - ); - }, - child: Container( - padding: EdgeInsets.all(10.0), - margin: EdgeInsets.only(left: 5, right: 5), - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: Colors.white, - borderRadius: BorderRadius.all( - Radius.circular(5.0), + child: Container( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + child: Row( + children: [ + Expanded( + child: Container( + margin: EdgeInsets.only(left: 0, right: 0), + child: AppText( + TranslationBase.of(context).generalResult, + fontSize: SizeConfig.textMultiplier! * 2.3, + bold: false, + ))), + Container( + width: 25, + height: 25, + child: Icon( + _isShowMoreGeneral ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, + color: Colors.grey[800], + size: 22, + ), + ) + ], + ), ), ), - child: Row( - children: [ - Expanded( - child: Container( - margin: EdgeInsets.only(left: 0, right: 0), - child: AppText( - TranslationBase.of(context).generalResult, - fontSize: SizeConfig.textMultiplier! * 2.3, - bold: false, - ))), - Container( - width: 25, - height: 25, - child: Icon( - _isShowMoreGeneral ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, - color: Colors.grey[800], - size: 22, + if (_isShowMoreGeneral) + AnimatedContainer( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(5.0), + bottomRight: Radius.circular(5.0), ), - ) - ], - ), - ), - ), - if (_isShowMoreGeneral) - AnimatedContainer( - padding: EdgeInsets.all(10.0), - margin: EdgeInsets.only(left: 5, right: 5), - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: Colors.white, - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(5.0), - bottomRight: Radius.circular(5.0), + ), + duration: Duration(milliseconds: 7000), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.builder( + itemCount: model.labResultLists.length, + scrollDirection: Axis.vertical, + physics: ScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, index) { + return LabResultWidget( + patientLabOrder: widget.patientLabOrder!, + filterName: model.labResultLists[index].filterName, + patientLabResultList: model.labResultLists[index].patientLabResultList, + patient: widget.patient!, + isInpatient: widget.isInpatient!, + model: model, + ); + }), + ], + ), ), - ), - duration: Duration(milliseconds: 7000), + ], + ), + ) + else if (widget.details == null) + Container( + child: ErrorMessage( + error: TranslationBase.of(context).noDataAvailable, + ), + ), + SizedBox( + height: 15, + ), + if (widget.details != null && widget.details!.isNotEmpty) + Column( + children: [ + InkWell( + onTap: () { + setState(() { + _isShowMore = !_isShowMore; + }); + }, child: Container( - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(5.0), + )), + child: Row( children: [ - ListView.builder( - itemCount: model.labResultLists.length, - scrollDirection: Axis.vertical, - physics: ScrollPhysics(), - shrinkWrap: true, - itemBuilder: (context, index) { - return LabResultWidget( - patientLabOrder: widget.patientLabOrder!, - filterName: model.labResultLists[index].filterName, - patientLabResultList: model.labResultLists[index].patientLabResultList, - patient: widget.patient!, - isInpatient: widget.isInpatient!, - ); - }), + Expanded( + child: Container( + margin: EdgeInsets.only(left: 0, right: 0), + child: AppText( + TranslationBase.of(context).specialResult, + fontSize: SizeConfig.textMultiplier! * 2.3, + bold: false, + ))), + Container( + width: 25, + height: 25, + child: Icon( + _isShowMore ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, + color: Colors.grey[800], + size: 22, + ), + ) ], ), ), ), - ], - ), - ) - else if (widget.details == null) - Container( - child: ErrorMessage( - error: TranslationBase.of(context).noDataAvailable, - ), - ), - SizedBox( - height: 15, - ), - if (widget.details != null && widget.details!.isNotEmpty) - Column( - children: [ - InkWell( - onTap: () { - setState(() { - _isShowMore = !_isShowMore; - }); - }, - child: Container( - padding: EdgeInsets.all(10.0), - margin: EdgeInsets.only(left: 5, right: 5), - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: Colors.white, - borderRadius: BorderRadius.all( - Radius.circular(5.0), - )), - child: Row( - children: [ - Expanded( - child: Container( - margin: EdgeInsets.only(left: 0, right: 0), - child: AppText( - TranslationBase.of(context).specialResult, - fontSize: SizeConfig.textMultiplier! * 2.3, - bold: false, - ))), - Container( - width: 25, - height: 25, - child: Icon( - _isShowMore ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, - color: Colors.grey[800], - size: 22, - ), - ) - ], - ), - ), - ), - if (_isShowMore) - AnimatedContainer( - padding: EdgeInsets.all(10.0), - margin: EdgeInsets.only(left: 5, right: 5), - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: Colors.white, - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(5.0), - bottomRight: Radius.circular(5.0), - )), - duration: Duration(milliseconds: 7000), - child: Container( - width: double.infinity, - child: !Utils.isTextHtml(widget.details!) - ? AppText( - widget.details ?? TranslationBase.of(context).noDataAvailable, - ) - : Html( - data: widget.details ?? TranslationBase.of(context).noDataAvailable, - ), + if (_isShowMore) + AnimatedContainer( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(5.0), + bottomRight: Radius.circular(5.0), + )), + duration: Duration(milliseconds: 7000), + child: Container( + width: double.infinity, + child: !Utils.isTextHtml(widget.details!) + ? AppText( + widget.details ?? TranslationBase.of(context).noDataAvailable, + ) + : Html( + data: widget.details ?? TranslationBase.of(context).noDataAvailable, + ), + ), + ), + SizedBox( + height: 10, ), - ), - SizedBox( - height: 10, + ], ), - ], - ), + ], + ), ], ), - ], + ), ), ), ), diff --git a/lib/utils/translations_delegate_base_utils.dart b/lib/utils/translations_delegate_base_utils.dart index 733e1d63..84679ff0 100644 --- a/lib/utils/translations_delegate_base_utils.dart +++ b/lib/utils/translations_delegate_base_utils.dart @@ -2009,6 +2009,11 @@ class TranslationBase { String get intendedLengthStay => localizedValues['intendedLengthStay']![locale.languageCode]!; + String get showAttachment => + localizedValues['showAttachment']![locale.languageCode]!; + + String get selectAnAttachment => + localizedValues['selectAnAttachment']![locale.languageCode]!; } diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 2b956957..9bb741f9 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/core/model/doctor/list_doctor_working_hours_table_model.dart'; @@ -13,11 +16,13 @@ import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:html/parser.dart'; +import 'package:path_provider/path_provider.dart'; import '../config/size_config.dart'; import '../locator.dart'; import '../update_page.dart'; import '../utils/dr_app_toast_msg.dart'; +import 'dart:typed_data'; DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); @@ -364,4 +369,13 @@ class Utils { }); return isVidaPlusInPatientProject; } + + static Future createFileFromString(String encodedStr, String ext) async { + Uint8List bytes = base64.decode(encodedStr); + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/${DateTime.now().millisecondsSinceEpoch}.$ext"); + await file.writeAsBytes(bytes); + return file.path; + } + } diff --git a/pubspec.yaml b/pubspec.yaml index e4a705ba..ae42ca34 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -143,6 +143,9 @@ dependencies: logger: ^2.6.1 freerasp: ^8.2.1 safe_device: ^1.4.1 + path_provider: ^2.0.8 + open_filex: ^4.7.0 + dependency_overrides: flutter_localizations: