无效状态:无法调用FirebaseAuth.veryfyPhone的phoneCodeAutoRetrievalTimeout回调后添加新事件。轻弹

时间:2020-10-24 12:25:03

标签: flutter bloc

我正在实施FirebaseAuth验证电话以适应本指南https://medium.com/@tapanrgohil/firebase-phone-authentication-in-flutter-with-bloc-pattern-4ddc2d43d76c,因为我不想登录,而只是将新的PhoneAuthentication链接到现有用户,而我使用的是AuthenticationBloc而不是Bloc在指南中。

我从PaymentScreen开始电话验证过程,并尝试直接在AuthenticationBloc的{​​{1}}中提供PaymentScreen,以为创建一个新的MultiBlocProvider,但是错误是相同的。

AuthenticationBloc中,内部AuthenticationBloc基本上负责所有电话验证事件。 StreamController的{​​{1}}中的传入States只会弹出并显示对话框,就像PaymentScreen出现手动otp插入对话框,错误,错误的otp等情况一样。 为了找出导致不良状态的原因,我首先注释掉了所有上下文弹出消息,以确保不是那样,然后注释掉了流中的所有BlocListener

这些是从控制台打印出来的:

AutoRetrieveCodeTimeout

您能发现关闭集团的原因吗?

非常感谢。

AuthenticationBloc

.close()

AuthenticationEvent:

I/flutter ( 7710): VerifyPhoneNumberEvent received
I/flutter ( 7710): _mapVerifyPhoneNumberToState started
I/BiChannelGoogleApi( 7710): [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq@7f6fccb
I/flutter ( 7710): _mapVerifyPhoneNumberToState PhoneCodeSent
I/flutter ( 7710): PhoneCodeSentEvent received
I/flutter ( 7710): _mapVerifyPhoneNumberToState PhoneCodeAutoRetrievalTimeout
I/flutter ( 7710): Bloc error is Bad state: Cannot add new events after calling close
I/flutter ( 7710): Bloc error is Bad state: Cannot add new events after calling close
I/flutter ( 7710): Bloc error is Bad state: Cannot add new events after calling close
I/flutter ( 7710): Bloc error is Bad state: Cannot add new events after calling close
I/flutter ( 7710): Bloc error is Bad state: Cannot add new events after calling close
I/flutter ( 7710): Bloc error is Bad state: Cannot add new events after calling close

AuthenticationState:

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  final UserRepository _userRepository;

  AuthenticationBloc({@required UserRepository userRepository})
      : assert(userRepository != null),
        _userRepository = userRepository;

  StreamSubscription subscription;
  String verificationId = "";


  @override
  AuthenticationState get initialState => Uninitialized();

  @override
  Stream<AuthenticationState> mapEventToState(
      AuthenticationEvent event) async* {
    if (event is StartApp) {
      yield* _startAppToState();
    }
    if (event is AppStarted) {
      yield* _mapAppStartedToState();
    } else if (event is LoggedIn) {
      yield* _mapLoggedInToState();
    } else if (event is LoggedOut) {
      yield* _mapLoggedOutToState();
    }
    // phone verification
    if (event is VerifyPhoneNumberEvent) {
      print('VerifyPhoneNumberEvent received');
      yield VerifyingState();
      subscription = _mapVerifyPhoneNumberToState(event.phoneNumber).listen((event) {
        add(event);
      });
    } else if (event is PhoneCodeSentEvent) {
      print('PhoneCodeSentEvent received');
      yield OtpSentState();
    } else if (event is VerificationCompletedEvent) {
      print('VerificationCompletedEvent received');
      yield VerificationCompleteState(firebaseUser: event.firebaseUser, isVerified: event.isVerified);
    } else if (event is VerificationExceptionEvent) {
      print('VerificationExceptionEvent received');
      yield VerificationExceptionState(message: event.message);
    } else if (event is VerifySmsCodeEvent) {
      print('VerifySmsCodeEvent received');
      yield VerifyingState();
      try {
        AuthResult result =
        await _userRepository.verifyAndLinkAuthCredentials(verificationId: verificationId, smsCode: event.smsCode);
        if (result.user != null) {
          yield VerificationCompleteState(firebaseUser: result.user, isVerified: true);
        } else {
          yield OtpExceptionState(message: "Invalid otp!",verificationId: verificationId);
        }
      } catch (e) {
        yield OtpExceptionState(message: "Invalid otp!", verificationId: verificationId);
        print(e);
      }
    } else if ( event is PhoneCodeAutoRetrievalTimeoutEvent){
      yield PhoneCodeAutoRetrievalTimeoutState(verificationId: event.verificationId);
    }
    
    if(event is SendVerificationCodeEvent) {
      yield*_mapVerificationCodeToState(event);
    }


  }


  Stream<AuthenticationEvent> _mapVerifyPhoneNumberToState(String phoneNumber) async* {
    print('_mapVerifyPhoneNumberToState started');
    StreamController<AuthenticationEvent> phoneVerificationStreamController = StreamController();
    final phoneVerificationCompleted = (AuthCredential authCredential) {
      print('_mapVerifyPhoneNumberToState PhoneVerificationCompleted');
//      _userRepository.getUser();
      _userRepository.getCurrentUser().catchError((onError) {
        print(onError);
      }).then((user) {
        phoneVerificationStreamController.add(VerificationCompletedEvent(firebaseUser: user, isVerified:  true));
//        phoneVerificationStreamController.close();
      });
    };
    final phoneVerificationFailed = (AuthException authException) {
      print('_mapVerifyPhoneNumberToState PhoneVerificationFailed');
      print(authException.message);
      phoneVerificationStreamController.add(VerificationExceptionEvent(onError.toString()));
//      phoneVerificationStreamController.close();
    };
    final phoneCodeSent = (String verificationId, [int forceResent]) {
      print('_mapVerifyPhoneNumberToState PhoneCodeSent');
      this.verificationId = verificationId;
      phoneVerificationStreamController.add(PhoneCodeSentEvent());
    };
     final phoneCodeAutoRetrievalTimeout = (String verificationId) {

       // after this print Bloc error is Bad state: Cannot add new events after calling close
      print('_mapVerifyPhoneNumberToState PhoneCodeAutoRetrievalTimeout');
      this.verificationId = verificationId;
//      phoneVerificationStreamController.close();
//      phoneVerificationStreamController.add(PhoneCodeAutoRetrievalTimeoutEvent(verificationId: verificationId));
    };

    await _userRepository.verifyPhone(
        phoneNumber: phoneNumber,
        timeOut: Duration(seconds: 0), // 0 triggers PhoneCodeAutoRetrievalTimeout immediately
        phoneVerificationFailed: phoneVerificationFailed,
        phoneVerificationCompleted: phoneVerificationCompleted,
        phoneCodeSent: phoneCodeSent,
        autoRetrievalTimeout: phoneCodeAutoRetrievalTimeout);

    yield* phoneVerificationStreamController.stream;
  }

  Stream<AuthenticationState> _startAppToState() async* {
    Timer(Duration(seconds: 5), () {
      add(AppStarted());
    });
  }

  Stream<AuthenticationState> _mapAppStartedToState() async* {
    try {
      final isSignedIn = await _userRepository.isSignedIn();
      if (isSignedIn) {
        final user = await _userRepository.getUser();
        yield Authenticated(user);
      } else {
        yield Unauthenticated();
      }
    } catch (_) {
      yield Unauthenticated();
    }
  }

  Stream<AuthenticationState> _mapLoggedInToState() async* {
    yield Authenticated(await _userRepository.getUser());
  }

  Stream<AuthenticationState> _mapLoggedOutToState() async* {
    yield Unauthenticated();
    _userRepository.signOut();
  }

  Stream<AuthenticationState> _mapVerificationCodeToState(SendVerificationCodeEvent event) async* {
    print('_mapVerificationCodeToState started');
    yield VerifyingState();
    try {
      AuthResult result =
      await _userRepository.verifyAndLinkAuthCredentials(verificationId: verificationId, smsCode: event.smsCode);
      if (result.user != null) {
        yield VerificationCompleteState(firebaseUser: result.user, isVerified: true);
      } else {
        yield OtpExceptionState(message: "Invalid otp!", verificationId: verificationId);
      }
    } catch (e) {
      yield OtpExceptionState(message: "Invalid otp!", verificationId: verificationId);
      print(e);
    }
  }
}

付款屏幕:

class VerifyPhoneNumberEvent extends AuthenticationEvent {
  final String phoneNumber;
  VerifyPhoneNumberEvent({this.phoneNumber});
}



class VerifySmsCodeEvent extends AuthenticationEvent {
  final String smsCode;
  VerifySmsCodeEvent({this.smsCode});
}



class PhoneCodeSentEvent extends AuthenticationEvent {}

class VerificationCompletedEvent extends AuthenticationEvent {
  final FirebaseUser firebaseUser;
  final bool isVerified;
  VerificationCompletedEvent({@required this.firebaseUser, @required this.isVerified});
  @override
  List<Object> get props => [firebaseUser,isVerified];
  @override
  String toString() => 'VerificationCompleteEvent{user:${firebaseUser.displayName}, isVerified: $isVerified}';
}

class VerificationExceptionEvent extends AuthenticationEvent {
  final String message;

  VerificationExceptionEvent(this.message);
}
class PhoneCodeAutoRetrievalTimeoutEvent extends AuthenticationEvent {
  final String verificationId;
  PhoneCodeAutoRetrievalTimeoutEvent({@required this.verificationId});
  @override
  List<Object> get props => [verificationId];
  @override 
  String toString() => 'PhoneCodeAutoRetrievalTimeoutEvent {verificationId: $verificationId}';
}

启动电话验证的对话框:

class OtpSentState extends AuthenticationState {}

class VerifyingState extends AuthenticationState {}

class OtpVerifiedState extends AuthenticationState {}

class PhoneCodeAutoRetrievalTimeoutState extends AuthenticationState {
  final String verificationId;

  PhoneCodeAutoRetrievalTimeoutState({@required this.verificationId});
  @override
  List<Object> get props => [verificationId];
  @override
  String toString() => 'PhoneCodeAutoRetrievalTimeoutState {verificationId: $verificationId}';
}

class VerificationCompleteState extends AuthenticationState {
  final FirebaseUser firebaseUser;

  final bool isVerified;
  VerificationCompleteState({@required this.firebaseUser, @required this.isVerified});

  FirebaseUser getUser(){
    return firebaseUser;
  }
  @override
  List<Object> get props => [firebaseUser, isVerified];

  @override
  String toString() => 'VerificationCompleteState{user:${firebaseUser.displayName}, isVerified: $isVerified}';

}

class VerificationExceptionState extends AuthenticationState {
  final String message;

  VerificationExceptionState({this.message});

  @override
  // TODO: implement props
  List<Object> get props => [message];
}

class OtpExceptionState extends AuthenticationState {
  final String message;
  final String verificationId;

  OtpExceptionState({@required this.message, @required this.verificationId});

  @override
  // TODO: implement props
  List<Object> get props => [message, verificationId];
}

1 个答案:

答案 0 :(得分:0)

经过几次试验,我发现主要问题是使用AuthenticationBloc,所以我在仍然使用PhoneAuthenticationBlocAuthenticationState的同时制作了专用的AuthenticationState并照顾了没有“ StreamController”的事件/状态路由。

我将把课程留在这里,以帮助其他人。

新集团:

class PhoneAuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  final UserRepository _userRepository;


  PhoneAuthenticationBloc({@required UserRepository userRepository})
      : assert(userRepository != null),
        _userRepository = userRepository;

  String verificationId = "";


  @override
  AuthenticationState get initialState => Uninitialized();

  @override
  Stream<AuthenticationState> mapEventToState(
      AuthenticationEvent event) async* {
    // phone verification
    if (event is VerifyPhoneNumberEvent) {
      print('VerifyPhoneNumberEvent received');
      yield VerifyingState();
      yield* _mapVerifyPhoneNumberToState(event);
    }
    if (event is PhoneCodeSentEvent) {
      print('PhoneCodeSentEvent received');
      yield OtpSentState();
    }
    if (event is VerificationCompletedEvent) {
      print('VerificationCompletedEvent received');
      yield VerificationCompleteState(firebaseUser: event.firebaseUser, isVerified: event.isVerified);
    }
    if (event is VerificationExceptionEvent) {
      print('VerificationExceptionEvent received');
      yield VerificationExceptionState(message: event.message);
    }

    if ( event is PhoneCodeAutoRetrievalTimeoutEvent){
      yield PhoneCodeAutoRetrievalTimeoutState(verificationId: event.verificationId);
    }

    if(event is SendVerificationCodeEvent) {
      yield VerifyingState();
      yield*_mapVerificationCodeToState(event);
    }


  }

  Stream<AuthenticationState> _mapVerifyPhoneNumberToState(VerifyPhoneNumberEvent event) async* {
    print('_mapVerifyPhoneNumberToState V2 started');
    final phoneVerificationCompleted = (AuthCredential authCredential) {
      print('_mapVerifyPhoneNumberToState PhoneVerificationCompleted');
      _userRepository.getCurrentUser().catchError((onError) {
        print(onError);
      }).then((user) {
        add(VerificationCompletedEvent(firebaseUser: user, isVerified:  true));
      });
    };
    final phoneVerificationFailed = (AuthException authException) {
      print('_mapVerifyPhoneNumberToState PhoneVerificationFailed');
      print(authException.message);
      add(VerificationExceptionEvent(onError.toString()));
    };
    final phoneCodeSent = (String verificationId, [int forceResent]) {
      print('_mapVerifyPhoneNumberToState PhoneCodeSent');
      this.verificationId = verificationId;
      add(PhoneCodeSentEvent());
    };
    final phoneCodeAutoRetrievalTimeout = (String verificationId) {
      print('_mapVerifyPhoneNumberToState PhoneCodeAutoRetrievalTimeout');
      this.verificationId = verificationId;
      add(PhoneCodeAutoRetrievalTimeoutEvent(verificationId: verificationId));
    };

    await _userRepository.verifyPhone(
        phoneNumber: event.phoneNumber,
        timeOut: Duration(seconds: 0),
        phoneVerificationFailed: phoneVerificationFailed,
        phoneVerificationCompleted: phoneVerificationCompleted,
        phoneCodeSent: phoneCodeSent,
        autoRetrievalTimeout: phoneCodeAutoRetrievalTimeout);
  }


  Stream<AuthenticationState> _mapVerificationCodeToState(SendVerificationCodeEvent event) async* {
    print('_mapVerificationCodeToState started');
      AuthResult result = await _userRepository.verifyAndLinkAuthCredentials(verificationId: verificationId, smsCode: event.smsCode)
          .catchError((e){
            print('verifyAndLinkAuthCredentials error: $e');
      });
      print(result);

      if (result != null) {
        yield VerificationCompleteState(firebaseUser: result.user, isVerified: true);
      } else {
        yield OtpExceptionState(message: "Invalid otp!", verificationId: verificationId);
      }
  }
}

新的UserRepository方法:

Future<void> verifyPhone(
      {@required String phoneNumber,
      @required Duration timeOut,
      @required PhoneVerificationFailed phoneVerificationFailed,
      @required PhoneVerificationCompleted phoneVerificationCompleted,
      @required PhoneCodeSent phoneCodeSent,
      @required PhoneCodeAutoRetrievalTimeout autoRetrievalTimeout}) async {
    _firebaseAuth.verifyPhoneNumber(
        phoneNumber: phoneNumber,
        timeout: timeOut,
        verificationCompleted: phoneVerificationCompleted,
        verificationFailed: phoneVerificationFailed,
        codeSent: phoneCodeSent,
        codeAutoRetrievalTimeout: autoRetrievalTimeout);
  }

  Future<AuthResult> verifyAndLinkAuthCredentials(
  {@required String verificationId, @required String smsCode}) async {
    AuthCredential authCredential = PhoneAuthProvider.getCredential(
        verificationId: verificationId, smsCode: smsCode);

//    return _firebaseAuth.signInWithCredential(authCredential);

    FirebaseUser user = await _firebaseAuth.currentUser();
    return user.linkWithCredential(authCredential).catchError((e) {
      print('UserRepository.verifyAndLinkAuthCredentials() error: $e');
//      return;
      });
  }

事件:

class VerifyPhoneNumberEvent extends AuthenticationEvent {
  final String phoneNumber;
  VerifyPhoneNumberEvent({this.phoneNumber});
}



class VerifySmsCodeEvent extends AuthenticationEvent {
  final String smsCode;
  VerifySmsCodeEvent({this.smsCode});
}



class PhoneCodeSentEvent extends AuthenticationEvent {}

class VerificationCompletedEvent extends AuthenticationEvent {
  final FirebaseUser firebaseUser;
  final bool isVerified;
  VerificationCompletedEvent({@required this.firebaseUser, @required this.isVerified});
  @override
  List<Object> get props => [firebaseUser,isVerified];
  @override
  String toString() => 'VerificationCompleteEvent{user:${firebaseUser.displayName}, isVerified: $isVerified}';
}

class VerificationExceptionEvent extends AuthenticationEvent {
  final String message;

  VerificationExceptionEvent(this.message);
}
class PhoneCodeAutoRetrievalTimeoutEvent extends AuthenticationEvent {
  final String verificationId;
  PhoneCodeAutoRetrievalTimeoutEvent({@required this.verificationId});
  @override
  List<Object> get props => [verificationId];
  @override 
  String toString() => 'PhoneCodeAutoRetrievalTimeoutEvent {verificationId: $verificationId}';
}

状态:

class OtpSentState extends AuthenticationState {}

class VerifyingState extends AuthenticationState {}

class OtpVerifiedState extends AuthenticationState {}

class PhoneCodeAutoRetrievalTimeoutState extends AuthenticationState {
  final String verificationId;

  PhoneCodeAutoRetrievalTimeoutState({@required this.verificationId});
  @override
  List<Object> get props => [verificationId];
  @override
  String toString() => 'PhoneCodeAutoRetrievalTimeoutState {verificationId: $verificationId}';
}

class VerificationCompleteState extends AuthenticationState {
  final FirebaseUser firebaseUser;

  final bool isVerified;
  VerificationCompleteState({@required this.firebaseUser, @required this.isVerified});

  FirebaseUser getUser(){
    return firebaseUser;
  }
  @override
  List<Object> get props => [firebaseUser, isVerified];

  @override
  String toString() => 'VerificationCompleteState{user:${firebaseUser.displayName}, isVerified: $isVerified}';

}

class VerificationExceptionState extends AuthenticationState {
  final String message;

  VerificationExceptionState({this.message});

  @override
  // TODO: implement props
  List<Object> get props => [message];
}

class OtpExceptionState extends AuthenticationState {
  final String message;
  final String verificationId;

  OtpExceptionState({@required this.message, @required this.verificationId});

  @override
  // TODO: implement props
  List<Object> get props => [message, verificationId];
}

UI:

showDialog(
                                          context: context,
                                          barrierDismissible: false,
                                          builder:
                                              (BuildContext dialogContext) {
                                            return SingleChildScrollView(
                                              child: ValidatePhoneDialog(
                                                  controller: controller,
                                                  onPressed: () {
                                                    if (controller
                                                            .text.length >=
                                                        9) {
                                                      BlocProvider.of<
                                                                  PhoneAuthenticationBloc>(
                                                              context)
                                                          .add(VerifyPhoneNumberEvent(
                                                              phoneNumber:
                                                                  controller
                                                                      .text
                                                                      .replaceAll(
                                                                          ' ',
                                                                          '')));
                                                    } else {
                                                      scaffoldKey.currentState
                                                          .showSnackBar(SnackBar(
                                                              backgroundColor:
                                                                  Colors
                                                                      .redAccent,
                                                              content: Text(
                                                                  AppLocalizations
                                                                      .instance
                                                                      .text(
                                                                          'Wrong number'),
                                                                  style: TextStyle(
                                                                      color: Colors
                                                                          .white))));
                                                    }
                                                  }),
                                            );
                                          });

BlocListener:

BlocListener<PhoneAuthenticationBloc, AuthenticationState>(
                    listener:
                        (BuildContext context, AuthenticationState state) {
                  if (state is VerifyingState) {
                    Navigator.of(context, rootNavigator: false).pop(context);
                    showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (BuildContext context) {
                          return VerifyingDialog();
                        });
                  }
                  if (state is VerificationExceptionState) {
                    // ain't no sunshine
                    Navigator.of(context, rootNavigator: false).pop(context);
                    // Todo retry
                    showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (BuildContext dialogContext) {
                          return SingleChildScrollView(
                            child: ValidatePhoneRetryDialog(
                                controller: controller,
                                onPressed: () {
                                  if (controller.text.length >= 9) {
                                    BlocProvider.of<PhoneAuthenticationBloc>(
                                            context)
                                        .add(VerifyPhoneNumberEvent(
                                            phoneNumber: controller.text
                                                .replaceAll(' ', '')));
//                                                    Navigator.pop(context);
                                    Navigator.of(context, rootNavigator: false)
                                        .pop();
                                    showDialog(
                                        context: context,
                                        barrierDismissible: false,
                                        builder: (BuildContext context) {
                                          return VerifyingDialog();
                                        });
                                  } else {
                                    scaffoldKey.currentState.showSnackBar(
                                        SnackBar(
                                            backgroundColor: Colors.redAccent,
                                            content: Text(
                                                AppLocalizations.instance
                                                    .text('Wrong number'),
                                                style: TextStyle(
                                                    color: Colors.white))));
                                  }
                                }),
                          );
                        });
//                        scaffoldKey.currentState.showSnackBar(SnackBar(
//                            backgroundColor: Colors.redAccent,
//                            content: Text(
//                                AppLocalizations.instance
//                                    .text('Phone verification error'),
//                                style: TextStyle(color: Colors.white))));
                  }

                  if (state is PhoneCodeAutoRetrievalTimeoutState) {
                    //manually insert OTP
                    print('PhoneCodeAutoRetrievalTimeoutState');
                    setState(() {
                      controller.text = '';
                    });
                    Navigator.of(context, rootNavigator: false).pop(context);
                    showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (BuildContext dialogContext) {
                          return SingleChildScrollView(
                            child: VerifyOtpDialog(
                                controller: controller,
                                onPressed: () {
                                  if (controller.text.length == 6) {
                                    BlocProvider.of<PhoneAuthenticationBloc>(
                                            context)
                                        .add(SendVerificationCodeEvent(
                                            verificationId:
                                                state.verificationId,
                                            smsCode: controller.text
                                                .replaceAll(' ', '')));
                                  } else {
                                    scaffoldKey.currentState.showSnackBar(
                                        SnackBar(
                                            backgroundColor: Colors.redAccent,
                                            content: Text(
                                                AppLocalizations.instance
                                                    .text('Wrong code'),
                                                style: TextStyle(
                                                    color: Colors.white))));
                                  }
                                }),
                          );
                        });
                  }

                  if (state is OtpExceptionState) {
                    // if at the first you don't succeed..
                    Navigator.of(context, rootNavigator: false).pop(context);
                    showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (BuildContext dialogContext) {
                          return SingleChildScrollView(
                            child: VerifyOtpRetryDialog(
                                controller: controller,
                                onPressed: () {
                                  if (controller.text.length == 6) {
                                    BlocProvider.of<PhoneAuthenticationBloc>(
                                            context)
                                        .add(SendVerificationCodeEvent(
                                            verificationId:
                                                state.verificationId,
                                            smsCode: controller.text
                                                .replaceAll(' ', '')));
                                  } else {
                                    scaffoldKey.currentState.showSnackBar(
                                        SnackBar(
                                            backgroundColor: Colors.redAccent,
                                            content: Text(
                                                AppLocalizations.instance
                                                    .text('Wrong code'),
                                                style: TextStyle(
                                                    color: Colors.white))));
                                  }
                                }),
                          );
                        });
                  }

                  if (state is VerificationCompleteState) {
                    // kool and the gang
                    if (state.isVerified == true) {
                      setState(() {
                        isVerified = state.isVerified;
                      });
                      Navigator.of(context, rootNavigator: false).pop(context);
                      showDialog(
                          context: context,
                          barrierDismissible: false,
                          builder: (BuildContext dialogContext) {
                            return VerifiedPhoneConfirmationDialog();
                          });
                      BlocProvider.of<UserBloc>(context)
                          .add(UserPhoneVerified(user: widget.user));
                      Timer(Duration(milliseconds: 1200), () {
                        Navigator.of(context, rootNavigator: false).pop();
                      });

                      // TODO: Save user isVerified to LocalDb and Firebase

                    }
                  }
                }),