import 'dart:ui'; import 'package:doctor_app_flutter/core/model/pharmacy-intervention-model/intervention_history.dart'; import 'package:doctor_app_flutter/core/model/pharmacy-intervention-model/pharmacy_intervention_item.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; import 'viewmodel/pharmacy_intervention_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/screens/base/base_view.dart'; import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; import '../../config/config.dart'; class PharmacyIntervention extends StatefulWidget { @override State createState() => _PharmacyInterventionState(); } class _PharmacyInterventionState extends State { @override Widget build(BuildContext context) { ProjectViewModel projectsProvider = Provider.of(context); return BaseView(builder: (_, model, __) { if (model.interventionHistoryList != null) { WidgetsBinding.instance.addPostFrameCallback((_) { showBottomSheet( context, model, model.interventionHistoryList!.history!, ); }); } return AppScaffold( isShowAppBar: true, appBar: PatientSearchHeader( title: TranslationBase .of(context) .pharmacyApproval, fontSize: 18, showSearchIcon: true, onSearchPressed: () { SearchDialog(context); }, ), appBarTitle: TranslationBase .of(context) .pharmacyApproval, body: Column( mainAxisSize: MainAxisSize.max, children: [ Expanded( child: ListView.builder( itemCount: model.medicationList?.medication?.length ?? 0, itemBuilder: (context, index) => InterventionCardItem( medication: model.medicationList!.medication![index], model: model, ))) ], ), ); }); } final _sheet = GlobalKey(); final _controller = DraggableScrollableController(); @override void initState() { super.initState(); _controller.addListener(_onChanged); } void _onChanged() { final currentSize = _controller.size; if (currentSize <= 0.05) _collapse(); } void _collapse() => _animateSheet(sheet.snapSizes!.first); void _anchor() => _animateSheet(sheet.snapSizes!.last); void _expand() => _animateSheet(sheet.maxChildSize); void _hide() => _animateSheet(sheet.minChildSize); void _animateSheet(double size) { _controller.animateTo( size, duration: const Duration(milliseconds: 50), curve: Curves.easeInOut, ); } @override void dispose() { super.dispose(); _controller.dispose(); } DraggableScrollableSheet get sheet => (_sheet.currentWidget as DraggableScrollableSheet); void showBottomSheet(BuildContext context, PharmacyInterventionViewModel model, List interventionHistory,) { showModalBottomSheet( isDismissible: true, context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20))), builder: (_) { return DraggableScrollableSheet( key: _sheet, initialChildSize: 0.5, minChildSize: 0.5, maxChildSize: 1, snapSizes: [ 0.5 ,// constraints.maxHeight, 0.9, ], expand: false, controller: _controller, builder:(_, controller) => InterventionHistoryBottomSheet( interventionList: interventionHistory, controller: controller, )); }, ).then((value) => model.toggleShowBottomSheetValue()); } void SearchDialog(BuildContext context) { showDialog( context: context, barrierDismissible: true, // user must tap button! builder: (_) { return PharmacyInterventionDialog( onDispose: (dateFrom, dateTo, admissionNumber, patientId) {}); }); } } class InterventionCardItem extends StatelessWidget { final Medication medication; final PharmacyInterventionViewModel model; const InterventionCardItem( {super.key, required this.medication, required this.model}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: Card( color: Colors.white, elevation: 5, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ InterventionCardBody( medication: medication, model: model, ), InterventionCardFooter(model: model) ], ), ), ), ); } } class InterventionCardFooter extends StatelessWidget { final PharmacyInterventionViewModel model; const InterventionCardFooter({super.key, required this.model}); @override Widget build(BuildContext context) { return Column(children: [ Row(children: [ Expanded( child: AppButton( title: TranslationBase .of(context) .details, hasBorder: true, borderColor: Colors.grey, color: Colors.grey, fontColor: Colors.white, onPressed: () async {}, ), ), ]), SizedBox( height: 8, ), Row(children: [ Expanded( child: AppButton( title: TranslationBase .of(context) .reject, hasBorder: true, borderColor: Color(0xFFB8382B), color: AppGlobal.appRedColor, fontColor: Colors.white, onPressed: () async {}, ), ), SizedBox( width: 6, ), Expanded( child: AppButton( title: TranslationBase .of(context) .accept, hasBorder: true, borderColor: AppGlobal.appGreenColor, color: AppGlobal.appGreenColor, fontColor: Colors.white, onPressed: () async {}, ), ), ]), ]); } } class InterventionCardBody extends StatelessWidget { final Medication medication; final PharmacyInterventionViewModel model; const InterventionCardBody( {super.key, required this.medication, required this.model}); @override Widget build(BuildContext context) { return Column( children: [ SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .accessLevel, data: medication.accessLevel.toString() ?? '', ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .patientID, data: medication.patientID.toString() ?? '', )) ], ), SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .patientName, data: medication.patientName.toString() ?? '', ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .nursingStation, data: medication.nursingStation.toString() ?? '', )) ], ), SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .admissionNumber, data: medication.admissionNo.toString() ?? '', ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .medication, data: medication.medication.toString() ?? '', )) ], ), SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .dosageDetails, data: medication.dosageDetail.toString() ?? '', ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .doctorComments, data: medication.doctorComments.toString() ?? '', )) ], ), SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .startDate, data: model.getDate(medication.startDatetime.toString() ?? ''), ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .stopDate, data: model.getDate(medication.stopDatetime.toString() ?? ''), )) ], ), SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .status, data: medication.status.toString() ?? '', ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .doctor, data: medication.doctorName.toString() ?? '', )) ], ), SizedBox( height: 10, ), Row( children: [ Expanded( child: InterventionDetails( title: TranslationBase .of(context) .authorizedBy, data: medication.authorizedBy.toString() ?? '-', ), ), Expanded( child: InterventionDetails( title: TranslationBase .of(context) .pharmacyRemarks, data: medication.pharmacyRemarks.toString() ?? '-', )) ], ), SizedBox( height: 10, ), ], ); } } class InterventionDetails extends StatelessWidget { final String title; final String data; const InterventionDetails( {super.key, required this.title, required this.data}); @override Widget build(BuildContext context) { return Column( children: [ Text( title, textAlign: TextAlign.center, style: TextStyle( color: Colors.black, fontWeight: FontWeight.w600, fontSize: 13, ), ), SizedBox( height: 8, ), Text( data, textAlign: TextAlign.center, style: TextStyle( color: Colors.grey, fontWeight: FontWeight.w400, fontSize: 12, ), ), ], ); } } class InterventionHistoryBottomSheet extends StatelessWidget { final List interventionList; final ScrollController controller; const InterventionHistoryBottomSheet( {super.key, required this.interventionList, required this.controller}); @override Widget build(BuildContext context) { return Material( color: Color(0xFFF7F7F7), shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20))), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AppText( TranslationBase .of(context) .histories, fontWeight: FontWeight.w700, fontSize: 24, color: Color(0xFF2B353E), ), SizedBox( height: 16, ), Expanded( child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: ListView.separated( shrinkWrap: true, controller: controller, itemCount: interventionList.length, itemBuilder: (context, index) => Material( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), color: Colors.white, child: InterventionHistoryItem( interventionHistory: interventionList[index], ), ), separatorBuilder: (_, __) => Divider(), )) ], ), ) ], ), ), ); } } class InterventionHistoryItem extends StatelessWidget { final InterventionHistory interventionHistory; const InterventionHistoryItem({super.key, required this.interventionHistory}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AppText( interventionHistory.commentedByName ?? '', fontWeight: FontWeight.w600, fontSize: 12, color: Color(0xFF2B353E), ), SizedBox( height: 4, ), AppText( "${TranslationBase .of(context) .remarks}: ${interventionHistory.remark?.isNotEmpty == true ? interventionHistory.remark : TranslationBase .of(context) .noRemarks}", fontWeight: FontWeight.w600, fontSize: 12, color: Color(0xFF2B353E), ), ], ), ); } } class TableCell extends StatelessWidget { final String text; const TableCell(this.text, {super.key}); @override Widget build(BuildContext context) { return Container( width: 150, // Adjust column width padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( border: Border.all(color: Colors.black), ), child: Text(text), ); } } class TableHeaderCell extends StatelessWidget { final String text; const TableHeaderCell(this.text, {super.key}); @override Widget build(BuildContext context) { return Container( width: 150, // Adjust column width padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( color: Colors.grey[300], border: Border.all(color: Colors.black), ), child: Text( text, style: const TextStyle(fontWeight: FontWeight.bold), ), ); } } class DataTable extends StatelessWidget { int? _rowCount = 100; int? _columnCount = 100; @override Widget build(BuildContext context) { return Scaffold( body: TableView.builder( cellBuilder: _buildCell, columnCount: _columnCount, columnBuilder: _buildColumn, rowCount: _rowCount, rowBuilder: _buildRowSpan, pinnedRowCount: 1, diagonalDragBehavior: DiagonalDragBehavior.free, verticalDetails: ScrollableDetails.vertical( controller: ScrollController(), physics: BouncingScrollPhysics(), ), horizontalDetails: ScrollableDetails.horizontal( controller: ScrollController(), physics: BouncingScrollPhysics(), ), ), ); } TableViewCell _buildCell(BuildContext context, TableVicinity vicinity) { final Color boxColor = switch ((vicinity.row.isEven, vicinity.column.isEven)) { (true, false) || (false, true) => Colors.white, (false, false) => Colors.indigo[100]!, (true, true) => Colors.indigo[200]! }; return TableViewCell( child: ColoredBox( color: boxColor, child: Center( child: Text('${vicinity.column}:${vicinity.row}'), ), ), ); } TableSpan _buildRowSpan(int index) { return const TableSpan( extent: MinSpanExtent(FixedSpanExtent(10), FixedSpanExtent(300))); } TableSpan _buildColumn(int index) { return const TableSpan( extent: MinSpanExtent(FixedSpanExtent(50), FixedSpanExtent(300))); } } class TableExample extends StatefulWidget { const TableExample({super.key, required this.model}); final PharmacyInterventionViewModel model; @override State createState() => _TableExampleState(); } class _TableExampleState extends State { late final ScrollController _verticalController = ScrollController(); int _rowCount = 0; int _columnCount = 14; final List headersList = []; @override void dispose() { _verticalController.dispose(); super.dispose(); } @override void initState() { print('the length is ${widget.model.medicationList?.medication?.length}'); _rowCount = ((widget.model.medicationList?.medication?.length ?? 0) + 1); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: TableView.builder( verticalDetails: ScrollableDetails.vertical( controller: _verticalController, ), cellBuilder: _buildCell, columnCount: _columnCount, pinnedRowCount: 1, columnBuilder: _buildColumnSpan, rowCount: _rowCount, rowBuilder: _buildRowSpan, ), persistentFooterButtons: [ TextButton( onPressed: () { _verticalController.jumpTo(0); }, child: const Text('Jump to Top'), ), ], ); } TableViewCell _buildCell(BuildContext context, TableVicinity vicinity) { if (vicinity.row == 0) { var title = ''; switch (vicinity.column) { case 0: title = TranslationBase .of(context) .accessLevel; break; case 1: title = TranslationBase .of(context) .patientID; break; case 2: title = TranslationBase .of(context) .patientName; break; case 3: title = TranslationBase .of(context) .nursingStation; break; case 4: title = TranslationBase .of(context) .admissionNumber; break; case 5: title = TranslationBase .of(context) .medication; break; case 6: title = TranslationBase .of(context) .dosageDetails; break; case 7: title = TranslationBase .of(context) .doctorComments; break; case 8: title = TranslationBase .of(context) .startDate; break; case 9: title = TranslationBase .of(context) .stopDate; break; case 10: title = TranslationBase .of(context) .status; break; case 11: title = TranslationBase .of(context) .doctor; break; case 12: title = TranslationBase .of(context) .authorizedBy; break; case 13: title = TranslationBase .of(context) .pharmacyRemarks; break; } return TableViewCell( child: ColoredBox( color: Colors.grey, child: Center( child: Text(title), ), ), ); } return TableViewCell( child: Center( child: Padding( padding: const EdgeInsets.all(2.0), child: Text( widget.model.medicationList?.medication?[vicinity.row - 1] .getValue(vicinity.column) .toString() ?? '', textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, ), ), ), ); } TableSpan _buildColumnSpan(int index) { const TableSpanDecoration decoration = TableSpanDecoration( border: TableSpanBorder( trailing: BorderSide(), ), ); switch (index) { case 0: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.3), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 1: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.4), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 2: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.5), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 3: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.4), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 4: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.5), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 5: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.7), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 6: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.7), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 7: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.8), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; case 8: case 9: case 10: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.4), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); case 11: case 12: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.6), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); case 13: return TableSpan( foregroundDecoration: decoration, extent: const FractionalTableSpanExtent(0.7), onEnter: (_) => print('Entered column $index'), cursor: SystemMouseCursors.contextMenu, ); break; } // switch (index % 5) { // case 0: // return TableSpan( // foregroundDecoration: decoration, // extent: const FixedTableSpanExtent(100), // onEnter: (_) => print('Entered column $index'), // recognizerFactories: { // TapGestureRecognizer: // GestureRecognizerFactoryWithHandlers( // () => TapGestureRecognizer(), // (TapGestureRecognizer t) => // t.onTap = () => print('Tap column $index'), // ), // }, // ); // case 1: // return TableSpan( // foregroundDecoration: decoration, // extent: const FractionalTableSpanExtent(0.5), // onEnter: (_) => print('Entered column $index'), // cursor: SystemMouseCursors.contextMenu, // ); // case 2: // return TableSpan( // foregroundDecoration: decoration, // extent: const FixedTableSpanExtent(140), // onEnter: (_) => print('Entered column $index'), // ); // case 3: // return TableSpan( // foregroundDecoration: decoration, // extent: const FixedTableSpanExtent(200), // onEnter: (_) => print('Entered column $index'), // ); // case 4: // return TableSpan( // foregroundDecoration: decoration, // extent: const FixedTableSpanExtent(200), // onEnter: (_) => print('Entered column $index'), // ); // } throw AssertionError( 'This should be unreachable, as every index is accounted for in the ' 'switch clauses.', ); } TableSpan _buildRowSpan(int index) { final TableSpanDecoration decoration = TableSpanDecoration( border: const TableSpanBorder( trailing: BorderSide( width: 1, ), ), ); if (index == 0) { TableSpan( backgroundDecoration: decoration, extent: const FixedTableSpanExtent(30), recognizerFactories: { TapGestureRecognizer: GestureRecognizerFactoryWithHandlers( () => TapGestureRecognizer(), (TapGestureRecognizer t) => t.onTap = () => print('Tap row $index'), ), }, ); } return TableSpan( backgroundDecoration: decoration, extent: const FixedTableSpanExtent(65), cursor: SystemMouseCursors.click, ); // switch (index) { // case 0: // return TableSpan( // backgroundDecoration: decoration, // extent: const FixedTableSpanExtent(30), // recognizerFactories: { // TapGestureRecognizer: // GestureRecognizerFactoryWithHandlers( // () => TapGestureRecognizer(), // (TapGestureRecognizer t) => // t.onTap = () => print('Tap row $index'), // ), // }, // ); // case 1: // return TableSpan( // backgroundDecoration: decoration, // extent: const FixedTableSpanExtent(65), // cursor: SystemMouseCursors.click, // ); // case 2: // return TableSpan( // backgroundDecoration: decoration, // extent: const FractionalTableSpanExtent(0.15), // ); // } throw AssertionError( 'This should be unreachable, as every index is accounted for in the ' 'switch clauses.', ); } } class PharmacyInterventionDialog extends StatefulWidget { final Function( String, String, String, String, ) onDispose; const PharmacyInterventionDialog({super.key, required this.onDispose}); @override State createState() => _PharmacyInterventionDialogState(); } class _PharmacyInterventionDialogState extends State { final TextEditingController admissionNumber = TextEditingController(); final TextEditingController nursingStation = TextEditingController(); final TextEditingController patientId = TextEditingController(); String dateFrom = ''; String dateTo = ''; @override void initState() { super.initState(); // initFromDate(); } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ _titleAndTextField(TranslationBase .of(context) .nursingStation, nursingStation, TextInputType.number), SizedBox( height: 4, ), _titleAndTextField(TranslationBase .of(context) .admissionNumber, admissionNumber, TextInputType.number), SizedBox( height: 4, ), _titleAndTextField(TranslationBase .of(context) .patientID, patientId, TextInputType.number), SizedBox( height: 4, ), _dateSelection(TranslationBase .of(context) .dateFrom, (date) { setState(() { dateFrom = date; }); }, dateFrom), SizedBox( height: 4, ), _dateSelection(TranslationBase .of(context) .dateTo, (date) { setState(() { dateTo = date; }); }, dateTo), SizedBox( height: 8, ), Row(children: [ Expanded( child: AppButton( title: TranslationBase .of(context) .search, hasBorder: true, borderColor: Color(0xFFB8382B), color: AppGlobal.appRedColor, fontColor: Colors.white, onPressed: () async {}, ), ), ]), ], ), ), ); } Widget _dateSelection(String title, Function(String) onDateSelected, String selectedDate) { return GestureDetector( onTap: () => _selectDate(onDateSelected), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text(title), Expanded( child: ListTile( title: Text( selectedDate, ), trailing: Icon(Icons.arrow_drop_down_outlined), ), ) ], ), ); } Future _selectDate(Function(String) updateDate) async { final DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(DateTime .now() .year - 150), lastDate: DateTime(DateTime .now() .year + 150), initialEntryMode: DatePickerEntryMode.calendar, builder: (_, child) { return Theme( data: ThemeData.light().copyWith( colorScheme: ColorScheme.fromSwatch( primarySwatch: Colors.red, accentColor: AppGlobal.appRedColor, ), dialogBackgroundColor: Colors.white, ), child: child!, ); }); if (picked != null) { updateDate(getFormattedDate(picked)); } // } } Widget _titleAndTextField(String title, TextEditingController controller, TextInputType? inputType) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.min, children: [ Text(title), Expanded( child: TextFormField( keyboardType: inputType, decoration: InputDecoration( hintText: '', focusedBorder: InputBorder.none, enabledBorder: InputBorder.none, contentPadding: EdgeInsetsDirectional.only(start: 10.0), ), textAlign: TextAlign.end, controller: controller, ), ) ], ); } void initFromDate() { var time = DateTime.now(); dateFrom = getFormattedDate(time); } String getFormattedDate(DateTime time) { return DateFormat('MM/dd/yyyy').format(time); } }