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: