TF-2928 Show confirm dialog & handle exception when reload browser or loss of connection
This commit is contained in:
@@ -19,6 +19,7 @@ export 'presentation/extensions/map_extensions.dart';
|
||||
export 'domain/exceptions/download_file_exception.dart';
|
||||
export 'data/extensions/options_extensions.dart';
|
||||
export 'domain/exceptions/web_session_exception.dart';
|
||||
export 'domain/exceptions/platform_exception.dart';
|
||||
|
||||
// Utils
|
||||
export 'presentation/utils/theme_utils.dart';
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class PlatformException with EquatableMixin implements Exception {
|
||||
final String message;
|
||||
|
||||
PlatformException(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
class NoSupportPlatformException extends PlatformException {
|
||||
NoSupportPlatformException() : super('This platform is not supported');
|
||||
}
|
||||
@@ -24,18 +24,19 @@ class ConfirmDialogBuilder {
|
||||
double? _radiusButton;
|
||||
EdgeInsetsGeometry? _paddingTitle;
|
||||
EdgeInsets? _paddingContent;
|
||||
EdgeInsets? _paddingButton;
|
||||
EdgeInsetsGeometry? _paddingButton;
|
||||
EdgeInsets? _marginButton;
|
||||
EdgeInsets? _outsideDialogPadding;
|
||||
EdgeInsetsGeometry? _marginIcon;
|
||||
EdgeInsets? _margin;
|
||||
double? _widthDialog;
|
||||
double maxWith;
|
||||
final double maxWith;
|
||||
Alignment? _alignment;
|
||||
Color? _backgroundColor;
|
||||
bool showAsBottomSheet;
|
||||
List<TextSpan>? listTextSpan;
|
||||
int? titleActionButtonMaxLines;
|
||||
bool isArrangeActionButtonsVertical;
|
||||
final bool showAsBottomSheet;
|
||||
final List<TextSpan>? listTextSpan;
|
||||
final int? titleActionButtonMaxLines;
|
||||
final bool isArrangeActionButtonsVertical;
|
||||
|
||||
OnConfirmButtonAction? _onConfirmButtonAction;
|
||||
OnCancelButtonAction? _onCancelButtonAction;
|
||||
@@ -104,10 +105,14 @@ class ConfirmDialogBuilder {
|
||||
_paddingContent = value;
|
||||
}
|
||||
|
||||
void paddingButton(EdgeInsets? value) {
|
||||
void paddingButton(EdgeInsetsGeometry? value) {
|
||||
_paddingButton = value;
|
||||
}
|
||||
|
||||
void marginButton(EdgeInsets? value) {
|
||||
_marginButton = value;
|
||||
}
|
||||
|
||||
void marginIcon(EdgeInsetsGeometry? value) {
|
||||
_marginIcon = value;
|
||||
}
|
||||
@@ -253,7 +258,7 @@ class ConfirmDialogBuilder {
|
||||
]
|
||||
else
|
||||
Padding(
|
||||
padding: _paddingButton ?? const EdgeInsetsDirectional.only(bottom: 16, start: 16, end: 16),
|
||||
padding: _marginButton ?? const EdgeInsetsDirectional.only(bottom: 16, start: 16, end: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
if (_cancelText.isNotEmpty)
|
||||
@@ -297,7 +302,7 @@ class ConfirmDialogBuilder {
|
||||
borderRadius: BorderRadius.circular(radius ?? 8),
|
||||
side: BorderSide(width: 0, color: bgColor ?? AppColor.colorTextButton),
|
||||
),
|
||||
padding: const EdgeInsets.all(8),
|
||||
padding: _paddingButton ?? const EdgeInsets.all(8),
|
||||
elevation: 0
|
||||
),
|
||||
child: Text(
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:contact/contact/model/capability_contact.dart';
|
||||
import 'package:core/data/network/config/dynamic_url_interceptors.dart';
|
||||
import 'package:core/domain/exceptions/platform_exception.dart';
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/state/failure.dart';
|
||||
@@ -60,6 +63,7 @@ import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
import 'package:tmail_ui_user/main/utils/app_config.dart';
|
||||
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
abstract class BaseController extends GetxController
|
||||
@@ -85,9 +89,42 @@ abstract class BaseController extends GetxController
|
||||
GetStoredFirebaseRegistrationInteractor? _getStoredFirebaseRegistrationInteractor;
|
||||
DestroyFirebaseRegistrationInteractor? _destroyFirebaseRegistrationInteractor;
|
||||
|
||||
StreamSubscription<html.Event>? _subscriptionBrowserOnBeforeUnload;
|
||||
StreamSubscription<html.Event>? _subscriptionBrowserOnUnload;
|
||||
|
||||
final viewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
|
||||
FpsCallback? fpsCallback;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
if (PlatformInfo.isWeb) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_triggerBrowserReloadListener();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _triggerBrowserReloadListener() {
|
||||
_subscriptionBrowserOnBeforeUnload =
|
||||
html.window.onBeforeUnload.listen(handleBrowserBeforeReloadAction);
|
||||
_subscriptionBrowserOnUnload =
|
||||
html.window.onUnload.listen(handleBrowserReloadAction);
|
||||
}
|
||||
|
||||
Future<void> handleBrowserBeforeReloadAction(html.Event event) async {}
|
||||
|
||||
Future<void> handleBrowserReloadAction(html.Event event) async {}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
if (PlatformInfo.isWeb) {
|
||||
_subscriptionBrowserOnBeforeUnload?.cancel();
|
||||
_subscriptionBrowserOnUnload?.cancel();
|
||||
}
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void consumeState(Stream<Either<Failure, Success>> newStateStream) async {
|
||||
newStateStream.listen(onData, onError: onError, onDone: onDone);
|
||||
}
|
||||
@@ -105,10 +142,9 @@ abstract class BaseController extends GetxController
|
||||
viewState.value.fold(
|
||||
(failure) {
|
||||
if (failure is FeatureFailure) {
|
||||
final exception = _performFilterExceptionInError(failure.exception);
|
||||
logError('$runtimeType::onData:exception: $exception');
|
||||
if (exception != null) {
|
||||
handleExceptionAction(failure: failure, exception: exception);
|
||||
final isUrgentException = _validateUrgentException(failure.exception);
|
||||
if (isUrgentException) {
|
||||
handleUrgentException(failure: failure, exception: failure.exception);
|
||||
} else {
|
||||
handleFailureViewState(failure);
|
||||
}
|
||||
@@ -119,11 +155,11 @@ abstract class BaseController extends GetxController
|
||||
handleSuccessViewState);
|
||||
}
|
||||
|
||||
void onError(Object error, StackTrace stackTrace) {
|
||||
logError('$runtimeType::onError():error: $error | stackTrace: $stackTrace');
|
||||
final exception = _performFilterExceptionInError(error);
|
||||
if (exception != null) {
|
||||
handleExceptionAction(exception: exception);
|
||||
void onError(dynamic error, StackTrace stackTrace) {
|
||||
logError('$runtimeType::onError():Error: $error | StackTrace: $stackTrace');
|
||||
final isUrgentException = _validateUrgentException(error);
|
||||
if (isUrgentException) {
|
||||
handleUrgentException(exception: error);
|
||||
} else {
|
||||
handleErrorViewState(error, stackTrace);
|
||||
}
|
||||
@@ -131,10 +167,41 @@ abstract class BaseController extends GetxController
|
||||
|
||||
void onDone() {}
|
||||
|
||||
Exception? _performFilterExceptionInError(dynamic error) {
|
||||
logError('$runtimeType::_performFilterExceptionInError(): $error');
|
||||
if (error is NoNetworkError || error is ConnectionTimeout || error is InternalServerError) {
|
||||
if (PlatformInfo.isWeb && currentOverlayContext != null && currentContext != null) {
|
||||
bool _validateUrgentException(dynamic exception) {
|
||||
return exception is NoNetworkError
|
||||
|| exception is BadCredentialsException
|
||||
|| exception is ConnectionError;
|
||||
}
|
||||
|
||||
void handleErrorViewState(Object error, StackTrace stackTrace) {}
|
||||
|
||||
void handleUrgentException({Failure? failure, Exception? exception}) {
|
||||
if (PlatformInfo.isWeb) {
|
||||
handleUrgentExceptionOnWeb(failure: failure, exception: exception);
|
||||
} else if (PlatformInfo.isMobile) {
|
||||
handleUrgentExceptionOnMobile(failure: failure, exception: exception);
|
||||
} else {
|
||||
throw NoSupportPlatformException();
|
||||
}
|
||||
}
|
||||
|
||||
void handleUrgentExceptionOnMobile({Failure? failure, Exception? exception}) {
|
||||
logError('$runtimeType::handleUrgentExceptionOnMobile():Failure: $failure | Exception: $exception');
|
||||
if (exception is ConnectionError) {
|
||||
if (currentOverlayContext != null && currentContext != null) {
|
||||
appToast.showToastErrorMessage(
|
||||
currentOverlayContext!,
|
||||
AppLocalizations.of(currentContext!).connectionError);
|
||||
}
|
||||
} else if (exception is BadCredentialsException) {
|
||||
_executeBeforeUnloadAndLogOut();
|
||||
}
|
||||
}
|
||||
|
||||
void handleUrgentExceptionOnWeb({Failure? failure, Exception? exception}) {
|
||||
logError('$runtimeType::handleUrgentExceptionOnWeb():Failure: $failure | Exception: $exception');
|
||||
if (exception is NoNetworkError) {
|
||||
if (currentOverlayContext != null && currentContext != null) {
|
||||
appToast.showToastMessage(
|
||||
currentOverlayContext!,
|
||||
AppLocalizations.of(currentContext!).no_internet_connection,
|
||||
@@ -143,43 +210,22 @@ abstract class BaseController extends GetxController
|
||||
leadingSVGIcon: imagePaths.icNotConnection,
|
||||
backgroundColor: AppColor.textFieldErrorBorderColor,
|
||||
textColor: Colors.white,
|
||||
infinityToast: true,
|
||||
);
|
||||
infinityToast: true,);
|
||||
}
|
||||
return error;
|
||||
} else if (error is BadCredentialsException || error is ConnectionError) {
|
||||
return error;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void handleErrorViewState(Object error, StackTrace stackTrace) {}
|
||||
|
||||
void handleExceptionAction({Failure? failure, Exception? exception}) {
|
||||
logError('$runtimeType::handleExceptionAction():failure: $failure | exception: $exception');
|
||||
if (exception is ConnectionError) {
|
||||
} else if (exception is ConnectionError) {
|
||||
if (currentOverlayContext != null && currentContext != null) {
|
||||
appToast.showToastErrorMessage(
|
||||
currentOverlayContext!,
|
||||
AppLocalizations.of(currentContext!).connectionError
|
||||
);
|
||||
AppLocalizations.of(currentContext!).connectionError);
|
||||
}
|
||||
} else if (exception is BadCredentialsException) {
|
||||
_executeBeforeUnloadAndLogOut();
|
||||
}
|
||||
|
||||
if (!authorizationInterceptors.isAppRunning) {
|
||||
return;
|
||||
}
|
||||
_executeBeforeUnloadAndLogOut(exception);
|
||||
}
|
||||
|
||||
Future<void> _executeBeforeUnloadAndLogOut(Exception? exception) async {
|
||||
if (exception is BadCredentialsException || exception is ConnectionError) {
|
||||
if (PlatformInfo.isWeb) {
|
||||
await executeBeforeUnload();
|
||||
}
|
||||
clearDataAndGoToLoginPage();
|
||||
}
|
||||
Future<void> _executeBeforeUnloadAndLogOut() async {
|
||||
await executeBeforeUnload();
|
||||
clearDataAndGoToLoginPage();
|
||||
}
|
||||
|
||||
void handleFailureViewState(Failure failure) async {
|
||||
|
||||
@@ -33,6 +33,7 @@ mixin MessageDialogActionMixin {
|
||||
Color? actionButtonColor,
|
||||
Color? cancelButtonColor,
|
||||
EdgeInsetsGeometry? marginIcon,
|
||||
EdgeInsetsGeometry? paddingButton,
|
||||
PopInvokedCallback? onPopInvoked,
|
||||
bool isArrangeActionButtonsVertical = false,
|
||||
int? titleActionButtonMaxLines,
|
||||
@@ -61,8 +62,9 @@ mixin MessageDialogActionMixin {
|
||||
: const EdgeInsetsDirectional.symmetric(horizontal: 24)
|
||||
)
|
||||
..radiusButton(12)
|
||||
..paddingButton(paddingButton)
|
||||
..paddingContent(const EdgeInsets.only(left: 24, right: 24, bottom: 24, top: 12))
|
||||
..paddingButton(hasCancelButton ? null : const EdgeInsets.only(bottom: 24, left: 24, right: 24))
|
||||
..marginButton(hasCancelButton ? null : const EdgeInsets.only(bottom: 24, left: 24, right: 24))
|
||||
..styleTitle(titleStyle ?? const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black))
|
||||
..styleContent(messageStyle ?? const TextStyle(fontSize: 14, fontWeight: FontWeight.normal, color: AppColor.colorContentEmail))
|
||||
..styleTextCancelButton(cancelStyle ?? const TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton))
|
||||
@@ -107,6 +109,7 @@ mixin MessageDialogActionMixin {
|
||||
..title(title ?? '')
|
||||
..content(message)
|
||||
..addIcon(icon)
|
||||
..paddingButton(paddingButton)
|
||||
..margin(const EdgeInsets.only(bottom: 42))
|
||||
..widthDialog(responsiveUtils.getSizeScreenWidth(context))
|
||||
..colorConfirmButton(actionButtonColor ?? AppColor.colorTextButton)
|
||||
@@ -117,7 +120,7 @@ mixin MessageDialogActionMixin {
|
||||
)
|
||||
..marginIcon(EdgeInsets.zero)
|
||||
..paddingContent(const EdgeInsets.only(left: 44, right: 44, bottom: 24, top: 12))
|
||||
..paddingButton(hasCancelButton ? null : const EdgeInsets.only(bottom: 16, left: 44, right: 44))
|
||||
..marginButton(hasCancelButton ? null : const EdgeInsets.only(bottom: 16, left: 44, right: 44))
|
||||
..styleTitle(titleStyle ?? const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black))
|
||||
..styleContent(messageStyle ?? const TextStyle(fontSize: 14, fontWeight: FontWeight.normal, color: AppColor.colorContentEmail))
|
||||
..styleTextCancelButton(cancelStyle ?? const TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton))
|
||||
@@ -187,6 +190,7 @@ mixin MessageDialogActionMixin {
|
||||
..title(title ?? '')
|
||||
..content(message)
|
||||
..addIcon(icon)
|
||||
..paddingButton(paddingButton)
|
||||
..colorConfirmButton(actionButtonColor ?? AppColor.colorTextButton)
|
||||
..colorCancelButton(cancelButtonColor ?? AppColor.colorCancelButton)
|
||||
..marginIcon(icon != null ? const EdgeInsets.only(top: 24) : null)
|
||||
@@ -195,7 +199,7 @@ mixin MessageDialogActionMixin {
|
||||
: const EdgeInsetsDirectional.symmetric(horizontal: 24))
|
||||
..marginIcon(EdgeInsets.zero)
|
||||
..paddingContent(const EdgeInsets.only(left: 44, right: 44, bottom: 24, top: 12))
|
||||
..paddingButton(hasCancelButton ? null : const EdgeInsets.only(bottom: 16, left: 44, right: 44))
|
||||
..marginButton(hasCancelButton ? null : const EdgeInsets.only(bottom: 16, left: 44, right: 44))
|
||||
..styleTitle(titleStyle ?? const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black))
|
||||
..styleContent(messageStyle ?? const TextStyle(fontSize: 14, fontWeight: FontWeight.normal, color: AppColor.colorContentEmail))
|
||||
..styleTextCancelButton(cancelStyle ?? const TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton))
|
||||
|
||||
@@ -92,6 +92,7 @@ import 'package:tmail_ui_user/features/upload/domain/state/local_image_picker_st
|
||||
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/usecases/local_image_picker_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/controller/upload_controller.dart';
|
||||
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
@@ -164,7 +165,6 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
||||
FocusNode? ccAddressFocusNodeKeyboard;
|
||||
FocusNode? bccAddressFocusNodeKeyboard;
|
||||
|
||||
StreamSubscription<html.Event>? _subscriptionOnBeforeUnload;
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragEnter;
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragOver;
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragLeave;
|
||||
@@ -213,7 +213,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
||||
super.onInit();
|
||||
if (PlatformInfo.isWeb) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_listenBrowserTabRefresh();
|
||||
_triggerBrowserEventListener();
|
||||
});
|
||||
richTextWebController = getBinding<RichTextWebController>();
|
||||
} else {
|
||||
@@ -244,7 +244,6 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
||||
emailContentsViewState.value = Right(UIClosedState());
|
||||
identitySelected.value = null;
|
||||
listFromIdentities.clear();
|
||||
_subscriptionOnBeforeUnload?.cancel();
|
||||
_subscriptionOnDragEnter?.cancel();
|
||||
_subscriptionOnDragOver?.cancel();
|
||||
_subscriptionOnDragLeave?.cancel();
|
||||
@@ -353,11 +352,17 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
||||
}
|
||||
|
||||
@override
|
||||
void handleExceptionAction({Failure? failure, Exception? exception}) {
|
||||
super.handleExceptionAction(failure: failure, exception: exception);
|
||||
if (failure is GetAllIdentitiesFailure) {
|
||||
_handleGetAllIdentitiesFailure(failure);
|
||||
void handleUrgentExceptionOnMobile({Failure? failure, Exception? exception}) {
|
||||
if (failure is GetAllIdentitiesFailure && exception is! BadCredentialsException) {
|
||||
_handleGetAllIdentitiesFailure();
|
||||
}
|
||||
super.handleUrgentExceptionOnMobile(failure: failure, exception: exception);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> handleBrowserReloadAction(html.Event event) async {
|
||||
await _removeComposerCacheOnWebInteractor.execute();
|
||||
await _saveComposerCacheOnWebAction();
|
||||
}
|
||||
|
||||
void _listenStreamEvent() {
|
||||
@@ -377,13 +382,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
||||
}
|
||||
}
|
||||
|
||||
void _listenBrowserTabRefresh() {
|
||||
_subscriptionOnBeforeUnload = html.window.onBeforeUnload.listen((event) async {
|
||||
await _removeComposerCacheOnWebInteractor.execute();
|
||||
|
||||
await _saveComposerCacheOnWebAction();
|
||||
});
|
||||
|
||||
void _triggerBrowserEventListener() {
|
||||
_subscriptionOnDragEnter = html.window.onDragEnter.listen((event) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -1966,9 +1965,8 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
||||
);
|
||||
}
|
||||
|
||||
void _handleGetAllIdentitiesFailure(GetAllIdentitiesFailure failure) async {
|
||||
log('ComposerController::_handleGetAllIdentitiesFailure:failure: $failure');
|
||||
if (composerArguments.value?.emailActionType == EmailActionType.editSendingEmail && PlatformInfo.isMobile) {
|
||||
Future<void> _handleGetAllIdentitiesFailure() async {
|
||||
if (composerArguments.value?.emailActionType == EmailActionType.editSendingEmail) {
|
||||
final signatureContent = await htmlEditorApi?.getSignatureContent();
|
||||
log('ComposerController::_handleGetAllIdentitiesFailure:signatureContent: $signatureContent');
|
||||
if (signatureContent?.isNotEmpty == true) {
|
||||
|
||||
@@ -203,17 +203,6 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper {
|
||||
|
||||
String _getTokenAsBearerHeader(String token) => 'Bearer $token';
|
||||
|
||||
bool get isAppRunning {
|
||||
switch(_authenticationType) {
|
||||
case AuthenticationType.basic:
|
||||
return _authorization != null;
|
||||
case AuthenticationType.oidc:
|
||||
return _configOIDC != null && _token != null;
|
||||
case AuthenticationType.none:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<PersonalAccount> _updateCurrentAccount({required TokenOIDC tokenOIDC}) async {
|
||||
final currentAccount = await _accountCacheManager.getCurrentAccount();
|
||||
|
||||
|
||||
@@ -172,8 +172,8 @@ class LoginController extends ReloadableController {
|
||||
}
|
||||
|
||||
@override
|
||||
void handleExceptionAction({Failure? failure, Exception? exception}) {
|
||||
logError('LoginController::handleExceptionAction:exception: $exception | failure: ${failure.runtimeType}');
|
||||
void handleUrgentException({Failure? failure, Exception? exception}) {
|
||||
logError('LoginController::handleUrgentException:Exception: $exception | Failure: $failure');
|
||||
if (failure is CheckOIDCIsAvailableFailure ||
|
||||
failure is GetStoredOidcConfigurationFailure ||
|
||||
failure is GetOIDCConfigurationFailure ||
|
||||
@@ -185,7 +185,7 @@ class LoginController extends ReloadableController {
|
||||
} else if (failure is GetSessionFailure) {
|
||||
clearAllData();
|
||||
} else {
|
||||
super.handleExceptionAction(failure: failure, exception: exception);
|
||||
super.handleUrgentException(failure: failure, exception: exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-7
@@ -153,6 +153,7 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
||||
import 'package:tmail_ui_user/main/utils/email_receive_manager.dart';
|
||||
import 'package:tmail_ui_user/main/utils/ios_notification_manager.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class MailboxDashBoardController extends ReloadableController {
|
||||
@@ -407,14 +408,19 @@ class MailboxDashBoardController extends ReloadableController {
|
||||
}
|
||||
|
||||
@override
|
||||
void handleExceptionAction({Failure? failure, Exception? exception}) {
|
||||
super.handleExceptionAction(failure: failure, exception: exception);
|
||||
if (failure is SendEmailFailure &&
|
||||
exception is NoNetworkError &&
|
||||
PlatformInfo.isMobile
|
||||
) {
|
||||
log('MailboxDashBoardController::handleExceptionAction(): $failure');
|
||||
void handleUrgentExceptionOnMobile({Failure? failure, Exception? exception}) {
|
||||
if (failure is SendEmailFailure && exception is NoNetworkError) {
|
||||
_storeSendingEmailInCaseOfSendingFailureInMobile(failure);
|
||||
} else {
|
||||
super.handleUrgentExceptionOnMobile(failure: failure, exception: exception);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> handleBrowserBeforeReloadAction(html.Event event) async {
|
||||
if (event is html.BeforeUnloadEvent
|
||||
&& composerOverlayState.value == ComposerOverlayState.active) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ class DeleteIdentityDialogBuilder extends StatelessWidget {
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white))
|
||||
..paddingButton(const EdgeInsets.only(bottom: 24, left: 24, right: 24))
|
||||
..marginButton(const EdgeInsets.only(bottom: 24, left: 24, right: 24))
|
||||
..backgroundColor(Colors.black26)
|
||||
..onConfirmButtonAction(AppLocalizations.of(context).delete, () =>
|
||||
onDeleteIdentityAction.call())
|
||||
|
||||
@@ -220,11 +220,10 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
}
|
||||
|
||||
@override
|
||||
void handleExceptionAction({Failure? failure, Exception? exception}) {
|
||||
super.handleExceptionAction(failure: failure, exception: exception);
|
||||
logError('ThreadController::handleExceptionAction(): failure: $failure | exception: $exception');
|
||||
void handleUrgentException({Failure? failure, Exception? exception}) {
|
||||
_resetLoadingMore();
|
||||
clearState();
|
||||
super.handleUrgentException(failure: failure, exception: exception);
|
||||
}
|
||||
|
||||
void _resetLoadingMore() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2024-07-10T13:53:40.940363",
|
||||
"@@last_modified": "2024-07-12T12:54:25.065342",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -3933,5 +3933,23 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"reconnect": "Reconnect",
|
||||
"@reconnect": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"sessionExpired": "Session expired",
|
||||
"@sessionExpired": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"dialogMessageSessionHasExpired": "The current session has expired. Please reconnect to the server",
|
||||
"@dialogMessageSessionHasExpired": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -4113,4 +4113,25 @@ class AppLocalizations {
|
||||
name: 'requestReadReceiptHasBeenDisabled'
|
||||
);
|
||||
}
|
||||
|
||||
String get reconnect {
|
||||
return Intl.message(
|
||||
'Reconnect',
|
||||
name: 'reconnect',
|
||||
);
|
||||
}
|
||||
|
||||
String get sessionExpired {
|
||||
return Intl.message(
|
||||
'Session expired',
|
||||
name: 'sessionExpired',
|
||||
);
|
||||
}
|
||||
|
||||
String get dialogMessageSessionHasExpired {
|
||||
return Intl.message(
|
||||
'The current session has expired. Please reconnect to the server',
|
||||
name: 'dialogMessageSessionHasExpired',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user