feat: legacy mobile apps created
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:krow/core/application/common/validators/phone_validator.dart';
|
||||
import 'package:krow/core/application/di/injectable.dart';
|
||||
import 'package:krow/core/sevices/auth_state_service/auth_service.dart';
|
||||
|
||||
part 'auth_event.dart';
|
||||
|
||||
part 'auth_state.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
String? phone;
|
||||
int? resendToken;
|
||||
String? verificationId;
|
||||
|
||||
AuthBloc() : super(AuthState()) {
|
||||
on<AuthTypeChangedEvent>(_onTypeChanged);
|
||||
on<AuthSendSmsEvent>(_onSendSms);
|
||||
on<AuthSendSmsToPhoneEvent>(_onSendSmsToCurrentPhone);
|
||||
on<AuthPhoneChangedEvent>(_onPhoneChanged);
|
||||
on<PhoneVerificationCompletedEvent>(_onPhoneVerificationCompleted);
|
||||
on<PhoneVerificationFailedEvent>(_onPhoneVerificationFailed);
|
||||
on<CodeSentEvent>(_onCodeSent);
|
||||
on<CodeAutoRetrievalTimeoutEvent>(_onCodeAutoRetrievalTimeout);
|
||||
on<AuthEventResendUpdateTimer>(_onUpdateTimer);
|
||||
on<AuthEventConfirmCode>(_onConfirmCode);
|
||||
on<SignInWithInitialLink>(_onSignInWithInitialLink);
|
||||
}
|
||||
|
||||
FutureOr<void> _onTypeChanged(
|
||||
AuthTypeChangedEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
emit(state.copyWith(authType: event.authType));
|
||||
}
|
||||
|
||||
FutureOr<void> _onPhoneChanged(
|
||||
AuthPhoneChangedEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
emit(state.copyWith(phoneError: null));
|
||||
}
|
||||
|
||||
Future<void> _handleSendingSmsToPhoneNumber(
|
||||
String? phone,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
if (state.resendTimeout > 0) return;
|
||||
|
||||
if (phone != null) {
|
||||
var phoneValidationResult = PhoneValidator.validate(phone);
|
||||
if (phoneValidationResult != null) {
|
||||
return emit(state.copyWith(phoneError: phoneValidationResult));
|
||||
}
|
||||
|
||||
resendToken = null;
|
||||
verificationId = null;
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
emit(state.copyWith(isLoading: true));
|
||||
|
||||
try {
|
||||
await _auth.verifyPhoneNumber(
|
||||
forceResendingToken: resendToken,
|
||||
phoneNumber: phone,
|
||||
verificationCompleted: (PhoneAuthCredential credential) {
|
||||
add(PhoneVerificationCompletedEvent(credential));
|
||||
},
|
||||
verificationFailed: (FirebaseAuthException e) {
|
||||
add(PhoneVerificationFailedEvent(e.message));
|
||||
},
|
||||
codeSent: (String verificationId, int? resendToken) {
|
||||
this.verificationId = verificationId;
|
||||
this.resendToken = resendToken;
|
||||
add(CodeSentEvent(verificationId, resendToken));
|
||||
},
|
||||
codeAutoRetrievalTimeout: (String verificationId) {
|
||||
if (isClosed) return;
|
||||
add(CodeAutoRetrievalTimeoutEvent(verificationId));
|
||||
},
|
||||
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
phoneError: 'Invalid phone number'.tr(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSendSms(
|
||||
AuthSendSmsEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
return _handleSendingSmsToPhoneNumber(event.phone, emit);
|
||||
}
|
||||
|
||||
FutureOr<void> _onSendSmsToCurrentPhone(
|
||||
AuthSendSmsToPhoneEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
return _handleSendingSmsToPhoneNumber(
|
||||
phone = event.userPhone,
|
||||
emit,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onConfirmCode(
|
||||
AuthEventConfirmCode event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
|
||||
PhoneAuthCredential credential = PhoneAuthProvider.credential(
|
||||
verificationId: verificationId ?? '',
|
||||
smsCode: event.smsCode,
|
||||
);
|
||||
|
||||
add(PhoneVerificationCompletedEvent(credential));
|
||||
}
|
||||
|
||||
FutureOr<void> _onUpdateTimer(
|
||||
AuthEventResendUpdateTimer event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
emit(state.copyWith(
|
||||
resendTimeout: event.seconds, codeError: state.codeError));
|
||||
}
|
||||
|
||||
FutureOr<void> _onPhoneVerificationCompleted(
|
||||
PhoneVerificationCompletedEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
try {
|
||||
await _auth.signInWithCredential(event.credential);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
autentificated: true,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
codeError: 'Invalid code'.tr(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onPhoneVerificationFailed(
|
||||
PhoneVerificationFailedEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
phoneError: event.error,
|
||||
));
|
||||
}
|
||||
|
||||
FutureOr<void> _onCodeSent(
|
||||
CodeSentEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
needNavigateToCodeVerification: true,
|
||||
resendTimeout: 30,
|
||||
),
|
||||
);
|
||||
_startRetryTimer();
|
||||
}
|
||||
|
||||
FutureOr<void> _onCodeAutoRetrievalTimeout(
|
||||
CodeAutoRetrievalTimeoutEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) {}
|
||||
|
||||
void _startRetryTimer() {
|
||||
var current = 30;
|
||||
Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (current <= 0) {
|
||||
timer.cancel();
|
||||
} else {
|
||||
current--;
|
||||
if (isClosed) {
|
||||
timer.cancel();
|
||||
return;
|
||||
}
|
||||
add(AuthEventResendUpdateTimer(current));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FutureOr<void> _onSignInWithInitialLink(
|
||||
SignInWithInitialLink event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
try {
|
||||
await getIt<AuthService>().signInWithEmailLink(link: event.initialLink);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
autentificated: true,
|
||||
),
|
||||
);
|
||||
} catch (except) {
|
||||
log('Failed to authenticate with Initial Link', error: except);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
@immutable
|
||||
sealed class AuthEvent {
|
||||
const AuthEvent();
|
||||
}
|
||||
|
||||
class AuthTypeChangedEvent extends AuthEvent {
|
||||
final AuthType authType;
|
||||
|
||||
const AuthTypeChangedEvent(this.authType);
|
||||
}
|
||||
|
||||
class AuthPhoneChangedEvent extends AuthEvent {
|
||||
const AuthPhoneChangedEvent();
|
||||
}
|
||||
|
||||
class AuthSendSmsEvent extends AuthEvent {
|
||||
final String? phone;
|
||||
|
||||
const AuthSendSmsEvent(this.phone);
|
||||
}
|
||||
|
||||
class AuthSendSmsToPhoneEvent extends AuthEvent {
|
||||
const AuthSendSmsToPhoneEvent(this.userPhone);
|
||||
|
||||
final String userPhone;
|
||||
}
|
||||
|
||||
class PhoneVerificationCompletedEvent extends AuthEvent {
|
||||
final PhoneAuthCredential credential;
|
||||
|
||||
const PhoneVerificationCompletedEvent(this.credential);
|
||||
}
|
||||
|
||||
class PhoneVerificationFailedEvent extends AuthEvent {
|
||||
final String? error;
|
||||
|
||||
const PhoneVerificationFailedEvent(this.error);
|
||||
}
|
||||
|
||||
class CodeSentEvent extends AuthEvent {
|
||||
final String verificationId;
|
||||
final int? resendToken;
|
||||
|
||||
const CodeSentEvent(this.verificationId, this.resendToken);
|
||||
}
|
||||
|
||||
class CodeAutoRetrievalTimeoutEvent extends AuthEvent {
|
||||
final String verificationId;
|
||||
|
||||
const CodeAutoRetrievalTimeoutEvent(this.verificationId);
|
||||
}
|
||||
|
||||
class AuthEventResendUpdateTimer extends AuthEvent {
|
||||
final int seconds;
|
||||
|
||||
const AuthEventResendUpdateTimer(this.seconds);
|
||||
}
|
||||
|
||||
class AuthEventConfirmCode extends AuthEvent {
|
||||
final String smsCode;
|
||||
|
||||
const AuthEventConfirmCode(this.smsCode);
|
||||
}
|
||||
|
||||
class SignInWithInitialLink extends AuthEvent {
|
||||
const SignInWithInitialLink({required this.initialLink});
|
||||
|
||||
final Uri initialLink;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
enum AuthType { login, register }
|
||||
|
||||
class AuthState {
|
||||
final AuthType? authType;
|
||||
final String? phoneError;
|
||||
String? codeError;
|
||||
final bool needClearPhone;
|
||||
final bool needNavigateToCodeVerification;
|
||||
final bool isLoading;
|
||||
final bool autentificated;
|
||||
final int resendTimeout;
|
||||
|
||||
AuthState({
|
||||
this.phoneError,
|
||||
this.codeError,
|
||||
this.needClearPhone = false,
|
||||
this.needNavigateToCodeVerification = false,
|
||||
this.isLoading = false,
|
||||
this.authType,
|
||||
this.autentificated = false,
|
||||
this.resendTimeout = 0,
|
||||
});
|
||||
|
||||
AuthState copyWith({
|
||||
AuthType? authType,
|
||||
String? phoneError,
|
||||
String? codeError,
|
||||
bool? needClearPhone,
|
||||
bool? needNavigateToCodeVerification,
|
||||
bool? isLoading,
|
||||
bool? autentificated,
|
||||
int? resendTimeout,
|
||||
}) {
|
||||
return AuthState(
|
||||
authType: authType ?? this.authType,
|
||||
phoneError: phoneError,
|
||||
codeError: codeError,
|
||||
needClearPhone: needClearPhone ?? false,
|
||||
needNavigateToCodeVerification: needNavigateToCodeVerification ?? false,
|
||||
isLoading: isLoading ?? false,
|
||||
autentificated: autentificated ?? false,
|
||||
resendTimeout: resendTimeout ?? this.resendTimeout,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user