diff --git a/assets/FpbIcons/blue_circle_check_mark.svg b/assets/FpbIcons/blue_circle_check_mark.svg
new file mode 100644
index 0000000..05f7d69
--- /dev/null
+++ b/assets/FpbIcons/blue_circle_check_mark.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/email_confirmation/view/email_confirmation_screen.dart b/lib/email_confirmation/view/email_confirmation_screen.dart
index cc85044..4013bf8 100644
--- a/lib/email_confirmation/view/email_confirmation_screen.dart
+++ b/lib/email_confirmation/view/email_confirmation_screen.dart
@@ -1,13 +1,21 @@
+import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:fpb/core/presentation/widget/confirmation_screen_illustration.dart';
import 'package:fpb/core/presentation/widget/otp_group_text_field.dart';
import 'package:fpb/l10n/l10n.dart';
import 'package:fpb/core/presentation/widget/confirmation_screen_actions.dart';
+import 'package:fpb/router/app_route.gr.dart';
class EmailConfirmationScreen extends StatefulWidget {
static const routeName = '/emailConfirmation';
- const EmailConfirmationScreen({super.key});
+ const EmailConfirmationScreen({
+ super.key,
+ required this.emailControllerValue,
+ required this.submitValue,
+ });
+ final String emailControllerValue;
+ final bool submitValue;
@override
State createState() =>
@@ -85,7 +93,9 @@ class _EmailConfirmationScreenState extends State {
Align(
alignment: Alignment.bottomCenter,
child: ConfirmationScreenAction(
- onTapConfirmButton: () {},
+ onTapConfirmButton: () {
+ context.router.push(CreateNewPasswordRoute());
+ },
confirmButtonLabel: l10n.confirmEmailResendButton,
onTapContactUsButton: () {},
),
diff --git a/lib/forgot_password_flow/application/bloc/forgot_password_bloc.dart b/lib/forgot_password_flow/application/bloc/forgot_password_bloc.dart
new file mode 100644
index 0000000..6cdaff8
--- /dev/null
+++ b/lib/forgot_password_flow/application/bloc/forgot_password_bloc.dart
@@ -0,0 +1,27 @@
+import 'package:bloc/bloc.dart';
+import 'package:fpb/forgot_password_flow/domain/i_forgot_password_facade.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:injectable/injectable.dart';
+
+part 'forgot_password_event.dart';
+part 'forgot_password_state.dart';
+part 'forgot_password_bloc.freezed.dart';
+
+@injectable
+class ForgotPasswordBloc
+ extends Bloc {
+ ForgotPasswordBloc(super.initialState,
+ {required this.forgotPasswordRepositoryFacade}) {
+ on(_onPasswordChanged);
+ // on(_onOtpSent);
+ }
+
+ final IForgotPasswordRepositoryFacade forgotPasswordRepositoryFacade;
+
+ Future _onPasswordChanged(
+ PasswordChanged event,
+ Emitter emit,
+ ) async {
+ await forgotPasswordRepositoryFacade.changePassword(state.newPassword);
+ }
+}
diff --git a/lib/forgot_password_flow/application/bloc/forgot_password_bloc.freezed.dart b/lib/forgot_password_flow/application/bloc/forgot_password_bloc.freezed.dart
new file mode 100644
index 0000000..f616f13
--- /dev/null
+++ b/lib/forgot_password_flow/application/bloc/forgot_password_bloc.freezed.dart
@@ -0,0 +1,680 @@
+// coverage:ignore-file
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
+
+part of 'forgot_password_bloc.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+T _$identity(T value) => value;
+
+final _privateConstructorUsedError = UnsupportedError(
+ 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
+
+/// @nodoc
+mixin _$ForgotPasswordEvent {
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() passwordChanged,
+ required TResult Function() otpSent,
+ required TResult Function() otpVerified,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? passwordChanged,
+ TResult? Function()? otpSent,
+ TResult? Function()? otpVerified,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? passwordChanged,
+ TResult Function()? otpSent,
+ TResult Function()? otpVerified,
+ required TResult orElse(),
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(PasswordChanged value) passwordChanged,
+ required TResult Function(OtpSent value) otpSent,
+ required TResult Function(OtpVerified value) otpVerified,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(PasswordChanged value)? passwordChanged,
+ TResult? Function(OtpSent value)? otpSent,
+ TResult? Function(OtpVerified value)? otpVerified,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(PasswordChanged value)? passwordChanged,
+ TResult Function(OtpSent value)? otpSent,
+ TResult Function(OtpVerified value)? otpVerified,
+ required TResult orElse(),
+ }) =>
+ throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $ForgotPasswordEventCopyWith<$Res> {
+ factory $ForgotPasswordEventCopyWith(
+ ForgotPasswordEvent value, $Res Function(ForgotPasswordEvent) then) =
+ _$ForgotPasswordEventCopyWithImpl<$Res, ForgotPasswordEvent>;
+}
+
+/// @nodoc
+class _$ForgotPasswordEventCopyWithImpl<$Res, $Val extends ForgotPasswordEvent>
+ implements $ForgotPasswordEventCopyWith<$Res> {
+ _$ForgotPasswordEventCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+}
+
+/// @nodoc
+abstract class _$$_StartedCopyWith<$Res> {
+ factory _$$_StartedCopyWith(
+ _$_Started value, $Res Function(_$_Started) then) =
+ __$$_StartedCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$_StartedCopyWithImpl<$Res>
+ extends _$ForgotPasswordEventCopyWithImpl<$Res, _$_Started>
+ implements _$$_StartedCopyWith<$Res> {
+ __$$_StartedCopyWithImpl(_$_Started _value, $Res Function(_$_Started) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$_Started implements _Started {
+ const _$_Started();
+
+ @override
+ String toString() {
+ return 'ForgotPasswordEvent.started()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$_Started);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() passwordChanged,
+ required TResult Function() otpSent,
+ required TResult Function() otpVerified,
+ }) {
+ return started();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? passwordChanged,
+ TResult? Function()? otpSent,
+ TResult? Function()? otpVerified,
+ }) {
+ return started?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? passwordChanged,
+ TResult Function()? otpSent,
+ TResult Function()? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (started != null) {
+ return started();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(PasswordChanged value) passwordChanged,
+ required TResult Function(OtpSent value) otpSent,
+ required TResult Function(OtpVerified value) otpVerified,
+ }) {
+ return started(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(PasswordChanged value)? passwordChanged,
+ TResult? Function(OtpSent value)? otpSent,
+ TResult? Function(OtpVerified value)? otpVerified,
+ }) {
+ return started?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(PasswordChanged value)? passwordChanged,
+ TResult Function(OtpSent value)? otpSent,
+ TResult Function(OtpVerified value)? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (started != null) {
+ return started(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class _Started implements ForgotPasswordEvent {
+ const factory _Started() = _$_Started;
+}
+
+/// @nodoc
+abstract class _$$PasswordChangedCopyWith<$Res> {
+ factory _$$PasswordChangedCopyWith(
+ _$PasswordChanged value, $Res Function(_$PasswordChanged) then) =
+ __$$PasswordChangedCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$PasswordChangedCopyWithImpl<$Res>
+ extends _$ForgotPasswordEventCopyWithImpl<$Res, _$PasswordChanged>
+ implements _$$PasswordChangedCopyWith<$Res> {
+ __$$PasswordChangedCopyWithImpl(
+ _$PasswordChanged _value, $Res Function(_$PasswordChanged) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$PasswordChanged implements PasswordChanged {
+ const _$PasswordChanged();
+
+ @override
+ String toString() {
+ return 'ForgotPasswordEvent.passwordChanged()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$PasswordChanged);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() passwordChanged,
+ required TResult Function() otpSent,
+ required TResult Function() otpVerified,
+ }) {
+ return passwordChanged();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? passwordChanged,
+ TResult? Function()? otpSent,
+ TResult? Function()? otpVerified,
+ }) {
+ return passwordChanged?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? passwordChanged,
+ TResult Function()? otpSent,
+ TResult Function()? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (passwordChanged != null) {
+ return passwordChanged();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(PasswordChanged value) passwordChanged,
+ required TResult Function(OtpSent value) otpSent,
+ required TResult Function(OtpVerified value) otpVerified,
+ }) {
+ return passwordChanged(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(PasswordChanged value)? passwordChanged,
+ TResult? Function(OtpSent value)? otpSent,
+ TResult? Function(OtpVerified value)? otpVerified,
+ }) {
+ return passwordChanged?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(PasswordChanged value)? passwordChanged,
+ TResult Function(OtpSent value)? otpSent,
+ TResult Function(OtpVerified value)? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (passwordChanged != null) {
+ return passwordChanged(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class PasswordChanged implements ForgotPasswordEvent {
+ const factory PasswordChanged() = _$PasswordChanged;
+}
+
+/// @nodoc
+abstract class _$$OtpSentCopyWith<$Res> {
+ factory _$$OtpSentCopyWith(_$OtpSent value, $Res Function(_$OtpSent) then) =
+ __$$OtpSentCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$OtpSentCopyWithImpl<$Res>
+ extends _$ForgotPasswordEventCopyWithImpl<$Res, _$OtpSent>
+ implements _$$OtpSentCopyWith<$Res> {
+ __$$OtpSentCopyWithImpl(_$OtpSent _value, $Res Function(_$OtpSent) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$OtpSent implements OtpSent {
+ const _$OtpSent();
+
+ @override
+ String toString() {
+ return 'ForgotPasswordEvent.otpSent()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$OtpSent);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() passwordChanged,
+ required TResult Function() otpSent,
+ required TResult Function() otpVerified,
+ }) {
+ return otpSent();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? passwordChanged,
+ TResult? Function()? otpSent,
+ TResult? Function()? otpVerified,
+ }) {
+ return otpSent?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? passwordChanged,
+ TResult Function()? otpSent,
+ TResult Function()? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (otpSent != null) {
+ return otpSent();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(PasswordChanged value) passwordChanged,
+ required TResult Function(OtpSent value) otpSent,
+ required TResult Function(OtpVerified value) otpVerified,
+ }) {
+ return otpSent(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(PasswordChanged value)? passwordChanged,
+ TResult? Function(OtpSent value)? otpSent,
+ TResult? Function(OtpVerified value)? otpVerified,
+ }) {
+ return otpSent?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(PasswordChanged value)? passwordChanged,
+ TResult Function(OtpSent value)? otpSent,
+ TResult Function(OtpVerified value)? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (otpSent != null) {
+ return otpSent(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class OtpSent implements ForgotPasswordEvent {
+ const factory OtpSent() = _$OtpSent;
+}
+
+/// @nodoc
+abstract class _$$OtpVerifiedCopyWith<$Res> {
+ factory _$$OtpVerifiedCopyWith(
+ _$OtpVerified value, $Res Function(_$OtpVerified) then) =
+ __$$OtpVerifiedCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$OtpVerifiedCopyWithImpl<$Res>
+ extends _$ForgotPasswordEventCopyWithImpl<$Res, _$OtpVerified>
+ implements _$$OtpVerifiedCopyWith<$Res> {
+ __$$OtpVerifiedCopyWithImpl(
+ _$OtpVerified _value, $Res Function(_$OtpVerified) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$OtpVerified implements OtpVerified {
+ const _$OtpVerified();
+
+ @override
+ String toString() {
+ return 'ForgotPasswordEvent.otpVerified()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$OtpVerified);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() passwordChanged,
+ required TResult Function() otpSent,
+ required TResult Function() otpVerified,
+ }) {
+ return otpVerified();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? passwordChanged,
+ TResult? Function()? otpSent,
+ TResult? Function()? otpVerified,
+ }) {
+ return otpVerified?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? passwordChanged,
+ TResult Function()? otpSent,
+ TResult Function()? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (otpVerified != null) {
+ return otpVerified();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(PasswordChanged value) passwordChanged,
+ required TResult Function(OtpSent value) otpSent,
+ required TResult Function(OtpVerified value) otpVerified,
+ }) {
+ return otpVerified(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(PasswordChanged value)? passwordChanged,
+ TResult? Function(OtpSent value)? otpSent,
+ TResult? Function(OtpVerified value)? otpVerified,
+ }) {
+ return otpVerified?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(PasswordChanged value)? passwordChanged,
+ TResult Function(OtpSent value)? otpSent,
+ TResult Function(OtpVerified value)? otpVerified,
+ required TResult orElse(),
+ }) {
+ if (otpVerified != null) {
+ return otpVerified(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class OtpVerified implements ForgotPasswordEvent {
+ const factory OtpVerified() = _$OtpVerified;
+}
+
+/// @nodoc
+mixin _$ForgotPasswordState {
+ bool get isLoading => throw _privateConstructorUsedError;
+ String get newPassword => throw _privateConstructorUsedError;
+
+ @JsonKey(ignore: true)
+ $ForgotPasswordStateCopyWith get copyWith =>
+ throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $ForgotPasswordStateCopyWith<$Res> {
+ factory $ForgotPasswordStateCopyWith(
+ ForgotPasswordState value, $Res Function(ForgotPasswordState) then) =
+ _$ForgotPasswordStateCopyWithImpl<$Res, ForgotPasswordState>;
+ @useResult
+ $Res call({bool isLoading, String newPassword});
+}
+
+/// @nodoc
+class _$ForgotPasswordStateCopyWithImpl<$Res, $Val extends ForgotPasswordState>
+ implements $ForgotPasswordStateCopyWith<$Res> {
+ _$ForgotPasswordStateCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? isLoading = null,
+ Object? newPassword = null,
+ }) {
+ return _then(_value.copyWith(
+ isLoading: null == isLoading
+ ? _value.isLoading
+ : isLoading // ignore: cast_nullable_to_non_nullable
+ as bool,
+ newPassword: null == newPassword
+ ? _value.newPassword
+ : newPassword // ignore: cast_nullable_to_non_nullable
+ as String,
+ ) as $Val);
+ }
+}
+
+/// @nodoc
+abstract class _$$_ForgotPasswordStateCopyWith<$Res>
+ implements $ForgotPasswordStateCopyWith<$Res> {
+ factory _$$_ForgotPasswordStateCopyWith(_$_ForgotPasswordState value,
+ $Res Function(_$_ForgotPasswordState) then) =
+ __$$_ForgotPasswordStateCopyWithImpl<$Res>;
+ @override
+ @useResult
+ $Res call({bool isLoading, String newPassword});
+}
+
+/// @nodoc
+class __$$_ForgotPasswordStateCopyWithImpl<$Res>
+ extends _$ForgotPasswordStateCopyWithImpl<$Res, _$_ForgotPasswordState>
+ implements _$$_ForgotPasswordStateCopyWith<$Res> {
+ __$$_ForgotPasswordStateCopyWithImpl(_$_ForgotPasswordState _value,
+ $Res Function(_$_ForgotPasswordState) _then)
+ : super(_value, _then);
+
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? isLoading = null,
+ Object? newPassword = null,
+ }) {
+ return _then(_$_ForgotPasswordState(
+ isLoading: null == isLoading
+ ? _value.isLoading
+ : isLoading // ignore: cast_nullable_to_non_nullable
+ as bool,
+ newPassword: null == newPassword
+ ? _value.newPassword
+ : newPassword // ignore: cast_nullable_to_non_nullable
+ as String,
+ ));
+ }
+}
+
+/// @nodoc
+
+class _$_ForgotPasswordState implements _ForgotPasswordState {
+ const _$_ForgotPasswordState({this.isLoading = false, this.newPassword = ''});
+
+ @override
+ @JsonKey()
+ final bool isLoading;
+ @override
+ @JsonKey()
+ final String newPassword;
+
+ @override
+ String toString() {
+ return 'ForgotPasswordState(isLoading: $isLoading, newPassword: $newPassword)';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType &&
+ other is _$_ForgotPasswordState &&
+ (identical(other.isLoading, isLoading) ||
+ other.isLoading == isLoading) &&
+ (identical(other.newPassword, newPassword) ||
+ other.newPassword == newPassword));
+ }
+
+ @override
+ int get hashCode => Object.hash(runtimeType, isLoading, newPassword);
+
+ @JsonKey(ignore: true)
+ @override
+ @pragma('vm:prefer-inline')
+ _$$_ForgotPasswordStateCopyWith<_$_ForgotPasswordState> get copyWith =>
+ __$$_ForgotPasswordStateCopyWithImpl<_$_ForgotPasswordState>(
+ this, _$identity);
+}
+
+abstract class _ForgotPasswordState implements ForgotPasswordState {
+ const factory _ForgotPasswordState(
+ {final bool isLoading,
+ final String newPassword}) = _$_ForgotPasswordState;
+
+ @override
+ bool get isLoading;
+ @override
+ String get newPassword;
+ @override
+ @JsonKey(ignore: true)
+ _$$_ForgotPasswordStateCopyWith<_$_ForgotPasswordState> get copyWith =>
+ throw _privateConstructorUsedError;
+}
diff --git a/lib/forgot_password_flow/application/bloc/forgot_password_event.dart b/lib/forgot_password_flow/application/bloc/forgot_password_event.dart
new file mode 100644
index 0000000..85ddd0e
--- /dev/null
+++ b/lib/forgot_password_flow/application/bloc/forgot_password_event.dart
@@ -0,0 +1,9 @@
+part of 'forgot_password_bloc.dart';
+
+@freezed
+class ForgotPasswordEvent with _$ForgotPasswordEvent {
+ const factory ForgotPasswordEvent.started() = _Started;
+ const factory ForgotPasswordEvent.passwordChanged() = PasswordChanged;
+ const factory ForgotPasswordEvent.otpSent() = OtpSent;
+ const factory ForgotPasswordEvent.otpVerified() = OtpVerified;
+}
diff --git a/lib/forgot_password_flow/application/bloc/forgot_password_state.dart b/lib/forgot_password_flow/application/bloc/forgot_password_state.dart
new file mode 100644
index 0000000..d7531cc
--- /dev/null
+++ b/lib/forgot_password_flow/application/bloc/forgot_password_state.dart
@@ -0,0 +1,9 @@
+part of 'forgot_password_bloc.dart';
+
+@freezed
+class ForgotPasswordState with _$ForgotPasswordState {
+ const factory ForgotPasswordState({
+ @Default(false) bool isLoading,
+ @Default('') String newPassword,
+ }) = _ForgotPasswordState;
+}
diff --git a/lib/forgot_password_flow/create_new_password.dart b/lib/forgot_password_flow/create_new_password.dart
new file mode 100644
index 0000000..e84c7b5
--- /dev/null
+++ b/lib/forgot_password_flow/create_new_password.dart
@@ -0,0 +1,176 @@
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:fpb/assets/fpb_svg.dart';
+import 'package:fpb/core/presentation/extension/extensions.dart';
+import 'package:fpb/core/presentation/widget/fpb_button.dart';
+import 'package:fpb/core/presentation/widget/fpb_text_form_field.dart';
+import 'package:fpb/core/shared/helpers/is_keyboard_visible.dart';
+import 'package:fpb/l10n/l10n.dart';
+import 'package:fpb/router/app_route.gr.dart';
+
+class CreateNewPasswordScreen extends StatefulWidget {
+ const CreateNewPasswordScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() =>
+ _CreateNewPasswordScreenState();
+}
+
+class _CreateNewPasswordScreenState extends State {
+ final FocusNode? node = FocusNode();
+ final TextEditingController passwordController = TextEditingController();
+ final TextEditingController confirmPasswordController =
+ TextEditingController();
+ bool _isLoading = false;
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = context.l10n;
+ final theme = Theme.of(context);
+ // final style = theme.textTheme;
+ // final colors = theme.colorScheme;
+
+ return LayoutBuilder(
+ builder: (context, cts) {
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ body: Stack(
+ children: [
+ BubblesTopBackGround(
+ cts: cts,
+ svgName: SvgNames.authBackground,
+ ),
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ PageTitle(
+ title: l10n.createNewPasswordTitle,
+ box: cts,
+ ),
+ SizedBox(
+ height: 0.025 * cts.maxHeight,
+ ),
+ Text(
+ l10n.createNewPasswordBodyContent,
+ style: TextStyle(
+ height: 1.5,
+ ),
+ ),
+ SizedBox(
+ height: 0.05 * cts.maxHeight,
+ ),
+ FpbTextFormField(
+ key: const Key('password_textField_create_new_password'),
+ box: cts,
+ label: l10n.signInPasswordFieldLabel,
+ hint: l10n.signInPasswordFieldHintText,
+ node: node,
+ isPassword: true,
+ textController: passwordController,
+ onChanged: (value) {
+ passwordController.text = value;
+ },
+ // errorText: state.email.invalid ? 'Invalid Email' : null,
+ ),
+ FpbTextFormField(
+ key: const Key(
+ 'confirm_password_textField_create_new_password'),
+ box: cts,
+ label: l10n.createNewPasswordConfirmPasswordLabel,
+ hint: l10n.signInPasswordFieldHintText,
+ node: node,
+ isPassword: true,
+ textController: confirmPasswordController,
+ onChanged: (value) {
+ setState(() {
+ confirmPasswordController.text = value;
+ });
+ },
+ // errorText: state.email.invalid ? 'Invalid Email' : null,
+ ),
+ SizedBox(
+ height: 0.03 * cts.maxHeight,
+ ),
+ _isLoading
+ ? CircularProgressIndicator()
+ : FpbButton(
+ label: l10n.createNewPasswordResetButtonLabel,
+ onTap: () {
+ setState(() {
+ _isLoading = true;
+ }); // passwordController.text == confirmPasswordController.text
+ // ? _submit(passwordController.text)
+ // : print("failed");
+
+ setState(() {
+ _isLoading = false;
+ });
+ Navigator.of(context).pop();
+ context.router.push(NewPasswordSuccessRoute());
+ },
+ ),
+ ],
+ ).card(
+ height:
+ (isKeyboardVisible(context) ? .80 : .8) * cts.maxHeight,
+ radiusTop: cts.maxWidth * 0.05,
+ color: theme.colorScheme.background,
+ padding: EdgeInsets.all(cts.maxHeight * 0.025),
+ ),
+ )
+ ],
+ ).card(
+ radiusTop: cts.maxWidth * 0.05,
+ color: theme.colorScheme.background,
+ ),
+ );
+ },
+ );
+ }
+}
+
+class PageTitle extends StatelessWidget {
+ const PageTitle({
+ super.key,
+ required this.title,
+ required this.box,
+ });
+ final String title;
+ final BoxConstraints box;
+
+ @override
+ Widget build(BuildContext context) {
+ return Text(
+ title,
+ style: Theme.of(context).textTheme.titleLarge?.copyWith(
+ fontSize: box.maxWidth * 0.085,
+ fontWeight: FontWeight.w700,
+ ),
+ );
+ }
+}
+
+class BubblesTopBackGround extends StatelessWidget {
+ const BubblesTopBackGround({
+ super.key,
+ required this.cts,
+ required this.svgName,
+ });
+ final BoxConstraints cts;
+ final String svgName;
+
+ @override
+ Widget build(BuildContext context) {
+ return Positioned(
+ top: -.035 * cts.maxHeight,
+ child: SvgPicture.asset(
+ svgName,
+ width: cts.maxWidth,
+ height: 0.4 * cts.maxHeight,
+ ),
+ );
+ }
+}
diff --git a/lib/forgot_password_flow/domain/i_forgot_password_facade.dart b/lib/forgot_password_flow/domain/i_forgot_password_facade.dart
new file mode 100644
index 0000000..802322e
--- /dev/null
+++ b/lib/forgot_password_flow/domain/i_forgot_password_facade.dart
@@ -0,0 +1,7 @@
+import 'package:dartz/dartz.dart';
+import 'package:fpb/core/failures/auth_failure.dart';
+
+abstract class IForgotPasswordRepositoryFacade {
+ Future authenticate(String email, String password, String urlSegment);
+ Future> changePassword(String newPassword);
+}
diff --git a/lib/forgot_password_flow/forgot_password.dart b/lib/forgot_password_flow/forgot_password.dart
new file mode 100644
index 0000000..31f79d7
--- /dev/null
+++ b/lib/forgot_password_flow/forgot_password.dart
@@ -0,0 +1,163 @@
+import 'package:auto_route/auto_route.dart';
+import 'package:email_auth/email_auth.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:fpb/assets/fpb_svg.dart';
+import 'package:fpb/core/presentation/extension/extensions.dart';
+import 'package:fpb/core/presentation/widget/fpb_button.dart';
+import 'package:fpb/core/presentation/widget/fpb_text_form_field.dart';
+import 'package:fpb/core/shared/helpers/is_keyboard_visible.dart';
+import 'package:fpb/l10n/l10n.dart';
+import 'package:fpb/router/app_route.gr.dart';
+
+class ForgotPasswordScreen extends StatefulWidget {
+ const ForgotPasswordScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _ForgotPasswordScreenState();
+}
+
+class _ForgotPasswordScreenState extends State {
+ final FocusNode node = FocusNode();
+ final TextEditingController emailAddressController = TextEditingController();
+ bool submitValid = false;
+ EmailAuth emailAuth = EmailAuth(sessionName: '');
+ bool result = false;
+
+ Future sendOtp() async {
+ emailAuth.sessionName = "FlutterPlaza";
+ bool? result = await emailAuth.sendOtp(
+ recipientMail: emailAddressController.value.text,
+ );
+ if (result) {
+ setState(() {
+ submitValid = true;
+ });
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = context.l10n;
+ final theme = Theme.of(context);
+ // final style = theme.textTheme;
+ // final colors = theme.colorScheme;
+
+ return LayoutBuilder(
+ builder: (context, cts) {
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ body: Stack(
+ children: [
+ BubblesTopBackGround(
+ cts: cts,
+ svgName: SvgNames.authBackground,
+ ),
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ PageTitle(
+ title: l10n.forgotPasswordTitle,
+ box: cts,
+ ),
+ SizedBox(
+ height: 0.025 * cts.maxHeight,
+ ),
+ Text(
+ l10n.forgotPasswordBodyContent,
+ style: TextStyle(
+ height: 1.5,
+ ),
+ ),
+ SizedBox(
+ height: 0.08 * cts.maxHeight,
+ ),
+ FpbTextFormField(
+ key: const Key('email_textField_forgotPassword'),
+ box: cts,
+ label: l10n.forgotPasswordEmailTextFieldLabel,
+ hint: l10n.forgotPasswordEmailTextFieldHint,
+ node: node,
+ isEmail: true,
+ textController: emailAddressController,
+ onChanged: (value) {},
+ // errorText: state.email.invalid ? 'Invalid Email' : null,
+ ),
+ SizedBox(
+ height: 0.03 * cts.maxHeight,
+ ),
+ FpbButton(
+ label: l10n.forgotPasswordSendButtonLabel,
+ onTap: () async {
+ await sendOtp();
+ context.router.push(EmailConfirmationRoute(
+ emailControllerValue:
+ emailAddressController.value.text,
+ submitValue: submitValid,
+ ));
+ },
+ ),
+ ],
+ ).card(
+ height:
+ (isKeyboardVisible(context) ? .80 : .8) * cts.maxHeight,
+ radiusTop: cts.maxWidth * 0.05,
+ color: theme.colorScheme.background,
+ padding: EdgeInsets.all(cts.maxHeight * 0.025),
+ ),
+ )
+ ],
+ ).card(
+ radiusTop: cts.maxWidth * 0.05,
+ color: theme.colorScheme.background,
+ ),
+ );
+ },
+ );
+ }
+}
+
+class PageTitle extends StatelessWidget {
+ const PageTitle({
+ super.key,
+ required this.title,
+ required this.box,
+ });
+ final String title;
+ final BoxConstraints box;
+
+ @override
+ Widget build(BuildContext context) {
+ return Text(
+ title,
+ style: Theme.of(context).textTheme.titleLarge?.copyWith(
+ fontSize: box.maxWidth * 0.085,
+ fontWeight: FontWeight.w700,
+ ),
+ );
+ }
+}
+
+class BubblesTopBackGround extends StatelessWidget {
+ const BubblesTopBackGround({
+ super.key,
+ required this.cts,
+ required this.svgName,
+ });
+ final BoxConstraints cts;
+ final String svgName;
+
+ @override
+ Widget build(BuildContext context) {
+ return Positioned(
+ top: -.035 * cts.maxHeight,
+ child: SvgPicture.asset(
+ svgName,
+ width: cts.maxWidth,
+ height: 0.4 * cts.maxHeight,
+ ),
+ );
+ }
+}
diff --git a/lib/forgot_password_flow/infrastructure/forgot_password_repository.dart b/lib/forgot_password_flow/infrastructure/forgot_password_repository.dart
new file mode 100644
index 0000000..e39c481
--- /dev/null
+++ b/lib/forgot_password_flow/infrastructure/forgot_password_repository.dart
@@ -0,0 +1,60 @@
+import 'dart:convert';
+import 'dart:io';
+import 'package:dartz/dartz.dart';
+import 'package:firebase_auth/firebase_auth.dart' hide User;
+import 'package:flutter/services.dart';
+import 'package:fpb/core/failures/auth_failure.dart';
+import 'package:fpb/forgot_password_flow/domain/i_forgot_password_facade.dart';
+import 'package:injectable/injectable.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'package:http/http.dart' as http;
+
+@LazySingleton(as: IForgotPasswordRepositoryFacade)
+class ForgotPasswordRepository implements IForgotPasswordRepositoryFacade {
+ final FirebaseAuth _firebaseAuth;
+ String _token;
+
+ ForgotPasswordRepository(this._firebaseAuth, this._token);
+
+ Future recoveryPassword(String email) async {
+ await _firebaseAuth.sendPasswordResetEmail(email: email);
+ }
+
+ @override
+ Future> changePassword(String newPassword) async {
+ SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
+
+ _token = sharedPreferences.getString("token")!;
+
+ final url = Uri.https('identitytoolkit.googleapis.com',
+ 'v1/accounts:update?key=AIzaSyAGxbjnzj7ruNcZEkeWcCEADt5d6Y_oakI');
+
+ try {
+ await http.post(
+ url,
+ body: json.encode(
+ {
+ 'idToken': _token,
+ 'password': newPassword,
+ 'returnSecureToken': true,
+ },
+ ),
+ );
+ return right(unit);
+ } on SocketException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.message));
+ } on PlatformException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ } on FirebaseAuthException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ } on FirebaseException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ }
+ }
+
+ @override
+ Future authenticate(String email, String password, String urlSegment) {
+ // TODO: implement authenticate
+ throw UnimplementedError();
+ }
+}
diff --git a/lib/forgot_password_flow/new_password_success.dart b/lib/forgot_password_flow/new_password_success.dart
new file mode 100644
index 0000000..94a7aee
--- /dev/null
+++ b/lib/forgot_password_flow/new_password_success.dart
@@ -0,0 +1,162 @@
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:fpb/assets/fpb_svg.dart';
+import 'package:fpb/core/presentation/extension/extensions.dart';
+import 'package:fpb/core/presentation/widget/fpb_button.dart';
+import 'package:fpb/core/shared/helpers/is_keyboard_visible.dart';
+import 'package:fpb/l10n/l10n.dart';
+import 'package:fpb/router/app_route.gr.dart';
+
+class NewPasswordSuccessScreen extends StatefulWidget {
+ const NewPasswordSuccessScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() =>
+ _NewPasswordSuccessScreenState();
+}
+
+class _NewPasswordSuccessScreenState extends State {
+ final FocusNode? node = FocusNode();
+ final TextEditingController? emailFieldController = TextEditingController();
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = context.l10n;
+ final theme = Theme.of(context);
+ // final style = theme.textTheme;
+ // final colors = theme.colorScheme;
+
+ return LayoutBuilder(
+ builder: (context, cts) {
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ body: Stack(
+ children: [
+ BubblesTopBackGround(
+ cts: cts,
+ svgName: SvgNames.authBackground,
+ ),
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SizedBox(
+ height: 0.025 * cts.maxHeight,
+ ),
+ Stack(
+ children: [
+ Container(
+ width: 99,
+ height: 85,
+ margin: EdgeInsets.all(30),
+ decoration: BoxDecoration(
+ color: Color(0xffEEF8FF),
+ borderRadius:
+ BorderRadius.all(Radius.circular(4.0)),
+ ),
+ ),
+ Positioned(
+ bottom: 50,
+ left: 55,
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(4.0), //or 15.0
+ child: SvgPicture.asset(
+ 'assets/FpbIcons/blue_circle_check_mark.svg',
+ width: 45.83,
+ height: 45.83,
+ ),
+ ),
+ ),
+ ],
+ ),
+ SizedBox(
+ height: 0.001 * cts.maxHeight,
+ ),
+ PageTitle(
+ title: l10n.newPasswordSuccessTitle,
+ box: cts,
+ ),
+ SizedBox(
+ height: 0.02 * cts.maxHeight,
+ ),
+ Text(
+ l10n.newPasswordSuccessBodyContent,
+ textAlign: TextAlign.center,
+ style: TextStyle(height: 1.5, fontSize: 12),
+ ),
+ SizedBox(
+ height: 0.025 * cts.maxHeight,
+ ),
+ SizedBox(
+ height: 0.03 * cts.maxHeight,
+ ),
+ FpbButton(
+ label: l10n.signInEmailLogInLabel,
+ onTap: () {
+ context.router.push((SaveMoneyRoute()));
+ },
+ ),
+ ],
+ ).card(
+ height:
+ (isKeyboardVisible(context) ? .80 : .8) * cts.maxHeight,
+ radiusTop: cts.maxWidth * 0.05,
+ color: theme.colorScheme.background,
+ padding: EdgeInsets.all(cts.maxHeight * 0.025),
+ ),
+ )
+ ],
+ ).card(
+ radiusTop: cts.maxWidth * 0.05,
+ color: theme.colorScheme.background,
+ ),
+ );
+ },
+ );
+ }
+}
+
+class PageTitle extends StatelessWidget {
+ const PageTitle({
+ super.key,
+ required this.title,
+ required this.box,
+ });
+ final String title;
+ final BoxConstraints box;
+
+ @override
+ Widget build(BuildContext context) {
+ return Text(
+ title,
+ style: Theme.of(context).textTheme.titleLarge?.copyWith(
+ fontSize: box.maxWidth * 0.085,
+ fontWeight: FontWeight.w700,
+ ),
+ );
+ }
+}
+
+class BubblesTopBackGround extends StatelessWidget {
+ const BubblesTopBackGround({
+ super.key,
+ required this.cts,
+ required this.svgName,
+ });
+ final BoxConstraints cts;
+ final String svgName;
+
+ @override
+ Widget build(BuildContext context) {
+ return Positioned(
+ top: -.035 * cts.maxHeight,
+ child: SvgPicture.asset(
+ svgName,
+ width: cts.maxWidth,
+ height: 0.4 * cts.maxHeight,
+ ),
+ );
+ }
+}
diff --git a/lib/home/view/home_container.dart b/lib/home/view/home_container.dart
index 2fa8f4b..8ad840c 100644
--- a/lib/home/view/home_container.dart
+++ b/lib/home/view/home_container.dart
@@ -15,7 +15,7 @@ class HomeContainer extends StatelessWidget {
builder: (context, state) {
return state.map(
home: (_) => DashBoard(), // -> LatestActivitiesPage(),
- savings: (_) => SavingsPage(),
+ savings: (_) => SavingsScreen(),
quickCash: (_) => Container(child: Center(child: Text('budget'))),
budget: (_) => BudgetScreen(),
search: (_) => UserSearchScreen(),
diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb
index 1ec51e7..2ea451b 100644
--- a/lib/l10n/arb/app_en.arb
+++ b/lib/l10n/arb/app_en.arb
@@ -295,6 +295,50 @@
"confirmEmailResendButton": "Resend confirmation email",
"@confirmEmailResendButton": {
"description": "This is the text label on the resend button on the phone number confirmation screen"
+ },
+ "createNewPasswordTitle": "Create new password",
+ "@createNewPasswordTitle": {
+ "description": "This is the main title on the create new password screen"
+ },
+ "createNewPasswordBodyContent": "Your new password must be different from the previous\nused password.",
+ "@createNewPasswordBodyContent": {
+ "description": "This is the body content of the create new password screen"
+ },
+ "createNewPasswordConfirmPasswordLabel": "Confirm Password",
+ "@createNewPasswordConfirmPasswordLabel": {
+ "description": "This is the confirm password label on the create new password screen"
+ },
+ "createNewPasswordResetButtonLabel": "Reset Password",
+ "@createNewPasswordResetButtonLabel": {
+ "description": "This is the text label of the reset button on the create new password screen"
+ },
+ "forgotPasswordTitle": "Forgot password",
+ "@forgotPasswordTitle": {
+ "description": "This is the main title text label on the forgot password screen"
+ },
+ "forgotPasswordBodyContent": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores !",
+ "@forgotPasswordBodyContent": {
+ "description": "This is the body content on the forgot password screen"
+ },
+ "forgotPasswordEmailTextFieldLabel": "Email address",
+ "@forgotPasswordEmailTextFieldLabel": {
+ "description": "This is the text label of the email text field on the forgot password screen"
+ },
+ "forgotPasswordEmailTextFieldHint": "Enter your email address...",
+ "@forgotPasswordEmailTextFieldHint": {
+ "description": "This is the hint of the email text field on the forgot password screen"
+ },
+ "forgotPasswordSendButtonLabel": "Send",
+ "@forgotPasswordSendButtonLabel": {
+ "description": "This is the text label of the send button on the forgot password screen"
+ },
+ "newPasswordSuccessTitle": "Yay !!",
+ "@newPasswordSuccessTitle": {
+ "description": "This is the main title on the new password success screen"
+ },
+ "newPasswordSuccessBodyContent": "Your password has been reset successfully\nnow login with your new password",
+ "@newPasswordSuccessBodyContent": {
+ "description": "This is the body content of the new password success screen"
}
}
\ No newline at end of file
diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb
index 8359a06..01acecd 100644
--- a/lib/l10n/arb/app_fr.arb
+++ b/lib/l10n/arb/app_fr.arb
@@ -295,6 +295,50 @@
"confirmEmailResendButton": "Renvoyer l'e-mail",
"@confirmEmailResendButton": {
"description": "Il s'agit du texte de l'étiquette du bouton de renvoi sur l'écran de confirmation du numéro de téléphone."
+ },
+ "createNewPasswordTitle": "Créer un nouveau mot de passe",
+ "@createNewPasswordTitle": {
+ "description": "Il s'agit du titre principal de l'écran de création d'un nouveau mot de passe."
+ },
+ "createNewPasswordBodyContent": "Votre nouveau mot de passe doit être différent du précédent\nmot de passe utilisé",
+ "@createNewPasswordBodyContent": {
+ "description": "Il s'agit du contenu de l'écran de création d'un nouveau mot de passe."
+ },
+ "createNewPasswordConfirmPasswordLabel": "Confirmez votre mot de passe",
+ "@createNewPasswordConfirmPasswordLabel": {
+ "description": "Il s'agit de l'étiquette de confirmation du mot de passe sur l'écran de création d'un nouveau mot de passe."
+ },
+ "createNewPasswordResetButtonLabel": "Réinitialiser le mot de passe",
+ "@createNewPasswordResetButtonLabel": {
+ "description": "Il s'agit du libellé du bouton de réinitialisation dans l'écran de création d'un nouveau mot de passe."
+ },
+ "forgotPasswordTitle": "Mot de passe oublié",
+ "@forgotPasswordTitle": {
+ "description": "Il s'agit du titre principal de l'écran mot de passe oublié."
+ },
+ "forgotPasswordBodyContent": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores !",
+ "@forgotPasswordBodyContent": {
+ "description": "Voici le contenu du corps de l'écran mot de passe oublié."
+ },
+ "forgotPasswordEmailTextFieldLabel": "Adresse email",
+ "@forgotPasswordEmailTextFieldLabel": {
+ "description": "Il s'agit de l'étiquette du champ de texte de l'email sur l'écran du mot de passe oublié."
+ },
+ "forgotPasswordEmailTextFieldHint": "Entrez votre adresse e-mail...",
+ "@forgotPasswordEmailTextFieldHint": {
+ "description": "Il s'agit de l'indice du champ de texte de l'email sur l'écran du mot de passe oublié."
+ },
+ "forgotPasswordSendButtonLabel": "Envoyer",
+ "@forgotPasswordSendButtonLabel": {
+ "description": "Il s'agit de l'étiquette de texte du bouton d'envoi de l'écran \"mot de passe oublié\"."
+ },
+ "newPasswordSuccessTitle": "Hourra !!",
+ "@newPasswordSuccessTitle": {
+ "description": "Il s'agit du titre principal de l'écran de réussite du nouveau mot de passe."
+ },
+ "newPasswordSuccessBodyContent": "Votre mot de passe a été réinitialisé avec succès\nConnectez-vous maintenant avec votre nouveau mot de passe",
+ "@newPasswordSuccessBodyContent": {
+ "description": "Voici le contenu de l'écran de réussite du nouveau mot de passe"
}
}
\ No newline at end of file
diff --git a/lib/router/app_route.dart b/lib/router/app_route.dart
index 7f7ba41..48a0800 100644
--- a/lib/router/app_route.dart
+++ b/lib/router/app_route.dart
@@ -1,5 +1,8 @@
import 'package:auto_route/annotations.dart';
import 'package:fpb/email_confirmation/email_confirmation.dart';
+import 'package:fpb/forgot_password_flow/create_new_password.dart';
+import 'package:fpb/forgot_password_flow/forgot_password.dart';
+import 'package:fpb/forgot_password_flow/new_password_success.dart';
import 'package:fpb/home/view/home_screen.dart';
import 'package:fpb/latest_activities/view/latest_activities_screen.dart';
import 'package:fpb/onboarding/view/onboarding_screens.dart';
@@ -8,6 +11,7 @@ import 'package:fpb/phone_number_confirmation/view/phone_number_confirmation.dar
import 'package:fpb/profile/view/profile_page.dart';
import 'package:fpb/qr_code_screen/view/qr_code_screen.dart';
import 'package:fpb/savings/save_money_with_bucket/save_money_with_bucket.dart';
+import 'package:fpb/savings/view/savings_page.dart';
import 'package:fpb/sign_in/view/sign_in_page.dart';
import 'package:fpb/sign_up/view/signup_page.dart';
@@ -20,6 +24,10 @@ import 'package:fpb/sign_up/view/signup_page.dart';
AutoRoute(page: EmailConfirmationScreen),
AutoRoute(page: SignUpScreen),
AutoRoute(page: SaveMoneyScreen),
+ AutoRoute(page: SavingsScreen),
+ AutoRoute(page: NewPasswordSuccessScreen),
+ AutoRoute(page: ForgotPasswordScreen),
+ AutoRoute(page: CreateNewPasswordScreen),
AutoRoute(
name: 'HomeRouter',
page: HomeScreen,
diff --git a/lib/router/app_route.gr.dart b/lib/router/app_route.gr.dart
index 9d58a39..0730e12 100644
--- a/lib/router/app_route.gr.dart
+++ b/lib/router/app_route.gr.dart
@@ -11,152 +11,201 @@
// ignore_for_file: type=lint
// ignore_for_file: no_leading_underscores_for_library_prefixes
-import 'package:auto_route/auto_route.dart' as _i12;
-import 'package:flutter/material.dart' as _i13;
+import 'package:auto_route/auto_route.dart' as _i16;
+import 'package:flutter/material.dart' as _i17;
-import '../core/domain/user.dart' as _i14;
+import '../core/domain/user.dart' as _i18;
import '../email_confirmation/email_confirmation.dart' as _i4;
-import '../home/view/home_screen.dart' as _i7;
-import '../latest_activities/view/latest_activities_screen.dart' as _i8;
-import '../onboarding/view/onboarding_screens.dart' as _i10;
+import '../forgot_password_flow/create_new_password.dart' as _i10;
+import '../forgot_password_flow/forgot_password.dart' as _i9;
+import '../forgot_password_flow/new_password_success.dart' as _i8;
+import '../home/view/home_screen.dart' as _i11;
+import '../latest_activities/view/latest_activities_screen.dart' as _i12;
+import '../onboarding/view/onboarding_screens.dart' as _i14;
import '../onboarding/view/splash_screen.dart' as _i1;
import '../phone_number_confirmation/view/phone_number_confirmation.dart'
as _i3;
-import '../profile/view/profile_page.dart' as _i11;
-import '../qr_code_screen/view/qr_code_screen.dart' as _i9;
+import '../profile/view/profile_page.dart' as _i15;
+import '../qr_code_screen/view/qr_code_screen.dart' as _i13;
import '../savings/save_money_with_bucket/save_money_with_bucket.dart' as _i6;
+import '../savings/view/savings_page.dart' as _i7;
import '../sign_in/view/sign_in_page.dart' as _i2;
import '../sign_up/view/signup_page.dart' as _i5;
-class AppRoute extends _i12.RootStackRouter {
- AppRoute([_i13.GlobalKey<_i13.NavigatorState>? navigatorKey])
+class AppRoute extends _i16.RootStackRouter {
+ AppRoute([_i17.GlobalKey<_i17.NavigatorState>? navigatorKey])
: super(navigatorKey);
@override
- final Map pagesMap = {
+ final Map pagesMap = {
SplashRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
child: const _i1.SplashScreen(),
);
},
SignInRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
child: const _i2.SignInScreen(),
);
},
PhoneNumberConfirmationRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
child: const _i3.PhoneNumberConfirmationScreen(),
);
},
EmailConfirmationRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ final args = routeData.argsAs();
+ return _i16.MaterialPageX(
routeData: routeData,
- child: const _i4.EmailConfirmationScreen(),
+ child: _i4.EmailConfirmationScreen(
+ key: args.key,
+ emailControllerValue: args.emailControllerValue,
+ submitValue: args.submitValue,
+ ),
);
},
SignUpRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
child: const _i5.SignUpScreen(),
);
},
SaveMoneyRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
child: const _i6.SaveMoneyScreen(),
);
},
+ SavingsRoute.name: (routeData) {
+ return _i16.MaterialPageX(
+ routeData: routeData,
+ child: const _i7.SavingsScreen(),
+ );
+ },
+ NewPasswordSuccessRoute.name: (routeData) {
+ return _i16.MaterialPageX(
+ routeData: routeData,
+ child: const _i8.NewPasswordSuccessScreen(),
+ );
+ },
+ ForgotPasswordRoute.name: (routeData) {
+ return _i16.MaterialPageX(
+ routeData: routeData,
+ child: const _i9.ForgotPasswordScreen(),
+ );
+ },
+ CreateNewPasswordRoute.name: (routeData) {
+ return _i16.MaterialPageX(
+ routeData: routeData,
+ child: const _i10.CreateNewPasswordScreen(),
+ );
+ },
HomeRouter.name: (routeData) {
final args = routeData.argsAs();
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
- child: _i7.HomeScreen(
+ child: _i11.HomeScreen(
key: args.key,
user: args.user,
),
);
},
LatestActivitiesPage.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
- child: const _i8.LatestActivitiesPage(),
+ child: const _i12.LatestActivitiesPage(),
);
},
QrCodeRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
- child: const _i9.QrCodeScreen(),
+ child: const _i13.QrCodeScreen(),
);
},
OnboardingRoute.name: (routeData) {
final args = routeData.argsAs(
orElse: () => const OnboardingRouteArgs());
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
- child: _i10.OnboardingScreen(
+ child: _i14.OnboardingScreen(
onGetStartedPressed: args.onGetStartedPressed,
key: args.key,
),
);
},
ProfileRoute.name: (routeData) {
- return _i12.MaterialPageX(
+ return _i16.MaterialPageX(
routeData: routeData,
- child: const _i11.ProfileScreen(),
+ child: const _i15.ProfileScreen(),
);
},
};
@override
- List<_i12.RouteConfig> get routes => [
- _i12.RouteConfig(
+ List<_i16.RouteConfig> get routes => [
+ _i16.RouteConfig(
SplashRoute.name,
path: '/',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
SignInRoute.name,
path: '/sign-in-screen',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
PhoneNumberConfirmationRoute.name,
path: '/phone-number-confirmation-screen',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
EmailConfirmationRoute.name,
path: '/email-confirmation-screen',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
SignUpRoute.name,
path: '/sign-up-screen',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
SaveMoneyRoute.name,
path: '/save-money-screen',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
+ SavingsRoute.name,
+ path: '/savings-screen',
+ ),
+ _i16.RouteConfig(
+ NewPasswordSuccessRoute.name,
+ path: '/new-password-success-screen',
+ ),
+ _i16.RouteConfig(
+ ForgotPasswordRoute.name,
+ path: '/forgot-password-screen',
+ ),
+ _i16.RouteConfig(
+ CreateNewPasswordRoute.name,
+ path: '/create-new-password-screen',
+ ),
+ _i16.RouteConfig(
HomeRouter.name,
path: '/home-screen',
children: [
- _i12.RouteConfig(
+ _i16.RouteConfig(
ProfileRoute.name,
path: 'profile',
parent: HomeRouter.name,
)
],
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
LatestActivitiesPage.name,
path: 'latestActivities',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
QrCodeRoute.name,
path: '/qr-code-screen',
),
- _i12.RouteConfig(
+ _i16.RouteConfig(
OnboardingRoute.name,
path: '/onboarding-screen',
),
@@ -165,7 +214,7 @@ class AppRoute extends _i12.RootStackRouter {
/// generated route for
/// [_i1.SplashScreen]
-class SplashRoute extends _i12.PageRouteInfo {
+class SplashRoute extends _i16.PageRouteInfo {
const SplashRoute()
: super(
SplashRoute.name,
@@ -177,7 +226,7 @@ class SplashRoute extends _i12.PageRouteInfo {
/// generated route for
/// [_i2.SignInScreen]
-class SignInRoute extends _i12.PageRouteInfo {
+class SignInRoute extends _i16.PageRouteInfo {
const SignInRoute()
: super(
SignInRoute.name,
@@ -189,7 +238,7 @@ class SignInRoute extends _i12.PageRouteInfo {
/// generated route for
/// [_i3.PhoneNumberConfirmationScreen]
-class PhoneNumberConfirmationRoute extends _i12.PageRouteInfo {
+class PhoneNumberConfirmationRoute extends _i16.PageRouteInfo {
const PhoneNumberConfirmationRoute()
: super(
PhoneNumberConfirmationRoute.name,
@@ -201,19 +250,47 @@ class PhoneNumberConfirmationRoute extends _i12.PageRouteInfo {
/// generated route for
/// [_i4.EmailConfirmationScreen]
-class EmailConfirmationRoute extends _i12.PageRouteInfo {
- const EmailConfirmationRoute()
- : super(
+class EmailConfirmationRoute
+ extends _i16.PageRouteInfo {
+ EmailConfirmationRoute({
+ _i17.Key? key,
+ required String emailControllerValue,
+ required bool submitValue,
+ }) : super(
EmailConfirmationRoute.name,
path: '/email-confirmation-screen',
+ args: EmailConfirmationRouteArgs(
+ key: key,
+ emailControllerValue: emailControllerValue,
+ submitValue: submitValue,
+ ),
);
static const String name = 'EmailConfirmationRoute';
}
+class EmailConfirmationRouteArgs {
+ const EmailConfirmationRouteArgs({
+ this.key,
+ required this.emailControllerValue,
+ required this.submitValue,
+ });
+
+ final _i17.Key? key;
+
+ final String emailControllerValue;
+
+ final bool submitValue;
+
+ @override
+ String toString() {
+ return 'EmailConfirmationRouteArgs{key: $key, emailControllerValue: $emailControllerValue, submitValue: $submitValue}';
+ }
+}
+
/// generated route for
/// [_i5.SignUpScreen]
-class SignUpRoute extends _i12.PageRouteInfo {
+class SignUpRoute extends _i16.PageRouteInfo {
const SignUpRoute()
: super(
SignUpRoute.name,
@@ -225,7 +302,7 @@ class SignUpRoute extends _i12.PageRouteInfo {
/// generated route for
/// [_i6.SaveMoneyScreen]
-class SaveMoneyRoute extends _i12.PageRouteInfo {
+class SaveMoneyRoute extends _i16.PageRouteInfo {
const SaveMoneyRoute()
: super(
SaveMoneyRoute.name,
@@ -236,12 +313,60 @@ class SaveMoneyRoute extends _i12.PageRouteInfo {
}
/// generated route for
-/// [_i7.HomeScreen]
-class HomeRouter extends _i12.PageRouteInfo {
+/// [_i7.SavingsScreen]
+class SavingsRoute extends _i16.PageRouteInfo {
+ const SavingsRoute()
+ : super(
+ SavingsRoute.name,
+ path: '/savings-screen',
+ );
+
+ static const String name = 'SavingsRoute';
+}
+
+/// generated route for
+/// [_i8.NewPasswordSuccessScreen]
+class NewPasswordSuccessRoute extends _i16.PageRouteInfo {
+ const NewPasswordSuccessRoute()
+ : super(
+ NewPasswordSuccessRoute.name,
+ path: '/new-password-success-screen',
+ );
+
+ static const String name = 'NewPasswordSuccessRoute';
+}
+
+/// generated route for
+/// [_i9.ForgotPasswordScreen]
+class ForgotPasswordRoute extends _i16.PageRouteInfo {
+ const ForgotPasswordRoute()
+ : super(
+ ForgotPasswordRoute.name,
+ path: '/forgot-password-screen',
+ );
+
+ static const String name = 'ForgotPasswordRoute';
+}
+
+/// generated route for
+/// [_i10.CreateNewPasswordScreen]
+class CreateNewPasswordRoute extends _i16.PageRouteInfo {
+ const CreateNewPasswordRoute()
+ : super(
+ CreateNewPasswordRoute.name,
+ path: '/create-new-password-screen',
+ );
+
+ static const String name = 'CreateNewPasswordRoute';
+}
+
+/// generated route for
+/// [_i11.HomeScreen]
+class HomeRouter extends _i16.PageRouteInfo {
HomeRouter({
- _i13.Key? key,
- required _i14.User user,
- List<_i12.PageRouteInfo>? children,
+ _i17.Key? key,
+ required _i18.User user,
+ List<_i16.PageRouteInfo>? children,
}) : super(
HomeRouter.name,
path: '/home-screen',
@@ -261,9 +386,9 @@ class HomeRouterArgs {
required this.user,
});
- final _i13.Key? key;
+ final _i17.Key? key;
- final _i14.User user;
+ final _i18.User user;
@override
String toString() {
@@ -272,8 +397,8 @@ class HomeRouterArgs {
}
/// generated route for
-/// [_i8.LatestActivitiesPage]
-class LatestActivitiesPage extends _i12.PageRouteInfo {
+/// [_i12.LatestActivitiesPage]
+class LatestActivitiesPage extends _i16.PageRouteInfo {
const LatestActivitiesPage()
: super(
LatestActivitiesPage.name,
@@ -284,8 +409,8 @@ class LatestActivitiesPage extends _i12.PageRouteInfo {
}
/// generated route for
-/// [_i9.QrCodeScreen]
-class QrCodeRoute extends _i12.PageRouteInfo {
+/// [_i13.QrCodeScreen]
+class QrCodeRoute extends _i16.PageRouteInfo {
const QrCodeRoute()
: super(
QrCodeRoute.name,
@@ -296,11 +421,11 @@ class QrCodeRoute extends _i12.PageRouteInfo {
}
/// generated route for
-/// [_i10.OnboardingScreen]
-class OnboardingRoute extends _i12.PageRouteInfo {
+/// [_i14.OnboardingScreen]
+class OnboardingRoute extends _i16.PageRouteInfo {
OnboardingRoute({
void Function()? onGetStartedPressed,
- _i13.Key? key,
+ _i17.Key? key,
}) : super(
OnboardingRoute.name,
path: '/onboarding-screen',
@@ -321,7 +446,7 @@ class OnboardingRouteArgs {
final void Function()? onGetStartedPressed;
- final _i13.Key? key;
+ final _i17.Key? key;
@override
String toString() {
@@ -330,8 +455,8 @@ class OnboardingRouteArgs {
}
/// generated route for
-/// [_i11.ProfileScreen]
-class ProfileRoute extends _i12.PageRouteInfo {
+/// [_i15.ProfileScreen]
+class ProfileRoute extends _i16.PageRouteInfo {
const ProfileRoute()
: super(
ProfileRoute.name,
diff --git a/lib/savings/view/savings_page.dart b/lib/savings/view/savings_page.dart
index 3e75a4e..84bda4e 100644
--- a/lib/savings/view/savings_page.dart
+++ b/lib/savings/view/savings_page.dart
@@ -5,15 +5,15 @@ import 'package:flutter/material.dart';
import 'package:fpb/l10n/l10n.dart';
import 'package:fpb/router/app_route.gr.dart';
-class SavingsPage extends StatefulWidget {
- const SavingsPage({super.key});
+class SavingsScreen extends StatefulWidget {
+ const SavingsScreen({super.key});
static const String routeName = '/savings';
@override
- State createState() => _SavingsPageState();
+ State createState() => _SavingsScreenState();
}
-class _SavingsPageState extends State {
+class _SavingsScreenState extends State {
int pageIndex = 1;
void onChanged(int index) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 73d449b..200e29a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -51,6 +51,7 @@ dependencies:
qr_flutter: ^4.0.0
path_provider: ^2.0.13
share_plus: ^6.3.1
+ email_auth: ^1.0.0
dev_dependencies:
widgetbook_generator: