Merge pull request 'added recoverPassword endpoints, providers and states' (#10) from auth-recover-password into develop
Reviewed-on: #10
This commit was merged in pull request #10.
This commit is contained in:
@@ -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<void> 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(
|
||||
|
||||
@@ -46,7 +46,7 @@ void configureAppRouter() {
|
||||
GoRoute(
|
||||
path: AppRoutes.recoverPassword,
|
||||
name: 'recover_password',
|
||||
pageBuilder: RecoverPasswordBuilder().buildPage,
|
||||
pageBuilder: RequestRecoveryBuilder().buildPage,
|
||||
),
|
||||
GoRoute(
|
||||
path: AppRoutes.deviceSignup,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -2,4 +2,8 @@ abstract class AuthRemoteDatasource {
|
||||
Future<void> requestPhoneCode({required String phone});
|
||||
|
||||
Future<void> verifyPhoneCode({required String phone, required String code});
|
||||
|
||||
Future<String> requestPasswordReset({String? phone, String? email});
|
||||
|
||||
Future<void> recoverPassword({required newPassword, required token});
|
||||
}
|
||||
|
||||
@@ -53,4 +53,46 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
|
||||
|
||||
return Exception(message);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> requestPasswordReset({
|
||||
String? phone,
|
||||
String? email
|
||||
}) async {
|
||||
try {
|
||||
if (phone == null && email == null) {
|
||||
throw FormatException("No phone or email address given");
|
||||
}
|
||||
|
||||
// late final Map<String, dynamic> 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<Map<String, dynamic>>(
|
||||
'/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<void> recoverPassword({required newPassword, required token}) async {
|
||||
try {
|
||||
await _repository.put<void>(
|
||||
'/auth/recovery-password',
|
||||
body: <String, dynamic>{'newPassword': newPassword, 'token': token},
|
||||
);
|
||||
} on DioException catch (error) {
|
||||
throw _mapDioError(error, defaultMessage: 'Error to request password recovery');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,14 @@ class AuthRepositoryImpl implements AuthRepository {
|
||||
Future<void> verifyPhoneCode({required String phone, required String code}) {
|
||||
return _remote.verifyPhoneCode(phone: phone, code: code);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> requestPasswordReset({String? phone, String? email}) {
|
||||
return _remote.requestPasswordReset(phone: phone, email: email);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> recoverPassword({required String newPassword, required String token}) {
|
||||
return _remote.recoverPassword(newPassword: newPassword, token: token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,8 @@ abstract class AuthRepository {
|
||||
Future<void> requestPhoneCode({required String phone});
|
||||
|
||||
Future<void> verifyPhoneCode({required String phone, required String code});
|
||||
|
||||
Future<String> requestPasswordReset({String phone, String email});
|
||||
|
||||
Future<void> recoverPassword({required String newPassword, required String token});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
abstract class RecoverPasswordUseCase {
|
||||
Future<String> requestEmail({required String email});
|
||||
|
||||
Future<String> requestSms({required String phone});
|
||||
|
||||
Future<void> recoverPassword({required String newPassword, required String token});
|
||||
}
|
||||
@@ -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<String> requestEmail({required String email}) async {
|
||||
return await _repository.requestPasswordReset(email: email);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> requestSms({required String phone}) async {
|
||||
return await _repository.requestPasswordReset(phone: phone);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> recoverPassword({required String newPassword, required String token}) async {
|
||||
await _repository.recoverPassword(newPassword: newPassword, token: token);
|
||||
}
|
||||
}
|
||||
@@ -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<void> buildPage(BuildContext context, GoRouterState state) {
|
||||
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
||||
|
||||
return MaterialPage<void>(
|
||||
key: state.pageKey,
|
||||
child: NewPasswordScreen(navigationContract: navigationContract),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
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';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class NewPasswordScreen extends ConsumerWidget {
|
||||
final NavigationContract navigationContract;
|
||||
|
||||
const NewPasswordScreen({super.key, required this.navigationContract});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
||||
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: [
|
||||
Text(
|
||||
context.translate(I18n.recoverPasswordTitle),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: SizeUtils.getByScreen(small: 30, big: 30, xl: 26),
|
||||
letterSpacing: 0
|
||||
),
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 42, big: 32)),
|
||||
CustomTextField(
|
||||
showPassword: viewState.passwordVisible,
|
||||
label: context.translate(I18n.newPassword),
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12),
|
||||
hint: '********',
|
||||
controller: viewModel.passwordController,
|
||||
onVisibilityChanged: viewModel.togglePasswordVisible,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
CustomTextField(
|
||||
showPassword: viewState.passwordVisible,
|
||||
label: context.translate(I18n.repeatPassword),
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 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),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.info_outline_rounded,
|
||||
color: Color.fromRGBO(239, 17, 17, 1),
|
||||
size: 16,
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.errorMessageUnequalPasswords),
|
||||
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),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.passwordLength),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12))
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 2, big: 4)),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: theme.getColorFor(viewState.securityChecks['capital']!
|
||||
? ThemeCode.buttonPrimary
|
||||
: ThemeCode.buttonSecondary),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.passwordCapital),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12))
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 2, big: 4)),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: theme.getColorFor(viewState.securityChecks['number']!
|
||||
? ThemeCode.buttonPrimary
|
||||
: ThemeCode.buttonSecondary),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.passwordNumber),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12))
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 2, big: 4)),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: theme.getColorFor(viewState.securityChecks['special']!
|
||||
? ThemeCode.buttonPrimary
|
||||
: ThemeCode.buttonSecondary),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.passwordSpecial),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12))
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 32, big: 32, xl: 24)),
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
context.translate(I18n.mobilePhone),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 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: context.translate(I18n.phoneNumber),
|
||||
numeric: true,
|
||||
controller: viewModel.newPhoneNumberController,
|
||||
))
|
||||
]
|
||||
),
|
||||
if (viewState.errorMessage.isNotEmpty) ...[
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
context.translate(viewState.errorMessage),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color.fromRGBO(239, 17, 17, 1),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
SizedBox(height: 56),
|
||||
PrimaryButton(
|
||||
onPressed: () async {
|
||||
await viewModel.recoverPassword();
|
||||
final updatedState = ref.read(recoverPasswordViewModelProvider);
|
||||
if (updatedState.passwordChanged) {
|
||||
navigationContract.goTo(AppRoutes.dashboardHome);
|
||||
}
|
||||
},
|
||||
text: context.translate(I18n.accept),
|
||||
color: theme.getColorFor(ThemeCode.buttonPrimary)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -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<NewPasswordScreen> createState() => NewPasswordScreenState();
|
||||
}
|
||||
|
||||
class NewPasswordScreenState extends ConsumerState<NewPasswordScreen> {
|
||||
bool passwordVisible = false;
|
||||
bool equalPasswords = false;
|
||||
String password = '';
|
||||
|
||||
Map<String, bool> 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<NavigationContract>();
|
||||
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<String, bool> 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),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<RecoverPasswordUseCase>((ref) {
|
||||
final authRepository = ref.read(authRepositoryProvider);
|
||||
return RecoverPasswordUseCaseImpl(authRepository);
|
||||
});
|
||||
@@ -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<void> buildPage(BuildContext context, GoRouterState state) {
|
||||
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
||||
|
||||
return MaterialPage<void>(
|
||||
key: state.pageKey,
|
||||
child: RequestRecoveryScreen(navigationContract: navigationContract),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
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 'package:utils/utils.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(SizeUtils.getByScreen(small: 30, big: 30, xl: 20)),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
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(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(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(I18n.mobilePhone),
|
||||
style: TextStyle(fontSize: 14, letterSpacing: 0),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
CountryPrefixPicker(
|
||||
headerText: context.translate(I18n.selectYourCountry),
|
||||
initialCountryCode: viewState.dialCode,
|
||||
onChanged: (country) {
|
||||
viewModel.updateDialCode(
|
||||
country.dialCode ?? viewState.dialCode,
|
||||
);
|
||||
},
|
||||
width: 80,
|
||||
),
|
||||
SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)),
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
hint: context.translate(I18n.phoneNumber),
|
||||
numeric: true,
|
||||
controller: viewModel.phoneNumberController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 40, big: 40, xl: 28)),
|
||||
if (viewState.errorMessage.isNotEmpty) ...[
|
||||
Text(
|
||||
context.translate(viewState.errorMessage),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color.fromRGBO(239, 17, 17, 1),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 40),
|
||||
],
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
onPressed: () => {Navigator.pop(context)},
|
||||
text: context.translate(I18n.back),
|
||||
size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14),
|
||||
),
|
||||
),
|
||||
SizedBox(width: SizeUtils.getByScreen(small: 20, big: 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: context.translate(I18n.send),
|
||||
size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14),
|
||||
color: theme.getColorFor(ThemeCode.buttonSecondary),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<void> buildPage(BuildContext context, GoRouterState state) {
|
||||
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
||||
|
||||
return MaterialPage<void>(
|
||||
key: state.pageKey,
|
||||
child: SentScreen(navigationContract: navigationContract),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
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 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:utils/utils.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(
|
||||
context.translate(I18n.recoverPasswordTitle),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: SizeUtils.getByScreen(small: 30, big: 30, xl: 26),
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
),
|
||||
SizedBox(width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6)),
|
||||
Text(
|
||||
viewState.recoveryFormat == "email"
|
||||
? context.translate(I18n.emailSent)
|
||||
: context.translate(I18n.smsSent),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)),
|
||||
Text(
|
||||
viewState.recoveryFormat == "email"
|
||||
? 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(I18n.checkEmail2)
|
||||
: context.translate(I18n.checkSms2),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0),
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
onPressed: () {
|
||||
if ( viewState.recoveryFormat == "email") {
|
||||
viewModel.requestEmail();
|
||||
} else {
|
||||
viewModel.requestSms();
|
||||
}
|
||||
},
|
||||
text: viewState.recoveryFormat == "email"
|
||||
? context.translate(I18n.resendEmail)
|
||||
: context.translate(I18n.resendSms),
|
||||
size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => NewPasswordScreen(navigationContract: navigationContract)),
|
||||
),
|
||||
text: context.translate(I18n.continueKey),
|
||||
color: theme.getColorFor(ThemeCode.buttonSecondary),
|
||||
size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
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, RecoverPasswordViewState>(
|
||||
RecoverPasswordViewModel.new,
|
||||
);
|
||||
|
||||
class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
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<String, bool> security = {
|
||||
'min': minCheck,
|
||||
'capital': capitalCheck,
|
||||
'number': numberCheck,
|
||||
'special': specialCheck,
|
||||
};
|
||||
|
||||
state = state.copyWith(
|
||||
password: raw,
|
||||
errorMessage: '',
|
||||
equalPasswords: equalPasswords,
|
||||
securityChecks: security,
|
||||
);
|
||||
}
|
||||
|
||||
void _onRepeatedPasswordChanged() {
|
||||
final String raw = repeatedPasswordController.text;
|
||||
final bool equalPasswords = raw == passwordController.text;
|
||||
state = state.copyWith(
|
||||
repeatedPassword: raw,
|
||||
errorMessage: '',
|
||||
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<void> 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<void> 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,
|
||||
token: token,
|
||||
recoveryFormat: 'email',
|
||||
);
|
||||
} catch (e) {
|
||||
if (!ref.mounted) return;
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.toString(),
|
||||
recoveryRequested: false,
|
||||
passwordChanged: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> requestSms() async {
|
||||
final trimmedNumber = state.phoneNumber.trim();
|
||||
|
||||
final fullPhone = '${state.dialCode}$trimmedNumber';
|
||||
|
||||
try {
|
||||
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) {
|
||||
if (!ref.mounted) return;
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.toString(),
|
||||
recoveryRequested: false,
|
||||
passwordChanged: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> 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.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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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 token,
|
||||
@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<String, bool> securityChecks,
|
||||
}) = _RecoverPasswordViewState;
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
// 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>(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 token; String get password; String get repeatedPassword; bool get passwordVisible; bool get equalPasswords; String get newDialCode; String get newPhoneNumber; Map<String, bool> 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<RecoverPasswordViewState> get copyWith => _$RecoverPasswordViewStateCopyWithImpl<RecoverPasswordViewState>(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.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,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, token: $token, 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 token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map<String, bool> 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? 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
|
||||
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,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
|
||||
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<String, bool>,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// 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 extends Object?>(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 extends Object?>(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 extends Object?>(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 extends Object?>(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<String, bool> 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.token,_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 extends Object?>(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<String, bool> 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.token,_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 extends Object?>(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<String, bool> 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.token,_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.token = '', this.password = '', this.repeatedPassword = '', this.passwordVisible = false, this.equalPasswords = true, this.newDialCode = '+34', this.newPhoneNumber = '', final Map<String, bool> 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 token;
|
||||
@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<String, bool> _securityChecks;
|
||||
@override@JsonKey() Map<String, bool> 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.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,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, token: $token, 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 token, String password, String repeatedPassword, bool passwordVisible, bool equalPasswords, String newDialCode, String newPhoneNumber, Map<String, bool> 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? 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
|
||||
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,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
|
||||
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<String, bool>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -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<void>(
|
||||
key: state.pageKey,
|
||||
child: RestorePasswordScreen(navigationContract: navigationContract),
|
||||
child: RequestRecoveryScreen(navigationContract: navigationContract),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<String>? 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<CustomTextField> createState() => CustomTextFieldState();
|
||||
}
|
||||
|
||||
class CustomTextFieldState extends State<CustomTextField> {
|
||||
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
|
||||
? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly]
|
||||
: const <TextInputFormatter>[],
|
||||
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,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -3,4 +3,4 @@ export 'src/generated/i18n.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';
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user