235 lines
7.9 KiB
Dart
235 lines
7.9 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:equatable/equatable.dart';
|
|
import 'package:user_repository/user_repository.dart';
|
|
|
|
part 'auth_event.dart';
|
|
part 'auth_state.dart';
|
|
|
|
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|
final UserRepository _userRepository;
|
|
final PhoneVerificationService phoneVerificationService =
|
|
PhoneVerificationService();
|
|
String? _verificationId;
|
|
|
|
AuthBloc({required UserRepository userRepository})
|
|
: _userRepository = userRepository,
|
|
super(AuthStateInitial()) {
|
|
on<AuthEventLoginOAuth>(_onAuthEventLoginOAuth);
|
|
on<AuthEventVerifyOAuth>(_onAuthEventVerifyOAuth);
|
|
on<AuthEventAddEmailAndPassword>(_onAuthEventAddEmailAndPassword);
|
|
on<AuthEventUpdatePassword>(_updatePassword);
|
|
on<LinkWithPhoneNumber>(_linkWithPhoneNumber);
|
|
on<LinkWithPhoneNumberOtp>(_linkWithPhoneNumberOtp);
|
|
}
|
|
|
|
void _onAuthEventLoginOAuth(
|
|
AuthEventLoginOAuth event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
try {
|
|
await _userRepository.signInWithPhoneNumber(event.phone);
|
|
|
|
emit(const AuthStateVerifyOAuth(false));
|
|
} catch (e) {
|
|
emit(const AuthStateFailure());
|
|
}
|
|
}
|
|
|
|
void _onAuthEventVerifyOAuth(
|
|
AuthEventVerifyOAuth event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
try {
|
|
final bool isVerified = await _userRepository.verifyOTP(event.code);
|
|
|
|
if (isVerified) {
|
|
emit(AuthStateSuccess());
|
|
} else {
|
|
emit(const AuthStateVerifyOAuth(true));
|
|
}
|
|
} catch (e) {
|
|
emit(const AuthStateFailure());
|
|
}
|
|
}
|
|
|
|
void _onAuthEventAddEmailAndPassword(
|
|
AuthEventAddEmailAndPassword event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
try {
|
|
final String? error = await _userRepository.addEmailAndPassword(
|
|
event.email, event.password);
|
|
if (error == null) {
|
|
emit(AuthStateSuccess());
|
|
} else {
|
|
if (error == 'requires-recent-login') {
|
|
emit(AuthStateRequiresRecentLogin());
|
|
} else if (error == 'email-already-in-use') {
|
|
emit(AuthStateEmailAlreadyInUse());
|
|
} else {
|
|
emit(const AuthStateFailure());
|
|
}
|
|
}
|
|
} catch (e) {
|
|
emit(const AuthStateFailure());
|
|
}
|
|
}
|
|
|
|
void _updatePassword(
|
|
AuthEventUpdatePassword event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
try {
|
|
final error = await _userRepository.updatePassword(
|
|
event.actualPassword, event.password);
|
|
if (error == null) {
|
|
emit(AuthStateSuccess());
|
|
} else {
|
|
switch (error) {
|
|
case UpdatePassworErros.credentialsWrong:
|
|
emit(const AuthStateFailure(message: "Contraseña incorrecta"));
|
|
break;
|
|
case UpdatePassworErros.userNotFound:
|
|
emit(const AuthStateFailure(message: "Usuario no encontrado"));
|
|
break;
|
|
case UpdatePassworErros.unknown:
|
|
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
|
|
break;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
|
|
}
|
|
}
|
|
|
|
void _linkWithPhoneNumber(
|
|
LinkWithPhoneNumber event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
|
|
try {
|
|
await for (PhoneAuthEvent event
|
|
in phoneVerificationService.verifyPhoneNumber(event.phoneNumber)) {
|
|
switch (event.type) {
|
|
case PhoneAuthEventType.verificationCompleted:
|
|
AuthCredential credential = event.data;
|
|
print('Verificación completada. Credencial: $credential');
|
|
break;
|
|
case PhoneAuthEventType.verificationFailed:
|
|
FirebaseAuthException exception = event.data;
|
|
print('Verificación fallida. Excepción: $exception');
|
|
emit(AuthStateFailure(message: "Error inesperado. 🥸 $exception"));
|
|
return; // Detener la ejecución aquí
|
|
case PhoneAuthEventType.codeAutoRetrievalTimeout:
|
|
String verificationId = event.data;
|
|
print(
|
|
'Tiempo de espera agotado para recuperar el código. ID: $verificationId');
|
|
emit(const AuthStateFailure(
|
|
message: "Tiempo de espera agotado. 🥸",
|
|
));
|
|
break;
|
|
case PhoneAuthEventType.codeSent:
|
|
Map<String, dynamic> eventData = event.data;
|
|
String verificationId = eventData['verificationId'];
|
|
int? resendToken = eventData['resendToken'];
|
|
print(
|
|
'Código enviado. ID: $verificationId, resendToken: $resendToken');
|
|
_verificationId = verificationId;
|
|
emit(const AuthStateVerifyOAuth(false));
|
|
break;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
|
|
}
|
|
}
|
|
|
|
void _linkWithPhoneNumber3(
|
|
LinkWithPhoneNumber event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
|
|
try {
|
|
StreamSubscription<PhoneAuthEvent> subscription = phoneVerificationService
|
|
.verifyPhoneNumber(event.phoneNumber)
|
|
.listen((event) async {
|
|
switch (event.type) {
|
|
case PhoneAuthEventType.verificationCompleted:
|
|
AuthCredential credential = event.data;
|
|
print('Verificación completada. Credencial: $credential');
|
|
break;
|
|
case PhoneAuthEventType.verificationFailed:
|
|
FirebaseAuthException exception = event.data;
|
|
print('Verificación fallida. Excepción: $exception');
|
|
break;
|
|
case PhoneAuthEventType.codeAutoRetrievalTimeout:
|
|
String verificationId = event.data;
|
|
print(
|
|
'Tiempo de espera agotado para recuperar el código. ID: $verificationId');
|
|
break;
|
|
case PhoneAuthEventType.codeSent:
|
|
Map<String, dynamic> eventData = event.data;
|
|
String verificationId = eventData['verificationId'];
|
|
int? resendToken = eventData['resendToken'];
|
|
print(
|
|
'Código enviado. ID: $verificationId, resendToken: $resendToken');
|
|
_verificationId = verificationId;
|
|
emit(const AuthStateVerifyOAuth(false));
|
|
break;
|
|
}
|
|
|
|
if (event.type == PhoneAuthEventType.verificationFailed) {
|
|
// Detener la suscripción si la verificación falla
|
|
// subscription.cancel();
|
|
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
|
|
}
|
|
});
|
|
|
|
// await _userRepository
|
|
} catch (e) {
|
|
emit(const AuthStateFailure(message: "Error inesperado. 🥸"));
|
|
}
|
|
}
|
|
|
|
void _linkWithPhoneNumberOtp(
|
|
LinkWithPhoneNumberOtp event, Emitter<AuthState> emit) async {
|
|
emit(AuthStateProcess());
|
|
try {
|
|
final bool isVerified = await _userRepository.linkWithOTP(
|
|
event.phoneNumber, _verificationId!, event.code);
|
|
|
|
if (isVerified) {
|
|
emit(AuthStateSuccess());
|
|
} else {
|
|
emit(const AuthStateVerifyOAuth(true));
|
|
}
|
|
} catch (e) {
|
|
if (e is FirebaseAuthException) {
|
|
switch (e.code) {
|
|
case "invalid-verification-code":
|
|
emit(const AuthStateFailure(
|
|
message: "Código de verificación incorrecto. 🥸",
|
|
));
|
|
break;
|
|
|
|
case "provider-already-linked":
|
|
emit(const AuthStateFailure(
|
|
message: "Cuenta ya vinculada. 🥸",
|
|
));
|
|
break;
|
|
|
|
case "credential-already-in-use":
|
|
emit(const AuthStateFailure(
|
|
message:
|
|
"Este numero ya se encuentra registrado con otra cuenta. 🥸",
|
|
));
|
|
break;
|
|
|
|
default:
|
|
emit(AuthStateFailure(message: "Error inesperado. 🥸 $e"));
|
|
break;
|
|
}
|
|
} else {
|
|
emit(AuthStateFailure(message: "Error inesperado. 🥸 $e"));
|
|
}
|
|
}
|
|
}
|
|
}
|