diff --git a/core/lib/core.dart b/core/lib/core.dart index 0a3b3391a..7a2799fcb 100644 --- a/core/lib/core.dart +++ b/core/lib/core.dart @@ -101,7 +101,6 @@ export 'data/network/download/downloaded_response.dart'; // State export 'presentation/state/success.dart'; export 'presentation/state/failure.dart'; -export 'presentation/state/app_state.dart'; // Model export 'data/model/source_type/data_source_type.dart'; diff --git a/core/lib/presentation/state/app_state.dart b/core/lib/presentation/state/app_state.dart deleted file mode 100644 index 96a36a845..000000000 --- a/core/lib/presentation/state/app_state.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:core/presentation/state/failure.dart'; -import 'package:core/presentation/state/success.dart'; -import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; - -@immutable -abstract class AppState with EquatableMixin { - final Either viewState; - - AppState(this.viewState); - - @override - List get props => [viewState]; -} \ No newline at end of file diff --git a/lib/features/home/presentation/home_controller.dart b/lib/features/home/presentation/home_controller.dart index d37d32abf..38cfacc99 100644 --- a/lib/features/home/presentation/home_controller.dart +++ b/lib/features/home/presentation/home_controller.dart @@ -126,7 +126,7 @@ class HomeController extends BaseController { failure is GetAuthenticatedAccountFailure || failure is GetStoredTokenOidcFailure || failure is GetCredentialFailure) { - _goToLogin(arguments: LoginArguments(LoginFormType.credentialForm)); + _goToLogin(arguments: LoginArguments(LoginFormType.baseUrlForm)); } } diff --git a/lib/features/login/presentation/base_login_view.dart b/lib/features/login/presentation/base_login_view.dart index 4907f80bc..a8344e8a6 100644 --- a/lib/features/login/presentation/base_login_view.dart +++ b/lib/features/login/presentation/base_login_view.dart @@ -1,17 +1,25 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/text/type_ahead_form_field_builder.dart'; +import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/widget/recent_item_tile_widget.dart'; +import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; import 'package:tmail_ui_user/features/login/domain/model/recent_login_username.dart'; +import 'package:tmail_ui_user/features/login/domain/state/authenticate_oidc_on_browser_state.dart'; +import 'package:tmail_ui_user/features/login/domain/state/authentication_user_state.dart'; +import 'package:tmail_ui_user/features/login/domain/state/check_oidc_is_available_state.dart'; import 'package:tmail_ui_user/features/login/domain/state/get_oidc_configuration_state.dart'; +import 'package:tmail_ui_user/features/login/domain/state/get_oidc_is_available_state.dart'; import 'package:tmail_ui_user/features/login/domain/state/get_token_oidc_state.dart'; import 'package:tmail_ui_user/features/login/presentation/login_controller.dart'; import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart'; -import 'package:tmail_ui_user/features/login/presentation/state/login_state.dart'; import 'package:tmail_ui_user/features/login/presentation/widgets/login_input_decoration_builder.dart'; import 'package:tmail_ui_user/features/login/presentation/widgets/login_text_input_builder.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -25,27 +33,26 @@ abstract class BaseLoginView extends GetWidget { final FocusNode passFocusNode = FocusNode(); - Widget buildLoginMessage(BuildContext context, LoginState loginState) { + Widget buildLoginMessage(BuildContext context, Either viewState) { return Padding( padding: const EdgeInsets.only(top: 11, bottom: 36, left: 58, right: 58), child: SizedBox( width: responsiveUtils.getWidthLoginTextField(context), child: Text( - loginState.viewState.fold( + viewState.fold( (failure) { - if (failure is LoginMissUrlAction) { - return AppLocalizations.of(context).requiredUrl; - } else if (failure is LoginMissUsernameAction) { - return AppLocalizations.of(context).requiredEmail; - } else if (failure is LoginMissPasswordAction) { - return AppLocalizations.of(context).requiredPassword; - } else if (failure is LoginSSONotAvailableAction) { - return AppLocalizations.of(context).ssoNotAvailable; - } else if (failure is GetOIDCConfigurationFailure - || failure is LoginCanNotVerifySSOConfigurationAction) { + if (failure is CheckOIDCIsAvailableFailure) { + return _getMessageFailure(context, failure.exception); + } else if (failure is AuthenticationUserFailure) { + return _getMessageFailure(context, failure.exception); + } else if (failure is GetOIDCIsAvailableFailure) { + return _getMessageFailure(context, failure.exception); + } else if (failure is GetTokenOIDCFailure) { + return _getMessageFailure(context, failure.exception); + } else if (failure is AuthenticateOidcOnBrowserFailure) { + return _getMessageFailure(context, failure.exception); + } else if (failure is GetOIDCConfigurationFailure) { return AppLocalizations.of(context).canNotVerifySSOConfiguration; - } else if (failure is GetTokenOIDCFailure || failure is LoginCanNotGetTokenAction) { - return AppLocalizations.of(context).canNotGetToken; } else { return AppLocalizations.of(context).unknownError; } @@ -63,13 +70,29 @@ abstract class BaseLoginView extends GetWidget { style: TextStyle( fontSize: 15, fontWeight: FontWeight.w400, - color: loginState.viewState.fold( + color: viewState.fold( (failure) => AppColor.textFieldErrorBorderColor, (success) => AppColor.colorNameEmail)), )) ); } + String _getMessageFailure(BuildContext context, dynamic exception) { + if (exception is CanNotFoundBaseUrl) { + return AppLocalizations.of(context).requiredUrl; + } else if (exception is CanNotFoundUserName) { + return AppLocalizations.of(context).requiredEmail; + } else if (exception is CanNotFoundPassword) { + return AppLocalizations.of(context).requiredPassword; + } else if (exception is CanNotFoundOIDCLinks) { + return AppLocalizations.of(context).ssoNotAvailable; + } else if (exception is CanNotFoundToken) { + return AppLocalizations.of(context).canNotGetToken; + } else { + return ''; + } + } + Widget buildLoginButton(BuildContext context) { return Container( margin: const EdgeInsets.only(bottom: 16, left: 24, right: 24), diff --git a/lib/features/login/presentation/login_controller.dart b/lib/features/login/presentation/login_controller.dart index 5439d9e1a..9c81cef77 100644 --- a/lib/features/login/presentation/login_controller.dart +++ b/lib/features/login/presentation/login_controller.dart @@ -6,7 +6,6 @@ import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; @@ -17,6 +16,8 @@ import 'package:model/oidc/request/oidc_request.dart'; import 'package:model/oidc/response/oidc_response.dart'; import 'package:model/oidc/token_oidc.dart'; import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart'; +import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; import 'package:tmail_ui_user/features/login/domain/model/login_constants.dart'; import 'package:tmail_ui_user/features/login/domain/model/recent_login_url.dart'; import 'package:tmail_ui_user/features/login/domain/model/recent_login_username.dart'; @@ -47,7 +48,6 @@ import 'package:tmail_ui_user/features/login/domain/usecases/save_login_username import 'package:tmail_ui_user/features/login/domain/usecases/update_authentication_account_interactor.dart'; import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart'; import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart'; -import 'package:tmail_ui_user/features/login/presentation/state/login_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/navigation_router.dart'; @@ -98,7 +98,6 @@ class LoginController extends ReloadableController { updateAuthenticationAccountInteractor ); - var loginState = LoginState(Right(LoginInitAction())).obs; final loginFormType = LoginFormType.baseUrlForm.obs; String? _urlText; @@ -144,17 +143,9 @@ class LoginController extends ReloadableController { if (failure is GetAuthenticationInfoFailure) { getAuthenticatedAccountAction(); } else if (failure is CheckOIDCIsAvailableFailure || - failure is GetStoredOidcConfigurationFailure) { + failure is GetStoredOidcConfigurationFailure || + failure is GetOIDCIsAvailableFailure) { _showFormLoginWithCredentialAction(); - } else if (failure is GetOIDCIsAvailableFailure) { - loginState.value = LoginState(Left(LoginSSONotAvailableAction())); - _showFormLoginWithCredentialAction(); - } else if (failure is AuthenticationUserFailure) { - _loginFailureAction(failure); - } else if (failure is GetOIDCConfigurationFailure || - failure is GetTokenOIDCFailure || - failure is AuthenticateOidcOnBrowserFailure) { - loginState.value = LoginState(Left(failure)); } } @@ -166,9 +157,8 @@ class LoginController extends ReloadableController { } else if (success is GetStoredOidcConfigurationSuccess) { _getTokenOIDCAction(success.oidcConfiguration); } else if (success is CheckOIDCIsAvailableSuccess) { - _showFormLoginWithSSOAction(success); + _redirectToSSOLoginScreen(success); } else if (success is GetOIDCIsAvailableSuccess) { - loginState.value = LoginState(Right(success)); _oidcResponse = success.oidcResponse; _getOIDCConfiguration(); } else if (success is GetOIDCConfigurationSuccess) { @@ -177,21 +167,13 @@ class LoginController extends ReloadableController { _getTokenOIDCSuccess(success); } else if (success is AuthenticationUserSuccess) { _loginSuccessAction(success); - } else if (success is GetAuthenticationInfoLoading || - success is CheckOIDCIsAvailableLoading || - success is GetStoredOidcConfigurationLoading || - success is GetOIDCConfigurationLoading || - success is GetTokenOIDCLoading || - success is AuthenticationUserLoading || - success is GetOIDCIsAvailableLoading) { - loginState.value = LoginState(Right(LoginLoadingAction())); } } @override void handleExceptionAction({Failure? failure, Exception? exception}) { super.handleExceptionAction(failure: failure, exception: exception); - loginState.value = LoginState(Right(LoginInitAction())); + clearState(); } @override @@ -215,29 +197,31 @@ class LoginController extends ReloadableController { } void _checkOIDCIsAvailable() { - final baseUri = PlatformInfo.isWeb ? _parseUri(AppConfig.baseUrl) : _parseUri(_urlText); - if (baseUri == null) { - loginState.value = LoginState(Left(LoginMissUrlAction())); + final baseUrl = _getBaseUrl(); + if (baseUrl == null) { + dispatchState(Left(CheckOIDCIsAvailableFailure(CanNotFoundBaseUrl()))); } else { - consumeState(_checkOIDCIsAvailableInteractor.execute(OIDCRequest( - baseUrl: baseUri.toString(), - resourceUrl: baseUri.origin))); + consumeState(_checkOIDCIsAvailableInteractor.execute( + OIDCRequest( + baseUrl: baseUrl.toString(), + resourceUrl: baseUrl.origin + ) + )); } } - void _showFormLoginWithSSOAction(CheckOIDCIsAvailableSuccess success) { - loginState.value = LoginState(Right(success)); - loginFormType.value = LoginFormType.ssoForm; + void _redirectToSSOLoginScreen(CheckOIDCIsAvailableSuccess success) { _oidcResponse = success.oidcResponse; + handleSSOPressed(); } void handleBackInCredentialForm() { - loginState.value = LoginState(Right(LoginInitAction())); + clearState(); loginFormType.value = LoginFormType.baseUrlForm; } void _showFormLoginWithCredentialAction() { - loginState.value = LoginState(Right(InputUrlCompletion())); + clearState(); loginFormType.value = LoginFormType.credentialForm; } @@ -249,29 +233,25 @@ class LoginController extends ReloadableController { if (loginFormType.value == LoginFormType.ssoForm) { _getOIDCConfiguration(); } else { - final baseUri = kIsWeb ? _parseUri(AppConfig.baseUrl) : _parseUri(_urlText); + final baseUrl = _getBaseUrl(); final userName = _parseUserName(_userNameText); final password = _parsePassword(_passwordText); - if (baseUri != null && userName != null && password != null) { - _loginAction(baseUri, userName, password); - } else if (baseUri == null) { - loginState.value = LoginState(Left(LoginMissUrlAction())); - } else if (userName == null) { - loginState.value = LoginState(Left(LoginMissUsernameAction())); - } else if (password == null) { - loginState.value = LoginState(Left(LoginMissPasswordAction())); - } + + _loginAction(baseUrl: baseUrl, userName: userName, password: password); } } void handleSSOPressed() { - final baseUri = _parseUri(AppConfig.baseUrl); - if (baseUri != null) { - consumeState(_getOIDCIsAvailableInteractor.execute(OIDCRequest( - baseUrl: baseUri.toString(), - resourceUrl: baseUri.origin))); - } else { - loginState.value = LoginState(Left(LoginCanNotAuthenticationSSOAction())); + final baseUrl = _getBaseUrl(); + if (baseUrl != null) { + consumeState(_getOIDCIsAvailableInteractor.execute( + OIDCRequest( + baseUrl: baseUrl.toString(), + resourceUrl: baseUrl.origin + ) + )); + } else { + dispatchState(Left(GetOIDCIsAvailableFailure(CanNotFoundBaseUrl()))); } } @@ -279,13 +259,12 @@ class LoginController extends ReloadableController { if (_oidcResponse != null) { consumeState(_getOIDCConfigurationInteractor.execute(_oidcResponse!)); } else { - loginState.value = LoginState(Left(LoginCanNotAuthenticationSSOAction())); + dispatchState(Left(GetOIDCIsAvailableFailure(CanNotFoundOIDCLinks()))); } } void _getOIDCConfigurationSuccess(GetOIDCConfigurationSuccess success) { log('LoginController::_getOIDCConfigurationSuccess():success: $success'); - loginState.value = LoginState(Right(success)); if (PlatformInfo.isWeb) { _authenticateOidcOnBrowserAction(success.oidcConfiguration); } else { @@ -294,11 +273,11 @@ class LoginController extends ReloadableController { } void _getTokenOIDCAction(OIDCConfiguration config) async { - final baseUri = kIsWeb ? _parseUri(AppConfig.baseUrl) : _parseUri(_urlText); + final baseUri = _getBaseUrl(); if (baseUri != null) { - consumeState(_getTokenOIDCInteractor.execute(baseUri, config)); + consumeState(_getTokenOIDCInteractor.execute(baseUri, config)); } else { - loginState.value = LoginState(Left(LoginCanNotGetTokenAction())); + dispatchState(Left(GetTokenOIDCFailure(CanNotFoundBaseUrl()))); } } @@ -309,7 +288,7 @@ class LoginController extends ReloadableController { if (baseUri != null) { consumeState(_authenticateOidcOnBrowserInteractor.execute(baseUri, config)); } else { - loginState.value = LoginState(Left(LoginCanNotAuthenticationSSOAction())); + dispatchState(Left(AuthenticateOidcOnBrowserFailure(CanNotFoundBaseUrl()))); } } @@ -322,9 +301,8 @@ class LoginController extends ReloadableController { void _getTokenOIDCSuccess(GetTokenOIDCSuccess success) { log('LoginController::_getTokenOIDCSuccess(): ${success.tokenOIDC.toString()}'); - loginState.value = LoginState(Right(success)); - _dynamicUrlInterceptors.setJmapUrl(PlatformInfo.isWeb ? AppConfig.baseUrl : _urlText); - _dynamicUrlInterceptors.changeBaseUrl(PlatformInfo.isWeb ? AppConfig.baseUrl : _urlText); + _dynamicUrlInterceptors.setJmapUrl(_getBaseUrl().toString()); + _dynamicUrlInterceptors.changeBaseUrl(_getBaseUrl().toString()); authorizationInterceptors.setTokenAndAuthorityOidc( newToken: success.tokenOIDC.toToken(), newConfig: success.configuration); @@ -334,24 +312,22 @@ class LoginController extends ReloadableController { pushAndPop(AppRoutes.session, arguments: _dynamicUrlInterceptors.baseUrl); } - void _loginAction(Uri baseUrl, UserName userName, Password password) async { - consumeState(_authenticationInteractor.execute(baseUrl, userName, password)); + void _loginAction({Uri? baseUrl, UserName? userName, Password? password}) { + consumeState(_authenticationInteractor.execute( + baseUrl: baseUrl, + userName: userName, + password: password + )); } void _loginSuccessAction(AuthenticationUserSuccess success) { - loginState.value = LoginState(Right(success)); - _dynamicUrlInterceptors.setJmapUrl(PlatformInfo.isWeb ? AppConfig.baseUrl : _urlText); - _dynamicUrlInterceptors.changeBaseUrl(PlatformInfo.isWeb ? AppConfig.baseUrl : _urlText); + _dynamicUrlInterceptors.setJmapUrl(_getBaseUrl().toString()); + _dynamicUrlInterceptors.changeBaseUrl(_getBaseUrl().toString()); authorizationInterceptors.setBasicAuthorization(_userNameText, _passwordText); authorizationIsolateInterceptors.setBasicAuthorization(_userNameText, _passwordText); pushAndPop(AppRoutes.session, arguments: _dynamicUrlInterceptors.baseUrl); } - void _loginFailureAction(FeatureFailure failure) { - logError('LoginController::_loginFailureAction(): $failure'); - loginState.value = LoginState(Left(failure)); - } - void formatUrl(String url) { log('LoginController::formatUrl(): $url'); if (url.isValid()) { @@ -364,7 +340,7 @@ class LoginController extends ReloadableController { if (_urlText?.isNotEmpty == true && PlatformInfo.isMobile) { final recentLoginUrl = RecentLoginUrl.now(_urlText!); log('LoginController::_saveRecentLoginUrl(): $recentLoginUrl'); - consumeState(_saveLoginUrlOnMobileInteractor.execute(recentLoginUrl)); + _saveLoginUrlOnMobileInteractor.execute(recentLoginUrl); } } @@ -391,7 +367,7 @@ class LoginController extends ReloadableController { } final recentLoginUsername = RecentLoginUsername.now(_userNameText!); log('LoginController::_saveRecentLoginUsername(): $recentLoginUsername'); - consumeState(_saveLoginUsernameOnMobileInteractor.execute(recentLoginUsername)); + _saveLoginUsernameOnMobileInteractor.execute(recentLoginUsername); } Future> getAllRecentLoginUsernameAction(String pattern) async { @@ -405,9 +381,12 @@ class LoginController extends ReloadableController { )); } + Uri? _getBaseUrl() => PlatformInfo.isWeb ? _parseUri(AppConfig.baseUrl) : _parseUri(_urlText); + @override void onClose() { - urlInputController.clear(); + urlInputController.dispose(); + usernameInputController.dispose(); super.onClose(); } } \ No newline at end of file diff --git a/lib/features/login/presentation/login_view.dart b/lib/features/login/presentation/login_view.dart index 1d53987de..39a9f3841 100644 --- a/lib/features/login/presentation/login_view.dart +++ b/lib/features/login/presentation/login_view.dart @@ -1,4 +1,5 @@ import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/views/text/type_ahead_form_field_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -9,7 +10,6 @@ import 'package:tmail_ui_user/features/login/domain/model/recent_login_url.dart' import 'package:tmail_ui_user/features/login/presentation/base_login_view.dart'; import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart'; import 'package:tmail_ui_user/features/login/presentation/privacy_link_widget.dart'; -import 'package:tmail_ui_user/features/login/presentation/state/login_state.dart'; import 'package:tmail_ui_user/features/login/presentation/widgets/login_input_decoration_builder.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -72,7 +72,7 @@ class LoginView extends BaseLoginView { style: const TextStyle(fontSize: 32, color: AppColor.colorNameEmail, fontWeight: FontWeight.w900) ) ), - Obx(() => buildLoginMessage(context, loginController.loginState.value)), + Obx(() => buildLoginMessage(context, loginController.viewState.value)), Obx(() { switch (controller.loginFormType.value) { case LoginFormType.baseUrlForm: @@ -83,30 +83,7 @@ class LoginView extends BaseLoginView { return const SizedBox.shrink(); } }), - Obx(() { - switch (controller.loginFormType.value) { - case LoginFormType.baseUrlForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => _buildNextButtonInContext(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : _buildNextButtonInContext(context))); - case LoginFormType.credentialForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => _buildLoginButtonInContext(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : _buildLoginButtonInContext(context))); - case LoginFormType.ssoForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => _buildLoginButtonInContext(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : _buildLoginButtonInContext(context))); - default: - return const SizedBox.shrink(); - } - }), + _buildLoadingProgress(context), const Padding( padding: EdgeInsets.only(top: 16), child: PrivacyLinkWidget(), @@ -209,4 +186,37 @@ class LoginView extends BaseLoginView { bool _supportScrollForm(BuildContext context) { return !(responsiveUtils.isMobile(context) && responsiveUtils.isPortrait(context)); } + + Widget _buildLoadingProgress(BuildContext context) { + return Obx(() => loginController.viewState.value.fold( + (failure) { + switch (controller.loginFormType.value) { + case LoginFormType.baseUrlForm: + return _buildNextButtonInContext(context); + case LoginFormType.credentialForm: + return _buildLoginButtonInContext(context); + case LoginFormType.ssoForm: + return _buildLoginButtonInContext(context); + default: + return const SizedBox.shrink(); + } + }, + (success) { + if (success is LoadingState) { + return buildLoadingCircularProgress(); + } else { + switch (controller.loginFormType.value) { + case LoginFormType.baseUrlForm: + return _buildNextButtonInContext(context); + case LoginFormType.credentialForm: + return _buildLoginButtonInContext(context); + case LoginFormType.ssoForm: + return _buildLoginButtonInContext(context); + default: + return const SizedBox.shrink(); + } + } + } + )); + } } \ No newline at end of file diff --git a/lib/features/login/presentation/login_view_web.dart b/lib/features/login/presentation/login_view_web.dart index a1c0af396..55cd1dece 100644 --- a/lib/features/login/presentation/login_view_web.dart +++ b/lib/features/login/presentation/login_view_web.dart @@ -1,11 +1,13 @@ -import 'package:core/core.dart'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:core/presentation/views/responsive/responsive_widget.dart'; +import 'package:core/presentation/views/text/slogan_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'; import 'package:tmail_ui_user/features/login/presentation/base_login_view.dart'; import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart'; import 'package:tmail_ui_user/features/login/presentation/privacy_link_widget.dart'; -import 'package:tmail_ui_user/features/login/presentation/state/login_state.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class LoginView extends BaseLoginView { @@ -45,7 +47,7 @@ class LoginView extends BaseLoginView { style: const TextStyle(fontSize: 32, color: AppColor.colorNameEmail, fontWeight: FontWeight.w900) ) ), - Obx(() => buildLoginMessage(context, loginController.loginState.value)), + Obx(() => buildLoginMessage(context, loginController.viewState.value)), Obx(() { switch (controller.loginFormType.value) { case LoginFormType.credentialForm: @@ -56,30 +58,7 @@ class LoginView extends BaseLoginView { return const SizedBox.shrink(); } }), - Obx(() { - switch (controller.loginFormType.value) { - case LoginFormType.baseUrlForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => const SizedBox.shrink(), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : const SizedBox.shrink())); - case LoginFormType.credentialForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => buildLoginButton(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : buildLoginButton(context))); - case LoginFormType.ssoForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => _buildSSOButton(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : _buildSSOButton(context))); - default: - return const SizedBox.shrink(); - } - }), + _buildLoadingProgress(context), const Padding( padding: EdgeInsets.only(top: 16), child: PrivacyLinkWidget(), @@ -200,7 +179,7 @@ class LoginView extends BaseLoginView { style: const TextStyle(fontSize: 32, color: AppColor.colorNameEmail, fontWeight: FontWeight.w900) ) ), - Obx(() => buildLoginMessage(context, loginController.loginState.value)), + Obx(() => buildLoginMessage(context, loginController.viewState.value)), Obx(() { switch (controller.loginFormType.value) { case LoginFormType.credentialForm: @@ -211,30 +190,7 @@ class LoginView extends BaseLoginView { return const SizedBox.shrink(); } }), - Obx(() { - switch (controller.loginFormType.value) { - case LoginFormType.baseUrlForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => const SizedBox.shrink(), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : const SizedBox.shrink())); - case LoginFormType.credentialForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => buildLoginButton(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : buildLoginButton(context))); - case LoginFormType.ssoForm: - return Obx(() => loginController.loginState.value.viewState.fold( - (failure) => _buildSSOButton(context), - (success) => success is LoginLoadingAction - ? buildLoadingCircularProgress() - : _buildSSOButton(context))); - default: - return const SizedBox.shrink(); - } - }), + _buildLoadingProgress(context), const Padding( padding: EdgeInsets.only(top: 16), child: PrivacyLinkWidget() @@ -300,4 +256,37 @@ class LoginView extends BaseLoginView { ) ); } + + Widget _buildLoadingProgress(BuildContext context) { + return Obx(() => loginController.viewState.value.fold( + (failure) { + switch (controller.loginFormType.value) { + case LoginFormType.baseUrlForm: + return const SizedBox.shrink(); + case LoginFormType.credentialForm: + return buildLoginButton(context); + case LoginFormType.ssoForm: + return _buildSSOButton(context); + default: + return const SizedBox.shrink(); + } + }, + (success) { + if (success is LoadingState) { + return buildLoadingCircularProgress(); + } else { + switch (controller.loginFormType.value) { + case LoginFormType.baseUrlForm: + return const SizedBox.shrink(); + case LoginFormType.credentialForm: + return buildLoginButton(context); + case LoginFormType.ssoForm: + return _buildSSOButton(context); + default: + return const SizedBox.shrink(); + } + } + } + )); + } } \ No newline at end of file diff --git a/lib/features/login/presentation/state/login_state.dart b/lib/features/login/presentation/state/login_state.dart deleted file mode 100644 index 502563db0..000000000 --- a/lib/features/login/presentation/state/login_state.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:core/core.dart'; -import 'package:dartz/dartz.dart'; -import 'package:flutter/material.dart'; - -@immutable -class LoginState extends AppState { - LoginState(Either viewState) : super(viewState); -} - -@immutable -class InputUrlCompletion extends ViewState { - @override - List get props => []; -} - -@immutable -class LoginLoadingAction extends ViewState { - @override - List get props => []; -} - -@immutable -class LoginInitAction extends ViewState { - @override - List get props => []; -} - -@immutable -class LoginMissUrlAction extends Failure { - @override - List get props => []; -} - -@immutable -class LoginMissUsernameAction extends Failure { - @override - List get props => []; -} - -@immutable -class LoginMissPasswordAction extends Failure { - @override - List get props => []; -} - -@immutable -class LoginCanNotVerifySSOConfigurationAction extends Failure { - @override - List get props => []; -} - -@immutable -class LoginCanNotGetTokenAction extends Failure { - @override - List get props => []; -} - -class LoginSSONotAvailableAction extends Failure { - @override - List get props => []; -} - -class LoginCanNotAuthenticationSSOAction extends Failure { - @override - List get props => []; -} \ No newline at end of file diff --git a/lib/features/session/presentation/session_controller.dart b/lib/features/session/presentation/session_controller.dart index 831cee088..e577ede95 100644 --- a/lib/features/session/presentation/session_controller.dart +++ b/lib/features/session/presentation/session_controller.dart @@ -102,8 +102,10 @@ class SessionController extends ReloadableController { } else if (sessionException is BadCredentialsException && currentContext != null) { errorMessage = AppLocalizations.of(currentContext!).badCredentials; } else if (sessionException is UnknownError && currentContext != null) { - if (sessionException.message != null) { + if (sessionException.message != null && sessionException.code != null) { errorMessage = '[${sessionException.code}] ${sessionException.message}'; + } else if (sessionException.message != null) { + errorMessage = sessionException.message!; } else { errorMessage = AppLocalizations.of(currentContext!).unknownError; }