From 59062f9af1613146b271e0f94330230476b46889 Mon Sep 17 00:00:00 2001 From: efrilm Date: Fri, 24 Oct 2025 02:02:00 +0700 Subject: [PATCH] auth state --- lib/application/auth/auth_bloc.dart | 49 ++ lib/application/auth/auth_bloc.freezed.dart | 806 ++++++++++++++++++ lib/application/auth/auth_event.dart | 6 + lib/application/auth/auth_state.dart | 26 + .../auth/repositories/i_auth_repository.dart | 2 + .../auth/repositories/auth_repository.dart | 16 + .../pages/splash/splash_page.dart | 34 +- 7 files changed, 930 insertions(+), 9 deletions(-) create mode 100644 lib/application/auth/auth_bloc.dart create mode 100644 lib/application/auth/auth_bloc.freezed.dart create mode 100644 lib/application/auth/auth_event.dart create mode 100644 lib/application/auth/auth_state.dart diff --git a/lib/application/auth/auth_bloc.dart b/lib/application/auth/auth_bloc.dart new file mode 100644 index 0000000..0ca87c5 --- /dev/null +++ b/lib/application/auth/auth_bloc.dart @@ -0,0 +1,49 @@ +import 'package:dartz/dartz.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:injectable/injectable.dart'; + +import '../../domain/auth/auth.dart'; + +part 'auth_event.dart'; +part 'auth_state.dart'; +part 'auth_bloc.freezed.dart'; + +@injectable +class AuthBloc extends Bloc { + final IAuthRepository _repository; + AuthBloc(this._repository) : super(AuthState.initial()) { + on(_onAuthEvent); + } + + Future _onAuthEvent(AuthEvent event, Emitter emit) { + return event.map( + fetchCurrentUser: (e) async { + emit(state.copyWith(failureOption: none())); + + final token = await _repository.hasToken(); + + final failureOrAuth = await _repository.currentUser(); + + failureOrAuth.fold( + (f) => emit( + state.copyWith( + failureOption: optionOf(f), + status: token + ? AuthStatus.authenticated() + : AuthStatus.unauthenticated(), + ), + ), + (user) => emit( + state.copyWith( + user: user, + status: token + ? AuthStatus.authenticated() + : AuthStatus.unauthenticated(), + ), + ), + ); + }, + ); + } +} diff --git a/lib/application/auth/auth_bloc.freezed.dart b/lib/application/auth/auth_bloc.freezed.dart new file mode 100644 index 0000000..7fd3e02 --- /dev/null +++ b/lib/application/auth/auth_bloc.freezed.dart @@ -0,0 +1,806 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +/// @nodoc +mixin _$AuthEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() fetchCurrentUser, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? fetchCurrentUser, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? fetchCurrentUser, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_FetchCurrentUser value) fetchCurrentUser, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_FetchCurrentUser value)? fetchCurrentUser, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_FetchCurrentUser value)? fetchCurrentUser, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthEventCopyWith<$Res> { + factory $AuthEventCopyWith(AuthEvent value, $Res Function(AuthEvent) then) = + _$AuthEventCopyWithImpl<$Res, AuthEvent>; +} + +/// @nodoc +class _$AuthEventCopyWithImpl<$Res, $Val extends AuthEvent> + implements $AuthEventCopyWith<$Res> { + _$AuthEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$FetchCurrentUserImplCopyWith<$Res> { + factory _$$FetchCurrentUserImplCopyWith( + _$FetchCurrentUserImpl value, + $Res Function(_$FetchCurrentUserImpl) then, + ) = __$$FetchCurrentUserImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$FetchCurrentUserImplCopyWithImpl<$Res> + extends _$AuthEventCopyWithImpl<$Res, _$FetchCurrentUserImpl> + implements _$$FetchCurrentUserImplCopyWith<$Res> { + __$$FetchCurrentUserImplCopyWithImpl( + _$FetchCurrentUserImpl _value, + $Res Function(_$FetchCurrentUserImpl) _then, + ) : super(_value, _then); + + /// Create a copy of AuthEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$FetchCurrentUserImpl implements _FetchCurrentUser { + const _$FetchCurrentUserImpl(); + + @override + String toString() { + return 'AuthEvent.fetchCurrentUser()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$FetchCurrentUserImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() fetchCurrentUser, + }) { + return fetchCurrentUser(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? fetchCurrentUser, + }) { + return fetchCurrentUser?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? fetchCurrentUser, + required TResult orElse(), + }) { + if (fetchCurrentUser != null) { + return fetchCurrentUser(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_FetchCurrentUser value) fetchCurrentUser, + }) { + return fetchCurrentUser(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_FetchCurrentUser value)? fetchCurrentUser, + }) { + return fetchCurrentUser?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_FetchCurrentUser value)? fetchCurrentUser, + required TResult orElse(), + }) { + if (fetchCurrentUser != null) { + return fetchCurrentUser(this); + } + return orElse(); + } +} + +abstract class _FetchCurrentUser implements AuthEvent { + const factory _FetchCurrentUser() = _$FetchCurrentUserImpl; +} + +/// @nodoc +mixin _$AuthState { + User get user => throw _privateConstructorUsedError; + AuthStatus get status => throw _privateConstructorUsedError; + Option get failureOption => throw _privateConstructorUsedError; + bool get isFetching => throw _privateConstructorUsedError; + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthStateCopyWith<$Res> { + factory $AuthStateCopyWith(AuthState value, $Res Function(AuthState) then) = + _$AuthStateCopyWithImpl<$Res, AuthState>; + @useResult + $Res call({ + User user, + AuthStatus status, + Option failureOption, + bool isFetching, + }); + + $UserCopyWith<$Res> get user; + $AuthStatusCopyWith<$Res> get status; +} + +/// @nodoc +class _$AuthStateCopyWithImpl<$Res, $Val extends AuthState> + implements $AuthStateCopyWith<$Res> { + _$AuthStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? user = null, + Object? status = null, + Object? failureOption = null, + Object? isFetching = null, + }) { + return _then( + _value.copyWith( + user: null == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as User, + status: null == status + ? _value.status + : status // ignore: cast_nullable_to_non_nullable + as AuthStatus, + failureOption: null == failureOption + ? _value.failureOption + : failureOption // ignore: cast_nullable_to_non_nullable + as Option, + isFetching: null == isFetching + ? _value.isFetching + : isFetching // ignore: cast_nullable_to_non_nullable + as bool, + ) + as $Val, + ); + } + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $UserCopyWith<$Res> get user { + return $UserCopyWith<$Res>(_value.user, (value) { + return _then(_value.copyWith(user: value) as $Val); + }); + } + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthStatusCopyWith<$Res> get status { + return $AuthStatusCopyWith<$Res>(_value.status, (value) { + return _then(_value.copyWith(status: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$AuthStateImplCopyWith<$Res> + implements $AuthStateCopyWith<$Res> { + factory _$$AuthStateImplCopyWith( + _$AuthStateImpl value, + $Res Function(_$AuthStateImpl) then, + ) = __$$AuthStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + User user, + AuthStatus status, + Option failureOption, + bool isFetching, + }); + + @override + $UserCopyWith<$Res> get user; + @override + $AuthStatusCopyWith<$Res> get status; +} + +/// @nodoc +class __$$AuthStateImplCopyWithImpl<$Res> + extends _$AuthStateCopyWithImpl<$Res, _$AuthStateImpl> + implements _$$AuthStateImplCopyWith<$Res> { + __$$AuthStateImplCopyWithImpl( + _$AuthStateImpl _value, + $Res Function(_$AuthStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? user = null, + Object? status = null, + Object? failureOption = null, + Object? isFetching = null, + }) { + return _then( + _$AuthStateImpl( + user: null == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as User, + status: null == status + ? _value.status + : status // ignore: cast_nullable_to_non_nullable + as AuthStatus, + failureOption: null == failureOption + ? _value.failureOption + : failureOption // ignore: cast_nullable_to_non_nullable + as Option, + isFetching: null == isFetching + ? _value.isFetching + : isFetching // ignore: cast_nullable_to_non_nullable + as bool, + ), + ); + } +} + +/// @nodoc + +class _$AuthStateImpl extends _AuthState { + const _$AuthStateImpl({ + required this.user, + this.status = const AuthStatus.initial(), + required this.failureOption, + this.isFetching = false, + }) : super._(); + + @override + final User user; + @override + @JsonKey() + final AuthStatus status; + @override + final Option failureOption; + @override + @JsonKey() + final bool isFetching; + + @override + String toString() { + return 'AuthState(user: $user, status: $status, failureOption: $failureOption, isFetching: $isFetching)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthStateImpl && + (identical(other.user, user) || other.user == user) && + (identical(other.status, status) || other.status == status) && + (identical(other.failureOption, failureOption) || + other.failureOption == failureOption) && + (identical(other.isFetching, isFetching) || + other.isFetching == isFetching)); + } + + @override + int get hashCode => + Object.hash(runtimeType, user, status, failureOption, isFetching); + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthStateImplCopyWith<_$AuthStateImpl> get copyWith => + __$$AuthStateImplCopyWithImpl<_$AuthStateImpl>(this, _$identity); +} + +abstract class _AuthState extends AuthState { + const factory _AuthState({ + required final User user, + final AuthStatus status, + required final Option failureOption, + final bool isFetching, + }) = _$AuthStateImpl; + const _AuthState._() : super._(); + + @override + User get user; + @override + AuthStatus get status; + @override + Option get failureOption; + @override + bool get isFetching; + + /// Create a copy of AuthState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthStateImplCopyWith<_$AuthStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$AuthStatus { + @optionalTypeArgs + TResult when({ + required TResult Function() authenticated, + required TResult Function() unauthenticated, + required TResult Function() initial, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? authenticated, + TResult? Function()? unauthenticated, + TResult? Function()? initial, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? authenticated, + TResult Function()? unauthenticated, + TResult Function()? initial, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Authenticated value) authenticated, + required TResult Function(_Unauthenticated value) unauthenticated, + required TResult Function(_Initial value) initial, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Authenticated value)? authenticated, + TResult? Function(_Unauthenticated value)? unauthenticated, + TResult? Function(_Initial value)? initial, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Authenticated value)? authenticated, + TResult Function(_Unauthenticated value)? unauthenticated, + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthStatusCopyWith<$Res> { + factory $AuthStatusCopyWith( + AuthStatus value, + $Res Function(AuthStatus) then, + ) = _$AuthStatusCopyWithImpl<$Res, AuthStatus>; +} + +/// @nodoc +class _$AuthStatusCopyWithImpl<$Res, $Val extends AuthStatus> + implements $AuthStatusCopyWith<$Res> { + _$AuthStatusCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthStatus + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$AuthenticatedImplCopyWith<$Res> { + factory _$$AuthenticatedImplCopyWith( + _$AuthenticatedImpl value, + $Res Function(_$AuthenticatedImpl) then, + ) = __$$AuthenticatedImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$AuthenticatedImplCopyWithImpl<$Res> + extends _$AuthStatusCopyWithImpl<$Res, _$AuthenticatedImpl> + implements _$$AuthenticatedImplCopyWith<$Res> { + __$$AuthenticatedImplCopyWithImpl( + _$AuthenticatedImpl _value, + $Res Function(_$AuthenticatedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of AuthStatus + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$AuthenticatedImpl implements _Authenticated { + const _$AuthenticatedImpl(); + + @override + String toString() { + return 'AuthStatus.authenticated()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$AuthenticatedImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() authenticated, + required TResult Function() unauthenticated, + required TResult Function() initial, + }) { + return authenticated(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? authenticated, + TResult? Function()? unauthenticated, + TResult? Function()? initial, + }) { + return authenticated?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? authenticated, + TResult Function()? unauthenticated, + TResult Function()? initial, + required TResult orElse(), + }) { + if (authenticated != null) { + return authenticated(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Authenticated value) authenticated, + required TResult Function(_Unauthenticated value) unauthenticated, + required TResult Function(_Initial value) initial, + }) { + return authenticated(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Authenticated value)? authenticated, + TResult? Function(_Unauthenticated value)? unauthenticated, + TResult? Function(_Initial value)? initial, + }) { + return authenticated?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Authenticated value)? authenticated, + TResult Function(_Unauthenticated value)? unauthenticated, + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) { + if (authenticated != null) { + return authenticated(this); + } + return orElse(); + } +} + +abstract class _Authenticated implements AuthStatus { + const factory _Authenticated() = _$AuthenticatedImpl; +} + +/// @nodoc +abstract class _$$UnauthenticatedImplCopyWith<$Res> { + factory _$$UnauthenticatedImplCopyWith( + _$UnauthenticatedImpl value, + $Res Function(_$UnauthenticatedImpl) then, + ) = __$$UnauthenticatedImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$UnauthenticatedImplCopyWithImpl<$Res> + extends _$AuthStatusCopyWithImpl<$Res, _$UnauthenticatedImpl> + implements _$$UnauthenticatedImplCopyWith<$Res> { + __$$UnauthenticatedImplCopyWithImpl( + _$UnauthenticatedImpl _value, + $Res Function(_$UnauthenticatedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of AuthStatus + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$UnauthenticatedImpl implements _Unauthenticated { + const _$UnauthenticatedImpl(); + + @override + String toString() { + return 'AuthStatus.unauthenticated()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$UnauthenticatedImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() authenticated, + required TResult Function() unauthenticated, + required TResult Function() initial, + }) { + return unauthenticated(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? authenticated, + TResult? Function()? unauthenticated, + TResult? Function()? initial, + }) { + return unauthenticated?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? authenticated, + TResult Function()? unauthenticated, + TResult Function()? initial, + required TResult orElse(), + }) { + if (unauthenticated != null) { + return unauthenticated(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Authenticated value) authenticated, + required TResult Function(_Unauthenticated value) unauthenticated, + required TResult Function(_Initial value) initial, + }) { + return unauthenticated(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Authenticated value)? authenticated, + TResult? Function(_Unauthenticated value)? unauthenticated, + TResult? Function(_Initial value)? initial, + }) { + return unauthenticated?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Authenticated value)? authenticated, + TResult Function(_Unauthenticated value)? unauthenticated, + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) { + if (unauthenticated != null) { + return unauthenticated(this); + } + return orElse(); + } +} + +abstract class _Unauthenticated implements AuthStatus { + const factory _Unauthenticated() = _$UnauthenticatedImpl; +} + +/// @nodoc +abstract class _$$InitialImplCopyWith<$Res> { + factory _$$InitialImplCopyWith( + _$InitialImpl value, + $Res Function(_$InitialImpl) then, + ) = __$$InitialImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$InitialImplCopyWithImpl<$Res> + extends _$AuthStatusCopyWithImpl<$Res, _$InitialImpl> + implements _$$InitialImplCopyWith<$Res> { + __$$InitialImplCopyWithImpl( + _$InitialImpl _value, + $Res Function(_$InitialImpl) _then, + ) : super(_value, _then); + + /// Create a copy of AuthStatus + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$InitialImpl implements _Initial { + const _$InitialImpl(); + + @override + String toString() { + return 'AuthStatus.initial()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$InitialImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() authenticated, + required TResult Function() unauthenticated, + required TResult Function() initial, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? authenticated, + TResult? Function()? unauthenticated, + TResult? Function()? initial, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? authenticated, + TResult Function()? unauthenticated, + TResult Function()? initial, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Authenticated value) authenticated, + required TResult Function(_Unauthenticated value) unauthenticated, + required TResult Function(_Initial value) initial, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Authenticated value)? authenticated, + TResult? Function(_Unauthenticated value)? unauthenticated, + TResult? Function(_Initial value)? initial, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Authenticated value)? authenticated, + TResult Function(_Unauthenticated value)? unauthenticated, + TResult Function(_Initial value)? initial, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class _Initial implements AuthStatus { + const factory _Initial() = _$InitialImpl; +} diff --git a/lib/application/auth/auth_event.dart b/lib/application/auth/auth_event.dart new file mode 100644 index 0000000..6c3c293 --- /dev/null +++ b/lib/application/auth/auth_event.dart @@ -0,0 +1,6 @@ +part of 'auth_bloc.dart'; + +@freezed +class AuthEvent with _$AuthEvent { + const factory AuthEvent.fetchCurrentUser() = _FetchCurrentUser; +} diff --git a/lib/application/auth/auth_state.dart b/lib/application/auth/auth_state.dart new file mode 100644 index 0000000..483740d --- /dev/null +++ b/lib/application/auth/auth_state.dart @@ -0,0 +1,26 @@ +part of 'auth_bloc.dart'; + +@freezed +class AuthState with _$AuthState { + const AuthState._(); + + const factory AuthState({ + required User user, + @Default(AuthStatus.initial()) AuthStatus status, + required Option failureOption, + @Default(false) bool isFetching, + }) = _AuthState; + + factory AuthState.initial() => + AuthState(user: User.empty(), failureOption: none()); + + bool get isAuthenticated => status == const AuthStatus.authenticated(); + bool get isInitial => status == const AuthStatus.initial(); +} + +@freezed +sealed class AuthStatus with _$AuthStatus { + const factory AuthStatus.authenticated() = _Authenticated; + const factory AuthStatus.unauthenticated() = _Unauthenticated; + const factory AuthStatus.initial() = _Initial; +} diff --git a/lib/domain/auth/repositories/i_auth_repository.dart b/lib/domain/auth/repositories/i_auth_repository.dart index def4bcb..ebeeece 100644 --- a/lib/domain/auth/repositories/i_auth_repository.dart +++ b/lib/domain/auth/repositories/i_auth_repository.dart @@ -5,4 +5,6 @@ abstract class IAuthRepository { required String email, required String password, }); + Future hasToken(); + Future> currentUser(); } diff --git a/lib/infrastructure/auth/repositories/auth_repository.dart b/lib/infrastructure/auth/repositories/auth_repository.dart index fac3e27..93a21b7 100644 --- a/lib/infrastructure/auth/repositories/auth_repository.dart +++ b/lib/infrastructure/auth/repositories/auth_repository.dart @@ -41,4 +41,20 @@ class AuthRepository implements IAuthRepository { return left(const AuthFailure.unexpectedError()); } } + + @override + Future> currentUser() async { + try { + User user = await _localDataProvider.currentUser(); + return right(user); + } catch (e, s) { + log('currentUserError', name: _logName, error: e, stackTrace: s); + return left(const AuthFailure.unexpectedError()); + } + } + + @override + Future hasToken() async { + return await _localDataProvider.hasToken(); + } } diff --git a/lib/presentation/pages/splash/splash_page.dart b/lib/presentation/pages/splash/splash_page.dart index dd30f1b..e5e3e38 100644 --- a/lib/presentation/pages/splash/splash_page.dart +++ b/lib/presentation/pages/splash/splash_page.dart @@ -1,6 +1,8 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../application/auth/auth_bloc.dart'; import '../../components/assets/assets.gen.dart'; import '../../router/app_router.gr.dart'; @@ -15,7 +17,11 @@ class SplashPage extends StatefulWidget { class _SplashPageState extends State { _startDelay() => Future.delayed(const Duration(seconds: 2), _goNext); - _goNext() => context.router.replace(const LoginRoute()); + _goNext() { + if (mounted) { + context.read().add(const AuthEvent.fetchCurrentUser()); + } + } @override void initState() { @@ -25,14 +31,24 @@ class _SplashPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Padding( - padding: const EdgeInsets.all(20), - child: Assets.images.logo.image( - width: 100, - height: 100, - fit: BoxFit.contain, + return BlocListener( + listenWhen: (previous, current) => previous.status != current.status, + listener: (context, state) { + if (state.isAuthenticated) { + context.router.replace(const MainRoute()); + } else { + context.router.replace(const LoginRoute()); + } + }, + child: Scaffold( + body: Center( + child: Padding( + padding: const EdgeInsets.all(20), + child: Assets.images.logo.image( + width: 100, + height: 100, + fit: BoxFit.contain, + ), ), ), ),