Compare commits
	
		
			4 Commits
		
	
	
		
			0c920e8245
			...
			6802a56bfc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6802a56bfc | |||
| b2a9dac7c6 | |||
| c0a91d6437 | |||
| 59bd3edb0d | 
@ -25,7 +25,7 @@ abstract class GetItInitializer {
 | 
				
			|||||||
      ..registerLazySingleton<AuthenticationRemoteDataSource>(
 | 
					      ..registerLazySingleton<AuthenticationRemoteDataSource>(
 | 
				
			||||||
        () => AuthenticationFirebaseDataSourceImpl(),
 | 
					        () => AuthenticationFirebaseDataSourceImpl(),
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
      ..registerLazySingleton<AuthenticationLocalDataSource<int>>(
 | 
					      ..registerLazySingleton<AuthenticationCacheDataSource<int>>(
 | 
				
			||||||
        () => AuthenticationCacheDataSourceImpl<int>(),
 | 
					        () => AuthenticationCacheDataSourceImpl<int>(),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
				
			|||||||
@ -1,21 +0,0 @@
 | 
				
			|||||||
// Author: Hugo Pointcheval
 | 
					 | 
				
			||||||
// Email: git@pcl.ovh
 | 
					 | 
				
			||||||
// -----
 | 
					 | 
				
			||||||
// File: forms.dart
 | 
					 | 
				
			||||||
// Created Date: 19/08/2022 12:00:31
 | 
					 | 
				
			||||||
// Last Modified: 19/08/2022 16:35:52
 | 
					 | 
				
			||||||
// -----
 | 
					 | 
				
			||||||
// Copyright (c) 2022
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import 'package:example_router/core/constants/form_field.dart';
 | 
					 | 
				
			||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Forms {
 | 
					 | 
				
			||||||
  static FormData getNormalData() => const FormData([
 | 
					 | 
				
			||||||
        FormInput(
 | 
					 | 
				
			||||||
          AppFormField.confirmedPassword,
 | 
					 | 
				
			||||||
          ConfirmedPassword.pure(),
 | 
					 | 
				
			||||||
          metadata: FormInputMetadata<void>(export: false),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -3,33 +3,58 @@
 | 
				
			|||||||
// -----
 | 
					// -----
 | 
				
			||||||
// File: app.dart
 | 
					// File: app.dart
 | 
				
			||||||
// Created Date: 19/08/2022 12:05:38
 | 
					// Created Date: 19/08/2022 12:05:38
 | 
				
			||||||
// Last Modified: Wed Nov 09 2022
 | 
					// Last Modified: Thu Nov 10 2022
 | 
				
			||||||
// -----
 | 
					// -----
 | 
				
			||||||
// Copyright (c) 2022
 | 
					// Copyright (c) 2022
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					import 'dart:math';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:example_router/core/constants/form_field.dart';
 | 
				
			||||||
import 'package:example_router/core/dependency_injection/get_it.dart';
 | 
					import 'package:example_router/core/dependency_injection/get_it.dart';
 | 
				
			||||||
import 'package:example_router/core/routes/router.dart';
 | 
					import 'package:example_router/core/routes/router.dart';
 | 
				
			||||||
import 'package:example_router/core/utils/forms.dart';
 | 
					 | 
				
			||||||
import 'package:example_router/presentation/features/home/home_page.dart';
 | 
					 | 
				
			||||||
import 'package:example_router/presentation/features/welcome/welcome_page.dart';
 | 
					 | 
				
			||||||
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:go_router/go_router.dart';
 | 
					import 'package:go_router/go_router.dart';
 | 
				
			||||||
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
					import 'package:wyatt_authentication_bloc/wyatt_authentication_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';
 | 
				
			||||||
 | 
					import 'package:wyatt_architecture/wyatt_architecture.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FutureResult<int?> onSignUpSuccess(
 | 
				
			||||||
 | 
					  Account? account,
 | 
				
			||||||
 | 
					  WyattForm form,
 | 
				
			||||||
 | 
					) async {
 | 
				
			||||||
 | 
					  const id = -1;
 | 
				
			||||||
 | 
					  final confirmedPassword =
 | 
				
			||||||
 | 
					      form.valueOf<String?>(AppFormField.confirmedPassword);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  debugPrint(
 | 
				
			||||||
 | 
					      'onSignUpSuccess: $account, generatedId: $id, extraFormData: $confirmedPassword');
 | 
				
			||||||
 | 
					  return const Ok<int, AppException>(id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FutureResult<int?> onAccountChanges(Account? account) async {
 | 
				
			||||||
 | 
					  final id = Random().nextInt(1000);
 | 
				
			||||||
 | 
					  debugPrint('onAccountChanges: $account, generatedId: $id');
 | 
				
			||||||
 | 
					  return Ok<int, AppException>(id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class App extends StatelessWidget {
 | 
					class App extends StatelessWidget {
 | 
				
			||||||
  final AuthenticationRepository<int> authenticationRepository =
 | 
					  final AuthenticationRepository<int> authenticationRepository =
 | 
				
			||||||
      AuthenticationRepositoryImpl(getIt<AuthenticationLocalDataSource<int>>(),
 | 
					      AuthenticationRepositoryImpl(
 | 
				
			||||||
          getIt<AuthenticationRemoteDataSource>(), (account) async {
 | 
					    authenticationCacheDataSource: getIt<AuthenticationCacheDataSource<int>>(),
 | 
				
			||||||
    debugPrint('onSignUpSuccess: $account');
 | 
					    authenticationRemoteDataSource: getIt<AuthenticationRemoteDataSource>(),
 | 
				
			||||||
    return const Ok(null);
 | 
					    onSignUpSuccess: onSignUpSuccess,
 | 
				
			||||||
  }, (account) async {
 | 
					    onAuthChange: onAccountChanges,
 | 
				
			||||||
    debugPrint('onAccountChanges: $account');
 | 
					    extraSignUpInputs: [
 | 
				
			||||||
    return const Ok(null);
 | 
					      FormInput(
 | 
				
			||||||
  });
 | 
					        AppFormField.confirmedPassword,
 | 
				
			||||||
 | 
					        const ConfirmedPassword.pure(),
 | 
				
			||||||
 | 
					        metadata: const FormInputMetadata<void>(export: false),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  App({Key? key}) : super(key: key);
 | 
					  App({Key? key}) : super(key: key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -65,12 +90,12 @@ class App extends StatelessWidget {
 | 
				
			|||||||
            if (isOnboarding) {
 | 
					            if (isOnboarding) {
 | 
				
			||||||
              return null;
 | 
					              return null;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              return state.namedLocation(WelcomePage.pageName);
 | 
					              return '/';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            debugPrint('Logged');
 | 
					            debugPrint('Logged');
 | 
				
			||||||
            if (isOnboarding) {
 | 
					            if (isOnboarding) {
 | 
				
			||||||
              return state.namedLocation(HomePage.pageName);
 | 
					              return '/home';
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              return null;
 | 
					              return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -91,13 +116,12 @@ class App extends StatelessWidget {
 | 
				
			|||||||
          BlocProvider<AuthenticationCubit<int>>.value(
 | 
					          BlocProvider<AuthenticationCubit<int>>.value(
 | 
				
			||||||
            value: authenticationCubit,
 | 
					            value: authenticationCubit,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          BlocProvider<SignUpCubit>(
 | 
					          BlocProvider<SignUpCubit<int>>(
 | 
				
			||||||
            create: (_) => SignUpCubit(
 | 
					            create: (_) => SignUpCubit(
 | 
				
			||||||
              authenticationRepository: authenticationRepository,
 | 
					              authenticationRepository: authenticationRepository,
 | 
				
			||||||
              formData: Forms.getNormalData(),
 | 
					 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          BlocProvider<SignInCubit>(
 | 
					          BlocProvider<SignInCubit<int>>(
 | 
				
			||||||
            create: (_) => SignInCubit(
 | 
					            create: (_) => SignInCubit(
 | 
				
			||||||
              authenticationRepository: authenticationRepository,
 | 
					              authenticationRepository: authenticationRepository,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
@ -106,9 +130,7 @@ class App extends StatelessWidget {
 | 
				
			|||||||
        child: MaterialApp.router(
 | 
					        child: MaterialApp.router(
 | 
				
			||||||
          title: 'Demo Authentication',
 | 
					          title: 'Demo Authentication',
 | 
				
			||||||
          debugShowCheckedModeBanner: false,
 | 
					          debugShowCheckedModeBanner: false,
 | 
				
			||||||
          routerDelegate: router.routerDelegate,
 | 
					          routerConfig: router,
 | 
				
			||||||
          routeInformationParser: router.routeInformationParser,
 | 
					 | 
				
			||||||
          routeInformationProvider: router.routeInformationProvider,
 | 
					 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,7 @@ class HomePage extends StatelessWidget {
 | 
				
			|||||||
            children: [
 | 
					            children: [
 | 
				
			||||||
              AuthenticationBuilder<int>(
 | 
					              AuthenticationBuilder<int>(
 | 
				
			||||||
                authenticated: (context, accountWrapper) =>
 | 
					                authenticated: (context, accountWrapper) =>
 | 
				
			||||||
                    Text('Logged as ${accountWrapper.account?.email}'),
 | 
					                    Text('Logged as ${accountWrapper.account?.email} | GeneratedId is ${accountWrapper.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)'),
 | 
				
			||||||
 | 
				
			|||||||
@ -3,30 +3,31 @@
 | 
				
			|||||||
// -----
 | 
					// -----
 | 
				
			||||||
// File: sign_in_form.dart
 | 
					// File: sign_in_form.dart
 | 
				
			||||||
// Created Date: 19/08/2022 15:24:37
 | 
					// Created Date: 19/08/2022 15:24:37
 | 
				
			||||||
// Last Modified: Wed Nov 09 2022
 | 
					// Last Modified: Thu Nov 10 2022
 | 
				
			||||||
// -----
 | 
					// -----
 | 
				
			||||||
// Copyright (c) 2022
 | 
					// Copyright (c) 2022
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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/wyatt_authentication_bloc.dart';
 | 
					import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
				
			||||||
 | 
					import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _EmailInput extends StatelessWidget {
 | 
					class _EmailInput extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignInCubit, SignInState>(
 | 
					    return InputBuilder<SignInCubit<int>>(
 | 
				
			||||||
      buildWhen: (previous, current) => previous.email != current.email,
 | 
					      field: AuthFormField.email,
 | 
				
			||||||
      builder: (context, state) {
 | 
					      builder: ((context, cubit, state, field, inputValid) {
 | 
				
			||||||
        return TextField(
 | 
					        return TextField(
 | 
				
			||||||
          onChanged: (email) => context.read<SignInCubit>().emailChanged(email),
 | 
					          onChanged: (email) => cubit.emailChanged(email),
 | 
				
			||||||
          keyboardType: TextInputType.emailAddress,
 | 
					          keyboardType: TextInputType.emailAddress,
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: 'Email',
 | 
					            labelText: 'Email',
 | 
				
			||||||
            helperText: '',
 | 
					            helperText: '',
 | 
				
			||||||
            errorText: state.email.invalid ? 'Invalid email' : null,
 | 
					            errorText: !inputValid ? 'Invalid email' : null,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -34,21 +35,19 @@ class _EmailInput extends StatelessWidget {
 | 
				
			|||||||
class _PasswordInput extends StatelessWidget {
 | 
					class _PasswordInput extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignInCubit, SignInState>(
 | 
					    return InputBuilder<SignInCubit<int>>(
 | 
				
			||||||
      buildWhen: (previous, current) => previous.password != current.password,
 | 
					      field: AuthFormField.password,
 | 
				
			||||||
      builder: (context, state) {
 | 
					      builder: ((context, cubit, state, field, inputValid) {
 | 
				
			||||||
        return TextField(
 | 
					        return TextField(
 | 
				
			||||||
          onChanged: (password) {
 | 
					          onChanged: (pwd) => cubit.passwordChanged(pwd),
 | 
				
			||||||
            context.read<SignInCubit>().passwordChanged(password);
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          obscureText: true,
 | 
					          obscureText: true,
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: 'Password',
 | 
					            labelText: 'Password',
 | 
				
			||||||
            helperText: '',
 | 
					            helperText: '',
 | 
				
			||||||
            errorText: state.password.invalid ? 'Invalid password' : null,
 | 
					            errorText: !inputValid ? 'Invalid password' : null,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -56,18 +55,15 @@ class _PasswordInput extends StatelessWidget {
 | 
				
			|||||||
class _SignInButton extends StatelessWidget {
 | 
					class _SignInButton extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignInCubit, SignInState>(
 | 
					    return SubmitBuilder<SignInCubit<int>>(
 | 
				
			||||||
      builder: (context, state) {
 | 
					      builder: ((context, cubit, status) {
 | 
				
			||||||
        return state.status.isSubmissionInProgress
 | 
					        return status.isSubmissionInProgress
 | 
				
			||||||
            ? const CircularProgressIndicator()
 | 
					            ? const CircularProgressIndicator()
 | 
				
			||||||
            : ElevatedButton(
 | 
					            : ElevatedButton(
 | 
				
			||||||
                onPressed: state.status.isValidated
 | 
					                onPressed: status.isValidated ? () => cubit.submit() : null,
 | 
				
			||||||
                    ? () =>
 | 
					 | 
				
			||||||
                        context.read<SignInCubit>().signInWithEmailAndPassword()
 | 
					 | 
				
			||||||
                    : null,
 | 
					 | 
				
			||||||
                child: const Text('Sign in'),
 | 
					                child: const Text('Sign in'),
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -77,7 +73,7 @@ class SignInForm extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocListener<SignInCubit, SignInState>(
 | 
					    return BlocListener<SignInCubit<int>, SignInState>(
 | 
				
			||||||
      listener: (context, state) {
 | 
					      listener: (context, state) {
 | 
				
			||||||
        if (state.status.isSubmissionFailure) {
 | 
					        if (state.status.isSubmissionFailure) {
 | 
				
			||||||
          ScaffoldMessenger.of(context)
 | 
					          ScaffoldMessenger.of(context)
 | 
				
			||||||
 | 
				
			|||||||
@ -3,12 +3,12 @@
 | 
				
			|||||||
// -----
 | 
					// -----
 | 
				
			||||||
// File: sign_up_form.dart
 | 
					// File: sign_up_form.dart
 | 
				
			||||||
// Created Date: 19/08/2022 14:41:08
 | 
					// Created Date: 19/08/2022 14:41:08
 | 
				
			||||||
// Last Modified: Fri Aug 26 2022
 | 
					// Last Modified: Thu Nov 10 2022
 | 
				
			||||||
// -----
 | 
					// -----
 | 
				
			||||||
// Copyright (c) 2022
 | 
					// Copyright (c) 2022
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:example_router/core/constants/form_field.dart';
 | 
					import 'package:example_router/core/constants/form_field.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart' hide FormField;
 | 
				
			||||||
import 'package:flutter_bloc/flutter_bloc.dart';
 | 
					import 'package:flutter_bloc/flutter_bloc.dart';
 | 
				
			||||||
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
					import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
				
			||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
					import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
				
			||||||
@ -16,19 +16,19 @@ import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
				
			|||||||
class _EmailInput extends StatelessWidget {
 | 
					class _EmailInput extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignUpCubit, SignUpState>(
 | 
					    return InputBuilder<SignUpCubit<int>>(
 | 
				
			||||||
      buildWhen: (previous, current) => previous.email != current.email,
 | 
					      field: AuthFormField.email,
 | 
				
			||||||
      builder: (context, state) {
 | 
					      builder: ((context, cubit, state, field, inputValid) {
 | 
				
			||||||
        return TextField(
 | 
					        return TextField(
 | 
				
			||||||
          onChanged: (email) => context.read<SignUpCubit>().emailChanged(email),
 | 
					          onChanged: (email) => cubit.emailChanged(email),
 | 
				
			||||||
          keyboardType: TextInputType.emailAddress,
 | 
					          keyboardType: TextInputType.emailAddress,
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: 'Email',
 | 
					            labelText: 'Email',
 | 
				
			||||||
            helperText: '',
 | 
					            helperText: '',
 | 
				
			||||||
            errorText: state.email.invalid ? 'Invalid email' : null,
 | 
					            errorText: !inputValid ? 'Invalid email' : null,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -36,33 +36,27 @@ class _EmailInput extends StatelessWidget {
 | 
				
			|||||||
class _PasswordInput extends StatelessWidget {
 | 
					class _PasswordInput extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignUpCubit, SignUpState>(
 | 
					    return InputBuilder<SignUpCubit<int>>(
 | 
				
			||||||
      buildWhen: (previous, current) => previous.password != current.password,
 | 
					      field: AuthFormField.password,
 | 
				
			||||||
      builder: (context, state) {
 | 
					      builder: ((context, cubit, state, field, inputValid) {
 | 
				
			||||||
        return TextField(
 | 
					        return TextField(
 | 
				
			||||||
          onChanged: (password) {
 | 
					          onChanged: (pwd) {
 | 
				
			||||||
            context.read<SignUpCubit>().passwordChanged(password);
 | 
					            cubit.passwordChanged(pwd);
 | 
				
			||||||
            context.read<SignUpCubit>().dataChanged(
 | 
					            cubit.dataChanged(
 | 
				
			||||||
                  AppFormField.confirmedPassword,
 | 
					                AppFormField.confirmedPassword,
 | 
				
			||||||
                  ConfirmedPassword.dirty(
 | 
					                ConfirmedPassword.dirty(
 | 
				
			||||||
                    password: password,
 | 
					                    password: pwd,
 | 
				
			||||||
                    value: context
 | 
					                    value: state.form
 | 
				
			||||||
                        .read<SignUpCubit>()
 | 
					                        .valueOf<String?>(AppFormField.confirmedPassword)));
 | 
				
			||||||
                        .state
 | 
					 | 
				
			||||||
                        .data
 | 
					 | 
				
			||||||
                        .valueOf<String>(
 | 
					 | 
				
			||||||
                            AppFormField.confirmedPassword),
 | 
					 | 
				
			||||||
                  ),
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          obscureText: true,
 | 
					          obscureText: true,
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: 'Password',
 | 
					            labelText: 'Password',
 | 
				
			||||||
            helperText: '',
 | 
					            helperText: '',
 | 
				
			||||||
            errorText: state.password.invalid ? 'Invalid password' : null,
 | 
					            errorText: !inputValid ? 'Invalid password' : null,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -70,28 +64,27 @@ class _PasswordInput extends StatelessWidget {
 | 
				
			|||||||
class _ConfirmPasswordInput extends StatelessWidget {
 | 
					class _ConfirmPasswordInput extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignUpCubit, SignUpState>(
 | 
					    return InputBuilder<SignUpCubit<int>>(
 | 
				
			||||||
      builder: (context, state) {
 | 
					      field: AppFormField.confirmedPassword,
 | 
				
			||||||
 | 
					      builder: ((context, cubit, state, field, inputValid) {
 | 
				
			||||||
        return TextField(
 | 
					        return TextField(
 | 
				
			||||||
          onChanged: (confirmPassword) => context
 | 
					          onChanged: (pwd) {
 | 
				
			||||||
              .read<SignUpCubit>()
 | 
					            cubit.dataChanged(
 | 
				
			||||||
              .dataChanged(
 | 
					              field,
 | 
				
			||||||
                AppFormField.confirmedPassword,
 | 
					              ConfirmedPassword.dirty(
 | 
				
			||||||
                ConfirmedPassword.dirty(
 | 
					                  password:
 | 
				
			||||||
                  password: context.read<SignUpCubit>().state.password.value,
 | 
					                      state.form.valueOf<String?>(AuthFormField.password) ?? '',
 | 
				
			||||||
                  value: confirmPassword,
 | 
					                  value: pwd),
 | 
				
			||||||
                ),
 | 
					            );
 | 
				
			||||||
              ),
 | 
					          },
 | 
				
			||||||
          obscureText: true,
 | 
					          obscureText: true,
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: 'Confirm password',
 | 
					            labelText: 'Confirm password',
 | 
				
			||||||
            helperText: '',
 | 
					            helperText: '',
 | 
				
			||||||
            errorText: state.data.isNotValid(AppFormField.confirmedPassword)
 | 
					            errorText: !inputValid ? 'Passwords do not match' : null,
 | 
				
			||||||
                ? 'Passwords do not match'
 | 
					 | 
				
			||||||
                : null,
 | 
					 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -99,17 +92,15 @@ class _ConfirmPasswordInput extends StatelessWidget {
 | 
				
			|||||||
class _SignUpButton extends StatelessWidget {
 | 
					class _SignUpButton extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocBuilder<SignUpCubit, SignUpState>(
 | 
					    return SubmitBuilder<SignUpCubit<int>>(
 | 
				
			||||||
      builder: (context, state) {
 | 
					      builder: ((context, cubit, status) {
 | 
				
			||||||
        return state.status.isSubmissionInProgress
 | 
					        return status.isSubmissionInProgress
 | 
				
			||||||
            ? const CircularProgressIndicator()
 | 
					            ? const CircularProgressIndicator()
 | 
				
			||||||
            : ElevatedButton(
 | 
					            : ElevatedButton(
 | 
				
			||||||
                onPressed: state.status.isValidated
 | 
					                onPressed: status.isValidated ? () => cubit.submit() : null,
 | 
				
			||||||
                    ? () => context.read<SignUpCubit>().signUpFormSubmitted()
 | 
					 | 
				
			||||||
                    : null,
 | 
					 | 
				
			||||||
                child: const Text('Sign up'),
 | 
					                child: const Text('Sign up'),
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
      },
 | 
					      }),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -119,11 +110,9 @@ class SignUpForm extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return BlocListener<SignUpCubit, SignUpState>(
 | 
					    return BlocListener<SignUpCubit<int>, SignUpState>(
 | 
				
			||||||
      listener: (context, state) {
 | 
					      listener: (context, state) {
 | 
				
			||||||
        if (state.status.isSubmissionSuccess) {
 | 
					        if (state.status.isSubmissionFailure) {
 | 
				
			||||||
          Navigator.of(context).pop();
 | 
					 | 
				
			||||||
        } else if (state.status.isSubmissionFailure) {
 | 
					 | 
				
			||||||
          ScaffoldMessenger.of(context)
 | 
					          ScaffoldMessenger.of(context)
 | 
				
			||||||
            ..hideCurrentSnackBar()
 | 
					            ..hideCurrentSnackBar()
 | 
				
			||||||
            ..showSnackBar(
 | 
					            ..showSnackBar(
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,12 @@ dependencies:
 | 
				
			|||||||
      ref: wyatt_form_bloc-v0.0.6
 | 
					      ref: wyatt_form_bloc-v0.0.6
 | 
				
			||||||
      path: packages/wyatt_form_bloc
 | 
					      path: packages/wyatt_form_bloc
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					  wyatt_type_utils:
 | 
				
			||||||
 | 
					    git:
 | 
				
			||||||
 | 
					      url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
 | 
				
			||||||
 | 
					      ref: wyatt_type_utils-v0.0.3+1
 | 
				
			||||||
 | 
					      path: packages/wyatt_type_utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # The following adds the Cupertino Icons font to your application.
 | 
					  # The following adds the Cupertino Icons font to your application.
 | 
				
			||||||
  # Use with the CupertinoIcons class for iOS style icons.
 | 
					  # Use with the CupertinoIcons class for iOS style icons.
 | 
				
			||||||
  cupertino_icons: ^1.0.5
 | 
					  cupertino_icons: ^1.0.5
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@
 | 
				
			|||||||
// 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:wyatt_architecture/wyatt_architecture.dart';
 | 
					abstract class AuthFormField {
 | 
				
			||||||
 | 
					  static const email = 'wyattEmailField';
 | 
				
			||||||
abstract class AuthenticationBiometricsDataSource extends BaseLocalDataSource {}
 | 
					  static const password = 'wyattPasswordField';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					// Copyright (C) 2022 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/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class AuthFormName {
 | 
				
			||||||
 | 
					  static const String signUpForm = 'wyattSignUpForm';
 | 
				
			||||||
 | 
					  static const String signInForm = 'wyattSignInForm';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -14,6 +14,8 @@
 | 
				
			|||||||
// 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/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export 'constants/form_field.dart';
 | 
				
			||||||
 | 
					export 'constants/form_name.dart';
 | 
				
			||||||
export 'enums/enums.dart';
 | 
					export 'enums/enums.dart';
 | 
				
			||||||
export 'exceptions/exceptions.dart';
 | 
					export 'exceptions/exceptions.dart';
 | 
				
			||||||
export 'utils/utils.dart';
 | 
					export 'utils/utils.dart';
 | 
				
			||||||
 | 
				
			|||||||
@ -15,29 +15,28 @@
 | 
				
			|||||||
// 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:wyatt_architecture/wyatt_architecture.dart';
 | 
					import 'package:wyatt_architecture/wyatt_architecture.dart';
 | 
				
			||||||
import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_local_data_source.dart';
 | 
					import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
				
			||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
 | 
					 | 
				
			||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
					import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthenticationCacheDataSourceImpl<T extends Object>
 | 
					class AuthenticationCacheDataSourceImpl<T extends Object>
 | 
				
			||||||
    extends AuthenticationLocalDataSource<T> {
 | 
					    extends AuthenticationCacheDataSource<T> {
 | 
				
			||||||
  Account? _account;
 | 
					  Account? _account;
 | 
				
			||||||
  T? _data;
 | 
					  T? _data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  AuthenticationCacheDataSourceImpl();
 | 
					  AuthenticationCacheDataSourceImpl();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void storeAccount(Account? account) {
 | 
					  Future<void> storeAccount(Account? account) async {
 | 
				
			||||||
    _account = account;
 | 
					    _account = account;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void storeData(T? data) {
 | 
					  Future<void> storeData(T? data) async {
 | 
				
			||||||
    _data = data;
 | 
					    _data = data;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Account loadAccount() {
 | 
					  Future<Account> loadAccount() async {
 | 
				
			||||||
    if (_account.isNotNull) {
 | 
					    if (_account.isNotNull) {
 | 
				
			||||||
      return _account!;
 | 
					      return _account!;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -45,7 +44,7 @@ class AuthenticationCacheDataSourceImpl<T extends Object>
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  T loadData() {
 | 
					  Future<T> loadData() async {
 | 
				
			||||||
    if (_data.isNotNull) {
 | 
					    if (_data.isNotNull) {
 | 
				
			||||||
      return _data!;
 | 
					      return _data!;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -53,8 +52,16 @@ class AuthenticationCacheDataSourceImpl<T extends Object>
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void destroy() {
 | 
					  Future<void> destroy() async {
 | 
				
			||||||
    _data = null;
 | 
					    _data = null;
 | 
				
			||||||
    _account = null;
 | 
					    _account = null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<AccountWrapper<T>> load() async {
 | 
				
			||||||
 | 
					    if (_account.isNull) {
 | 
				
			||||||
 | 
					      throw ClientException('Cached account is invalid');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return AccountWrapperModel(_account, _data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -15,28 +15,75 @@
 | 
				
			|||||||
// 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:wyatt_architecture/wyatt_architecture.dart';
 | 
					import 'package:wyatt_architecture/wyatt_architecture.dart';
 | 
				
			||||||
 | 
					import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart';
 | 
				
			||||||
 | 
					import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart';
 | 
				
			||||||
import 'package:wyatt_authentication_bloc/src/data/models/account_wrapper_model.dart';
 | 
					import 'package:wyatt_authentication_bloc/src/data/models/account_wrapper_model.dart';
 | 
				
			||||||
import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_local_data_source.dart';
 | 
					import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_cache_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/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/account_wrapper.dart';
 | 
					import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.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_type_utils/wyatt_type_utils.dart';
 | 
					import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef OnSignUpSuccess<T> = FutureResult<T?> Function(
 | 
				
			||||||
 | 
					  Account? account,
 | 
				
			||||||
 | 
					  WyattForm form,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef OnAuthChange<T> = FutureResult<T?> Function(Account? account);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthenticationRepositoryImpl<T extends Object>
 | 
					class AuthenticationRepositoryImpl<T extends Object>
 | 
				
			||||||
    extends AuthenticationRepository<T> {
 | 
					    extends AuthenticationRepository<T> {
 | 
				
			||||||
  final AuthenticationLocalDataSource<T> _authenticationLocalDataSource;
 | 
					  final AuthenticationCacheDataSource<T> _authenticationLocalDataSource;
 | 
				
			||||||
  final AuthenticationRemoteDataSource _authenticationRemoteDataSource;
 | 
					  final AuthenticationRemoteDataSource _authenticationRemoteDataSource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final FutureResult<T?> Function(Account? account)? _onSignUpSuccess;
 | 
					  late FormRepository _formRepository;
 | 
				
			||||||
  final FutureResult<T?> Function(Account? account)? _onAccountChanges;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  AuthenticationRepositoryImpl(
 | 
					  final OnSignUpSuccess<T>? _onSignUpSuccess;
 | 
				
			||||||
    this._authenticationLocalDataSource,
 | 
					
 | 
				
			||||||
    this._authenticationRemoteDataSource,
 | 
					  final OnAuthChange<T>? _onAccountChanges;
 | 
				
			||||||
    this._onSignUpSuccess,
 | 
					
 | 
				
			||||||
    this._onAccountChanges,
 | 
					  AuthenticationRepositoryImpl({
 | 
				
			||||||
  );
 | 
					    required AuthenticationCacheDataSource<T> authenticationCacheDataSource,
 | 
				
			||||||
 | 
					    required AuthenticationRemoteDataSource authenticationRemoteDataSource,
 | 
				
			||||||
 | 
					    FormRepository? formRepository,
 | 
				
			||||||
 | 
					    // ignore: strict_raw_type
 | 
				
			||||||
 | 
					    List<FormInput>? extraSignUpInputs,
 | 
				
			||||||
 | 
					    OnSignUpSuccess<T>? onSignUpSuccess,
 | 
				
			||||||
 | 
					    OnAuthChange<T>? onAuthChange,
 | 
				
			||||||
 | 
					  })  : _authenticationLocalDataSource = authenticationCacheDataSource,
 | 
				
			||||||
 | 
					        _authenticationRemoteDataSource = authenticationRemoteDataSource,
 | 
				
			||||||
 | 
					        _onSignUpSuccess = onSignUpSuccess,
 | 
				
			||||||
 | 
					        _onAccountChanges = onAuthChange {
 | 
				
			||||||
 | 
					    _formRepository = formRepository ?? FormRepositoryImpl();
 | 
				
			||||||
 | 
					    if (formRepository != null) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    _formRepository
 | 
				
			||||||
 | 
					      ..registerForm(
 | 
				
			||||||
 | 
					        WyattFormImpl(
 | 
				
			||||||
 | 
					          [
 | 
				
			||||||
 | 
					            FormInput(AuthFormField.email, const Email.pure()),
 | 
				
			||||||
 | 
					            FormInput(AuthFormField.password, const Password.pure())
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          name: AuthFormName.signInForm,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      ..registerForm(
 | 
				
			||||||
 | 
					        WyattFormImpl(
 | 
				
			||||||
 | 
					          [
 | 
				
			||||||
 | 
					            FormInput(AuthFormField.email, const Email.pure()),
 | 
				
			||||||
 | 
					            FormInput(AuthFormField.password, const Password.pure()),
 | 
				
			||||||
 | 
					            ...extraSignUpInputs ?? []
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          name: AuthFormName.signUpForm,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FormRepository get formRepository => _formRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  FutureResult<Account> signInWithEmailAndPassword({
 | 
					  FutureResult<Account> signInWithEmailAndPassword({
 | 
				
			||||||
@ -50,7 +97,7 @@ class AuthenticationRepositoryImpl<T extends Object>
 | 
				
			|||||||
            email: email,
 | 
					            email: email,
 | 
				
			||||||
            password: password,
 | 
					            password: password,
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
          _authenticationLocalDataSource.storeAccount(account);
 | 
					          await _authenticationLocalDataSource.storeAccount(account);
 | 
				
			||||||
          return account;
 | 
					          return account;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
@ -61,7 +108,7 @@ class AuthenticationRepositoryImpl<T extends Object>
 | 
				
			|||||||
      Result.tryCatchAsync<void, AppException, AppException>(
 | 
					      Result.tryCatchAsync<void, AppException, AppException>(
 | 
				
			||||||
        () async {
 | 
					        () async {
 | 
				
			||||||
          await _authenticationRemoteDataSource.signOut();
 | 
					          await _authenticationRemoteDataSource.signOut();
 | 
				
			||||||
          _authenticationLocalDataSource.destroy();
 | 
					          await _authenticationLocalDataSource.destroy();
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@ -77,10 +124,13 @@ class AuthenticationRepositoryImpl<T extends Object>
 | 
				
			|||||||
            email: email,
 | 
					            email: email,
 | 
				
			||||||
            password: password,
 | 
					            password: password,
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
          _authenticationLocalDataSource.storeAccount(account);
 | 
					          await _authenticationLocalDataSource.storeAccount(account);
 | 
				
			||||||
          if (_onSignUpSuccess.isNotNull) {
 | 
					          if (_onSignUpSuccess.isNotNull) {
 | 
				
			||||||
            final dataResult = await _onSignUpSuccess!.call(account);
 | 
					            final dataResult = await _onSignUpSuccess!.call(
 | 
				
			||||||
            dataResult.fold(
 | 
					              account,
 | 
				
			||||||
 | 
					              _formRepository.accessForm(AuthFormName.signUpForm).clone(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            await dataResult.foldAsync(
 | 
				
			||||||
              _authenticationLocalDataSource.storeData,
 | 
					              _authenticationLocalDataSource.storeData,
 | 
				
			||||||
              (error) => throw error,
 | 
					              (error) => throw error,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
@ -91,46 +141,51 @@ class AuthenticationRepositoryImpl<T extends Object>
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Result<void, AppException> destroyCache() =>
 | 
					  FutureResult<void> destroyCache() =>
 | 
				
			||||||
      Result.tryCatch<void, AppException, AppException>(
 | 
					      Result.tryCatchAsync<void, AppException, AppException>(
 | 
				
			||||||
        _authenticationLocalDataSource.destroy,
 | 
					        _authenticationLocalDataSource.destroy,
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Result<Account, AppException> getAccount() =>
 | 
					  FutureResult<AccountWrapper<T>> getCache() =>
 | 
				
			||||||
      Result.tryCatch<Account, AppException, AppException>(
 | 
					      Result.tryCatchAsync<AccountWrapper<T>, AppException, AppException>(
 | 
				
			||||||
 | 
					        _authenticationLocalDataSource.load,
 | 
				
			||||||
 | 
					        (error) => error,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureResult<Account> getAccount() =>
 | 
				
			||||||
 | 
					      Result.tryCatchAsync<Account, AppException, AppException>(
 | 
				
			||||||
        _authenticationLocalDataSource.loadAccount,
 | 
					        _authenticationLocalDataSource.loadAccount,
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Result<Account, AppException> setAccount(
 | 
					  FutureResult<void> setAccount(
 | 
				
			||||||
    Account account,
 | 
					    Account account,
 | 
				
			||||||
  ) =>
 | 
					  ) =>
 | 
				
			||||||
      Result.tryCatch<Account, AppException, AppException>(
 | 
					      Result.tryCatchAsync<void, AppException, AppException>(
 | 
				
			||||||
        () {
 | 
					        () async {
 | 
				
			||||||
          _authenticationLocalDataSource.storeAccount(account);
 | 
					          await _authenticationLocalDataSource.storeAccount(account);
 | 
				
			||||||
          return account;
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Result<T, AppException> getData() =>
 | 
					  FutureResult<T> getData() =>
 | 
				
			||||||
      Result.tryCatch<T, AppException, AppException>(
 | 
					      Result.tryCatchAsync<T, AppException, AppException>(
 | 
				
			||||||
        _authenticationLocalDataSource.loadData,
 | 
					        _authenticationLocalDataSource.loadData,
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Result<T, AppException> setData(
 | 
					  FutureResult<void> setData(
 | 
				
			||||||
    T data,
 | 
					    T? data,
 | 
				
			||||||
  ) =>
 | 
					  ) =>
 | 
				
			||||||
      Result.tryCatch<T, AppException, AppException>(
 | 
					      Result.tryCatchAsync<void, AppException, AppException>(
 | 
				
			||||||
        () {
 | 
					        () async {
 | 
				
			||||||
          _authenticationLocalDataSource.storeData(data);
 | 
					          await _authenticationLocalDataSource.storeData(data);
 | 
				
			||||||
          return data;
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        (error) => error,
 | 
					        (error) => error,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,5 @@
 | 
				
			|||||||
// 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/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export 'local/authentication_biometrics_data_source.dart';
 | 
					export 'local/authentication_cache_data_source.dart';
 | 
				
			||||||
export 'local/authentication_local_data_source.dart';
 | 
					 | 
				
			||||||
export 'remote/authentication_remote_data_source.dart';
 | 
					export 'remote/authentication_remote_data_source.dart';
 | 
				
			||||||
 | 
				
			|||||||
@ -16,12 +16,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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/account_wrapper.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class AuthenticationLocalDataSource<T extends Object>
 | 
					abstract class AuthenticationCacheDataSource<T extends Object>
 | 
				
			||||||
    extends BaseLocalDataSource {
 | 
					    extends BaseLocalDataSource {
 | 
				
			||||||
  void storeAccount(Account? account);
 | 
					  Future<void> storeAccount(Account? account);
 | 
				
			||||||
  void storeData(T? data);
 | 
					  Future<void> storeData(T? data);
 | 
				
			||||||
  Account loadAccount();
 | 
					  Future<Account> loadAccount();
 | 
				
			||||||
  T loadData();
 | 
					  Future<T> loadData();
 | 
				
			||||||
  void destroy();
 | 
					  Future<AccountWrapper<T>> load();
 | 
				
			||||||
 | 
					  Future<void> destroy();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -17,13 +17,14 @@
 | 
				
			|||||||
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/account_wrapper.dart';
 | 
					import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart';
 | 
				
			||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
					import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class AuthenticationRepository<T> extends BaseRepository {
 | 
					abstract class AuthenticationRepository<T> extends BaseRepository {
 | 
				
			||||||
 | 
					  FormRepository get formRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FutureResult<Account> signUp({
 | 
					  FutureResult<Account> signUp({
 | 
				
			||||||
    required String email,
 | 
					    required String email,
 | 
				
			||||||
    required String password,
 | 
					    required String password,
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FutureResult<Account> signInWithEmailAndPassword({
 | 
					  FutureResult<Account> signInWithEmailAndPassword({
 | 
				
			||||||
@ -37,11 +38,12 @@ abstract class AuthenticationRepository<T> extends BaseRepository {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  FutureResult<String> getIdentityToken();
 | 
					  FutureResult<String> getIdentityToken();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Result<Account, AppException> getAccount();
 | 
					  FutureResult<Account> getAccount();
 | 
				
			||||||
  Result<Account, AppException> setAccount(Account account);
 | 
					  FutureResult<void> setAccount(Account account);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Result<T, AppException> getData();
 | 
					  FutureResult<T> getData();
 | 
				
			||||||
  Result<T, AppException> setData(T data);
 | 
					  FutureResult<void> setData(T? data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Result<void, AppException> destroyCache();
 | 
					  FutureResult<AccountWrapper<T>> getCache();
 | 
				
			||||||
 | 
					  FutureResult<void> destroyCache();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,55 +14,96 @@
 | 
				
			|||||||
// 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';
 | 
					import 'dart:async';
 | 
				
			||||||
import 'package:flutter_bloc/flutter_bloc.dart';
 | 
					
 | 
				
			||||||
 | 
					import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart';
 | 
				
			||||||
 | 
					import 'package:wyatt_authentication_bloc/src/core/constants/form_name.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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
part 'sign_in_state.dart';
 | 
					part 'sign_in_state.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SignInCubit<Extra> extends Cubit<SignInState> {
 | 
					class SignInCubit<Extra> extends FormDataCubit<SignInState> {
 | 
				
			||||||
  final AuthenticationRepository<Extra> _authenticationRepository;
 | 
					  final AuthenticationRepository<Extra> _authenticationRepository;
 | 
				
			||||||
 | 
					  FormRepository get _formRepository =>
 | 
				
			||||||
  final FormValidator _validationStrategy;
 | 
					      _authenticationRepository.formRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SignInCubit({
 | 
					  SignInCubit({
 | 
				
			||||||
    required AuthenticationRepository<Extra> authenticationRepository,
 | 
					    required AuthenticationRepository<Extra> authenticationRepository,
 | 
				
			||||||
    FormValidator validationStrategy = const EveryInputValidator(),
 | 
					 | 
				
			||||||
  })  : _authenticationRepository = authenticationRepository,
 | 
					  })  : _authenticationRepository = authenticationRepository,
 | 
				
			||||||
        _validationStrategy = validationStrategy,
 | 
					        super(
 | 
				
			||||||
        super(const SignInState());
 | 
					          SignInState(
 | 
				
			||||||
 | 
					            form: authenticationRepository.formRepository
 | 
				
			||||||
 | 
					                .accessForm(AuthFormName.signInForm),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String get formName => AuthFormName.signInForm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void emailChanged(String value) {
 | 
					  void emailChanged(String value) {
 | 
				
			||||||
    final Email email = Email.dirty(value);
 | 
					    final Email email = Email.dirty(value);
 | 
				
			||||||
    emit(
 | 
					    dataChanged(AuthFormField.email, email);
 | 
				
			||||||
      state.copyWith(
 | 
					 | 
				
			||||||
        email: email,
 | 
					 | 
				
			||||||
        status: _validationStrategy.rawValidate([email, state.password]),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void passwordChanged(String value) {
 | 
					  void passwordChanged(String value) {
 | 
				
			||||||
    final Password password = Password.dirty(value);
 | 
					    final Password password = Password.dirty(value);
 | 
				
			||||||
 | 
					    dataChanged(AuthFormField.password, password);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> dataChanged<Value>(
 | 
				
			||||||
 | 
					    String key,
 | 
				
			||||||
 | 
					    FormInputValidator<Value, ValidationError> dirtyValue,
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    final form = _formRepository.accessForm(formName).clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      form.updateValidator(key, dirtyValue);
 | 
				
			||||||
 | 
					      _formRepository.updateForm(form);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      rethrow;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit(
 | 
					    emit(
 | 
				
			||||||
      state.copyWith(
 | 
					      state.copyWith(form: form, status: form.validate()),
 | 
				
			||||||
        password: password,
 | 
					 | 
				
			||||||
        status: _validationStrategy.rawValidate([state.email, password]),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> signInWithEmailAndPassword() async {
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> reset() {
 | 
				
			||||||
 | 
					    final form = state.form.reset();
 | 
				
			||||||
 | 
					    _formRepository.updateForm(form);
 | 
				
			||||||
 | 
					    emit(
 | 
				
			||||||
 | 
					      state.copyWith(form: form, status: form.validate()),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> submit() async {
 | 
				
			||||||
    if (!state.status.isValidated) {
 | 
					    if (!state.status.isValidated) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit(state.copyWith(status: FormStatus.submissionInProgress));
 | 
					    emit(state.copyWith(status: FormStatus.submissionInProgress));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final form = _formRepository.accessForm(formName);
 | 
				
			||||||
 | 
					    final email = form.valueOf<String?>(AuthFormField.email);
 | 
				
			||||||
 | 
					    final password = form.valueOf<String?>(AuthFormField.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (email.isNullOrEmpty || password.isNullOrEmpty) {
 | 
				
			||||||
 | 
					      emit(
 | 
				
			||||||
 | 
					        state.copyWith(
 | 
				
			||||||
 | 
					          errorMessage: 'An error occured while retrieving data from the form.',
 | 
				
			||||||
 | 
					          status: FormStatus.submissionFailure,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final uid = await _authenticationRepository.signInWithEmailAndPassword(
 | 
					    final uid = await _authenticationRepository.signInWithEmailAndPassword(
 | 
				
			||||||
      email: state.email.value,
 | 
					      email: email!,
 | 
				
			||||||
      password: state.password.value,
 | 
					      password: password!,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit(
 | 
					    emit(
 | 
				
			||||||
@ -75,4 +116,30 @@ class SignInCubit<Extra> extends Cubit<SignInState> {
 | 
				
			|||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> update(
 | 
				
			||||||
 | 
					    WyattForm form, {
 | 
				
			||||||
 | 
					    SetOperation operation = SetOperation.replace,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    final WyattForm current = _formRepository.accessForm(formName).clone();
 | 
				
			||||||
 | 
					    final WyattForm newForm = operation.operation.call(current, form);
 | 
				
			||||||
 | 
					    _formRepository.updateForm(newForm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    emit(
 | 
				
			||||||
 | 
					      state.copyWith(
 | 
				
			||||||
 | 
					        form: newForm,
 | 
				
			||||||
 | 
					        status: newForm.validate(),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> validate() {
 | 
				
			||||||
 | 
					    emit(
 | 
				
			||||||
 | 
					      state.copyWith(
 | 
				
			||||||
 | 
					        status: _formRepository.accessForm(formName).validate(),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,28 +16,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
part of 'sign_in_cubit.dart';
 | 
					part of 'sign_in_cubit.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SignInState extends Equatable {
 | 
					class SignInState extends FormDataState {
 | 
				
			||||||
  final Email email;
 | 
					  Email get email => form.validatorOf(AuthFormField.email);
 | 
				
			||||||
  final Password password;
 | 
					  Password get password => form.validatorOf(AuthFormField.password);
 | 
				
			||||||
  final FormStatus status;
 | 
					 | 
				
			||||||
  final String? errorMessage;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const SignInState({
 | 
					  const SignInState({
 | 
				
			||||||
    this.email = const Email.pure(),
 | 
					    required super.form,
 | 
				
			||||||
    this.password = const Password.pure(),
 | 
					    super.status = FormStatus.pure,
 | 
				
			||||||
    this.status = FormStatus.pure,
 | 
					    super.errorMessage,
 | 
				
			||||||
    this.errorMessage,
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SignInState copyWith({
 | 
					  SignInState copyWith({
 | 
				
			||||||
    Email? email,
 | 
					    WyattForm? form,
 | 
				
			||||||
    Password? password,
 | 
					 | 
				
			||||||
    FormStatus? status,
 | 
					    FormStatus? status,
 | 
				
			||||||
    String? errorMessage,
 | 
					    String? errorMessage,
 | 
				
			||||||
  }) =>
 | 
					  }) =>
 | 
				
			||||||
      SignInState(
 | 
					      SignInState(
 | 
				
			||||||
        email: email ?? this.email,
 | 
					        form: form ?? this.form,
 | 
				
			||||||
        password: password ?? this.password,
 | 
					 | 
				
			||||||
        status: status ?? this.status,
 | 
					        status: status ?? this.status,
 | 
				
			||||||
        errorMessage: errorMessage ?? this.errorMessage,
 | 
					        errorMessage: errorMessage ?? this.errorMessage,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@ -46,10 +41,6 @@ class SignInState extends Equatable {
 | 
				
			|||||||
  List<Object> get props => [email, password, status];
 | 
					  List<Object> get props => [email, password, status];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => '''
 | 
					  String toString() => 'SignInState(status: ${status.name} '
 | 
				
			||||||
      email: $email,
 | 
					      '${(errorMessage != null) ? " [$errorMessage]" : ""}, $form)';
 | 
				
			||||||
      password: $password,
 | 
					 | 
				
			||||||
      status: $status,
 | 
					 | 
				
			||||||
      errorMessage: $errorMessage,
 | 
					 | 
				
			||||||
    ''';
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,132 +16,94 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:equatable/equatable.dart';
 | 
					import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart';
 | 
				
			||||||
import 'package:flutter_bloc/flutter_bloc.dart';
 | 
					import 'package:wyatt_authentication_bloc/src/core/constants/form_name.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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
part 'sign_up_state.dart';
 | 
					part 'sign_up_state.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SignUpCubit<Extra> extends Cubit<SignUpState> {
 | 
					class SignUpCubit<Extra> extends FormDataCubit<SignUpState> {
 | 
				
			||||||
  final AuthenticationRepository<Extra> _authenticationRepository;
 | 
					  final AuthenticationRepository<Extra> _authenticationRepository;
 | 
				
			||||||
 | 
					  FormRepository get _formRepository =>
 | 
				
			||||||
  final FormValidator _validationStrategy;
 | 
					      _authenticationRepository.formRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SignUpCubit({
 | 
					  SignUpCubit({
 | 
				
			||||||
    required AuthenticationRepository<Extra> authenticationRepository,
 | 
					    required AuthenticationRepository<Extra> authenticationRepository,
 | 
				
			||||||
    required FormData formData,
 | 
					 | 
				
			||||||
    FormValidator validationStrategy = const EveryInputValidator(),
 | 
					 | 
				
			||||||
  })  : _authenticationRepository = authenticationRepository,
 | 
					  })  : _authenticationRepository = authenticationRepository,
 | 
				
			||||||
        _validationStrategy = validationStrategy,
 | 
					        super(
 | 
				
			||||||
        super(SignUpState(data: formData));
 | 
					          SignUpState(
 | 
				
			||||||
 | 
					            form: authenticationRepository.formRepository
 | 
				
			||||||
 | 
					                .accessForm(AuthFormName.signUpForm),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String get formName => AuthFormName.signUpForm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void emailChanged(String value) {
 | 
					  void emailChanged(String value) {
 | 
				
			||||||
    final Email email = Email.dirty(value);
 | 
					    final Email email = Email.dirty(value);
 | 
				
			||||||
 | 
					    dataChanged(AuthFormField.email, email);
 | 
				
			||||||
    final List<FormInputValidator<dynamic, ValidationError>> toValidate = [
 | 
					 | 
				
			||||||
      email,
 | 
					 | 
				
			||||||
      state.password,
 | 
					 | 
				
			||||||
      ...state.data.validators<dynamic, ValidationError>(),
 | 
					 | 
				
			||||||
    ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    emit(
 | 
					 | 
				
			||||||
      state.copyWith(
 | 
					 | 
				
			||||||
        email: email,
 | 
					 | 
				
			||||||
        status: _validationStrategy.rawValidate(toValidate),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void passwordChanged(String value) {
 | 
					  void passwordChanged(String value) {
 | 
				
			||||||
    final Password password = Password.dirty(value);
 | 
					    final Password password = Password.dirty(value);
 | 
				
			||||||
 | 
					    dataChanged(AuthFormField.password, password);
 | 
				
			||||||
    final List<FormInputValidator<dynamic, ValidationError>> toValidate = [
 | 
					 | 
				
			||||||
      state.email,
 | 
					 | 
				
			||||||
      password,
 | 
					 | 
				
			||||||
      ...state.data.validators<dynamic, ValidationError>(),
 | 
					 | 
				
			||||||
    ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    emit(
 | 
					 | 
				
			||||||
      state.copyWith(
 | 
					 | 
				
			||||||
        password: password,
 | 
					 | 
				
			||||||
        status: _validationStrategy.rawValidate(toValidate),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Take from wyatt_form_bloc/wyatt_form_bloc.dart
 | 
					  @override
 | 
				
			||||||
  void dataChanged<T>(
 | 
					  FutureOr<void> dataChanged<Value>(
 | 
				
			||||||
    String field,
 | 
					    String key,
 | 
				
			||||||
    FormInputValidator<T, ValidationError> dirtyValue,
 | 
					    FormInputValidator<Value, ValidationError> dirtyValue,
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    final form = state.data.clone();
 | 
					    final form = _formRepository.accessForm(formName).clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (form.contains(field)) {
 | 
					    try {
 | 
				
			||||||
      form.updateValidator(field, dirtyValue);
 | 
					      form.updateValidator(key, dirtyValue);
 | 
				
			||||||
    } else {
 | 
					      _formRepository.updateForm(form);
 | 
				
			||||||
      throw Exception('Form field $field not found');
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      rethrow;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit(
 | 
					    emit(
 | 
				
			||||||
      state.copyWith(
 | 
					      state.copyWith(form: form, status: form.validate()),
 | 
				
			||||||
        data: form,
 | 
					 | 
				
			||||||
        status: _validationStrategy.rawValidate(
 | 
					 | 
				
			||||||
          [
 | 
					 | 
				
			||||||
            state.email,
 | 
					 | 
				
			||||||
            state.password,
 | 
					 | 
				
			||||||
            ...state.data.validators<dynamic, ValidationError>(),
 | 
					 | 
				
			||||||
          ],
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Take from wyatt_form_bloc/wyatt_form_bloc.dart
 | 
					  @override
 | 
				
			||||||
  void updateFormData(
 | 
					  FutureOr<void> reset() {
 | 
				
			||||||
    FormData data, {
 | 
					    final form = state.form.reset();
 | 
				
			||||||
    SetOperation operation = SetOperation.replace,
 | 
					    _formRepository.updateForm(form);
 | 
				
			||||||
  }) {
 | 
					 | 
				
			||||||
    FormData form = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch (operation) {
 | 
					 | 
				
			||||||
      case SetOperation.replace:
 | 
					 | 
				
			||||||
        form = data;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case SetOperation.difference:
 | 
					 | 
				
			||||||
        form = state.data.difference(data);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case SetOperation.intersection:
 | 
					 | 
				
			||||||
        form = state.data.intersection(data);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case SetOperation.union:
 | 
					 | 
				
			||||||
        form = state.data.union(data);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    emit(
 | 
					    emit(
 | 
				
			||||||
      state.copyWith(
 | 
					      state.copyWith(form: form, status: form.validate()),
 | 
				
			||||||
        data: form,
 | 
					 | 
				
			||||||
        status: _validationStrategy.rawValidate(
 | 
					 | 
				
			||||||
          [
 | 
					 | 
				
			||||||
            state.email,
 | 
					 | 
				
			||||||
            state.password,
 | 
					 | 
				
			||||||
            ...state.data.validators<dynamic, ValidationError>(),
 | 
					 | 
				
			||||||
          ],
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> signUpFormSubmitted() async {
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> submit() async {
 | 
				
			||||||
    if (!state.status.isValidated) {
 | 
					    if (!state.status.isValidated) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit(state.copyWith(status: FormStatus.submissionInProgress));
 | 
					    emit(state.copyWith(status: FormStatus.submissionInProgress));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final form = _formRepository.accessForm(formName);
 | 
				
			||||||
 | 
					    final email = form.valueOf<String?>(AuthFormField.email);
 | 
				
			||||||
 | 
					    final password = form.valueOf<String?>(AuthFormField.password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (email.isNullOrEmpty || password.isNullOrEmpty) {
 | 
				
			||||||
 | 
					      emit(
 | 
				
			||||||
 | 
					        state.copyWith(
 | 
				
			||||||
 | 
					          errorMessage: 'An error occured while retrieving data from the form.',
 | 
				
			||||||
 | 
					          status: FormStatus.submissionFailure,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final uid = await _authenticationRepository.signUp(
 | 
					    final uid = await _authenticationRepository.signUp(
 | 
				
			||||||
      email: state.email.value,
 | 
					      email: email!,
 | 
				
			||||||
      password: state.password.value,
 | 
					      password: password!,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    emit(
 | 
					    emit(
 | 
				
			||||||
@ -154,4 +116,30 @@ class SignUpCubit<Extra> extends Cubit<SignUpState> {
 | 
				
			|||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> update(
 | 
				
			||||||
 | 
					    WyattForm form, {
 | 
				
			||||||
 | 
					    SetOperation operation = SetOperation.replace,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    final WyattForm current = _formRepository.accessForm(formName).clone();
 | 
				
			||||||
 | 
					    final WyattForm newForm = operation.operation.call(current, form);
 | 
				
			||||||
 | 
					    _formRepository.updateForm(newForm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    emit(
 | 
				
			||||||
 | 
					      state.copyWith(
 | 
				
			||||||
 | 
					        form: newForm,
 | 
				
			||||||
 | 
					        status: newForm.validate(),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  FutureOr<void> validate() {
 | 
				
			||||||
 | 
					    emit(
 | 
				
			||||||
 | 
					      state.copyWith(
 | 
				
			||||||
 | 
					        status: _formRepository.accessForm(formName).validate(),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,40 +16,32 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
part of 'sign_up_cubit.dart';
 | 
					part of 'sign_up_cubit.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SignUpState extends Equatable {
 | 
					class SignUpState extends FormDataState {
 | 
				
			||||||
  final Email email;
 | 
					  Email get email => form.validatorOf(AuthFormField.email);
 | 
				
			||||||
  final Password password;
 | 
					  Password get password => form.validatorOf(AuthFormField.password);
 | 
				
			||||||
  final FormStatus status;
 | 
					 | 
				
			||||||
  final FormData data;
 | 
					 | 
				
			||||||
  final String? errorMessage;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const SignUpState({
 | 
					  const SignUpState({
 | 
				
			||||||
    required this.data,
 | 
					    required super.form,
 | 
				
			||||||
    this.email = const Email.pure(),
 | 
					    super.status = FormStatus.pure,
 | 
				
			||||||
    this.password = const Password.pure(),
 | 
					    super.errorMessage,
 | 
				
			||||||
    this.status = FormStatus.pure,
 | 
					 | 
				
			||||||
    this.errorMessage,
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SignUpState copyWith({
 | 
					  SignUpState copyWith({
 | 
				
			||||||
    Email? email,
 | 
					    WyattForm? form,
 | 
				
			||||||
    Password? password,
 | 
					 | 
				
			||||||
    FormStatus? status,
 | 
					    FormStatus? status,
 | 
				
			||||||
    FormData? data,
 | 
					 | 
				
			||||||
    String? errorMessage,
 | 
					    String? errorMessage,
 | 
				
			||||||
  }) =>
 | 
					  }) =>
 | 
				
			||||||
      SignUpState(
 | 
					      SignUpState(
 | 
				
			||||||
        email: email ?? this.email,
 | 
					        form: form ?? this.form,
 | 
				
			||||||
        password: password ?? this.password,
 | 
					 | 
				
			||||||
        status: status ?? this.status,
 | 
					        status: status ?? this.status,
 | 
				
			||||||
        data: data ?? this.data,
 | 
					 | 
				
			||||||
        errorMessage: errorMessage ?? this.errorMessage,
 | 
					        errorMessage: errorMessage ?? this.errorMessage,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'SignUpState(email: $email, password: $password, '
 | 
					  List<Object?> get props => [email, password, status, form];
 | 
				
			||||||
      'status: $status, data: $data, errorMessage: $errorMessage)';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  List<Object?> get props => [email, password, status, data, errorMessage];
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() => 'SignUpState(status: ${status.name} '
 | 
				
			||||||
 | 
					      '${(errorMessage != null) ? " [$errorMessage]" : ""}, $form)';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user