master #81
@ -37,7 +37,7 @@ class ExampleAuthenticationCubit extends AuthenticationCubit<int> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) {
|
FutureOrResult<int?> onSignInFromCache(AuthenticationSession<int> session) {
|
||||||
print('onSignInFromCache');
|
print('onSignInFromCache');
|
||||||
|
|
||||||
return const Ok(1);
|
return const Ok(1);
|
||||||
|
@ -30,8 +30,7 @@ class HomePage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text('Home | ${context.watchAccount<int>()?.email}'),
|
||||||
'Home | ${context.account<AuthenticationCubit<int>, int>()?.email}'),
|
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
@ -44,8 +43,8 @@ class HomePage extends StatelessWidget {
|
|||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
AuthenticationBuilder<int>(
|
AuthenticationBuilder<int>(
|
||||||
authenticated: (context, sessionWrapper) => Text(
|
authenticated: (context, session) => Text(
|
||||||
'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'),
|
'Logged as ${session.account?.email} | GeneratedId is ${session.data}'),
|
||||||
unauthenticated: (context) =>
|
unauthenticated: (context) =>
|
||||||
const Text('Not logged (unauthenticated)'),
|
const Text('Not logged (unauthenticated)'),
|
||||||
unknown: (context) => const Text('Not logged (unknown)'),
|
unknown: (context) => const Text('Not logged (unknown)'),
|
||||||
|
@ -17,26 +17,82 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart';
|
import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart';
|
||||||
|
|
||||||
/// Extension that helps to quickly access useful resources like wrapper,
|
/// Extension that helps to quickly access useful resources like wrapper,
|
||||||
/// session, account or data.
|
/// session, account or data.
|
||||||
extension BuildContextExtension on BuildContext {
|
extension BuildContextExtension on BuildContext {
|
||||||
/// Returns session wrapper
|
/// Read session in context from a specific AuthenticationCubit type [T]
|
||||||
SessionWrapper<Data>? wrapper<T extends AuthenticationCubit<Data>, Data>() =>
|
AuthenticationSession<Data>?
|
||||||
watch<T>().currentSession();
|
readSessionFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
read<T>().currentSession();
|
||||||
|
|
||||||
/// Returns session
|
/// Watch session in context from a specific AuthenticationCubit type [T]
|
||||||
Session<Data>? session<T extends AuthenticationCubit<Data>, Data>() =>
|
AuthenticationSession<Data>?
|
||||||
watch<T>().currentSession()?.session;
|
watchSessionFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
watch<T>().currentSession();
|
||||||
|
|
||||||
/// Returns account
|
/// Read session in context from generic AuthenticationCubit type
|
||||||
Account? account<T extends AuthenticationCubit<Data>, Data>() =>
|
AuthenticationSession<Data>? readSession<Data>() =>
|
||||||
watch<T>().currentSession()?.session?.account;
|
read<AuthenticationCubit<Data>>().currentSession();
|
||||||
|
|
||||||
/// Returns associated data
|
/// Watch session in context from generic AuthenticationCubit type
|
||||||
Data? data<T extends AuthenticationCubit<Data>, Data>() =>
|
AuthenticationSession<Data>? watchSession<Data>() =>
|
||||||
watch<T>().currentSession()?.session?.data;
|
watch<AuthenticationCubit<Data>>().currentSession();
|
||||||
|
|
||||||
|
/// Read event in context from a specific AuthenticationCubit type [T]
|
||||||
|
AuthenticationChangeEvent?
|
||||||
|
readEventFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
readSessionFrom<T, Data>()?.latestEvent;
|
||||||
|
|
||||||
|
/// Watch event in context from a specific AuthenticationCubit type [T]
|
||||||
|
AuthenticationChangeEvent?
|
||||||
|
watchEventFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
watchSessionFrom<T, Data>()?.latestEvent;
|
||||||
|
|
||||||
|
/// Read event in context from generic AuthenticationCubit type
|
||||||
|
AuthenticationChangeEvent? readEvent<Data>() =>
|
||||||
|
readSession<Data>()?.latestEvent;
|
||||||
|
|
||||||
|
/// Watch event in context from generic AuthenticationCubit type
|
||||||
|
AuthenticationChangeEvent? watchEvent<Data>() =>
|
||||||
|
watchSession<Data>()?.latestEvent;
|
||||||
|
|
||||||
|
/// Read account in context from a specific AuthenticationCubit type [T]
|
||||||
|
Account? readAccountFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
readSessionFrom<T, Data>()?.account;
|
||||||
|
|
||||||
|
/// Watch account in context from a specific AuthenticationCubit type [T]
|
||||||
|
Account? watchAccountFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
watchSessionFrom<T, Data>()?.account;
|
||||||
|
|
||||||
|
/// Read account in context from generic AuthenticationCubit type
|
||||||
|
Account? readAccount<Data>() => readSession<Data>()?.account;
|
||||||
|
|
||||||
|
/// Watch account in context from generic AuthenticationCubit type
|
||||||
|
Account? watchAccount<Data>() => watchSession<Data>()?.account;
|
||||||
|
|
||||||
|
/// Read data in context from a specific AuthenticationCubit type [T]
|
||||||
|
Data? readDataFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
readSessionFrom<T, Data>()?.data;
|
||||||
|
|
||||||
|
/// Watch data in context from a specific AuthenticationCubit type [T]
|
||||||
|
Data? watchDataFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
watchSessionFrom<T, Data>()?.data;
|
||||||
|
|
||||||
|
/// Read data in context from generic AuthenticationCubit type
|
||||||
|
Data? readData<Data>() => readSession<Data>()?.data;
|
||||||
|
|
||||||
|
/// Watch data in context from generic AuthenticationCubit type
|
||||||
|
Data? watchData<Data>() => watchSession<Data>()?.data;
|
||||||
|
|
||||||
|
/// Check if user is authenticated from a
|
||||||
|
/// specific AuthenticationCubit type [T]
|
||||||
|
bool isAuthenticatedFrom<T extends AuthenticationCubit<Data>, Data>() =>
|
||||||
|
readEventFrom<T, Data>() is AuthenticatedChangeEvent;
|
||||||
|
|
||||||
|
/// Check if user is authenticated from generic AuthenticationCubit type
|
||||||
|
bool isAuthenticated<Data>() => readEvent<Data>() is AuthenticatedChangeEvent;
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart';
|
|||||||
import 'package:wyatt_authentication_bloc/src/data/models/models.dart';
|
import 'package:wyatt_authentication_bloc/src/data/models/models.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
||||||
|
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
|
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
class AuthenticationFirebaseDataSourceImpl<Data>
|
class AuthenticationFirebaseDataSourceImpl<Data>
|
||||||
@ -41,7 +41,7 @@ class AuthenticationFirebaseDataSourceImpl<Data>
|
|||||||
_checkForCachedAccount();
|
_checkForCachedAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
late StreamController<SessionWrapper<Data>> _sessionStream;
|
late StreamController<AuthenticationSession<Data>> _sessionStream;
|
||||||
late StreamController<UserCredential?> _latestCredentials;
|
late StreamController<UserCredential?> _latestCredentials;
|
||||||
|
|
||||||
final FirebaseAuth _firebaseAuth;
|
final FirebaseAuth _firebaseAuth;
|
||||||
@ -51,8 +51,11 @@ class AuthenticationFirebaseDataSourceImpl<Data>
|
|||||||
final currentUser = _firebaseAuth.currentUser;
|
final currentUser = _firebaseAuth.currentUser;
|
||||||
|
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
_sessionStream
|
_sessionStream.add(
|
||||||
.add(const SessionWrapper(event: UnknownAuthenticationEvent()));
|
const AuthenticationSession(
|
||||||
|
latestEvent: UnknownAuthenticationEvent(),
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +65,9 @@ class AuthenticationFirebaseDataSourceImpl<Data>
|
|||||||
accessToken: jwt,
|
accessToken: jwt,
|
||||||
);
|
);
|
||||||
_sessionStream.add(
|
_sessionStream.add(
|
||||||
SessionWrapper(event: SignedInFromCacheEvent(account: currentAccount)),
|
AuthenticationSession.fromEvent(
|
||||||
|
SignedInFromCacheEvent(account: currentAccount),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -78,19 +83,23 @@ class AuthenticationFirebaseDataSourceImpl<Data>
|
|||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream related methods ===================================================
|
// Session related methods ===================================================
|
||||||
|
|
||||||
/// {@macro add_session}
|
/// {@macro add_session}
|
||||||
@override
|
@override
|
||||||
void addSession(SessionWrapper<Data> wrapper) {
|
void addSession(AuthenticationSession<Data> session) {
|
||||||
_sessionStream.add(wrapper);
|
_sessionStream.add(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// {@macro session_stream}
|
/// {@macro session_stream}
|
||||||
@override
|
@override
|
||||||
Stream<SessionWrapper<Data>> sessionStream() =>
|
Stream<AuthenticationSession<Data>> sessionStream() =>
|
||||||
_sessionStream.stream.asBroadcastStream();
|
_sessionStream.stream.asBroadcastStream();
|
||||||
|
|
||||||
|
/// {@macro current_session}
|
||||||
|
@override
|
||||||
|
Future<AuthenticationSession<Data>> currentSession() => sessionStream().last;
|
||||||
|
|
||||||
// SignUp/SignIn methods ====================================================
|
// SignUp/SignIn methods ====================================================
|
||||||
|
|
||||||
/// {@macro signup_pwd}
|
/// {@macro signup_pwd}
|
||||||
|
@ -18,7 +18,7 @@ import 'package:wyatt_architecture/wyatt_architecture.dart';
|
|||||||
import 'package:wyatt_authentication_bloc/src/core/utils/forms.dart';
|
import 'package:wyatt_authentication_bloc/src/core/utils/forms.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
@ -73,18 +73,30 @@ class AuthenticationRepositoryImpl<Data extends Object>
|
|||||||
@override
|
@override
|
||||||
FormRepository get formRepository => _formRepository;
|
FormRepository get formRepository => _formRepository;
|
||||||
|
|
||||||
// Stream related methods ===================================================
|
// Session related methods ===================================================
|
||||||
|
|
||||||
/// {@macro add_session}
|
/// {@macro add_session}
|
||||||
@override
|
@override
|
||||||
void addSession(SessionWrapper<Data> wrapper) =>
|
void addSession(AuthenticationSession<Data> session) =>
|
||||||
authenticationRemoteDataSource.addSession(wrapper);
|
authenticationRemoteDataSource.addSession(session);
|
||||||
|
|
||||||
/// {@macro session_stream}
|
/// {@macro session_stream}
|
||||||
@override
|
@override
|
||||||
Stream<SessionWrapper<Data>> sessionStream() =>
|
Stream<AuthenticationSession<Data>> sessionStream() =>
|
||||||
authenticationRemoteDataSource.sessionStream();
|
authenticationRemoteDataSource.sessionStream();
|
||||||
|
|
||||||
|
/// {@macro current_session}
|
||||||
|
@override
|
||||||
|
FutureOrResult<AuthenticationSession<Data>> currentSession() =>
|
||||||
|
Result.tryCatchAsync<AuthenticationSession<Data>, AppException,
|
||||||
|
AppException>(
|
||||||
|
() async {
|
||||||
|
final session = await authenticationRemoteDataSource.currentSession();
|
||||||
|
return session;
|
||||||
|
},
|
||||||
|
(error) => error,
|
||||||
|
);
|
||||||
|
|
||||||
// SignUp/SignIn methods ====================================================
|
// SignUp/SignIn methods ====================================================
|
||||||
|
|
||||||
/// {@macro signup_pwd}
|
/// {@macro signup_pwd}
|
||||||
|
@ -16,16 +16,16 @@
|
|||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
|
||||||
|
|
||||||
/// Is responsible for abstracting the provenance of the data.
|
/// Is responsible for abstracting the provenance of the data.
|
||||||
abstract class AuthenticationRemoteDataSource<Data>
|
abstract class AuthenticationRemoteDataSource<Data>
|
||||||
extends BaseRemoteDataSource {
|
extends BaseRemoteDataSource {
|
||||||
// Stream related methods ===================================================
|
// Session related methods ===================================================
|
||||||
|
|
||||||
void addSession(SessionWrapper<Data> wrapper);
|
void addSession(AuthenticationSession<Data> session);
|
||||||
|
Stream<AuthenticationSession<Data>> sessionStream();
|
||||||
Stream<SessionWrapper<Data>> sessionStream();
|
Future<AuthenticationSession<Data>> currentSession();
|
||||||
|
|
||||||
// SignUp/SignIn methods ====================================================
|
// SignUp/SignIn methods ====================================================
|
||||||
|
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (C) 2023 WYATT GROUP
|
||||||
|
// Please see the AUTHORS file for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
|
||||||
|
|
||||||
|
/// The [AuthenticationSession] object is used to transport and propagate
|
||||||
|
/// the last event issued by an authentication state change, a user account
|
||||||
|
/// if connected, and the associated data.
|
||||||
|
class AuthenticationSession<Data> extends Equatable {
|
||||||
|
const AuthenticationSession({
|
||||||
|
required this.latestEvent,
|
||||||
|
this.account,
|
||||||
|
this.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AuthenticationSession.fromEvent(
|
||||||
|
AuthenticationChangeEvent latestEvent, {
|
||||||
|
Data? data,
|
||||||
|
}) {
|
||||||
|
if (latestEvent is AuthenticatedChangeEvent) {
|
||||||
|
return AuthenticationSession(
|
||||||
|
latestEvent: latestEvent,
|
||||||
|
account: latestEvent.account,
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return AuthenticationSession(
|
||||||
|
latestEvent: latestEvent,
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final AuthenticationChangeEvent latestEvent;
|
||||||
|
final Account? account;
|
||||||
|
final Data? data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
latestEvent,
|
||||||
|
account,
|
||||||
|
data,
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool? get stringify => true;
|
||||||
|
}
|
@ -14,23 +14,15 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
part of 'authentication_change_event.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
|
||||||
|
|
||||||
|
/// Represents every event where user is authenticated.
|
||||||
|
abstract class AuthenticatedChangeEvent extends AuthenticationChangeEvent {
|
||||||
|
const AuthenticatedChangeEvent({required this.account});
|
||||||
|
|
||||||
/// The [Session] object is used to transport and propagate
|
|
||||||
/// the connected user [Account] and personalized [Data] in the application.
|
|
||||||
class Session<Data> extends Equatable {
|
|
||||||
const Session({
|
|
||||||
required this.account,
|
|
||||||
this.data,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Account account;
|
final Account account;
|
||||||
final Data? data;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account, data];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool? get stringify => true;
|
List<Object?> get props => [account];
|
||||||
}
|
}
|
@ -18,15 +18,16 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
||||||
|
|
||||||
|
part 'authenticated_change_event.dart';
|
||||||
|
part 'deleted_event.dart';
|
||||||
|
part 'reauthenticated_event.dart';
|
||||||
|
part 'refreshed_event.dart';
|
||||||
part 'signed_in_event.dart';
|
part 'signed_in_event.dart';
|
||||||
|
part 'signed_in_from_cache_event.dart';
|
||||||
part 'signed_out_event.dart';
|
part 'signed_out_event.dart';
|
||||||
part 'signed_up_event.dart';
|
part 'signed_up_event.dart';
|
||||||
part 'refreshed_event.dart';
|
|
||||||
part 'reauthenticated_event.dart';
|
|
||||||
part 'updated_event.dart';
|
|
||||||
part 'unknown_authentication_event.dart';
|
part 'unknown_authentication_event.dart';
|
||||||
part 'signed_in_from_cache_event.dart';
|
part 'updated_event.dart';
|
||||||
part 'deleted_event.dart';
|
|
||||||
|
|
||||||
/// Represents an event initiated by a change in
|
/// Represents an event initiated by a change in
|
||||||
/// the user's authentication status.
|
/// the user's authentication status.
|
||||||
|
@ -16,14 +16,9 @@
|
|||||||
|
|
||||||
part of 'authentication_change_event.dart';
|
part of 'authentication_change_event.dart';
|
||||||
|
|
||||||
/// When a user re-authenticates (from the logged in state to the
|
/// When a user re-authenticates (from the logged in state to the
|
||||||
/// logged in state with a different and fresh access
|
/// logged in state with a different and fresh access
|
||||||
/// token and a different login time)
|
/// token and a different login time)
|
||||||
class ReauthenticatedEvent extends AuthenticationChangeEvent {
|
class ReauthenticatedEvent extends AuthenticatedChangeEvent {
|
||||||
const ReauthenticatedEvent({required this.account});
|
const ReauthenticatedEvent({required super.account});
|
||||||
|
|
||||||
final Account account;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account];
|
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,8 @@
|
|||||||
|
|
||||||
part of 'authentication_change_event.dart';
|
part of 'authentication_change_event.dart';
|
||||||
|
|
||||||
/// When a user access token is refreshed (from the logged in state to the
|
/// When a user access token is refreshed (from the logged in state to the
|
||||||
/// logged in state with a different access token)
|
/// logged in state with a different access token)
|
||||||
class RefreshedEvent extends AuthenticationChangeEvent {
|
class RefreshedEvent extends AuthenticatedChangeEvent {
|
||||||
const RefreshedEvent({required this.account});
|
const RefreshedEvent({required super.account});
|
||||||
|
|
||||||
final Account account;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account];
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
part of 'authentication_change_event.dart';
|
part of 'authentication_change_event.dart';
|
||||||
|
|
||||||
/// When a user authenticates (from not logged in to logged in).
|
/// When a user authenticates (from not logged in to logged in).
|
||||||
class SignedInEvent extends AuthenticationChangeEvent {
|
class SignedInEvent extends AuthenticatedChangeEvent {
|
||||||
const SignedInEvent({required this.account});
|
const SignedInEvent({required super.account});
|
||||||
|
|
||||||
final Account account;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account];
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
part of 'authentication_change_event.dart';
|
part of 'authentication_change_event.dart';
|
||||||
|
|
||||||
/// When a user authenticates automatically (from not logged in to logged in).
|
/// When a user authenticates automatically (from not logged in to logged in).
|
||||||
class SignedInFromCacheEvent extends AuthenticationChangeEvent {
|
class SignedInFromCacheEvent extends AuthenticatedChangeEvent {
|
||||||
const SignedInFromCacheEvent({required this.account});
|
const SignedInFromCacheEvent({required super.account});
|
||||||
|
|
||||||
final Account account;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account];
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
part of 'authentication_change_event.dart';
|
part of 'authentication_change_event.dart';
|
||||||
|
|
||||||
/// When a user creates an account.
|
/// When a user creates an account.
|
||||||
class SignedUpEvent extends AuthenticationChangeEvent {
|
class SignedUpEvent extends AuthenticatedChangeEvent {
|
||||||
const SignedUpEvent({required this.account});
|
const SignedUpEvent({required super.account});
|
||||||
|
|
||||||
final Account account;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account];
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
part of 'authentication_change_event.dart';
|
part of 'authentication_change_event.dart';
|
||||||
|
|
||||||
/// When the user's account has been updated.
|
/// When the user's account has been updated.
|
||||||
class UpdatedEvent extends AuthenticationChangeEvent {
|
class UpdatedEvent extends AuthenticatedChangeEvent {
|
||||||
const UpdatedEvent({required this.account});
|
const UpdatedEvent({required super.account});
|
||||||
|
|
||||||
final Account account;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [account];
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,5 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export 'account.dart';
|
export 'account.dart';
|
||||||
|
export 'auth_session.dart';
|
||||||
export 'authentication_change_event/authentication_change_event.dart';
|
export 'authentication_change_event/authentication_change_event.dart';
|
||||||
export 'session.dart';
|
|
||||||
export 'session_wrapper.dart';
|
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
// Copyright (C) 2023 WYATT GROUP
|
|
||||||
// Please see the AUTHORS file for details.
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart';
|
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session.dart';
|
|
||||||
|
|
||||||
/// Contains the [AuthenticationChangeEvent] initiating the state
|
|
||||||
/// change and the current [Session].
|
|
||||||
class SessionWrapper<Data> extends Equatable implements Entity {
|
|
||||||
const SessionWrapper({
|
|
||||||
required this.event,
|
|
||||||
this.session,
|
|
||||||
});
|
|
||||||
|
|
||||||
final AuthenticationChangeEvent event;
|
|
||||||
final Session<Data>? session;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [event, session];
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get stringify => true;
|
|
||||||
}
|
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
abstract class AuthenticationRepository<Data> extends BaseRepository {
|
abstract class AuthenticationRepository<Data> extends BaseRepository {
|
||||||
@ -30,12 +30,17 @@ abstract class AuthenticationRepository<Data> extends BaseRepository {
|
|||||||
/// {@template add_session}
|
/// {@template add_session}
|
||||||
/// Add a new authentication event.
|
/// Add a new authentication event.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
void addSession(SessionWrapper<Data> wrapper);
|
void addSession(AuthenticationSession<Data> session);
|
||||||
|
|
||||||
/// {@template session_stream}
|
/// {@template session_stream}
|
||||||
/// Authentication state change event stream.
|
/// Authentication state change event stream.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
Stream<SessionWrapper<Data>> sessionStream();
|
Stream<AuthenticationSession<Data>> sessionStream();
|
||||||
|
|
||||||
|
/// {@template current_session}
|
||||||
|
/// Latest session issued by the session stream.
|
||||||
|
/// {@endtemplate}
|
||||||
|
FutureOrResult<AuthenticationSession<Data>> currentSession();
|
||||||
|
|
||||||
// SignUp/SignIn methods ====================================================
|
// SignUp/SignIn methods ====================================================
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/core/enums/authentication_status.dart';
|
import 'package:wyatt_authentication_bloc/src/core/enums/authentication_status.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart';
|
import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart';
|
||||||
|
|
||||||
class AuthenticationBuilder<Data> extends StatelessWidget {
|
class AuthenticationBuilder<Data> extends StatelessWidget {
|
||||||
@ -30,7 +30,7 @@ class AuthenticationBuilder<Data> extends StatelessWidget {
|
|||||||
|
|
||||||
final Widget Function(
|
final Widget Function(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
SessionWrapper<Data> sessionWrapper,
|
AuthenticationSession<Data> session,
|
||||||
) authenticated;
|
) authenticated;
|
||||||
final Widget Function(BuildContext context) unauthenticated;
|
final Widget Function(BuildContext context) unauthenticated;
|
||||||
final Widget Function(BuildContext context) unknown;
|
final Widget Function(BuildContext context) unknown;
|
||||||
@ -40,8 +40,8 @@ class AuthenticationBuilder<Data> extends StatelessWidget {
|
|||||||
BlocBuilder<AuthenticationCubit<Data>, AuthenticationState<Data>>(
|
BlocBuilder<AuthenticationCubit<Data>, AuthenticationState<Data>>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.status == AuthenticationStatus.authenticated) {
|
if (state.status == AuthenticationStatus.authenticated) {
|
||||||
if (state.wrapper != null) {
|
if (state.session != null) {
|
||||||
return authenticated(context, state.wrapper!);
|
return authenticated(context, state.session!);
|
||||||
} else {
|
} else {
|
||||||
return unauthenticated(context);
|
return unauthenticated(context);
|
||||||
}
|
}
|
||||||
|
@ -42,35 +42,31 @@ abstract class AuthenticationCubit<Data>
|
|||||||
}
|
}
|
||||||
final AuthenticationRepository<Data> authenticationRepository;
|
final AuthenticationRepository<Data> authenticationRepository;
|
||||||
|
|
||||||
SessionWrapper<Data>? _latestSession;
|
AuthenticationSession<Data>? _latestSession;
|
||||||
|
|
||||||
void _listenForAuthenticationChanges() {
|
void _listenForAuthenticationChanges() {
|
||||||
authenticationRepository.sessionStream().asyncMap((wrapper) async {
|
authenticationRepository.sessionStream().asyncMap((session) async {
|
||||||
final event = wrapper.event;
|
final event = session.latestEvent;
|
||||||
if (event is SignedInFromCacheEvent) {
|
if (event is SignedInFromCacheEvent) {
|
||||||
final customRoutineResult = await onSignInFromCache(wrapper);
|
final customRoutineResult = await onSignInFromCache(session);
|
||||||
|
|
||||||
if (customRoutineResult.isOk) {
|
if (customRoutineResult.isOk) {
|
||||||
final account = event.account;
|
final account = event.account;
|
||||||
final sessionData = customRoutineResult.ok;
|
final sessionData = customRoutineResult.ok;
|
||||||
|
|
||||||
final signedInSession = SessionWrapper(
|
final signedInSession = AuthenticationSession.fromEvent(
|
||||||
event: SignedInFromCacheEvent(account: account),
|
SignedInFromCacheEvent(account: account),
|
||||||
session: Session<Data>(
|
data: sessionData,
|
||||||
account: account,
|
|
||||||
data: sessionData,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return signedInSession;
|
return signedInSession;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wrapper;
|
return session;
|
||||||
}).listen((wrapper) async {
|
}).listen((session) async {
|
||||||
_latestSession = wrapper;
|
_latestSession = session;
|
||||||
final session = wrapper.session;
|
if (session.account != null) {
|
||||||
if (session != null) {
|
emit(AuthenticationState<Data>.authenticated(session));
|
||||||
emit(AuthenticationState<Data>.authenticated(wrapper));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(AuthenticationState<Data>.unauthenticated());
|
emit(AuthenticationState<Data>.unauthenticated());
|
||||||
@ -80,19 +76,16 @@ abstract class AuthenticationCubit<Data>
|
|||||||
|
|
||||||
/// {@macro refresh}
|
/// {@macro refresh}
|
||||||
FutureOr<void> refresh() async => CustomRoutine<Account, Data?>(
|
FutureOr<void> refresh() async => CustomRoutine<Account, Data?>(
|
||||||
routine: authenticationRepository.refresh,
|
routine: authenticationRepository.refresh,
|
||||||
attachedLogic: onRefresh,
|
attachedLogic: onRefresh,
|
||||||
onError: addError,
|
onError: addError,
|
||||||
onSuccess: (result, data) => authenticationRepository.addSession(
|
onSuccess: (result, data) => authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: RefreshedEvent(account: result),
|
RefreshedEvent(account: result),
|
||||||
session: Session<Data>(
|
|
||||||
account: result,
|
|
||||||
data: data,
|
data: data,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
).call();
|
||||||
).call();
|
|
||||||
|
|
||||||
/// {@macro reauthenticate}
|
/// {@macro reauthenticate}
|
||||||
FutureOr<void> reauthenticate() async => CustomRoutine<Account, Data?>(
|
FutureOr<void> reauthenticate() async => CustomRoutine<Account, Data?>(
|
||||||
@ -100,12 +93,9 @@ abstract class AuthenticationCubit<Data>
|
|||||||
attachedLogic: onReauthenticate,
|
attachedLogic: onReauthenticate,
|
||||||
onError: addError,
|
onError: addError,
|
||||||
onSuccess: (result, data) => authenticationRepository.addSession(
|
onSuccess: (result, data) => authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: ReauthenticatedEvent(account: result),
|
ReauthenticatedEvent(account: result),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: result,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).call();
|
).call();
|
||||||
@ -115,8 +105,11 @@ abstract class AuthenticationCubit<Data>
|
|||||||
routine: authenticationRepository.signOut,
|
routine: authenticationRepository.signOut,
|
||||||
attachedLogic: (routineResult) => onSignOut(),
|
attachedLogic: (routineResult) => onSignOut(),
|
||||||
onError: addError,
|
onError: addError,
|
||||||
onSuccess: (result, data) => authenticationRepository
|
onSuccess: (result, data) => authenticationRepository.addSession(
|
||||||
.addSession(SessionWrapper<Data>(event: const SignedOutEvent())),
|
const AuthenticationSession(
|
||||||
|
latestEvent: SignedOutEvent(),
|
||||||
|
),
|
||||||
|
),
|
||||||
).call();
|
).call();
|
||||||
|
|
||||||
/// {@macro delete}
|
/// {@macro delete}
|
||||||
@ -124,20 +117,23 @@ abstract class AuthenticationCubit<Data>
|
|||||||
routine: authenticationRepository.delete,
|
routine: authenticationRepository.delete,
|
||||||
attachedLogic: (routineResult) => onDelete(),
|
attachedLogic: (routineResult) => onDelete(),
|
||||||
onError: addError,
|
onError: addError,
|
||||||
onSuccess: (result, data) => authenticationRepository
|
onSuccess: (result, data) => authenticationRepository.addSession(
|
||||||
.addSession(SessionWrapper<Data>(event: const DeletedEvent())),
|
const AuthenticationSession(
|
||||||
|
latestEvent: DeletedEvent(),
|
||||||
|
),
|
||||||
|
),
|
||||||
).call();
|
).call();
|
||||||
|
|
||||||
/// Returns latest session wrapper.
|
/// Returns latest session.
|
||||||
///
|
///
|
||||||
/// Contains latest event and latest session data (account + extra data)
|
/// Contains latest event and latest session data (account + extra data)
|
||||||
SessionWrapper<Data>? currentSession() => _latestSession;
|
AuthenticationSession<Data>? currentSession() => _latestSession;
|
||||||
|
|
||||||
/// This callback is triggered when the user is automaticcaly logged in from
|
/// This callback is triggered when the user is automaticcaly logged in from
|
||||||
/// the cache.
|
/// the cache.
|
||||||
///
|
///
|
||||||
/// For example: when the user is sign in from the Firebase cache.
|
/// For example: when the user is sign in from the Firebase cache.
|
||||||
FutureOrResult<Data?> onSignInFromCache(SessionWrapper<Data> wrapper);
|
FutureOrResult<Data?> onSignInFromCache(AuthenticationSession<Data> session);
|
||||||
|
|
||||||
/// This callback is triggered when the account is refreshed.
|
/// This callback is triggered when the account is refreshed.
|
||||||
///
|
///
|
||||||
|
@ -17,25 +17,25 @@
|
|||||||
part of 'authentication_cubit.dart';
|
part of 'authentication_cubit.dart';
|
||||||
|
|
||||||
class AuthenticationState<Data> extends Equatable {
|
class AuthenticationState<Data> extends Equatable {
|
||||||
const AuthenticationState._(this.status, this.wrapper);
|
const AuthenticationState._(this.status, this.session);
|
||||||
|
|
||||||
const AuthenticationState.unauthenticated()
|
const AuthenticationState.unauthenticated()
|
||||||
: this._(AuthenticationStatus.unauthenticated, null);
|
: this._(AuthenticationStatus.unauthenticated, null);
|
||||||
|
|
||||||
const AuthenticationState.authenticated(SessionWrapper<Data> sessionWrapper)
|
const AuthenticationState.authenticated(AuthenticationSession<Data> session)
|
||||||
: this._(
|
: this._(
|
||||||
AuthenticationStatus.authenticated,
|
AuthenticationStatus.authenticated,
|
||||||
sessionWrapper,
|
session,
|
||||||
);
|
);
|
||||||
|
|
||||||
const AuthenticationState.unknown()
|
const AuthenticationState.unknown()
|
||||||
: this._(AuthenticationStatus.unknown, null);
|
: this._(AuthenticationStatus.unknown, null);
|
||||||
|
|
||||||
final AuthenticationStatus status;
|
final AuthenticationStatus status;
|
||||||
final SessionWrapper<Data>? wrapper;
|
final AuthenticationSession<Data>? session;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [status, wrapper];
|
List<Object?> get props => [status, session];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool? get stringify => true;
|
bool? get stringify => true;
|
||||||
|
@ -111,12 +111,9 @@ mixin UpdateEmail<Data> on BaseEditAccountCubit<Data> {
|
|||||||
},
|
},
|
||||||
onSuccess: (account, data) {
|
onSuccess: (account, data) {
|
||||||
authenticationRepository.addSession(
|
authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: UpdatedEvent(account: account),
|
UpdatedEvent(account: account),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: account,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(
|
emit(
|
||||||
|
@ -110,12 +110,9 @@ mixin UpdatePassword<Data> on BaseEditAccountCubit<Data> {
|
|||||||
},
|
},
|
||||||
onSuccess: (account, data) {
|
onSuccess: (account, data) {
|
||||||
authenticationRepository.addSession(
|
authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInEvent(account: account),
|
UpdatedEvent(account: account),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: account,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(
|
emit(
|
||||||
|
@ -31,12 +31,13 @@ class EmailVerificationCubit<Data> extends Cubit<EmailVerificationState> {
|
|||||||
final AuthenticationRepository<Data> authenticationRepository;
|
final AuthenticationRepository<Data> authenticationRepository;
|
||||||
|
|
||||||
FutureOr<void> sendEmailVerification() async {
|
FutureOr<void> sendEmailVerification() async {
|
||||||
emit(state.copyWith(status: FormStatus.submissionInProgress));
|
emit(const EmailVerificationState(status: FormStatus.submissionInProgress));
|
||||||
final response = await authenticationRepository.sendEmailVerification();
|
final response = await authenticationRepository.sendEmailVerification();
|
||||||
emit(
|
emit(
|
||||||
response.fold(
|
response.fold(
|
||||||
(value) => state.copyWith(status: FormStatus.submissionSuccess),
|
(value) =>
|
||||||
(error) => state.copyWith(
|
const EmailVerificationState(status: FormStatus.submissionSuccess),
|
||||||
|
(error) => EmailVerificationState(
|
||||||
errorMessage: error.message,
|
errorMessage: error.message,
|
||||||
status: FormStatus.submissionFailure,
|
status: FormStatus.submissionFailure,
|
||||||
),
|
),
|
||||||
@ -45,7 +46,7 @@ class EmailVerificationCubit<Data> extends Cubit<EmailVerificationState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> checkEmailVerification() async {
|
FutureOr<void> checkEmailVerification() async {
|
||||||
emit(state.copyWith(status: FormStatus.submissionInProgress));
|
emit(const EmailVerificationState(status: FormStatus.submissionInProgress));
|
||||||
|
|
||||||
final refresh = await authenticationRepository.refresh();
|
final refresh = await authenticationRepository.refresh();
|
||||||
if (refresh.isErr) {
|
if (refresh.isErr) {
|
||||||
@ -59,11 +60,11 @@ class EmailVerificationCubit<Data> extends Cubit<EmailVerificationState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final wrapper = await authenticationRepository.sessionStream().last;
|
final session = await authenticationRepository.currentSession();
|
||||||
final currentAccount = wrapper.session?.account;
|
final currentAccount = session.ok?.account;
|
||||||
if (currentAccount != null) {
|
if (currentAccount != null) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
EmailVerificationState(
|
||||||
isVerified: currentAccount.emailVerified,
|
isVerified: currentAccount.emailVerified,
|
||||||
status: FormStatus.submissionSuccess,
|
status: FormStatus.submissionSuccess,
|
||||||
),
|
),
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
|
||||||
// Copyright (C) 2023 WYATT GROUP
|
// Copyright (C) 2023 WYATT GROUP
|
||||||
// Please see the AUTHORS file for details.
|
// Please see the AUTHORS file for details.
|
||||||
//
|
//
|
||||||
@ -18,16 +17,16 @@
|
|||||||
part of 'email_verification_cubit.dart';
|
part of 'email_verification_cubit.dart';
|
||||||
|
|
||||||
class EmailVerificationState extends Equatable {
|
class EmailVerificationState extends Equatable {
|
||||||
final FormStatus status;
|
|
||||||
final bool isVerified;
|
|
||||||
final String? errorMessage;
|
|
||||||
|
|
||||||
const EmailVerificationState({
|
const EmailVerificationState({
|
||||||
this.isVerified = false,
|
this.isVerified = false,
|
||||||
this.status = FormStatus.pure,
|
this.status = FormStatus.pure,
|
||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final FormStatus status;
|
||||||
|
final bool isVerified;
|
||||||
|
final String? errorMessage;
|
||||||
|
|
||||||
EmailVerificationState copyWith({
|
EmailVerificationState copyWith({
|
||||||
FormStatus? status,
|
FormStatus? status,
|
||||||
bool? isVerified,
|
bool? isVerified,
|
||||||
|
@ -63,12 +63,9 @@ mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
|
|||||||
},
|
},
|
||||||
onSuccess: (account, data) {
|
onSuccess: (account, data) {
|
||||||
authenticationRepository.addSession(
|
authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInEvent(account: account),
|
SignedInEvent(account: account),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: account,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(
|
emit(
|
||||||
|
@ -136,12 +136,9 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
|
|||||||
},
|
},
|
||||||
onSuccess: (account, data) {
|
onSuccess: (account, data) {
|
||||||
authenticationRepository.addSession(
|
authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInEvent(account: account),
|
SignedInEvent(account: account),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: account,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(
|
emit(
|
||||||
|
@ -62,12 +62,9 @@ mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
|
|||||||
},
|
},
|
||||||
onSuccess: (account, data) {
|
onSuccess: (account, data) {
|
||||||
authenticationRepository.addSession(
|
authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInEvent(account: account),
|
SignedInEvent(account: account),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: account,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(
|
emit(
|
||||||
|
@ -126,12 +126,9 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
|
|||||||
},
|
},
|
||||||
onSuccess: (account, data) {
|
onSuccess: (account, data) {
|
||||||
authenticationRepository.addSession(
|
authenticationRepository.addSession(
|
||||||
SessionWrapper(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedUpEvent(account: account),
|
SignedUpEvent(account: account),
|
||||||
session: Session<Data>(
|
data: data,
|
||||||
account: account,
|
|
||||||
data: data,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(
|
emit(
|
||||||
|
@ -43,7 +43,9 @@ class TestAuthenticationCubit extends AuthenticationCubit<int> {
|
|||||||
const Ok(null);
|
const Ok(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) async =>
|
FutureOrResult<int?> onSignInFromCache(
|
||||||
|
AuthenticationSession<int> session,
|
||||||
|
) async =>
|
||||||
const Ok(null);
|
const Ok(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -53,9 +55,10 @@ class TestAuthenticationCubit extends AuthenticationCubit<int> {
|
|||||||
void main() {
|
void main() {
|
||||||
group('AuthenticationCubit<T>', () {
|
group('AuthenticationCubit<T>', () {
|
||||||
final MockAccount account = MockAccount();
|
final MockAccount account = MockAccount();
|
||||||
final SessionWrapper<int> wrapper = SessionWrapper(
|
final AuthenticationSession<int> session = AuthenticationSession<int>(
|
||||||
event: const UnknownAuthenticationEvent(),
|
latestEvent: const UnknownAuthenticationEvent(),
|
||||||
session: Session(account: account, data: 10),
|
account: account,
|
||||||
|
data: 10,
|
||||||
);
|
);
|
||||||
late AuthenticationRepository<int> authenticationRepository;
|
late AuthenticationRepository<int> authenticationRepository;
|
||||||
|
|
||||||
@ -80,14 +83,14 @@ void main() {
|
|||||||
'emits authenticated when stream contains session',
|
'emits authenticated when stream contains session',
|
||||||
setUp: () {
|
setUp: () {
|
||||||
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
(_) => Stream.fromIterable([wrapper]),
|
(_) => Stream.fromIterable([session]),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
build: () => TestAuthenticationCubit(
|
build: () => TestAuthenticationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
authenticationRepository: authenticationRepository,
|
||||||
),
|
),
|
||||||
seed: () => const AuthenticationState.unknown(),
|
seed: () => const AuthenticationState.unknown(),
|
||||||
expect: () => [AuthenticationState<int>.authenticated(wrapper)],
|
expect: () => [AuthenticationState<int>.authenticated(session)],
|
||||||
);
|
);
|
||||||
|
|
||||||
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
||||||
@ -95,7 +98,8 @@ void main() {
|
|||||||
setUp: () {
|
setUp: () {
|
||||||
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
(_) => Stream.fromIterable(
|
(_) => Stream.fromIterable(
|
||||||
[const SessionWrapper(event: SignedOutEvent())],),
|
[const AuthenticationSession(latestEvent: SignedOutEvent())],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
build: () => TestAuthenticationCubit(
|
build: () => TestAuthenticationCubit(
|
||||||
|
@ -27,7 +27,7 @@ void main() {
|
|||||||
const AuthenticationState<void> state =
|
const AuthenticationState<void> state =
|
||||||
AuthenticationState.unauthenticated();
|
AuthenticationState.unauthenticated();
|
||||||
expect(state.status, AuthenticationStatus.unauthenticated);
|
expect(state.status, AuthenticationStatus.unauthenticated);
|
||||||
expect(state.wrapper, null);
|
expect(state.session, null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -36,13 +36,12 @@ void main() {
|
|||||||
final MockAccount account = MockAccount();
|
final MockAccount account = MockAccount();
|
||||||
final AuthenticationState<void> state =
|
final AuthenticationState<void> state =
|
||||||
AuthenticationState.authenticated(
|
AuthenticationState.authenticated(
|
||||||
SessionWrapper<void>(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInEvent(account: account),
|
SignedInEvent(account: account),
|
||||||
session: Session(account: account),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(state.status, AuthenticationStatus.authenticated);
|
expect(state.status, AuthenticationStatus.authenticated);
|
||||||
expect(state.wrapper?.session?.account, account);
|
expect(state.session?.account, account);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,14 +51,14 @@ void main() {
|
|||||||
const String extra = 'AwesomeExtraData';
|
const String extra = 'AwesomeExtraData';
|
||||||
final AuthenticationState<String> state =
|
final AuthenticationState<String> state =
|
||||||
AuthenticationState.authenticated(
|
AuthenticationState.authenticated(
|
||||||
SessionWrapper<String>(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInEvent(account: account),
|
SignedInEvent(account: account),
|
||||||
session: Session(account: account, data: extra),
|
data: extra,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(state.status, AuthenticationStatus.authenticated);
|
expect(state.status, AuthenticationStatus.authenticated);
|
||||||
expect(state.wrapper?.session?.account, account);
|
expect(state.session?.account, account);
|
||||||
expect(state.wrapper?.session?.data, extra);
|
expect(state.session?.data, extra);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -43,13 +43,24 @@ void main() {
|
|||||||
|
|
||||||
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
(_) => Stream.fromIterable([
|
(_) => Stream.fromIterable([
|
||||||
SessionWrapper<int>(
|
AuthenticationSession.fromEvent(
|
||||||
event: SignedInFromCacheEvent(account: account),
|
SignedInFromCacheEvent(account: account),
|
||||||
session: Session<int>(account: account, data: 10),
|
data: 10,
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => authenticationRepository.currentSession(),
|
||||||
|
).thenAnswer(
|
||||||
|
(_) async => Ok(
|
||||||
|
AuthenticationSession.fromEvent(
|
||||||
|
SignedInFromCacheEvent(account: account),
|
||||||
|
data: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
when(
|
when(
|
||||||
() => authenticationRepository.refresh(),
|
() => authenticationRepository.refresh(),
|
||||||
).thenAnswer((_) async => Ok(account));
|
).thenAnswer((_) async => Ok(account));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user