Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion integration_test/robots/email_robot.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_item_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/attachments_pin/email_attachments_pin_header_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_back_button.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/information_sender_and_receiver_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
Expand All @@ -16,7 +17,7 @@ class EmailRobot extends CoreRobot {
}

Future<void> tapDownloadAllButton() async {
await $(AppLocalizations().archiveAndDownload).tap();
await $(AppLocalizations().downloadAll).tap();
await $.pumpAndSettle();
}

Expand Down Expand Up @@ -80,6 +81,10 @@ class EmailRobot extends CoreRobot {
await $(InformationSenderAndReceiverBuilder).$(email).longPress();
}

Future<void> tapAttachmentPin() async {
await $(EmailAttachmentsPinHeaderWidget).$(InkWell).tap();
}

Future<void> onTapAttachmentItem() async {
await $(AttachmentItemWidget).$(InkWell).tap();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_item_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/attachments_pin/email_attachments_pin_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';

import '../../base/base_test_scenario.dart';
Expand Down Expand Up @@ -37,8 +37,9 @@ class ExportAttachmentScenario extends BaseTestScenario {

await threadRobot.openEmailWithSubject(subject);
await $.pumpAndSettle();
_expectAttachmentVisible();
_expectAttachmentPinVisible();

await emailRobot.tapAttachmentPin();
await emailRobot.onTapAttachmentItem();
await $.pumpAndSettle();

Expand All @@ -47,8 +48,8 @@ class ExportAttachmentScenario extends BaseTestScenario {
_expectExportDialogLoadingInvisible(appLocalizations);
}

void _expectAttachmentVisible() {
expect($(AttachmentItemWidget), findsOneWidget);
void _expectAttachmentPinVisible() {
expect($(EmailAttachmentsPinWidget), findsOneWidget);
}

void _expectEmailViewVisible() {
Expand Down
2 changes: 2 additions & 0 deletions lib/features/email/data/datasource/email_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,6 @@ abstract class EmailDataSource {
);

Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);

Future<bool> isPinAttachmentEnabled();
}
Original file line number Diff line number Diff line change
Expand Up @@ -611,4 +611,9 @@ class EmailDataSourceImpl extends EmailDataSource {
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest) {
throw UnimplementedError();
}

@override
Future<bool> isPinAttachmentEnabled() {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -612,4 +612,9 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource {
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest) {
throw UnimplementedError();
}

@override
Future<bool> isPinAttachmentEnabled() {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import 'package:tmail_ui_user/features/email/domain/model/view_entire_message_re
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';

Expand All @@ -53,6 +54,8 @@ class EmailLocalStorageDataSourceImpl extends EmailDataSource {
final ExceptionThrower _exceptionThrower;
final ImagePaths _imagePaths = Get.find<ImagePaths>();
final FileUtils _fileUtils = Get.find<FileUtils>();
final PreferencesSettingManager _settingManager =
Get.find<PreferencesSettingManager>();

EmailLocalStorageDataSourceImpl(
this._localStorageManager,
Expand Down Expand Up @@ -377,4 +380,10 @@ class EmailLocalStorageDataSourceImpl extends EmailDataSource {
}) {
throw UnimplementedError();
}

@override
Future<bool> isPinAttachmentEnabled() => Future.sync(() async {
final config = await _settingManager.getPinAttachmentsConfig();
return config.isEnabled;
}).catchError(_exceptionThrower.throwException);
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,9 @@ class EmailSessionStorageDatasourceImpl extends EmailDataSource {
}) {
throw UnimplementedError();
}

@override
Future<bool> isPinAttachmentEnabled() {
throw UnimplementedError();
}
}
5 changes: 5 additions & 0 deletions lib/features/email/data/repository/email_repository_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -617,4 +617,9 @@ class EmailRepositoryImpl extends EmailRepository {
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest) {
return emailDataSource[DataSourceType.local]!.generateEntireMessageAsDocument(entireMessageRequest);
}

@override
Future<bool> isPinAttachmentEnabled() {
return emailDataSource[DataSourceType.local]!.isPinAttachmentEnabled();
}
}
2 changes: 2 additions & 0 deletions lib/features/email/domain/repository/email_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,6 @@ abstract class EmailRepository {
);

Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);

Future<bool> isPinAttachmentEnabled();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';

class GettingPinAttachmentStatus extends LoadingState {}

class GetPinAttachmentStatusSuccess extends UIState {
final bool isEnabled;

GetPinAttachmentStatusSuccess(this.isEnabled);

@override
List<Object?> get props => [isEnabled];
}

class GetPinAttachmentStatusFailure extends FeatureFailure {
GetPinAttachmentStatusFailure(dynamic exception) : super(exception: exception,);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_pin_attachment_status_state.dart';

class GetPinAttachmentStatusInteractor {
final EmailRepository _emailRepository;

const GetPinAttachmentStatusInteractor(this._emailRepository);

Stream<Either<Failure, Success>> execute() async* {
try {
yield Right<Failure, Success>(GettingPinAttachmentStatus());
final isEnabled = await _emailRepository.isPinAttachmentEnabled();
yield Right<Failure, Success>(GetPinAttachmentStatusSuccess(isEnabled));
} catch (e) {
yield Left<Failure, Success>(GetPinAttachmentStatusFailure(e));
}
}
}
39 changes: 39 additions & 0 deletions lib/features/email/presentation/action/email_ui_action.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/email/attachment.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';

class EmailUIAction extends UIAction {
static final idle = EmailUIAction();
Expand Down Expand Up @@ -87,4 +89,41 @@ class CollapseEmailInThreadDetailAction extends EmailUIAction {

@override
List<Object?> get props => [emailId];
}

class DownloadEmailAttachmentInThreadDetailAction extends EmailUIAction {
final Attachment attachment;
final EmailId emailIdOpened;

DownloadEmailAttachmentInThreadDetailAction(
this.attachment,
this.emailIdOpened,
);

@override
List<Object?> get props => [attachment, emailIdOpened];
}

class ViewEmailAttachmentInThreadDetailAction extends EmailUIAction {
final AppLocalizations appLocalizations;
final Attachment attachment;
final EmailId emailIdOpened;

ViewEmailAttachmentInThreadDetailAction(
this.appLocalizations,
this.attachment,
this.emailIdOpened,
);

@override
List<Object?> get props => [appLocalizations, attachment, emailIdOpened];
}

class DownloadAllEmailAttachmentInThreadDetailAction extends EmailUIAction {
final EmailId emailIdOpened;

DownloadAllEmailAttachmentInThreadDetailAction(this.emailIdOpened);

@override
List<Object?> get props => [emailIdOpened];
}
4 changes: 4 additions & 0 deletions lib/features/email/presentation/bindings/email_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachme
import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_entire_message_as_document_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_pin_attachment_status_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_stored_email_state_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
Expand Down Expand Up @@ -190,6 +191,9 @@ class EmailBindings extends BaseBindings {
Get.find<EmailRepository>(),
));
}
Get.lazyPut(
() => GetPinAttachmentStatusInteractor(Get.find<EmailRepository>()),
);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {

GlobalObjectKey? get htmlViewKey => _threadDetailController?.expandedEmailHtmlViewKey;

ThreadDetailController? get threadDetailController => _threadDetailController;

SingleEmailController(
this._getEmailContentInteractor,
this._markAsEmailReadInteractor,
Expand Down Expand Up @@ -272,7 +274,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {

@override
void handleSuccessViewState(Success success) {
super.handleSuccessViewState(success);
if (success is GetEmailContentSuccess) {
_getEmailContentSuccess(success);
} else if (success is GetEmailContentFromCacheSuccess) {
Expand Down Expand Up @@ -327,12 +328,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
));
} else if (success is GettingHtmlContentFromAttachment) {
_updateAttachmentsViewState(success.attachment.blobId, Right(success));
} else {
super.handleSuccessViewState(success);
}
}

@override
void handleFailureViewState(Failure failure) {
super.handleFailureViewState(failure);
if (failure is MarkAsEmailReadFailure) {
_handleMarkAsEmailReadFailure(failure);
} else if (failure is DownloadAttachmentsFailure) {
Expand Down Expand Up @@ -361,6 +363,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_handleGetHtmlContentFromAttachmentFailure(failure);
} else if (failure is PreviewPDFFileFailure) {
_handlePreviewPDFFileFailure(failure);
} else {
super.handleFailureViewState(failure);
}
}

Expand Down Expand Up @@ -429,6 +433,15 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
worker.dispose();
}
Get.delete<SingleEmailController>(tag: _currentEmailId!.id.value);
} else if (action is DownloadEmailAttachmentInThreadDetailAction &&
action.emailIdOpened == _currentEmailId) {
handleDownloadAttachmentAction(action.attachment);
} else if (action is ViewEmailAttachmentInThreadDetailAction &&
action.emailIdOpened == _currentEmailId) {
handleViewAttachmentAction(action.appLocalizations, action.attachment);
} else if (action is DownloadAllEmailAttachmentInThreadDetailAction &&
action.emailIdOpened == _currentEmailId) {
handleDownloadAllAttachmentsAction();
}
}));

Expand Down Expand Up @@ -1762,7 +1775,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
(AttachmentListBottomSheetBuilder(context, attachments, imagePaths, _attachmentListScrollController, tag)
..onCloseButtonAction(() => popBack())
..onDownloadAttachmentFileAction((attachment) => handleDownloadAttachmentAction(attachment))
..onViewAttachmentFileAction((attachment) => handleViewAttachmentAction(context, attachment))
..onViewAttachmentFileAction((attachment) =>
handleViewAttachmentAction(
AppLocalizations.of(context),
attachment,
)
)
..onDownloadAllButtonAction(isDownloadAllSupported()
? () => downloadAllAttachmentsForWeb('TwakeMail-${DateTime.now()}')
: null
Expand All @@ -1779,7 +1797,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
backgroundColor: Colors.black.withAlpha(24),
onCloseButtonAction: () => popBack(),
onDownloadAttachmentFileAction: (attachment) => handleDownloadAttachmentAction(attachment),
onViewAttachmentFileAction: (attachment) => handleViewAttachmentAction(context, attachment),
onViewAttachmentFileAction: (attachment) =>
handleViewAttachmentAction(
AppLocalizations.of(context),
attachment,
),
onDownloadAllButtonAction: isDownloadAllSupported()
? () => downloadAllAttachmentsForWeb('TwakeMail-${DateTime.now()}')
: null,
Expand Down Expand Up @@ -2034,7 +2056,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
}

void handleDownloadAllAttachmentsAction(String outputFileName) {
void handleDownloadAllAttachmentsAction() {
final outputFileName = 'TwakeMail-${DateTime.now()}';
if (PlatformInfo.isWeb) {
downloadAllAttachmentsForWeb(outputFileName);
} else if (PlatformInfo.isMobile) {
Expand All @@ -2044,11 +2067,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
}

void handleViewAttachmentAction(BuildContext context, Attachment attachment) {
void handleViewAttachmentAction(
AppLocalizations appLocalizations,
Attachment attachment,
) {
if (PlatformInfo.isWeb && PlatformInfo.isCanvasKit && attachment.isPDFFile) {
previewPDFFileAction(context, attachment);
previewPDFFileAction(attachment);
} else if (attachment.isEMLFile) {
previewEMLFileAction(attachment.blobId, AppLocalizations.of(context));
previewEMLFileAction(attachment.blobId, appLocalizations);
} else if (attachment.isHTMLFile) {
final attachmentEvaluation = evaluateAttachment(attachment);
if (!attachmentEvaluation.canDownloadAttachment) {
Expand Down Expand Up @@ -2117,11 +2143,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
);
}

Future<void> previewPDFFileAction(BuildContext context, Attachment attachment) async {
Future<void> previewPDFFileAction(Attachment attachment) async {
if (accountId == null || session == null) {
appToast.showToastErrorMessage(
context,
AppLocalizations.of(context).noPreviewAvailable);
if (currentContext != null && currentOverlayContext != null) {
appToast.showToastErrorMessage(
currentOverlayContext!,
AppLocalizations.of(currentContext!).noPreviewAvailable,
);
}
return;
}

Expand Down
Loading
Loading