refactor(login): type auth errors with status-code-based enum
Replace the raw errorMessage string in the login view state with a typed LegacyAuthErrorEvent that classifies backend failures by HTTP status (403/404 → invalidCredentials, 423 → accountLocked, 401 + NOT_VERIFIED/expired → dedicated events, 429 → tooManyAttempts, timeout → network). The login screen and 2FA sheet now switch on the enum to show specific i18n messages instead of surfacing raw backend text. Adds auth i18n keys for the full set of mapped states.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
||||
|
||||
enum LegacyAuthErrorEvent {
|
||||
invalidCredentials,
|
||||
accountLocked,
|
||||
accountNotVerified,
|
||||
passwordExpired,
|
||||
invalidCode,
|
||||
invalidToken,
|
||||
tooManyAttempts,
|
||||
noMethodsAvailable,
|
||||
network,
|
||||
generic,
|
||||
}
|
||||
|
||||
LegacyAuthErrorEvent mapLoginError(Object error) {
|
||||
if (error is! ApiException) return LegacyAuthErrorEvent.generic;
|
||||
if (error.isNetworkError) return LegacyAuthErrorEvent.network;
|
||||
|
||||
final message = error.message;
|
||||
switch (error.statusCode) {
|
||||
case 403:
|
||||
case 404:
|
||||
return LegacyAuthErrorEvent.invalidCredentials;
|
||||
case 423:
|
||||
return LegacyAuthErrorEvent.accountLocked;
|
||||
case 401:
|
||||
if (message.contains('NOT_VERIFIED')) {
|
||||
return LegacyAuthErrorEvent.accountNotVerified;
|
||||
}
|
||||
if (message.toLowerCase().contains('expired')) {
|
||||
return LegacyAuthErrorEvent.passwordExpired;
|
||||
}
|
||||
return LegacyAuthErrorEvent.invalidCredentials;
|
||||
case 429:
|
||||
return LegacyAuthErrorEvent.tooManyAttempts;
|
||||
default:
|
||||
return LegacyAuthErrorEvent.generic;
|
||||
}
|
||||
}
|
||||
|
||||
LegacyAuthErrorEvent mapTwoFactorError(Object error) {
|
||||
if (error is! ApiException) return LegacyAuthErrorEvent.generic;
|
||||
if (error.isNetworkError) return LegacyAuthErrorEvent.network;
|
||||
|
||||
switch (error.statusCode) {
|
||||
case 400:
|
||||
return LegacyAuthErrorEvent.invalidToken;
|
||||
case 401:
|
||||
return LegacyAuthErrorEvent.invalidCode;
|
||||
case 429:
|
||||
return LegacyAuthErrorEvent.tooManyAttempts;
|
||||
default:
|
||||
return LegacyAuthErrorEvent.generic;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:legacy_auth/src/features/login/domain/entities/legacy_auth_error_event.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/state/login_view_model.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/widgets/field_error_text.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/widgets/two_factor_sheet_launcher.dart';
|
||||
@@ -7,6 +8,21 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:navigation/navigation.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
|
||||
String _authErrorI18nKey(LegacyAuthErrorEvent event) {
|
||||
return switch (event) {
|
||||
LegacyAuthErrorEvent.invalidCredentials => I18n.authErrorInvalidCredentials,
|
||||
LegacyAuthErrorEvent.accountLocked => I18n.authErrorAccountLocked,
|
||||
LegacyAuthErrorEvent.accountNotVerified => I18n.authErrorAccountNotVerified,
|
||||
LegacyAuthErrorEvent.passwordExpired => I18n.authErrorPasswordExpired,
|
||||
LegacyAuthErrorEvent.invalidCode => I18n.errorTwoFactorCodeInvalid,
|
||||
LegacyAuthErrorEvent.invalidToken => I18n.authErrorInvalidToken,
|
||||
LegacyAuthErrorEvent.tooManyAttempts => I18n.authErrorTooManyAttempts,
|
||||
LegacyAuthErrorEvent.noMethodsAvailable => I18n.errorTwoFactorNoMethods,
|
||||
LegacyAuthErrorEvent.network => I18n.authErrorNetwork,
|
||||
LegacyAuthErrorEvent.generic => I18n.errorGeneric,
|
||||
};
|
||||
}
|
||||
|
||||
class LegacyLoginScreen extends ConsumerWidget {
|
||||
final NavigationContract navigationContract;
|
||||
|
||||
@@ -22,19 +38,21 @@ class LegacyLoginScreen extends ConsumerWidget {
|
||||
ref.listen(
|
||||
legacyLoginViewModelProvider.select(
|
||||
(s) => (
|
||||
error: s.errorMessage,
|
||||
errorEvent: s.errorEvent,
|
||||
twoFA: s.twoFARequested,
|
||||
verified: s.twoFAVerified,
|
||||
hasDevices: s.hasDevices,
|
||||
),
|
||||
),
|
||||
(previous, next) {
|
||||
if (next.error.isNotEmpty && !next.twoFA) {
|
||||
final errorEvent = next.errorEvent;
|
||||
if (errorEvent != null && !next.twoFA) {
|
||||
showTopSnackbar(
|
||||
context,
|
||||
message: context.translate(next.error),
|
||||
message: context.translate(_authErrorI18nKey(errorEvent)),
|
||||
type: MessageType.error,
|
||||
);
|
||||
ref.read(legacyLoginViewModelProvider.notifier).clearErrorEvent();
|
||||
}
|
||||
if (next.twoFA && previous?.twoFA != true) {
|
||||
showTwoFactorSheet(context);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:legacy_auth/src/core/domain/repositories/login_repository.dart';
|
||||
import 'package:legacy_auth/src/core/providers/login_repository_provider.dart';
|
||||
import 'package:legacy_auth/src/features/login/domain/entities/legacy_auth_error_event.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/mixins/login_form_validation.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/state/login_view_state.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@@ -52,7 +53,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
if (value == state.email) return;
|
||||
state = state.copyWith(
|
||||
email: value,
|
||||
errorMessage: '',
|
||||
errorEvent: null,
|
||||
emailError: state.showErrors ? validateEmail(value) : state.emailError,
|
||||
);
|
||||
}
|
||||
@@ -62,7 +63,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
if (value == state.password) return;
|
||||
state = state.copyWith(
|
||||
password: value,
|
||||
errorMessage: '',
|
||||
errorEvent: null,
|
||||
passwordError: state.showErrors
|
||||
? validatePassword(value)
|
||||
: state.passwordError,
|
||||
@@ -81,6 +82,10 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
state = state.copyWith(passwordVisible: !state.passwordVisible);
|
||||
}
|
||||
|
||||
void clearErrorEvent() {
|
||||
if (state.errorEvent != null) state = state.copyWith(errorEvent: null);
|
||||
}
|
||||
|
||||
bool _validateForm() {
|
||||
final emailError = validateEmail(state.email);
|
||||
final passwordError = validatePassword(state.password);
|
||||
@@ -89,7 +94,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
showErrors: true,
|
||||
emailError: emailError,
|
||||
passwordError: passwordError,
|
||||
errorMessage: '',
|
||||
errorEvent: null,
|
||||
);
|
||||
|
||||
return emailError.isEmpty && passwordError.isEmpty;
|
||||
@@ -131,7 +136,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: formatErrorMessage(e),
|
||||
errorEvent: mapLoginError(e),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -150,7 +155,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
Future<void> _requestTwoFACode({bool updateLoading = false}) async {
|
||||
if (state.availableMethods.isEmpty) {
|
||||
state = state.copyWith(
|
||||
errorMessage: 'No 2FA methods available',
|
||||
errorEvent: LegacyAuthErrorEvent.noMethodsAvailable,
|
||||
isLoading: updateLoading ? false : state.isLoading,
|
||||
);
|
||||
return;
|
||||
@@ -175,7 +180,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
if (!ref.mounted) return;
|
||||
|
||||
state = state.copyWith(
|
||||
errorMessage: formatErrorMessage(e),
|
||||
errorEvent: mapTwoFactorError(e),
|
||||
isLoading: updateLoading ? false : state.isLoading,
|
||||
);
|
||||
}
|
||||
@@ -209,7 +214,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
orElse: () => state.availableMethods.first,
|
||||
);
|
||||
|
||||
state = state.copyWith(isLoading: true, errorMessage: '', codeError: '');
|
||||
state = state.copyWith(isLoading: true, errorEvent: null, codeError: '');
|
||||
|
||||
try {
|
||||
await _repository.twoFASendCode(
|
||||
@@ -248,7 +253,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: formatErrorMessage(e),
|
||||
errorEvent: mapTwoFactorError(e),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:legacy_auth/src/features/login/domain/entities/legacy_auth_error_event.dart';
|
||||
import 'package:legacy_auth/src/features/login/domain/entities/login_response_entity.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@@ -11,7 +12,7 @@ abstract class LegacyLoginViewState with _$LegacyLoginViewState {
|
||||
@Default(false) bool passwordVisible,
|
||||
@Default('') String emailError,
|
||||
@Default('') String passwordError,
|
||||
@Default('') String errorMessage,
|
||||
LegacyAuthErrorEvent? errorEvent,
|
||||
@Default(false) bool showErrors,
|
||||
@Default(false) bool isLoading,
|
||||
@Default(<LegacyAvailableMethodEntity>[])
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$LegacyLoginViewState {
|
||||
|
||||
String get email; String get password; bool get passwordVisible; String get emailError; String get passwordError; String get errorMessage; bool get showErrors; bool get isLoading; List<LegacyAvailableMethodEntity> get availableMethods; String get token; bool get twoFARequested; String get code; String get codeError; int get resendCooldown; bool get twoFAVerified; bool get hasDevices;
|
||||
String get email; String get password; bool get passwordVisible; String get emailError; String get passwordError; LegacyAuthErrorEvent? get errorEvent; bool get showErrors; bool get isLoading; List<LegacyAvailableMethodEntity> get availableMethods; String get token; bool get twoFARequested; String get code; String get codeError; int get resendCooldown; bool get twoFAVerified; bool get hasDevices;
|
||||
/// Create a copy of LegacyLoginViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $LegacyLoginViewStateCopyWith<LegacyLoginViewState> get copyWith => _$LegacyLogi
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is LegacyLoginViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.password, password) || other.password == password)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.emailError, emailError) || other.emailError == emailError)&&(identical(other.passwordError, passwordError) || other.passwordError == passwordError)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.showErrors, showErrors) || other.showErrors == showErrors)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&const DeepCollectionEquality().equals(other.availableMethods, availableMethods)&&(identical(other.token, token) || other.token == token)&&(identical(other.twoFARequested, twoFARequested) || other.twoFARequested == twoFARequested)&&(identical(other.code, code) || other.code == code)&&(identical(other.codeError, codeError) || other.codeError == codeError)&&(identical(other.resendCooldown, resendCooldown) || other.resendCooldown == resendCooldown)&&(identical(other.twoFAVerified, twoFAVerified) || other.twoFAVerified == twoFAVerified)&&(identical(other.hasDevices, hasDevices) || other.hasDevices == hasDevices));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is LegacyLoginViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.password, password) || other.password == password)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.emailError, emailError) || other.emailError == emailError)&&(identical(other.passwordError, passwordError) || other.passwordError == passwordError)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.showErrors, showErrors) || other.showErrors == showErrors)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&const DeepCollectionEquality().equals(other.availableMethods, availableMethods)&&(identical(other.token, token) || other.token == token)&&(identical(other.twoFARequested, twoFARequested) || other.twoFARequested == twoFARequested)&&(identical(other.code, code) || other.code == code)&&(identical(other.codeError, codeError) || other.codeError == codeError)&&(identical(other.resendCooldown, resendCooldown) || other.resendCooldown == resendCooldown)&&(identical(other.twoFAVerified, twoFAVerified) || other.twoFAVerified == twoFAVerified)&&(identical(other.hasDevices, hasDevices) || other.hasDevices == hasDevices));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,email,password,passwordVisible,emailError,passwordError,errorMessage,showErrors,isLoading,const DeepCollectionEquality().hash(availableMethods),token,twoFARequested,code,codeError,resendCooldown,twoFAVerified,hasDevices);
|
||||
int get hashCode => Object.hash(runtimeType,email,password,passwordVisible,emailError,passwordError,errorEvent,showErrors,isLoading,const DeepCollectionEquality().hash(availableMethods),token,twoFARequested,code,codeError,resendCooldown,twoFAVerified,hasDevices);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LegacyLoginViewState(email: $email, password: $password, passwordVisible: $passwordVisible, emailError: $emailError, passwordError: $passwordError, errorMessage: $errorMessage, showErrors: $showErrors, isLoading: $isLoading, availableMethods: $availableMethods, token: $token, twoFARequested: $twoFARequested, code: $code, codeError: $codeError, resendCooldown: $resendCooldown, twoFAVerified: $twoFAVerified, hasDevices: $hasDevices)';
|
||||
return 'LegacyLoginViewState(email: $email, password: $password, passwordVisible: $passwordVisible, emailError: $emailError, passwordError: $passwordError, errorEvent: $errorEvent, showErrors: $showErrors, isLoading: $isLoading, availableMethods: $availableMethods, token: $token, twoFARequested: $twoFARequested, code: $code, codeError: $codeError, resendCooldown: $resendCooldown, twoFAVerified: $twoFAVerified, hasDevices: $hasDevices)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract mixin class $LegacyLoginViewStateCopyWith<$Res> {
|
||||
factory $LegacyLoginViewStateCopyWith(LegacyLoginViewState value, $Res Function(LegacyLoginViewState) _then) = _$LegacyLoginViewStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String email, String password, bool passwordVisible, String emailError, String passwordError, String errorMessage, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices
|
||||
String email, String password, bool passwordVisible, String emailError, String passwordError, LegacyAuthErrorEvent? errorEvent, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices
|
||||
});
|
||||
|
||||
|
||||
@@ -62,15 +62,15 @@ class _$LegacyLoginViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of LegacyLoginViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? email = null,Object? password = null,Object? passwordVisible = null,Object? emailError = null,Object? passwordError = null,Object? errorMessage = null,Object? showErrors = null,Object? isLoading = null,Object? availableMethods = null,Object? token = null,Object? twoFARequested = null,Object? code = null,Object? codeError = null,Object? resendCooldown = null,Object? twoFAVerified = null,Object? hasDevices = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? email = null,Object? password = null,Object? passwordVisible = null,Object? emailError = null,Object? passwordError = null,Object? errorEvent = freezed,Object? showErrors = null,Object? isLoading = null,Object? availableMethods = null,Object? token = null,Object? twoFARequested = null,Object? code = null,Object? codeError = null,Object? resendCooldown = null,Object? twoFAVerified = null,Object? hasDevices = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable
|
||||
as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable
|
||||
as String,passwordVisible: null == passwordVisible ? _self.passwordVisible : passwordVisible // ignore: cast_nullable_to_non_nullable
|
||||
as bool,emailError: null == emailError ? _self.emailError : emailError // ignore: cast_nullable_to_non_nullable
|
||||
as String,passwordError: null == passwordError ? _self.passwordError : passwordError // ignore: cast_nullable_to_non_nullable
|
||||
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,showErrors: null == showErrors ? _self.showErrors : showErrors // ignore: cast_nullable_to_non_nullable
|
||||
as String,errorEvent: freezed == errorEvent ? _self.errorEvent : errorEvent // ignore: cast_nullable_to_non_nullable
|
||||
as LegacyAuthErrorEvent?,showErrors: null == showErrors ? _self.showErrors : showErrors // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,availableMethods: null == availableMethods ? _self.availableMethods : availableMethods // ignore: cast_nullable_to_non_nullable
|
||||
as List<LegacyAvailableMethodEntity>,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
@@ -165,10 +165,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String email, String password, bool passwordVisible, String emailError, String passwordError, String errorMessage, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String email, String password, bool passwordVisible, String emailError, String passwordError, LegacyAuthErrorEvent? errorEvent, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LegacyLoginViewState() when $default != null:
|
||||
return $default(_that.email,_that.password,_that.passwordVisible,_that.emailError,_that.passwordError,_that.errorMessage,_that.showErrors,_that.isLoading,_that.availableMethods,_that.token,_that.twoFARequested,_that.code,_that.codeError,_that.resendCooldown,_that.twoFAVerified,_that.hasDevices);case _:
|
||||
return $default(_that.email,_that.password,_that.passwordVisible,_that.emailError,_that.passwordError,_that.errorEvent,_that.showErrors,_that.isLoading,_that.availableMethods,_that.token,_that.twoFARequested,_that.code,_that.codeError,_that.resendCooldown,_that.twoFAVerified,_that.hasDevices);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -186,10 +186,10 @@ return $default(_that.email,_that.password,_that.passwordVisible,_that.emailErro
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String email, String password, bool passwordVisible, String emailError, String passwordError, String errorMessage, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String email, String password, bool passwordVisible, String emailError, String passwordError, LegacyAuthErrorEvent? errorEvent, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LegacyLoginViewState():
|
||||
return $default(_that.email,_that.password,_that.passwordVisible,_that.emailError,_that.passwordError,_that.errorMessage,_that.showErrors,_that.isLoading,_that.availableMethods,_that.token,_that.twoFARequested,_that.code,_that.codeError,_that.resendCooldown,_that.twoFAVerified,_that.hasDevices);case _:
|
||||
return $default(_that.email,_that.password,_that.passwordVisible,_that.emailError,_that.passwordError,_that.errorEvent,_that.showErrors,_that.isLoading,_that.availableMethods,_that.token,_that.twoFARequested,_that.code,_that.codeError,_that.resendCooldown,_that.twoFAVerified,_that.hasDevices);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -206,10 +206,10 @@ return $default(_that.email,_that.password,_that.passwordVisible,_that.emailErro
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String email, String password, bool passwordVisible, String emailError, String passwordError, String errorMessage, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String email, String password, bool passwordVisible, String emailError, String passwordError, LegacyAuthErrorEvent? errorEvent, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LegacyLoginViewState() when $default != null:
|
||||
return $default(_that.email,_that.password,_that.passwordVisible,_that.emailError,_that.passwordError,_that.errorMessage,_that.showErrors,_that.isLoading,_that.availableMethods,_that.token,_that.twoFARequested,_that.code,_that.codeError,_that.resendCooldown,_that.twoFAVerified,_that.hasDevices);case _:
|
||||
return $default(_that.email,_that.password,_that.passwordVisible,_that.emailError,_that.passwordError,_that.errorEvent,_that.showErrors,_that.isLoading,_that.availableMethods,_that.token,_that.twoFARequested,_that.code,_that.codeError,_that.resendCooldown,_that.twoFAVerified,_that.hasDevices);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -221,7 +221,7 @@ return $default(_that.email,_that.password,_that.passwordVisible,_that.emailErro
|
||||
|
||||
|
||||
class _LegacyLoginViewState implements LegacyLoginViewState {
|
||||
const _LegacyLoginViewState({this.email = '', this.password = '', this.passwordVisible = false, this.emailError = '', this.passwordError = '', this.errorMessage = '', this.showErrors = false, this.isLoading = false, final List<LegacyAvailableMethodEntity> availableMethods = const <LegacyAvailableMethodEntity>[], this.token = '', this.twoFARequested = false, this.code = '', this.codeError = '', this.resendCooldown = 0, this.twoFAVerified = false, this.hasDevices = false}): _availableMethods = availableMethods;
|
||||
const _LegacyLoginViewState({this.email = '', this.password = '', this.passwordVisible = false, this.emailError = '', this.passwordError = '', this.errorEvent, this.showErrors = false, this.isLoading = false, final List<LegacyAvailableMethodEntity> availableMethods = const <LegacyAvailableMethodEntity>[], this.token = '', this.twoFARequested = false, this.code = '', this.codeError = '', this.resendCooldown = 0, this.twoFAVerified = false, this.hasDevices = false}): _availableMethods = availableMethods;
|
||||
|
||||
|
||||
@override@JsonKey() final String email;
|
||||
@@ -229,7 +229,7 @@ class _LegacyLoginViewState implements LegacyLoginViewState {
|
||||
@override@JsonKey() final bool passwordVisible;
|
||||
@override@JsonKey() final String emailError;
|
||||
@override@JsonKey() final String passwordError;
|
||||
@override@JsonKey() final String errorMessage;
|
||||
@override final LegacyAuthErrorEvent? errorEvent;
|
||||
@override@JsonKey() final bool showErrors;
|
||||
@override@JsonKey() final bool isLoading;
|
||||
final List<LegacyAvailableMethodEntity> _availableMethods;
|
||||
@@ -257,16 +257,16 @@ _$LegacyLoginViewStateCopyWith<_LegacyLoginViewState> get copyWith => __$LegacyL
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LegacyLoginViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.password, password) || other.password == password)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.emailError, emailError) || other.emailError == emailError)&&(identical(other.passwordError, passwordError) || other.passwordError == passwordError)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.showErrors, showErrors) || other.showErrors == showErrors)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&const DeepCollectionEquality().equals(other._availableMethods, _availableMethods)&&(identical(other.token, token) || other.token == token)&&(identical(other.twoFARequested, twoFARequested) || other.twoFARequested == twoFARequested)&&(identical(other.code, code) || other.code == code)&&(identical(other.codeError, codeError) || other.codeError == codeError)&&(identical(other.resendCooldown, resendCooldown) || other.resendCooldown == resendCooldown)&&(identical(other.twoFAVerified, twoFAVerified) || other.twoFAVerified == twoFAVerified)&&(identical(other.hasDevices, hasDevices) || other.hasDevices == hasDevices));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LegacyLoginViewState&&(identical(other.email, email) || other.email == email)&&(identical(other.password, password) || other.password == password)&&(identical(other.passwordVisible, passwordVisible) || other.passwordVisible == passwordVisible)&&(identical(other.emailError, emailError) || other.emailError == emailError)&&(identical(other.passwordError, passwordError) || other.passwordError == passwordError)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.showErrors, showErrors) || other.showErrors == showErrors)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&const DeepCollectionEquality().equals(other._availableMethods, _availableMethods)&&(identical(other.token, token) || other.token == token)&&(identical(other.twoFARequested, twoFARequested) || other.twoFARequested == twoFARequested)&&(identical(other.code, code) || other.code == code)&&(identical(other.codeError, codeError) || other.codeError == codeError)&&(identical(other.resendCooldown, resendCooldown) || other.resendCooldown == resendCooldown)&&(identical(other.twoFAVerified, twoFAVerified) || other.twoFAVerified == twoFAVerified)&&(identical(other.hasDevices, hasDevices) || other.hasDevices == hasDevices));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,email,password,passwordVisible,emailError,passwordError,errorMessage,showErrors,isLoading,const DeepCollectionEquality().hash(_availableMethods),token,twoFARequested,code,codeError,resendCooldown,twoFAVerified,hasDevices);
|
||||
int get hashCode => Object.hash(runtimeType,email,password,passwordVisible,emailError,passwordError,errorEvent,showErrors,isLoading,const DeepCollectionEquality().hash(_availableMethods),token,twoFARequested,code,codeError,resendCooldown,twoFAVerified,hasDevices);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LegacyLoginViewState(email: $email, password: $password, passwordVisible: $passwordVisible, emailError: $emailError, passwordError: $passwordError, errorMessage: $errorMessage, showErrors: $showErrors, isLoading: $isLoading, availableMethods: $availableMethods, token: $token, twoFARequested: $twoFARequested, code: $code, codeError: $codeError, resendCooldown: $resendCooldown, twoFAVerified: $twoFAVerified, hasDevices: $hasDevices)';
|
||||
return 'LegacyLoginViewState(email: $email, password: $password, passwordVisible: $passwordVisible, emailError: $emailError, passwordError: $passwordError, errorEvent: $errorEvent, showErrors: $showErrors, isLoading: $isLoading, availableMethods: $availableMethods, token: $token, twoFARequested: $twoFARequested, code: $code, codeError: $codeError, resendCooldown: $resendCooldown, twoFAVerified: $twoFAVerified, hasDevices: $hasDevices)';
|
||||
}
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ abstract mixin class _$LegacyLoginViewStateCopyWith<$Res> implements $LegacyLogi
|
||||
factory _$LegacyLoginViewStateCopyWith(_LegacyLoginViewState value, $Res Function(_LegacyLoginViewState) _then) = __$LegacyLoginViewStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String email, String password, bool passwordVisible, String emailError, String passwordError, String errorMessage, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices
|
||||
String email, String password, bool passwordVisible, String emailError, String passwordError, LegacyAuthErrorEvent? errorEvent, bool showErrors, bool isLoading, List<LegacyAvailableMethodEntity> availableMethods, String token, bool twoFARequested, String code, String codeError, int resendCooldown, bool twoFAVerified, bool hasDevices
|
||||
});
|
||||
|
||||
|
||||
@@ -294,15 +294,15 @@ class __$LegacyLoginViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of LegacyLoginViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? email = null,Object? password = null,Object? passwordVisible = null,Object? emailError = null,Object? passwordError = null,Object? errorMessage = null,Object? showErrors = null,Object? isLoading = null,Object? availableMethods = null,Object? token = null,Object? twoFARequested = null,Object? code = null,Object? codeError = null,Object? resendCooldown = null,Object? twoFAVerified = null,Object? hasDevices = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? email = null,Object? password = null,Object? passwordVisible = null,Object? emailError = null,Object? passwordError = null,Object? errorEvent = freezed,Object? showErrors = null,Object? isLoading = null,Object? availableMethods = null,Object? token = null,Object? twoFARequested = null,Object? code = null,Object? codeError = null,Object? resendCooldown = null,Object? twoFAVerified = null,Object? hasDevices = null,}) {
|
||||
return _then(_LegacyLoginViewState(
|
||||
email: null == email ? _self.email : email // ignore: cast_nullable_to_non_nullable
|
||||
as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable
|
||||
as String,passwordVisible: null == passwordVisible ? _self.passwordVisible : passwordVisible // ignore: cast_nullable_to_non_nullable
|
||||
as bool,emailError: null == emailError ? _self.emailError : emailError // ignore: cast_nullable_to_non_nullable
|
||||
as String,passwordError: null == passwordError ? _self.passwordError : passwordError // ignore: cast_nullable_to_non_nullable
|
||||
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,showErrors: null == showErrors ? _self.showErrors : showErrors // ignore: cast_nullable_to_non_nullable
|
||||
as String,errorEvent: freezed == errorEvent ? _self.errorEvent : errorEvent // ignore: cast_nullable_to_non_nullable
|
||||
as LegacyAuthErrorEvent?,showErrors: null == showErrors ? _self.showErrors : showErrors // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,availableMethods: null == availableMethods ? _self._availableMethods : availableMethods // ignore: cast_nullable_to_non_nullable
|
||||
as List<LegacyAvailableMethodEntity>,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:legacy_auth/src/features/login/domain/entities/legacy_auth_error_event.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/state/login_view_model.dart';
|
||||
import 'package:legacy_auth/src/features/login/presentation/widgets/two_factor_bottom_sheet.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
@@ -5,6 +6,17 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
|
||||
String _twoFactorErrorI18nKey(LegacyAuthErrorEvent event) {
|
||||
return switch (event) {
|
||||
LegacyAuthErrorEvent.invalidCode => I18n.errorTwoFactorCodeInvalid,
|
||||
LegacyAuthErrorEvent.invalidToken => I18n.authErrorInvalidToken,
|
||||
LegacyAuthErrorEvent.tooManyAttempts => I18n.authErrorTooManyAttempts,
|
||||
LegacyAuthErrorEvent.noMethodsAvailable => I18n.errorTwoFactorNoMethods,
|
||||
LegacyAuthErrorEvent.network => I18n.authErrorNetwork,
|
||||
_ => I18n.errorGeneric,
|
||||
};
|
||||
}
|
||||
|
||||
void showTwoFactorSheet(BuildContext context) {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
@@ -38,15 +50,19 @@ void showTwoFactorSheet(BuildContext context) {
|
||||
|
||||
ref.listen(
|
||||
legacyLoginViewModelProvider.select(
|
||||
(s) => (error: s.errorMessage, verified: s.twoFAVerified),
|
||||
(s) => (errorEvent: s.errorEvent, verified: s.twoFAVerified),
|
||||
),
|
||||
(previous, next) {
|
||||
if (next.error.isNotEmpty && next.error != previous?.error) {
|
||||
final errorEvent = next.errorEvent;
|
||||
if (errorEvent != null && errorEvent != previous?.errorEvent) {
|
||||
showTopSnackbar(
|
||||
sheetContext,
|
||||
message: sheetContext.translate(next.error),
|
||||
message: sheetContext.translate(
|
||||
_twoFactorErrorI18nKey(errorEvent),
|
||||
),
|
||||
type: MessageType.error,
|
||||
);
|
||||
ref.read(legacyLoginViewModelProvider.notifier).clearErrorEvent();
|
||||
}
|
||||
if (next.verified) {
|
||||
Navigator.of(sheetContext).pop();
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
"errorTwoFactorNoMethods": "Keine 2FA-Methoden verfügbar.",
|
||||
"errorTwoFactorResendFailed": "Fehler beim erneuten Senden des Codes.",
|
||||
"loginSuccess": "Anmeldung erfolgreich",
|
||||
"authErrorInvalidCredentials": "E-Mail oder Passwort ist falsch.",
|
||||
"authErrorAccountLocked": "Ihr Konto ist vorübergehend gesperrt. Versuchen Sie es später erneut.",
|
||||
"authErrorAccountNotVerified": "Ihr Konto ist noch nicht verifiziert. Bitte prüfen Sie Ihre E-Mails.",
|
||||
"authErrorPasswordExpired": "Ihr Passwort ist abgelaufen. Verwenden Sie 'Passwort vergessen', um es zurückzusetzen.",
|
||||
"authErrorInvalidToken": "Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",
|
||||
"authErrorTooManyAttempts": "Zu viele Versuche. Bitte warten Sie einige Minuten und versuchen Sie es erneut.",
|
||||
"authErrorNetwork": "Keine Verbindung. Überprüfen Sie Ihr Netzwerk und versuchen Sie es erneut.",
|
||||
"stepUserContactSupertitle": "Benutzer und Kontakt",
|
||||
"stepUserContactTitle": "Erstelle dein Konto",
|
||||
"stepUserContactSubtitle": "Mit deiner E-Mail und deiner Telefonnummer können wir dich jederzeit informieren",
|
||||
@@ -863,6 +870,7 @@
|
||||
"locateDeviceInstructions": "1. Drücken Sie die Schaltfläche Ton abspielen, um den Ton auf dem Gerät zu aktivieren.\n2. Drücken Sie OK\n3. Das Gerät spielt einen Ton ab\n4. Das Gerät beginnt nach Erhalt der Anweisungen zu klingeln",
|
||||
"mapTitle": "Karte",
|
||||
"logOut": "Abmelden",
|
||||
"logOutConfirm": "Möchten Sie sich wirklich abmelden?",
|
||||
"loginEmail": "(E-Mail)",
|
||||
"makeFriends": "Freunde finden",
|
||||
"male": "Männlich",
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
"errorTwoFactorNoMethods": "No 2FA methods available.",
|
||||
"errorTwoFactorResendFailed": "Error resending code.",
|
||||
"loginSuccess": "Login successful",
|
||||
"authErrorInvalidCredentials": "Incorrect email or password.",
|
||||
"authErrorAccountLocked": "Your account is temporarily locked. Try again later.",
|
||||
"authErrorAccountNotVerified": "Your account is not verified yet. Check your email.",
|
||||
"authErrorPasswordExpired": "Your password has expired. Use 'Forgot password' to reset it.",
|
||||
"authErrorInvalidToken": "Your session has expired. Please log in again.",
|
||||
"authErrorTooManyAttempts": "Too many attempts. Please wait a few minutes and try again.",
|
||||
"authErrorNetwork": "No connection. Check your network and try again.",
|
||||
"stepUserContactSupertitle": "User & contact",
|
||||
"stepUserContactTitle": "Create your account",
|
||||
"stepUserContactSubtitle": "With your email and phone number we can keep you informed at all times",
|
||||
@@ -507,6 +514,7 @@
|
||||
"regCode": "Device registration code",
|
||||
"deleteAccount": "Delete account",
|
||||
"logOut": "Log out",
|
||||
"logOutConfirm": "Are you sure you want to log out?",
|
||||
"loginEmail": "(Login email)",
|
||||
"submit": "Submit",
|
||||
"save": "Save",
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
"errorTwoFactorNoMethods": "No hay métodos 2FA disponibles.",
|
||||
"errorTwoFactorResendFailed": "Error al reenviar el código.",
|
||||
"loginSuccess": "Inicio de sesión exitoso",
|
||||
"authErrorInvalidCredentials": "Email o contraseña incorrectos.",
|
||||
"authErrorAccountLocked": "Tu cuenta está bloqueada temporalmente. Intenta más tarde.",
|
||||
"authErrorAccountNotVerified": "Tu cuenta aún no está verificada. Revisa tu email.",
|
||||
"authErrorPasswordExpired": "Tu contraseña ha caducado. Recupérala desde 'Olvidé mi contraseña'.",
|
||||
"authErrorInvalidToken": "La sesión ha caducado. Vuelve a iniciar sesión.",
|
||||
"authErrorTooManyAttempts": "Demasiados intentos. Espera unos minutos e inténtalo de nuevo.",
|
||||
"authErrorNetwork": "No hay conexión. Comprueba tu red e inténtalo de nuevo.",
|
||||
"stepUserContactSupertitle": "Usuario y contacto",
|
||||
"stepUserContactTitle": "Crea tu usuario",
|
||||
"stepUserContactSubtitle": "Con tu email y tu número podremos mantenerte siempre informado",
|
||||
@@ -506,6 +513,7 @@
|
||||
"regCode": "Código de registro del dispositivo",
|
||||
"deleteAccount": "Eliminar cuenta",
|
||||
"logOut": "Cerrar sesión",
|
||||
"logOutConfirm": "¿Estás seguro de que quieres cerrar sesión?",
|
||||
"loginEmail": "(Correo electrónico)",
|
||||
"passwordLabel": "Contraseña (de 6 a 12 caracteres)",
|
||||
"submit": "Enviar",
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
"errorTwoFactorNoMethods": "Aucune méthode 2FA disponible.",
|
||||
"errorTwoFactorResendFailed": "Erreur lors du renvoi du code.",
|
||||
"loginSuccess": "Connexion réussie",
|
||||
"authErrorInvalidCredentials": "E-mail ou mot de passe incorrect.",
|
||||
"authErrorAccountLocked": "Votre compte est temporairement verrouillé. Réessayez plus tard.",
|
||||
"authErrorAccountNotVerified": "Votre compte n'est pas encore vérifié. Consultez vos e-mails.",
|
||||
"authErrorPasswordExpired": "Votre mot de passe a expiré. Utilisez 'Mot de passe oublié' pour le réinitialiser.",
|
||||
"authErrorInvalidToken": "Votre session a expiré. Veuillez vous reconnecter.",
|
||||
"authErrorTooManyAttempts": "Trop de tentatives. Patientez quelques minutes avant de réessayer.",
|
||||
"authErrorNetwork": "Pas de connexion. Vérifiez votre réseau et réessayez.",
|
||||
"stepUserContactSupertitle": "Utilisateur et contact",
|
||||
"stepUserContactTitle": "Crée ton compte",
|
||||
"stepUserContactSubtitle": "Avec ton e-mail et ton numéro, nous pourrons te tenir informé à tout moment",
|
||||
@@ -863,6 +870,7 @@
|
||||
"locateDeviceInstructions": "1. Appuyez sur le bouton Lire le son pour activer le son sur l'appareil.\n2. Appuyez sur OK\n3. L'appareil émettra un son\n4. L'appareil commencera à sonner après avoir reçu les instructions",
|
||||
"mapTitle": "Carte",
|
||||
"logOut": "Se déconnecter",
|
||||
"logOutConfirm": "Êtes-vous sûr de vouloir vous déconnecter ?",
|
||||
"loginEmail": "(E-mail)",
|
||||
"makeFriends": "Se faire des amis",
|
||||
"male": "Homme",
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
"errorTwoFactorNoMethods": "Nessun metodo 2FA disponibile.",
|
||||
"errorTwoFactorResendFailed": "Errore durante il reinvio del codice.",
|
||||
"loginSuccess": "Accesso riuscito",
|
||||
"authErrorInvalidCredentials": "Email o password errati.",
|
||||
"authErrorAccountLocked": "Il tuo account è temporaneamente bloccato. Riprova più tardi.",
|
||||
"authErrorAccountNotVerified": "Il tuo account non è ancora verificato. Controlla la tua email.",
|
||||
"authErrorPasswordExpired": "La tua password è scaduta. Usa 'Password dimenticata' per reimpostarla.",
|
||||
"authErrorInvalidToken": "La tua sessione è scaduta. Accedi di nuovo.",
|
||||
"authErrorTooManyAttempts": "Troppi tentativi. Attendi qualche minuto e riprova.",
|
||||
"authErrorNetwork": "Nessuna connessione. Controlla la tua rete e riprova.",
|
||||
"stepUserContactSupertitle": "Utente e contatti",
|
||||
"stepUserContactTitle": "Crea il tuo account",
|
||||
"stepUserContactSubtitle": "Con la tua email e il tuo numero potremo tenerti sempre informato",
|
||||
@@ -863,6 +870,7 @@
|
||||
"locateDeviceInstructions": "1. Premi il pulsante Riproduci suono per attivare il suono sul dispositivo.\n2. Premi OK\n3. Il dispositivo riprodurrà un suono\n4. Il dispositivo inizierà a suonare dopo aver ricevuto le istruzioni",
|
||||
"mapTitle": "Mappa",
|
||||
"logOut": "Disconnetti",
|
||||
"logOutConfirm": "Sei sicuro di voler disconnetterti?",
|
||||
"loginEmail": "(Email)",
|
||||
"makeFriends": "Fare amicizia",
|
||||
"male": "Uomo",
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
"errorTwoFactorNoMethods": "Nenhum método 2FA disponível.",
|
||||
"errorTwoFactorResendFailed": "Erro ao reenviar o código.",
|
||||
"loginSuccess": "Login realizado com sucesso",
|
||||
"authErrorInvalidCredentials": "Email ou palavra-passe incorretos.",
|
||||
"authErrorAccountLocked": "A tua conta está temporariamente bloqueada. Tenta mais tarde.",
|
||||
"authErrorAccountNotVerified": "A tua conta ainda não está verificada. Verifica o teu email.",
|
||||
"authErrorPasswordExpired": "A tua palavra-passe expirou. Usa 'Esqueci a palavra-passe' para a redefinir.",
|
||||
"authErrorInvalidToken": "A tua sessão expirou. Volta a iniciar sessão.",
|
||||
"authErrorTooManyAttempts": "Demasiadas tentativas. Aguarda alguns minutos e tenta novamente.",
|
||||
"authErrorNetwork": "Sem ligação. Verifica a tua rede e tenta novamente.",
|
||||
"stepUserContactSupertitle": "Utilizador e contacto",
|
||||
"stepUserContactTitle": "Cria a tua conta",
|
||||
"stepUserContactSubtitle": "Com o teu email e o teu número poderemos manter-te sempre informado",
|
||||
@@ -863,6 +870,7 @@
|
||||
"locateDeviceInstructions": "1. Pressione o botão Reproduzir Som para ativar o som no dispositivo.\n2. Pressione OK\n3. O dispositivo reproduzirá um som\n4. O dispositivo começará a tocar após receber as instruções",
|
||||
"mapTitle": "Mapa",
|
||||
"logOut": "Sair",
|
||||
"logOutConfirm": "Tem certeza de que deseja sair?",
|
||||
"loginEmail": "(E-mail)",
|
||||
"makeFriends": "Fazer amigos",
|
||||
"male": "Homem",
|
||||
|
||||
@@ -414,6 +414,15 @@ class I18n {
|
||||
static const String errorFrequentPlaceUpdate = 'errorFrequentPlaceUpdate';
|
||||
static const String errorGeneric = 'errorGeneric';
|
||||
static const String pullDownToRetry = 'pullDownToRetry';
|
||||
static const String authErrorInvalidCredentials =
|
||||
'authErrorInvalidCredentials';
|
||||
static const String authErrorAccountLocked = 'authErrorAccountLocked';
|
||||
static const String authErrorAccountNotVerified =
|
||||
'authErrorAccountNotVerified';
|
||||
static const String authErrorPasswordExpired = 'authErrorPasswordExpired';
|
||||
static const String authErrorInvalidToken = 'authErrorInvalidToken';
|
||||
static const String authErrorTooManyAttempts = 'authErrorTooManyAttempts';
|
||||
static const String authErrorNetwork = 'authErrorNetwork';
|
||||
static const String errorGeofenceCreate = 'errorGeofenceCreate';
|
||||
static const String errorGeofenceDelete = 'errorGeofenceDelete';
|
||||
static const String errorGeofenceUpdate = 'errorGeofenceUpdate';
|
||||
@@ -640,6 +649,7 @@ class I18n {
|
||||
static const String loginEmail = 'loginEmail';
|
||||
static const String loginSuccess = 'loginSuccess';
|
||||
static const String logOut = 'logOut';
|
||||
static const String logOutConfirm = 'logOutConfirm';
|
||||
static const String mainContactPhoneNumber = 'mainContactPhoneNumber';
|
||||
static const String makeFriends = 'makeFriends';
|
||||
static const String male = 'male';
|
||||
|
||||
Reference in New Issue
Block a user