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/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/app_assets.dart';
|
||||||
import 'package:hmg_patient_app_new/core/utils/size_utils.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/core/utils/utils.dart';
|
||||||
import 'package:hmg_patient_app_new/extensions/string_extensions.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/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/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: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 {
|
class AppointmentCheckinBottomSheet extends StatelessWidget {
|
||||||
AppointmentCheckinBottomSheet({super.key, required this.patientAppointmentHistoryResponseModel});
|
AppointmentCheckinBottomSheet({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel});
|
||||||
|
|
||||||
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
|
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
|
||||||
|
MyAppointmentsViewModel myAppointmentsViewModel;
|
||||||
|
|
||||||
|
bool _supportsNFC = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
FlutterNfcKit.nfcAvailability.then((value) {
|
||||||
|
_supportsNFC = (value == NFCAvailability.available);
|
||||||
|
});
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
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),
|
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),
|
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) {
|
Widget checkInOptionCard(String icon, String title, String subTitle) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 120.h,
|
|
||||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
color: AppColors.whiteColor,
|
color: AppColors.whiteColor,
|
||||||
borderRadius: 20.h,
|
borderRadius: 20.h,
|
||||||
hasShadow: false,
|
hasShadow: false,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Utils.buildSvgWithAssets(icon: icon),
|
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