added linkPhone use cases, auth repository providers and data folder
This commit is contained in:
31
.dart_tool/extension_discovery/README.md
Normal file
31
.dart_tool/extension_discovery/README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
Extension Discovery Cache
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This folder is used by `package:extension_discovery` to cache lists of
|
||||||
|
packages that contains extensions for other packages.
|
||||||
|
|
||||||
|
DO NOT USE THIS FOLDER
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
* Do not read (or rely) the contents of this folder.
|
||||||
|
* Do write to this folder.
|
||||||
|
|
||||||
|
If you're interested in the lists of extensions stored in this folder use the
|
||||||
|
API offered by package `extension_discovery` to get this information.
|
||||||
|
|
||||||
|
If this package doesn't work for your use-case, then don't try to read the
|
||||||
|
contents of this folder. It may change, and will not remain stable.
|
||||||
|
|
||||||
|
Use package `extension_discovery`
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
If you want to access information from this folder.
|
||||||
|
|
||||||
|
Feel free to delete this folder
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Files in this folder act as a cache, and the cache is discarded if the files
|
||||||
|
are older than the modification time of `.dart_tool/package_config.json`.
|
||||||
|
|
||||||
|
Hence, it should never be necessary to clear this cache manually, if you find a
|
||||||
|
need to do please file a bug.
|
||||||
1
.dart_tool/extension_discovery/vs_code.json
Normal file
1
.dart_tool/extension_discovery/vs_code.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":2,"entries":[{"package":"sf_app_platform_mono_repo","rootUri":"../","packageUri":"lib/"}]}
|
||||||
@@ -1 +1,2 @@
|
|||||||
API_BASE_URL=https://api-neki-b2b.neki.es/gateway/api/
|
API_BASE_URL=https://api-neki-b2b.neki.es/gateway/api/
|
||||||
|
API_ORIGIN =https://neki-b2b.neki.es
|
||||||
1
apps/mobile_app/lib/config/env/env.dart
vendored
1
apps/mobile_app/lib/config/env/env.dart
vendored
@@ -2,6 +2,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|||||||
|
|
||||||
class Env {
|
class Env {
|
||||||
static String get apiBaseUrl => dotenv.env['API_BASE_URL'] ?? '';
|
static String get apiBaseUrl => dotenv.env['API_BASE_URL'] ?? '';
|
||||||
|
static String get apiOrigin => dotenv.env['API_ORIGIN'] ?? '';
|
||||||
|
|
||||||
// static String get apiKey => dotenv.env['API_KEY'] ?? '';
|
// static String get apiKey => dotenv.env['API_KEY'] ?? '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import 'env.dart';
|
|||||||
class QuestiaEnvConfig implements EnvConfig {
|
class QuestiaEnvConfig implements EnvConfig {
|
||||||
@override
|
@override
|
||||||
String get apiBaseUrl => Env.apiBaseUrl;
|
String get apiBaseUrl => Env.apiBaseUrl;
|
||||||
|
@override
|
||||||
|
String get apiOrigin => Env.apiOrigin;
|
||||||
|
|
||||||
// @override
|
// @override
|
||||||
// String get apiKey => Env.apiKey;
|
// String get apiKey => Env.apiKey;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ late final GoRouter appRouter;
|
|||||||
void configureAppRouter() {
|
void configureAppRouter() {
|
||||||
appRouter = GoRouter(
|
appRouter = GoRouter(
|
||||||
navigatorKey: rootNavigatorKey,
|
navigatorKey: rootNavigatorKey,
|
||||||
initialLocation: AppRoutes.linkPhone,
|
initialLocation: AppRoutes.login,
|
||||||
debugLogDiagnostics: true,
|
debugLogDiagnostics: true,
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
@@ -35,13 +35,13 @@ void configureAppRouter() {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: AppRoutes.linkPhone,
|
path: AppRoutes.linkPhone,
|
||||||
name: 'link_phone',
|
name: 'request_link_phone',
|
||||||
pageBuilder: LinkPhoneBuilder().buildPage,
|
pageBuilder: RequestLinkPhoneBuilder().buildPage,
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: AppRoutes.phoneCode,
|
path: AppRoutes.phoneCode,
|
||||||
name: 'phone_code',
|
name: 'Verify_link_phone_code',
|
||||||
pageBuilder: PhoneCodeBuilder().buildPage,
|
pageBuilder: VerifyLinkPhoneCodeBuilder().buildPage,
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: AppRoutes.recoverPassword,
|
path: AppRoutes.recoverPassword,
|
||||||
|
|||||||
@@ -448,14 +448,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.20.2"
|
version: "0.20.2"
|
||||||
intl_phone_field_v2:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: intl_phone_field_v2
|
|
||||||
sha256: b1e5077e31cc8705639a69b2e0410a8ecc858c3e518726d99b378b6c35adfefb
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.0.5"
|
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export 'src/features/device_sign_up/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/onboarding/onboarding_builder.dart';
|
||||||
export 'src/features/link_phone/link_phone_builder.dart';
|
export 'src/features/link_phone/presentation/request_phone/request_link_phone_builder.dart';
|
||||||
export 'src/features/login/phone_code_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/login/login_builder.dart';
|
||||||
export 'src/features/recover_password/recover_password_builder.dart';
|
export 'src/features/recover_password/recover_password_builder.dart';
|
||||||
export 'src/features/device_sign_up/device_signup_builder.dart';
|
export 'src/features/device_sign_up/device_signup_builder.dart';
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
|
|||||||
body: <String, dynamic>{'phone': phone},
|
body: <String, dynamic>{'phone': phone},
|
||||||
);
|
);
|
||||||
} on DioException catch (error) {
|
} on DioException catch (error) {
|
||||||
throw _mapDioError(error, defaultMessage: 'Error al solicitar el código');
|
throw _mapDioError(
|
||||||
|
error,
|
||||||
|
defaultMessage: error.response?.data ?? 'Error to request phone code',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
|
|||||||
body: <String, dynamic>{'phone': phone, 'code': code},
|
body: <String, dynamic>{'phone': phone, 'code': code},
|
||||||
);
|
);
|
||||||
} on DioException catch (error) {
|
} on DioException catch (error) {
|
||||||
throw _mapDioError(error, defaultMessage: 'Error al verificar el código');
|
throw _mapDioError(error, defaultMessage: 'Error in verification code');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ class LinkPhoneUseCaseImpl implements LinkPhoneUseCase {
|
|||||||
final AuthRepository _repository;
|
final AuthRepository _repository;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> requestCode({required String phone}) {
|
Future<void> requestCode({required String phone}) async {
|
||||||
return _repository.requestPhoneCode(phone: phone);
|
// return _repository.requestPhoneCode(phone: phone);
|
||||||
|
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> verifyCode({required String phone, required String code}) {
|
Future<void> verifyCode({required String phone, required String code}) async {
|
||||||
return _repository.verifyPhoneCode(phone: phone, code: code);
|
// return _repository.verifyPhoneCode(phone: phone, code: code);
|
||||||
|
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'package:auth/src/features/link_phone/presentation/link_phone_screen.dart';
|
import 'package:auth/src/features/link_phone/presentation/request_phone/request_link_phone_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:navigation/navigation.dart';
|
import 'package:navigation/navigation.dart';
|
||||||
|
|
||||||
class LinkPhoneBuilder {
|
class RequestLinkPhoneBuilder {
|
||||||
const LinkPhoneBuilder();
|
const RequestLinkPhoneBuilder();
|
||||||
|
|
||||||
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
||||||
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
||||||
|
|
||||||
return MaterialPage<void>(
|
return MaterialPage<void>(
|
||||||
key: state.pageKey,
|
key: state.pageKey,
|
||||||
child: LinkPhoneScreen(navigationContract: navigationContract),
|
child: RequestLinkPhoneScreen(navigationContract: navigationContract),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
import 'package:auth/src/features/link_phone/presentation/link_phone_view_model.dart';
|
import 'package:auth/src/features/link_phone/presentation/state/link_phone_view_model.dart';
|
||||||
import 'package:design_system/src/dropdowns/country_prefix_picker.dart';
|
|
||||||
import 'package:design_system/design_system.dart';
|
import 'package:design_system/design_system.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:navigation/navigation.dart';
|
import 'package:navigation/navigation.dart';
|
||||||
import 'package:sf_localizations/sf_localizations.dart';
|
import 'package:sf_localizations/sf_localizations.dart';
|
||||||
|
|
||||||
class LinkPhoneScreen extends ConsumerWidget {
|
class RequestLinkPhoneScreen extends ConsumerWidget {
|
||||||
final NavigationContract navigationContract;
|
final NavigationContract navigationContract;
|
||||||
|
|
||||||
const LinkPhoneScreen({super.key, required this.navigationContract});
|
const RequestLinkPhoneScreen({super.key, required this.navigationContract});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@@ -56,6 +55,7 @@ class LinkPhoneScreen extends ConsumerWidget {
|
|||||||
spacing: 10,
|
spacing: 10,
|
||||||
children: [
|
children: [
|
||||||
CountryPrefixPicker(
|
CountryPrefixPicker(
|
||||||
|
headerText: context.translate(I18n.selectYourCountry),
|
||||||
initialCountryCode: viewState.dialCode,
|
initialCountryCode: viewState.dialCode,
|
||||||
onChanged: (country) {
|
onChanged: (country) {
|
||||||
viewModel.updateDialCode(
|
viewModel.updateDialCode(
|
||||||
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:auth/src/features/link_phone/domain/use_cases/link_phone_use_case.dart';
|
import 'package:auth/src/features/link_phone/domain/use_cases/link_phone_use_case.dart';
|
||||||
import 'package:auth/src/features/link_phone/presentation/link_phone_view_state.dart';
|
import 'package:auth/src/features/link_phone/presentation/state/link_phone_view_state.dart';
|
||||||
|
|
||||||
final linkPhoneViewModelProvider =
|
final linkPhoneViewModelProvider =
|
||||||
NotifierProvider.autoDispose<LinkPhoneViewModel, LinkPhoneViewState>(
|
NotifierProvider.autoDispose<LinkPhoneViewModel, LinkPhoneViewState>(
|
||||||
@@ -13,6 +13,7 @@ final linkPhoneViewModelProvider =
|
|||||||
class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
||||||
late final LinkPhoneUseCase _linkPhoneUseCase;
|
late final LinkPhoneUseCase _linkPhoneUseCase;
|
||||||
late final TextEditingController phoneNumberController;
|
late final TextEditingController phoneNumberController;
|
||||||
|
late final TextEditingController codeController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
LinkPhoneViewState build() {
|
LinkPhoneViewState build() {
|
||||||
@@ -21,6 +22,8 @@ class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
|||||||
phoneNumberController = TextEditingController();
|
phoneNumberController = TextEditingController();
|
||||||
phoneNumberController.addListener(_onPhoneNumberChanged);
|
phoneNumberController.addListener(_onPhoneNumberChanged);
|
||||||
|
|
||||||
|
codeController = TextEditingController();
|
||||||
|
|
||||||
ref.onDispose(disposeControllers);
|
ref.onDispose(disposeControllers);
|
||||||
|
|
||||||
return const LinkPhoneViewState();
|
return const LinkPhoneViewState();
|
||||||
@@ -28,18 +31,34 @@ class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
|||||||
|
|
||||||
void _onPhoneNumberChanged() {
|
void _onPhoneNumberChanged() {
|
||||||
final raw = phoneNumberController.text;
|
final raw = phoneNumberController.text;
|
||||||
state = state.copyWith(phoneNumber: raw, errorMessage: '');
|
state = state.copyWith(
|
||||||
|
phoneNumber: raw,
|
||||||
|
errorMessage: '',
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDialCode(String dialCode) {
|
void updateDialCode(String dialCode) {
|
||||||
state = state.copyWith(dialCode: dialCode, errorMessage: '');
|
state = state.copyWith(
|
||||||
|
dialCode: dialCode,
|
||||||
|
errorMessage: '',
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCode(String code) {
|
||||||
|
codeController.text = code;
|
||||||
|
state = state.copyWith(errorMessage: '', codeVerified: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> requestCode() async {
|
Future<void> requestCode() async {
|
||||||
final trimmedNumber = state.phoneNumber.trim();
|
final trimmedNumber = state.phoneNumber.trim();
|
||||||
|
|
||||||
if (trimmedNumber.isEmpty) {
|
if (trimmedNumber.isEmpty) {
|
||||||
state = state.copyWith(errorMessage: 'El teléfono no puede estar vacío');
|
state = state.copyWith(
|
||||||
|
errorMessage: 'errorMessagePhoneIsEmpty',
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +68,7 @@ class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
|||||||
isLoading: true,
|
isLoading: true,
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
codeRequested: false,
|
codeRequested: false,
|
||||||
|
codeVerified: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -67,6 +87,55 @@ class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
|||||||
isLoading: false,
|
isLoading: false,
|
||||||
errorMessage: e.toString(),
|
errorMessage: e.toString(),
|
||||||
codeRequested: false,
|
codeRequested: false,
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> verifyCode() async {
|
||||||
|
final dialCode = state.dialCode;
|
||||||
|
final phoneNumber = state.phoneNumber.trim();
|
||||||
|
final code = codeController.text.trim();
|
||||||
|
final fullPhone = '$dialCode$phoneNumber';
|
||||||
|
|
||||||
|
if (phoneNumber.isEmpty) {
|
||||||
|
state = state.copyWith(
|
||||||
|
errorMessage: 'errorMessagePhoneIsEmpty',
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code.isEmpty) {
|
||||||
|
state = state.copyWith(
|
||||||
|
errorMessage: 'errorMessageCodeIsEmpty',
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = state.copyWith(
|
||||||
|
isLoading: true,
|
||||||
|
errorMessage: '',
|
||||||
|
codeVerified: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _linkPhoneUseCase.verifyCode(phone: fullPhone, code: code);
|
||||||
|
if (!ref.mounted) return;
|
||||||
|
|
||||||
|
state = state.copyWith(
|
||||||
|
isLoading: false,
|
||||||
|
errorMessage: '',
|
||||||
|
codeVerified: true,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (!ref.mounted) return;
|
||||||
|
|
||||||
|
state = state.copyWith(
|
||||||
|
isLoading: false,
|
||||||
|
errorMessage: e.toString(),
|
||||||
|
codeVerified: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,5 +143,6 @@ class LinkPhoneViewModel extends Notifier<LinkPhoneViewState> {
|
|||||||
void disposeControllers() {
|
void disposeControllers() {
|
||||||
phoneNumberController.removeListener(_onPhoneNumberChanged);
|
phoneNumberController.removeListener(_onPhoneNumberChanged);
|
||||||
phoneNumberController.dispose();
|
phoneNumberController.dispose();
|
||||||
|
codeController.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,5 +10,6 @@ abstract class LinkPhoneViewState with _$LinkPhoneViewState {
|
|||||||
@Default('') String errorMessage,
|
@Default('') String errorMessage,
|
||||||
@Default(false) bool isLoading,
|
@Default(false) bool isLoading,
|
||||||
@Default(false) bool codeRequested,
|
@Default(false) bool codeRequested,
|
||||||
|
@Default(false) bool codeVerified,
|
||||||
}) = _LinkPhoneViewState;
|
}) = _LinkPhoneViewState;
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$LinkPhoneViewState {
|
mixin _$LinkPhoneViewState {
|
||||||
|
|
||||||
String get phoneNumber; String get dialCode; String get errorMessage; bool get isLoading; bool get codeRequested;
|
String get phoneNumber; String get dialCode; String get errorMessage; bool get isLoading; bool get codeRequested; bool get codeVerified;
|
||||||
/// Create a copy of LinkPhoneViewState
|
/// Create a copy of LinkPhoneViewState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -25,16 +25,16 @@ $LinkPhoneViewStateCopyWith<LinkPhoneViewState> get copyWith => _$LinkPhoneViewS
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is LinkPhoneViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.codeRequested, codeRequested) || other.codeRequested == codeRequested));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is LinkPhoneViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.codeRequested, codeRequested) || other.codeRequested == codeRequested)&&(identical(other.codeVerified, codeVerified) || other.codeVerified == codeVerified));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,errorMessage,isLoading,codeRequested);
|
int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,errorMessage,isLoading,codeRequested,codeVerified);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LinkPhoneViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, errorMessage: $errorMessage, isLoading: $isLoading, codeRequested: $codeRequested)';
|
return 'LinkPhoneViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, errorMessage: $errorMessage, isLoading: $isLoading, codeRequested: $codeRequested, codeVerified: $codeVerified)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ abstract mixin class $LinkPhoneViewStateCopyWith<$Res> {
|
|||||||
factory $LinkPhoneViewStateCopyWith(LinkPhoneViewState value, $Res Function(LinkPhoneViewState) _then) = _$LinkPhoneViewStateCopyWithImpl;
|
factory $LinkPhoneViewStateCopyWith(LinkPhoneViewState value, $Res Function(LinkPhoneViewState) _then) = _$LinkPhoneViewStateCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested
|
String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested, bool codeVerified
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -62,13 +62,14 @@ class _$LinkPhoneViewStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of LinkPhoneViewState
|
/// Create a copy of LinkPhoneViewState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// 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? errorMessage = null,Object? isLoading = null,Object? codeRequested = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? errorMessage = null,Object? isLoading = null,Object? codeRequested = null,Object? codeVerified = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable
|
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,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
|
||||||
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||||
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,codeRequested: null == codeRequested ? _self.codeRequested : codeRequested // ignore: cast_nullable_to_non_nullable
|
as bool,codeRequested: null == codeRequested ? _self.codeRequested : codeRequested // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,codeVerified: null == codeVerified ? _self.codeVerified : codeVerified // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -154,10 +155,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested, bool codeVerified)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _LinkPhoneViewState() when $default != null:
|
case _LinkPhoneViewState() when $default != null:
|
||||||
return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoading,_that.codeRequested);case _:
|
return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoading,_that.codeRequested,_that.codeVerified);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -175,10 +176,10 @@ return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoad
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested, bool codeVerified) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _LinkPhoneViewState():
|
case _LinkPhoneViewState():
|
||||||
return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoading,_that.codeRequested);case _:
|
return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoading,_that.codeRequested,_that.codeVerified);case _:
|
||||||
throw StateError('Unexpected subclass');
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -195,10 +196,10 @@ return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoad
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested, bool codeVerified)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _LinkPhoneViewState() when $default != null:
|
case _LinkPhoneViewState() when $default != null:
|
||||||
return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoading,_that.codeRequested);case _:
|
return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoading,_that.codeRequested,_that.codeVerified);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -210,7 +211,7 @@ return $default(_that.phoneNumber,_that.dialCode,_that.errorMessage,_that.isLoad
|
|||||||
|
|
||||||
|
|
||||||
class _LinkPhoneViewState implements LinkPhoneViewState {
|
class _LinkPhoneViewState implements LinkPhoneViewState {
|
||||||
const _LinkPhoneViewState({this.phoneNumber = '', this.dialCode = '+34', this.errorMessage = '', this.isLoading = false, this.codeRequested = false});
|
const _LinkPhoneViewState({this.phoneNumber = '', this.dialCode = '+34', this.errorMessage = '', this.isLoading = false, this.codeRequested = false, this.codeVerified = false});
|
||||||
|
|
||||||
|
|
||||||
@override@JsonKey() final String phoneNumber;
|
@override@JsonKey() final String phoneNumber;
|
||||||
@@ -218,6 +219,7 @@ class _LinkPhoneViewState implements LinkPhoneViewState {
|
|||||||
@override@JsonKey() final String errorMessage;
|
@override@JsonKey() final String errorMessage;
|
||||||
@override@JsonKey() final bool isLoading;
|
@override@JsonKey() final bool isLoading;
|
||||||
@override@JsonKey() final bool codeRequested;
|
@override@JsonKey() final bool codeRequested;
|
||||||
|
@override@JsonKey() final bool codeVerified;
|
||||||
|
|
||||||
/// Create a copy of LinkPhoneViewState
|
/// Create a copy of LinkPhoneViewState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@@ -229,16 +231,16 @@ _$LinkPhoneViewStateCopyWith<_LinkPhoneViewState> get copyWith => __$LinkPhoneVi
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LinkPhoneViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.codeRequested, codeRequested) || other.codeRequested == codeRequested));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LinkPhoneViewState&&(identical(other.phoneNumber, phoneNumber) || other.phoneNumber == phoneNumber)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.codeRequested, codeRequested) || other.codeRequested == codeRequested)&&(identical(other.codeVerified, codeVerified) || other.codeVerified == codeVerified));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,errorMessage,isLoading,codeRequested);
|
int get hashCode => Object.hash(runtimeType,phoneNumber,dialCode,errorMessage,isLoading,codeRequested,codeVerified);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LinkPhoneViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, errorMessage: $errorMessage, isLoading: $isLoading, codeRequested: $codeRequested)';
|
return 'LinkPhoneViewState(phoneNumber: $phoneNumber, dialCode: $dialCode, errorMessage: $errorMessage, isLoading: $isLoading, codeRequested: $codeRequested, codeVerified: $codeVerified)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -249,7 +251,7 @@ abstract mixin class _$LinkPhoneViewStateCopyWith<$Res> implements $LinkPhoneVie
|
|||||||
factory _$LinkPhoneViewStateCopyWith(_LinkPhoneViewState value, $Res Function(_LinkPhoneViewState) _then) = __$LinkPhoneViewStateCopyWithImpl;
|
factory _$LinkPhoneViewStateCopyWith(_LinkPhoneViewState value, $Res Function(_LinkPhoneViewState) _then) = __$LinkPhoneViewStateCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested
|
String phoneNumber, String dialCode, String errorMessage, bool isLoading, bool codeRequested, bool codeVerified
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -266,13 +268,14 @@ class __$LinkPhoneViewStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of LinkPhoneViewState
|
/// Create a copy of LinkPhoneViewState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// 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? errorMessage = null,Object? isLoading = null,Object? codeRequested = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? phoneNumber = null,Object? dialCode = null,Object? errorMessage = null,Object? isLoading = null,Object? codeRequested = null,Object? codeVerified = null,}) {
|
||||||
return _then(_LinkPhoneViewState(
|
return _then(_LinkPhoneViewState(
|
||||||
phoneNumber: null == phoneNumber ? _self.phoneNumber : phoneNumber // ignore: cast_nullable_to_non_nullable
|
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,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
|
||||||
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||||
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,codeRequested: null == codeRequested ? _self.codeRequested : codeRequested // ignore: cast_nullable_to_non_nullable
|
as bool,codeRequested: null == codeRequested ? _self.codeRequested : codeRequested // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,codeVerified: null == codeVerified ? _self.codeVerified : codeVerified // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'package:auth/src/features/login/presentation/phone_code_screen.dart';
|
import 'package:auth/src/features/link_phone/presentation/verify_code/verify_link_phone_code_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:navigation/navigation.dart';
|
import 'package:navigation/navigation.dart';
|
||||||
|
|
||||||
class PhoneCodeBuilder {
|
class VerifyLinkPhoneCodeBuilder {
|
||||||
const PhoneCodeBuilder();
|
const VerifyLinkPhoneCodeBuilder();
|
||||||
|
|
||||||
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
||||||
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
final NavigationContract navigationContract = GetIt.I<NavigationContract>();
|
||||||
|
|
||||||
return MaterialPage<void>(
|
return MaterialPage<void>(
|
||||||
key: state.pageKey,
|
key: state.pageKey,
|
||||||
child: PhoneCodeScreen(navigationContract: navigationContract),
|
child: VerifyLinkPhoneCodeScreen(navigationContract: navigationContract),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import 'package:auth/src/features/link_phone/presentation/state/link_phone_view_model.dart';
|
||||||
|
import 'package:auth/src/features/link_phone/presentation/widgets/link_phone_code_input.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';
|
||||||
|
|
||||||
|
class VerifyLinkPhoneCodeScreen extends ConsumerWidget {
|
||||||
|
final NavigationContract navigationContract;
|
||||||
|
|
||||||
|
const VerifyLinkPhoneCodeScreen({
|
||||||
|
super.key,
|
||||||
|
required this.navigationContract,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final theme = ref.watch(themePortProvider);
|
||||||
|
|
||||||
|
final viewModel = ref.read(linkPhoneViewModelProvider.notifier);
|
||||||
|
final viewState = ref.watch(linkPhoneViewModelProvider);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 48,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.translate(I18n.connect),
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: context.translate(I18n.verificationCodeSentTo),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: '${viewState.dialCode}${viewState.phoneNumber}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 48),
|
||||||
|
Text(
|
||||||
|
context.translate(I18n.enterCodeHere),
|
||||||
|
style: TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
LinkPhoneCodeInput(
|
||||||
|
length: 6,
|
||||||
|
onCodeChanged: viewModel.updateCode,
|
||||||
|
),
|
||||||
|
|
||||||
|
if (viewState.errorMessage.isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
viewState.errorMessage,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color.fromRGBO(239, 17, 17, 1),
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
PrimaryButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await viewModel.verifyCode();
|
||||||
|
final updatedState = ref.read(linkPhoneViewModelProvider);
|
||||||
|
|
||||||
|
if (updatedState.codeVerified) {
|
||||||
|
navigationContract.pushTo(AppRoutes.login);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text: context.translate(I18n.enter),
|
||||||
|
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Text(
|
||||||
|
context.translate(I18n.didNotReceiveIt),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
letterSpacing: 0,
|
||||||
|
height: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
CustomTextButton(
|
||||||
|
onPressed: () => navigationContract.goBack(),
|
||||||
|
text: context.translate(I18n.tryAgain),
|
||||||
|
size: 18,
|
||||||
|
weight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class LinkPhoneCodeInput extends StatefulWidget {
|
||||||
|
const LinkPhoneCodeInput({
|
||||||
|
super.key,
|
||||||
|
this.length = 6,
|
||||||
|
required this.onCodeChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int length;
|
||||||
|
final ValueChanged<String> onCodeChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LinkPhoneCodeInput> createState() => _LinkPhoneCodeInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LinkPhoneCodeInputState extends State<LinkPhoneCodeInput> {
|
||||||
|
late final List<TextEditingController> _controllers;
|
||||||
|
late final List<FocusNode> _focusNodes;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controllers = List<TextEditingController>.generate(
|
||||||
|
widget.length,
|
||||||
|
(_) => TextEditingController(),
|
||||||
|
);
|
||||||
|
_focusNodes = List<FocusNode>.generate(widget.length, (_) => FocusNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
for (final controller in _controllers) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
for (final node in _focusNodes) {
|
||||||
|
node.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onDigitChanged(int index, String value) {
|
||||||
|
if (value.length > 1) {
|
||||||
|
final single = value.characters.last;
|
||||||
|
_controllers[index].text = single;
|
||||||
|
_controllers[index].selection = TextSelection.fromPosition(
|
||||||
|
TextPosition(offset: single.length),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.isNotEmpty && index < widget.length - 1) {
|
||||||
|
_focusNodes[index + 1].requestFocus();
|
||||||
|
} else if (value.isEmpty && index > 0) {
|
||||||
|
_focusNodes[index - 1].requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
final code = _controllers.map((c) => c.text).join();
|
||||||
|
widget.onCodeChanged(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: List<Widget>.generate(widget.length, (int i) {
|
||||||
|
return Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: _controllers[i],
|
||||||
|
focusNode: _focusNodes[i],
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: '0',
|
||||||
|
counterText: '',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
maxLength: 1,
|
||||||
|
onChanged: (value) => _onDigitChanged(i, value),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import 'package:design_system/design_system.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:navigation/navigation.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
|
|
||||||
class PhoneCodeScreen extends ConsumerWidget {
|
|
||||||
final NavigationContract navigationContract;
|
|
||||||
|
|
||||||
PhoneCodeScreen({super.key, required this.navigationContract});
|
|
||||||
|
|
||||||
final focusNodes = List<FocusNode>.generate(6, (int i) {
|
|
||||||
return FocusNode();
|
|
||||||
});
|
|
||||||
|
|
||||||
@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: Expanded(
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
spacing: 48,
|
|
||||||
children: [
|
|
||||||
Spacer(flex: 8),
|
|
||||||
Column(
|
|
||||||
spacing: 24,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Conéctate",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 30,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: "Hemos enviado el código al ",
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
// text: widget.phone,
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text("Introduce el código aquí"),
|
|
||||||
Row(
|
|
||||||
spacing: 8,
|
|
||||||
children: List<Widget>.generate(6, (int i) {
|
|
||||||
return Expanded(
|
|
||||||
child: TextField(
|
|
||||||
focusNode: focusNodes[i],
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter.digitsOnly,
|
|
||||||
],
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: "0",
|
|
||||||
counterText: "",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
maxLength: 1,
|
|
||||||
onChanged: (String value) => {
|
|
||||||
value != ""
|
|
||||||
? focusNodes[i + 1].requestFocus()
|
|
||||||
: focusNodes[i - 1].requestFocus(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
spacing: 24,
|
|
||||||
children: [
|
|
||||||
PrimaryButton(
|
|
||||||
onPressed: () => {
|
|
||||||
navigationContract.pushTo(AppRoutes.login),
|
|
||||||
},
|
|
||||||
text: "Entrar",
|
|
||||||
color: theme.getColorFor(ThemeCode.buttonPrimary),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"¿No lo has recibido?",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
letterSpacing: 0,
|
|
||||||
height: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CustomTextButton(
|
|
||||||
onPressed: () => {},
|
|
||||||
text: "Volver a intentarlo",
|
|
||||||
size: 18,
|
|
||||||
weight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Spacer(flex: 10),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ class CountryPrefixPicker extends StatelessWidget {
|
|||||||
const CountryPrefixPicker({
|
const CountryPrefixPicker({
|
||||||
super.key,
|
super.key,
|
||||||
required this.onChanged,
|
required this.onChanged,
|
||||||
|
required this.headerText,
|
||||||
this.initialCountryCode = '+34',
|
this.initialCountryCode = '+34',
|
||||||
this.radius = 12,
|
this.radius = 12,
|
||||||
this.width = 90,
|
this.width = 90,
|
||||||
@@ -15,7 +16,7 @@ class CountryPrefixPicker extends StatelessWidget {
|
|||||||
|
|
||||||
final ValueChanged<CountryCode> onChanged;
|
final ValueChanged<CountryCode> onChanged;
|
||||||
final String initialCountryCode;
|
final String initialCountryCode;
|
||||||
|
final String headerText;
|
||||||
final double radius;
|
final double radius;
|
||||||
final double width;
|
final double width;
|
||||||
final double height;
|
final double height;
|
||||||
@@ -28,6 +29,7 @@ class CountryPrefixPicker extends StatelessWidget {
|
|||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
child: CountryCodePicker(
|
child: CountryCodePicker(
|
||||||
|
headerText: headerText,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
initialSelection: initialCountryCode,
|
initialSelection: initialCountryCode,
|
||||||
showFlag: false,
|
showFlag: false,
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class CustomTextFieldState extends State<CustomTextField> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
|
controller: widget.controller,
|
||||||
keyboardType: widget.numeric
|
keyboardType: widget.numeric
|
||||||
? TextInputType.number
|
? TextInputType.number
|
||||||
: TextInputType.text,
|
: TextInputType.text,
|
||||||
|
|||||||
31
packages/fonts/.dart_tool/extension_discovery/README.md
Normal file
31
packages/fonts/.dart_tool/extension_discovery/README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
Extension Discovery Cache
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This folder is used by `package:extension_discovery` to cache lists of
|
||||||
|
packages that contains extensions for other packages.
|
||||||
|
|
||||||
|
DO NOT USE THIS FOLDER
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
* Do not read (or rely) the contents of this folder.
|
||||||
|
* Do write to this folder.
|
||||||
|
|
||||||
|
If you're interested in the lists of extensions stored in this folder use the
|
||||||
|
API offered by package `extension_discovery` to get this information.
|
||||||
|
|
||||||
|
If this package doesn't work for your use-case, then don't try to read the
|
||||||
|
contents of this folder. It may change, and will not remain stable.
|
||||||
|
|
||||||
|
Use package `extension_discovery`
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
If you want to access information from this folder.
|
||||||
|
|
||||||
|
Feel free to delete this folder
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Files in this folder act as a cache, and the cache is discarded if the files
|
||||||
|
are older than the modification time of `.dart_tool/package_config.json`.
|
||||||
|
|
||||||
|
Hence, it should never be necessary to clear this cache manually, if you find a
|
||||||
|
need to do please file a bug.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":2,"entries":[{"package":"fonts","rootUri":"../","packageUri":"lib/"}]}
|
||||||
@@ -2,8 +2,8 @@ class AppRoutes {
|
|||||||
static const login = '/login';
|
static const login = '/login';
|
||||||
static const signup = '/signup';
|
static const signup = '/signup';
|
||||||
static const onboarding = '/onboarding';
|
static const onboarding = '/onboarding';
|
||||||
static const linkPhone = '/link_phone';
|
static const linkPhone = '/request_link_phone';
|
||||||
static const phoneCode = '/phone_code';
|
static const phoneCode = '/verify_link_phone_code';
|
||||||
static const deviceSignup = '/device_signup';
|
static const deviceSignup = '/device_signup';
|
||||||
static const recoverPassword = '/recover_password';
|
static const recoverPassword = '/recover_password';
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Future<void> configureDependencies(EnvConfig env, {bool log = false}) async {
|
|||||||
getIt.registerLazySingleton<Dio>(
|
getIt.registerLazySingleton<Dio>(
|
||||||
() => buildDioClient(
|
() => buildDioClient(
|
||||||
baseUrl: env.apiBaseUrl,
|
baseUrl: env.apiBaseUrl,
|
||||||
|
origin: env.apiOrigin,
|
||||||
// apiKey: env.apiKey,
|
// apiKey: env.apiKey,
|
||||||
log: log,
|
log: log,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
abstract class EnvConfig {
|
abstract class EnvConfig {
|
||||||
String get apiBaseUrl;
|
String get apiBaseUrl;
|
||||||
|
String get apiOrigin;
|
||||||
// String get apiKey;
|
// String get apiKey;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:dio/dio.dart';
|
|||||||
|
|
||||||
Dio buildDioClient({
|
Dio buildDioClient({
|
||||||
required String baseUrl,
|
required String baseUrl,
|
||||||
|
required String origin,
|
||||||
// required String apiKey,
|
// required String apiKey,
|
||||||
bool log = false,
|
bool log = false,
|
||||||
}) {
|
}) {
|
||||||
@@ -15,6 +16,7 @@ Dio buildDioClient({
|
|||||||
// if (apiKey.isNotEmpty) 'x-api-key': apiKey,
|
// if (apiKey.isNotEmpty) 'x-api-key': apiKey,
|
||||||
'accept': 'application/json',
|
'accept': 'application/json',
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
|
'origin': origin,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,5 +12,13 @@
|
|||||||
"linkPhoneTitle": "Wir freuen uns sehr, dass du hier bist!",
|
"linkPhoneTitle": "Wir freuen uns sehr, dass du hier bist!",
|
||||||
"linkPhoneSubtitle": "Um dich sicher anzumelden, senden wir dir einen Code an deine Telefonnummer",
|
"linkPhoneSubtitle": "Um dich sicher anzumelden, senden wir dir einen Code an deine Telefonnummer",
|
||||||
"mobilePhone": "Mobiltelefon",
|
"mobilePhone": "Mobiltelefon",
|
||||||
"phoneNumber": "Telefonnummer"
|
"phoneNumber": "Telefonnummer",
|
||||||
|
"selectYourCountry": "Wähle dein Land",
|
||||||
|
"errorMessagePhoneIsEmpty": "Die Telefonnummer darf nicht leer sein",
|
||||||
|
"connect": "Verbinden",
|
||||||
|
"verificationCodeSentTo": "Wir haben den Code an ",
|
||||||
|
"enterCodeHere": "Gib den Code hier ein",
|
||||||
|
"enter": "Weiter",
|
||||||
|
"didNotReceiveIt": "Hast du es nicht erhalten?",
|
||||||
|
"tryAgain": "Erneut versuchen"
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,13 @@
|
|||||||
"linkPhoneTitle": "We're really happy to have you here!",
|
"linkPhoneTitle": "We're really happy to have you here!",
|
||||||
"linkPhoneSubtitle": "To sign in securely, we'll send a code to your phone number",
|
"linkPhoneSubtitle": "To sign in securely, we'll send a code to your phone number",
|
||||||
"mobilePhone": "Mobile phone",
|
"mobilePhone": "Mobile phone",
|
||||||
"phoneNumber": "Phone number"
|
"phoneNumber": "Phone number",
|
||||||
|
"selectYourCountry": "Select your country",
|
||||||
|
"errorMessagePhoneIsEmpty": "Phone number cannot be empty",
|
||||||
|
"connect": "Connect",
|
||||||
|
"verificationCodeSentTo": "We have sent the code to ",
|
||||||
|
"enterCodeHere": "Enter the code here",
|
||||||
|
"enter": "Enter",
|
||||||
|
"didNotReceiveIt": "Didn't receive it?",
|
||||||
|
"tryAgain": "Try again"
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,13 @@
|
|||||||
"linkPhoneTitle": "¡Nos alegra mucho tenerte por aquí!",
|
"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, te vamos a enviar un código al teléfono",
|
||||||
"mobilePhone": "Teléfono móvil",
|
"mobilePhone": "Teléfono móvil",
|
||||||
"phoneNumber": "Teléfono"
|
"phoneNumber": "Teléfono",
|
||||||
|
"selectYourCountry": "Selecciona tu país",
|
||||||
|
"errorMessagePhoneIsEmpty": "El número de teléfono no puede estar vacío",
|
||||||
|
"connect": "Conéctate",
|
||||||
|
"verificationCodeSentTo": "Hemos enviado el código al ",
|
||||||
|
"enterCodeHere": "Introduce el código aquí",
|
||||||
|
"enter": "enter",
|
||||||
|
"didNotReceiveIt": "¿No lo has recibido?",
|
||||||
|
"tryAgain": "Volver a intentarlo"
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,13 @@
|
|||||||
"linkPhoneTitle": "Nous sommes ravis de te compter parmi nous !",
|
"linkPhoneTitle": "Nous sommes ravis de te compter parmi nous !",
|
||||||
"linkPhoneSubtitle": "Pour te connecter en toute sécurité, nous allons envoyer un code sur ton téléphone",
|
"linkPhoneSubtitle": "Pour te connecter en toute sécurité, nous allons envoyer un code sur ton téléphone",
|
||||||
"mobilePhone": "Téléphone portable",
|
"mobilePhone": "Téléphone portable",
|
||||||
"phoneNumber": "Numéro de téléphone"
|
"phoneNumber": "Numéro de téléphone",
|
||||||
|
"selectYourCountry": "Sélectionne ton pays",
|
||||||
|
"errorMessagePhoneIsEmpty": "Le numéro de téléphone ne peut pas être vide",
|
||||||
|
"connect": "Connecter",
|
||||||
|
"verificationCodeSentTo": "Nous avons envoyé le code à ",
|
||||||
|
"enterCodeHere": "Saisissez le code ici",
|
||||||
|
"enter": "Entrer",
|
||||||
|
"didNotReceiveIt": "Tu ne l'as pas reçu ?",
|
||||||
|
"tryAgain": "Réessayer"
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,13 @@
|
|||||||
"linkPhoneTitle": "Siamo molto felici di averti qui!",
|
"linkPhoneTitle": "Siamo molto felici di averti qui!",
|
||||||
"linkPhoneSubtitle": "Per accedere in modo sicuro, ti invieremo un codice al tuo telefono",
|
"linkPhoneSubtitle": "Per accedere in modo sicuro, ti invieremo un codice al tuo telefono",
|
||||||
"mobilePhone": "Telefono cellulare",
|
"mobilePhone": "Telefono cellulare",
|
||||||
"phoneNumber": "Numero di telefono"
|
"phoneNumber": "Numero di telefono",
|
||||||
|
"selectYourCountry": "Seleziona il tuo paese",
|
||||||
|
"errorMessagePhoneIsEmpty": "Il numero di telefono non può essere vuoto",
|
||||||
|
"connect": "Collegare",
|
||||||
|
"verificationCodeSentTo": "Abbiamo inviato il codice a ",
|
||||||
|
"enterCodeHere": "Inserisci il codice qui",
|
||||||
|
"enter": "Entra",
|
||||||
|
"didNotReceiveIt": "Non lo hai ricevuto?",
|
||||||
|
"tryAgain": "Riprova"
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,13 @@
|
|||||||
"linkPhoneTitle": "Ficamos muito felizes em ter você aqui!",
|
"linkPhoneTitle": "Ficamos muito felizes em ter você aqui!",
|
||||||
"linkPhoneSubtitle": "Para entrar com segurança, vamos enviar um código para o seu telefone",
|
"linkPhoneSubtitle": "Para entrar com segurança, vamos enviar um código para o seu telefone",
|
||||||
"mobilePhone": "Telefone celular",
|
"mobilePhone": "Telefone celular",
|
||||||
"phoneNumber": "Número de telefone"
|
"phoneNumber": "Número de telefone",
|
||||||
|
"selectYourCountry": "Selecione seu país",
|
||||||
|
"errorMessagePhoneIsEmpty": "O número de telefone não pode estar vazio",
|
||||||
|
"connect": "Conectar",
|
||||||
|
"verificationCodeSentTo": "Enviamos o código para ",
|
||||||
|
"enterCodeHere": "Insira o código aqui",
|
||||||
|
"enter": "Entrar",
|
||||||
|
"didNotReceiveIt": "Você não recebeu?",
|
||||||
|
"tryAgain": "Tentar novamente"
|
||||||
}
|
}
|
||||||
@@ -17,4 +17,12 @@ class I18n {
|
|||||||
static const String linkPhoneSubtitle = 'linkPhoneSubtitle';
|
static const String linkPhoneSubtitle = 'linkPhoneSubtitle';
|
||||||
static const String mobilePhone = 'mobilePhone';
|
static const String mobilePhone = 'mobilePhone';
|
||||||
static const String phoneNumber = 'phoneNumber';
|
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";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user