milestone/stable-1-reconcile-auth-3 #176
@ -37,7 +37,7 @@ class ExampleAuthenticationCubit extends AuthenticationCubit<int> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) {
 | 
			
		||||
  FutureOrResult<int?> onSignInFromCache(AuthenticationSession<int> session) {
 | 
			
		||||
    print('onSignInFromCache');
 | 
			
		||||
 | 
			
		||||
    return const Ok(1);
 | 
			
		||||
 | 
			
		||||
@ -30,8 +30,7 @@ class HomePage extends StatelessWidget {
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      appBar: AppBar(
 | 
			
		||||
        title: Text(
 | 
			
		||||
            'Home | ${context.account<AuthenticationCubit<int>, int>()?.email}'),
 | 
			
		||||
        title: Text('Home | ${context.watchAccount<int>()?.email}'),
 | 
			
		||||
        actions: [
 | 
			
		||||
          IconButton(
 | 
			
		||||
              onPressed: () =>
 | 
			
		||||
@ -44,8 +43,8 @@ class HomePage extends StatelessWidget {
 | 
			
		||||
        child: ListView(
 | 
			
		||||
          children: [
 | 
			
		||||
            AuthenticationBuilder<int>(
 | 
			
		||||
              authenticated: (context, sessionWrapper) => Text(
 | 
			
		||||
                  'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'),
 | 
			
		||||
              authenticated: (context, session) => Text(
 | 
			
		||||
                  'Logged as ${session.account?.email} | GeneratedId is ${session.data}'),
 | 
			
		||||
              unauthenticated: (context) =>
 | 
			
		||||
                  const Text('Not logged (unauthenticated)'),
 | 
			
		||||
              unknown: (context) => const Text('Not logged (unknown)'),
 | 
			
		||||
 | 
			
		||||
@ -17,26 +17,82 @@
 | 
			
		||||
import 'package:flutter/widgets.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/session.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/entities/authentication_change_event/authentication_change_event.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart';
 | 
			
		||||
 | 
			
		||||
/// Extension that helps to quickly access useful resources like wrapper,
 | 
			
		||||
/// session, account or data.
 | 
			
		||||
extension BuildContextExtension on BuildContext {
 | 
			
		||||
  /// Returns session wrapper
 | 
			
		||||
  SessionWrapper<Data>? wrapper<T extends AuthenticationCubit<Data>, Data>() =>
 | 
			
		||||
      watch<T>().currentSession();
 | 
			
		||||
  /// Read session in context from a specific AuthenticationCubit type [T]
 | 
			
		||||
  AuthenticationSession<Data>?
 | 
			
		||||
      readSessionFrom<T extends AuthenticationCubit<Data>, Data>() =>
 | 
			
		||||
          read<T>().currentSession();
 | 
			
		||||
 | 
			
		||||
  /// Returns session
 | 
			
		||||
  Session<Data>? session<T extends AuthenticationCubit<Data>, Data>() =>
 | 
			
		||||
      watch<T>().currentSession()?.session;
 | 
			
		||||
  /// Watch session in context from a specific AuthenticationCubit type [T]
 | 
			
		||||
  AuthenticationSession<Data>?
 | 
			
		||||
      watchSessionFrom<T extends AuthenticationCubit<Data>, Data>() =>
 | 
			
		||||
          watch<T>().currentSession();
 | 
			
		||||
 | 
			
		||||
  /// Returns account
 | 
			
		||||
  Account? account<T extends AuthenticationCubit<Data>, Data>() =>
 | 
			
		||||
      watch<T>().currentSession()?.session?.account;
 | 
			
		||||
  /// Read session in context from generic AuthenticationCubit type
 | 
			
		||||
  AuthenticationSession<Data>? readSession<Data>() =>
 | 
			
		||||
      read<AuthenticationCubit<Data>>().currentSession();
 | 
			
		||||
 | 
			
		||||
  /// Returns associated data
 | 
			
		||||
  Data? data<T extends AuthenticationCubit<Data>, Data>() =>
 | 
			
		||||
      watch<T>().currentSession()?.session?.data;
 | 
			
		||||
  /// Watch session in context from generic AuthenticationCubit type
 | 
			
		||||
  AuthenticationSession<Data>? watchSession<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/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/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/session_wrapper.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
@ -41,7 +41,7 @@ class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
    _checkForCachedAccount();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  late StreamController<SessionWrapper<Data>> _sessionStream;
 | 
			
		||||
  late StreamController<AuthenticationSession<Data>> _sessionStream;
 | 
			
		||||
  late StreamController<UserCredential?> _latestCredentials;
 | 
			
		||||
 | 
			
		||||
  final FirebaseAuth _firebaseAuth;
 | 
			
		||||
@ -51,8 +51,11 @@ class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
    final currentUser = _firebaseAuth.currentUser;
 | 
			
		||||
 | 
			
		||||
    if (currentUser == null) {
 | 
			
		||||
      _sessionStream
 | 
			
		||||
          .add(const SessionWrapper(event: UnknownAuthenticationEvent()));
 | 
			
		||||
      _sessionStream.add(
 | 
			
		||||
        const AuthenticationSession(
 | 
			
		||||
          latestEvent: UnknownAuthenticationEvent(),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -62,7 +65,9 @@ class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
      accessToken: jwt,
 | 
			
		||||
    );
 | 
			
		||||
    _sessionStream.add(
 | 
			
		||||
      SessionWrapper(event: SignedInFromCacheEvent(account: currentAccount)),
 | 
			
		||||
      AuthenticationSession.fromEvent(
 | 
			
		||||
        SignedInFromCacheEvent(account: currentAccount),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@ -78,19 +83,23 @@ class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
    return account;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Stream related methods ===================================================
 | 
			
		||||
  // Session related methods ===================================================
 | 
			
		||||
 | 
			
		||||
  /// {@macro add_session}
 | 
			
		||||
  @override
 | 
			
		||||
  void addSession(SessionWrapper<Data> wrapper) {
 | 
			
		||||
    _sessionStream.add(wrapper);
 | 
			
		||||
  void addSession(AuthenticationSession<Data> session) {
 | 
			
		||||
    _sessionStream.add(session);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// {@macro session_stream}
 | 
			
		||||
  @override
 | 
			
		||||
  Stream<SessionWrapper<Data>> sessionStream() =>
 | 
			
		||||
  Stream<AuthenticationSession<Data>> sessionStream() =>
 | 
			
		||||
      _sessionStream.stream.asBroadcastStream();
 | 
			
		||||
 | 
			
		||||
  /// {@macro current_session}
 | 
			
		||||
  @override
 | 
			
		||||
  Future<AuthenticationSession<Data>> currentSession() => sessionStream().last;
 | 
			
		||||
 | 
			
		||||
  // SignUp/SignIn methods ====================================================
 | 
			
		||||
 | 
			
		||||
  /// {@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/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/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_form_bloc/wyatt_form_bloc.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
@ -73,18 +73,30 @@ class AuthenticationRepositoryImpl<Data extends Object>
 | 
			
		||||
  @override
 | 
			
		||||
  FormRepository get formRepository => _formRepository;
 | 
			
		||||
 | 
			
		||||
  // Stream related methods ===================================================
 | 
			
		||||
  // Session related methods ===================================================
 | 
			
		||||
 | 
			
		||||
  /// {@macro add_session}
 | 
			
		||||
  @override
 | 
			
		||||
  void addSession(SessionWrapper<Data> wrapper) =>
 | 
			
		||||
      authenticationRemoteDataSource.addSession(wrapper);
 | 
			
		||||
  void addSession(AuthenticationSession<Data> session) =>
 | 
			
		||||
      authenticationRemoteDataSource.addSession(session);
 | 
			
		||||
 | 
			
		||||
  /// {@macro session_stream}
 | 
			
		||||
  @override
 | 
			
		||||
  Stream<SessionWrapper<Data>> sessionStream() =>
 | 
			
		||||
  Stream<AuthenticationSession<Data>> 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 ====================================================
 | 
			
		||||
 | 
			
		||||
  /// {@macro signup_pwd}
 | 
			
		||||
 | 
			
		||||
@ -16,16 +16,16 @@
 | 
			
		||||
 | 
			
		||||
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/session_wrapper.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart';
 | 
			
		||||
 | 
			
		||||
/// Is responsible for abstracting the provenance of the data.
 | 
			
		||||
abstract class AuthenticationRemoteDataSource<Data>
 | 
			
		||||
    extends BaseRemoteDataSource {
 | 
			
		||||
  // Stream related methods ===================================================
 | 
			
		||||
  // Session related methods ===================================================
 | 
			
		||||
 | 
			
		||||
  void addSession(SessionWrapper<Data> wrapper);
 | 
			
		||||
 | 
			
		||||
  Stream<SessionWrapper<Data>> sessionStream();
 | 
			
		||||
  void addSession(AuthenticationSession<Data> session);
 | 
			
		||||
  Stream<AuthenticationSession<Data>> sessionStream();
 | 
			
		||||
  Future<AuthenticationSession<Data>> currentSession();
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:equatable/equatable.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
 | 
			
		||||
part of 'authentication_change_event.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 Data? data;
 | 
			
		||||
  
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account, data];
 | 
			
		||||
 | 
			
		||||
  @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_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_from_cache_event.dart';
 | 
			
		||||
part 'signed_out_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 'signed_in_from_cache_event.dart';
 | 
			
		||||
part 'deleted_event.dart';
 | 
			
		||||
part 'updated_event.dart';
 | 
			
		||||
 | 
			
		||||
/// Represents an event initiated by a change in
 | 
			
		||||
/// the user's authentication status.
 | 
			
		||||
 | 
			
		||||
@ -16,14 +16,9 @@
 | 
			
		||||
 | 
			
		||||
part of 'authentication_change_event.dart';
 | 
			
		||||
 | 
			
		||||
/// When a user re-authenticates (from the logged in state to the 
 | 
			
		||||
/// logged in state with a different and fresh access 
 | 
			
		||||
/// When a user re-authenticates (from the logged in state to the
 | 
			
		||||
/// logged in state with a different and fresh access
 | 
			
		||||
/// token and a different login time)
 | 
			
		||||
class ReauthenticatedEvent extends AuthenticationChangeEvent {
 | 
			
		||||
  const ReauthenticatedEvent({required this.account});
 | 
			
		||||
 | 
			
		||||
  final Account account;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account];
 | 
			
		||||
class ReauthenticatedEvent extends AuthenticatedChangeEvent {
 | 
			
		||||
  const ReauthenticatedEvent({required super.account});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,13 +16,8 @@
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
class RefreshedEvent extends AuthenticationChangeEvent {
 | 
			
		||||
  const RefreshedEvent({required this.account});
 | 
			
		||||
 | 
			
		||||
  final Account account;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account];
 | 
			
		||||
class RefreshedEvent extends AuthenticatedChangeEvent {
 | 
			
		||||
  const RefreshedEvent({required super.account});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,6 @@
 | 
			
		||||
part of 'authentication_change_event.dart';
 | 
			
		||||
 | 
			
		||||
/// When a user authenticates (from not logged in to logged in).
 | 
			
		||||
class SignedInEvent extends AuthenticationChangeEvent {
 | 
			
		||||
  const SignedInEvent({required this.account});
 | 
			
		||||
 | 
			
		||||
  final Account account;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account];
 | 
			
		||||
class SignedInEvent extends AuthenticatedChangeEvent {
 | 
			
		||||
  const SignedInEvent({required super.account});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,6 @@
 | 
			
		||||
part of 'authentication_change_event.dart';
 | 
			
		||||
 | 
			
		||||
/// When a user authenticates automatically (from not logged in to logged in).
 | 
			
		||||
class SignedInFromCacheEvent extends AuthenticationChangeEvent {
 | 
			
		||||
  const SignedInFromCacheEvent({required this.account});
 | 
			
		||||
 | 
			
		||||
  final Account account;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account];
 | 
			
		||||
class SignedInFromCacheEvent extends AuthenticatedChangeEvent {
 | 
			
		||||
  const SignedInFromCacheEvent({required super.account});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,6 @@
 | 
			
		||||
part of 'authentication_change_event.dart';
 | 
			
		||||
 | 
			
		||||
/// When a user creates an account.
 | 
			
		||||
class SignedUpEvent extends AuthenticationChangeEvent {
 | 
			
		||||
  const SignedUpEvent({required this.account});
 | 
			
		||||
 | 
			
		||||
  final Account account;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account];
 | 
			
		||||
class SignedUpEvent extends AuthenticatedChangeEvent {
 | 
			
		||||
  const SignedUpEvent({required super.account});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,6 @@
 | 
			
		||||
part of 'authentication_change_event.dart';
 | 
			
		||||
 | 
			
		||||
/// When the user's account has been updated.
 | 
			
		||||
class UpdatedEvent extends AuthenticationChangeEvent {
 | 
			
		||||
  const UpdatedEvent({required this.account});
 | 
			
		||||
 | 
			
		||||
  final Account account;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [account];
 | 
			
		||||
class UpdatedEvent extends AuthenticatedChangeEvent {
 | 
			
		||||
  const UpdatedEvent({required super.account});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,5 @@
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
export 'account.dart';
 | 
			
		||||
export 'auth_session.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_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';
 | 
			
		||||
 | 
			
		||||
abstract class AuthenticationRepository<Data> extends BaseRepository {
 | 
			
		||||
@ -30,12 +30,17 @@ abstract class AuthenticationRepository<Data> extends BaseRepository {
 | 
			
		||||
  /// {@template add_session}
 | 
			
		||||
  /// Add a new authentication event.
 | 
			
		||||
  /// {@endtemplate}
 | 
			
		||||
  void addSession(SessionWrapper<Data> wrapper);
 | 
			
		||||
  void addSession(AuthenticationSession<Data> session);
 | 
			
		||||
 | 
			
		||||
  /// {@template session_stream}
 | 
			
		||||
  /// Authentication state change event stream.
 | 
			
		||||
  /// {@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 ====================================================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
import 'package:flutter/material.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/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';
 | 
			
		||||
 | 
			
		||||
class AuthenticationBuilder<Data> extends StatelessWidget {
 | 
			
		||||
@ -30,7 +30,7 @@ class AuthenticationBuilder<Data> extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  final Widget Function(
 | 
			
		||||
    BuildContext context,
 | 
			
		||||
    SessionWrapper<Data> sessionWrapper,
 | 
			
		||||
    AuthenticationSession<Data> session,
 | 
			
		||||
  ) authenticated;
 | 
			
		||||
  final Widget Function(BuildContext context) unauthenticated;
 | 
			
		||||
  final Widget Function(BuildContext context) unknown;
 | 
			
		||||
@ -40,8 +40,8 @@ class AuthenticationBuilder<Data> extends StatelessWidget {
 | 
			
		||||
      BlocBuilder<AuthenticationCubit<Data>, AuthenticationState<Data>>(
 | 
			
		||||
        builder: (context, state) {
 | 
			
		||||
          if (state.status == AuthenticationStatus.authenticated) {
 | 
			
		||||
            if (state.wrapper != null) {
 | 
			
		||||
              return authenticated(context, state.wrapper!);
 | 
			
		||||
            if (state.session != null) {
 | 
			
		||||
              return authenticated(context, state.session!);
 | 
			
		||||
            } else {
 | 
			
		||||
              return unauthenticated(context);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -42,35 +42,31 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
  }
 | 
			
		||||
  final AuthenticationRepository<Data> authenticationRepository;
 | 
			
		||||
 | 
			
		||||
  SessionWrapper<Data>? _latestSession;
 | 
			
		||||
  AuthenticationSession<Data>? _latestSession;
 | 
			
		||||
 | 
			
		||||
  void _listenForAuthenticationChanges() {
 | 
			
		||||
    authenticationRepository.sessionStream().asyncMap((wrapper) async {
 | 
			
		||||
      final event = wrapper.event;
 | 
			
		||||
    authenticationRepository.sessionStream().asyncMap((session) async {
 | 
			
		||||
      final event = session.latestEvent;
 | 
			
		||||
      if (event is SignedInFromCacheEvent) {
 | 
			
		||||
        final customRoutineResult = await onSignInFromCache(wrapper);
 | 
			
		||||
        final customRoutineResult = await onSignInFromCache(session);
 | 
			
		||||
 | 
			
		||||
        if (customRoutineResult.isOk) {
 | 
			
		||||
          final account = event.account;
 | 
			
		||||
          final sessionData = customRoutineResult.ok;
 | 
			
		||||
 | 
			
		||||
          final signedInSession = SessionWrapper(
 | 
			
		||||
            event: SignedInFromCacheEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: sessionData,
 | 
			
		||||
            ),
 | 
			
		||||
          final signedInSession = AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInFromCacheEvent(account: account),
 | 
			
		||||
            data: sessionData,
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          return signedInSession;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return wrapper;
 | 
			
		||||
    }).listen((wrapper) async {
 | 
			
		||||
      _latestSession = wrapper;
 | 
			
		||||
      final session = wrapper.session;
 | 
			
		||||
      if (session != null) {
 | 
			
		||||
        emit(AuthenticationState<Data>.authenticated(wrapper));
 | 
			
		||||
      return session;
 | 
			
		||||
    }).listen((session) async {
 | 
			
		||||
      _latestSession = session;
 | 
			
		||||
      if (session.account != null) {
 | 
			
		||||
        emit(AuthenticationState<Data>.authenticated(session));
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      emit(AuthenticationState<Data>.unauthenticated());
 | 
			
		||||
@ -80,19 +76,16 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
 | 
			
		||||
  /// {@macro refresh}
 | 
			
		||||
  FutureOr<void> refresh() async => CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: authenticationRepository.refresh,
 | 
			
		||||
      attachedLogic: onRefresh,
 | 
			
		||||
      onError: addError,
 | 
			
		||||
      onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
        SessionWrapper(
 | 
			
		||||
          event: RefreshedEvent(account: result),
 | 
			
		||||
          session: Session<Data>(
 | 
			
		||||
            account: result,
 | 
			
		||||
        routine: authenticationRepository.refresh,
 | 
			
		||||
        attachedLogic: onRefresh,
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            RefreshedEvent(account: result),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    ).call();
 | 
			
		||||
      ).call();
 | 
			
		||||
 | 
			
		||||
  /// {@macro reauthenticate}
 | 
			
		||||
  FutureOr<void> reauthenticate() async => CustomRoutine<Account, Data?>(
 | 
			
		||||
@ -100,12 +93,9 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
        attachedLogic: onReauthenticate,
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: ReauthenticatedEvent(account: result),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: result,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            ReauthenticatedEvent(account: result),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ).call();
 | 
			
		||||
@ -115,8 +105,11 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
        routine: authenticationRepository.signOut,
 | 
			
		||||
        attachedLogic: (routineResult) => onSignOut(),
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository
 | 
			
		||||
            .addSession(SessionWrapper<Data>(event: const SignedOutEvent())),
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
          const AuthenticationSession(
 | 
			
		||||
            latestEvent: SignedOutEvent(),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ).call();
 | 
			
		||||
 | 
			
		||||
  /// {@macro delete}
 | 
			
		||||
@ -124,20 +117,23 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
        routine: authenticationRepository.delete,
 | 
			
		||||
        attachedLogic: (routineResult) => onDelete(),
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository
 | 
			
		||||
            .addSession(SessionWrapper<Data>(event: const DeletedEvent())),
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
          const AuthenticationSession(
 | 
			
		||||
            latestEvent: DeletedEvent(),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ).call();
 | 
			
		||||
 | 
			
		||||
  /// Returns latest session wrapper.
 | 
			
		||||
  /// Returns latest session.
 | 
			
		||||
  ///
 | 
			
		||||
  /// 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
 | 
			
		||||
  /// the 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.
 | 
			
		||||
  ///
 | 
			
		||||
 | 
			
		||||
@ -17,25 +17,25 @@
 | 
			
		||||
part of 'authentication_cubit.dart';
 | 
			
		||||
 | 
			
		||||
class AuthenticationState<Data> extends Equatable {
 | 
			
		||||
  const AuthenticationState._(this.status, this.wrapper);
 | 
			
		||||
  const AuthenticationState._(this.status, this.session);
 | 
			
		||||
 | 
			
		||||
  const AuthenticationState.unauthenticated()
 | 
			
		||||
      : this._(AuthenticationStatus.unauthenticated, null);
 | 
			
		||||
 | 
			
		||||
  const AuthenticationState.authenticated(SessionWrapper<Data> sessionWrapper)
 | 
			
		||||
  const AuthenticationState.authenticated(AuthenticationSession<Data> session)
 | 
			
		||||
      : this._(
 | 
			
		||||
          AuthenticationStatus.authenticated,
 | 
			
		||||
          sessionWrapper,
 | 
			
		||||
          session,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
  const AuthenticationState.unknown()
 | 
			
		||||
      : this._(AuthenticationStatus.unknown, null);
 | 
			
		||||
 | 
			
		||||
  final AuthenticationStatus status;
 | 
			
		||||
  final SessionWrapper<Data>? wrapper;
 | 
			
		||||
  final AuthenticationSession<Data>? session;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object?> get props => [status, wrapper];
 | 
			
		||||
  List<Object?> get props => [status, session];
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool? get stringify => true;
 | 
			
		||||
 | 
			
		||||
@ -111,12 +111,9 @@ mixin UpdateEmail<Data> on BaseEditAccountCubit<Data> {
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: UpdatedEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            UpdatedEvent(account: account),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
 | 
			
		||||
@ -110,12 +110,9 @@ mixin UpdatePassword<Data> on BaseEditAccountCubit<Data> {
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            UpdatedEvent(account: account),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
 | 
			
		||||
@ -31,12 +31,13 @@ class EmailVerificationCubit<Data> extends Cubit<EmailVerificationState> {
 | 
			
		||||
  final AuthenticationRepository<Data> authenticationRepository;
 | 
			
		||||
 | 
			
		||||
  FutureOr<void> sendEmailVerification() async {
 | 
			
		||||
    emit(state.copyWith(status: FormStatus.submissionInProgress));
 | 
			
		||||
    emit(const EmailVerificationState(status: FormStatus.submissionInProgress));
 | 
			
		||||
    final response = await authenticationRepository.sendEmailVerification();
 | 
			
		||||
    emit(
 | 
			
		||||
      response.fold(
 | 
			
		||||
        (value) => state.copyWith(status: FormStatus.submissionSuccess),
 | 
			
		||||
        (error) => state.copyWith(
 | 
			
		||||
        (value) =>
 | 
			
		||||
            const EmailVerificationState(status: FormStatus.submissionSuccess),
 | 
			
		||||
        (error) => EmailVerificationState(
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
@ -45,7 +46,7 @@ class EmailVerificationCubit<Data> extends Cubit<EmailVerificationState> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FutureOr<void> checkEmailVerification() async {
 | 
			
		||||
    emit(state.copyWith(status: FormStatus.submissionInProgress));
 | 
			
		||||
    emit(const EmailVerificationState(status: FormStatus.submissionInProgress));
 | 
			
		||||
 | 
			
		||||
    final refresh = await authenticationRepository.refresh();
 | 
			
		||||
    if (refresh.isErr) {
 | 
			
		||||
@ -59,11 +60,11 @@ class EmailVerificationCubit<Data> extends Cubit<EmailVerificationState> {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final wrapper = await authenticationRepository.sessionStream().last;
 | 
			
		||||
    final currentAccount = wrapper.session?.account;
 | 
			
		||||
    final session = await authenticationRepository.currentSession();
 | 
			
		||||
    final currentAccount = session.ok?.account;
 | 
			
		||||
    if (currentAccount != null) {
 | 
			
		||||
      emit(
 | 
			
		||||
        state.copyWith(
 | 
			
		||||
        EmailVerificationState(
 | 
			
		||||
          isVerified: currentAccount.emailVerified,
 | 
			
		||||
          status: FormStatus.submissionSuccess,
 | 
			
		||||
        ),
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
@ -18,16 +17,16 @@
 | 
			
		||||
part of 'email_verification_cubit.dart';
 | 
			
		||||
 | 
			
		||||
class EmailVerificationState extends Equatable {
 | 
			
		||||
  final FormStatus status;
 | 
			
		||||
  final bool isVerified;
 | 
			
		||||
  final String? errorMessage;
 | 
			
		||||
 | 
			
		||||
  const EmailVerificationState({
 | 
			
		||||
    this.isVerified = false,
 | 
			
		||||
    this.status = FormStatus.pure,
 | 
			
		||||
    this.errorMessage,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  final FormStatus status;
 | 
			
		||||
  final bool isVerified;
 | 
			
		||||
  final String? errorMessage;
 | 
			
		||||
 | 
			
		||||
  EmailVerificationState copyWith({
 | 
			
		||||
    FormStatus? status,
 | 
			
		||||
    bool? isVerified,
 | 
			
		||||
 | 
			
		||||
@ -63,12 +63,9 @@ mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInEvent(account: account),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
 | 
			
		||||
@ -136,12 +136,9 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInEvent(account: account),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
 | 
			
		||||
@ -62,12 +62,9 @@ mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInEvent(account: account),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
 | 
			
		||||
@ -126,12 +126,9 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedUpEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedUpEvent(account: account),
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,9 @@ class TestAuthenticationCubit extends AuthenticationCubit<int> {
 | 
			
		||||
      const Ok(null);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) async =>
 | 
			
		||||
  FutureOrResult<int?> onSignInFromCache(
 | 
			
		||||
    AuthenticationSession<int> session,
 | 
			
		||||
  ) async =>
 | 
			
		||||
      const Ok(null);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@ -53,9 +55,10 @@ class TestAuthenticationCubit extends AuthenticationCubit<int> {
 | 
			
		||||
void main() {
 | 
			
		||||
  group('AuthenticationCubit<T>', () {
 | 
			
		||||
    final MockAccount account = MockAccount();
 | 
			
		||||
    final SessionWrapper<int> wrapper = SessionWrapper(
 | 
			
		||||
      event: const UnknownAuthenticationEvent(),
 | 
			
		||||
      session: Session(account: account, data: 10),
 | 
			
		||||
    final AuthenticationSession<int> session = AuthenticationSession<int>(
 | 
			
		||||
      latestEvent: const UnknownAuthenticationEvent(),
 | 
			
		||||
      account: account,
 | 
			
		||||
      data: 10,
 | 
			
		||||
    );
 | 
			
		||||
    late AuthenticationRepository<int> authenticationRepository;
 | 
			
		||||
 | 
			
		||||
@ -80,14 +83,14 @@ void main() {
 | 
			
		||||
        'emits authenticated when stream contains session',
 | 
			
		||||
        setUp: () {
 | 
			
		||||
          when(() => authenticationRepository.sessionStream()).thenAnswer(
 | 
			
		||||
            (_) => Stream.fromIterable([wrapper]),
 | 
			
		||||
            (_) => Stream.fromIterable([session]),
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        build: () => TestAuthenticationCubit(
 | 
			
		||||
          authenticationRepository: authenticationRepository,
 | 
			
		||||
        ),
 | 
			
		||||
        seed: () => const AuthenticationState.unknown(),
 | 
			
		||||
        expect: () => [AuthenticationState<int>.authenticated(wrapper)],
 | 
			
		||||
        expect: () => [AuthenticationState<int>.authenticated(session)],
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
 | 
			
		||||
@ -95,7 +98,8 @@ void main() {
 | 
			
		||||
        setUp: () {
 | 
			
		||||
          when(() => authenticationRepository.sessionStream()).thenAnswer(
 | 
			
		||||
            (_) => Stream.fromIterable(
 | 
			
		||||
                [const SessionWrapper(event: SignedOutEvent())],),
 | 
			
		||||
              [const AuthenticationSession(latestEvent: SignedOutEvent())],
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        build: () => TestAuthenticationCubit(
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ void main() {
 | 
			
		||||
        const AuthenticationState<void> state =
 | 
			
		||||
            AuthenticationState.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 AuthenticationState<void> state =
 | 
			
		||||
            AuthenticationState.authenticated(
 | 
			
		||||
          SessionWrapper<void>(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session(account: account),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInEvent(account: account),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        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';
 | 
			
		||||
        final AuthenticationState<String> state =
 | 
			
		||||
            AuthenticationState.authenticated(
 | 
			
		||||
          SessionWrapper<String>(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session(account: account, data: extra),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInEvent(account: account),
 | 
			
		||||
            data: extra,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        expect(state.status, AuthenticationStatus.authenticated);
 | 
			
		||||
        expect(state.wrapper?.session?.account, account);
 | 
			
		||||
        expect(state.wrapper?.session?.data, extra);
 | 
			
		||||
        expect(state.session?.account, account);
 | 
			
		||||
        expect(state.session?.data, extra);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@ -43,13 +43,24 @@ void main() {
 | 
			
		||||
 | 
			
		||||
      when(() => authenticationRepository.sessionStream()).thenAnswer(
 | 
			
		||||
        (_) => Stream.fromIterable([
 | 
			
		||||
          SessionWrapper<int>(
 | 
			
		||||
            event: SignedInFromCacheEvent(account: account),
 | 
			
		||||
            session: Session<int>(account: account, data: 10),
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInFromCacheEvent(account: account),
 | 
			
		||||
            data: 10,
 | 
			
		||||
          )
 | 
			
		||||
        ]),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      when(
 | 
			
		||||
        () => authenticationRepository.currentSession(),
 | 
			
		||||
      ).thenAnswer(
 | 
			
		||||
        (_) async => Ok(
 | 
			
		||||
          AuthenticationSession.fromEvent(
 | 
			
		||||
            SignedInFromCacheEvent(account: account),
 | 
			
		||||
            data: 10,
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      when(
 | 
			
		||||
        () => authenticationRepository.refresh(),
 | 
			
		||||
      ).thenAnswer((_) async => Ok(account));
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user