import 'dart:io' show Platform; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/core/model/imei_details.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; import 'package:doctor_app_flutter/models/auth/send_activation_code_model2.dart'; import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; import 'package:doctor_app_flutter/widgets/otp/sms-popup.dart'; import 'package:doctor_app_flutter/widgets/shared/app_button.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; import '../../config/size_config.dart'; import '../../core/viewModel/auth_view_model.dart'; import '../../routes.dart'; import '../../util/dr_app_shared_pref.dart'; import '../../util/helpers.dart'; import '../../widgets/shared/dr_app_circular_progress_Indeicator.dart'; DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); Helpers helpers = Helpers(); /* *@author: Elham Rababah *@Date:4/7/2020 *@param: *@return: *@desc: Verification Methods widget */ class VerificationMethods extends StatefulWidget { VerificationMethods({this.changeLoadingStata, this.password}); final password; final Function changeLoadingStata; @override _VerificationMethodsState createState() => _VerificationMethodsState(); } class _VerificationMethodsState extends State { MainAxisAlignment spaceBetweenMethods = MainAxisAlignment.spaceBetween; Future _loggedUserFuture; var _loggedUser; var verificationMethod; GetIMEIDetailsModel user; final LocalAuthentication auth = LocalAuthentication(); var _availableBiometrics; ProjectViewModel projectsProvider; var isMoreOption = false; var onlySMSBox = false; static BuildContext _context; var loginTokenID; bool authenticated; var fingrePrintBefore; var selectedOption; @override void initState() { super.initState(); _loggedUserFuture = getSharedPref(); _getAvailableBiometrics(); } Future getSharedPref() async { sharedPref.getObj(LOGGED_IN_USER).then((userInfo) { _loggedUser = userInfo; }); sharedPref.getObj(LAST_LOGIN_USER).then((lastLogin) { if (lastLogin != null) { user = GetIMEIDetailsModel.fromJson(lastLogin); } }); print(user); } @override void didChangeDependencies() { super.didChangeDependencies(); final routeArgs = ModalRoute.of(context).settings.arguments as Map; verificationMethod = routeArgs != null ? routeArgs['verificationMethod'] : null; } @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); projectsProvider = Provider.of(context); return FutureBuilder( future: Future.wait([_loggedUserFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { switch (snapshot.connectionState) { case ConnectionState.waiting: return DrAppCircularProgressIndeicator(); default: if (snapshot.hasError) { helpers.showErrorToast('Error: ${snapshot.error}'); return Text('Error: ${snapshot.error}'); } else { return SingleChildScrollView( child: Container( height: SizeConfig.realScreenHeight, width: SizeConfig.realScreenWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( // height: SizeConfig.realScreenHeight * 0.6, child: Column( children: [ user != null && isMoreOption == false ? Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: [ AppText( TranslationBase.of(context) .welcomeBack + ' ' + user.doctorName, fontSize: SizeConfig.textMultiplier * 3.5, ), SizedBox( height: 20, ), AppText( TranslationBase.of(context).accountInfo, fontSize: SizeConfig.textMultiplier * 2.5, ), SizedBox( height: 20, ), Card( color: Colors.grey[300], child: Row( children: [ Flexible( child: ListTile( title: Text( TranslationBase.of(context) .lastLoginAt, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, ), subtitle: Text( user.editedOn != null ? formatDate(Helpers .convertStringToDate( user.editedOn)) : user.createdOn != null ? formatDate(Helpers .convertStringToDate(user .createdOn)) : '--', overflow: TextOverflow.ellipsis, textAlign: TextAlign.center), )), Flexible( child: ListTile( title: Text( TranslationBase.of(context) .lastLoginWith, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center), subtitle: Text( getType(user.logInTypeID, context), overflow: TextOverflow.ellipsis, textAlign: TextAlign.center), )) ], )), ], ) : Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: [ this.onlySMSBox == false ? AppText( TranslationBase.of(context) .verifyLoginWith, fontSize: SizeConfig.textMultiplier * 3.5, textAlign: TextAlign.left, ) : AppText( TranslationBase.of(context) .verifyFingerprint2, fontSize: SizeConfig.textMultiplier * 2.5, textAlign: TextAlign.start, ), ]), user != null && isMoreOption == false ? Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: InkWell( onTap: () => { authenticateUser( 3, BiometricType .face.index, authProv) }, child: getButton( user.logInTypeID, authProv))), Expanded( child: getButton(5, authProv)) ]) ]) : Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ onlySMSBox == false ? Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: getButton( 3, authProv)), Expanded( child: getButton( 4, authProv)) ], ) : SizedBox(), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: getButton(1, authProv)), Expanded( child: getButton(2, authProv)) ], ), ]), // ) ], ), ), Column( mainAxisAlignment: MainAxisAlignment.end, children: [ user != null ? Row( children: [ Expanded( child: Button( title: TranslationBase.of(context) .useAnotherAccount, onTap: () { Navigator.of(context).pushNamed(LOGIN); }, )), ], ) : SizedBox(), ], ), ], ), )); } } }); } bool hideSilentMethods() { return verificationMethod == 4 || verificationMethod == 3 ? true : false; } /* *@author: Elham Rababah *@Date:15/4/2020 *@param: oTPSendType *@return: *@desc: send Activation Code By Otp Notification Type */ sendActivationCodeByOtpNotificationType( oTPSendType, AuthViewModel authProv) async { // TODO : build enum for verfication method if (oTPSendType == 1 || oTPSendType == 2) { widget.changeLoadingStata(true); int projectID = await sharedPref.getInt(PROJECT_ID); ActivationCodeModel activationCodeModel = ActivationCodeModel( facilityId: projectID, memberID: _loggedUser['List_MemberInformation'][0]['MemberID'], zipCode: _loggedUser['ZipCode'], mobileNumber: _loggedUser['MobileNumber'], otpSendType: oTPSendType.toString(), password: widget.password); try { authProv .sendActivationCodeForDoctorApp(activationCodeModel) .then((res) { if (res['MessageStatus'] == 1) { print("VerificationCode : " + res["VerificationCode"]); sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); sharedPref.setString( VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); sharedPref.setString(PASSWORD, widget.password); this.startSMSService(oTPSendType, authProv); } else { print(res['ErrorEndUserMessage']); helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { print('$err'); widget.changeLoadingStata(false); helpers.showErrorToast(); }); } catch (e) {} } else { // TODO route to this page with parameters to inicate we should present 2 option if (Platform.isAndroid && oTPSendType == 3) { helpers.showErrorToast('Your device not support this feature'); } else { // Navigator.of(context).push(MaterialPageRoute( // builder: (BuildContext context) => // VerificationMethodsScreen(password: widget.password,))); // Navigator.of(context).pushNamed(VERIFICATION_METHODS, // arguments: {'verificationMethod': oTPSendType}); } } } sendActivationCodeVerificationScreen( oTPSendType, AuthViewModel authProv) async { // TODO : build enum for verfication method //if (oTPSendType == 1 || oTPSendType == 2) { widget.changeLoadingStata(true); ActivationCodeModel2 activationCodeModel = ActivationCodeModel2( iMEI: user.iMEI, facilityId: user.projectID, memberID: user.doctorID, zipCode: user.outSA == true ? '971' : '966', mobileNumber: user.mobile, oTPSendType: oTPSendType, isMobileFingerPrint: 1, vidaAuthTokenID: user.vidaAuthTokenID, vidaRefreshTokenID: user.vidaRefreshTokenID); try { authProv .sendActivationCodeVerificationScreen(activationCodeModel) .then((res) { if (res['MessageStatus'] == 1) { print("VerificationCode : " + res["VerificationCode"]); sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); sharedPref.setString( VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); if (oTPSendType == 1 || oTPSendType == 2) { widget.changeLoadingStata(false); this.startSMSService(oTPSendType, authProv); } else { checkActivationCode(authProv); } } else { print(res['ErrorEndUserMessage']); helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { print('$err'); widget.changeLoadingStata(false); helpers.showErrorToast(); }); } catch (e) {} // } // else { // checkActivationCode(authProv); // } } Widget getButton(flag, authProv) { switch (flag) { case 2: return InkWell( onTap: () => {authenticateUser(2, true, authProv)}, child: RoundedContainer( borderColor: Colors.grey, showBorder: true, child: Padding( padding: EdgeInsets.fromLTRB(30, 15, 30, 15), child: Column( children: [ Image.asset( 'assets/images/login/104.png', height: SizeConfig.imageSizeMultiplier * 13, width: SizeConfig.imageSizeMultiplier * 16, ), SizedBox( height: 20, ), AppText( TranslationBase.of(context).verifyWhatsApp, fontSize: SizeConfig.textMultiplier * 2, textAlign: TextAlign.center, ) ], ), ))); break; case 1: return InkWell( onTap: () => {authenticateUser(1, true, authProv)}, child: RoundedContainer( borderColor: Colors.grey, showBorder: true, child: Padding( padding: EdgeInsets.fromLTRB(5, 15, 5, 15), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/images/login/103.png', height: SizeConfig.imageSizeMultiplier * 13, width: SizeConfig.imageSizeMultiplier * 16, ), projectsProvider.isArabic ? SizedBox( height: 20, ) : SizedBox( height: 20, ), AppText( TranslationBase.of(context).verifySMS, fontSize: projectsProvider.isArabic ? SizeConfig.textMultiplier * 1.8 : SizeConfig.textMultiplier * 2, textAlign: TextAlign.center, ) ], ), ))); break; case 3: return InkWell( onTap: () => { if (checkIfBiometricAvailable(BiometricType.fingerprint)) { authenticateUser( 3, BiometricType.fingerprint.index, authProv) } }, child: RoundedContainer( backgroundColor: checkIfBiometricAvailable(BiometricType.fingerprint) ? Colors.white : Colors.white.withOpacity(.7), borderColor: Colors.grey, showBorder: true, child: Padding( padding: EdgeInsets.fromLTRB(5, 15, 5, 15), child: Column( children: [ Image.asset( 'assets/images/login/102.png', height: SizeConfig.imageSizeMultiplier * 13, width: SizeConfig.imageSizeMultiplier * 16, ), SizedBox( height: 20, ), AppText( TranslationBase.of(context).verifyFingerprint, fontSize: SizeConfig.textMultiplier * 2, textAlign: TextAlign.center, ) ], ), ))); break; case 4: return InkWell( onTap: () { if (checkIfBiometricAvailable(BiometricType.face)) { authenticateUser(4, BiometricType.face.index, authProv); } }, child: RoundedContainer( backgroundColor: checkIfBiometricAvailable(BiometricType.face) ? Colors.white : Colors.white.withOpacity(.7), borderColor: Colors.grey, showBorder: true, child: Padding( padding: EdgeInsets.fromLTRB(5, 15, 5, 15), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/images/login/101.png', height: SizeConfig.imageSizeMultiplier * 13, width: SizeConfig.imageSizeMultiplier * 16, ), SizedBox( height: 20, ), AppText( TranslationBase.of(context).verifyFaceID, fontSize: SizeConfig.textMultiplier * 2, textAlign: TextAlign.center, ) ], ), ))); break; default: return InkWell( onTap: () => { setState(() { isMoreOption = true; }) }, child: RoundedContainer( backgroundColor: Colors.white, borderColor: Colors.grey, showBorder: true, child: Padding( padding: EdgeInsets.fromLTRB(5, 0, 5, 5), child: Column( children: [ Image.asset( 'assets/images/login/more_icon.png', height: SizeConfig.imageSizeMultiplier * 13, width: SizeConfig.imageSizeMultiplier * 16, ), projectsProvider.isArabic ? SizedBox( height: 15, ) : SizedBox( height: 10, ), AppText( TranslationBase.of(context).moreVerification, fontSize: SizeConfig.textMultiplier * 2, textAlign: TextAlign.center, ) ], ), ))); } } getType(type, context) { switch (type) { case 1: return TranslationBase.of(context).verifySMS; break; case 3: return TranslationBase.of(context).verifyFingerprint; break; case 4: return TranslationBase.of(context).verifyFaceID; break; case 2: return TranslationBase.of(context).verifyWhatsApp; break; default: return TranslationBase.of(context).verifySMS; break; } } bool checkIfBiometricAvailable(BiometricType biometricType) { bool isAvailable = false; if (_availableBiometrics != null) { for (var i = 0; i < _availableBiometrics.length; i++) { if (biometricType == _availableBiometrics[i]) isAvailable = true; } } return isAvailable; } formatDate(date) { return DateFormat('MMM dd, yyy, kk:mm').format(date); } authenticateUser(type, isActive, authProv) { //GifLoaderDialogUtils.showMyDialog(context); if (type == 3 || type == 4) { fingrePrintBefore = type; } this.selectedOption = fingrePrintBefore != null ? fingrePrintBefore : type; switch (type) { case 1: this.loginWithSMS(1, isActive, authProv); break; case 2: this.loginWithSMS(2, isActive, authProv); break; case 3: this.loginWithFingurePrintFace(3, isActive, authProv); break; case 4: this.loginWithFingurePrintFace(4, isActive, authProv); break; default: break; } sharedPref.setInt(OTP_TYPE, selectedOption); // sharedPref.setInt(LAST_LOGIN), } loginWithSMS(type, isActive, authProv) { this.sendActivationCode(type, authProv); } Future _getAvailableBiometrics() async { var availableBiometrics; try { availableBiometrics = await auth.getAvailableBiometrics(); } on PlatformException catch (e) { print(e); } if (!mounted) return; setState(() { _availableBiometrics = availableBiometrics; }); } sendActivationCode(type, authProv) async { if (user != null) { sendActivationCodeVerificationScreen(type, authProv); } else { sendActivationCodeByOtpNotificationType(type, authProv); } } startSMSService(type, authProv) { new SMSOTP( context, type, _loggedUser != null ? _loggedUser['MobileNumber'] : user.mobile, (value) { showDialog( context: context, builder: (BuildContext context) { return Center( child: CircularProgressIndicator(), ); }); this.checkActivationCode(authProv, value: value); }, () => { //Navigator.pop(context), print('Faild..'), }, ).displayDialog(context); } loginWithFingurePrintFace(type, isActive, authProv) async { if (isActive == 1) { // this.startBiometricLoginIfAvailable(); authenticated = await auth.authenticateWithBiometrics( localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true); if (user != null && (user.logInTypeID == 3 || user.logInTypeID == 4)) { this.sendActivationCode(type, authProv); // this.checkActivationCode(authProv); } else { setState(() { this.onlySMSBox = true; }); } } } checkActivationCode(AuthViewModel authProv, {value}) async { CheckActivationCodeRequestModel checkActivationCodeForDoctorApp = new CheckActivationCodeRequestModel( zipCode: _loggedUser != null ? _loggedUser['ZipCode'] : user.zipCode, mobileNumber: _loggedUser != null ? _loggedUser['MobileNumber'] : user.mobile, projectID: await sharedPref.getInt(PROJECT_ID) != null ? await sharedPref.getInt(PROJECT_ID) : user.projectID, logInTokenID: await sharedPref.getString(LOGIN_TOKEN_ID), activationCode: value ?? '0000', oTPSendType: await sharedPref.getInt(OTP_TYPE), generalid: "Cs2020@2016\$2958"); authProv .checkActivationCodeForDoctorApp(checkActivationCodeForDoctorApp) .then((res) async { widget.changeLoadingStata(false); if (res['MessageStatus'] == 1) { sharedPref.setString(TOKEN, res['AuthenticationTokenID']); if (res['List_DoctorProfile'] != null) { loginProcessCompleted(res['List_DoctorProfile'][0], authProv); sharedPref.setObj(CLINIC_NAME, res['List_DoctorsClinic']); } else { sharedPref.setObj(CLINIC_NAME, res['List_DoctorsClinic']); ClinicModel clinic = ClinicModel.fromJson(res['List_DoctorsClinic'][0]); getDocProfiles(clinic, authProv); } } else { Navigator.pop(context); helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { Navigator.pop(context); helpers.showErrorToast(err); }); } loginProcessCompleted(Map profile, authProv) { var doctor = DoctorProfileModel.fromJson(profile); authProv.setDoctorProfile(doctor); sharedPref.setObj(DOCTOR_PROFILE, profile); projectsProvider.isLogin = true; Navigator.of(context).pushReplacementNamed(HOME); } getDocProfiles(ClinicModel clinicInfo, authProv) { ProfileReqModel docInfo = new ProfileReqModel( doctorID: clinicInfo.doctorID, clinicID: clinicInfo.clinicID, license: true, projectID: clinicInfo.projectID, tokenID: '', languageID: 2); authProv.getDocProfiles(docInfo.toJson()).then((res) { if (res['MessageStatus'] == 1) { loginProcessCompleted(res['DoctorProfileList'][0], authProv); } else { // changeLoadingStata(false); helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { // changeLoadingStata(false); helpers.showErrorToast(err); }); } }