Online CheckIn implementation contd.
							parent
							
								
									851bd569b4
								
							
						
					
					
						commit
						b10523dac3
					
				
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								| @ -1,44 +1,138 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_assets.dart'; | ||||
| import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | ||||
| import 'package:hmg_patient_app_new/core/utils/utils.dart'; | ||||
| import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; | ||||
| import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; | ||||
| import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; | ||||
| import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart'; | ||||
| import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:barcode_scan2/barcode_scan2.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/nfc/nfc_reader_sheet.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; | ||||
| 
 | ||||
| class AppointmentCheckinBottomSheet extends StatelessWidget { | ||||
|   AppointmentCheckinBottomSheet({super.key, required this.patientAppointmentHistoryResponseModel}); | ||||
|   AppointmentCheckinBottomSheet({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel}); | ||||
| 
 | ||||
|   PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; | ||||
|   MyAppointmentsViewModel myAppointmentsViewModel; | ||||
| 
 | ||||
|   bool _supportsNFC = false; | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     FlutterNfcKit.nfcAvailability.then((value) { | ||||
|       _supportsNFC = (value == NFCAvailability.available); | ||||
|     }); | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         checkInOptionCard(AppAssets.checkin_location_icon, "Live Location".needTranslation, "".needTranslation), | ||||
|         checkInOptionCard( | ||||
|           AppAssets.checkin_location_icon, | ||||
|           "Live Location".needTranslation, | ||||
|           "Verify your location to be at hospital to check in".needTranslation, | ||||
|         ).onPress(() { | ||||
|           Navigator.of(context).pop(); | ||||
|         }), | ||||
|         SizedBox(height: 16.h), | ||||
|         checkInOptionCard(AppAssets.checkin_nfc_icon, "NFC (Near Field Communication)".needTranslation, "".needTranslation), | ||||
|         checkInOptionCard( | ||||
|           AppAssets.checkin_nfc_icon, | ||||
|           "NFC (Near Field Communication)".needTranslation, | ||||
|           "Scan your phone via NFC board to check in".needTranslation, | ||||
|         ).onPress(() { | ||||
|           Future.delayed(const Duration(milliseconds: 500), () { | ||||
|             showNfcReader(context, onNcfScan: (String nfcId) { | ||||
|               Future.delayed(const Duration(milliseconds: 100), () { | ||||
|                 sendCheckInRequest(nfcId, context); | ||||
|               }); | ||||
|             }, onCancel: () {}); | ||||
|           }); | ||||
|         }), | ||||
|         SizedBox(height: 16.h), | ||||
|         checkInOptionCard(AppAssets.checkin_qr_icon, "QR Code".needTranslation, "".needTranslation), | ||||
|         checkInOptionCard( | ||||
|           AppAssets.checkin_qr_icon, | ||||
|           "QR Code".needTranslation, | ||||
|           "Scan QR code with your camera to check in".needTranslation, | ||||
|         ).onPress(() async { | ||||
|           String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent)); | ||||
|           if (onlineCheckInQRCode != "") { | ||||
|             sendCheckInRequest(onlineCheckInQRCode, context); | ||||
|           } else {} | ||||
|         }), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Widget checkInOptionCard(String icon, String title, String subTitle) { | ||||
|     return Container( | ||||
|       height: 120.h, | ||||
|       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||
|         color: AppColors.whiteColor, | ||||
|         borderRadius: 20.h, | ||||
|         hasShadow: false, | ||||
|       ), | ||||
|       child: Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Utils.buildSvgWithAssets(icon: icon), | ||||
|           Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill), | ||||
|           SizedBox(height: 16.h), | ||||
|           Row( | ||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|             children: [ | ||||
|               Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: [ | ||||
|                   title.toText16(isBold: true, color: AppColors.textColor), | ||||
|                   subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), | ||||
|                 ], | ||||
|               ), | ||||
|               Utils.buildSvgWithAssets( | ||||
|                 icon: AppAssets.forward_arrow_icon, | ||||
|                 iconColor: AppColors.blackColor, | ||||
|                 width: 18.h, | ||||
|                 height: 13.h, | ||||
|                 fit: BoxFit.contain, | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|       ).paddingAll(16.h), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   void sendCheckInRequest(String scannedCode, BuildContext context) async { | ||||
|     showCommonBottomSheet(context, | ||||
|         child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false); | ||||
|     await myAppointmentsViewModel.sendCheckInNfcRequest( | ||||
|       patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, | ||||
|       scannedCode: scannedCode, | ||||
|       checkInType: 2, | ||||
|       onSuccess: (apiResponse) { | ||||
|         Navigator.of(context).pop(); | ||||
|         showCommonBottomSheetWithoutHeight(context, title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () { | ||||
|           Navigator.of(context).pop(); | ||||
|           Navigator.pushAndRemoveUntil( | ||||
|               context, | ||||
|               FadePage( | ||||
|                 page: LandingNavigation(), | ||||
|               ), | ||||
|               (r) => false); | ||||
|           Navigator.of(context).push( | ||||
|             FadePage(page: MyAppointmentsPage()), | ||||
|           ); | ||||
|         }, isFullScreen: false); | ||||
|       }, | ||||
|       onError: (error) { | ||||
|         Navigator.of(context).pop(); | ||||
|         showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), callBackFunc: () { | ||||
|           Navigator.of(context).pop(); | ||||
|         }, isFullScreen: false); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,212 @@ | ||||
| import 'dart:io'; | ||||
| 
 | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; | ||||
| import 'package:flutter_svg/flutter_svg.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_assets.dart'; | ||||
| import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | ||||
| import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; | ||||
| 
 | ||||
| void showNfcReader(BuildContext context, {required Function onNcfScan, required VoidCallback onCancel}) { | ||||
|   showModalBottomSheet( | ||||
|       context: context, | ||||
|       enableDrag: false, | ||||
|       isDismissible: true, | ||||
|       shape: RoundedRectangleBorder( | ||||
|         borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), | ||||
|       ), | ||||
|       backgroundColor: Colors.white, | ||||
|       builder: (context) { | ||||
|         return NfcLayout( | ||||
|           onNcfScan: onNcfScan, | ||||
|           onCancel: onCancel, | ||||
|         ); | ||||
|       }); | ||||
| } | ||||
| 
 | ||||
| class NfcLayout extends StatefulWidget { | ||||
|   Function? onNcfScan; | ||||
|   VoidCallback? onCancel; | ||||
| 
 | ||||
|   NfcLayout({this.onNcfScan, this.onCancel}); | ||||
| 
 | ||||
|   @override | ||||
|   _NfcLayoutState createState() => _NfcLayoutState(); | ||||
| } | ||||
| 
 | ||||
| class _NfcLayoutState extends State<NfcLayout> { | ||||
|   bool _reading = false; | ||||
|   Widget? mainWidget; | ||||
|   late String nfcId; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     readNFC(); | ||||
|   } | ||||
| 
 | ||||
|   void readNFC() async { | ||||
|     FlutterNfcKit.finish(); | ||||
|     FlutterNfcKit.poll(timeout: Duration(seconds: 10), androidPlatformSound: true, androidCheckNDEF: false, iosMultipleTagMessage: "Multiple tags found!").then((value) async { | ||||
|       setState(() { | ||||
|         _reading = true; | ||||
|         mainWidget = doneNfc(); | ||||
|       }); | ||||
|       Future.delayed(const Duration(milliseconds: 500), () async { | ||||
|         await FlutterNfcKit.finish(); | ||||
|         widget.onNcfScan!(nfcId); | ||||
|         Navigator.pop(context); | ||||
|       }); | ||||
|       nfcId = value.id; | ||||
|     }).catchError((err) { | ||||
|       print(err); | ||||
|       Navigator.of(context).pop(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     // return SizedBox(); | ||||
|     (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); | ||||
|     return Platform.isAndroid ? AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget) : SizedBox.shrink(); | ||||
|   } | ||||
| 
 | ||||
|   Widget scanNfc() { | ||||
|     return Container( | ||||
|       key: ValueKey(1), | ||||
|       child: Column( | ||||
|         mainAxisSize: MainAxisSize.min, | ||||
|         children: <Widget>[ | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           Text( | ||||
|             "Ready To Scan", | ||||
|             style: TextStyle( | ||||
|               fontWeight: FontWeight.bold, | ||||
|               fontSize: 24, | ||||
|             ), | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           SvgPicture.asset( | ||||
|             "assets/images/nfc/contactless.svg", | ||||
|             height: MediaQuery.of(context).size.width / 3, | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           Text( | ||||
|             "Approach an NFC Tag", | ||||
|             style: TextStyle( | ||||
|               fontSize: 18, | ||||
|             ), | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           ButtonTheme( | ||||
|             minWidth: MediaQuery.of(context).size.width / 1.2, | ||||
|             height: 45.0, | ||||
|             buttonColor: Colors.grey[300], | ||||
|             shape: RoundedRectangleBorder( | ||||
|               borderRadius: BorderRadius.circular(6), | ||||
|             ), | ||||
|             child: CustomButton( | ||||
|               text: LocaleKeys.cancel.tr(), | ||||
|               onPressed: () { | ||||
|                 widget.onCancel!(); | ||||
|                 Navigator.pop(context); | ||||
|               }, | ||||
|               backgroundColor: AppColors.primaryRedColor, | ||||
|               borderColor: AppColors.primaryRedColor, | ||||
|               textColor: AppColors.whiteColor, | ||||
|               fontSize: 14, | ||||
|               fontWeight: FontWeight.w500, | ||||
|               borderRadius: 12.h, | ||||
|               height: 40.h, | ||||
|               icon: AppAssets.cancel, | ||||
|               iconColor: AppColors.whiteColor, | ||||
|               iconSize: 16.h, | ||||
|             ), | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Widget doneNfc() { | ||||
|     return Container( | ||||
|       key: ValueKey(2), | ||||
|       child: Column( | ||||
|         mainAxisSize: MainAxisSize.min, | ||||
|         children: <Widget>[ | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           Text( | ||||
|             "Successfully Scanned", | ||||
|             style: TextStyle( | ||||
|               fontWeight: FontWeight.bold, | ||||
|               fontSize: 24, | ||||
|             ), | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           Image.asset( | ||||
|             "assets/images/nfc/ic_done.png", | ||||
|             height: MediaQuery.of(context).size.width / 3, | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           Text( | ||||
|             "Approach an NFC Tag", | ||||
|             style: TextStyle( | ||||
|               fontSize: 18, | ||||
|             ), | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|           ButtonTheme( | ||||
|             minWidth: MediaQuery.of(context).size.width / 1.2, | ||||
|             height: 45.0, | ||||
|             buttonColor: Colors.grey[300], | ||||
|             shape: RoundedRectangleBorder( | ||||
|               borderRadius: BorderRadius.circular(6), | ||||
|             ), | ||||
|             child: CustomButton( | ||||
|               text: LocaleKeys.done.tr(), | ||||
|               onPressed: () { | ||||
|                 widget.onCancel!(); | ||||
|                 Navigator.pop(context); | ||||
|               }, | ||||
|               backgroundColor: AppColors.primaryRedColor, | ||||
|               borderColor: AppColors.primaryRedColor, | ||||
|               textColor: AppColors.whiteColor, | ||||
|               fontSize: 14, | ||||
|               fontWeight: FontWeight.w500, | ||||
|               borderRadius: 12.h, | ||||
|               height: 40.h, | ||||
|               icon: AppAssets.cancel, | ||||
|               iconColor: AppColors.whiteColor, | ||||
|               iconSize: 16.h, | ||||
|             ), | ||||
|           ), | ||||
|           SizedBox( | ||||
|             height: 30, | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue