Compare commits
1 Commits
recover_pa
...
auth-recov
| Author | SHA1 | Date | |
|---|---|---|---|
| 4be6a30a33 |
@@ -15,7 +15,7 @@ late final GoRouter appRouter;
|
||||
void configureAppRouter() {
|
||||
appRouter = GoRouter(
|
||||
navigatorKey: rootNavigatorKey,
|
||||
initialLocation: AppRoutes.login,
|
||||
initialLocation: AppRoutes.onboarding,
|
||||
debugLogDiagnostics: true,
|
||||
routes: [
|
||||
GoRoute(
|
||||
|
||||
@@ -832,7 +832,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
utils:
|
||||
dependency: "direct main"
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
path: "../../packages/utils"
|
||||
relative: true
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export 'src/features/device_sign_up/presentation/link_watch/create_profile_screen.dart';
|
||||
export 'src/features/device_sign_up/link_watch/create_profile_screen.dart';
|
||||
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';
|
||||
|
||||
@@ -16,21 +16,7 @@ abstract class AuthRemoteDatasource {
|
||||
required String token,
|
||||
required String code,
|
||||
});
|
||||
Future<String> requestPasswordReset({required String email});
|
||||
Future<String> requestPasswordReset({String? phone, String? email});
|
||||
|
||||
Future<void> recoverPassword({required newPassword, required token});
|
||||
|
||||
Future<String> createChildProfile({
|
||||
required String id,
|
||||
required String parentId,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required int bornAt,
|
||||
required String gender,
|
||||
required String relationType,
|
||||
required String address,
|
||||
required String cardPublicKey,
|
||||
required String deviceActivationCode,
|
||||
required String scaProof,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -169,26 +169,32 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> requestPasswordReset({required String email}) async {
|
||||
Future<String> requestPasswordReset({
|
||||
String? phone,
|
||||
String? email
|
||||
}) async {
|
||||
try {
|
||||
late final Map<String, dynamic> body;
|
||||
body = {'email': email};
|
||||
if (phone == null && email == null) {
|
||||
throw FormatException("No phone or email address given");
|
||||
}
|
||||
|
||||
final response = await _repository.put<String>(
|
||||
// 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 data = response.data;
|
||||
if (data == null || data.isEmpty) {
|
||||
throw Exception('Empty response from /auth/totp/code');
|
||||
}
|
||||
|
||||
return data;
|
||||
final token = response.data!['token'];
|
||||
return token;*/
|
||||
} on DioException catch (error) {
|
||||
throw _mapDioError(
|
||||
error,
|
||||
defaultMessage: 'Error to request password reset',
|
||||
);
|
||||
throw _mapDioError(error, defaultMessage: 'Error to request password reset');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,52 +206,7 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
|
||||
body: <String, dynamic>{'newPassword': newPassword, 'token': token},
|
||||
);
|
||||
} on DioException catch (error) {
|
||||
throw _mapDioError(
|
||||
error,
|
||||
defaultMessage: 'Error to request password recovery',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> createChildProfile({
|
||||
required String id,
|
||||
required String parentId,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required int bornAt,
|
||||
required String gender,
|
||||
required String relationType,
|
||||
required String address,
|
||||
required String cardPublicKey,
|
||||
required String deviceActivationCode,
|
||||
required String scaProof,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _repository.post<Map<String, dynamic>>(
|
||||
'/auth/child-profiles',
|
||||
body: <String, dynamic>{
|
||||
'id': id,
|
||||
'parentId': parentId,
|
||||
'firstName': firstName,
|
||||
'lastName': lastName,
|
||||
'bornAt': bornAt,
|
||||
'gender': gender,
|
||||
'relationType': relationType,
|
||||
'address': address,
|
||||
'cardPublicKey': cardPublicKey,
|
||||
'deviceActivationCode': deviceActivationCode,
|
||||
'scaProof': scaProof,
|
||||
},
|
||||
);
|
||||
final data = response.data;
|
||||
if (data == null || data.isEmpty) {
|
||||
throw Exception('Empty response from /auth/child-profiles');
|
||||
} else {
|
||||
return data['id'];
|
||||
}
|
||||
} on DioException catch (error) {
|
||||
throw _mapDioError(error, defaultMessage: 'Error in createChildProfile');
|
||||
throw _mapDioError(error, defaultMessage: 'Error to request password recovery');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ class AuthRepositoryImpl implements AuthRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> requestPasswordReset({required String email}) {
|
||||
return _remote.requestPasswordReset(email: email);
|
||||
Future<String> requestPasswordReset({String? phone, String? email}) {
|
||||
return _remote.requestPasswordReset(phone: phone, email: email);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -58,33 +58,4 @@ class AuthRepositoryImpl implements AuthRepository {
|
||||
}) {
|
||||
return _remote.recoverPassword(newPassword: newPassword, token: token);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> createChildProfile({
|
||||
required String id,
|
||||
required String parentId,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required int bornAt,
|
||||
required String gender,
|
||||
required String relationType,
|
||||
required String address,
|
||||
required String cardPublicKey,
|
||||
required String deviceActivationCode,
|
||||
required String scaProof,
|
||||
}) {
|
||||
return _remote.createChildProfile(
|
||||
id: id,
|
||||
parentId: parentId,
|
||||
firstName: firstName,
|
||||
lastName: lastName,
|
||||
bornAt: bornAt,
|
||||
gender: gender,
|
||||
relationType: relationType,
|
||||
address: address,
|
||||
cardPublicKey: cardPublicKey,
|
||||
deviceActivationCode: deviceActivationCode,
|
||||
scaProof: scaProof,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ abstract class AuthRepository {
|
||||
Future<String> login({required String email, required String password});
|
||||
Future<void> twoFactor({required String token, required String code});
|
||||
|
||||
Future<String> requestPasswordReset({required String email});
|
||||
Future<String> requestPasswordReset({String phone, String email});
|
||||
|
||||
Future<void> recoverPassword({
|
||||
required String newPassword,
|
||||
@@ -23,17 +23,4 @@ abstract class AuthRepository {
|
||||
required String token,
|
||||
required String code,
|
||||
});
|
||||
Future<String> createChildProfile({
|
||||
required String id,
|
||||
required String parentId,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required int bornAt,
|
||||
required String gender,
|
||||
required String relationType,
|
||||
required String address,
|
||||
required String cardPublicKey,
|
||||
required String deviceActivationCode,
|
||||
required String scaProof,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:auth/src/features/device_sign_up/presentation/device_signup_screen.dart';
|
||||
import 'package:auth/src/features/device_sign_up/device_signup_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:auth/auth.dart';
|
||||
import 'package:auth/src/features/device_sign_up/presentation/add_kid_screen.dart';
|
||||
import 'package:auth/src/features/device_sign_up/presentation/link_watch/link_watch_screen.dart';
|
||||
import 'package:auth/src/features/device_sign_up/presentation/link_watch/link_watch_previous_screen.dart';
|
||||
import 'package:auth/src/features/device_sign_up/add_kid_screen.dart';
|
||||
import 'package:auth/src/features/device_sign_up/link_watch/link_watch_screen.dart';
|
||||
import 'package:auth/src/features/device_sign_up/link_watch/link_watch_previous_screen.dart';
|
||||
import 'package:auth/src/features/sign_up/presentation/screens/account_created_screen.dart';
|
||||
import 'package:auth/src/widgets/layouts/form_step_layout.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
@@ -1,15 +0,0 @@
|
||||
abstract class CreateChildProfileUseCase {
|
||||
Future<String> createChildProfile({
|
||||
required String id,
|
||||
required String parentId,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required int bornAt,
|
||||
required String gender,
|
||||
required String relationType,
|
||||
required String address,
|
||||
required String cardPublicKey,
|
||||
required String deviceActivationCode,
|
||||
required String scaProof,
|
||||
});
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import 'package:auth/src/core/domain/repositories/auth_repository.dart';
|
||||
import 'package:auth/src/features/device_sign_up/domain/create_child_profile_use_case.dart';
|
||||
|
||||
class CreateChildProfileUseCaseImpl implements CreateChildProfileUseCase {
|
||||
CreateChildProfileUseCaseImpl(this._repository);
|
||||
|
||||
final AuthRepository _repository;
|
||||
|
||||
@override
|
||||
Future<String> createChildProfile({
|
||||
required String id,
|
||||
required String parentId,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required int bornAt,
|
||||
required String gender,
|
||||
required String relationType,
|
||||
required String address,
|
||||
required String cardPublicKey,
|
||||
required String deviceActivationCode,
|
||||
required String scaProof,
|
||||
}) {
|
||||
return _repository.createChildProfile(
|
||||
id: id,
|
||||
parentId: parentId,
|
||||
firstName: firstName,
|
||||
lastName: lastName,
|
||||
bornAt: bornAt,
|
||||
gender: gender,
|
||||
relationType: relationType,
|
||||
address: address,
|
||||
cardPublicKey: cardPublicKey,
|
||||
deviceActivationCode: deviceActivationCode,
|
||||
scaProof: scaProof,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ 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';
|
||||
|
||||
class RequestLinkPhoneScreen extends ConsumerWidget {
|
||||
final NavigationContract navigationContract;
|
||||
@@ -27,19 +28,22 @@ class RequestLinkPhoneScreen extends ConsumerWidget {
|
||||
Text(
|
||||
context.translate(I18n.linkPhoneTitle),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 30, big: 28, xl: 26),
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 24, big: 22, xl: 20)),
|
||||
Text(
|
||||
context.translate(I18n.linkPhoneSubtitle),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 16, letterSpacing: 0),
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 16, big: 16, xl: 14),
|
||||
letterSpacing: 0
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 46, xl: 44)),
|
||||
|
||||
Column(
|
||||
spacing: 8,
|
||||
@@ -89,7 +93,7 @@ class RequestLinkPhoneScreen extends ConsumerWidget {
|
||||
),
|
||||
],
|
||||
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 10, big: 10)),
|
||||
|
||||
PrimaryButton(
|
||||
onPressed: () async {
|
||||
|
||||
@@ -5,6 +5,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';
|
||||
|
||||
class VerifyLinkPhoneCodeScreen extends ConsumerWidget {
|
||||
final NavigationContract navigationContract;
|
||||
@@ -34,30 +35,32 @@ class VerifyLinkPhoneCodeScreen extends ConsumerWidget {
|
||||
children: [
|
||||
Text(
|
||||
context.translate(I18n.connect),
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: SizeUtils.getByScreen(small: 30, big: 28)),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: context.translate(I18n.verificationCodeSentTo),
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 18, big: 15),
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${viewState.dialCode}${viewState.phoneNumber}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 42, xl: 36)),
|
||||
Text(
|
||||
context.translate(I18n.enterCodeHere),
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 24, big: 24, xl: 20)),
|
||||
|
||||
LinkPhoneCodeInput(
|
||||
length: 6,
|
||||
@@ -90,21 +93,22 @@ class VerifyLinkPhoneCodeScreen extends ConsumerWidget {
|
||||
},
|
||||
text: context.translate(I18n.enter),
|
||||
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
size: SizeUtils.getByScreen(small: 18, big: 17, xl: 16),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
context.translate(I18n.didNotReceiveIt),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontSize: SizeUtils.getByScreen(small: 18, big: 17, xl: 16),
|
||||
letterSpacing: 0,
|
||||
height: 1.5,
|
||||
height: SizeUtils.getByScreen(small: 1.5, big: 0),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 0)),
|
||||
CustomTextButton(
|
||||
onPressed: () => navigationContract.goBack(),
|
||||
text: context.translate(I18n.tryAgain),
|
||||
size: 18,
|
||||
size: SizeUtils.getByScreen(small: 18, big: 17, xl: 16),
|
||||
weight: FontWeight.w500,
|
||||
),
|
||||
],
|
||||
@@ -115,4 +119,4 @@ class VerifyLinkPhoneCodeScreen extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class LinkPhoneCodeInput extends StatefulWidget {
|
||||
const LinkPhoneCodeInput({
|
||||
@@ -74,8 +75,9 @@ class _LinkPhoneCodeInputState extends State<LinkPhoneCodeInput> {
|
||||
decoration: const InputDecoration(
|
||||
hintText: '0',
|
||||
counterText: '',
|
||||
border: OutlineInputBorder(),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(14))),
|
||||
),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 20, big: 22, xl: 17)),
|
||||
maxLength: 1,
|
||||
onChanged: (value) => _onDigitChanged(i, value),
|
||||
),
|
||||
@@ -83,4 +85,4 @@ class _LinkPhoneCodeInputState extends State<LinkPhoneCodeInput> {
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ 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';
|
||||
|
||||
class LoginScreen extends ConsumerWidget {
|
||||
final NavigationContract navigationContract;
|
||||
@@ -98,27 +99,28 @@ class LoginScreen extends ConsumerWidget {
|
||||
child: AbsorbPointer(
|
||||
absorbing: isLoading,
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
padding: EdgeInsets.symmetric(horizontal: SizeUtils.getByScreen(small: 24, big: 24)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 0, big: 30, xl: 44)),
|
||||
_Header(theme: theme),
|
||||
SizedBox(height: 48),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 26, big: 30, xl: 40)),
|
||||
const _EmailSection(),
|
||||
SizedBox(height: 24),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 18, big: 24, xl: 20)),
|
||||
_PasswordSection(onSubmitted: () => _onLogIn(context, ref)),
|
||||
SizedBox(height: 16),
|
||||
_ForgotPassword(navigationContract: navigationContract),
|
||||
SizedBox(height: 30),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 0, big: 24, xl: 22)),
|
||||
_SignInSection(
|
||||
theme: theme,
|
||||
onSignIn: () => _onLogIn(context, ref),
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 30, big: 60, xl: 56)),
|
||||
_OrContinueWith(theme: theme),
|
||||
SizedBox(height: 24),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 24, big: 24, xl: 26)),
|
||||
_SocialButtons(theme: theme),
|
||||
SizedBox(height: 30),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 18, big: 36)),
|
||||
_Footer(navigationContract: navigationContract),
|
||||
],
|
||||
),
|
||||
@@ -140,12 +142,15 @@ class _Header extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
size: 54,
|
||||
size: SizeUtils.getByScreen(small: 54, big: 50, xl: 46),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.welcome),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 30, big: 28, xl: 27),
|
||||
fontWeight: FontWeight.w500
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -168,6 +173,7 @@ class _EmailSection extends ConsumerWidget {
|
||||
CustomTextField(
|
||||
hint: context.translate(I18n.username),
|
||||
label: context.translate(I18n.username),
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12),
|
||||
controller: vm.emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.next,
|
||||
@@ -199,6 +205,7 @@ class _PasswordSection extends ConsumerWidget {
|
||||
CustomTextField(
|
||||
showPassword: passwordVisible,
|
||||
label: context.translate(I18n.password),
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12),
|
||||
hint: '********',
|
||||
controller: vm.passwordController,
|
||||
textInputAction: TextInputAction.done,
|
||||
@@ -227,7 +234,7 @@ class _ForgotPassword extends ConsumerWidget {
|
||||
onPressed: isLoading
|
||||
? () {}
|
||||
: () => navigationContract.pushTo(AppRoutes.recoverPassword),
|
||||
size: 16,
|
||||
size: SizeUtils.getByScreen(small: 16, big: 15, xl: 14),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -265,6 +272,7 @@ class _SignInSection extends ConsumerWidget {
|
||||
),
|
||||
)
|
||||
: null,
|
||||
size: SizeUtils.getByScreen(small: 18, big: 17, xl: 16),
|
||||
),
|
||||
if (errorMessage.isNotEmpty)
|
||||
Padding(
|
||||
@@ -274,7 +282,7 @@ class _SignInSection extends ConsumerWidget {
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
fontSize: 13,
|
||||
fontSize: SizeUtils.getByScreen(small: 13, big: 12, xl: 11),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -328,7 +336,7 @@ class _SocialButtons extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
radius: 16,
|
||||
padding: 44,
|
||||
padding: SizeUtils.getByScreen(small: 44, big: 40, xl: 36),
|
||||
text: context.translate(I18n.google),
|
||||
label: 'Google',
|
||||
),
|
||||
@@ -336,7 +344,7 @@ class _SocialButtons extends ConsumerWidget {
|
||||
SecondaryButton(
|
||||
onPressed: isLoading ? () {} : () {},
|
||||
radius: 16,
|
||||
padding: 44,
|
||||
padding: SizeUtils.getByScreen(small: 44, big: 40, xl: 36),
|
||||
icon: Icons.apple,
|
||||
label: 'Apple',
|
||||
),
|
||||
@@ -359,20 +367,15 @@ class _Footer extends ConsumerWidget {
|
||||
children: [
|
||||
Text(
|
||||
context.translate(I18n.dontHaveAccount),
|
||||
style: const TextStyle(fontSize: 18, letterSpacing: 0),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 17, xl: 16), letterSpacing: 0, height: 0),
|
||||
),
|
||||
TextButton(
|
||||
CustomTextButton(
|
||||
onPressed: isLoading
|
||||
? null
|
||||
: () => navigationContract.pushTo(AppRoutes.signup),
|
||||
child: Text(
|
||||
context.translate(I18n.createOneNow),
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
text: context.translate(I18n.createOneNow),
|
||||
size: SizeUtils.getByScreen(small: 18, big: 17, xl: 16),
|
||||
weight: FontWeight.w500,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'package:auth/src/features/login/presentation/widgets/otp_code_fields.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class TwoFactorBottomSheetView extends StatelessWidget {
|
||||
const TwoFactorBottomSheetView({
|
||||
@@ -82,8 +83,9 @@ class TwoFactorBottomSheetView extends StatelessWidget {
|
||||
if (isOtpLoading || !_isValidOtp) return;
|
||||
unawaited(onVerify());
|
||||
},
|
||||
gap: SizeUtils.getByScreen(small: 10, big: 8, xl: 4),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 24, big: 38)),
|
||||
|
||||
PrimaryButton(
|
||||
onPressed: (isOtpLoading || !_isValidOtp)
|
||||
@@ -103,7 +105,7 @@ class TwoFactorBottomSheetView extends StatelessWidget {
|
||||
: null,
|
||||
),
|
||||
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 9)),
|
||||
|
||||
TextButton(
|
||||
onPressed: isOtpLoading ? null : onClose,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
abstract class RecoverPasswordUseCase {
|
||||
Future<String> requestEmail({required String email});
|
||||
|
||||
Future<void> recoverPassword({
|
||||
required String newPassword,
|
||||
required String token,
|
||||
});
|
||||
}
|
||||
Future<String> requestSms({required String phone});
|
||||
|
||||
Future<void> recoverPassword({required String newPassword, required String token});
|
||||
}
|
||||
@@ -12,10 +12,12 @@ class RecoverPasswordUseCaseImpl implements RecoverPasswordUseCase {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> recoverPassword({
|
||||
required String newPassword,
|
||||
required String token,
|
||||
}) async {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ class NewPasswordScreen extends ConsumerWidget {
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12),
|
||||
hint: '********',
|
||||
controller: viewModel.passwordController,
|
||||
// onVisibilityChanged: viewModel.togglePasswordVisible,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
CustomTextField(
|
||||
@@ -53,9 +54,11 @@ class NewPasswordScreen extends ConsumerWidget {
|
||||
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),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 8)),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
@@ -76,7 +79,7 @@ class NewPasswordScreen extends ConsumerWidget {
|
||||
],
|
||||
),
|
||||
],
|
||||
SizedBox(height: 12),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 14, big: 12)),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
@@ -173,7 +176,43 @@ class NewPasswordScreen extends ConsumerWidget {
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: SizeUtils.getByScreen(small: 32, big: 32, xl: 24),
|
||||
height: SizeUtils.getByScreen(small: 28, 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),
|
||||
keyboardType: TextInputType.number,
|
||||
controller: viewModel.newPhoneNumberController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (viewState.errorMessage.isNotEmpty) ...[
|
||||
SizedBox(height: 10),
|
||||
|
||||
@@ -23,52 +23,70 @@ class RequestRecoveryScreen extends ConsumerWidget {
|
||||
return Scaffold(
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
body: Container(
|
||||
margin: EdgeInsets.all(
|
||||
SizeUtils.getByScreen(small: 30, big: 30, xl: 20),
|
||||
),
|
||||
margin: EdgeInsets.symmetric(horizontal: 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: 28, xl: 26),
|
||||
),
|
||||
style: TextStyle(fontWeight: FontWeight.w500, fontSize: SizeUtils.getByScreen(small: 29, big: 27, 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),
|
||||
),
|
||||
style: TextStyle(letterSpacing: 0, fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 16)),
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 56, big: 48)),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 56, big: 52)),
|
||||
CustomTextField(
|
||||
label: context.translate(I18n.email),
|
||||
hint: context.translate(I18n.email),
|
||||
controller: viewModel.emailController,
|
||||
),
|
||||
SizedBox(
|
||||
height: SizeUtils.getByScreen(small: 20, big: 20, 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: SizeUtils.getByScreen(small: 36, big: 36, xl: 26)),
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
context.translate(I18n.mobilePhone),
|
||||
style: TextStyle(fontSize: 14, letterSpacing: 0),
|
||||
),
|
||||
],
|
||||
SizedBox(
|
||||
height: SizeUtils.getByScreen(small: 10, big: 10, xl: 18),
|
||||
),
|
||||
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),
|
||||
keyboardType: TextInputType.number,
|
||||
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(
|
||||
@@ -78,23 +96,17 @@ class RequestRecoveryScreen extends ConsumerWidget {
|
||||
size: SizeUtils.getByScreen(small: 16, big: 16, xl: 14),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: SizeUtils.getByScreen(small: 20, big: 20, xl: 10),
|
||||
),
|
||||
SizedBox(width: SizeUtils.getByScreen(small: 20, big: 20, xl: 10)),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
onPressed: () async {
|
||||
await viewModel.requestRecovery();
|
||||
final updatedState = ref.read(
|
||||
recoverPasswordViewModelProvider,
|
||||
);
|
||||
final updatedState = ref.read(recoverPasswordViewModelProvider);
|
||||
if (updatedState.recoveryRequested) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => SentScreen(
|
||||
navigationContract: navigationContract,
|
||||
),
|
||||
builder: (_) => SentScreen(navigationContract: navigationContract),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@ class SentScreen extends ConsumerWidget {
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40),
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@@ -47,58 +45,41 @@ class SentScreen extends ConsumerWidget {
|
||||
Icons.check,
|
||||
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
),
|
||||
SizedBox(
|
||||
width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6),
|
||||
),
|
||||
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,
|
||||
),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 18, xl: 15), fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: SizeUtils.getByScreen(small: 48, big: 48, xl: 40),
|
||||
),
|
||||
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,
|
||||
),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 17, big: 17, xl: 14), letterSpacing: 0),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 16, big: 16, xl: 14)),
|
||||
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),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 14, big: 14, xl: 12), letterSpacing: 0),
|
||||
),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 48, big: 48, xl: 38)),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
onPressed: () {
|
||||
if (viewState.recoveryFormat == "email") {
|
||||
if ( viewState.recoveryFormat == "email") {
|
||||
viewModel.requestEmail();
|
||||
} else {
|
||||
viewModel.requestSms();
|
||||
}
|
||||
},
|
||||
text: viewState.recoveryFormat == "email"
|
||||
@@ -112,11 +93,7 @@ class SentScreen extends ConsumerWidget {
|
||||
child: PrimaryButton(
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => NewPasswordScreen(
|
||||
navigationContract: navigationContract,
|
||||
),
|
||||
),
|
||||
MaterialPageRoute(builder: (_) => NewPasswordScreen(navigationContract: navigationContract)),
|
||||
),
|
||||
text: context.translate(I18n.continueKey),
|
||||
color: theme.getColorFor(ThemeCode.buttonSecondary),
|
||||
|
||||
@@ -6,10 +6,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../providers/recover_password_provider.dart';
|
||||
|
||||
final recoverPasswordViewModelProvider =
|
||||
NotifierProvider.autoDispose<
|
||||
RecoverPasswordViewModel,
|
||||
RecoverPasswordViewState
|
||||
>(RecoverPasswordViewModel.new);
|
||||
NotifierProvider.autoDispose<RecoverPasswordViewModel, RecoverPasswordViewState>(
|
||||
RecoverPasswordViewModel.new,
|
||||
);
|
||||
|
||||
class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
late final RecoverPasswordUseCase _recoverPasswordUseCase;
|
||||
@@ -23,6 +22,9 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
RecoverPasswordViewState build() {
|
||||
_recoverPasswordUseCase = ref.read(recoverPasswordUseCaseProvider);
|
||||
|
||||
phoneNumberController = TextEditingController();
|
||||
phoneNumberController.addListener(_onPhoneNumberChanged);
|
||||
|
||||
emailController = TextEditingController();
|
||||
emailController.addListener(_onEmailChanged);
|
||||
|
||||
@@ -32,11 +34,32 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
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(
|
||||
@@ -80,11 +103,28 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
);
|
||||
}
|
||||
|
||||
void togglePasswordVisible() {
|
||||
state = state.copyWith(passwordVisible: !state.passwordVisible);
|
||||
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(
|
||||
@@ -95,6 +135,8 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
|
||||
if (email.isNotEmpty) {
|
||||
await requestEmail();
|
||||
} else if (trimmedNumber.isNotEmpty) {
|
||||
await requestSms();
|
||||
} else {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
@@ -108,9 +150,7 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
final email = state.email.trim();
|
||||
|
||||
try {
|
||||
final String token = await _recoverPasswordUseCase.requestEmail(
|
||||
email: email,
|
||||
);
|
||||
final String token = await _recoverPasswordUseCase.requestEmail(email: email);
|
||||
if (!ref.mounted) return;
|
||||
|
||||
state = state.copyWith(
|
||||
@@ -132,6 +172,34 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -176,13 +244,17 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(isLoading: true, passwordChanged: false);
|
||||
state = state.copyWith(
|
||||
isLoading: true,
|
||||
passwordChanged: false,
|
||||
);
|
||||
try {
|
||||
await _recoverPasswordUseCase.recoverPassword(
|
||||
newPassword: password,
|
||||
token: state.token,
|
||||
newPassword: password, token: state.token);
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
passwordChanged: true,
|
||||
);
|
||||
state = state.copyWith(isLoading: false, passwordChanged: true);
|
||||
} catch (error) {
|
||||
state = state.copyWith(
|
||||
errorMessage: error.toString(),
|
||||
@@ -193,11 +265,15 @@ class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
|
||||
}
|
||||
|
||||
void disposeControllers() {
|
||||
emailController.removeListener(_onEmailChanged);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import 'package:country_code_picker/country_code_picker.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class SignupAddressScreen extends StatelessWidget {
|
||||
const SignupAddressScreen({
|
||||
@@ -145,7 +146,9 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
const SizedBox(height: 8),
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(birthCountryLabel, style: const TextStyle(fontSize: 14)),
|
||||
child: Text(birthCountryLabel, style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
@@ -168,6 +171,7 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
|
||||
CustomTextField(
|
||||
label: streetLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: streetHint,
|
||||
controller: streetController,
|
||||
),
|
||||
@@ -175,6 +179,7 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
|
||||
CustomTextField(
|
||||
label: cityLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: cityHint,
|
||||
controller: cityController,
|
||||
),
|
||||
@@ -182,6 +187,7 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
|
||||
CustomTextField(
|
||||
label: provinceLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: provinceHint,
|
||||
controller: provinceController,
|
||||
),
|
||||
@@ -189,6 +195,7 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
|
||||
CustomTextField(
|
||||
label: stateLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: stateHint,
|
||||
controller: stateController,
|
||||
),
|
||||
@@ -222,6 +229,7 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
|
||||
CustomTextField(
|
||||
label: postCodeLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: postCodeHint,
|
||||
keyboardType: TextInputType.number,
|
||||
controller: postCodeController,
|
||||
@@ -229,4 +237,4 @@ class SignupAddressScreen extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import 'package:country_code_picker/country_code_picker.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class SignupPersonalScreen extends StatelessWidget {
|
||||
final TextEditingController firstNameTextFieldController;
|
||||
@@ -72,12 +73,14 @@ class SignupPersonalScreen extends StatelessWidget {
|
||||
children: [
|
||||
CustomTextField(
|
||||
label: firstNameLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: firstNameHint,
|
||||
controller: firstNameTextFieldController,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
CustomTextField(
|
||||
label: lastNameLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: lastNameHint,
|
||||
controller: lastNameTextFieldController,
|
||||
),
|
||||
@@ -99,6 +102,7 @@ class SignupPersonalScreen extends StatelessWidget {
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
label: documentNumberLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: documentNumberHint,
|
||||
controller: documentNumberTextFieldController,
|
||||
),
|
||||
@@ -108,7 +112,9 @@ class SignupPersonalScreen extends StatelessWidget {
|
||||
const SizedBox(height: 8),
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(phoneLabel, style: const TextStyle(fontSize: 14)),
|
||||
child: Text(phoneLabel, style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12)
|
||||
)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
@@ -130,11 +136,12 @@ class SignupPersonalScreen extends StatelessWidget {
|
||||
const SizedBox(height: 8),
|
||||
CustomTextField(
|
||||
label: emailLabel,
|
||||
labelSize: SizeUtils.getByScreen(small: 14, big: 13, xl: 12),
|
||||
hint: emailHint,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: emailTextFieldController,
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
CheckboxListTile(
|
||||
value: acceptTerms,
|
||||
onChanged: onAcceptTermsPressed,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class FormStepLayout extends ConsumerWidget {
|
||||
final int currentStep;
|
||||
@@ -70,7 +71,7 @@ class FormStepLayout extends ConsumerWidget {
|
||||
Text(
|
||||
subtitle!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 18),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 17)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:auth/src/widgets/form_error_banner.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class SignUpLayout extends StatelessWidget {
|
||||
final ThemePort theme;
|
||||
@@ -53,24 +54,24 @@ class SignUpLayout extends StatelessWidget {
|
||||
Text(
|
||||
supertitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 18),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 16, xl: 15)),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 5)),
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.bold,
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 30, big: 28, xl: 26),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
subtitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 18),
|
||||
style: TextStyle(fontSize: SizeUtils.getByScreen(small: 18, big: 17, xl: 15)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SizedBox(height: SizeUtils.getByScreen(small: 16, big: 20, xl: 36)),
|
||||
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomTextButton extends StatelessWidget {
|
||||
final VoidCallback onPressed;
|
||||
final VoidCallback? onPressed;
|
||||
final String text;
|
||||
final double size;
|
||||
final FontWeight weight;
|
||||
|
||||
@@ -76,18 +76,18 @@ class CustomTextFieldState extends State<CustomTextField> {
|
||||
gapPadding: 16,
|
||||
),
|
||||
suffixIcon: widget.showPassword != null
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
_showPassword ? Icons.visibility_off : Icons.visibility,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_showPassword = !_showPassword;
|
||||
});
|
||||
},
|
||||
//onpressed: widget.onVisibilityChanged,
|
||||
)
|
||||
: null,
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
_showPassword ? Icons.visibility_off_outlined : Icons.visibility_outlined,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_showPassword = !_showPassword;
|
||||
});
|
||||
},
|
||||
//onpressed: widget.onVisibilityChanged,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
minLines: widget.lines ?? 1,
|
||||
maxLines: widget.lines ?? 1,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"next": "Siguiente",
|
||||
"skip": "Omitir",
|
||||
"linkPhoneTitle": "¡Nos alegra mucho tenerte por aquí!",
|
||||
"linkPhoneSubtitle": "Para poder entrar de forma segura, te vamos a enviar un código al teléfono",
|
||||
"linkPhoneSubtitle": "Para poder entrar de forma segura,\nte vamos a enviar un código al teléfono",
|
||||
"mobilePhone": "Teléfono móvil",
|
||||
"phoneNumber": "Teléfono",
|
||||
"selectYourCountry": "Selecciona tu país",
|
||||
@@ -18,7 +18,7 @@
|
||||
"connect": "Conéctate",
|
||||
"verificationCodeSentTo": "Hemos enviado el código al ",
|
||||
"enterCodeHere": "Introduce el código aquí",
|
||||
"enter": "entrar",
|
||||
"enter": "Entrar",
|
||||
"didNotReceiveIt": "¿No lo has recibido?",
|
||||
"tryAgain": "Volver a intentarlo",
|
||||
"welcome": "¡Te damos la bienvenida!",
|
||||
|
||||
Reference in New Issue
Block a user