I'm trying to implement Firebase phone authorization using Flutter Bloc pattern. I have the following code
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:firebase_auth/firebase_auth.dart';
import './bloc.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final FirebaseAuth _auth = FirebaseAuth.instance;
@override
AuthState get initialState => AuthNotStarted();
@override
Stream<AuthState> mapEventToState(
AuthEvent event,
) async* {
if (event is VerifyPhone) {
yield* _mapVerifyPhoneToState(event);
}
}
Stream<AuthState> _mapVerifyPhoneToState(VerifyPhone event) async* {
yield AuthStarted();
_auth.verifyPhoneNumber(
phoneNumber: "+" + event.phoneNumber,
timeout: Duration(seconds: 60),
verificationCompleted: (AuthCredential authCredential) {
print("verification completed: auth credential");
},
verificationFailed: (AuthException authException) {
print("verification failed: auth exception");
print(authException.message);
},
codeSent: (String verificationId, [int forceResendingToken]) {
print("code sent verification id" + verificationId);
},
codeAutoRetrievalTimeout: (String verificationId) {
print("auto time" + verificationId);
});
}
}
But i can't use yield inside verifyPhoneNumber
callbacks. The question is how to yield different states inside of callback functions?
You can add an event from your callback. For example, in verificationCompleted
, you can do:
verificationCompleted: (AuthCredential authCredential) {
print("verification completed: auth credential");
add(AuthCompleted());
},
And you can handle the AuthCompleted()
event on mapEventToState
:
@override
Stream<AuthState> mapEventToState(
AuthEvent event,
) async* {
if (event is VerifyPhone) {
yield* _mapVerifyPhoneToState(event);
}
if (event is AuthCompleted){
//Here you can use yield and whathever you want
}
}
PhoneAuthenticationBloc
class PhoneAuthenticationBloc
extends Bloc<PhoneAuthenticationEvent, PhoneAuthenticationState> {
final AuthRepository _authRepository;
final AuthBloc _authBloc;
@override
Stream<PhoneAuthenticationState> mapEventToState(
PhoneAuthenticationEvent event,
) async* {
if (event is PhoneLoadingEvent) {
yield PhoneLoadingState();
} else if (event is PhoneVerificationFailedEvent) {
yield PhoneOTPFailureState(event.failure);
} else if (event is PhoneSmsCodeSentEvent) {
yield PhoneSmsCodeSentState(
verificationId: event.verificationId, resendCode: event.resendId);
} else if (event is PhoneVerifiedOtpEvent) {
yield* _mapToVerifyOtp(event.smsCode, event.verificationId);
}
}
void verifyPhoneNumber(String phoneNumber) async {
try {
add(PhoneLoadingEvent());
await _authRepository.verifyPhoneNumber(phoneNumber,
onRetrieval: (String retrievalCode) {
print("Time Out Retrieval Code: $retrievalCode");
}, onFailed: (Failure f) {
print("OnFailed: ${f.message}");
add(PhoneVerificationFailedEvent(f));
}, onCompleted: (Map<String, dynamic> data) {
print("verificationCompleted: $data");
}, onCodeSent: (String verificationId, int resendCode) {
print("verificationId:$verificationId & resendCode: $resendCode");
add(PhoneSmsCodeSentEvent(
verificationId: verificationId, resendId: resendCode));
});
} catch (e) {
add(PhoneVerificationFailedEvent(Failure(message: e.toString())));
}
}}
UI Screen
builder: (context, state) {
return AppButton(
isLoading: state is PhoneLoadingState,
onPressed: () async {
if (_formKey.currentState.validate()) {
BlocProvider.of<PhoneAuthenticationBloc>(context)
.verifyPhoneNumber(_phoneController.text);
}
},
title: "Continue",
textColor: Colors.white,
);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.