Initial commit
This commit is contained in:
116
lib/features/auth/presentation/bloc/auth/auth_bloc.dart
Normal file
116
lib/features/auth/presentation/bloc/auth/auth_bloc.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
import 'package:cargocalculaterapp/core/local_source/local_source.dart';
|
||||
import 'package:cargocalculaterapp/generated/l10n.dart';
|
||||
import 'package:cargocalculaterapp/router/app_routes.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../../constants/constants.dart';
|
||||
import '../../../../../injector_container.dart';
|
||||
import '../../../../../router/name_routes.dart';
|
||||
import '../../../data/model/login_request.dart';
|
||||
import '../../../domain/usecases/login_usecase.dart';
|
||||
import '../../pages/auth_confirm/argument/auth_confirm_argument.dart';
|
||||
|
||||
part 'auth_event.dart';
|
||||
|
||||
part 'auth_state.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
AuthBloc(this.loginUseCase)
|
||||
: super(
|
||||
const AuthState(
|
||||
passwordHidden: true,
|
||||
isLoading: false,
|
||||
isButtonEnabled: false,
|
||||
),
|
||||
) {
|
||||
on<PasswordVisibilityEvent>(_showHidePassword);
|
||||
on<OnInputEnterEvent>(_onInputEnter);
|
||||
on<SubmitEvent>(_onSubmit);
|
||||
}
|
||||
|
||||
final LoginUseCase loginUseCase;
|
||||
|
||||
void _showHidePassword(
|
||||
PasswordVisibilityEvent event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
emit(state.copyWith(passwordHidden: !state.passwordHidden));
|
||||
}
|
||||
|
||||
void _onInputEnter(OnInputEnterEvent event, Emitter<AuthState> emit) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isButtonEnabled:
|
||||
(isEmail(event.login) || isPhoneNumber(event.login)) &&
|
||||
event.password.isNotEmpty,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSubmit(SubmitEvent event, Emitter<AuthState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final response = await loginUseCase(
|
||||
LoginRequest(
|
||||
email: isEmail(event.login) ? event.login : "",
|
||||
phone: isPhoneNumber(event.login)
|
||||
? event.login.replaceAll("+", "")
|
||||
: "",
|
||||
ucode: event.password,
|
||||
),
|
||||
);
|
||||
response.fold(
|
||||
(l) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
showErrorSnackBar();
|
||||
},
|
||||
(r) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
sl<LocalSource>().setUCode(event.password);
|
||||
Navigator.pushNamed(
|
||||
rootNavigatorKey.currentContext!,
|
||||
Routes.authConfirm,
|
||||
arguments: AuthConfirmArgument(
|
||||
fullName: "",
|
||||
mail: isEmail(event.login) ? event.login : "",
|
||||
phoneNumber: isPhoneNumber(event.login) ? event.login : "",
|
||||
fromLoginPage: true,
|
||||
password: event.password,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isEmail(String input) {
|
||||
return RegExConst.emailRegex.hasMatch(input);
|
||||
}
|
||||
|
||||
bool isPhoneNumber(String input) {
|
||||
return RegExConst.phoneRegex.hasMatch(input);
|
||||
}
|
||||
|
||||
void showErrorSnackBar() {
|
||||
final snackBar = SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Row(
|
||||
children: [
|
||||
const Icon(Icons.error, color: Colors.white),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
AppLocalization.current.login_error,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
duration: const Duration(seconds: 3),
|
||||
);
|
||||
|
||||
ScaffoldMessenger.of(
|
||||
rootNavigatorKey.currentContext!,
|
||||
).showSnackBar(snackBar);
|
||||
}
|
||||
}
|
||||
32
lib/features/auth/presentation/bloc/auth/auth_event.dart
Normal file
32
lib/features/auth/presentation/bloc/auth/auth_event.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
sealed class AuthEvent extends Equatable {
|
||||
const AuthEvent();
|
||||
}
|
||||
|
||||
final class PasswordVisibilityEvent extends AuthEvent {
|
||||
const PasswordVisibilityEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
final class OnInputEnterEvent extends AuthEvent {
|
||||
final String login;
|
||||
final String password;
|
||||
|
||||
const OnInputEnterEvent({required this.login, required this.password});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [login, password];
|
||||
}
|
||||
|
||||
final class SubmitEvent extends AuthEvent {
|
||||
final String login;
|
||||
final String password;
|
||||
|
||||
const SubmitEvent({required this.login, required this.password});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [login, password];
|
||||
}
|
||||
28
lib/features/auth/presentation/bloc/auth/auth_state.dart
Normal file
28
lib/features/auth/presentation/bloc/auth/auth_state.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
class AuthState extends Equatable {
|
||||
const AuthState({
|
||||
required this.passwordHidden,
|
||||
required this.isLoading,
|
||||
required this.isButtonEnabled,
|
||||
});
|
||||
|
||||
final bool passwordHidden;
|
||||
final bool isLoading;
|
||||
final bool isButtonEnabled;
|
||||
|
||||
AuthState copyWith({
|
||||
bool? passwordHidden,
|
||||
bool? isLoading,
|
||||
bool? isButtonEnabled,
|
||||
}) {
|
||||
return AuthState(
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
passwordHidden: passwordHidden ?? this.passwordHidden,
|
||||
isButtonEnabled: isButtonEnabled ?? this.isButtonEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [passwordHidden, isLoading, isButtonEnabled];
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../../core/error/failure.dart';
|
||||
import '../../../../../core/functions/base_finctions.dart';
|
||||
import '../../../../../core/local_source/local_source.dart';
|
||||
import '../../../../../injector_container.dart';
|
||||
import '../../../../../service/notification_service.dart';
|
||||
import '../../../data/model/auth_verification_request.dart';
|
||||
import '../../../data/model/fcm_add_request.dart';
|
||||
import '../../../data/model/login_request.dart';
|
||||
import '../../../data/model/sign_up_request.dart';
|
||||
import '../../../domain/usecases/fcm_add_usecase.dart';
|
||||
import '../../../domain/usecases/login_usecase.dart';
|
||||
import '../../../domain/usecases/sign_up_usecase.dart';
|
||||
import '../../../domain/usecases/verify_phone_usecase.dart';
|
||||
import '../../pages/auth_confirm/argument/auth_confirm_argument.dart';
|
||||
|
||||
part 'auth_confirm_event.dart';
|
||||
|
||||
part 'auth_confirm_state.dart';
|
||||
|
||||
class AuthConfirmBloc extends Bloc<AuthConfirmEvent, AuthConfirmState> {
|
||||
AuthConfirmBloc(
|
||||
this.signUpUseCase,
|
||||
this.verifyPhoneUseCase,
|
||||
this.loginUseCase,
|
||||
this.fcmAddUseCase,
|
||||
) : super(const InitialState(true)) {
|
||||
on<TimerChangedEvent>(_timerChanged);
|
||||
on<SmsCodeEnterEvent>(_codeChanged);
|
||||
on<ResendCodeEvent>(_resendCode);
|
||||
on<OnSubmitEvent>(_onSubmitCode);
|
||||
}
|
||||
|
||||
final SignUpUseCase signUpUseCase;
|
||||
final VerifyPhoneUseCase verifyPhoneUseCase;
|
||||
final LoginUseCase loginUseCase;
|
||||
final FcmAddUseCase fcmAddUseCase;
|
||||
|
||||
Future<void> _timerChanged(
|
||||
TimerChangedEvent event,
|
||||
Emitter<AuthConfirmState> emit,
|
||||
) async {
|
||||
emit(InitialState(event.isVisible));
|
||||
}
|
||||
|
||||
void _codeChanged(SmsCodeEnterEvent event, Emitter<AuthConfirmState> emit) {
|
||||
if (event.code.length == 4) {
|
||||
emit(ButtonEnableState(state.isTimerVisible, event.code));
|
||||
} else {
|
||||
emit(InitialState(state.isTimerVisible));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _resendCode(
|
||||
ResendCodeEvent event,
|
||||
Emitter<AuthConfirmState> emit,
|
||||
) async {
|
||||
add(const TimerChangedEvent(isVisible: true));
|
||||
if (event.argument.fromLoginPage) {
|
||||
await loginUseCase(
|
||||
LoginRequest(
|
||||
email: event.argument.mail,
|
||||
phone: event.argument.phoneNumber?.replaceAll("+", ""),
|
||||
ucode: event.argument.password,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
await signUpUseCase(
|
||||
SignUpRequest(
|
||||
fullname: event.argument.fullName,
|
||||
email: event.argument.mail,
|
||||
phoneNumber: event.argument.phoneNumber?.replaceAll("+", ""),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSubmitCode(
|
||||
OnSubmitEvent event,
|
||||
Emitter<AuthConfirmState> emit,
|
||||
) async {
|
||||
emit(LoadingState(state.isTimerVisible));
|
||||
final response = await verifyPhoneUseCase(
|
||||
AuthVerificationRequest(
|
||||
phoneNumber: event.argument?.phoneNumber?.replaceAll("+", ""),
|
||||
smsCode: event.code,
|
||||
email: event.argument?.mail ?? "",
|
||||
),
|
||||
);
|
||||
await response.fold(
|
||||
(l) {
|
||||
if (l is ServerFailure) {
|
||||
Functions.showErrorSnackBar(l.message);
|
||||
}
|
||||
emit(InitialState(state.isTimerVisible));
|
||||
},
|
||||
(r) async {
|
||||
sl<LocalSource>().setHasProfile(true);
|
||||
sl<LocalSource>().setAccessToken(r.accessToken ?? "");
|
||||
await _addFcmToken();
|
||||
emit(SuccessSate(state.isTimerVisible));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _addFcmToken() async {
|
||||
final String fcmToken = await NotificationService.getFcmToken();
|
||||
await fcmAddUseCase(FcmAddRequest(sfmToken: fcmToken));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
part of 'auth_confirm_bloc.dart';
|
||||
|
||||
sealed class AuthConfirmEvent extends Equatable {
|
||||
const AuthConfirmEvent();
|
||||
}
|
||||
|
||||
final class SmsCodeEnterEvent extends AuthConfirmEvent {
|
||||
final String code;
|
||||
|
||||
const SmsCodeEnterEvent(this.code);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [code];
|
||||
}
|
||||
|
||||
final class TimerChangedEvent extends AuthConfirmEvent {
|
||||
final bool isVisible;
|
||||
|
||||
const TimerChangedEvent({required this.isVisible});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [isVisible];
|
||||
}
|
||||
|
||||
final class OnSubmitEvent extends AuthConfirmEvent {
|
||||
final String code;
|
||||
final AuthConfirmArgument? argument;
|
||||
|
||||
const OnSubmitEvent({required this.code, required this.argument});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [code, argument];
|
||||
}
|
||||
|
||||
final class ResendCodeEvent extends AuthConfirmEvent {
|
||||
final AuthConfirmArgument argument;
|
||||
|
||||
const ResendCodeEvent({required this.argument});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [argument];
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
part of 'auth_confirm_bloc.dart';
|
||||
|
||||
sealed class AuthConfirmState extends Equatable {
|
||||
const AuthConfirmState(this.isTimerVisible);
|
||||
|
||||
final bool isTimerVisible;
|
||||
}
|
||||
|
||||
class InitialState extends AuthConfirmState {
|
||||
const InitialState(super.isTimerVisible);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [super.isTimerVisible];
|
||||
}
|
||||
|
||||
class LoadingState extends AuthConfirmState {
|
||||
const LoadingState(super.isTimerVisible);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [super.isTimerVisible];
|
||||
}
|
||||
|
||||
class SuccessSate extends AuthConfirmState {
|
||||
const SuccessSate(super.isTimerVisible);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [super.isTimerVisible];
|
||||
}
|
||||
|
||||
class ErrorState extends AuthConfirmState {
|
||||
const ErrorState(super.isTimerVisible);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [super.isTimerVisible];
|
||||
}
|
||||
|
||||
class ButtonEnableState extends AuthConfirmState {
|
||||
const ButtonEnableState(super.isTimerVisible, this.code);
|
||||
|
||||
final String code;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [super.isTimerVisible, code];
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import 'package:cargocalculaterapp/core/local_source/local_source.dart';
|
||||
import 'package:cargocalculaterapp/generated/l10n.dart';
|
||||
import 'package:cargocalculaterapp/router/app_routes.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../../constants/constants.dart';
|
||||
import '../../../../../core/error/failure.dart';
|
||||
import '../../../../../core/functions/base_finctions.dart';
|
||||
import '../../../../../injector_container.dart';
|
||||
import '../../../../../router/name_routes.dart';
|
||||
import '../../../data/model/sign_up_request.dart';
|
||||
import '../../../domain/usecases/sign_up_usecase.dart';
|
||||
import '../../pages/auth_confirm/argument/auth_confirm_argument.dart';
|
||||
|
||||
part 'sign_up_event.dart';
|
||||
|
||||
part 'sign_up_state.dart';
|
||||
|
||||
class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
|
||||
SignUpBloc(this.signUpUseCase)
|
||||
: super(
|
||||
const SignUpState(
|
||||
isLoading: false,
|
||||
isButtonEnabled: false,
|
||||
passwordHidden: true,
|
||||
),
|
||||
) {
|
||||
on<PasswordVisibilityEvent>(_passwordVisibility);
|
||||
on<OnInputEnterEvent>(_onDataEnter);
|
||||
on<SubmitEvent>(_signUp);
|
||||
}
|
||||
|
||||
final SignUpUseCase signUpUseCase;
|
||||
|
||||
void _passwordVisibility(
|
||||
PasswordVisibilityEvent event,
|
||||
Emitter<SignUpState> emit,
|
||||
) {
|
||||
emit(state.copyWith(isButtonEnabled: !state.isButtonEnabled));
|
||||
}
|
||||
|
||||
void _onDataEnter(OnInputEnterEvent event, Emitter<SignUpState> emit) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isButtonEnabled:
|
||||
(isEmail(event.login) || isPhoneNumber(event.login)) &&
|
||||
event.fullName.isNotEmpty,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool isEmail(String input) {
|
||||
return RegExConst.emailRegex.hasMatch(input);
|
||||
}
|
||||
|
||||
bool isPhoneNumber(String input) {
|
||||
return RegExConst.phoneRegex.hasMatch(input);
|
||||
}
|
||||
|
||||
Future<void> _signUp(SubmitEvent event, Emitter<SignUpState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final response = await signUpUseCase(
|
||||
SignUpRequest(
|
||||
fullname: event.fullName,
|
||||
email: isEmail(event.login) ? event.login : "",
|
||||
phoneNumber: isPhoneNumber(event.login)
|
||||
? event.login.replaceAll("+", "")
|
||||
: "",
|
||||
),
|
||||
);
|
||||
response.fold(
|
||||
(l) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
if (l is ServerFailure) {
|
||||
Functions.showErrorSnackBar(AppLocalization.current.phone_registered);
|
||||
}
|
||||
},
|
||||
(r) {
|
||||
sl<LocalSource>().setAccessToken(r.token ?? "");
|
||||
emit(state.copyWith(isLoading: false));
|
||||
Navigator.pushNamed(
|
||||
rootNavigatorKey.currentContext!,
|
||||
Routes.authConfirm,
|
||||
arguments: AuthConfirmArgument(
|
||||
fullName: event.fullName,
|
||||
mail: isEmail(event.login) ? event.login : "",
|
||||
phoneNumber: isPhoneNumber(event.login) ? event.login : "",
|
||||
fromLoginPage: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
part of 'sign_up_bloc.dart';
|
||||
|
||||
sealed class SignUpEvent extends Equatable {
|
||||
const SignUpEvent();
|
||||
}
|
||||
|
||||
final class PasswordVisibilityEvent extends SignUpEvent {
|
||||
const PasswordVisibilityEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
final class OnInputEnterEvent extends SignUpEvent {
|
||||
final String login;
|
||||
final String fullName;
|
||||
|
||||
const OnInputEnterEvent({required this.login, required this.fullName});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [login, fullName];
|
||||
}
|
||||
|
||||
final class SubmitEvent extends SignUpEvent {
|
||||
final String login;
|
||||
final String fullName;
|
||||
|
||||
const SubmitEvent({required this.login, required this.fullName});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [login, fullName];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
part of 'sign_up_bloc.dart';
|
||||
|
||||
class SignUpState extends Equatable {
|
||||
const SignUpState({
|
||||
required this.passwordHidden,
|
||||
required this.isLoading,
|
||||
required this.isButtonEnabled,
|
||||
});
|
||||
|
||||
final bool passwordHidden;
|
||||
final bool isLoading;
|
||||
final bool isButtonEnabled;
|
||||
|
||||
SignUpState copyWith({
|
||||
bool? passwordHidden,
|
||||
bool? isLoading,
|
||||
bool? isButtonEnabled,
|
||||
}) {
|
||||
return SignUpState(
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
passwordHidden: passwordHidden ?? this.passwordHidden,
|
||||
isButtonEnabled: isButtonEnabled ?? this.isButtonEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [passwordHidden, isLoading, isButtonEnabled];
|
||||
}
|
||||
Reference in New Issue
Block a user