From 098217f47a7b40fa22ad3dffe7baf2972a646739 Mon Sep 17 00:00:00 2001 From: aitorarana Date: Fri, 12 Dec 2025 11:28:02 +0100 Subject: [PATCH 1/6] added recoverPassword endpoints, providers and states --- .../mobile_app/lib/navigation/app_router.dart | 2 +- modules/auth/lib/auth.dart | 2 +- .../datasource/auth_remote_datasource.dart | 4 + .../auth_remote_datasource_impl.dart | 42 +++ .../repositories/auth_repository_impl.dart | 10 + .../domain/repositories/auth_repository.dart | 4 + .../use_cases/recover_password_use_case.dart | 7 + .../recover_password_use_case_impl.dart | 23 ++ .../new_password/new_password_builder.dart | 18 + .../new_password/new_password_screen.dart | 201 +++++++++++ .../presentation/new_password_screen.dart | 193 ----------- .../providers/recover_password_provider.dart | 10 + .../request_recovery_builder.dart | 18 + .../request_recovery_screen.dart | 126 +++++++ .../presentation/restore_password_screen.dart | 114 ------- .../presentation/sent/sent_builder.dart | 18 + .../presentation/sent/sent_screen.dart | 109 ++++++ .../presentation/sent_screen.dart | 99 ------ .../state/recover_password_view_model.dart | 275 +++++++++++++++ .../state/recover_password_view_state.dart | 29 ++ .../recover_password_view_state.freezed.dart | 319 ++++++++++++++++++ .../recover_password_builder.dart | 4 +- .../lib/src/inputs/textfields.dart | 76 ++--- .../design_system/test/goldens/textfield.png | Bin 8784 -> 8765 bytes 24 files changed, 1254 insertions(+), 449 deletions(-) create mode 100644 modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case.dart create mode 100644 modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case_impl.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_builder.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart delete mode 100644 modules/auth/lib/src/features/recover_password/presentation/new_password_screen.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/providers/recover_password_provider.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_builder.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart delete mode 100644 modules/auth/lib/src/features/recover_password/presentation/restore_password_screen.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/sent/sent_builder.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart delete mode 100644 modules/auth/lib/src/features/recover_password/presentation/sent_screen.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart create mode 100644 modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart diff --git a/apps/mobile_app/lib/navigation/app_router.dart b/apps/mobile_app/lib/navigation/app_router.dart index e7ee4782..b8850e17 100644 --- a/apps/mobile_app/lib/navigation/app_router.dart +++ b/apps/mobile_app/lib/navigation/app_router.dart @@ -46,7 +46,7 @@ void configureAppRouter() { GoRoute( path: AppRoutes.recoverPassword, name: 'recover_password', - pageBuilder: RecoverPasswordBuilder().buildPage, + pageBuilder: RequestRecoveryBuilder().buildPage, ), GoRoute( path: AppRoutes.deviceSignup, diff --git a/modules/auth/lib/auth.dart b/modules/auth/lib/auth.dart index 2991c63d..86d23c73 100644 --- a/modules/auth/lib/auth.dart +++ b/modules/auth/lib/auth.dart @@ -3,6 +3,6 @@ export 'src/features/onboarding/onboarding_builder.dart'; export 'src/features/link_phone/presentation/request_phone/request_link_phone_builder.dart'; export 'src/features/link_phone/presentation/verify_code/verify_link_phone_code_builder.dart'; export 'src/features/login/login_builder.dart'; -export 'src/features/recover_password/recover_password_builder.dart'; +export 'src/features/recover_password/presentation/request_recovery/request_recovery_builder.dart'; export 'src/features/device_sign_up/device_signup_builder.dart'; export 'src/features/sign_up/signup_builder.dart'; diff --git a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart index 573fcef8..c3253f3d 100644 --- a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart +++ b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource.dart @@ -2,4 +2,8 @@ abstract class AuthRemoteDatasource { Future requestPhoneCode({required String phone}); Future verifyPhoneCode({required String phone, required String code}); + + Future requestPasswordReset({String? phone, String? email}); + + Future recoverPassword({required newPassword, required token}); } diff --git a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart index 1053f587..6cffc665 100644 --- a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart +++ b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart @@ -53,4 +53,46 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource { return Exception(message); } + + @override + Future requestPasswordReset({ + String? phone, + String? email + }) async { + try { + if (phone == null && email == null) { + throw FormatException("No phone or email address given"); + } + + late final Map body; + if (email != null) { + body = {'email': email}; + return 'ec14b7e7-58dd-4a59-9f41-0da86eaabf14'; + } else { + body = {'phone': phone!}; + return 'ec14b7e7-58dd-4a59-9f41-0da86eaabf14'; + throw Exception("reset by phone is not currently implemented"); + } + final response = await _repository.put>( + '/auth/reset-password', + body: body, + ); + final token = response.data!['token']; + return token; + } on DioException catch (error) { + throw _mapDioError(error, defaultMessage: 'Error to request password reset'); + } + } + + @override + Future recoverPassword({required newPassword, required token}) async { + try { + await _repository.put( + '/auth/recovery-password', + body: {'newPassword': newPassword, 'token': token}, + ); + } on DioException catch (error) { + throw _mapDioError(error, defaultMessage: 'Error to request password recovery'); + } + } } diff --git a/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart b/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart index 127c6070..88ae3a61 100644 --- a/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart +++ b/modules/auth/lib/src/core/data/repositories/auth_repository_impl.dart @@ -15,4 +15,14 @@ class AuthRepositoryImpl implements AuthRepository { Future verifyPhoneCode({required String phone, required String code}) { return _remote.verifyPhoneCode(phone: phone, code: code); } + + @override + Future requestPasswordReset({String? phone, String? email}) { + return _remote.requestPasswordReset(phone: phone, email: email); + } + + @override + Future recoverPassword({required String newPassword, required String token}) { + return _remote.recoverPassword(newPassword: newPassword, token: token); + } } diff --git a/modules/auth/lib/src/core/domain/repositories/auth_repository.dart b/modules/auth/lib/src/core/domain/repositories/auth_repository.dart index 4584b9db..f6338e9a 100644 --- a/modules/auth/lib/src/core/domain/repositories/auth_repository.dart +++ b/modules/auth/lib/src/core/domain/repositories/auth_repository.dart @@ -2,4 +2,8 @@ abstract class AuthRepository { Future requestPhoneCode({required String phone}); Future verifyPhoneCode({required String phone, required String code}); + + Future requestPasswordReset({String phone, String email}); + + Future recoverPassword({required String newPassword, required String token}); } diff --git a/modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case.dart b/modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case.dart new file mode 100644 index 00000000..76228be2 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case.dart @@ -0,0 +1,7 @@ +abstract class RecoverPasswordUseCase { + Future requestEmail({required String email}); + + Future requestSms({required String phone}); + + Future recoverPassword({required String newPassword, required String token}); +} \ No newline at end of file diff --git a/modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case_impl.dart b/modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case_impl.dart new file mode 100644 index 00000000..6699e8f8 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/domain/use_cases/recover_password_use_case_impl.dart @@ -0,0 +1,23 @@ +import 'package:auth/src/core/domain/repositories/auth_repository.dart'; +import 'package:auth/src/features/recover_password/domain/use_cases/recover_password_use_case.dart'; + +class RecoverPasswordUseCaseImpl implements RecoverPasswordUseCase { + RecoverPasswordUseCaseImpl(this._repository); + + final AuthRepository _repository; + + @override + Future requestEmail({required String email}) async { + return await _repository.requestPasswordReset(email: email); + } + + @override + Future requestSms({required String phone}) async { + return await _repository.requestPasswordReset(phone: phone); + } + + @override + Future recoverPassword({required String newPassword, required String token}) async { + await _repository.recoverPassword(newPassword: newPassword, token: token); + } +} diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_builder.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_builder.dart new file mode 100644 index 00000000..4fe9f6b2 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_builder.dart @@ -0,0 +1,18 @@ +import 'package:auth/src/features/recover_password/presentation/new_password/new_password_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:get_it/get_it.dart'; +import 'package:navigation/navigation.dart'; + +class NewPasswordBuilder { + const NewPasswordBuilder(); + + Page buildPage(BuildContext context, GoRouterState state) { + final NavigationContract navigationContract = GetIt.I(); + + return MaterialPage( + key: state.pageKey, + child: NewPasswordScreen(navigationContract: navigationContract), + ); + } +} \ No newline at end of file diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart new file mode 100644 index 00000000..74e35d38 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart @@ -0,0 +1,201 @@ +import 'package:auth/src/features/recover_password/presentation/state/recover_password_view_model.dart'; +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:get_it/get_it.dart'; +import 'package:navigation/navigation.dart'; +import 'package:sf_localizations/sf_localizations.dart'; + +class NewPasswordScreen extends ConsumerStatefulWidget { + final NavigationContract navigationContract; + + const NewPasswordScreen({super.key, required this.navigationContract}); + + @override + ConsumerState createState() => NewPasswordScreenState(); +} + +class NewPasswordScreenState extends ConsumerState { + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + final NavigationContract navigationContract = GetIt.I(); + final theme = ref.watch(themePortProvider); + + final viewModel = ref.read(recoverPasswordViewModelProvider.notifier); + final viewState = ref.watch(recoverPasswordViewModelProvider); + + return Scaffold( + backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), + body: Container( + margin: const EdgeInsets.symmetric(horizontal: 24), + child: Center( + child: SingleChildScrollView(child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Recuperar contraseña', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 30/*SizeUtils.getByScreen(small: 30, xl: 26)*/, + letterSpacing: 0 + ), + ), + SizedBox(height: 42/*SizeUtils.getBySize(small: 42, big: 32)*/), + CustomTextField( + showPassword: viewState.passwordVisible, + label: 'Nueva contraseña', + labelSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, + hint: '********', + controller: viewModel.passwordController, + onVisibilityChanged: viewModel.togglePasswordVisible, + ), + SizedBox(height: 16), + CustomTextField( + showPassword: viewState.passwordVisible, + label: 'Repetir contraseña', + labelSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, + hint: '********', + controller: viewModel.repeatedPasswordController, + onVisibilityChanged: viewModel.togglePasswordVisible, + color: viewState.equalPasswords ? const Color(0xFF4B4B4B) : const Color.fromRGBO(239, 17, 17, 1), + ), + if (!viewState.equalPasswords) ...[ + SizedBox(height: 4), + const Row( + spacing: 8, + children: [ + Icon( + Icons.info_outline_rounded, + color: Color.fromRGBO(239, 17, 17, 1), + size: 16, + ), + Text( + 'Las contraseñas no coinciden. Inténtalo de nuevo', + textAlign: TextAlign.left, + style: TextStyle( + color: Color.fromRGBO(239, 17, 17, 1), + fontSize: 10, + ), + ), + Spacer(), + ] + ), + ], + SizedBox(height: 12), + Row( + spacing: 8, + children: [ + Icon( + Icons.check, + color: theme.getColorFor(viewState.securityChecks['min']! + ? ThemeCode.buttonPrimary + : ThemeCode.buttonSecondary), + ), + const Text( + 'Al menos 8 caracteres', + style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + ), + ], + ), + SizedBox(height: 2/*SizeUtils.getBySize(small: 2, big: 4)*/), + Row( + spacing: 8, + children: [ + Icon( + Icons.check, + color: theme.getColorFor(viewState.securityChecks['capital']! + ? ThemeCode.buttonPrimary + : ThemeCode.buttonSecondary), + ), + const Text( + 'Una mayúscula', + style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + ), + ], + ), + SizedBox(height: 2/*SizeUtils.getBySize(small: 2, big: 4)*/), + Row( + spacing: 8, + children: [ + Icon( + Icons.check, + color: theme.getColorFor(viewState.securityChecks['number']! + ? ThemeCode.buttonPrimary + : ThemeCode.buttonSecondary), + ), + const Text( + 'Un número', + style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + ), + ], + ), + SizedBox(height: 2/*SizeUtils.getBySize(small: 2, big: 4)*/), + Row( + spacing: 8, + children: [ + Icon( + Icons.check, + color: theme.getColorFor(viewState.securityChecks['special']! + ? ThemeCode.buttonPrimary + : ThemeCode.buttonSecondary), + ), + const Text( + 'Un carácter especial', + style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + ), + ], + ), + SizedBox(height: 32/*SizeUtils.getByScreen(small: 32, xl: 24)*/), + Align( + alignment: Alignment.bottomLeft, + child: const Text( + 'Teléfono móvil', + style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, letterSpacing: 0), + ) + ), + SizedBox(height: 8), + Row( + spacing: 8, + children: [ + CountryPrefixPicker( + headerText: context.translate(I18n.selectYourCountry), + width: 80, + onChanged: (country) { + viewModel.updateDialCode( + country.dialCode ?? viewState.dialCode, + ); + }, + ), + Expanded(child: CustomTextField( + hint: 'Teléfono', + numeric: true, + controller: viewModel.newPhoneNumberController, + )) + ] + ), + SizedBox(height: 56), + PrimaryButton( + onPressed: () async { + await viewModel.recoverPassword(); + final updatedState = ref.read(recoverPasswordViewModelProvider); + if (updatedState.passwordChanged) { + navigationContract.goTo(AppRoutes.dashboardHome); + } + }, + text: 'Aceptar', + color: theme.getColorFor(ThemeCode.buttonPrimary) + ), + ], + ), + ), + ), + )); + } +} diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password_screen.dart deleted file mode 100644 index 866fe532..00000000 --- a/modules/auth/lib/src/features/recover_password/presentation/new_password_screen.dart +++ /dev/null @@ -1,193 +0,0 @@ -import 'package:design_system/design_system.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:get_it/get_it.dart'; -import 'package:navigation/navigation.dart'; - -class NewPasswordScreen extends ConsumerStatefulWidget { - const NewPasswordScreen({super.key}); - - @override - ConsumerState createState() => NewPasswordScreenState(); -} - -class NewPasswordScreenState extends ConsumerState { - bool passwordVisible = false; - bool equalPasswords = false; - String password = ''; - - Map securityChecks = { - 'min': false, - 'capital': false, - 'number': false, - 'special': false, - }; - - @override - void initState() { - super.initState(); - passwordVisible = false; - equalPasswords = false; - password = ''; - securityChecks = { - 'min': false, - 'capital': false, - 'number': false, - 'special': false, - }; - } - - @override - Widget build(BuildContext context) { - final NavigationContract navigationContract = GetIt.I(); - final theme = ref.watch(themePortProvider); - - return Scaffold( - backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), - body: Container( - margin: const EdgeInsets.all(24), - child: Center( - child: Column( - spacing: 48, - children: [ - const Spacer(), - Column( - spacing: 32, - children: [ - const Text( - "Recuperar contraseña", - textAlign: TextAlign.center, - style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30, letterSpacing: 0), - ), - Column( - spacing: 16, - children: [ - CustomTextField( - showPassword: passwordVisible, - label: "Nueva contraseña", - hint: "********", - onChanged: (value) => { - setState(() { - password = value; - securityChecks = checkSecurity(value); - }), - }, - ), - CustomTextField( - showPassword: passwordVisible, - label: "Repetir contraseña", - hint: "********", - onChanged: (value) => { - setState(() { - equalPasswords = password == value; - }), - }, - ), - Column( - spacing: 4, - children: [ - Row( - spacing: 8, - children: [ - Icon( - Icons.check, - color: theme.getColorFor(securityChecks["min"]! - ? ThemeCode.buttonPrimary - : ThemeCode.buttonSecondary), - ), - const Text("Al menos 8 caracteres", style: TextStyle(fontSize: 14)), - ], - ), - Row( - spacing: 8, - children: [ - Icon( - Icons.check, - color: theme.getColorFor(securityChecks["capital"]! - ? ThemeCode.buttonPrimary - : ThemeCode.buttonSecondary), - ), - const Text("Una mayúscula", style: TextStyle(fontSize: 14)), - ], - ), - Row( - spacing: 8, - children: [ - Icon( - Icons.check, - color: theme.getColorFor(securityChecks["number"]! - ? ThemeCode.buttonPrimary - : ThemeCode.buttonSecondary), - ), - const Text("Un número", style: TextStyle(fontSize: 14)), - ], - ), - Row( - spacing: 8, - children: [ - Icon( - Icons.check, - color: theme.getColorFor(securityChecks["special"]! - ? ThemeCode.buttonPrimary - : ThemeCode.buttonSecondary), - ), - const Text("Un carácter especial", style: TextStyle(fontSize: 14)), - ], - ), - ], - ) - ], - ), - Column( - spacing: 8, - children: [ - Align( - alignment: Alignment.bottomLeft, - child: const Text( - "Teléfono móvil", - style: TextStyle(fontSize: 14, letterSpacing: 0), - ) - ), - Row( - spacing: 8, - children: [ - CustomDropdown( - value: 0, - items: [Icon(Icons.outlined_flag), Icon(Icons.outlined_flag), Icon(Icons.outlined_flag)], - onChanged: (value)=> {}, - width: 80, - ), - Expanded(child: CustomTextField( - hint: "Teléfono", - numeric: true - )) - ] - ), - ], - ) - - ], - ), - PrimaryButton( - onPressed: ()=>{navigationContract.goTo(AppRoutes.dashboardHome)}, - text: "Aceptar", - color: theme.getColorFor(ThemeCode.buttonPrimary) - ), - const Spacer(), - ], - ), - ), - ), - ); - } - - //TODO: Extraer de la vista - Map checkSecurity(String value) { - return { - 'min': value.length >= 8, - 'capital': RegExp(r'[A-Z]').hasMatch(value), - 'number': RegExp(r'[0-9]').hasMatch(value), - 'special': RegExp(r'[^A-Za-z0-9]').hasMatch(value), - }; - } -} diff --git a/modules/auth/lib/src/features/recover_password/presentation/providers/recover_password_provider.dart b/modules/auth/lib/src/features/recover_password/presentation/providers/recover_password_provider.dart new file mode 100644 index 00000000..d23165b1 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/providers/recover_password_provider.dart @@ -0,0 +1,10 @@ +import 'package:auth/src/core/providers/auth_repository_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../domain/use_cases/recover_password_use_case.dart'; +import '../../domain/use_cases/recover_password_use_case_impl.dart'; + +final recoverPasswordUseCaseProvider = Provider.autoDispose((ref) { + final authRepository = ref.read(authRepositoryProvider); + return RecoverPasswordUseCaseImpl(authRepository); +}); diff --git a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_builder.dart b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_builder.dart new file mode 100644 index 00000000..11e2fa57 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_builder.dart @@ -0,0 +1,18 @@ +import 'package:auth/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:get_it/get_it.dart'; +import 'package:navigation/navigation.dart'; + +class RequestRecoveryBuilder { + const RequestRecoveryBuilder(); + + Page buildPage(BuildContext context, GoRouterState state) { + final NavigationContract navigationContract = GetIt.I(); + + return MaterialPage( + key: state.pageKey, + child: RequestRecoveryScreen(navigationContract: navigationContract), + ); + } +} diff --git a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart new file mode 100644 index 00000000..27f5547d --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart @@ -0,0 +1,126 @@ +import 'package:auth/src/features/recover_password/presentation/sent/sent_screen.dart'; +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:navigation/navigation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:sf_localizations/sf_localizations.dart'; + +import '../state/recover_password_view_model.dart'; + +class RequestRecoveryScreen extends ConsumerWidget { + final NavigationContract navigationContract; + + const RequestRecoveryScreen({super.key, required this.navigationContract}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.watch(themePortProvider); + + final viewModel = ref.read(recoverPasswordViewModelProvider.notifier); + final viewState = ref.watch(recoverPasswordViewModelProvider); + + return Scaffold( + backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), + body: Container( + margin: EdgeInsets.all(30/*SizeUtils.getByScreen(small: 30, xl: 20)*/), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Recuperar contaseña", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 26/*SizeUtils.getByScreen(small: 30, xl: 26)*/), + ), + SizedBox(height: 24,/*SizeUtils.getByScreen(small: 24, big: 32),*/), + Text( + "Introduce tu email para enviarte un enlace de recuperación", + textAlign: TextAlign.center, + style: TextStyle(letterSpacing: 0, fontSize: 16/*SizeUtils.getByScreen(small: 28, xl: 16)*/), + ), + SizedBox(height: 56,/*SizeUtils.getByScreen(small: 56, big: 48),*/), + CustomTextField( + label: "Correo electrónico", + hint: "Correo electrónico", + controller: viewModel.emailController, + ), + SizedBox(height: 40/*SizeUtils.getByScreen(small: 40, xl: 28)*/), + Align( + alignment: Alignment.bottomLeft, + child: Text( + "Teléfono móvil", + style: TextStyle(fontSize: 14, letterSpacing: 0), + ), + ), + SizedBox(height: 8/*SizeUtils.getByScreen(small: 8, xl: 4)*/), + Row( + children: [ + CountryPrefixPicker( + headerText: context.translate(I18n.selectYourCountry), + initialCountryCode: viewState.dialCode, + onChanged: (country) { + viewModel.updateDialCode( + country.dialCode ?? viewState.dialCode, + ); + }, + width: 80, + ), + SizedBox(width: 10/*SizeUtils.getByScreen(small: 10, xl: 6)*/), + Expanded( + child: CustomTextField( + hint: "Teléfono", + numeric: true, + controller: viewModel.phoneNumberController, + ), + ), + ], + ), + SizedBox(height: 40/*SizeUtils.getByScreen(small: 40, xl: 28)*/), + if (viewState.errorMessage.isNotEmpty) + ...[Text( + viewState.errorMessage, + textAlign: TextAlign.center, + style: const TextStyle( + color: Color.fromRGBO(239, 17, 17, 1), + fontSize: 12, + ), + ), + SizedBox(height: 40/*SizeUtils.getByScreen(small: 40, xl: 28)*/), + ], + Row( + children: [ + Expanded( + child: SecondaryButton( + onPressed: () => {Navigator.pop(context)}, + text: "Volver", + size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + ), + ), + SizedBox(width: 20/*SizeUtils.getByScreen(small: 20, xl: 10)*/), + Expanded( + child: PrimaryButton( + onPressed: () async { + await viewModel.requestRecovery(); + final updatedState = ref.read(recoverPasswordViewModelProvider); + if (updatedState.recoveryRequested) { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => SentScreen(navigationContract: navigationContract), + ), + ); + } + }, + text: "Enviar", + size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + color: theme.getColorFor(ThemeCode.buttonSecondary), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/modules/auth/lib/src/features/recover_password/presentation/restore_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/restore_password_screen.dart deleted file mode 100644 index 7068801f..00000000 --- a/modules/auth/lib/src/features/recover_password/presentation/restore_password_screen.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:auth/src/features/recover_password/presentation/sent_screen.dart'; -import 'package:design_system/design_system.dart'; -import 'package:flutter/material.dart'; -import 'package:navigation/navigation.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -class RestorePasswordScreen extends ConsumerWidget { - final NavigationContract navigationContract; - - const RestorePasswordScreen({super.key, required this.navigationContract}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final theme = ref.watch(themePortProvider); - - return Scaffold( - backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), - body: Container( - margin: EdgeInsets.all(30), - child: Center( - child: Column( - spacing: 48, - children: [ - Spacer(flex: 8), - Column( - spacing: 32, - children: [ - Text( - "Recuperar contaseña", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30), - ), - Text( - "Introduce tu email para enviarte un enlace de recuperación", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 18, letterSpacing: 0), - ), - ], - ), - Column( - spacing: 40, - children: [ - CustomTextField( - label: "Correo electrónico", - hint: "Correo electrónico", - ), - Column( - spacing: 8, - children: [ - Align( - alignment: Alignment.bottomLeft, - child: Text( - "Teléfono móvil", - style: TextStyle(fontSize: 14, letterSpacing: 0), - ), - ), - Row( - spacing: 10, - children: [ - CustomDropdown( - value: 0, - items: [ - Icon(Icons.outlined_flag), - Icon(Icons.outlined_flag), - Icon(Icons.outlined_flag), - ], - onChanged: (value) => {}, - width: 80, - ), - Expanded( - child: CustomTextField( - hint: "Teléfono", - numeric: true, - ), - ), - ], - ), - ], - ), - Row( - spacing: 20, - children: [ - Expanded( - child: SecondaryButton( - onPressed: () => {Navigator.pop(context)}, - text: "Volver", - ), - ), - Expanded( - child: PrimaryButton( - onPressed: () => { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => SentScreen(format: "email"), - ), - ), - }, - text: "Enviar", - size: 16, - color: theme.getColorFor(ThemeCode.buttonSecondary), - ), - ), - ], - ), - ], - ), - Spacer(flex: 10), - ], - ), - ), - ), - ); - } -} diff --git a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_builder.dart b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_builder.dart new file mode 100644 index 00000000..c2ed8e60 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_builder.dart @@ -0,0 +1,18 @@ +import 'package:auth/src/features/recover_password/presentation/sent/sent_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:get_it/get_it.dart'; +import 'package:navigation/navigation.dart'; + +class SentBuilder { + const SentBuilder(); + + Page buildPage(BuildContext context, GoRouterState state) { + final NavigationContract navigationContract = GetIt.I(); + + return MaterialPage( + key: state.pageKey, + child: SentScreen(navigationContract: navigationContract), + ); + } +} diff --git a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart new file mode 100644 index 00000000..0ab57d92 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart @@ -0,0 +1,109 @@ +import 'package:auth/src/features/recover_password/presentation/new_password/new_password_screen.dart'; +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:navigation/navigation.dart'; + +import '../state/recover_password_view_model.dart'; + +class SentScreen extends ConsumerWidget { + final NavigationContract navigationContract; + + const SentScreen({super.key, required this.navigationContract}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.watch(themePortProvider); + + final viewModel = ref.read(recoverPasswordViewModelProvider.notifier); + final viewState = ref.watch(recoverPasswordViewModelProvider); + + return Scaffold( + backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), + body: Container( + margin: EdgeInsets.all(24), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Recuperar contraseña", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 30/*SizeUtils.getByScreen(small: 30, xl: 26)*/, + letterSpacing: 0, + ), + ), + SizedBox(height: 48/*SizeUtils.getByScreen(small: 48, xl: 40)*/), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.check, + color: theme.getColorFor(ThemeCode.buttonPrimary), + ), + SizedBox(width: 6/*SizeUtils.getByScreen(small: 10, xl: 6)*/), + Text( + viewState.recoveryFormat == "email" + ? "Correo enviado correctamente" + : "SMS enviado correctamente", + style: TextStyle(fontSize: 18/*SizeUtils.getByScreen(small: 18, xl: 15)*/, fontWeight: FontWeight.bold), + ), + ], + ), + SizedBox(height: 48/*SizeUtils.getByScreen(small: 48, xl: 40)*/), + Text( + viewState.recoveryFormat == "email" + ? "Revisa tu email y haz clic en el enlace para crear una nueva contraseña." + : "Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 18/*SizeUtils.getByScreen(small: 18, xl: 15)*/, letterSpacing: 0), + ), + SizedBox(height: 16), + Text( + viewState.recoveryFormat == "email" + ? "Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\"." + : "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS \".", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, letterSpacing: 0), + ), + SizedBox(height: 48/*SizeUtils.getByScreen(small: 48, xl: 40)*/), + Row( + children: [ + Expanded( + child: SecondaryButton( + onPressed: () { + if ( viewState.recoveryFormat == "email") { + viewModel.requestEmail(); + } else { + viewModel.requestSms(); + } + }, + text: viewState.recoveryFormat == "email" + ? "Reenviar correo" + : "Reenviar SMS", + size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + ), + ), + SizedBox(width: 10), + Expanded( + child: PrimaryButton( + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (_) => NewPasswordScreen(navigationContract: navigationContract)), + ), + text: "Continuar", + color: theme.getColorFor(ThemeCode.buttonSecondary), + size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/modules/auth/lib/src/features/recover_password/presentation/sent_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/sent_screen.dart deleted file mode 100644 index f386c359..00000000 --- a/modules/auth/lib/src/features/recover_password/presentation/sent_screen.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:auth/src/features/recover_password/presentation/new_password_screen.dart'; -import 'package:design_system/design_system.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -class SentScreen extends ConsumerWidget { - final String format; - - const SentScreen({super.key, required this.format}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final theme = ref.watch(themePortProvider); - - return Scaffold( - backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), - body: Container( - margin: EdgeInsets.all(24), - child: Center( - child: Column( - spacing: 48, - children: [ - Spacer(flex: 8), - Text( - "Recuperar contraseña", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 30, - letterSpacing: 0, - ), - ), - Row( - spacing: 10, - children: [ - Spacer(), - Icon( - Icons.check, - color: theme.getColorFor(ThemeCode.buttonPrimary), - ), - Text( - format == "email" - ? "Correo enviado correctamente" - : "SMS enviado correctamente", - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - Spacer(), - ], - ), - Column( - spacing: 16, - children: [ - Text( - format == "email" - ? "Revisa tu email y haz clic en el enlace para crear una nueva contraseña." - : "Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 18, letterSpacing: 0), - ), - Text( - format == "email" - ? "Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\"." - : "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS \".", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, letterSpacing: 0), - ), - ], - ), - Row( - spacing: 10, - children: [ - Expanded( - child: SecondaryButton( - onPressed: () => {}, - text: format == "email" - ? "Reenviar correo" - : "Reenviar SMS", - ), - ), - Expanded( - child: PrimaryButton( - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (_) => NewPasswordScreen()), - ), - text: "Continuar", - color: theme.getColorFor(ThemeCode.buttonSecondary), - ), - ), - ], - ), - Spacer(flex: 10), - ], - ), - ), - ), - ); - } -} diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart new file mode 100644 index 00000000..ca96fbb5 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart @@ -0,0 +1,275 @@ +import 'package:auth/src/features/recover_password/domain/use_cases/recover_password_use_case.dart'; +import 'package:auth/src/features/recover_password/presentation/state/recover_password_view_state.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../providers/recover_password_provider.dart'; + +final recoverPasswordViewModelProvider = +NotifierProvider.autoDispose( + RecoverPasswordViewModel.new, +); + +class RecoverPasswordViewModel extends Notifier { + late final RecoverPasswordUseCase _recoverPasswordUseCase; + late final TextEditingController phoneNumberController; + late final TextEditingController emailController; + late final TextEditingController passwordController; + late final TextEditingController repeatedPasswordController; + late final TextEditingController newPhoneNumberController; + + @override + RecoverPasswordViewState build() { + _recoverPasswordUseCase = ref.read(recoverPasswordUseCaseProvider); + + phoneNumberController = TextEditingController(); + phoneNumberController.addListener(_onPhoneNumberChanged); + + emailController = TextEditingController(); + emailController.addListener(_onEmailChanged); + + passwordController = TextEditingController(); + passwordController.addListener(_onPasswordChanged); + + repeatedPasswordController = TextEditingController(); + repeatedPasswordController.addListener(_onRepeatedPasswordChanged); + + newPhoneNumberController = TextEditingController(); + newPhoneNumberController.addListener(_onNewPhoneNumberChanged); + + ref.onDispose(disposeControllers); + + return const RecoverPasswordViewState(); + } + + void _onPhoneNumberChanged() { + final String raw = phoneNumberController.text; + state = state.copyWith( + phoneNumber: raw, + errorMessage: '', + recoveryRequested: false, + ); + } + + void _onNewPhoneNumberChanged() { + final String raw = newPhoneNumberController.text; + state = state.copyWith( + newPhoneNumber: raw, + errorMessage: '', + recoveryRequested: false, + ); + } + + void _onEmailChanged() { + final String raw = emailController.text; + state = state.copyWith( + email: raw, + errorMessage: '', + recoveryRequested: false, + ); + } + + void _onPasswordChanged() { + final String raw = passwordController.text; + final bool equalPasswords = raw == repeatedPasswordController.text; + + final bool minCheck = raw.length >= 8; + final bool capitalCheck = RegExp(r'[A-Z]').hasMatch(raw); + final bool numberCheck = RegExp(r'[0-9]').hasMatch(raw); + final bool specialCheck = RegExp(r'[^A-Za-z0-9]').hasMatch(raw); + + final Map security = { + 'min': minCheck, + 'capital': capitalCheck, + 'number': numberCheck, + 'special': specialCheck, + }; + + state = state.copyWith( + password: raw, + equalPasswords: equalPasswords, + securityChecks: security, + ); + } + + void _onRepeatedPasswordChanged() { + final String raw = repeatedPasswordController.text; + final bool equalPasswords = raw == passwordController.text; + state = state.copyWith( + repeatedPassword: raw, + equalPasswords: equalPasswords, + ); + } + + void updateDialCode(String dialCode) { + state = state.copyWith( + dialCode: dialCode, + errorMessage: '', + ); + } + + void updateNewDialCode(String dialCode) { + state = state.copyWith( + newDialCode: dialCode, + errorMessage: '', + ); + } + + void togglePasswordVisible(){ + state = state.copyWith( + passwordVisible: !state.passwordVisible, + ); + } + + Future requestRecovery() async { + final trimmedNumber = state.phoneNumber.trim(); + final email = state.email.trim(); + + state = state.copyWith( + isLoading: true, + errorMessage: '', + recoveryRequested: false, + ); + + if (email.isNotEmpty) { + await requestEmail(); + }else if (trimmedNumber.isNotEmpty) { + await requestSms(); + } else { + state = state.copyWith( + isLoading: false, + errorMessage: 'errorMessageContactIsEmpty', + ); + return; + } + } + + Future requestEmail() async { + final email = state.email.trim(); + + try { + final String token = await _recoverPasswordUseCase.requestEmail(email: email); + if (!ref.mounted) return; + + state = state.copyWith( + isLoading: false, + errorMessage: '', + recoveryRequested: true, + recoveryFormat: 'email', + ); + } catch (e) { + if (!ref.mounted) return; + + state = state.copyWith( + isLoading: false, + errorMessage: e.toString(), + recoveryRequested: false, + passwordChanged: false, + ); + } + } + + Future requestSms() async { + final trimmedNumber = state.phoneNumber.trim(); + + final fullPhone = '${state.dialCode}$trimmedNumber'; + + try { + await _recoverPasswordUseCase.requestSms(phone: fullPhone); + if (!ref.mounted) return; + + state = state.copyWith( + isLoading: false, + errorMessage: '', + recoveryRequested: true, + recoveryFormat: 'sms' + ); + } catch (e) { + if (!ref.mounted) return; + + state = state.copyWith( + isLoading: false, + errorMessage: e.toString(), + recoveryRequested: false, + passwordChanged: false, + ); + } + } + + Future recoverPassword() async { + final String fullPhone = state.newDialCode + state.newPhoneNumber; + final String password = state.password; + + if (!state.equalPasswords) { + state = state.copyWith( + errorMessage: 'errorMessageUnequalPasswords', + passwordChanged: false, + ); + return; + } + + if (!state.securityChecks['min']!) { + state = state.copyWith( + errorMessage: 'errorMessagePasswordTooShort', + passwordChanged: false, + ); + return; + } + + if (!state.securityChecks['capital']!) { + state = state.copyWith( + errorMessage: 'errorMessagePasswordNoCapitals', + passwordChanged: false, + ); + return; + } + + if (!state.securityChecks['number']!) { + state = state.copyWith( + errorMessage: 'errorMessagePasswordNoNumbers', + passwordChanged: false, + ); + return; + } + + if (!state.securityChecks['special']!) { + state = state.copyWith( + errorMessage: 'errorMessagePasswordNoSpecialChars', + passwordChanged: false, + ); + return; + } + + state = state.copyWith( + isLoading: true, + passwordChanged: false, + ); + try { + /*await _recoverPasswordUseCase.recoverPassword( + newPassword: password, token: "");*/ + state = state.copyWith( + isLoading: false, + passwordChanged: true, + ); + } catch (error) { + state = state.copyWith( + errorMessage: error.toString(), + isLoading: false, + passwordChanged: false, + ); + } + } + + void disposeControllers() { + phoneNumberController.removeListener(_onPhoneNumberChanged); + phoneNumberController.dispose(); + emailController.removeListener(_onPhoneNumberChanged); + emailController.dispose(); + passwordController.removeListener(_onPasswordChanged); + passwordController.dispose(); + repeatedPasswordController.removeListener(_onRepeatedPasswordChanged); + repeatedPasswordController.dispose(); + newPhoneNumberController.removeListener(_onNewPhoneNumberChanged); + newPhoneNumberController.dispose(); + } +} \ No newline at end of file diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart new file mode 100644 index 00000000..766e67d7 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart @@ -0,0 +1,29 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'recover_password_view_state.freezed.dart'; + +@freezed +abstract class RecoverPasswordViewState with _$RecoverPasswordViewState { + const factory RecoverPasswordViewState({ + @Default('') String phoneNumber, + @Default('+34') String dialCode, + @Default('') String email, + @Default('') String errorMessage, + @Default('') String recoveryFormat, + @Default(false) bool isLoading, + @Default(false) bool recoveryRequested, + @Default(false) bool passwordChanged, + @Default('') String password, + @Default('') String repeatedPassword, + @Default(false) bool passwordVisible, + @Default(true) bool equalPasswords, + @Default('+34') String newDialCode, + @Default('') String newPhoneNumber, + @Default({ + 'min': false, + 'capital': false, + 'number': false, + 'special': false, + }) Map securityChecks, + }) = _RecoverPasswordViewState; +} \ No newline at end of file diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart new file mode 100644 index 00000000..950aeda5 --- /dev/null +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart @@ -0,0 +1,319 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// 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, unnecessary_question_mark + +part of 'recover_password_view_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$RecoverPasswordViewState { + + String get phoneNumber; String get dialCode; String get email; String get errorMessage; String get recoveryFormat; bool get isLoading; bool get recoveryRequested; bool get passwordChanged; String get password; String get repeatedPassword; bool get passwordVisible; bool get equalPasswords; String get newDialCode; String get newPhoneNumber; Map get securityChecks; +/// Create a copy of RecoverPasswordViewState +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RecoverPasswordViewStateCopyWith get copyWith => _$RecoverPasswordViewStateCopyWithImpl(this as RecoverPasswordViewState, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is RecoverPasswordViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.recoveryFormat, recoveryFormat) || other.recoveryFormat == recoveryFormat)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&(identical(other.newDialCode, newDialCode) || other.newDialCode == newDialCode)&&(identical(other.newPhoneNumber, newPhoneNumber) || other.newPhoneNumber == newPhoneNumber)&&const DeepCollectionEquality().equals(other.securityChecks, securityChecks)); +} + + +@override +int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,email,errorMessage,recoveryFormat,isLoading,recoveryRequested,passwordChanged,password,repeatedPassword,passwordVisible,equalPasswords,newDialCode,newPhoneNumber,const DeepCollectionEquality().hash(securityChecks)); + +@override +String toString() { + return 'RecoverPasswordViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, email: $email, errorMessage: $errorMessage, recoveryFormat: $recoveryFormat, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, newDialCode: $newDialCode, newPhoneNumber: $newPhoneNumber, securityChecks: $securityChecks)'; +} + + +} + +/// @nodoc +abstract mixin class $RecoverPasswordViewStateCopyWith<$Res> { + factory $RecoverPasswordViewStateCopyWith(RecoverPasswordViewState value, $Res Function(RecoverPasswordViewState) _then) = _$RecoverPasswordViewStateCopyWithImpl; +@useResult +$Res call({ + String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks +}); + + + + +} +/// @nodoc +class _$RecoverPasswordViewStateCopyWithImpl<$Res> + implements $RecoverPasswordViewStateCopyWith<$Res> { + _$RecoverPasswordViewStateCopyWithImpl(this._self, this._then); + + final RecoverPasswordViewState _self; + final $Res Function(RecoverPasswordViewState) _then; + +/// Create a copy of RecoverPasswordViewState +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? email = null,Object? errorMessage = null,Object? recoveryFormat = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? newDialCode = null,Object? newPhoneNumber = null,Object? securityChecks = null,}) { + return _then(_self.copyWith( +phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable +as String,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable +as String,email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable +as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String,recoveryFormat: null == recoveryFormat ? _self.recoveryFormat : recoveryFormat // ignore: cast_nullable_to_non_nullable +as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as bool,recoveryRequested: null == recoveryRequested ? _self.recoveryRequested : recoveryRequested // ignore: cast_nullable_to_non_nullable +as bool,passwordChanged: null == passwordChanged ? _self.passwordChanged : passwordChanged // ignore: cast_nullable_to_non_nullable +as bool,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String,repeatedPassword: null == repeatedPassword ? _self.repeatedPassword : repeatedPassword // ignore: cast_nullable_to_non_nullable +as String,passwordVisible: null == passwordVisible ? _self.passwordVisible : passwordVisible // ignore: cast_nullable_to_non_nullable +as bool,equalPasswords: null == equalPasswords ? _self.equalPasswords : equalPasswords // ignore: cast_nullable_to_non_nullable +as bool,newDialCode: null == newDialCode ? _self.newDialCode : newDialCode // ignore: cast_nullable_to_non_nullable +as String,newPhoneNumber: null == newPhoneNumber ? _self.newPhoneNumber : newPhoneNumber // ignore: cast_nullable_to_non_nullable +as String,securityChecks: null == securityChecks ? _self.securityChecks : securityChecks // ignore: cast_nullable_to_non_nullable +as Map, + )); +} + +} + + +/// Adds pattern-matching-related methods to [RecoverPasswordViewState]. +extension RecoverPasswordViewStatePatterns on RecoverPasswordViewState { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _RecoverPasswordViewState value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _RecoverPasswordViewState() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _RecoverPasswordViewState value) $default,){ +final _that = this; +switch (_that) { +case _RecoverPasswordViewState(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _RecoverPasswordViewState value)? $default,){ +final _that = this; +switch (_that) { +case _RecoverPasswordViewState() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _RecoverPasswordViewState() when $default != null: +return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks) $default,) {final _that = this; +switch (_that) { +case _RecoverPasswordViewState(): +return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks)? $default,) {final _that = this; +switch (_that) { +case _RecoverPasswordViewState() when $default != null: +return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _RecoverPasswordViewState implements RecoverPasswordViewState { + const _RecoverPasswordViewState({this.phoneNumber = '', this.dialCode = '+34', this.email = '', this.errorMessage = '', this.recoveryFormat = '', this.isLoading = false, this.recoveryRequested = false, this.passwordChanged = false, this.password = '', this.repeatedPassword = '', this.passwordVisible = false, this.equalPasswords = true, this.newDialCode = '+34', this.newPhoneNumber = '', final Map securityChecks = const {'min' : false, 'capital' : false, 'number' : false, 'special' : false}}): _securityChecks = securityChecks; + + +@override@JsonKey() final String phoneNumber; +@override@JsonKey() final String dialCode; +@override@JsonKey() final String email; +@override@JsonKey() final String errorMessage; +@override@JsonKey() final String recoveryFormat; +@override@JsonKey() final bool isLoading; +@override@JsonKey() final bool recoveryRequested; +@override@JsonKey() final bool passwordChanged; +@override@JsonKey() final String password; +@override@JsonKey() final String repeatedPassword; +@override@JsonKey() final bool passwordVisible; +@override@JsonKey() final bool equalPasswords; +@override@JsonKey() final String newDialCode; +@override@JsonKey() final String newPhoneNumber; + final Map _securityChecks; +@override@JsonKey() Map get securityChecks { + if (_securityChecks is EqualUnmodifiableMapView) return _securityChecks; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_securityChecks); +} + + +/// Create a copy of RecoverPasswordViewState +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RecoverPasswordViewStateCopyWith<_RecoverPasswordViewState> get copyWith => __$RecoverPasswordViewStateCopyWithImpl<_RecoverPasswordViewState>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RecoverPasswordViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.recoveryFormat, recoveryFormat) || other.recoveryFormat == recoveryFormat)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&(identical(other.newDialCode, newDialCode) || other.newDialCode == newDialCode)&&(identical(other.newPhoneNumber, newPhoneNumber) || other.newPhoneNumber == newPhoneNumber)&&const DeepCollectionEquality().equals(other._securityChecks, _securityChecks)); +} + + +@override +int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,email,errorMessage,recoveryFormat,isLoading,recoveryRequested,passwordChanged,password,repeatedPassword,passwordVisible,equalPasswords,newDialCode,newPhoneNumber,const DeepCollectionEquality().hash(_securityChecks)); + +@override +String toString() { + return 'RecoverPasswordViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, email: $email, errorMessage: $errorMessage, recoveryFormat: $recoveryFormat, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, newDialCode: $newDialCode, newPhoneNumber: $newPhoneNumber, securityChecks: $securityChecks)'; +} + + +} + +/// @nodoc +abstract mixin class _$RecoverPasswordViewStateCopyWith<$Res> implements $RecoverPasswordViewStateCopyWith<$Res> { + factory _$RecoverPasswordViewStateCopyWith(_RecoverPasswordViewState value, $Res Function(_RecoverPasswordViewState) _then) = __$RecoverPasswordViewStateCopyWithImpl; +@override @useResult +$Res call({ + String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks +}); + + + + +} +/// @nodoc +class __$RecoverPasswordViewStateCopyWithImpl<$Res> + implements _$RecoverPasswordViewStateCopyWith<$Res> { + __$RecoverPasswordViewStateCopyWithImpl(this._self, this._then); + + final _RecoverPasswordViewState _self; + final $Res Function(_RecoverPasswordViewState) _then; + +/// Create a copy of RecoverPasswordViewState +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? email = null,Object? errorMessage = null,Object? recoveryFormat = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? newDialCode = null,Object? newPhoneNumber = null,Object? securityChecks = null,}) { + return _then(_RecoverPasswordViewState( +phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable +as String,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable +as String,email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable +as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String,recoveryFormat: null == recoveryFormat ? _self.recoveryFormat : recoveryFormat // ignore: cast_nullable_to_non_nullable +as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as bool,recoveryRequested: null == recoveryRequested ? _self.recoveryRequested : recoveryRequested // ignore: cast_nullable_to_non_nullable +as bool,passwordChanged: null == passwordChanged ? _self.passwordChanged : passwordChanged // ignore: cast_nullable_to_non_nullable +as bool,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String,repeatedPassword: null == repeatedPassword ? _self.repeatedPassword : repeatedPassword // ignore: cast_nullable_to_non_nullable +as String,passwordVisible: null == passwordVisible ? _self.passwordVisible : passwordVisible // ignore: cast_nullable_to_non_nullable +as bool,equalPasswords: null == equalPasswords ? _self.equalPasswords : equalPasswords // ignore: cast_nullable_to_non_nullable +as bool,newDialCode: null == newDialCode ? _self.newDialCode : newDialCode // ignore: cast_nullable_to_non_nullable +as String,newPhoneNumber: null == newPhoneNumber ? _self.newPhoneNumber : newPhoneNumber // ignore: cast_nullable_to_non_nullable +as String,securityChecks: null == securityChecks ? _self._securityChecks : securityChecks // ignore: cast_nullable_to_non_nullable +as Map, + )); +} + + +} + +// dart format on diff --git a/modules/auth/lib/src/features/recover_password/recover_password_builder.dart b/modules/auth/lib/src/features/recover_password/recover_password_builder.dart index 930f53ba..1749d1f3 100644 --- a/modules/auth/lib/src/features/recover_password/recover_password_builder.dart +++ b/modules/auth/lib/src/features/recover_password/recover_password_builder.dart @@ -1,4 +1,4 @@ -import 'package:auth/src/features/recover_password/presentation/restore_password_screen.dart'; +import 'package:auth/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:get_it/get_it.dart'; @@ -12,7 +12,7 @@ class RecoverPasswordBuilder { return MaterialPage( key: state.pageKey, - child: RestorePasswordScreen(navigationContract: navigationContract), + child: RequestRecoveryScreen(navigationContract: navigationContract), ); } } diff --git a/packages/design_system/lib/src/inputs/textfields.dart b/packages/design_system/lib/src/inputs/textfields.dart index a665ff8d..53ab0400 100644 --- a/packages/design_system/lib/src/inputs/textfields.dart +++ b/packages/design_system/lib/src/inputs/textfields.dart @@ -1,90 +1,88 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -class CustomTextField extends StatefulWidget { +class CustomTextField extends StatelessWidget { final bool? showPassword; + final VoidCallback? onVisibilityChanged; final bool numeric; final String hint; final String label; + final double labelSize; final int? lines; final ValueChanged? onChanged; final int? length; final TextEditingController? controller; + final String? initialValue; + final Color color; const CustomTextField({ super.key, this.showPassword, + this.onVisibilityChanged, this.numeric = false, this.hint = '', this.label = '', + this.labelSize = 14, this.lines, this.length, this.onChanged, this.controller, + this.initialValue, + this.color = const Color(0xFF4B4B4B), }); - @override - State createState() => CustomTextFieldState(); -} - -class CustomTextFieldState extends State { - late bool _showPassword; - @override - void initState() { - super.initState(); - _showPassword = widget.showPassword ?? true; - } - @override Widget build(BuildContext context) { return Column( spacing: 8, children: [ - if (widget.label.isNotEmpty) + if (label.isNotEmpty) Align( alignment: Alignment.bottomLeft, child: Text( - widget.label, - style: const TextStyle(fontSize: 14, letterSpacing: 0), + label, + style: TextStyle(fontSize: labelSize, letterSpacing: 0), ), ), TextFormField( - controller: widget.controller, - keyboardType: widget.numeric + controller: controller, + keyboardType: numeric ? TextInputType.number : TextInputType.text, - obscureText: !_showPassword, - enableSuggestions: _showPassword, - autocorrect: !_showPassword, + obscureText: !(showPassword ?? true), + enableSuggestions: (showPassword ?? true), + autocorrect: !(showPassword ?? true), style: const TextStyle(color: Color(0xFF4B4B4B)), - inputFormatters: widget.numeric + inputFormatters: numeric ? [FilteringTextInputFormatter.digitsOnly] : const [], decoration: InputDecoration( counterText: "", - hintText: widget.hint, - border: const OutlineInputBorder( + hintText: hint, + enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), - borderSide: BorderSide(color: Color(0xFF4B4B4B)), + borderSide: BorderSide(color: color), gapPadding: 16, ), - suffixIcon: widget.showPassword != null + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + borderSide: BorderSide(color: color), + gapPadding: 16, + ), + suffixIcon: showPassword != null ? IconButton( - icon: Icon( - _showPassword ? Icons.visibility_off : Icons.visibility, - ), - onPressed: () { - setState(() { - _showPassword = !_showPassword; - }); - }, - ) + icon: Icon( + showPassword! ? Icons.visibility_off_outlined : Icons.visibility_outlined, + ), + onPressed: onVisibilityChanged, + ) : null, ), - minLines: widget.lines ?? 1, - maxLines: widget.lines ?? 1, - maxLength: widget.length, - onChanged: widget.onChanged, + initialValue: initialValue, + minLines: lines ?? 1, + maxLines: lines ?? 1, + maxLength: length, + onChanged: onChanged, ), ], ); diff --git a/packages/design_system/test/goldens/textfield.png b/packages/design_system/test/goldens/textfield.png index 3021a3737838bde0949e9de68a39efc252dd5da2..dc4db806fa31ae9577887ce9526825ae8d796db4 100644 GIT binary patch literal 8765 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 D#jn^9 literal 8784 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 Date: Fri, 12 Dec 2025 13:42:06 +0100 Subject: [PATCH 2/6] added size utils to recoverPassword --- apps/mobile_app/lib/main.dart | 3 ++ apps/mobile_app/pubspec.yaml | 2 + .../new_password/new_password_screen.dart | 39 ++++++++++--------- .../request_recovery_screen.dart | 31 ++++++++------- .../presentation/sent/sent_screen.dart | 21 +++++----- modules/auth/pubspec.yaml | 4 +- packages/utils/lib/src/size_utils.dart | 7 +++- 7 files changed, 60 insertions(+), 47 deletions(-) diff --git a/apps/mobile_app/lib/main.dart b/apps/mobile_app/lib/main.dart index 8d3ebb5d..471095ce 100644 --- a/apps/mobile_app/lib/main.dart +++ b/apps/mobile_app/lib/main.dart @@ -9,6 +9,7 @@ import 'package:sf_app_platform/navigation/app_router.dart'; import 'package:navigation/navigation_module.dart'; import 'package:sf_infrastructure/sf_infrastructure.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:utils/utils.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -26,6 +27,8 @@ class PlatformApp extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + SizeUtils.init(context: context); + return MaterialApp.router( title: 'SaveFamily', theme: ThemeData( diff --git a/apps/mobile_app/pubspec.yaml b/apps/mobile_app/pubspec.yaml index 09555ae8..ec4145f2 100644 --- a/apps/mobile_app/pubspec.yaml +++ b/apps/mobile_app/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: path: ../../packages/fonts sf_infrastructure: path: ../../packages/sf_infrastructure + utils: + path: ../../packages/utils #dependencies go here cupertino_icons: ^1.0.8 diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart index 74e35d38..906a9c35 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get_it/get_it.dart'; import 'package:navigation/navigation.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:utils/utils.dart'; class NewPasswordScreen extends ConsumerStatefulWidget { final NavigationContract navigationContract; @@ -38,20 +39,20 @@ class NewPasswordScreenState extends ConsumerState { child: SingleChildScrollView(child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( + Text( 'Recuperar contraseña', textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w500, - fontSize: 30/*SizeUtils.getByScreen(small: 30, xl: 26)*/, + fontSize: SizeUtils.getByScreen(small: 30, big: 30, xl: 26), letterSpacing: 0 ), ), - SizedBox(height: 42/*SizeUtils.getBySize(small: 42, big: 32)*/), + SizedBox(height: SizeUtils.getByScreen(small: 42, big: 32)), CustomTextField( showPassword: viewState.passwordVisible, label: 'Nueva contraseña', - labelSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, + labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), hint: '********', controller: viewModel.passwordController, onVisibilityChanged: viewModel.togglePasswordVisible, @@ -60,7 +61,7 @@ class NewPasswordScreenState extends ConsumerState { CustomTextField( showPassword: viewState.passwordVisible, label: 'Repetir contraseña', - labelSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, + labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), hint: '********', controller: viewModel.repeatedPasswordController, onVisibilityChanged: viewModel.togglePasswordVisible, @@ -98,13 +99,13 @@ class NewPasswordScreenState extends ConsumerState { ? ThemeCode.buttonPrimary : ThemeCode.buttonSecondary), ), - const Text( + Text( 'Al menos 8 caracteres', - style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], ), - SizedBox(height: 2/*SizeUtils.getBySize(small: 2, big: 4)*/), + SizedBox(height: SizeUtils.getByScreen(small: 2, big: 4)), Row( spacing: 8, children: [ @@ -114,13 +115,13 @@ class NewPasswordScreenState extends ConsumerState { ? ThemeCode.buttonPrimary : ThemeCode.buttonSecondary), ), - const Text( + Text( 'Una mayúscula', - style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], ), - SizedBox(height: 2/*SizeUtils.getBySize(small: 2, big: 4)*/), + SizedBox(height: SizeUtils.getByScreen(small: 2, big: 4)), Row( spacing: 8, children: [ @@ -130,13 +131,13 @@ class NewPasswordScreenState extends ConsumerState { ? ThemeCode.buttonPrimary : ThemeCode.buttonSecondary), ), - const Text( + Text( 'Un número', - style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], ), - SizedBox(height: 2/*SizeUtils.getBySize(small: 2, big: 4)*/), + SizedBox(height: SizeUtils.getByScreen(small: 2, big: 4)), Row( spacing: 8, children: [ @@ -146,18 +147,18 @@ class NewPasswordScreenState extends ConsumerState { ? ThemeCode.buttonPrimary : ThemeCode.buttonSecondary), ), - const Text( + Text( 'Un carácter especial', - style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/) + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], ), - SizedBox(height: 32/*SizeUtils.getByScreen(small: 32, xl: 24)*/), + SizedBox(height: SizeUtils.getByScreen(small: 32, big: 32, xl: 24)), Align( alignment: Alignment.bottomLeft, - child: const Text( + child: Text( 'Teléfono móvil', - style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, letterSpacing: 0), + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0), ) ), SizedBox(height: 8), diff --git a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart index 27f5547d..38d01e31 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:navigation/navigation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:utils/utils.dart'; import '../state/recover_password_view_model.dart'; @@ -22,28 +23,28 @@ class RequestRecoveryScreen extends ConsumerWidget { return Scaffold( backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), body: Container( - margin: EdgeInsets.all(30/*SizeUtils.getByScreen(small: 30, xl: 20)*/), + margin: EdgeInsets.all(SizeUtils.getByScreen(small: 30, big: 30, xl: 20)), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Recuperar contaseña", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 26/*SizeUtils.getByScreen(small: 30, xl: 26)*/), + style: TextStyle(fontWeight: FontWeight.bold, fontSize: SizeUtils.getByScreen(small: 30, big: 30, xl: 26)), ), - SizedBox(height: 24,/*SizeUtils.getByScreen(small: 24, big: 32),*/), + SizedBox(height: SizeUtils.getByScreen(small: 24, big: 32)), Text( "Introduce tu email para enviarte un enlace de recuperación", textAlign: TextAlign.center, - style: TextStyle(letterSpacing: 0, fontSize: 16/*SizeUtils.getByScreen(small: 28, xl: 16)*/), + style: TextStyle(letterSpacing: 0, fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 16)), ), - SizedBox(height: 56,/*SizeUtils.getByScreen(small: 56, big: 48),*/), + SizedBox(height: SizeUtils.getByScreen(small: 56, big: 48)), CustomTextField( label: "Correo electrónico", hint: "Correo electrónico", controller: viewModel.emailController, ), - SizedBox(height: 40/*SizeUtils.getByScreen(small: 40, xl: 28)*/), + SizedBox(height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28)), Align( alignment: Alignment.bottomLeft, child: Text( @@ -51,7 +52,7 @@ class RequestRecoveryScreen extends ConsumerWidget { style: TextStyle(fontSize: 14, letterSpacing: 0), ), ), - SizedBox(height: 8/*SizeUtils.getByScreen(small: 8, xl: 4)*/), + SizedBox(height: 8), Row( children: [ CountryPrefixPicker( @@ -64,7 +65,7 @@ class RequestRecoveryScreen extends ConsumerWidget { }, width: 80, ), - SizedBox(width: 10/*SizeUtils.getByScreen(small: 10, xl: 6)*/), + SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)), Expanded( child: CustomTextField( hint: "Teléfono", @@ -74,9 +75,9 @@ class RequestRecoveryScreen extends ConsumerWidget { ), ], ), - SizedBox(height: 40/*SizeUtils.getByScreen(small: 40, xl: 28)*/), - if (viewState.errorMessage.isNotEmpty) - ...[Text( + SizedBox(height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28)), + if (viewState.errorMessage.isNotEmpty) ...[ + Text( viewState.errorMessage, textAlign: TextAlign.center, style: const TextStyle( @@ -84,7 +85,7 @@ class RequestRecoveryScreen extends ConsumerWidget { fontSize: 12, ), ), - SizedBox(height: 40/*SizeUtils.getByScreen(small: 40, xl: 28)*/), + SizedBox(height: 40), ], Row( children: [ @@ -92,10 +93,10 @@ class RequestRecoveryScreen extends ConsumerWidget { child: SecondaryButton( onPressed: () => {Navigator.pop(context)}, text: "Volver", - size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), - SizedBox(width: 20/*SizeUtils.getByScreen(small: 20, xl: 10)*/), + SizedBox(width: SizeUtils.getByScreen(small: 20, big: 20, xl: 10)), Expanded( child: PrimaryButton( onPressed: () async { @@ -111,7 +112,7 @@ class RequestRecoveryScreen extends ConsumerWidget { } }, text: "Enviar", - size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), color: theme.getColorFor(ThemeCode.buttonSecondary), ), ), diff --git a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart index 0ab57d92..cbbca3ca 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart @@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:navigation/navigation.dart'; +import 'package:utils/utils.dart'; import '../state/recover_password_view_model.dart'; @@ -31,11 +32,11 @@ class SentScreen extends ConsumerWidget { textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w500, - fontSize: 30/*SizeUtils.getByScreen(small: 30, xl: 26)*/, + fontSize: SizeUtils.getByScreen(small: 30, big: 30, xl: 26), letterSpacing: 0, ), ), - SizedBox(height: 48/*SizeUtils.getByScreen(small: 48, xl: 40)*/), + SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -43,22 +44,22 @@ class SentScreen extends ConsumerWidget { Icons.check, color: theme.getColorFor(ThemeCode.buttonPrimary), ), - SizedBox(width: 6/*SizeUtils.getByScreen(small: 10, xl: 6)*/), + SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)), Text( viewState.recoveryFormat == "email" ? "Correo enviado correctamente" : "SMS enviado correctamente", - style: TextStyle(fontSize: 18/*SizeUtils.getByScreen(small: 18, xl: 15)*/, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), fontWeight: FontWeight.bold), ), ], ), - SizedBox(height: 48/*SizeUtils.getByScreen(small: 48, xl: 40)*/), + SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)), Text( viewState.recoveryFormat == "email" ? "Revisa tu email y haz clic en el enlace para crear una nueva contraseña." : "Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.", textAlign: TextAlign.center, - style: TextStyle(fontSize: 18/*SizeUtils.getByScreen(small: 18, xl: 15)*/, letterSpacing: 0), + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), letterSpacing: 0), ), SizedBox(height: 16), Text( @@ -66,9 +67,9 @@ class SentScreen extends ConsumerWidget { ? "Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\"." : "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS \".", textAlign: TextAlign.center, - style: TextStyle(fontSize: 14/*SizeUtils.getByScreen(small: 14, xl: 12)*/, letterSpacing: 0), + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0), ), - SizedBox(height: 48/*SizeUtils.getByScreen(small: 48, xl: 40)*/), + SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)), Row( children: [ Expanded( @@ -83,7 +84,7 @@ class SentScreen extends ConsumerWidget { text: viewState.recoveryFormat == "email" ? "Reenviar correo" : "Reenviar SMS", - size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), SizedBox(width: 10), @@ -95,7 +96,7 @@ class SentScreen extends ConsumerWidget { ), text: "Continuar", color: theme.getColorFor(ThemeCode.buttonSecondary), - size: 16/*SizeUtils.getByScreen(small: 16, xl: 14)*/, + size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), ], diff --git a/modules/auth/pubspec.yaml b/modules/auth/pubspec.yaml index d8ff6537..d5eff810 100644 --- a/modules/auth/pubspec.yaml +++ b/modules/auth/pubspec.yaml @@ -21,9 +21,11 @@ dependencies: navigation: path: ../../packages/navigation sf_localizations: - path: ../../packages/sf_localizations + path: ../../packages/sf_localizations sf_infrastructure: path: ../../packages/sf_infrastructure + utils: + path: ../../packages/utils #dependencies go here flutter_svg: ^2.2.1 get_it: ^9.0.5 diff --git a/packages/utils/lib/src/size_utils.dart b/packages/utils/lib/src/size_utils.dart index 576cebc0..08b0d3e5 100755 --- a/packages/utils/lib/src/size_utils.dart +++ b/packages/utils/lib/src/size_utils.dart @@ -69,7 +69,9 @@ class SizeUtils { static bool get isMediumScreen => physicalAspectRatioHeight <= 18.0; - static bool get isXLScreen => physicalAspectRatioHeight >= 20.0; + static bool get isBigScreen => physicalAspectRatioHeight <= 20.0; + + static bool get isXLScreen => physicalAspectRatioHeight >= 21.5; static Size get screenSize => Size(width, height); @@ -81,7 +83,8 @@ class SizeUtils { }) { if (isSmallerScreen) return small; if (isMediumScreen) return medium ?? small; - if (isXLScreen && xl != null) return xl; + if (isBigScreen) return big; + if (isXLScreen) return xl ?? big; return big; } From ce062ec6e89cb3b3f3f69af2779edf646edcb9b4 Mon Sep 17 00:00:00 2001 From: aitorarana Date: Wed, 17 Dec 2025 12:39:41 +0100 Subject: [PATCH 3/6] Added error message text to new password screen --- .../new_password/new_password_screen.dart | 11 +++++++++++ .../state/recover_password_view_model.dart | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart index 906a9c35..02b002a3 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart @@ -181,6 +181,17 @@ class NewPasswordScreenState extends ConsumerState { )) ] ), + if (viewState.errorMessage.isNotEmpty) ...[ + SizedBox(height: 10), + Text( + viewState.errorMessage, + textAlign: TextAlign.center, + style: const TextStyle( + color: Color.fromRGBO(239, 17, 17, 1), + fontSize: 12, + ), + ), + ], SizedBox(height: 56), PrimaryButton( onPressed: () async { diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart index ca96fbb5..54714b79 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart @@ -87,6 +87,7 @@ class RecoverPasswordViewModel extends Notifier { state = state.copyWith( password: raw, + errorMessage: '', equalPasswords: equalPasswords, securityChecks: security, ); @@ -97,6 +98,7 @@ class RecoverPasswordViewModel extends Notifier { final bool equalPasswords = raw == passwordController.text; state = state.copyWith( repeatedPassword: raw, + errorMessage: '', equalPasswords: equalPasswords, ); } @@ -133,7 +135,7 @@ class RecoverPasswordViewModel extends Notifier { if (email.isNotEmpty) { await requestEmail(); - }else if (trimmedNumber.isNotEmpty) { + } else if (trimmedNumber.isNotEmpty) { await requestSms(); } else { state = state.copyWith( From f6e07192dc9e4513d2a3c859dbd07ccccddb7611 Mon Sep 17 00:00:00 2001 From: aitorarana Date: Thu, 18 Dec 2025 10:56:06 +0100 Subject: [PATCH 4/6] Added recover password texts to i18n --- .../new_password/new_password_screen.dart | 45 +++++++------------ .../request_recovery_screen.dart | 20 ++++----- .../presentation/sent/sent_screen.dart | 23 +++++----- .../state/recover_password_view_model.dart | 8 ++-- .../state/recover_password_view_state.dart | 1 + .../recover_password_view_state.freezed.dart | 43 +++++++++--------- packages/sf_localizations/assets/l10n/de.json | 29 +++++++++++- packages/sf_localizations/assets/l10n/en.json | 29 +++++++++++- packages/sf_localizations/assets/l10n/es.json | 29 +++++++++++- packages/sf_localizations/assets/l10n/fr.json | 29 +++++++++++- packages/sf_localizations/assets/l10n/it.json | 29 +++++++++++- packages/sf_localizations/assets/l10n/pt.json | 29 +++++++++++- .../lib/sf_localizations.dart | 3 +- 13 files changed, 238 insertions(+), 79 deletions(-) diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart index 02b002a3..1cfa07cc 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart @@ -7,24 +7,13 @@ import 'package:navigation/navigation.dart'; import 'package:sf_localizations/sf_localizations.dart'; import 'package:utils/utils.dart'; -class NewPasswordScreen extends ConsumerStatefulWidget { +class NewPasswordScreen extends ConsumerWidget { final NavigationContract navigationContract; - const NewPasswordScreen({super.key, required this.navigationContract}); + const NewPasswordScreen({required this.navigationContract}); @override - ConsumerState createState() => NewPasswordScreenState(); -} - -class NewPasswordScreenState extends ConsumerState { - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final NavigationContract navigationContract = GetIt.I(); final theme = ref.watch(themePortProvider); @@ -40,7 +29,7 @@ class NewPasswordScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - 'Recuperar contraseña', + context.translate(LocaleKeys.recoverPasswordTitle), textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w500, @@ -51,7 +40,7 @@ class NewPasswordScreenState extends ConsumerState { SizedBox(height: SizeUtils.getByScreen(small: 42, big: 32)), CustomTextField( showPassword: viewState.passwordVisible, - label: 'Nueva contraseña', + label: context.translate(LocaleKeys.newPassword), labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), hint: '********', controller: viewModel.passwordController, @@ -60,7 +49,7 @@ class NewPasswordScreenState extends ConsumerState { SizedBox(height: 16), CustomTextField( showPassword: viewState.passwordVisible, - label: 'Repetir contraseña', + label: context.translate(LocaleKeys.repeatPassword), labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), hint: '********', controller: viewModel.repeatedPasswordController, @@ -69,16 +58,16 @@ class NewPasswordScreenState extends ConsumerState { ), if (!viewState.equalPasswords) ...[ SizedBox(height: 4), - const Row( + Row( spacing: 8, children: [ - Icon( + const Icon( Icons.info_outline_rounded, color: Color.fromRGBO(239, 17, 17, 1), size: 16, ), Text( - 'Las contraseñas no coinciden. Inténtalo de nuevo', + context.translate(LocaleKeys.errorMessageUnequalPasswords), textAlign: TextAlign.left, style: TextStyle( color: Color.fromRGBO(239, 17, 17, 1), @@ -100,7 +89,7 @@ class NewPasswordScreenState extends ConsumerState { : ThemeCode.buttonSecondary), ), Text( - 'Al menos 8 caracteres', + context.translate(LocaleKeys.passwordLength), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -116,7 +105,7 @@ class NewPasswordScreenState extends ConsumerState { : ThemeCode.buttonSecondary), ), Text( - 'Una mayúscula', + context.translate(LocaleKeys.passwordCapital), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -132,7 +121,7 @@ class NewPasswordScreenState extends ConsumerState { : ThemeCode.buttonSecondary), ), Text( - 'Un número', + context.translate(LocaleKeys.passwordNumber), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -148,7 +137,7 @@ class NewPasswordScreenState extends ConsumerState { : ThemeCode.buttonSecondary), ), Text( - 'Un carácter especial', + context.translate(LocaleKeys.passwordSpecial), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -157,7 +146,7 @@ class NewPasswordScreenState extends ConsumerState { Align( alignment: Alignment.bottomLeft, child: Text( - 'Teléfono móvil', + context.translate(LocaleKeys.mobilePhone), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0), ) ), @@ -175,7 +164,7 @@ class NewPasswordScreenState extends ConsumerState { }, ), Expanded(child: CustomTextField( - hint: 'Teléfono', + hint: context.translate(LocaleKeys.phoneNumber), numeric: true, controller: viewModel.newPhoneNumberController, )) @@ -184,7 +173,7 @@ class NewPasswordScreenState extends ConsumerState { if (viewState.errorMessage.isNotEmpty) ...[ SizedBox(height: 10), Text( - viewState.errorMessage, + context.translate(viewState.errorMessage), textAlign: TextAlign.center, style: const TextStyle( color: Color.fromRGBO(239, 17, 17, 1), @@ -201,7 +190,7 @@ class NewPasswordScreenState extends ConsumerState { navigationContract.goTo(AppRoutes.dashboardHome); } }, - text: 'Aceptar', + text: context.translate(LocaleKeys.accept), color: theme.getColorFor(ThemeCode.buttonPrimary) ), ], diff --git a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart index 38d01e31..662ada93 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart @@ -29,26 +29,26 @@ class RequestRecoveryScreen extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - "Recuperar contaseña", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: SizeUtils.getByScreen(small: 30, big: 30, xl: 26)), + context.translate(LocaleKeys.recoverPasswordTitle), + style: TextStyle(fontWeight: FontWeight.bold, fontSize: SizeUtils.getByScreen(small: 29, big: 29, xl: 26)), ), SizedBox(height: SizeUtils.getByScreen(small: 24, big: 32)), Text( - "Introduce tu email para enviarte un enlace de recuperación", + context.translate(LocaleKeys.recoverPasswordSubtitle), textAlign: TextAlign.center, style: TextStyle(letterSpacing: 0, fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 16)), ), SizedBox(height: SizeUtils.getByScreen(small: 56, big: 48)), CustomTextField( - label: "Correo electrónico", - hint: "Correo electrónico", + label: context.translate(LocaleKeys.email), + hint: context.translate(LocaleKeys.email), controller: viewModel.emailController, ), SizedBox(height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28)), Align( alignment: Alignment.bottomLeft, child: Text( - "Teléfono móvil", + context.translate(LocaleKeys.mobilePhone), style: TextStyle(fontSize: 14, letterSpacing: 0), ), ), @@ -68,7 +68,7 @@ class RequestRecoveryScreen extends ConsumerWidget { SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)), Expanded( child: CustomTextField( - hint: "Teléfono", + hint: context.translate(I18n.phoneNumber), numeric: true, controller: viewModel.phoneNumberController, ), @@ -78,7 +78,7 @@ class RequestRecoveryScreen extends ConsumerWidget { SizedBox(height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28)), if (viewState.errorMessage.isNotEmpty) ...[ Text( - viewState.errorMessage, + context.translate(viewState.errorMessage), textAlign: TextAlign.center, style: const TextStyle( color: Color.fromRGBO(239, 17, 17, 1), @@ -92,7 +92,7 @@ class RequestRecoveryScreen extends ConsumerWidget { Expanded( child: SecondaryButton( onPressed: () => {Navigator.pop(context)}, - text: "Volver", + text: context.translate(LocaleKeys.back), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), @@ -111,7 +111,7 @@ class RequestRecoveryScreen extends ConsumerWidget { ); } }, - text: "Enviar", + text: context.translate(LocaleKeys.send), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), color: theme.getColorFor(ThemeCode.buttonSecondary), ), diff --git a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart index cbbca3ca..182021ff 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart @@ -3,6 +3,7 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:navigation/navigation.dart'; +import 'package:sf_localizations/sf_localizations.dart'; import 'package:utils/utils.dart'; import '../state/recover_password_view_model.dart'; @@ -28,7 +29,7 @@ class SentScreen extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - "Recuperar contraseña", + context.translate(LocaleKeys.recoverPasswordTitle), textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w500, @@ -47,8 +48,8 @@ class SentScreen extends ConsumerWidget { SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)), Text( viewState.recoveryFormat == "email" - ? "Correo enviado correctamente" - : "SMS enviado correctamente", + ? context.translate(LocaleKeys.emailSent) + : context.translate(LocaleKeys.smsSent), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), fontWeight: FontWeight.bold), ), ], @@ -56,16 +57,16 @@ class SentScreen extends ConsumerWidget { SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)), Text( viewState.recoveryFormat == "email" - ? "Revisa tu email y haz clic en el enlace para crear una nueva contraseña." - : "Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.", + ? context.translate(LocaleKeys.checkEmail1) + : context.translate(LocaleKeys.checkSms1), textAlign: TextAlign.center, - style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), letterSpacing: 0), + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 17, big: 17, xl: 15), letterSpacing: 0), ), SizedBox(height: 16), Text( viewState.recoveryFormat == "email" - ? "Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\"." - : "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS \".", + ? context.translate(LocaleKeys.checkEmail2) + : context.translate(LocaleKeys.checkSms2), textAlign: TextAlign.center, style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0), ), @@ -82,8 +83,8 @@ class SentScreen extends ConsumerWidget { } }, text: viewState.recoveryFormat == "email" - ? "Reenviar correo" - : "Reenviar SMS", + ? context.translate(LocaleKeys.resendEmail) + : context.translate(LocaleKeys.resendSms), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), @@ -94,7 +95,7 @@ class SentScreen extends ConsumerWidget { context, MaterialPageRoute(builder: (_) => NewPasswordScreen(navigationContract: navigationContract)), ), - text: "Continuar", + text: context.translate(LocaleKeys.continueKey), color: theme.getColorFor(ThemeCode.buttonSecondary), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart index 54714b79..ad93dd8d 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart @@ -157,6 +157,7 @@ class RecoverPasswordViewModel extends Notifier { isLoading: false, errorMessage: '', recoveryRequested: true, + token: token, recoveryFormat: 'email', ); } catch (e) { @@ -177,13 +178,14 @@ class RecoverPasswordViewModel extends Notifier { final fullPhone = '${state.dialCode}$trimmedNumber'; try { - await _recoverPasswordUseCase.requestSms(phone: fullPhone); + final String token = await _recoverPasswordUseCase.requestSms(phone: fullPhone); if (!ref.mounted) return; state = state.copyWith( isLoading: false, errorMessage: '', recoveryRequested: true, + token: token, recoveryFormat: 'sms' ); } catch (e) { @@ -247,8 +249,8 @@ class RecoverPasswordViewModel extends Notifier { passwordChanged: false, ); try { - /*await _recoverPasswordUseCase.recoverPassword( - newPassword: password, token: "");*/ + await _recoverPasswordUseCase.recoverPassword( + newPassword: password, token: state.token); state = state.copyWith( isLoading: false, passwordChanged: true, diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart index 766e67d7..b63e227f 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.dart @@ -13,6 +13,7 @@ abstract class RecoverPasswordViewState with _$RecoverPasswordViewState { @Default(false) bool isLoading, @Default(false) bool recoveryRequested, @Default(false) bool passwordChanged, + @Default('') String token, @Default('') String password, @Default('') String repeatedPassword, @Default(false) bool passwordVisible, diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart index 950aeda5..a833a83b 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_state.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$RecoverPasswordViewState { - String get phoneNumber; String get dialCode; String get email; String get errorMessage; String get recoveryFormat; bool get isLoading; bool get recoveryRequested; bool get passwordChanged; String get password; String get repeatedPassword; bool get passwordVisible; bool get equalPasswords; String get newDialCode; String get newPhoneNumber; Map get securityChecks; + String get phoneNumber; String get dialCode; String get email; String get errorMessage; String get recoveryFormat; bool get isLoading; bool get recoveryRequested; bool get passwordChanged; String get token; String get password; String get repeatedPassword; bool get passwordVisible; bool get equalPasswords; String get newDialCode; String get newPhoneNumber; Map get securityChecks; /// Create a copy of RecoverPasswordViewState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -25,16 +25,16 @@ $RecoverPasswordViewStateCopyWith get copyWith => _$Re @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is RecoverPasswordViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.recoveryFormat, recoveryFormat) || other.recoveryFormat == recoveryFormat)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&(identical(other.newDialCode, newDialCode) || other.newDialCode == newDialCode)&&(identical(other.newPhoneNumber, newPhoneNumber) || other.newPhoneNumber == newPhoneNumber)&&const DeepCollectionEquality().equals(other.securityChecks, securityChecks)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is RecoverPasswordViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.recoveryFormat, recoveryFormat) || other.recoveryFormat == recoveryFormat)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.token, token) || other.token == token)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&(identical(other.newDialCode, newDialCode) || other.newDialCode == newDialCode)&&(identical(other.newPhoneNumber, newPhoneNumber) || other.newPhoneNumber == newPhoneNumber)&&const DeepCollectionEquality().equals(other.securityChecks, securityChecks)); } @override -int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,email,errorMessage,recoveryFormat,isLoading,recoveryRequested,passwordChanged,password,repeatedPassword,passwordVisible,equalPasswords,newDialCode,newPhoneNumber,const DeepCollectionEquality().hash(securityChecks)); +int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,email,errorMessage,recoveryFormat,isLoading,recoveryRequested,passwordChanged,token,password,repeatedPassword,passwordVisible,equalPasswords,newDialCode,newPhoneNumber,const DeepCollectionEquality().hash(securityChecks)); @override String toString() { - return 'RecoverPasswordViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, email: $email, errorMessage: $errorMessage, recoveryFormat: $recoveryFormat, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, newDialCode: $newDialCode, newPhoneNumber: $newPhoneNumber, securityChecks: $securityChecks)'; + return 'RecoverPasswordViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, email: $email, errorMessage: $errorMessage, recoveryFormat: $recoveryFormat, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, token: $token, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, newDialCode: $newDialCode, newPhoneNumber: $newPhoneNumber, securityChecks: $securityChecks)'; } @@ -45,7 +45,7 @@ abstract mixin class $RecoverPasswordViewStateCopyWith<$Res> { factory $RecoverPasswordViewStateCopyWith(RecoverPasswordViewState value, $Res Function(RecoverPasswordViewState) _then) = _$RecoverPasswordViewStateCopyWithImpl; @useResult $Res call({ - String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks + String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks }); @@ -62,7 +62,7 @@ class _$RecoverPasswordViewStateCopyWithImpl<$Res> /// Create a copy of RecoverPasswordViewState /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? email = null,Object? errorMessage = null,Object? recoveryFormat = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? newDialCode = null,Object? newPhoneNumber = null,Object? securityChecks = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? email = null,Object? errorMessage = null,Object? recoveryFormat = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? token = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? newDialCode = null,Object? newPhoneNumber = null,Object? securityChecks = null,}) { return _then(_self.copyWith( phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable as String,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable @@ -72,7 +72,8 @@ as String,recoveryFormat: null == recoveryFormat ? _self.recoveryFormat : recove as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool,recoveryRequested: null == recoveryRequested ? _self.recoveryRequested : recoveryRequested // ignore: cast_nullable_to_non_nullable as bool,passwordChanged: null == passwordChanged ? _self.passwordChanged : passwordChanged // ignore: cast_nullable_to_non_nullable -as bool,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as bool,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable +as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable as String,repeatedPassword: null == repeatedPassword ? _self.repeatedPassword : repeatedPassword // ignore: cast_nullable_to_non_nullable as String,passwordVisible: null == passwordVisible ? _self.passwordVisible : passwordVisible // ignore: cast_nullable_to_non_nullable as bool,equalPasswords: null == equalPasswords ? _self.equalPasswords : equalPasswords // ignore: cast_nullable_to_non_nullable @@ -164,10 +165,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _RecoverPasswordViewState() when $default != null: -return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: +return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: return orElse(); } @@ -185,10 +186,10 @@ return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage, /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks) $default,) {final _that = this; switch (_that) { case _RecoverPasswordViewState(): -return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: +return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: throw StateError('Unexpected subclass'); } @@ -205,10 +206,10 @@ return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage, /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks)? $default,) {final _that = this; switch (_that) { case _RecoverPasswordViewState() when $default != null: -return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: +return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage,_that.recoveryFormat,_that.isLoading,_that.recoveryRequested,_that.passwordChanged,_that.token,_that.password,_that.repeatedPassword,_that.passwordVisible,_that.equalPasswords,_that.newDialCode,_that.newPhoneNumber,_that.securityChecks);case _: return null; } @@ -220,7 +221,7 @@ return $default(_that.phoneNumber,_that.dialCode,_that.email,_that.errorMessage, class _RecoverPasswordViewState implements RecoverPasswordViewState { - const _RecoverPasswordViewState({this.phoneNumber = '', this.dialCode = '+34', this.email = '', this.errorMessage = '', this.recoveryFormat = '', this.isLoading = false, this.recoveryRequested = false, this.passwordChanged = false, this.password = '', this.repeatedPassword = '', this.passwordVisible = false, this.equalPasswords = true, this.newDialCode = '+34', this.newPhoneNumber = '', final Map securityChecks = const {'min' : false, 'capital' : false, 'number' : false, 'special' : false}}): _securityChecks = securityChecks; + const _RecoverPasswordViewState({this.phoneNumber = '', this.dialCode = '+34', this.email = '', this.errorMessage = '', this.recoveryFormat = '', this.isLoading = false, this.recoveryRequested = false, this.passwordChanged = false, this.token = '', this.password = '', this.repeatedPassword = '', this.passwordVisible = false, this.equalPasswords = true, this.newDialCode = '+34', this.newPhoneNumber = '', final Map securityChecks = const {'min' : false, 'capital' : false, 'number' : false, 'special' : false}}): _securityChecks = securityChecks; @override@JsonKey() final String phoneNumber; @@ -231,6 +232,7 @@ class _RecoverPasswordViewState implements RecoverPasswordViewState { @override@JsonKey() final bool isLoading; @override@JsonKey() final bool recoveryRequested; @override@JsonKey() final bool passwordChanged; +@override@JsonKey() final String token; @override@JsonKey() final String password; @override@JsonKey() final String repeatedPassword; @override@JsonKey() final bool passwordVisible; @@ -255,16 +257,16 @@ _$RecoverPasswordViewStateCopyWith<_RecoverPasswordViewState> get copyWith => __ @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _RecoverPasswordViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.recoveryFormat, recoveryFormat) || other.recoveryFormat == recoveryFormat)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&(identical(other.newDialCode, newDialCode) || other.newDialCode == newDialCode)&&(identical(other.newPhoneNumber, newPhoneNumber) || other.newPhoneNumber == newPhoneNumber)&&const DeepCollectionEquality().equals(other._securityChecks, _securityChecks)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RecoverPasswordViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.email, email) || other.email == email)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.recoveryFormat, recoveryFormat) || other.recoveryFormat == recoveryFormat)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.recoveryRequested, recoveryRequested) || other.recoveryRequested == recoveryRequested)&&(identical(other.passwordChanged, passwordChanged) || other.passwordChanged == passwordChanged)&&(identical(other.token, token) || other.token == token)&&(identical(other.password, password) || other.password == password)&&(identical(other.repeatedPassword, repeatedPassword) || other.repeatedPassword == repeatedPassword)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.equalPasswords, equalPasswords) || other.equalPasswords == equalPasswords)&&(identical(other.newDialCode, newDialCode) || other.newDialCode == newDialCode)&&(identical(other.newPhoneNumber, newPhoneNumber) || other.newPhoneNumber == newPhoneNumber)&&const DeepCollectionEquality().equals(other._securityChecks, _securityChecks)); } @override -int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,email,errorMessage,recoveryFormat,isLoading,recoveryRequested,passwordChanged,password,repeatedPassword,passwordVisible,equalPasswords,newDialCode,newPhoneNumber,const DeepCollectionEquality().hash(_securityChecks)); +int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,email,errorMessage,recoveryFormat,isLoading,recoveryRequested,passwordChanged,token,password,repeatedPassword,passwordVisible,equalPasswords,newDialCode,newPhoneNumber,const DeepCollectionEquality().hash(_securityChecks)); @override String toString() { - return 'RecoverPasswordViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, email: $email, errorMessage: $errorMessage, recoveryFormat: $recoveryFormat, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, newDialCode: $newDialCode, newPhoneNumber: $newPhoneNumber, securityChecks: $securityChecks)'; + return 'RecoverPasswordViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, email: $email, errorMessage: $errorMessage, recoveryFormat: $recoveryFormat, isLoading: $isLoading, recoveryRequested: $recoveryRequested, passwordChanged: $passwordChanged, token: $token, password: $password, repeatedPassword: $repeatedPassword, passwordVisible: $passwordVisible, equalPasswords: $equalPasswords, newDialCode: $newDialCode, newPhoneNumber: $newPhoneNumber, securityChecks: $securityChecks)'; } @@ -275,7 +277,7 @@ abstract mixin class _$RecoverPasswordViewStateCopyWith<$Res> implements $Recove factory _$RecoverPasswordViewStateCopyWith(_RecoverPasswordViewState value, $Res Function(_RecoverPasswordViewState) _then) = __$RecoverPasswordViewStateCopyWithImpl; @override @useResult $Res call({ - String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks + String phoneNumber, String dialCode, String email, String errorMessage, String recoveryFormat, bool isLoading, bool recoveryRequested, bool passwordChanged, String token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map securityChecks }); @@ -292,7 +294,7 @@ class __$RecoverPasswordViewStateCopyWithImpl<$Res> /// Create a copy of RecoverPasswordViewState /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? email = null,Object? errorMessage = null,Object? recoveryFormat = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? newDialCode = null,Object? newPhoneNumber = null,Object? securityChecks = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? email = null,Object? errorMessage = null,Object? recoveryFormat = null,Object? isLoading = null,Object? recoveryRequested = null,Object? passwordChanged = null,Object? token = null,Object? password = null,Object? repeatedPassword = null,Object? passwordVisible = null,Object? equalPasswords = null,Object? newDialCode = null,Object? newPhoneNumber = null,Object? securityChecks = null,}) { return _then(_RecoverPasswordViewState( phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable as String,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable @@ -302,7 +304,8 @@ as String,recoveryFormat: null == recoveryFormat ? _self.recoveryFormat : recove as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool,recoveryRequested: null == recoveryRequested ? _self.recoveryRequested : recoveryRequested // ignore: cast_nullable_to_non_nullable as bool,passwordChanged: null == passwordChanged ? _self.passwordChanged : passwordChanged // ignore: cast_nullable_to_non_nullable -as bool,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as bool,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable +as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable as String,repeatedPassword: null == repeatedPassword ? _self.repeatedPassword : repeatedPassword // ignore: cast_nullable_to_non_nullable as String,passwordVisible: null == passwordVisible ? _self.passwordVisible : passwordVisible // ignore: cast_nullable_to_non_nullable as bool,equalPasswords: null == equalPasswords ? _self.equalPasswords : equalPasswords // ignore: cast_nullable_to_non_nullable diff --git a/packages/sf_localizations/assets/l10n/de.json b/packages/sf_localizations/assets/l10n/de.json index 447bc8b7..f6920fe1 100644 --- a/packages/sf_localizations/assets/l10n/de.json +++ b/packages/sf_localizations/assets/l10n/de.json @@ -20,5 +20,32 @@ "enterCodeHere": "Gib den Code hier ein", "enter": "Weiter", "didNotReceiveIt": "Hast du es nicht erhalten?", - "tryAgain": "Erneut versuchen" + "tryAgain": "Erneut versuchen", + "recoverPasswordTitle": "Passwort wiederherstellen", + "recoverPasswordSubtitle": "Geben Sie Ihre E-Mail-Adresse ein, um Ihnen einen Wiederherstellungslink zu senden", + "send": "Schicken", + "back": "Zurückkehren", + "email": "E-Mail", + "errorMessageContactIsEmpty": "Geben Sie eine E-Mail-Adresse oder Telefonnummer ein", + "emailSent": "E-Mail erfolgreich gesendet", + "smsSent": "SMS erfolgreich gesendet", + "checkEmail1": "Überprüfen Sie Ihre E-Mails und klicken Sie auf den Link, um ein neues Passwort zu erstellen.", + "checkSms1": "Überprüfen Sie Ihr Telefon und befolgen Sie die Anweisungen, um ein neues Passwort zu erstellen", + "checkEmail2": "Wenn Sie die E-Mail nicht innerhalb weniger Minuten erhalten, überprüfen Sie Ihren Spam-Ordner oder klicken Sie auf „E-Mail erneut senden“.", + "checkSms2": "Wenn Sie die SMS nicht innerhalb weniger Minuten erhalten, stellen Sie sicher, dass Sie erreichbar sind, oder klicken Sie auf „SMS erneut senden“.", + "resendEmail": "E-Mail weiterleiten", + "resendSms": "SMS weiterleiten", + "continueKey": "Weitermachen", + "newPassword": "Neues Passwort", + "repeatPassword": "Passwort wiederholen", + "passwordLength": "Mindestens 8 Zeichen", + "passwordCapital": "ein Großbuchstabe", + "passwordNumber": "eine Zahl", + "passwordSpecial": "Ein Sonderzeichen enthalten", + "accept": "Akzeptieren", + "errorMessageUnequalPasswords": "Passwörter stimmen nicht überein. versuchen Sie es erneut", + "errorMessagePasswordTooShort": "Das Passwort muss mindestens 8 Zeichen lang sein", + "errorMessagePasswordNoCapitals": "Das Passwort muss mindestens einen Großbuchstaben enthalten", + "errorMessagePasswordNoNumbers": "Das Passwort muss mindestens eine Zahl enthalten", + "errorMessagePasswordNoSpecialChars": "Das Passwort muss mindestens ein Sonderzeichen enthalten" } \ No newline at end of file diff --git a/packages/sf_localizations/assets/l10n/en.json b/packages/sf_localizations/assets/l10n/en.json index 15d42b73..fd11abd1 100755 --- a/packages/sf_localizations/assets/l10n/en.json +++ b/packages/sf_localizations/assets/l10n/en.json @@ -20,5 +20,32 @@ "enterCodeHere": "Enter the code here", "enter": "Enter", "didNotReceiveIt": "Didn't receive it?", - "tryAgain": "Try again" + "tryAgain": "Try again", + "recoverPasswordTitle": "Recover password", + "recoverPasswordSubtitle": "Insert your email to send you a recovery link", + "send": "Send", + "back": "Back", + "email": "Email", + "errorMessageContactIsEmpty": "Insert an email or phone number", + "emailSent": "Email sent correctly", + "smsSent": "SMS sent correctly", + "checkEmail1": "Check your email and click the link to create a new password.", + "checkSms1": "Check your phone and follow the instructions to create a new password.", + "checkEmail2": "If you don't receive the email in some minutes, check your spam folder or press \"Resend email\".", + "checkSms2": "If you don't receive the SMS in some minutes, make sure you have signal or press \"Resend SMS\"", + "resendEmail": "Resend email", + "resendSms": "Resend SMS", + "continueKey": "Continue", + "newPassword": "New password", + "repeatPassword": "Repeat password", + "passwordLength": "At least 8 characters", + "passwordCapital": "One capital letter", + "passwordNumber": "One number", + "passwordSpecial": "One special character", + "accept": "Accept", + "errorMessageUnequalPasswords": "Passwords don't match. Try again", + "errorMessagePasswordTooShort": "Password must include at least 8 characters", + "errorMessagePasswordNoCapitals": "Password must include at least one capital letter", + "errorMessagePasswordNoNumbers": "Password must include at least one number", + "errorMessagePasswordNoSpecialChars": "Password must include at least one special character" } \ No newline at end of file diff --git a/packages/sf_localizations/assets/l10n/es.json b/packages/sf_localizations/assets/l10n/es.json index f9acdf5a..ccfe576a 100644 --- a/packages/sf_localizations/assets/l10n/es.json +++ b/packages/sf_localizations/assets/l10n/es.json @@ -20,5 +20,32 @@ "enterCodeHere": "Introduce el código aquí", "enter": "enter", "didNotReceiveIt": "¿No lo has recibido?", - "tryAgain": "Volver a intentarlo" + "tryAgain": "Volver a intentarlo", + "recoverPasswordTitle": "Recuperar contraseña", + "recoverPasswordSubtitle": "Introduce tu email para enviarte un enlace de recuperación", + "send": "Enviar", + "back": "Volver", + "email": "Correo electrónico", + "errorMessageContactIsEmpty": "Introduce un correo electrónico o un número de teléfono", + "emailSent": "Correo enviado correctamente", + "smsSent": "SMS enviado correctamente", + "checkEmail1": "Revisa tu email y haz clic en el enlace para crear una nueva contraseña.", + "checkSms1": "Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.", + "checkEmail2": "Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\".", + "checkSms2": "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS\"", + "resendEmail": "Reenviar correo", + "resendSms": "Reenviar SMS", + "continueKey": "Continuar", + "newPassword": "Nueva contraseña", + "repeatPassword": "Repetir contraseña", + "passwordLength": "Al menos 8 caracteres", + "passwordCapital": "Una mayúscula", + "passwordNumber": "Un número", + "passwordSpecial": "Una carácter especial", + "accept": "Aceptar", + "errorMessageUnequalPasswords": "Las contraseñas no coinciden. Inténtalo de nuevo", + "errorMessagePasswordTooShort": "La contraseña debe tener al menos 8 caracteres", + "errorMessagePasswordNoCapitals": "La contraseña debe tener al menos una mayúscula", + "errorMessagePasswordNoNumbers": "La contraseña debe tener al menos un número", + "errorMessagePasswordNoSpecialChars": "La contraseña debe tener al menos un carácter especial" } \ No newline at end of file diff --git a/packages/sf_localizations/assets/l10n/fr.json b/packages/sf_localizations/assets/l10n/fr.json index 557f92e8..b997f6b6 100644 --- a/packages/sf_localizations/assets/l10n/fr.json +++ b/packages/sf_localizations/assets/l10n/fr.json @@ -20,5 +20,32 @@ "enterCodeHere": "Saisissez le code ici", "enter": "Entrer", "didNotReceiveIt": "Tu ne l'as pas reçu ?", - "tryAgain": "Réessayer" + "tryAgain": "Réessayer", + "recoverPasswordTitle": "Récupérer le mot de passe", + "recoverPasswordSubtitle": "Entrez votre email pour vous envoyer un lien de récupération", + "send": "Envoyer", + "back": "Retour", + "email": "E-mail", + "errorMessageContactIsEmpty": "Entrez un e-mail ou un numéro de téléphone", + "emailSent": "Mail envoyé avec succès", + "smsSent": "SMS envoyé avec succès", + "checkEmail1": "Vérifiez votre courrier électronique et cliquez sur le lien pour créer un nouveau mot de passe.", + "checkSms1": "Vérifiez votre téléphone et suivez les instructions pour créer un nouveau mot de passe", + "checkEmail2": "Si vous ne recevez pas l'e-mail au bout de quelques minutes, vérifiez votre dossier spam ou appuyez sur « Renvoyer l'e-mail ».", + "checkSms2": "Si vous ne recevez pas le SMS au bout de quelques minutes, assurez-vous d'être couvert ou appuyez sur \"Renvoyer le SMS\".", + "resendEmail": "Transférer le courrier", + "resendSms": "Transférer des SMS", + "continueKey": "Continuer", + "newPassword": "Nouveau mot de passe", + "repeatPassword": "Répéter le mot de passe", + "passwordLength": "Au moins 8 caractères", + "passwordCapital": "une majuscule", + "passwordNumber": "un numéro", + "passwordSpecial": "Un caractère particulier", + "accept": "Accepter", + "errorMessageUnequalPasswords": "Les mots de passe ne correspondent pas. essayer à nouveau", + "errorMessagePasswordTooShort": "Le mot de passe doit contenir au moins 8 caractères", + "errorMessagePasswordNoCapitals": "Le mot de passe doit contenir au moins une lettre majuscule", + "errorMessagePasswordNoNumbers": "Le mot de passe doit contenir au moins un chiffre", + "errorMessagePasswordNoSpecialChars": "Le mot de passe doit contenir au moins un caractère spécial" } \ No newline at end of file diff --git a/packages/sf_localizations/assets/l10n/it.json b/packages/sf_localizations/assets/l10n/it.json index b55a0679..0384d084 100644 --- a/packages/sf_localizations/assets/l10n/it.json +++ b/packages/sf_localizations/assets/l10n/it.json @@ -20,5 +20,32 @@ "enterCodeHere": "Inserisci il codice qui", "enter": "Entra", "didNotReceiveIt": "Non lo hai ricevuto?", - "tryAgain": "Riprova" + "tryAgain": "Riprova", + "recoverPasswordTitle": "Recupera la password", + "recoverPasswordSubtitle": "Inserisci la tua email per inviarti un collegamento di recupero", + "send": "Inviare", + "back": "Ritorno", + "email": "E-mail", + "errorMessageContactIsEmpty": "Inserisci un'e-mail o un numero di telefono", + "emailSent": "Mail inviata con successo", + "smsSent": "SMS inviato con successo", + "checkEmail1": "Controlla la tua email e fai clic sul collegamento per creare una nuova password.", + "checkSms1": "Controlla il tuo telefono e segui le istruzioni per creare una nuova password", + "checkEmail2": "Se non ricevi l'e-mail entro pochi minuti, controlla la cartella spam o premi \"Invia nuovamente e-mail\".", + "checkSms2": "Se non ricevi l'SMS entro pochi minuti, assicurati di avere copertura oppure premi \"Rinvia SMS\"", + "resendEmail": "Inoltra la posta", + "resendSms": "Inoltra SMS", + "continueKey": "Continuare", + "newPassword": "Nuova password", + "repeatPassword": "Ripeti la password", + "passwordLength": "Almeno 8 caratteri", + "passwordCapital": "una lettera maiuscola", + "passwordNumber": "un numero", + "passwordSpecial": "Un carattere speciale", + "accept": "Accettare", + "errorMessageUnequalPasswords": "Le password non corrispondono. riprova", + "errorMessagePasswordTooShort": "La password deve contenere almeno 8 caratteri", + "errorMessagePasswordNoCapitals": "La password deve contenere almeno una lettera maiuscola", + "errorMessagePasswordNoNumbers": "La password deve contenere almeno un numero", + "errorMessagePasswordNoSpecialChars": "La password deve contenere almeno un carattere speciale" } \ No newline at end of file diff --git a/packages/sf_localizations/assets/l10n/pt.json b/packages/sf_localizations/assets/l10n/pt.json index 2fff2b01..ce523889 100644 --- a/packages/sf_localizations/assets/l10n/pt.json +++ b/packages/sf_localizations/assets/l10n/pt.json @@ -20,5 +20,32 @@ "enterCodeHere": "Insira o código aqui", "enter": "Entrar", "didNotReceiveIt": "Você não recebeu?", - "tryAgain": "Tentar novamente" + "tryAgain": "Tentar novamente", + "recoverPasswordTitle": "Recuperar senha", + "recoverPasswordSubtitle": "Insira seu e-mail para enviar um link de recuperação", + "send": "Enviar", + "back": "Voltar", + "email": "Correio eletrônico", + "errorMessageContactIsEmpty": "Introduzir um correio eletrônico ou um número de telefone", + "emailSent": "Correo enviado corretamente", + "smsSent": "SMS enviado corretamente", + "checkEmail1": "Revise seu e-mail e clique no link para criar uma nova senha.", + "checkSms1": "Revise seu celular e siga as instruções para criar uma nova senha", + "checkEmail2": "Se você não receber a correspondência em alguns minutos, revise sua pasta de spam ou pressione \"Reenviar correspondência\".", + "checkSms2": "Se você não receber o SMS em alguns minutos, certifique-se de ter cobertura ou pressione \"Reenviar SMS\"", + "resendEmail": "Reenviar correio", + "resendSms": "Reenviar SMS", + "continueKey": "Continuar", + "newPassword": "Nova contrasenha", + "repeatPassword": "Repetir contraseña", + "passwordLength": "Pelo menos 8 caracteres", + "passwordCapital": "Una mayúscula", + "passwordNumber": "Um número", + "passwordSpecial": "Um caráter especial", + "accept": "Aceitar", + "errorMessageUnequalPasswords": "Las contraseñas não é coincidência.", + "errorMessagePasswordTooShort": "A senha deve ter pelo menos 8 caracteres", + "errorMessagePasswordNoCapitals": "A senha deve ter pelo menos uma maioscula", + "errorMessagePasswordNoNumbers": "A senha deve ter pelo menos um número", + "errorMessagePasswordNoSpecialChars": "A senha deve ter menos caráter especial" } \ No newline at end of file diff --git a/packages/sf_localizations/lib/sf_localizations.dart b/packages/sf_localizations/lib/sf_localizations.dart index de2c2808..6fc48667 100755 --- a/packages/sf_localizations/lib/sf_localizations.dart +++ b/packages/sf_localizations/lib/sf_localizations.dart @@ -1,6 +1,7 @@ export 'src/sf_delegate.dart'; export 'src/generated/i18n.dart'; +export 'src/generated/i18n.g.dart'; export 'src/utils/constants.dart'; export 'src/utils/context_extension.dart'; export 'src/utils/string_extension.dart'; -export 'src/utils/locale_extension.dart'; +export 'src/utils/locale_extension.dart'; \ No newline at end of file From ea6a9741eed8193e5f3f3caee278020d155a4c58 Mon Sep 17 00:00:00 2001 From: aitorarana Date: Thu, 18 Dec 2025 11:13:58 +0100 Subject: [PATCH 5/6] Updated locale keys --- .../new_password/new_password_screen.dart | 22 +++--- .../request_recovery_screen.dart | 14 ++-- .../presentation/sent/sent_screen.dart | 20 +++--- packages/sf_localizations/assets/l10n/en.json | 2 +- packages/sf_localizations/assets/l10n/es.json | 2 +- packages/sf_localizations/assets/l10n/it.json | 2 +- packages/sf_localizations/assets/l10n/pt.json | 2 +- .../lib/sf_localizations.dart | 1 - .../lib/src/generated/i18n.dart | 71 +++++++++++++------ 9 files changed, 81 insertions(+), 55 deletions(-) diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart index 1cfa07cc..070ac3d3 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart @@ -29,7 +29,7 @@ class NewPasswordScreen extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - context.translate(LocaleKeys.recoverPasswordTitle), + context.translate(I18n.recoverPasswordTitle), textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w500, @@ -40,7 +40,7 @@ class NewPasswordScreen extends ConsumerWidget { SizedBox(height: SizeUtils.getByScreen(small: 42, big: 32)), CustomTextField( showPassword: viewState.passwordVisible, - label: context.translate(LocaleKeys.newPassword), + label: context.translate(I18n.newPassword), labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), hint: '********', controller: viewModel.passwordController, @@ -49,7 +49,7 @@ class NewPasswordScreen extends ConsumerWidget { SizedBox(height: 16), CustomTextField( showPassword: viewState.passwordVisible, - label: context.translate(LocaleKeys.repeatPassword), + label: context.translate(I18n.repeatPassword), labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), hint: '********', controller: viewModel.repeatedPasswordController, @@ -67,7 +67,7 @@ class NewPasswordScreen extends ConsumerWidget { size: 16, ), Text( - context.translate(LocaleKeys.errorMessageUnequalPasswords), + context.translate(I18n.errorMessageUnequalPasswords), textAlign: TextAlign.left, style: TextStyle( color: Color.fromRGBO(239, 17, 17, 1), @@ -89,7 +89,7 @@ class NewPasswordScreen extends ConsumerWidget { : ThemeCode.buttonSecondary), ), Text( - context.translate(LocaleKeys.passwordLength), + context.translate(I18n.passwordLength), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -105,7 +105,7 @@ class NewPasswordScreen extends ConsumerWidget { : ThemeCode.buttonSecondary), ), Text( - context.translate(LocaleKeys.passwordCapital), + context.translate(I18n.passwordCapital), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -121,7 +121,7 @@ class NewPasswordScreen extends ConsumerWidget { : ThemeCode.buttonSecondary), ), Text( - context.translate(LocaleKeys.passwordNumber), + context.translate(I18n.passwordNumber), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -137,7 +137,7 @@ class NewPasswordScreen extends ConsumerWidget { : ThemeCode.buttonSecondary), ), Text( - context.translate(LocaleKeys.passwordSpecial), + context.translate(I18n.passwordSpecial), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12)) ), ], @@ -146,7 +146,7 @@ class NewPasswordScreen extends ConsumerWidget { Align( alignment: Alignment.bottomLeft, child: Text( - context.translate(LocaleKeys.mobilePhone), + context.translate(I18n.mobilePhone), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0), ) ), @@ -164,7 +164,7 @@ class NewPasswordScreen extends ConsumerWidget { }, ), Expanded(child: CustomTextField( - hint: context.translate(LocaleKeys.phoneNumber), + hint: context.translate(I18n.phoneNumber), numeric: true, controller: viewModel.newPhoneNumberController, )) @@ -190,7 +190,7 @@ class NewPasswordScreen extends ConsumerWidget { navigationContract.goTo(AppRoutes.dashboardHome); } }, - text: context.translate(LocaleKeys.accept), + text: context.translate(I18n.accept), color: theme.getColorFor(ThemeCode.buttonPrimary) ), ], diff --git a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart index 662ada93..11d56d6b 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/request_recovery/request_recovery_screen.dart @@ -29,26 +29,26 @@ class RequestRecoveryScreen extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - context.translate(LocaleKeys.recoverPasswordTitle), + context.translate(I18n.recoverPasswordTitle), style: TextStyle(fontWeight: FontWeight.bold, fontSize: SizeUtils.getByScreen(small: 29, big: 29, xl: 26)), ), SizedBox(height: SizeUtils.getByScreen(small: 24, big: 32)), Text( - context.translate(LocaleKeys.recoverPasswordSubtitle), + context.translate(I18n.recoverPasswordSubtitle), textAlign: TextAlign.center, style: TextStyle(letterSpacing: 0, fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 16)), ), SizedBox(height: SizeUtils.getByScreen(small: 56, big: 48)), CustomTextField( - label: context.translate(LocaleKeys.email), - hint: context.translate(LocaleKeys.email), + label: context.translate(I18n.email), + hint: context.translate(I18n.email), controller: viewModel.emailController, ), SizedBox(height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28)), Align( alignment: Alignment.bottomLeft, child: Text( - context.translate(LocaleKeys.mobilePhone), + context.translate(I18n.mobilePhone), style: TextStyle(fontSize: 14, letterSpacing: 0), ), ), @@ -92,7 +92,7 @@ class RequestRecoveryScreen extends ConsumerWidget { Expanded( child: SecondaryButton( onPressed: () => {Navigator.pop(context)}, - text: context.translate(LocaleKeys.back), + text: context.translate(I18n.back), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), @@ -111,7 +111,7 @@ class RequestRecoveryScreen extends ConsumerWidget { ); } }, - text: context.translate(LocaleKeys.send), + text: context.translate(I18n.send), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), color: theme.getColorFor(ThemeCode.buttonSecondary), ), diff --git a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart index 182021ff..ddec9f64 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/sent/sent_screen.dart @@ -29,7 +29,7 @@ class SentScreen extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - context.translate(LocaleKeys.recoverPasswordTitle), + context.translate(I18n.recoverPasswordTitle), textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w500, @@ -48,8 +48,8 @@ class SentScreen extends ConsumerWidget { SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)), Text( viewState.recoveryFormat == "email" - ? context.translate(LocaleKeys.emailSent) - : context.translate(LocaleKeys.smsSent), + ? context.translate(I18n.emailSent) + : context.translate(I18n.smsSent), style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), fontWeight: FontWeight.bold), ), ], @@ -57,16 +57,16 @@ class SentScreen extends ConsumerWidget { SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)), Text( viewState.recoveryFormat == "email" - ? context.translate(LocaleKeys.checkEmail1) - : context.translate(LocaleKeys.checkSms1), + ? context.translate(I18n.checkEmail1) + : context.translate(I18n.checkSms1), textAlign: TextAlign.center, style: TextStyle(fontSize: SizeUtils.getByScreen(small: 17, big: 17, xl: 15), letterSpacing: 0), ), SizedBox(height: 16), Text( viewState.recoveryFormat == "email" - ? context.translate(LocaleKeys.checkEmail2) - : context.translate(LocaleKeys.checkSms2), + ? context.translate(I18n.checkEmail2) + : context.translate(I18n.checkSms2), textAlign: TextAlign.center, style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0), ), @@ -83,8 +83,8 @@ class SentScreen extends ConsumerWidget { } }, text: viewState.recoveryFormat == "email" - ? context.translate(LocaleKeys.resendEmail) - : context.translate(LocaleKeys.resendSms), + ? context.translate(I18n.resendEmail) + : context.translate(I18n.resendSms), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), ), @@ -95,7 +95,7 @@ class SentScreen extends ConsumerWidget { context, MaterialPageRoute(builder: (_) => NewPasswordScreen(navigationContract: navigationContract)), ), - text: context.translate(LocaleKeys.continueKey), + text: context.translate(I18n.continueKey), color: theme.getColorFor(ThemeCode.buttonSecondary), size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14), ), diff --git a/packages/sf_localizations/assets/l10n/en.json b/packages/sf_localizations/assets/l10n/en.json index fd11abd1..4adf55d7 100755 --- a/packages/sf_localizations/assets/l10n/en.json +++ b/packages/sf_localizations/assets/l10n/en.json @@ -32,7 +32,7 @@ "checkEmail1": "Check your email and click the link to create a new password.", "checkSms1": "Check your phone and follow the instructions to create a new password.", "checkEmail2": "If you don't receive the email in some minutes, check your spam folder or press \"Resend email\".", - "checkSms2": "If you don't receive the SMS in some minutes, make sure you have signal or press \"Resend SMS\"", + "checkSms2": "If you don't receive the SMS in some minutes, make sure you have signal or press \"Resend SMS\".", "resendEmail": "Resend email", "resendSms": "Resend SMS", "continueKey": "Continue", diff --git a/packages/sf_localizations/assets/l10n/es.json b/packages/sf_localizations/assets/l10n/es.json index ccfe576a..83ec610c 100644 --- a/packages/sf_localizations/assets/l10n/es.json +++ b/packages/sf_localizations/assets/l10n/es.json @@ -32,7 +32,7 @@ "checkEmail1": "Revisa tu email y haz clic en el enlace para crear una nueva contraseña.", "checkSms1": "Revisa tu móvil y sigue las instrucciones para crear una nueva contraseña.", "checkEmail2": "Si no recibes el correo en unos minutos, revisa tu carpeta de spam o pulsa \"Reenviar correo\".", - "checkSms2": "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS\"", + "checkSms2": "Si no recibes el SMS en unos minutos, asegúrate de tener cobertura o pulsa \"Reenviar SMS\".", "resendEmail": "Reenviar correo", "resendSms": "Reenviar SMS", "continueKey": "Continuar", diff --git a/packages/sf_localizations/assets/l10n/it.json b/packages/sf_localizations/assets/l10n/it.json index 0384d084..648a9c0e 100644 --- a/packages/sf_localizations/assets/l10n/it.json +++ b/packages/sf_localizations/assets/l10n/it.json @@ -32,7 +32,7 @@ "checkEmail1": "Controlla la tua email e fai clic sul collegamento per creare una nuova password.", "checkSms1": "Controlla il tuo telefono e segui le istruzioni per creare una nuova password", "checkEmail2": "Se non ricevi l'e-mail entro pochi minuti, controlla la cartella spam o premi \"Invia nuovamente e-mail\".", - "checkSms2": "Se non ricevi l'SMS entro pochi minuti, assicurati di avere copertura oppure premi \"Rinvia SMS\"", + "checkSms2": "Se non ricevi l'SMS entro pochi minuti, assicurati di avere copertura oppure premi \"Rinvia SMS\".", "resendEmail": "Inoltra la posta", "resendSms": "Inoltra SMS", "continueKey": "Continuare", diff --git a/packages/sf_localizations/assets/l10n/pt.json b/packages/sf_localizations/assets/l10n/pt.json index ce523889..6f27616a 100644 --- a/packages/sf_localizations/assets/l10n/pt.json +++ b/packages/sf_localizations/assets/l10n/pt.json @@ -32,7 +32,7 @@ "checkEmail1": "Revise seu e-mail e clique no link para criar uma nova senha.", "checkSms1": "Revise seu celular e siga as instruções para criar uma nova senha", "checkEmail2": "Se você não receber a correspondência em alguns minutos, revise sua pasta de spam ou pressione \"Reenviar correspondência\".", - "checkSms2": "Se você não receber o SMS em alguns minutos, certifique-se de ter cobertura ou pressione \"Reenviar SMS\"", + "checkSms2": "Se você não receber o SMS em alguns minutos, certifique-se de ter cobertura ou pressione \"Reenviar SMS\".", "resendEmail": "Reenviar correio", "resendSms": "Reenviar SMS", "continueKey": "Continuar", diff --git a/packages/sf_localizations/lib/sf_localizations.dart b/packages/sf_localizations/lib/sf_localizations.dart index 6fc48667..3a2bc410 100755 --- a/packages/sf_localizations/lib/sf_localizations.dart +++ b/packages/sf_localizations/lib/sf_localizations.dart @@ -1,6 +1,5 @@ export 'src/sf_delegate.dart'; export 'src/generated/i18n.dart'; -export 'src/generated/i18n.g.dart'; export 'src/utils/constants.dart'; export 'src/utils/context_extension.dart'; export 'src/utils/string_extension.dart'; diff --git a/packages/sf_localizations/lib/src/generated/i18n.dart b/packages/sf_localizations/lib/src/generated/i18n.dart index 84ec6a23..6ccf4c1f 100755 --- a/packages/sf_localizations/lib/src/generated/i18n.dart +++ b/packages/sf_localizations/lib/src/generated/i18n.dart @@ -3,26 +3,53 @@ class I18n { const I18n._(); - static const String example = 'example'; - static const String start = 'start'; - static const String next = 'next'; - static const String skip = 'skip'; - static const String onboardingTitle1 = 'onboardingTitle1'; - static const String onboardingSubtitle1 = 'onboardingSubtitle1'; - static const String onboardingTitle2 = 'onboardingTitle2'; - static const String onboardingSubtitle2 = 'onboardingSubtitle2'; - static const String onboardingTitle3 = 'onboardingTitle3'; - static const String onboardingSubtitle3 = 'onboardingSubtitle3'; - static const String linkPhoneTitle = 'linkPhoneTitle'; - static const String linkPhoneSubtitle = 'linkPhoneSubtitle'; - static const String mobilePhone = 'mobilePhone'; - static const String phoneNumber = 'phoneNumber'; - static const String selectYourCountry = 'selectYourCountry'; - static const String errorMessagePhoneIsEmpty = 'errorMessagePhoneIsEmpty'; - static const String connect = "connect"; - static const String verificationCodeSentTo = "verificationCodeSentTo"; - static const String enterCodeHere = "enterCodeHere"; - static const String enter = "enter"; - static const String didNotReceiveIt = "didNotReceiveIt"; - static const String tryAgain = "tryAgain"; + static const example = 'example'; + static const onboardingTitle1 = 'onboardingTitle1'; + static const onboardingSubtitle1 = 'onboardingSubtitle1'; + static const onboardingTitle2 = 'onboardingTitle2'; + static const onboardingSubtitle2 = 'onboardingSubtitle2'; + static const onboardingTitle3 = 'onboardingTitle3'; + static const onboardingSubtitle3 = 'onboardingSubtitle3'; + static const start = 'start'; + static const next = 'next'; + static const skip = 'skip'; + static const linkPhoneTitle = 'linkPhoneTitle'; + static const linkPhoneSubtitle = 'linkPhoneSubtitle'; + static const mobilePhone = 'mobilePhone'; + static const phoneNumber = 'phoneNumber'; + static const selectYourCountry = 'selectYourCountry'; + static const errorMessagePhoneIsEmpty = 'errorMessagePhoneIsEmpty'; + static const connect = 'connect'; + static const verificationCodeSentTo = 'verificationCodeSentTo'; + static const enterCodeHere = 'enterCodeHere'; + static const enter = 'enter'; + static const didNotReceiveIt = 'didNotReceiveIt'; + static const tryAgain = 'tryAgain'; + static const recoverPasswordTitle = 'recoverPasswordTitle'; + static const recoverPasswordSubtitle = 'recoverPasswordSubtitle'; + static const send = 'send'; + static const back = 'back'; + static const email = 'email'; + static const errorMessageContactIsEmpty = 'errorMessageContactIsEmpty'; + static const emailSent = 'emailSent'; + static const smsSent = 'smsSent'; + static const checkEmail1 = 'checkEmail1'; + static const checkSms1 = 'checkSms1'; + static const checkEmail2 = 'checkEmail2'; + static const checkSms2 = 'checkSms2'; + static const resendEmail = 'resendEmail'; + static const resendSms = 'resendSms'; + static const continueKey = 'continueKey'; + static const newPassword = 'newPassword'; + static const repeatPassword = 'repeatPassword'; + static const passwordLength = 'passwordLength'; + static const passwordCapital = 'passwordCapital'; + static const passwordNumber = 'passwordNumber'; + static const passwordSpecial = 'passwordSpecial'; + static const accept = 'accept'; + static const errorMessageUnequalPasswords = 'errorMessageUnequalPasswords'; + static const errorMessagePasswordTooShort = 'errorMessagePasswordTooShort'; + static const errorMessagePasswordNoCapitals = 'errorMessagePasswordNoCapitals'; + static const errorMessagePasswordNoNumbers = 'errorMessagePasswordNoNumbers'; + static const errorMessagePasswordNoSpecialChars = 'errorMessagePasswordNoSpecialChars'; } From 6a9d68e9452ae3ea7f24d6703c7c7074900beab4 Mon Sep 17 00:00:00 2001 From: aitorarana Date: Thu, 18 Dec 2025 16:46:42 +0100 Subject: [PATCH 6/6] clean warnings --- .../data/datasource/auth_remote_datasource_impl.dart | 12 ++++++------ .../new_password/new_password_screen.dart | 2 +- .../state/recover_password_view_model.dart | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart index 6cffc665..331a1dd1 100644 --- a/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart +++ b/modules/auth/lib/src/core/data/datasource/auth_remote_datasource_impl.dart @@ -64,21 +64,21 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource { throw FormatException("No phone or email address given"); } - late final Map body; + // late final Map body; if (email != null) { - body = {'email': email}; + // body = {'email': email}; return 'ec14b7e7-58dd-4a59-9f41-0da86eaabf14'; } else { - body = {'phone': phone!}; + // body = {'phone': phone!}; return 'ec14b7e7-58dd-4a59-9f41-0da86eaabf14'; - throw Exception("reset by phone is not currently implemented"); + // throw Exception("reset by phone is not currently implemented"); } - final response = await _repository.put>( + /*final response = await _repository.put>( '/auth/reset-password', body: body, ); final token = response.data!['token']; - return token; + return token;*/ } on DioException catch (error) { throw _mapDioError(error, defaultMessage: 'Error to request password reset'); } diff --git a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart index 070ac3d3..ca9ffc35 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/new_password/new_password_screen.dart @@ -10,7 +10,7 @@ import 'package:utils/utils.dart'; class NewPasswordScreen extends ConsumerWidget { final NavigationContract navigationContract; - const NewPasswordScreen({required this.navigationContract}); + const NewPasswordScreen({super.key, required this.navigationContract}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart index ad93dd8d..2fd912c7 100644 --- a/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart +++ b/modules/auth/lib/src/features/recover_password/presentation/state/recover_password_view_model.dart @@ -201,7 +201,7 @@ class RecoverPasswordViewModel extends Notifier { } Future recoverPassword() async { - final String fullPhone = state.newDialCode + state.newPhoneNumber; + //final String fullPhone = state.newDialCode + state.newPhoneNumber; final String password = state.password; if (!state.equalPasswords) {