From 5298bd99ed819358f7cadf19bb250d89b127b2bd Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Sat, 3 Dec 2022 20:12:08 -0500 Subject: [PATCH 1/4] feat(authentication): add reauthenticate, updateEmail and updatePassword --- .../lib/src/core/exceptions/exceptions.dart | 21 ++++++ .../core/exceptions/exceptions_firebase.dart | 72 +++++++++++++++++++ ...hentication_firebase_data_source_impl.dart | 61 ++++++++++++++++ .../authentication_mock_data_source_impl.dart | 45 ++++++++++++ .../authentication_repository_impl.dart | 34 +++++++++ .../authentication_remote_data_source.dart | 6 ++ .../authentication_repository.dart | 33 +++++++++ 7 files changed, 272 insertions(+) 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..1d750629 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,7 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource { ); _streamAccount.add(mock); _registeredMock = Pair(mock, password); + _lastSignInTime = DateTime.now(); return Future.value(mock); } @@ -204,4 +208,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} -- 2.47.2 From 94d7efbe8caaa5d321424baf21193003738c2890 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 7 Dec 2022 19:43:25 -0500 Subject: [PATCH 2/4] fix(form): fix textController rebuild --- .../features/widgets/input_builder_text_controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 -- 2.47.2 From 672aba708464e1b08127d96f50641d5902307eb7 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 7 Dec 2022 19:45:25 -0500 Subject: [PATCH 3/4] fix(auth): fix mock on register --- .../remote/authentication_mock_data_source_impl.dart | 1 + 1 file changed, 1 insertion(+) 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 1d750629..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 @@ -196,6 +196,7 @@ class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource { ); _streamAccount.add(mock); _registeredMock = Pair(mock, password); + _connectedMock = _registeredMock!.copyWith(); _lastSignInTime = DateTime.now(); return Future.value(mock); } -- 2.47.2 From 5e83c9e74e7c2cffb5c7981a0c5e49ec3cf3e764 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 7 Dec 2022 19:47:47 -0500 Subject: [PATCH 4/4] docs(auth): add correct header --- .../example/lib/bootstrap.dart | 23 +-- .../lib/core/constants/form_field.dart | 24 ++-- .../example/lib/core/constants/form_name.dart | 19 +++ .../example/lib/core/routes/router.dart | 33 +++-- .../lib/core/utils/app_bloc_observer.dart | 23 +-- .../example/lib/core/utils/forms.dart | 32 +++++ .../example/lib/main.dart | 16 +++ .../lib/presentation/features/app/app.dart | 53 +++---- .../blocs/edit_profile_cubit.dart | 74 ++++++++++ .../edit_profile/edit_profile_page.dart | 61 ++++++++ .../widgets/edit_profile_form.dart | 136 ++++++++++++++++++ .../presentation/features/home/home_page.dart | 40 ++++-- .../features/sign_in/sign_in_page.dart | 23 +-- .../sign_in/widgets/sign_in_form.dart | 23 +-- .../features/sign_up/sign_up_page.dart | 23 +-- .../sign_up/widgets/sign_up_form.dart | 23 +-- .../presentation/features/sub/sub_page.dart | 28 ++-- .../features/welcome/welcome_page.dart | 23 +-- 18 files changed, 557 insertions(+), 120 deletions(-) create mode 100644 packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart create mode 100644 packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart create mode 100644 packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart create mode 100644 packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart create mode 100644 packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart 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'; -- 2.47.2