TF-3487 Handle get email content failure

This commit is contained in:
DatDang
2025-02-24 10:37:45 +07:00
committed by Dat H. Pham
parent 91dddff18d
commit 39cea85f86
4 changed files with 122 additions and 6 deletions
@@ -51,5 +51,6 @@ class GetEmailContentFromCacheSuccess extends UIState {
class GetEmailContentFailure extends FeatureFailure {
GetEmailContentFailure(dynamic exception) : super(exception: exception);
GetEmailContentFailure(dynamic exception, {super.onRetry})
: super(exception: exception);
}
@@ -49,7 +49,17 @@ class GetEmailContentInteractor {
}
} catch (e) {
log('GetEmailContentInteractor::execute(): exception = $e');
yield Left<Failure, Success>(GetEmailContentFailure(e));
yield Left<Failure, Success>(GetEmailContentFailure(
e,
onRetry: execute(
session,
accountId,
emailId,
baseDownloadUrl,
transformConfiguration,
additionalProperties: additionalProperties
),
));
}
}
@@ -97,7 +107,17 @@ class GetEmailContentInteractor {
}
} catch (e) {
logError('GetEmailContentInteractor::_getContentEmailFromServer():EXCEPTION: $e');
yield Left<Failure, Success>(GetEmailContentFailure(e));
yield Left<Failure, Success>(GetEmailContentFailure(
e,
onRetry: execute(
session,
accountId,
emailId,
baseDownloadUrl,
transformConfiguration,
additionalProperties: additionalProperties
),
));
}
}
@@ -35,6 +35,7 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:jmap_dart_client/jmap/mdn/disposition.dart';
import 'package:jmap_dart_client/jmap/mdn/mdn.dart';
import 'package:model/email/eml_attachment.dart';
import 'package:model/error_type_handler/unknown_uri_exception.dart';
import 'package:model/model.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
@@ -332,7 +333,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
} else if (failure is ParseCalendarEventFailure) {
_handleParseCalendarEventFailure(failure);
} else if (failure is GetEmailContentFailure) {
emailLoadedViewState.value = Left<Failure, Success>(failure);
_handleGetEmailContentFailure(failure);
} else if (failure is PrintEmailFailure) {
_showMessageWhenEmailPrintingFailed(failure);
} else if (failure is CalendarEventReplyFailure) {
@@ -348,6 +349,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
}
void _handleGetEmailContentFailure(GetEmailContentFailure failure) {
emailLoadedViewState.value = Left<Failure, Success>(failure);
showRetryToast(failure);
}
void _registerObxStreamListener() {
ever(mailboxDashBoardController.accountId, (accountId) {
if (accountId is AccountId) {
@@ -609,7 +615,20 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
));
} catch (e) {
logError('SingleEmailController::_getEmailContentAction(): $e');
consumeState(Stream.value(Left(GetEmailContentFailure(e))));
consumeState(Stream.value(Left(GetEmailContentFailure(
e,
onRetry: e is UnknownUriException
? null
: _getEmailContentInteractor.execute(
session!,
accountId!,
emailId,
session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl),
PlatformInfo.isWeb
? TransformConfiguration.forPreviewEmailOnWeb()
: TransformConfiguration.forPreviewEmail(),
),
))));
}
}
}
@@ -1,9 +1,10 @@
import 'dart:convert';
import 'dart:ui';
import 'package:core/core.dart';
import 'package:dartz/dartz.dart' hide State;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' hide State;
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
@@ -24,6 +25,7 @@ import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasourc
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
import 'package:tmail_ui_user/features/email/data/repository/calendar_event_repository_impl.dart';
import 'package:tmail_ui_user/features/email/domain/model/event_action.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart';
@@ -57,6 +59,9 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oi
import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart';
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations_delegate.dart';
import 'package:tmail_ui_user/main/localizations/localization_service.dart';
import 'package:tmail_ui_user/main/utils/toast_manager.dart';
import 'package:tmail_ui_user/main/utils/twake_app_manager.dart';
import 'package:uuid/uuid.dart';
@@ -449,4 +454,75 @@ void main() {
);
});
});
Widget makeTestableWidget({required Widget child}) {
return GetMaterialApp(
localizationsDelegates: const [
AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: LocalizationService.supportedLocales,
home: Scaffold(body: child),
);
}
testWidgets(
'should show retry toast '
'when handleFailureViewState is called with GetEmailContentFailure',
(tester) async {
// arrange
when(mailboxDashboardController.selectedEmail).thenReturn(Rxn(PresentationEmail()));
when(mailboxDashboardController.emailUIAction).thenReturn(Rxn(EmailUIAction()));
when(mailboxDashboardController.viewState).thenReturn(Rx(Right(UIState.idle)));
when(appToast.showToastMessageWithMultipleActions(
any,
any,
actions: anyNamed('actions'),
textColor: anyNamed('textColor'),
backgroundColor: anyNamed('backgroundColor'),
infinityToast: anyNamed('infinityToast'),
)).thenAnswer((realInvocation) {
AppToast().showToastMessageWithMultipleActions(
realInvocation.positionalArguments[0],
realInvocation.positionalArguments[1],
actions: realInvocation.namedArguments[const Symbol('actions')],
textColor: realInvocation.namedArguments[const Symbol('textColor')],
backgroundColor: realInvocation.namedArguments[const Symbol('backgroundColor')],
infinityToast: realInvocation.namedArguments[const Symbol('infinityToast')],
);
});
when(imagePaths.icUndo).thenReturn(ImagePaths().icUndo);
when(imagePaths.icClose).thenReturn(ImagePaths().icClose);
Get.put(singleEmailController);
final widget = makeTestableWidget(child: const _TestView());
await tester.pumpWidget(widget);
await tester.pump();
// act
singleEmailController.handleFailureViewState(GetEmailContentFailure(
null,
onRetry: const Stream.empty(),
));
await tester.pump();
// assert
expect(find.text(AppLocalizations().unknownError), findsOneWidget);
expect(find.text(AppLocalizations().retry), findsOneWidget);
expect(find.text(AppLocalizations().close), findsOneWidget);
// cleanup
Get.delete<SingleEmailController>();
},
);
}
class _TestView extends GetWidget<SingleEmailController> {
const _TestView();
@override
Widget build(BuildContext context) {
return const SizedBox();
}
}