diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000..9ca476d0
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,7 @@
+repos:
+ - repo: https://github.com/compilerla/conventional-pre-commit
+ rev: v2.1.1
+ hooks:
+ - id: conventional-pre-commit
+ stages: [commit-msg]
+ args: [build, ci, docs, feat, fix, perf, refactor, style, test, chore]
diff --git a/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart b/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart
index 84bb68c4..4e0f4070 100644
--- a/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: bootstrap.dart
-// Created Date: 19/08/2022 15:05:17
-// Last Modified: Fri Nov 11 2022
-// -----
-// Copyright (c) 2022
+// 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 .
import 'dart:async';
diff --git a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart
index e371dfb6..84636b9f 100644
--- a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart
@@ -1,12 +1,20 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: form_field.dart
-// Created Date: 19/08/2022 11:52:33
-// Last Modified: 19/08/2022 16:35:39
-// -----
-// Copyright (c) 2022
+// 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 .
abstract class AppFormField {
+ static const oldPassword = 'oldPassword';
static const confirmedPassword = 'confirmedPassword';
}
diff --git a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart
new file mode 100644
index 00000000..a5ce457e
--- /dev/null
+++ b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart
@@ -0,0 +1,19 @@
+// 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 .
+
+abstract class AppFormName {
+ static const editProfile = 'editProfile';
+}
diff --git a/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart b/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart
index 85545c34..657d3917 100644
--- a/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart
@@ -1,12 +1,20 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: router.dart
-// Created Date: 19/08/2022 11:52:22
-// Last Modified: 19/08/2022 16:39:07
-// -----
-// Copyright (c) 2022
+// 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 .
+import 'package:example_router/presentation/features/edit_profile/edit_profile_page.dart';
import 'package:example_router/presentation/features/home/home_page.dart';
import 'package:example_router/presentation/features/sign_in/sign_in_page.dart';
import 'package:example_router/presentation/features/sign_up/sign_up_page.dart';
@@ -75,5 +83,14 @@ class AppRouter {
const SubPage(),
),
),
+ GoRoute(
+ path: '/home/edit',
+ name: EditProfilePage.pageName,
+ pageBuilder: (context, state) => defaultTransition(
+ context,
+ state,
+ const EditProfilePage(),
+ ),
+ ),
];
}
diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart
index 1b44c4e8..3490aee1 100644
--- a/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: app_bloc_observer.dart
-// Created Date: 19/08/2022 12:02:23
-// Last Modified: 19/08/2022 12:02:45
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart
new file mode 100644
index 00000000..abfc6857
--- /dev/null
+++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart
@@ -0,0 +1,32 @@
+// 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 .
+
+import 'package:example_router/core/constants/form_field.dart';
+import 'package:example_router/core/constants/form_name.dart';
+import 'package:example_router/core/utils/custom_password.dart';
+import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
+import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
+
+abstract class AppForms {
+ static WyattForm getEditProfileForm() => WyattFormImpl(
+ [
+ FormInput(AuthFormField.email, const Email.pure()),
+ FormInput(AuthFormField.password, const CustomPassword.pure()),
+ FormInput(AppFormField.oldPassword, const CustomPassword.pure()),
+ ],
+ name: AppFormName.editProfile,
+ );
+}
diff --git a/packages/wyatt_authentication_bloc/example/lib/main.dart b/packages/wyatt_authentication_bloc/example/lib/main.dart
index 06b15c7c..0149dcb6 100644
--- a/packages/wyatt_authentication_bloc/example/lib/main.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/main.dart
@@ -1,3 +1,19 @@
+// 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 .
+
import 'package:example_router/bootstrap.dart';
import 'package:example_router/presentation/features/app/app.dart';
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart
index a2afa06e..99d1d999 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: app.dart
-// Created Date: 19/08/2022 12:05:38
-// Last Modified: Sat Dec 03 2022
-// -----
-// Copyright (c) 2022
+// 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 .
import 'dart:async';
import 'dart:math';
@@ -14,6 +21,7 @@ import 'package:example_router/core/constants/form_field.dart';
import 'package:example_router/core/dependency_injection/get_it.dart';
import 'package:example_router/core/routes/router.dart';
import 'package:example_router/core/utils/custom_password.dart';
+import 'package:example_router/core/utils/forms.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
@@ -69,7 +77,7 @@ class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
- AuthenticationState? previous;
+ AuthenticationState? previous;
final AuthenticationCubit authenticationCubit =
AuthenticationCubit(authenticationRepository: authenticationRepository);
@@ -85,29 +93,18 @@ class App extends StatelessWidget {
redirect: (context, state) {
final authState = authenticationCubit.state;
- if (authState != previous) {
+ if (authState.status != previous?.status) {
previous = authState;
- // Check if current user is logged in
- final loggedIn =
- authState.status == AuthenticationStatus.authenticated;
-
// Checking if current path is onboarding or not
final isOnboarding = AppRouter.publicRoutes.contains(state.subloc);
-
- if (!loggedIn) {
+ if (authState.status == AuthenticationStatus.unauthenticated) {
debugPrint('Not logged');
- if (isOnboarding) {
- return null;
- } else {
+ if (!isOnboarding) {
return '/';
}
- } else {
+ } else if (authState.status == AuthenticationStatus.authenticated) {
debugPrint('Logged');
- if (isOnboarding) {
- return '/home';
- } else {
- return null;
- }
+ return '/home';
}
}
return null;
@@ -116,9 +113,13 @@ class App extends StatelessWidget {
return MultiRepositoryProvider(
providers: [
- RepositoryProvider.value(
+ RepositoryProvider>.value(
value: authenticationRepository,
),
+ RepositoryProvider(
+ create: (context) =>
+ FormRepositoryImpl()..registerForm(AppForms.getEditProfileForm()),
+ ),
],
child: MultiBlocProvider(
providers: [
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart
new file mode 100644
index 00000000..e82e2b4c
--- /dev/null
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart
@@ -0,0 +1,74 @@
+// 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 .
+
+import 'package:example_router/core/constants/form_field.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';
+
+class EditProfileCubit extends FormDataCubitImpl {
+ final AuthenticationRepository authenticationRepository;
+
+ EditProfileCubit(
+ super._formRepository,
+ super._formName, {
+ required this.authenticationRepository,
+ }) : super();
+
+ @override
+ Future submit() async {
+ emit(
+ state.copyWith(
+ status: FormStatus.submissionInProgress,
+ ),
+ );
+ final user = (await authenticationRepository.getAccount()).ok;
+
+ final form = state.form;
+ final email = form.valueOf(AuthFormField.email);
+ final oldPassword = form.valueOf(AppFormField.oldPassword);
+ final newPassword = form.valueOf(AuthFormField.password);
+
+ if (email.isNullOrEmpty ||
+ oldPassword.isNullOrEmpty ||
+ newPassword.isNullOrEmpty) {
+ emit(
+ state.copyWith(
+ errorMessage: 'An error occured while retrieving data from the form.',
+ status: FormStatus.submissionFailure,
+ ),
+ );
+ }
+
+ try {
+ // await authenticationRepository.signInWithEmailAndPassword(
+ // email: user?.email ?? '',
+ // password: oldPassword ?? '',
+ // );
+ // await authenticationRepository.reauthenticateWithCredential();
+ await authenticationRepository.updateEmail(email: email!);
+ await authenticationRepository.updatePassword(password: newPassword!);
+ } on Exception catch (e) {
+ emit(
+ state.copyWith(
+ status: FormStatus.submissionFailure,
+ errorMessage: e.toString(),
+ ),
+ );
+ }
+ emit(state.copyWith(status: FormStatus.submissionSuccess));
+ }
+}
\ No newline at end of file
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart
new file mode 100644
index 00000000..a557d338
--- /dev/null
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart
@@ -0,0 +1,61 @@
+// 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 .
+
+import 'package:example_router/core/constants/form_name.dart';
+import 'package:example_router/presentation/features/edit_profile/blocs/edit_profile_cubit.dart';
+import 'package:example_router/presentation/features/edit_profile/widgets/edit_profile_form.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
+import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
+
+class EditProfilePage extends StatelessWidget {
+ const EditProfilePage({Key? key}) : super(key: key);
+
+ static String pageName = 'EditProfile';
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Edit Profile')),
+ body: Padding(
+ padding: const EdgeInsets.all(8),
+ child: SingleChildScrollView(
+ child: BlocProvider(
+ create: (context) => EditProfileCubit(
+ context.read(),
+ AppFormName.editProfile,
+ authenticationRepository:
+ context.read>(),
+ )..dataChanged(
+ AuthFormField.email,
+ Email.dirty(
+ context
+ .read>()
+ .state
+ .accountWrapper
+ ?.account
+ ?.email ??
+ '',
+ ),
+ ),
+ child: const EditProfileForm(),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart
new file mode 100644
index 00000000..726e51a4
--- /dev/null
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart
@@ -0,0 +1,136 @@
+// 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 .
+
+import 'package:example_router/core/constants/form_field.dart';
+import 'package:example_router/core/utils/custom_password.dart';
+import 'package:example_router/presentation/features/edit_profile/blocs/edit_profile_cubit.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
+import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
+
+class _EmailInput extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return InputBuilderTextController(
+ field: AuthFormField.email,
+ builder: ((context, cubit, state, field, input, controller, extra) {
+ return TextField(
+ onChanged: (email) => cubit.dataChanged(
+ AuthFormField.email, Email.dirty(email)),
+ keyboardType: TextInputType.emailAddress,
+ controller: controller,
+ decoration: InputDecoration(
+ labelText: 'Email',
+ helperText: '',
+ errorText: input.validator.invalid ? 'Invalid email' : null,
+ ),
+ );
+ }),
+ );
+ }
+}
+
+class _OldPasswordInput extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return InputBuilder(
+ field: AppFormField.oldPassword,
+ builder: ((context, cubit, state, field, input) {
+ return TextField(
+ onChanged: (pwd) => cubit.dataChanged(
+ AppFormField.oldPassword, CustomPassword.dirty(pwd)),
+ obscureText: true,
+ decoration: InputDecoration(
+ labelText: 'Old Password',
+ helperText: '',
+ errorText: input.validator.invalid ? 'Invalid password' : null,
+ ),
+ );
+ }),
+ );
+ }
+}
+
+class _NewPasswordInput extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return InputBuilder(
+ field: AuthFormField.password,
+ builder: ((context, cubit, state, field, input) {
+ return TextField(
+ onChanged: (pwd) => cubit.dataChanged(
+ AuthFormField.password, CustomPassword.dirty(pwd)),
+ obscureText: true,
+ decoration: InputDecoration(
+ labelText: 'New Password',
+ helperText: '',
+ errorText: input.validator.invalid ? 'Invalid password' : null,
+ ),
+ );
+ }),
+ );
+ }
+}
+
+class _EditButton extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return SubmitBuilder(
+ builder: ((context, cubit, status) {
+ return status.isSubmissionInProgress
+ ? const CircularProgressIndicator()
+ : ElevatedButton(
+ onPressed: status.isValidated ? () => cubit.submit() : null,
+ child: const Text('Edit profile'),
+ );
+ }),
+ );
+ }
+}
+
+class EditProfileForm extends StatelessWidget {
+ const EditProfileForm({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocListener(
+ listener: (context, state) {
+ if (state.status == FormStatus.submissionFailure) {
+ ScaffoldMessenger.of(context)
+ ..hideCurrentSnackBar()
+ ..showSnackBar(
+ SnackBar(content: Text(state.errorMessage ?? 'Edit Failure')),
+ );
+ }
+ },
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ _EmailInput(),
+ const SizedBox(height: 8),
+ _OldPasswordInput(),
+ const SizedBox(height: 8),
+ _NewPasswordInput(),
+ const SizedBox(height: 16),
+ _EditButton(),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart
index e271c7e1..a015690b 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart
@@ -1,12 +1,20 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: home_page.dart
-// Created Date: 19/08/2022 14:38:24
-// Last Modified: Wed Nov 09 2022
-// -----
-// Copyright (c) 2022
+// 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 .
+import 'package:example_router/presentation/features/edit_profile/edit_profile_page.dart';
import 'package:example_router/presentation/features/sub/sub_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -25,7 +33,8 @@ class HomePage extends StatelessWidget {
title: const Text('Home'),
actions: [
IconButton(
- onPressed: () => context.read>().signOut(),
+ onPressed: () =>
+ context.read>().signOut(),
icon: const Icon(Icons.logout_rounded))
],
),
@@ -35,8 +44,8 @@ class HomePage extends StatelessWidget {
child: Column(
children: [
AuthenticationBuilder(
- authenticated: (context, accountWrapper) =>
- Text('Logged as ${accountWrapper.account?.email} | GeneratedId is ${accountWrapper.data}'),
+ authenticated: (context, accountWrapper) => Text(
+ 'Logged as ${accountWrapper.account?.email} | GeneratedId is ${accountWrapper.data}'),
unauthenticated: (context) =>
const Text('Not logged (unauthenticated)'),
unknown: (context) => const Text('Not logged (unknown)'),
@@ -45,8 +54,13 @@ class HomePage extends StatelessWidget {
height: 8,
),
ElevatedButton(
- onPressed: () => context.pushNamed(SubPage.pageName),
- child: const Text('Go to sub page')),
+ onPressed: () => context.pushNamed(SubPage.pageName),
+ child: const Text('Go to sub page'),
+ ),
+ ElevatedButton(
+ onPressed: () => context.pushNamed(EditProfilePage.pageName),
+ child: const Text('Go to edit profile page'),
+ ),
],
),
),
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart
index 39fd0463..5d7aa1e4 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: sign_in_page.dart
-// Created Date: 19/08/2022 12:41:42
-// Last Modified: 19/08/2022 15:26:36
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:example_router/presentation/features/sign_in/widgets/sign_in_form.dart';
import 'package:flutter/material.dart';
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart
index 45a45c4a..865b6cec 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: sign_in_form.dart
-// Created Date: 19/08/2022 15:24:37
-// Last Modified: Sat Dec 03 2022
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:example_router/core/utils/custom_password.dart';
import 'package:flutter/material.dart';
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart
index 31f18bb6..918f09cd 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: sign_up_page.dart
-// Created Date: 19/08/2022 12:41:27
-// Last Modified: 19/08/2022 14:58:51
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:example_router/presentation/features/sign_up/widgets/sign_up_form.dart';
import 'package:flutter/material.dart';
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart
index 0a512fb8..546ec326 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: sign_up_form.dart
-// Created Date: 19/08/2022 14:41:08
-// Last Modified: Sat Dec 03 2022
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:example_router/core/constants/form_field.dart';
import 'package:example_router/core/utils/custom_password.dart';
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart
index 14b340b8..48a39986 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: sub_page.dart
-// Created Date: 19/08/2022 16:10:05
-// Last Modified: Wed Nov 09 2022
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -24,7 +31,10 @@ class SubPage extends StatelessWidget {
actions: [
IconButton(
onPressed: () => context.read>().signOut(),
- icon: const Icon(Icons.logout_rounded))
+ icon: const Icon(Icons.logout_rounded)),
+ IconButton(
+ onPressed: () => context.read>().refresh(),
+ icon: const Icon(Icons.refresh))
],
),
body: const Padding(
diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart
index 3794f971..5080183c 100644
--- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart
+++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart
@@ -1,11 +1,18 @@
-// Author: Hugo Pointcheval
-// Email: git@pcl.ovh
-// -----
-// File: welcome_page.dart
-// Created Date: 19/08/2022 12:33:21
-// Last Modified: Wed Nov 09 2022
-// -----
-// Copyright (c) 2022
+// 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 .
import 'package:example_router/presentation/features/sign_in/sign_in_page.dart';
import 'package:example_router/presentation/features/sign_up/sign_up_page.dart';
diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart
index dbe4b429..cfcfba68 100644
--- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart
@@ -256,3 +256,24 @@ abstract class GetIdTokenFailureInterface
GetIdTokenFailureInterface.fromCode(super.code) : super.fromCode();
}
+
+abstract class ReauthenticateFailureInterface
+ extends AuthenticationFailureInterface {
+ ReauthenticateFailureInterface(super.code, super.msg);
+
+ ReauthenticateFailureInterface.fromCode(super.code) : super.fromCode();
+}
+
+abstract class UpdateEmailFailureInterface
+ extends AuthenticationFailureInterface {
+ UpdateEmailFailureInterface(super.code, super.msg);
+
+ UpdateEmailFailureInterface.fromCode(super.code) : super.fromCode();
+}
+
+abstract class UpdatePasswordFailureInterface
+ extends AuthenticationFailureInterface {
+ UpdatePasswordFailureInterface(super.code, super.msg);
+
+ UpdatePasswordFailureInterface.fromCode(super.code) : super.fromCode();
+}
diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart
index 7a6e37b4..c36dcbd0 100644
--- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart
@@ -277,3 +277,75 @@ class GetIdTokenFailureFirebase extends GetIdTokenFailureInterface {
GetIdTokenFailureFirebase.fromCode(super.code) : super.fromCode();
}
+
+class ReauthenticateFailureFirebase extends ReauthenticateFailureInterface {
+ ReauthenticateFailureFirebase([String? code, String? msg])
+ : super(code ?? 'unknown', msg ?? 'An unknown error occurred.');
+ ReauthenticateFailureFirebase.fromCode(String code) : super.fromCode(code) {
+ switch (code) {
+ case 'user-mismatch':
+ msg = 'Given credential does not correspond to the user.';
+ break;
+ case 'user-not-found':
+ msg = 'User is not found, please create an account.';
+ break;
+ case 'invalid-credential':
+ msg = 'The credential received is malformed or has expired.';
+ break;
+ case 'invalid-email':
+ msg = 'Email is not valid or badly formatted.';
+ break;
+ case 'wrong-password':
+ msg = 'Incorrect password, please try again.';
+ break;
+ case 'invalid-verification-code':
+ msg = 'The credential verification code received is invalid.';
+ break;
+ case 'invalid-verification-id':
+ msg = 'The credential verification ID received is invalid.';
+ break;
+ default:
+ this.code = 'unknown';
+ msg = 'An unknown error occurred.';
+ }
+ }
+}
+
+class UpdateEmailFailureFirebase extends UpdateEmailFailureInterface {
+ UpdateEmailFailureFirebase([String? code, String? msg])
+ : super(code ?? 'unknown', msg ?? 'An unknown error occurred.');
+ UpdateEmailFailureFirebase.fromCode(String code) : super.fromCode(code) {
+ switch (code) {
+ case 'invalid-email':
+ msg = 'Email is not valid or badly formatted.';
+ break;
+ case 'email-already-in-use':
+ msg = 'An account already exists for that email.';
+ break;
+ case 'requires-recent-login':
+ msg = "User's last sign-in time does not meet the security threshold.";
+ break;
+ default:
+ this.code = 'unknown';
+ msg = 'An unknown error occurred.';
+ }
+ }
+}
+
+class UpdatePasswordFailureFirebase extends UpdatePasswordFailureInterface {
+ UpdatePasswordFailureFirebase([String? code, String? msg])
+ : super(code ?? 'unknown', msg ?? 'An unknown error occurred.');
+ UpdatePasswordFailureFirebase.fromCode(String code) : super.fromCode(code) {
+ switch (code) {
+ case 'weak-password':
+ msg = 'Please enter a stronger password.';
+ break;
+ case 'requires-recent-login':
+ msg = "User's last sign-in time does not meet the security threshold.";
+ break;
+ default:
+ this.code = 'unknown';
+ msg = 'An unknown error occurred.';
+ }
+ }
+}
diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart
index 565b76cc..131e160a 100644
--- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart
@@ -21,6 +21,7 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class AuthenticationFirebaseDataSourceImpl
extends AuthenticationRemoteDataSource {
final FirebaseAuth _firebaseAuth;
+ UserCredential? _latestCreds;
AuthenticationFirebaseDataSourceImpl({FirebaseAuth? firebaseAuth})
: _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance;
@@ -51,6 +52,7 @@ class AuthenticationFirebaseDataSourceImpl
email: email,
password: password,
);
+ _latestCreds = userCredential;
final user = userCredential.user;
if (user.isNotNull) {
return _mapper(user!);
@@ -76,6 +78,7 @@ class AuthenticationFirebaseDataSourceImpl
email: email,
password: password,
);
+ _latestCreds = userCredential;
final user = userCredential.user;
if (user.isNotNull) {
return _mapper(user!);
@@ -92,6 +95,7 @@ class AuthenticationFirebaseDataSourceImpl
@override
Future signOut() async {
try {
+ _latestCreds = null;
await _firebaseAuth.signOut();
} catch (_) {
throw SignOutFailureFirebase();
@@ -164,6 +168,7 @@ class AuthenticationFirebaseDataSourceImpl
Future signInAnonymously() async {
try {
final userCredential = await _firebaseAuth.signInAnonymously();
+ _latestCreds = userCredential;
final user = userCredential.user;
if (user.isNotNull) {
return _mapper(user!);
@@ -199,4 +204,60 @@ class AuthenticationFirebaseDataSourceImpl
throw RefreshFailureFirebase();
}
}
+
+ @override
+ Future reauthenticateWithCredential() async {
+ try {
+ if (_latestCreds?.credential != null) {
+ await _firebaseAuth.currentUser
+ ?.reauthenticateWithCredential(_latestCreds!.credential!);
+ } else {
+ throw Exception(); // Get caught just after.
+ }
+ final user = _firebaseAuth.currentUser;
+ if (user.isNotNull) {
+ return _mapper(user!);
+ } else {
+ throw Exception(); // Get caught just after.
+ }
+ } on FirebaseAuthException catch (e) {
+ throw ReauthenticateFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw ReauthenticateFailureFirebase();
+ }
+ }
+
+ @override
+ Future updateEmail({required String email}) async {
+ try {
+ await _firebaseAuth.currentUser!.updateEmail(email);
+ final user = _firebaseAuth.currentUser;
+ if (user.isNotNull) {
+ return _mapper(user!);
+ } else {
+ throw Exception(); // Get caught just after.
+ }
+ } on FirebaseAuthException catch (e) {
+ throw UpdateEmailFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw UpdateEmailFailureFirebase();
+ }
+ }
+
+ @override
+ Future updatePassword({required String password}) async {
+ try {
+ await _firebaseAuth.currentUser!.updatePassword(password);
+ final user = _firebaseAuth.currentUser;
+ if (user.isNotNull) {
+ return _mapper(user!);
+ } else {
+ throw Exception(); // Get caught just after.
+ }
+ } on FirebaseAuthException catch (e) {
+ throw UpdatePasswordFailureFirebase.fromCode(e.code);
+ } catch (_) {
+ throw UpdatePasswordFailureFirebase();
+ }
+ }
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart
index 1a7fa1d5..67ef28cd 100644
--- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart
@@ -23,6 +23,7 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource {
Pair? _connectedMock;
Pair? _registeredMock;
+ DateTime _lastSignInTime = DateTime.now();
final StreamController _streamAccount = StreamController()
..add(null);
@@ -118,6 +119,7 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource {
);
_streamAccount.add(mock);
_connectedMock = _connectedMock?.copyWith(left: mock);
+ _lastSignInTime = DateTime.now();
return Future.value(mock);
}
@@ -149,6 +151,7 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource {
}
_streamAccount.add(_registeredMock!.left);
_connectedMock = _registeredMock!.copyWith();
+ _lastSignInTime = DateTime.now();
return _registeredMock!.left!;
}
throw SignInWithCredentialFailureFirebase();
@@ -193,6 +196,8 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource {
);
_streamAccount.add(mock);
_registeredMock = Pair(mock, password);
+ _connectedMock = _registeredMock!.copyWith();
+ _lastSignInTime = DateTime.now();
return Future.value(mock);
}
@@ -204,4 +209,45 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource {
await _randomDelay();
return true;
}
+
+ @override
+ Future reauthenticateWithCredential() async {
+ await _randomDelay();
+ if (_connectedMock.isNull) {
+ throw ReauthenticateFailureFirebase();
+ }
+ await refresh();
+ _lastSignInTime = DateTime.now();
+ return Future.value(_connectedMock?.left);
+ }
+
+ @override
+ Future updateEmail({required String email}) {
+ final before = DateTime.now().subtract(const Duration(seconds: 10));
+ if (_lastSignInTime.isBefore(before)) {
+ throw UpdateEmailFailureFirebase('requires-recent-login');
+ }
+ final refresh = DateTime.now();
+ final mock = (_connectedMock?.left as AccountModel?)
+ ?.copyWith(lastSignInTime: refresh, email: email);
+ _connectedMock = _connectedMock?.copyWith(left: mock);
+ _registeredMock = _registeredMock?.copyWith(left: mock);
+ _streamAccount.add(mock);
+ return Future.value(_connectedMock?.left);
+ }
+
+ @override
+ Future updatePassword({required String password}) {
+ final before = DateTime.now().subtract(const Duration(seconds: 10));
+ if (_lastSignInTime.isBefore(before)) {
+ throw UpdatePasswordFailureFirebase('requires-recent-login');
+ }
+ final refresh = DateTime.now();
+ final mock = (_connectedMock?.left as AccountModel?)
+ ?.copyWith(lastSignInTime: refresh);
+ _connectedMock = _connectedMock?.copyWith(left: mock, right: password);
+ _registeredMock = _registeredMock?.copyWith(left: mock, right: password);
+ _streamAccount.add(mock);
+ return Future.value(_connectedMock?.left);
+ }
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart
index f5653592..c0f2c8e1 100644
--- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart
@@ -314,4 +314,38 @@ class AuthenticationRepositoryImpl
},
(error) => error,
);
+
+ @override
+ FutureOrResult reauthenticateWithCredential() =>
+ Result.tryCatchAsync(
+ () async {
+ final account = await _authenticationRemoteDataSource
+ .reauthenticateWithCredential();
+ return account;
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureOrResult updateEmail({required String email}) =>
+ Result.tryCatchAsync(
+ () async {
+ final account =
+ await _authenticationRemoteDataSource.updateEmail(email: email);
+ return account;
+ },
+ (error) => error,
+ );
+
+ @override
+ FutureOrResult updatePassword({required String password}) =>
+ Result.tryCatchAsync(
+ () async {
+ final account = await _authenticationRemoteDataSource.updatePassword(
+ password: password,
+ );
+ return account;
+ },
+ (error) => error,
+ );
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart
index 755aa157..b379de92 100644
--- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart
@@ -48,4 +48,10 @@ abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource {
Future verifyPasswordResetCode({required String code});
Future signInAnonymously();
+
+ Future updateEmail({required String email});
+
+ Future updatePassword({required String password});
+
+ Future reauthenticateWithCredential();
}
diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart
index b88de024..d4b2c23b 100644
--- a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart
+++ b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart
@@ -84,12 +84,45 @@ abstract class AuthenticationRepository extends BaseRepository {
required String password,
});
+ /// {@template update_email}
+ /// Update or add [email].
+ ///
+ /// Throws a UpdateEmailFailureInterface if
+ /// an exception occurs.
+ /// {@endtemplate}
+ FutureOrResult updateEmail({
+ required String email,
+ });
+
+ /// {@template update_password}
+ /// Update or add [password].
+ ///
+ /// Throws a UpdatePasswordFailureInterface if
+ /// an exception occurs.
+ /// {@endtemplate}
+ FutureOrResult updatePassword({
+ required String password,
+ });
+
+ /// {@template reauthenticate}
+ /// Some security-sensitive actions—such as deleting an account,
+ /// setting a primary email address, and changing a password—require that
+ /// the user has recently signed in.
+ ///
+ /// Throws a ReauthenticateFailureInterface if
+ /// an exception occurs.
+ /// {@endtemplate}
+ FutureOrResult reauthenticateWithCredential();
+
/// {@template signout}
/// Signs out the current user.
/// It also clears the cache and the associated data.
/// {@endtemplate}
FutureOrResult signOut();
+ /// {@template refresh}
+ /// Refreshes the current user, if signed in.
+ /// {@endtemplate}
FutureOrResult refresh();
/// {@template stream_account}
diff --git a/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart b/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart
index 999c9104..a571ce69 100644
--- a/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart
+++ b/packages/wyatt_form_bloc/lib/src/presentation/features/widgets/input_builder_text_controller.dart
@@ -48,7 +48,7 @@ class InputBuilderTextController().formName;
+ final formName = context.read().formName;
final value =
context.read().accessForm(formName).valueOf(field);
_controller
diff --git a/packages/wyatt_ui_components/example/lib/component_theme.dart b/packages/wyatt_ui_components/example/lib/component_theme.dart
new file mode 100644
index 00000000..1cf944bf
--- /dev/null
+++ b/packages/wyatt_ui_components/example/lib/component_theme.dart
@@ -0,0 +1,14 @@
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+import 'package:wyatt_ui_components_example/components/custom_app_bar.dart';
+import 'package:wyatt_ui_components_example/components/custom_bottom_bar.dart';
+import 'package:wyatt_ui_components_example/components/custom_error_widget.dart';
+import 'package:wyatt_ui_components_example/components/custom_loading_widget.dart';
+
+class AppThemeComponent {
+ static ComponentThemeData get components => const ComponentThemeData.raw(
+ appBar: CustomAppBar(),
+ bottomNavigationBar: CustomBottomNavigationBar(),
+ errorWidget: CustomErrorWidget(),
+ loadingWidget: CustomLoadingWidget(),
+ );
+}
diff --git a/packages/wyatt_ui_components/example/lib/components/custom_app_bar.dart b/packages/wyatt_ui_components/example/lib/components/custom_app_bar.dart
new file mode 100644
index 00000000..8bac84a7
--- /dev/null
+++ b/packages/wyatt_ui_components/example/lib/components/custom_app_bar.dart
@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+
+class CustomAppBar extends AppBarComponent {
+ const CustomAppBar({super.title, super.key});
+
+ @override
+ Widget build(BuildContext context) => AppBar(
+ title: Text(super.title ?? ''),
+ );
+
+ @override
+ AppBarComponent configure({String? title}) => CustomAppBar(
+ title: title ?? this.title,
+ );
+}
diff --git a/packages/wyatt_ui_components/example/lib/components/custom_bottom_bar.dart b/packages/wyatt_ui_components/example/lib/components/custom_bottom_bar.dart
new file mode 100644
index 00000000..d3c13033
--- /dev/null
+++ b/packages/wyatt_ui_components/example/lib/components/custom_bottom_bar.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+
+class CustomBottomNavigationBar extends BottomNavigationBarComponent {
+ const CustomBottomNavigationBar({
+ super.currentIndex,
+ super.onTap,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) => BottomNavigationBar(
+ currentIndex: currentIndex,
+ onTap: (index) => super.onTap?.call(context, index),
+ items: const [
+ BottomNavigationBarItem(
+ label: 'Icon 1',
+ icon: Icon(
+ Icons.nearby_off,
+ ),
+ ),
+ BottomNavigationBarItem(
+ label: 'Icon 2',
+ icon: Icon(
+ Icons.dangerous,
+ ),
+ ),
+ ],
+ );
+
+ @override
+ CustomBottomNavigationBar configure({
+ void Function(BuildContext, int)? onTap,
+ int currentIndex = 0,
+ }) =>
+ CustomBottomNavigationBar(
+ onTap: onTap ?? this.onTap,
+ currentIndex: currentIndex,
+ );
+}
diff --git a/packages/wyatt_ui_components/example/lib/components/custom_error_widget.dart b/packages/wyatt_ui_components/example/lib/components/custom_error_widget.dart
new file mode 100644
index 00000000..8b2a9b5a
--- /dev/null
+++ b/packages/wyatt_ui_components/example/lib/components/custom_error_widget.dart
@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+
+class CustomErrorWidget extends ErrorWidgetComponent {
+ const CustomErrorWidget({super.error, super.key});
+
+ @override
+ Widget build(BuildContext context) => ColoredBox(
+ color: Colors.red,
+ child: Center(child: Text(error ?? 'Error')),
+ );
+
+ @override
+ ErrorWidgetComponent configure({String? error}) =>
+ CustomErrorWidget(error: error ?? this.error);
+}
diff --git a/packages/wyatt_ui_components/example/lib/components/custom_loading_widget.dart b/packages/wyatt_ui_components/example/lib/components/custom_loading_widget.dart
new file mode 100644
index 00000000..912312fe
--- /dev/null
+++ b/packages/wyatt_ui_components/example/lib/components/custom_loading_widget.dart
@@ -0,0 +1,18 @@
+import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+
+class CustomLoadingWidget extends LoadingWidgetComponent {
+ const CustomLoadingWidget({super.color, super.key});
+
+ @override
+ Widget build(BuildContext context) => Center(
+ child: CircularProgressIndicator(
+ color: color,
+ ),
+ );
+
+ @override
+ CustomLoadingWidget configure({Color? color}) => CustomLoadingWidget(
+ color: color ?? this.color,
+ );
+}
diff --git a/packages/wyatt_ui_components/example/lib/main.dart b/packages/wyatt_ui_components/example/lib/main.dart
index 840b81d6..673d614a 100644
--- a/packages/wyatt_ui_components/example/lib/main.dart
+++ b/packages/wyatt_ui_components/example/lib/main.dart
@@ -15,6 +15,8 @@
// along with this program. If not, see .
import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+import 'package:wyatt_ui_components_example/component_theme.dart';
void main() {
runApp(const MyApp());
@@ -26,17 +28,45 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Wyatt Ui Components Example',
- theme: ThemeData(
- primarySwatch: Colors.blue,
- ),
- home: Scaffold(
- appBar: AppBar(
- title: const Text('Wyatt Ui Components Example'),
+ return ComponentTheme(
+ componentThemeWidget: AppThemeComponent.components,
+ child: MaterialApp(
+ title: 'Wyatt Ui Components Example',
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ ),
+ home: const Scaffold(
+ body: Home(),
),
- body: const Center(child: Text('')),
),
);
}
}
+
+class Home extends StatelessWidget {
+ const Home({super.key});
+
+ @override
+ Widget build(BuildContext context) => Scaffold(
+ appBar: PreferredSize(
+ preferredSize: const Size.fromHeight(60),
+ child: context.components.appBar.configure(title: 'Example title'),
+ ),
+ body: Column(
+ children: [
+ Expanded(
+ child: context.components.errorWidget
+ .configure(error: 'Example erreur'),
+ ),
+ const SizedBox(
+ height: 10,
+ ),
+ Expanded(
+ child: context.components.loadingWidget
+ .configure(color: Colors.green),
+ ),
+ ],
+ ),
+ bottomNavigationBar: context.components.bottomNavigationBar,
+ );
+}
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/component.dart
new file mode 100644
index 00000000..04e60ebc
--- /dev/null
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/component.dart
@@ -0,0 +1,7 @@
+import 'package:flutter/material.dart';
+
+abstract class Component extends StatelessWidget {
+ const Component({super.key});
+
+ Component configure();
+}
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/components.dart b/packages/wyatt_ui_components/lib/src/domain/entities/components.dart
index 496f50ce..be6d79e2 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/components.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/components.dart
@@ -15,19 +15,17 @@
// along with this program. If not, see .
import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/src/domain/entities/component.dart';
-abstract class AppBarComponent extends PreferredSize {
+abstract class AppBarComponent extends Component {
final String? title;
- const AppBarComponent({this.title, super.key})
- : super(
- preferredSize: const Size.fromHeight(60),
- child: const SizedBox.shrink(),
- );
+ const AppBarComponent({this.title, super.key});
+ @override
AppBarComponent configure({String? title});
}
-abstract class BottomNavigationBarComponent extends StatelessWidget {
+abstract class BottomNavigationBarComponent extends Component {
final int currentIndex;
final void Function(BuildContext, int)? onTap;
const BottomNavigationBarComponent({
@@ -36,8 +34,25 @@ abstract class BottomNavigationBarComponent extends StatelessWidget {
super.key,
});
+ @override
BottomNavigationBarComponent configure({
void Function(BuildContext, int)? onTap,
int currentIndex = 0,
});
}
+
+abstract class ErrorWidgetComponent extends Component {
+ final String? error;
+ const ErrorWidgetComponent({required this.error, super.key});
+
+ @override
+ ErrorWidgetComponent configure({String? error});
+}
+
+abstract class LoadingWidgetComponent extends Component {
+ final Color? color;
+ const LoadingWidgetComponent({required this.color, super.key});
+
+ @override
+ LoadingWidgetComponent configure({Color? color});
+}
diff --git a/packages/wyatt_ui_components/lib/src/features/component_theme_data.dart b/packages/wyatt_ui_components/lib/src/features/component_theme_data.dart
index 0e6ddf34..66540540 100644
--- a/packages/wyatt_ui_components/lib/src/features/component_theme_data.dart
+++ b/packages/wyatt_ui_components/lib/src/features/component_theme_data.dart
@@ -19,9 +19,13 @@ import 'package:wyatt_ui_components/src/domain/entities/components.dart';
class ComponentThemeData {
final AppBarComponent appBar;
final BottomNavigationBarComponent bottomNavigationBar;
+ final ErrorWidgetComponent errorWidget;
+ final LoadingWidgetComponent loadingWidget;
const ComponentThemeData.raw({
required this.appBar,
required this.bottomNavigationBar,
+ required this.errorWidget,
+ required this.loadingWidget,
});
}
diff --git a/packages/wyatt_ui_layout/README.md b/packages/wyatt_ui_layout/README.md
index 7f0c4c68..2cbb1aab 100644
--- a/packages/wyatt_ui_layout/README.md
+++ b/packages/wyatt_ui_layout/README.md
@@ -32,3 +32,4 @@ Wyatt Ui Layout for Flutter
- Layouts :
- App Bar Layout
- Bottom Navigation Bar Layout
+ - Frame Layout (wrapp both appbar & bottom bar)
diff --git a/packages/wyatt_ui_layout/lib/src/presentation/layouts/frame_layout.dart b/packages/wyatt_ui_layout/lib/src/presentation/layouts/frame_layout.dart
new file mode 100644
index 00000000..ebe8f13b
--- /dev/null
+++ b/packages/wyatt_ui_layout/lib/src/presentation/layouts/frame_layout.dart
@@ -0,0 +1,41 @@
+// 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 .
+
+import 'package:flutter/material.dart';
+import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
+import 'package:wyatt_ui_layout/src/presentation/layouts/layout.dart';
+
+class FrameLayout extends Layout {
+ final String title;
+ final Widget body;
+ final int currentIndex;
+
+ const FrameLayout({
+ required this.title,
+ required this.body,
+ required this.currentIndex,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) => Scaffold(
+ appBar: context.components.appBar.configure(title: title),
+ body: body,
+ bottomNavigationBar: context.components.bottomNavigationBar.configure(
+ currentIndex: currentIndex,
+ ),
+ );
+}
diff --git a/packages/wyatt_ui_layout/lib/src/presentation/presentation.dart b/packages/wyatt_ui_layout/lib/src/presentation/presentation.dart
index b9ee6729..a1bff66c 100644
--- a/packages/wyatt_ui_layout/lib/src/presentation/presentation.dart
+++ b/packages/wyatt_ui_layout/lib/src/presentation/presentation.dart
@@ -1,2 +1,3 @@
export 'layouts/app_bar_layout.dart';
export 'layouts/bottom_navigation_bar_layout.dart';
+export 'layouts/frame_layout.dart';