diff --git a/assets/images/nfc/ic_done.png b/assets/images/nfc/ic_done.png new file mode 100644 index 00000000..5b802855 Binary files /dev/null and b/assets/images/nfc/ic_done.png differ diff --git a/assets/images/nfc/ic_nfc.png b/assets/images/nfc/ic_nfc.png new file mode 100644 index 00000000..274e1b8c Binary files /dev/null and b/assets/images/nfc/ic_nfc.png differ diff --git a/lib/config/config.dart b/lib/config/config.dart index 40e0a300..1d0e7a88 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -313,6 +313,9 @@ const UPDATE_HEALTH_TERMS = const GET_PATIENT_HEALTH_STATS = 'Services/Patients.svc/REST/Med_GetTransactionsSts'; +const SEND_CHECK_IN_NFC_REQUEST = + 'Services/Patients.svc/REST/Patient_CheckAppointmentValidation_ForNFC'; + //URL to get medicine and pharmacies list const CHANNEL = 3; const GENERAL_ID = 'Cs2020@2016\$2958'; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 2fa685da..96820fb1 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -473,6 +473,7 @@ const Map localizedValues = { "ar": "خدمة المواقف، تتيح هذه الخدمة للمستخدم معلومات عن موقف السيارة ليسهل عليه العودة لها لاحقاً ، 1- بالضغط على زر(قراءة الكود) تستطيع حفظ البيانات الخاصة بالموقف. 2-بالضغط على زر(عرض موقف سيارتي) يعرض لك موقع السيارة في خرائط قوقل. 3- لإعادة قراءة موقف آخرعن طريق الضغط على زر(مسح بيانات الموقف)." }, + "checkinOption": {"en": "Check-In Options", "ar": "تحقق في الخيارات"}, "readBarcode": {"en": "Read Barcode", "ar": "قراءة الكود"}, "showMyPark": {"en": "Show My Park", "ar": "عرض بارك"}, "clearMyData": {"en": "clear My Data", "ar": "امسح البيانات"}, diff --git a/lib/pages/BookAppointment/QRCode.dart b/lib/pages/BookAppointment/QRCode.dart index 00fb2fc8..ff7224be 100644 --- a/lib/pages/BookAppointment/QRCode.dart +++ b/lib/pages/BookAppointment/QRCode.dart @@ -13,8 +13,10 @@ 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/dialogs/confirm_dialog.dart'; +import 'package:diplomaticquarterapp/widgets/nfc/nfc_reader_sheet.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; +import 'package:nfc_in_flutter/nfc_in_flutter.dart'; class QRCode extends StatefulWidget { PatientShareResponse patientShareResponse; @@ -30,17 +32,27 @@ class QRCode extends StatefulWidget { class _QRCodeState extends State { Uint8List _bytes; + bool _supportsNFC = false; + BuildContext _context; @override void initState() { // TODO: implement initState + _bytes = base64.decode(widget.appoQR.split(',').last); widget.authUser = new AuthenticatedUser(); + NFC.isNDEFSupported.then((supported) { + setState(() { + print("nfc supprted"); + _supportsNFC = true; + }); + }); super.initState(); } @override Widget build(BuildContext context) { + _context = context; return AppScaffold( appBarTitle: TranslationBase.of(context).attendRegisterCode, isShowAppBar: true, @@ -51,9 +63,56 @@ class _QRCodeState extends State { mainAxisSize: MainAxisSize.max, children: [ Container( - margin: EdgeInsets.only(top: 30.0), - alignment: Alignment.center, - child: Image.memory(_bytes, scale: 0.5), + width: double.infinity, + height: MediaQuery.of(context).size.width / 3, + child: Row( + children: [ + _supportsNFC + ? Expanded( + flex: 1, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + child: Container( + margin: EdgeInsets.only(top: 30.0), + alignment: Alignment.center, + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(10), + ), + child: Image.asset( + "assets/images/nfc/ic_nfc.png"), + ), + onTap: () { + showNfcReader(context, + onNcfScan: (String nfcId) { + Future.delayed( + const Duration(milliseconds: 100), + () { + sendNfcCheckInRequest(nfcId); + }); + }); + }, + ), + ], + ), + ) + : Container(), + Expanded( + flex: 1, + child: Container( + margin: EdgeInsets.only(top: 30.0), + alignment: Alignment.center, + child: Image.memory( + _bytes, + ), + ), + ), + ], + ), ), Container( margin: EdgeInsets.only(top: 20.0, left: 20.0, right: 20.0), @@ -70,18 +129,20 @@ class _QRCodeState extends State { EdgeInsets.only(top: 10.0, left: 40.0, bottom: 10.0), child: Image.asset( "assets/images/new-design/device_icon.png", - width: 120.0, - height: 120.0), + width: MediaQuery.of(context).size.width / 3.4, + height: MediaQuery.of(context).size.width / 3.4), ), - Container( - width: MediaQuery.of(context).size.width * 0.5, - margin: EdgeInsets.only( - top: 15.0, bottom: 10.0, left: 20.0, right: 20.0), - child: Text(TranslationBase.of(context).scanQRHospital, - style: TextStyle( - color: Colors.red[700], - fontSize: 20.0, - fontWeight: FontWeight.bold)), + Expanded( + child: Container( + width: double.infinity, + margin: EdgeInsets.only( + top: 15.0, bottom: 10.0, left: 20.0, right: 20.0), + child: Text(TranslationBase.of(context).scanQRHospital, + style: TextStyle( + color: Colors.red[700], + fontSize: 18.0, + fontWeight: FontWeight.bold)), + ), ), ], ), @@ -300,4 +361,51 @@ class _QRCodeState extends State { } return docSpeciality; } + + sendNfcCheckInRequest(String nfcId) { + GifLoaderDialogUtils.showMyDialog(context); + + DoctorsListService service = new DoctorsListService(); + + service + .sendCheckinNfcRequest(widget.patientShareResponse.appointmentNo, nfcId, + widget.patientShareResponse.projectID, context) + .then((res) { + print(res); + + GifLoaderDialogUtils.hideDialog(context); + _showMyDialog(res["SuccessMsg"], this.context); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + print(err); + _showMyDialog(err, this.context); + }); + } + + Future _showMyDialog(String message, BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: true, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Alert'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text(message), + ], + ), + ), + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } } diff --git a/lib/pages/ToDoList/ToDo.dart b/lib/pages/ToDoList/ToDo.dart index 79bcd94b..319221d5 100644 --- a/lib/pages/ToDoList/ToDo.dart +++ b/lib/pages/ToDoList/ToDo.dart @@ -92,6 +92,12 @@ class _ToDoState extends State { padding: EdgeInsets.all(0.0), itemCount: widget.appoList.length, itemBuilder: (context, index) { + print("ttt "+getNextActionImage(widget + .appoList[index] + .nextAction)); + print("ttt "+widget + .appoList[index] + .nextAction.toString()); return Container( margin: EdgeInsets.all(10.0), child: Column( @@ -459,6 +465,10 @@ class _ToDoState extends State { return "assets/images/new-design/waiting_for_doctor.png"; break; + case 90: + return "assets/images/new-design/check-in.png"; + break; + default: return ""; } @@ -480,6 +490,9 @@ class _ToDoState extends State { break; case 60: break; + case 90: + getAppoQR(context, appo); + break; } } @@ -516,6 +529,10 @@ class _ToDoState extends State { return TranslationBase.of(context).waitingForDoctor; break; + case 90: + return TranslationBase.of(context).checkinOptions; + break; + default: return ""; } diff --git a/lib/services/appointment_services/GetDoctorsList.dart b/lib/services/appointment_services/GetDoctorsList.dart index 65fe2b04..c894c84c 100644 --- a/lib/services/appointment_services/GetDoctorsList.dart +++ b/lib/services/appointment_services/GetDoctorsList.dart @@ -1445,4 +1445,24 @@ class DoctorsListService extends BaseService { }, body: request); return Future.value(localRes); } + + Future sendCheckinNfcRequest( + int appointmentNo, String nfcCode,int projectId, BuildContext context) async { + Map request; + + Request req = appGlobal.getPublicRequest(); + request = { + "AppointmentNo":appointmentNo, + "NFC_Code": nfcCode, + "ProjectID": projectId, + }; + dynamic localRes; + await baseAppClient.post(SEND_CHECK_IN_NFC_REQUEST, + onSuccess: (response, statusCode) async { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: request); + return Future.value(localRes); + } } diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index a74c7177..96cffc60 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -472,6 +472,7 @@ class TranslationBase { localizedValues['medicalProfile'][locale.languageCode]; String get parking => localizedValues['parking'][locale.languageCode]; String get parkingDescription => localizedValues['parkingDescription'][locale.languageCode]; + String get checkinOptions => localizedValues['checkinOption'][locale.languageCode]; String get alhabiServices => localizedValues['alhabiServices'][locale.languageCode]; String get parkingTitle => diff --git a/lib/widgets/in_app_browser/InAppBrowser.dart b/lib/widgets/in_app_browser/InAppBrowser.dart index 63509b7c..946876a7 100644 --- a/lib/widgets/in_app_browser/InAppBrowser.dart +++ b/lib/widgets/in_app_browser/InAppBrowser.dart @@ -21,17 +21,17 @@ var _InAppBrowserOptions = InAppBrowserClassOptions( class MyInAppBrowser extends InAppBrowser { _PAYMENT_TYPE paymentType; - // static String SERVICE_URL = - // 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT - static String SERVICE_URL = - 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE + 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT - // static String PREAUTH_SERVICE_URL = - // 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort PreAuth Payment Gateway URL UAT + // static String SERVICE_URL = + // 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE static String PREAUTH_SERVICE_URL = - 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort PreAuth Payment Gateway URL Live Store + 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort PreAuth Payment Gateway URL UAT + + // static String PREAUTH_SERVICE_URL = + // 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort PreAuth Payment Gateway URL Live Store // static String PRESCRIPTION_PAYMENT_WITH_ORDERID = // 'https://uat.hmgwebservices.com/epharmacy/checkout/OpcCompleteRedirectionPaymentClientbyOrder?orderID='; diff --git a/lib/widgets/nfc/nfc_reader_sheet.dart b/lib/widgets/nfc/nfc_reader_sheet.dart new file mode 100644 index 00000000..067c0c9a --- /dev/null +++ b/lib/widgets/nfc/nfc_reader_sheet.dart @@ -0,0 +1,196 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:nfc_in_flutter/nfc_in_flutter.dart'; + +void showNfcReader(BuildContext context, {Function onNcfScan}) { + showModalBottomSheet( + context: context, + enableDrag: false, + isDismissible: false, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12), topRight: Radius.circular(12)), + ), + backgroundColor: Colors.white, + builder: (context) { + return NfcLayout( + onNcfScan: onNcfScan, + ); + }); +} + +class NfcLayout extends StatefulWidget { + Function onNcfScan; + + NfcLayout({this.onNcfScan}); + + @override + _NfcLayoutState createState() => _NfcLayoutState(); +} + +class _NfcLayoutState extends State { + StreamSubscription _stream; + bool _reading = false; + Widget mainWidget; + String nfcId; + + @override + void initState() { + super.initState(); + + setState(() { + // _reading = true; + // Start reading using NFC.readNDEF() + _stream = NFC + .readNDEF( + once: false, + throwOnUserCancel: false, + readerMode: NFCDispatchReaderMode()) + .listen((NDEFMessage message) { + setState(() { + _reading = true; + mainWidget = doneNfc(); + }); + Future.delayed(const Duration(milliseconds: 500), () { + _stream?.cancel(); + widget.onNcfScan(nfcId); + Navigator.pop(context); + }); + print("read NDEF id: ${message.id}"); + // widget.onNcfScan(message.id); + nfcId = message.id; + }, onError: (e) { + // Check error handling guide below + }); + }); + } + + @override + Widget build(BuildContext context) { + (mainWidget == null && !_reading) + ? mainWidget = scanNfc() + : mainWidget = doneNfc(); + return AnimatedSwitcher( + duration: Duration(milliseconds: 500), child: mainWidget); + } + + Widget scanNfc() { + return Container( + key: ValueKey(1), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 30, + ), + Text( + "Ready To Scan", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + SizedBox( + height: 30, + ), + Image.asset( + "assets/images/nfc/ic_nfc.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: RaisedButton( + onPressed: () { + _stream?.cancel(); + Navigator.pop(context); + }, + child: Text("CANCEL"), + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } + + Widget doneNfc() { + return Container( + key: ValueKey(2), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + 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: RaisedButton( + // onPressed: () { + // _stream?.cancel(); + // widget.onNcfScan(nfcId); + // Navigator.pop(context); + // }, + onPressed: null, + + child: Text("DONE"), + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index db0811fb..c109bd0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -221,6 +221,7 @@ flutter: - assets/images/gif/ - assets/images/pharmacy_module/payment/ - assets/images/pharmacy_module/lakum/ + - assets/images/nfc/ fonts: