diff --git a/assets/images/lock-icon.png b/assets/images/lock-icon.png new file mode 100644 index 00000000..39645887 Binary files /dev/null and b/assets/images/lock-icon.png differ diff --git a/assets/images/svg/Check Mark.lottie b/assets/images/svg/Check Mark.lottie new file mode 100644 index 00000000..28630fbd Binary files /dev/null and b/assets/images/svg/Check Mark.lottie differ diff --git a/assets/images/svg/qlogin.svg b/assets/images/svg/qlogin.svg deleted file mode 100644 index 3fcf2ffd..00000000 --- a/assets/images/svg/qlogin.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 7922976e..211e4108 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -2329,6 +2329,8 @@ const Map localizedValues = { "clickPrivacyPolicy": {"en": "Please click here to view the privacy policy", "ar": "الرجاء الضغط هنا لعرض سياسة الخصوصية"}, "welcomeToDrSulaiman": {"en": "Welcome to Dr. Sulaiman Al Habib Medical Group", "ar": "مرحباً بكم في مجموعة الدكتور سليمان الحبيب الطبية"}, "dontHaveAccount": {"en": "Don’t have an account?", "ar": "ليس لديك حساب؟"}, + "loginByOTP": {"en": "Login By OTP", "ar":"تسجيل الدخول باستخدام OTP"}, + "loginBy": {"en": "Login By", "ar":"تسجيل الدخول بواسطة"} "prepareToElevate": {"en": "Prepared to elevate your health and well-being?", "ar": "هل أنت مستعد لتحسين صحتك ورفاهتك؟"}, "alreadyHaveAccount": {"en": "Already have an account?", "ar": "هل لديك حساب بالفعل؟"}, "loginNow": {"en": "Login Now", "ar": "تسجيل الدخول الآن"} diff --git a/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart b/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart index d51c8dea..2bd1b5f4 100644 --- a/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart +++ b/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart @@ -109,6 +109,7 @@ class CustomButton extends StatelessWidget { this.fontFamily, this.fontWeight = FontWeight.w500, this.isDisabled = false, + this.icon, }) : super(key: key); diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 18171bf1..0ce516bc 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:flutter/services.dart'; import 'package:hmg_patient_app/config/config.dart'; import 'package:hmg_patient_app/config/shared_pref_kay.dart'; import 'package:hmg_patient_app/core/model/ImagesInfo.dart'; @@ -9,11 +10,15 @@ import 'package:hmg_patient_app/core/viewModels/appointment_rate_view_model.dart import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; import 'package:hmg_patient_app/models/Appointments/toDoCountProviderModel.dart'; import 'package:hmg_patient_app/models/Authentication/authenticated_user.dart'; +import 'package:hmg_patient_app/models/Authentication/check_paitent_authentication_req.dart'; +import 'package:hmg_patient_app/models/Authentication/select_device_imei_res.dart'; import 'package:hmg_patient_app/models/LiveCare/IncomingCallData.dart'; import 'package:hmg_patient_app/pages/BookAppointment/Search.dart'; import 'package:hmg_patient_app/pages/DrawerPages/family/my-family.dart'; import 'package:hmg_patient_app/pages/ToDoList/ToDo.dart'; import 'package:hmg_patient_app/pages/landing/home_page_2.dart'; +import 'package:hmg_patient_app/pages/login/saved_login.dart'; +import 'package:hmg_patient_app/pages/login/welcome.dart'; import 'package:hmg_patient_app/pages/medical/medical_profile_page_new.dart'; import 'package:hmg_patient_app/services/authentication/auth_provider.dart'; import 'package:hmg_patient_app/services/clinic_services/get_clinic_service.dart'; @@ -41,6 +46,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart'; +import 'package:hmg_patient_app/widgets/quick_login.dart'; +import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; import '../../locator.dart'; @@ -69,7 +76,7 @@ class LandingPage extends StatefulWidget { class _LandingPageState extends State with WidgetsBindingObserver { var authProvider = new AuthProvider(); AppointmentRateViewModel appointmentRateViewModel = locator(); - + final LocalAuthentication auth = LocalAuthentication(); int currentTab = 0; late PageController pageController; late ProjectViewModel projectViewModel; @@ -77,9 +84,9 @@ class _LandingPageState extends State with WidgetsBindingObserver { var notificationCount = ''; var themeNotifier; DateTime? currentBackPressTime; - + bool authenticated = false; // SignalRUtil signalRUtil; - + // bool isDoneQuickLogin =false; late ToDoCountProviderModel toDoProvider; bool _showBottomNavigationBar = true; @@ -100,26 +107,26 @@ class _LandingPageState extends State with WidgetsBindingObserver { bool isTalking = false; var sharedPref = new AppSharedPreferences(); - - var data = { - "AppointmentNo": "2016059247", - "ProjectID": "15", - "NotificationType": "10", - "background": "0", - "doctorname": "Call from postman", - "clinicname": "LIVECARE FAMILY MEDICINE AND GP", - "speciality": "General Practioner", - "appointmentdate": "2022-01-19", - "appointmenttime": "12:10", - "PatientName": "Testing", - "session_id": "1_MX40NjIwOTk2Mn5-MTY0NzI1NjYxNDI2OX5ySXhlVjZjam13RFdMVmdleWVsSDhzQkx-fg", - "token": - "T1==cGFydG5lcl9pZD00NjIwOTk2MiZzaWc9OGMyY2IyYWFiZmZmMzI4ZmEwMjgxNDdmMGFhZGI0N2JiZjdmZWY4MjpzZXNzaW9uX2lkPTFfTVg0ME5qSXdPVGsyTW41LU1UWTBOekkxTmpZeE5ESTJPWDV5U1hobFZqWmphbTEzUkZkTVZtZGxlV1ZzU0RoelFreC1mZyZjcmVhdGVfdGltZT0xNjQ3MjU2NjE0Jm5vbmNlPTAuMjgzNDgyNjM1NDczNjQ2OCZyb2xlPW1vZGVyYXRvciZleHBpcmVfdGltZT0xNjQ3MjU4NDE0JmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9", - "DoctorImageURL": "https://image.shutterstock.com/image-vector/sample-stamp-square-grunge-sign-260nw-1474408826.jpg", - "callerID": "9920", - "PatientID": "1231755", - "is_call": "true" - }; + // + // var data = { + // "AppointmentNo": "2016059247", + // "ProjectID": "15", + // "NotificationType": "10", + // "background": "0", + // "doctorname": "Call from postman", + // "clinicname": "LIVECARE FAMILY MEDICINE AND GP", + // "speciality": "General Practioner", + // "appointmentdate": "2022-01-19", + // "appointmenttime": "12:10", + // "PatientName": "Testing", + // "session_id": "1_MX40NjIwOTk2Mn5-MTY0NzI1NjYxNDI2OX5ySXhlVjZjam13RFdMVmdleWVsSDhzQkx-fg", + // "token": + // "T1==cGFydG5lcl9pZD00NjIwOTk2MiZzaWc9OGMyY2IyYWFiZmZmMzI4ZmEwMjgxNDdmMGFhZGI0N2JiZjdmZWY4MjpzZXNzaW9uX2lkPTFfTVg0ME5qSXdPVGsyTW41LU1UWTBOekkxTmpZeE5ESTJPWDV5U1hobFZqWmphbTEzUkZkTVZtZGxlV1ZzU0RoelFreC1mZyZjcmVhdGVfdGltZT0xNjQ3MjU2NjE0Jm5vbmNlPTAuMjgzNDgyNjM1NDczNjQ2OCZyb2xlPW1vZGVyYXRvciZleHBpcmVfdGltZT0xNjQ3MjU4NDE0JmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9", + // "DoctorImageURL": "https://image.shutterstock.com/image-vector/sample-stamp-square-grunge-sign-260nw-1474408826.jpg", + // "callerID": "9920", + // "PatientID": "1231755", + // "is_call": "true" + // }; void _requestIOSPermissions() { flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( @@ -368,25 +375,42 @@ class _LandingPageState extends State with WidgetsBindingObserver { var data = await sharedPref.getObject(IMEI_USER_DATA); sharedPref.remove(REGISTER_DATA_FOR_LOGIIN); if (data != null) { - Navigator.of(context).pushNamed(CONFIRM_LOGIN); + SelectDeviceIMEIRES savedData = SelectDeviceIMEIRES.fromJson(data); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => SavedLogin(savedData), + ), + ); + + } else { - // AppGlobal.context = context; GifLoaderDialogUtils.showMyDialog(context); authService.selectDeviceImei(DEVICE_TOKEN).then((value) async { GifLoaderDialogUtils.hideDialog(context); var data = await sharedPref.getObject(IMEI_USER_DATA); if (value != null) { + SelectDeviceIMEIRES savedData = SelectDeviceIMEIRES.fromJson(data); setUserValues(value); - Navigator.of(context).pushNamed(CONFIRM_LOGIN); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => SavedLogin(savedData), + ), + ); } else { GifLoaderDialogUtils.hideDialog(context); - Navigator.of(context).pushNamed( - WELCOME_LOGIN, + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => WelcomeLogin(), + ), ); } }).catchError((err) { GifLoaderDialogUtils.hideDialog(context); - Navigator.of(context).pushNamed(WELCOME_LOGIN); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => WelcomeLogin(), + ), + ); }); } } @@ -450,10 +474,12 @@ class _LandingPageState extends State with WidgetsBindingObserver { getNotificationCount(token) async { if (await sharedPref.getObject(USER_PROFILE) != null) { var data = AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); + if (data != null) { authService.getDashboard().then((value) => { if (value != null) { + setState(() { notificationCount = value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString(); @@ -652,6 +678,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { var data = AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); if (data != null) { authService.registeredAuthenticatedUser(data, token, 0, 0).then((res) => {}); + checkLastLoginStatus(data, token); authService.getDashboard().then((value) async { setState(() { if (value != null) { @@ -659,7 +686,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { notificationCount = value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString(); model.setState(model.count, model.ancillaryCount, true, notificationCount); sharedPref.setString(NOTIFICATION_COUNT, notificationCount); - checkLastLoginStatus(); + } }); // if (await AppSharedPreferences().getBool(IS_LAST_APPOINTMENT_RATE_SHOWN) == null || !await AppSharedPreferences().getBool(IS_LAST_APPOINTMENT_RATE_SHOWN)) { @@ -706,12 +733,68 @@ class _LandingPageState extends State with WidgetsBindingObserver { sharedPref.setString(IS_COVID_CONSENT_SHOWN, "true"); } - checkLastLoginStatus() async{ + checkLastLoginStatus(AuthenticatedUser user, String deviceToken) async{ int lastLoginStatus = await sharedPref.getInt(LAST_LOGIN) != null ? await sharedPref.getInt(LAST_LOGIN) : 1; if(lastLoginStatus == 1 || lastLoginStatus == 2){ - print("SMS or Whatsapp Consent"); + showQuickLoginBottomSheet(context, user, deviceToken,false); } } -} + + void showQuickLoginBottomSheet(BuildContext context, AuthenticatedUser user, String deviceToken, bool isDone) { + showModalBottomSheet( + context: context, + backgroundColor: Colors.transparent, + isScrollControlled: true, + builder: (context) => QuickLoginBottomSheet( + isDone:isDone, + onPressed: (){ + loginWithFingerPrintFace(3, 1, user, deviceToken); + },), + ); + } + loginWithFingerPrintFace(type, int isActive, AuthenticatedUser user, String deviceToken ) async { + try { + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + options: AuthenticationOptions( + useErrorDialogs: true, + stickyAuth: true, + ), + authMessages: [ + // IOSAuthMessages( + // cancelButton: 'cancel', + // goToSettingsButton: 'settings', + // goToSettingsDescription: 'Please set up your Touch ID.', + // lockOut: 'Please reenable your Touch ID'), + ], + ); + } on PlatformException catch (e) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: 'Please enable your Touch or Face ID'); + } + if (authenticated == true) { + Navigator.of(context).pop(); + int lastLogin = 1; + var availableBiometrics = await auth.getAvailableBiometrics(); + + if (availableBiometrics.contains(BiometricType.strong)) { + lastLogin = 3; // Assume Face or secure fingerprint + } else if (availableBiometrics.contains(BiometricType.weak)) { + lastLogin = 2; // Likely weak fingerprint + } + + await sharedPref.setInt(LAST_LOGIN, lastLogin); + showQuickLoginBottomSheet(context, user, deviceToken, true); + insertIMEI(lastLogin); + } + } + + insertIMEI(lastLogin) { + authService.insertDeviceImei(lastLogin).then((value) => {}).catchError((err) { + print(err); + }); + } + } + diff --git a/lib/pages/livecare/incoming_call.dart b/lib/pages/livecare/incoming_call.dart index 2c0a1ef7..229a2c32 100644 --- a/lib/pages/livecare/incoming_call.dart +++ b/lib/pages/livecare/incoming_call.dart @@ -1,13 +1,10 @@ import 'dart:ui'; -import 'package:camera/camera.dart'; import 'package:hmg_patient_app/models/LiveCare/IncomingCallData.dart'; import 'package:hmg_patient_app/pages/conference/widgets/platform_exception_alert_dialog.dart'; import 'package:hmg_patient_app/pages/conference/zoom/call_screen.dart'; import 'package:hmg_patient_app/pages/landing/landing_page.dart'; -import 'package:hmg_patient_app/pages/videocall-webrtc-rnd/webrtc/start_video_call.dart'; import 'package:hmg_patient_app/pages/webRTC/OpenTok/OpenTok.dart'; -import 'package:hmg_patient_app/pages/webRTC/signaling.dart'; import 'package:hmg_patient_app/services/livecare_services/livecare_provider.dart'; import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; import 'package:hmg_patient_app/uitl/utils_new.dart'; @@ -31,7 +28,7 @@ class _IncomingCallState extends State with SingleTickerProviderSt bool openCallInWeb = true; final player = AudioPlayer(); - late CameraController _controller; + // late CameraController _controller; late Future _initializeControllerFuture; bool isCameraReady = false; diff --git a/lib/pages/login/confirm-login.dart b/lib/pages/login/confirm-login.dart index 595a6a8b..422955ba 100644 --- a/lib/pages/login/confirm-login.dart +++ b/lib/pages/login/confirm-login.dart @@ -369,7 +369,7 @@ class _ConfirmLogin extends State { checkUserAuthentication(type) { showLoader(true); - var req = getCommonRequest(type: type); + var req = authService.getCommonRequest(type: type, registerd_data: this.registerd_data, deviceToken: this.deviceToken, mobileNumber: this.mobileNumber, zipCode: this.zipCode, patientOutSA: this.patientOutSA, loginTokenID: this.loginTokenID, selectedOption: this.selectedOption, user: this.user!); req.logInTokenID = ""; var request = CheckPatientAuthenticationReq.fromJson(req.toJson()); @@ -400,7 +400,7 @@ class _ConfirmLogin extends State { } sendActivationCode(type) async { - var request = this.getCommonRequest(type: type); + var request = this.authService.getCommonRequest(type: type, registerd_data: this.registerd_data, deviceToken: this.deviceToken, mobileNumber: this.mobileNumber, zipCode: this.zipCode, patientOutSA: this.patientOutSA, loginTokenID: this.loginTokenID, selectedOption: this.selectedOption, user: this.user!); request.sMSSignature = await SMSOTP.getSignature(); GifLoaderDialogUtils.showMyDialog(context); if (healthId != null || widget.isDubai) { @@ -478,7 +478,7 @@ class _ConfirmLogin extends State { // this.checkActivationCode(); // } else { - var request = this.getCommonRequest(type: type); + var request = this.authService.getCommonRequest(type: type, registerd_data: this.registerd_data, deviceToken: this.deviceToken, mobileNumber: this.mobileNumber, zipCode: this.zipCode, patientOutSA: this.patientOutSA, loginTokenID: this.loginTokenID, selectedOption: this.selectedOption, user: this.user!); this.getMobileInfo(request); //} } @@ -563,39 +563,39 @@ class _ConfirmLogin extends State { //this.cs.sharedService.getStorage(AuthenticationService.LAST_LOGIN); } - getCommonRequest({type}) { - var request = SendActivationRequest(); - request.patientMobileNumber = this.mobileNumber; - request.mobileNo = '0' + this.mobileNumber.toString(); - request.deviceToken = this.deviceToken; - request.projectOutSA = this.patientOutSA == true ? true : false; - request.loginType = this.selectedOption; - request.oTPSendType = type == 1 ? type : 2; //this.selectedOption == 1 ? 1 : 2; - request.zipCode = this.zipCode; - - request.logInTokenID = this.loginTokenID ?? ""; - - if (this.registerd_data != null) { - request.searchType = this.registerd_data.searchType != null ? this.registerd_data.searchType : 1; - request.patientID = this.registerd_data.patientID != null ? this.registerd_data.patientID : 0; - request.patientIdentificationID = request.nationalID = this.registerd_data.patientIdentificationID != null ? this.registerd_data.patientIdentificationID : '0'; - request.dob = this.registerd_data.dob; - request.isRegister = this.registerd_data.isRegister; - } else { - request.searchType = request.searchType != null ? request.searchType : 2; - request.patientID = this.user!.patientID != null ? this.user!.patientID : 0; - request.nationalID = request.nationalID != null ? request.nationalID : '0'; - request.patientIdentificationID = request.patientIdentificationID != null ? request.patientIdentificationID : '0'; - request.isRegister = false; - } - request.deviceTypeID = request.searchType; - return request; - } + // getCommonRequest({type}) { + // var request = SendActivationRequest(); + // request.patientMobileNumber = this.mobileNumber; + // request.mobileNo = '0' + this.mobileNumber.toString(); + // request.deviceToken = this.deviceToken; + // request.projectOutSA = this.patientOutSA == true ? true : false; + // request.loginType = this.selectedOption; + // request.oTPSendType = type == 1 ? type : 2; //this.selectedOption == 1 ? 1 : 2; + // request.zipCode = this.zipCode; + // + // request.logInTokenID = this.loginTokenID ?? ""; + // + // if (this.registerd_data != null) { + // request.searchType = this.registerd_data.searchType != null ? this.registerd_data.searchType : 1; + // request.patientID = this.registerd_data.patientID != null ? this.registerd_data.patientID : 0; + // request.patientIdentificationID = request.nationalID = this.registerd_data.patientIdentificationID != null ? this.registerd_data.patientIdentificationID : '0'; + // request.dob = this.registerd_data.dob; + // request.isRegister = this.registerd_data.isRegister; + // } else { + // request.searchType = request.searchType != null ? request.searchType : 2; + // request.patientID = this.user!.patientID != null ? this.user!.patientID : 0; + // request.nationalID = request.nationalID != null ? request.nationalID : '0'; + // request.patientIdentificationID = request.patientIdentificationID != null ? request.patientIdentificationID : '0'; + // request.isRegister = false; + // } + // request.deviceTypeID = request.searchType; + // return request; + // } checkActivationCode({value}) async { // Navigator.pop(context); GifLoaderDialogUtils.showMyDialog(context); - var request = this.getCommonRequest().toJson(); + var request = authService.getCommonRequest(registerd_data: this.registerd_data, deviceToken: this.deviceToken, mobileNumber: this.mobileNumber, zipCode: this.zipCode, patientOutSA: this.patientOutSA, loginTokenID: this.loginTokenID, selectedOption: this.selectedOption, user: this.user! ).toJson(); dynamic res; if (healthId != null || widget.isDubai) { if (!widget.isDubai) { diff --git a/lib/pages/login/saved_login.dart b/lib/pages/login/saved_login.dart new file mode 100644 index 00000000..50ebe25e --- /dev/null +++ b/lib/pages/login/saved_login.dart @@ -0,0 +1,441 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hmg_patient_app/config/config.dart'; +import 'package:hmg_patient_app/config/shared_pref_kay.dart'; +import 'package:hmg_patient_app/core/service/client/base_app_client.dart'; +import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; +import 'package:hmg_patient_app/extensions/string_extensions.dart'; +import 'package:hmg_patient_app/models/Authentication/authenticated_user.dart'; +import 'package:hmg_patient_app/models/Authentication/check_activation_code_response.dart'; +import 'package:hmg_patient_app/models/Authentication/select_device_imei_res.dart'; +import 'package:hmg_patient_app/new_ui/otp/otp_validation_bootmsheet_widget.dart'; +import 'package:hmg_patient_app/pages/landing/landing_page.dart'; +import 'package:hmg_patient_app/pages/login/welcome.dart'; +import 'package:hmg_patient_app/services/authentication/auth_provider.dart' hide sharedPref; +import 'package:hmg_patient_app/uitl/app_toast.dart'; +import 'package:hmg_patient_app/uitl/date_uitl.dart'; +import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart'; +import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; +import 'package:hmg_patient_app/uitl/utils.dart' hide sharedPref; +import 'package:hmg_patient_app/widgets/text/app_texts_widget.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:provider/provider.dart'; + + +class SavedLogin extends StatefulWidget { + final SelectDeviceIMEIRES savedLoginData; + const SavedLogin(this.savedLoginData, {Key? key}) : super(key: key); + + @override + _SavedLogin createState() => _SavedLogin(); +} + +class _SavedLogin extends State { + TextEditingController get phoneController => + TextEditingController( + text: widget.savedLoginData.mobile!.startsWith('0') + ? widget.savedLoginData.mobile!.substring(1) + : widget.savedLoginData.mobile, + ); + + final authService = new AuthProvider(); + late ProjectViewModel projectViewModel; + + + @override + Widget build(BuildContext context) { + + projectViewModel = Provider.of(context); + + return Scaffold( + backgroundColor: const Color(0xFFF8F8FA), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Spacer(flex: 2), + // Welcome back text + const Text( + 'Welcome back', + style: TextStyle( + fontSize: 22, + color: Color(0xFF6C757D), + fontWeight: FontWeight.w400, + ), + ), + const SizedBox(height: 16), + // Names + Column( + children: [ + Text( + widget.savedLoginData.name!.toLowerCase().capitalizeFirstofEach, + style: TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + color: Colors.grey[800], + ), + ), + // Text( + // 'Abdul Ghaffar', + // style: TextStyle( + // fontSize: 28, + // fontWeight: FontWeight.bold, + // color: Colors.grey[800], + // ), + // ), + ], + ), + const SizedBox(height: 24), + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.white), + borderRadius: BorderRadius.circular(8.0), + ), + child: Column(children: [ + + // Last login info + Text( + 'Last Login by ${getType(widget.savedLoginData!.logInType!, context)}', + style: const TextStyle( + fontSize: 14, + color: Color(0xFF6C757D), + ), + ), + Text( + widget.savedLoginData.createdOn != null ? DateUtil.getFormattedDate(DateUtil.convertStringToDate( widget.savedLoginData!.createdOn!), "d MMMM, y 'at' HH:mm") : '--', + style: const TextStyle( + fontSize: 16, + ), + ), + Container( + margin: EdgeInsets.all(16), + child: SvgPicture.asset("assets/images/svg/apple-finder.svg", color: Colors.red, height: 54, width: 54,),), + // Face ID login button + CustomButton( + text: "${TranslationBase.of(context).loginBy} ${getType(widget.savedLoginData!.logInType!, context)}", + onPressed: (){ + loginWithFingerPrintFace(widget.savedLoginData!.logInType!, widget.savedLoginData!.iMEI!); + + }, + backgroundColor:Color(0xffFEE9EA), + borderColor:Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 12, + padding : EdgeInsets.fromLTRB(0, 10, 0, 10), + // icon: "assets/images/svg/apple-finder.svg", + ), + ],),), + const SizedBox(height: 24), + Padding( + padding: EdgeInsets.symmetric(horizontal: 16.0), + + child: Text( + 'OR', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500 + ), + ), + ), + const SizedBox(height: 24), + // OTP login button + CustomButton( + text:TranslationBase.of(context).loginByOTP, + onPressed: (){ + + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, + backgroundColor: Colors.transparent, + builder: (bottomSheetContext) => Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom), + child: SingleChildScrollView( + child: GenericBottomSheet( + countryCode: "966", + initialPhoneNumber: "", + textController: phoneController!, // Assumed to be a TextEditingController + buttons: [ + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: CustomButton( + text: "Send me OTP on SMS", + onPressed: () { + int? val = Utils.onOtpBtnPressed(OTPType.sms, phoneController); + if (val != null) { + //checkUserAuthentication(val); + } + }, + backgroundColor: Colors.red, + borderColor: Colors.red, + textColor: Colors.white, + icon: "assets/images/svg/message.svg", + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: AppText( + "OR", + fontSize: 16, + fontFamily: 'poppins', + color: Color(0xFF2E3039), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: CustomButton( + text: "Send me OTP on WhatsApp", + onPressed: () { + int? val = Utils.onOtpBtnPressed(OTPType.whatsapp, phoneController); + if (val != null) { + //checkUserAuthentication(val); + } + }, + backgroundColor: Colors.white, + borderColor: Color(0xFF2E3039), + textColor: Color(0xFF2E3039), + icon: "assets/images/svg/whatsapp.svg", + ), + ), + ], + ), + ), + ));}, + backgroundColor:Colors.white, + borderColor:Colors.black, + textColor: Colors.black, + padding : EdgeInsets.fromLTRB(0, 14, 0, 14), + // icon: "assets/images/svg/apple-finder.svg", + ), + const Spacer(flex: 2), + // OR divider + + const SizedBox(height: 24), + // Guest and Switch account + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton( + onPressed: () { Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => LandingPage(), + + ), + );}, + child: const Text( + 'Guest', + style: TextStyle( + color: Color(0xFFED1C2B), + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + const SizedBox(width: 24), + TextButton( + onPressed: () { + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => WelcomeLogin(), + + ), + ); + + }, + child: const Text( + 'Switch account', + style: TextStyle( + color: Color(0xFFED1C2B), + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + const SizedBox(height: 20), + ], + ), + ), + ), + + ); + } + + String getType(int type, BuildContext context) { + final t = TranslationBase.of(context); + final types = { + 1: t.verifySMS, + 2: t.verifyFingerprint, + 3: t.verifyFaceID, + 4: t.verifyWhatsApp, + }; + return types[type] ?? t.verifySMS; + } + + //need to move this function on provider to avoid multiple repeat + + loginWithFingerPrintFace(type, String deviceToken ) async { + bool authenticated = false; + final LocalAuthentication auth = LocalAuthentication(); + + try { + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + options: const AuthenticationOptions( + useErrorDialogs: true, + stickyAuth: true, + ), + authMessages: [ + // Optional: uncomment for iOS custom messages + // IOSAuthMessages( + // cancelButton: 'Cancel', + // goToSettingsButton: 'Settings', + // goToSettingsDescription: 'Please set up your Touch ID.', + // lockOut: 'Please re-enable your Touch ID.', + // ), + ], + ); + } on PlatformException catch (e) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: 'Please enable your Touch or Face ID'); + return; + } + + + if (authenticated) { + int lastLogin = 1; + var availableBiometrics = await auth.getAvailableBiometrics(); + + if (availableBiometrics.contains(BiometricType.strong)) { + lastLogin = 3; // Assume Face or secure fingerprint + } else if (availableBiometrics.contains(BiometricType.weak)) { + lastLogin = 2; // Likely weak fingerprint + } + + var request = authService.getCommonRequest( + type: type, + registerd_data: null, + deviceToken: widget.savedLoginData.iMEI, + mobileNumber: int.parse(widget.savedLoginData.mobile!), + zipCode: widget.savedLoginData.outSA == 1 ? '971' : '966', + patientOutSA: widget.savedLoginData.outSA, + loginTokenID: null, + selectedOption: lastLogin, + user: widget.savedLoginData, + ); + + getMobileInfo(request, lastLogin); + } +} + + + getMobileInfo(request,int lastLogin) { + // GifLoaderDialogUtils.showMyDialog(context); + this.authService.getLoginInfo(request).then((result) { + GifLoaderDialogUtils.hideDialog(context); + if (result['SMSLoginRequired'] == false) { + // this.loginTokenID = result['LogInTokenID']; + // this.patientOutSA = result['PatientOutSA']; + // setDefault(); + checkActivationCode(lastLogin,result['LogInTokenID']); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + print(err); + }); + } + + + checkActivationCode(int loginType, String loginToken) async { + + AppGlobal.context = context; + GifLoaderDialogUtils.showMyDialog(context); + var request = authService.getCommonRequest( + type: loginType, + registerd_data: null, + deviceToken: widget.savedLoginData.iMEI, + mobileNumber: int.parse(widget.savedLoginData.mobile!), + zipCode: widget.savedLoginData.outSA == 1 ? '971' : '966', + patientOutSA: widget.savedLoginData.outSA, + loginTokenID: loginToken, + selectedOption: loginType, + user: widget.savedLoginData, + ).toJson(); + dynamic res; + + authService + .checkActivationCode(request, null) + .then((result) async => { + res = result, + if (result is Map) + { + result = CheckActivationCode.fromJson(result as Map), + // if (result.errorCode == '699') + // { + // //699 block run here + // GifLoaderDialogUtils.hideDialog(context), + // Future.delayed(Duration(seconds: 2), () { + // AppToast.showErrorToast(message: result.errorEndUserMessage); + // Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: Login)); + // }) + // } + // else if (this.registerd_data != null && this.registerd_data.isRegister == true) + // { + // widget.changePageViewIndex!(1), + // Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew)), + // } + // else + { + sharedPref.remove(FAMILY_FILE), + result.list.isFamily = false, + // userData = result.list, + sharedPref.setString(BLOOD_TYPE, result.patientBloodType ?? ""), + //Remove o+ from here Added by Aamir + authenticatedUserObject.user = result.list, + projectViewModel.setPrivilege(privilegeList: res), + await sharedPref.setObject(MAIN_USER, result.list), + await sharedPref.setObject(USER_PROFILE, result.list), + // loginTokenID = result.logInTokenID, + await sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID), + await sharedPref.setString(TOKEN, result.authenticationTokenID), + // checkIfUserAgreedBefore(result), + projectViewModel.analytics.loginRegistration.login_successful(), + } + } + // else + // { + // // Navigator.of(context).pop(), + // GifLoaderDialogUtils.hideDialog(context), + // Future.delayed(Duration(seconds: 1), () { + // Navigator.of(context).pop(); + // AppToast.showErrorToast(message: result, localContext: context); + // startSMSService(tempType); + // }), + // + // projectViewModel.analytics.loginRegistration.login_fail(error: result), + // projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result) + // } + }); + } + + + insertIMEI(lastLogin) { + + authService.insertDeviceImei(lastLogin).then((value) => {}).catchError((err) { + print(err); + }); + } +} \ No newline at end of file diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index e0405520..33a02900 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -102,6 +102,7 @@ class _WelcomeLogin extends State { @override Widget build(BuildContext context) { projectViewModel = context.read(); + toDoProvider = context.read(); return AppScaffold( appBarTitle: TranslationBase.of(context).welcome, isShowDecPage: false, @@ -284,7 +285,8 @@ class _WelcomeLogin extends State { } checkUserAuthentication(type) { - showLoader(true); + // showLoader(true); + GifLoaderDialogUtils.showMyDialog(context); var req = getCommonRequest(type: type); req.logInTokenID = ""; @@ -525,7 +527,8 @@ class _WelcomeLogin extends State { ? user!.logInType : null; - showLoader(false); + // showLoader(false); + GifLoaderDialogUtils.hideDialog(context); //this.cs.sharedService.getStorage(AuthenticationService.LAST_LOGIN); } diff --git a/lib/routes.dart b/lib/routes.dart index ec391bd3..b48cd5d7 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -15,6 +15,7 @@ import 'package:hmg_patient_app/pages/login/login-type.dart'; import 'package:hmg_patient_app/pages/login/login.dart'; import 'package:hmg_patient_app/pages/login/register-info.dart'; import 'package:hmg_patient_app/pages/login/register.dart'; +import 'package:hmg_patient_app/pages/login/saved_login.dart'; import 'package:hmg_patient_app/pages/login/welcome.dart'; import 'package:hmg_patient_app/pages/packages_offers/OfferAndPackagesCartPage.dart'; import 'package:hmg_patient_app/pages/packages_offers/PackageOrderCompletedPage.dart'; @@ -58,7 +59,6 @@ const String OPENTOK_CALL_PAGE = 'OPENTOK_CALL_PAGE'; const String CART_ORDER_PAGE = 'cart-order-page'; const String CALL_PAGE = 'CALL_PAGE'; const String INCOMING_CALL_PAGE = 'INCOMING_CALL_PAGE'; - const String HEALTH_WEATHER = 'health-weather'; const APP_UPDATE = 'app-update'; diff --git a/lib/services/authentication/auth_provider.dart b/lib/services/authentication/auth_provider.dart index 6c03f9e9..8e338426 100644 --- a/lib/services/authentication/auth_provider.dart +++ b/lib/services/authentication/auth_provider.dart @@ -18,6 +18,7 @@ import 'package:hmg_patient_app/models/Authentication/insert_device_imei_request import 'package:hmg_patient_app/models/Authentication/register_user_requet.dart'; import 'package:hmg_patient_app/models/Authentication/registered_authenticated_user_req.dart'; import 'package:hmg_patient_app/models/Authentication/select_device_imei_res.dart'; +import 'package:hmg_patient_app/models/Authentication/send_activation_request.dart'; import 'package:hmg_patient_app/models/Request.dart'; import 'package:hmg_patient_app/routes.dart'; import 'package:hmg_patient_app/uitl/app_shared_preferences.dart'; @@ -1937,4 +1938,33 @@ class AuthProvider with ChangeNotifier { model.setState(0, 0, false, null); Navigator.of(AppGlobal.context).pushReplacementNamed(HOME); } + + SendActivationRequest getCommonRequest({type, required registerd_data,required deviceToken,required mobileNumber,required zipCode,required patientOutSA, required loginTokenID, required selectedOption, required SelectDeviceIMEIRES user} ) { + var request = SendActivationRequest(); + request.patientMobileNumber = mobileNumber; + request.mobileNo = '0' + mobileNumber.toString(); + request.deviceToken = deviceToken; + request.projectOutSA = patientOutSA == true ? true : false; + request.loginType = selectedOption; + request.oTPSendType = type == 1 ? type : 2; //this.selectedOption == 1 ? 1 : 2; + request.zipCode = zipCode; + + request.logInTokenID = loginTokenID ?? ""; + + if (registerd_data != null) { + request.searchType = registerd_data.searchType != null ? registerd_data.searchType : 1; + request.patientID = registerd_data.patientID != null ? registerd_data.patientID : 0; + request.patientIdentificationID = request.nationalID = registerd_data.patientIdentificationID != null ? registerd_data.patientIdentificationID : '0'; + request.dob = registerd_data.dob; + request.isRegister = registerd_data.isRegister; + } else { + request.searchType = request.searchType != null ? request.searchType : 2; + request.patientID = user!.patientID != null ? user!.patientID : 0; + request.nationalID = request.nationalID != null ? request.nationalID : '0'; + request.patientIdentificationID = request.patientIdentificationID != null ? request.patientIdentificationID : '0'; + request.isRegister = false; + } + request.deviceTypeID = request.searchType; + return request; + } } diff --git a/lib/splashPage.dart b/lib/splashPage.dart index ebff30a2..ac51a490 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -51,7 +51,7 @@ class _SplashScreenState extends State { if (!_privilegeService.hasError) { Navigator.of(context).pushReplacement( MaterialPageRoute( - builder: (BuildContext context) => WelcomeLogin(), + builder: (BuildContext context) => LandingPage(), // builder: (BuildContext context) => LandingPage(), ), ); diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index bea13750..c8b93fd6 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -3477,6 +3477,8 @@ class TranslationBase { String get welcomeToDrSulaiman => localizedValues["welcomeToDrSulaiman"][locale.languageCode]; String get prepareToElevate => localizedValues["prepareToElevate"][locale.languageCode]; String get dontHaveAccount => localizedValues["dontHaveAccount"][locale.languageCode]; + String get loginByOTP => localizedValues['loginByOTP'][locale.languageCode]; + String get loginBy => localizedValues['loginBy'][locale.languageCode]; String get alreadyHaveAccount => localizedValues["alreadyHaveAccount"][locale.languageCode]; String get loginNow => localizedValues["loginNow"][locale.languageCode]; diff --git a/lib/widgets/quick_login.dart b/lib/widgets/quick_login.dart new file mode 100644 index 00000000..ae57f2af --- /dev/null +++ b/lib/widgets/quick_login.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hmg_patient_app/new_ui/otp/otp_validation_bootmsheet_widget.dart'; +import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; +import 'package:hmg_patient_app/uitl/utils.dart'; +import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart'; + + + +class QuickLoginBottomSheet extends StatefulWidget { + final VoidCallback onPressed; + final bool isDone; + + const QuickLoginBottomSheet({required this.onPressed, this.isDone = false}); + + @override + _QuickLoginBottomSheet createState() => _QuickLoginBottomSheet(); +} +class _QuickLoginBottomSheet extends State { + + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24), + topRight: Radius.circular(24), + ), + ), + padding: const EdgeInsets.all(24), + child: Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center,children: [ + + + widget.isDone ? Column(children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: SvgPicture.asset("assets/images/svg/cross-circle.svg", width: 24, height: 24)),],), + Utils.showLottie(context: context, assetPath: 'assets/animations/lottie/checkmark.json', width: 120, height: 120, repeat: true), + + + const Text( + 'All Set! Now you can login with Face ID or Biometric', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + fontFamily: 'Poppins', + + ), + ), + + ],) : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Image.asset("assets/images/lock-icon.png", height: 101,), + const SizedBox(height: 10), + const Text( + 'Enable Quick Login', + style: TextStyle( + fontSize: 26, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + + const SizedBox(height: 5), + + // Description + const Text( + 'Enabling the quick login will verify through your existing device Face ID / Biometric', + style: TextStyle( + fontSize: 16, + color: Color(0xFF666666), + height: 1.5, + ), + ), + + + + const SizedBox(height: 24), + + // Buttons + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded(child: + + CustomButton( + text: "Enable Quick Login", + onPressed:widget.onPressed, + backgroundColor:Color(0xffED1C2B), + borderColor:Color(0xffED1C2B), + textColor: Colors.white, + icon: "assets/images/svg/apple-finder.svg", + )), + ], + ), + SizedBox(height: 16,), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded(child: + + CustomButton( + text: "Not Now", + onPressed: (){ Navigator.pop(context);}, + backgroundColor:Color(0xffFEE9EA), + borderColor:Color(0xffFEE9EA), + textColor: Colors.red, + // icon: "assets/images/svg/apple-finder.svg", + )), + ], + ), + ], + )],), + ); + } + + +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 131b639f..e5e4d524 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: get_it: ^8.0.3 health: ^13.1.1 fl_chart: ^1.0.0 - camera: ^0.11.1 +# camera: ^0.11.2 permission_handler: ^12.0.0+1 flutter_html: ^3.0.0-beta.2 flutter_widget_from_html: ^0.16.0 @@ -83,6 +83,7 @@ dependencies: flutter_local_notifications: any device_calendar: ^4.3.3 geolocator: ^14.0.2 + geolocator_android: ^5.0.2 geocoding: ^4.0.0 jiffy: ^6.2.1