TF-4050 Preview and download uploaded file in composer on web
This commit is contained in:
@@ -16,6 +16,7 @@ import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
|||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
import 'package:rule_filter/rule_filter/capability_rule_filter.dart';
|
import 'package:rule_filter/rule_filter/capability_rule_filter.dart';
|
||||||
import 'package:tmail_ui_user/features/base/before_reconnect_manager.dart';
|
import 'package:tmail_ui_user/features/base/before_reconnect_manager.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/emit_state_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/logout_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/logout_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
|
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
|
||||||
@@ -63,7 +64,7 @@ import 'package:tmail_ui_user/main/utils/twake_app_manager.dart';
|
|||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
abstract class BaseController extends GetxController
|
abstract class BaseController extends GetxController
|
||||||
with PopupContextMenuActionMixin, LogoutMixin {
|
with PopupContextMenuActionMixin, LogoutMixin, EmitStateMixin {
|
||||||
|
|
||||||
final CachingManager cachingManager = Get.find<CachingManager>();
|
final CachingManager cachingManager = Get.find<CachingManager>();
|
||||||
final LanguageCacheManager languageCacheManager = Get.find<LanguageCacheManager>();
|
final LanguageCacheManager languageCacheManager = Get.find<LanguageCacheManager>();
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||||
|
|
||||||
|
mixin EmitStateMixin {
|
||||||
|
void emitFailure({
|
||||||
|
required BaseController controller,
|
||||||
|
required FeatureFailure failure,
|
||||||
|
}) {
|
||||||
|
controller.consumeState(Stream.value(Left(failure)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_e
|
|||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_recipients_collapsed_extensions.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_recipients_collapsed_extensions.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_keyboard_shortcut_actions_extension.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_keyboard_shortcut_actions_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/mark_as_important_extension.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/mark_as_important_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/preview_upload_file_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/remove_draggable_email_address_between_recipient_fields_extension.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/remove_draggable_email_address_between_recipient_fields_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
|
||||||
@@ -70,6 +71,22 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final attachmentWidget = Obx(() {
|
||||||
|
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
||||||
|
return AttachmentComposerWidget(
|
||||||
|
listFileUploaded: controller.uploadController.listUploadAttachments,
|
||||||
|
isCollapsed: controller.isAttachmentCollapsed,
|
||||||
|
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
|
||||||
|
onPreviewAttachmentAction: (id) =>
|
||||||
|
controller.previewUploadFile(context, id),
|
||||||
|
onToggleExpandAttachmentAction: (isCollapsed) =>
|
||||||
|
controller.isAttachmentCollapsed = isCollapsed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
final bodyWidget = ResponsiveWidget(
|
final bodyWidget = ResponsiveWidget(
|
||||||
responsiveUtils: controller.responsiveUtils,
|
responsiveUtils: controller.responsiveUtils,
|
||||||
mobile: MobileResponsiveContainerView(
|
mobile: MobileResponsiveContainerView(
|
||||||
@@ -251,18 +268,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
attachmentWidget,
|
||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
|
||||||
return AttachmentComposerWidget(
|
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
|
||||||
isCollapsed: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
|
|
||||||
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
|
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
|
||||||
return ToolbarRichTextWidget(
|
return ToolbarRichTextWidget(
|
||||||
@@ -504,18 +510,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
attachmentWidget,
|
||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
|
||||||
return AttachmentComposerWidget(
|
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
|
||||||
isCollapsed: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
|
|
||||||
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
|
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
|
||||||
return ToolbarRichTextWidget(
|
return ToolbarRichTextWidget(
|
||||||
@@ -785,18 +780,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
attachmentWidget,
|
||||||
if (controller.uploadController.listUploadAttachments.isNotEmpty) {
|
|
||||||
return AttachmentComposerWidget(
|
|
||||||
listFileUploaded: controller.uploadController.listUploadAttachments,
|
|
||||||
isCollapsed: controller.isAttachmentCollapsed,
|
|
||||||
onDeleteAttachmentAction: controller.deleteAttachmentUploaded,
|
|
||||||
onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
|
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
|
||||||
return ToolbarRichTextWidget(
|
return ToolbarRichTextWidget(
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_attachment_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
|
extension PreviewUploadFileExtension on ComposerController {
|
||||||
|
void previewUploadFile(BuildContext context, UploadTaskId uploadId) {
|
||||||
|
final uploadFile = uploadController.getUploadFileId(uploadId);
|
||||||
|
|
||||||
|
if (uploadFile == null || uploadFile.attachment == null) {
|
||||||
|
appToast.showToastWarningMessage(
|
||||||
|
context,
|
||||||
|
AppLocalizations.of(context).noPreviewAvailable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mailboxDashBoardController.previewUploadFile(
|
||||||
|
context: context,
|
||||||
|
uploadFile: uploadFile,
|
||||||
|
isDialogLoadingVisible: true,
|
||||||
|
onPreviewOrDownloadAction: (attachment, isPreview) {
|
||||||
|
mailboxDashBoardController.downloadAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
previewerSupported: isPreview,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
|||||||
import 'package:core/presentation/views/text/middle_ellipsis_text.dart';
|
import 'package:core/presentation/views/text/middle_ellipsis_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_progress_loading_composer_widget.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_progress_loading_composer_widget.dart';
|
||||||
@@ -11,11 +10,11 @@ import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
|
|||||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart';
|
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart';
|
||||||
|
|
||||||
typedef OnDeleteAttachmentAction = void Function(UploadTaskId uploadTaskId);
|
typedef OnDeleteAttachmentAction = void Function(UploadTaskId uploadTaskId);
|
||||||
|
typedef OnPreviewAttachmentAction = void Function(UploadTaskId uploadTaskId);
|
||||||
|
|
||||||
class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||||
|
|
||||||
final _imagePaths = Get.find<ImagePaths>();
|
final ImagePaths imagePaths;
|
||||||
|
|
||||||
final String fileIcon;
|
final String fileIcon;
|
||||||
final String fileName;
|
final String fileName;
|
||||||
final String fileSize;
|
final String fileSize;
|
||||||
@@ -26,10 +25,12 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
|||||||
final EdgeInsetsGeometry? itemMargin;
|
final EdgeInsetsGeometry? itemMargin;
|
||||||
final EdgeInsetsGeometry? itemPadding;
|
final EdgeInsetsGeometry? itemPadding;
|
||||||
final OnDeleteAttachmentAction? onDeleteAttachmentAction;
|
final OnDeleteAttachmentAction? onDeleteAttachmentAction;
|
||||||
|
final OnPreviewAttachmentAction? onPreviewAttachmentAction;
|
||||||
final Widget? buttonAction;
|
final Widget? buttonAction;
|
||||||
|
|
||||||
AttachmentItemComposerWidget({
|
const AttachmentItemComposerWidget({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.imagePaths,
|
||||||
required this.fileIcon,
|
required this.fileIcon,
|
||||||
required this.fileName,
|
required this.fileName,
|
||||||
required this.fileSize,
|
required this.fileSize,
|
||||||
@@ -41,10 +42,65 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
|||||||
this.itemPadding,
|
this.itemPadding,
|
||||||
this.buttonAction,
|
this.buttonAction,
|
||||||
this.onDeleteAttachmentAction,
|
this.onDeleteAttachmentAction,
|
||||||
|
this.onPreviewAttachmentAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
Widget bodyItem = Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
fileIcon,
|
||||||
|
width: AttachmentItemComposerWidgetStyle.iconSize,
|
||||||
|
height: AttachmentItemComposerWidgetStyle.iconSize,
|
||||||
|
fit: BoxFit.fill
|
||||||
|
),
|
||||||
|
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
||||||
|
Flexible(
|
||||||
|
child: MiddleEllipsisText(
|
||||||
|
fileName,
|
||||||
|
style: AttachmentItemComposerWidgetStyle.labelTextStyle,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
||||||
|
Text(
|
||||||
|
fileSize,
|
||||||
|
style: AttachmentItemComposerWidgetStyle.sizeLabelTextStyle
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
AttachmentProgressLoadingComposerWidget(
|
||||||
|
uploadStatus: uploadStatus,
|
||||||
|
percentUploading: percentUploading,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
||||||
|
TMailButtonWidget.fromIcon(
|
||||||
|
icon: imagePaths.icCancel,
|
||||||
|
iconSize: AttachmentItemComposerWidgetStyle.deleteIconSize,
|
||||||
|
borderRadius: AttachmentItemComposerWidgetStyle.deleteIconRadius,
|
||||||
|
padding: AttachmentItemComposerWidgetStyle.deleteIconPadding,
|
||||||
|
iconColor: AttachmentItemComposerWidgetStyle.deleteIconColor,
|
||||||
|
onTapActionCallback: () => onDeleteAttachmentAction?.call(uploadTaskId),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (onPreviewAttachmentAction != null) {
|
||||||
|
bodyItem = InkWell(
|
||||||
|
onTap: () => onPreviewAttachmentAction!(uploadTaskId),
|
||||||
|
child: bodyItem,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(AttachmentItemComposerWidgetStyle.radius)),
|
borderRadius: const BorderRadius.all(Radius.circular(AttachmentItemComposerWidgetStyle.radius)),
|
||||||
@@ -54,52 +110,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
|||||||
width: AttachmentItemComposerWidgetStyle.width,
|
width: AttachmentItemComposerWidgetStyle.width,
|
||||||
padding: itemPadding ?? AttachmentItemComposerWidgetStyle.padding,
|
padding: itemPadding ?? AttachmentItemComposerWidgetStyle.padding,
|
||||||
margin: itemMargin,
|
margin: itemMargin,
|
||||||
child: Row(
|
child: bodyItem,
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(
|
|
||||||
fileIcon,
|
|
||||||
width: AttachmentItemComposerWidgetStyle.iconSize,
|
|
||||||
height: AttachmentItemComposerWidgetStyle.iconSize,
|
|
||||||
fit: BoxFit.fill
|
|
||||||
),
|
|
||||||
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
|
||||||
Flexible(
|
|
||||||
child: MiddleEllipsisText(
|
|
||||||
fileName,
|
|
||||||
style: AttachmentItemComposerWidgetStyle.labelTextStyle,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
|
||||||
Text(
|
|
||||||
fileSize,
|
|
||||||
style: AttachmentItemComposerWidgetStyle.sizeLabelTextStyle
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
AttachmentProgressLoadingComposerWidget(
|
|
||||||
uploadStatus: uploadStatus,
|
|
||||||
percentUploading: percentUploading,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
|
||||||
TMailButtonWidget.fromIcon(
|
|
||||||
icon: _imagePaths.icCancel,
|
|
||||||
iconSize: AttachmentItemComposerWidgetStyle.deleteIconSize,
|
|
||||||
borderRadius: AttachmentItemComposerWidgetStyle.deleteIconRadius,
|
|
||||||
padding: AttachmentItemComposerWidgetStyle.deleteIconPadding,
|
|
||||||
iconColor: AttachmentItemComposerWidgetStyle.deleteIconColor,
|
|
||||||
onTapActionCallback: () => onDeleteAttachmentAction?.call(uploadTaskId),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
@@ -76,6 +76,7 @@ class _MobileAttachmentComposerWidgetState extends State<MobileAttachmentCompose
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final file = _listFileDisplayed[index];
|
final file = _listFileDisplayed[index];
|
||||||
return AttachmentItemComposerWidget(
|
return AttachmentItemComposerWidget(
|
||||||
|
imagePaths: _imagePaths,
|
||||||
fileIcon: file.getIcon(_imagePaths),
|
fileIcon: file.getIcon(_imagePaths),
|
||||||
fileName: file.fileName,
|
fileName: file.fileName,
|
||||||
fileSize: filesize(file.fileSize),
|
fileSize: filesize(file.fileSize),
|
||||||
@@ -139,6 +140,7 @@ class _MobileAttachmentComposerWidgetState extends State<MobileAttachmentCompose
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final file = _listFileDisplayed[index];
|
final file = _listFileDisplayed[index];
|
||||||
return AttachmentItemComposerWidget(
|
return AttachmentItemComposerWidget(
|
||||||
|
imagePaths: _imagePaths,
|
||||||
fileIcon: file.getIcon(_imagePaths),
|
fileIcon: file.getIcon(_imagePaths),
|
||||||
fileName: file.fileName,
|
fileName: file.fileName,
|
||||||
fileSize: filesize(file.fileSize),
|
fileSize: filesize(file.fileSize),
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class AttachmentComposerWidget extends StatefulWidget {
|
|||||||
final bool isCollapsed;
|
final bool isCollapsed;
|
||||||
final OnDeleteAttachmentAction onDeleteAttachmentAction;
|
final OnDeleteAttachmentAction onDeleteAttachmentAction;
|
||||||
final OnToggleExpandAttachmentAction onToggleExpandAttachmentAction;
|
final OnToggleExpandAttachmentAction onToggleExpandAttachmentAction;
|
||||||
|
final OnPreviewAttachmentAction onPreviewAttachmentAction;
|
||||||
|
|
||||||
const AttachmentComposerWidget({
|
const AttachmentComposerWidget({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -23,6 +24,7 @@ class AttachmentComposerWidget extends StatefulWidget {
|
|||||||
required this.isCollapsed,
|
required this.isCollapsed,
|
||||||
required this.onDeleteAttachmentAction,
|
required this.onDeleteAttachmentAction,
|
||||||
required this.onToggleExpandAttachmentAction,
|
required this.onToggleExpandAttachmentAction,
|
||||||
|
required this.onPreviewAttachmentAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -76,6 +78,7 @@ class _AttachmentComposerWidgetState extends State<AttachmentComposerWidget> {
|
|||||||
runSpacing: AttachmentComposerWidgetStyle.listItemSpace,
|
runSpacing: AttachmentComposerWidgetStyle.listItemSpace,
|
||||||
children: widget.listFileUploaded
|
children: widget.listFileUploaded
|
||||||
.map((file) => AttachmentItemComposerWidget(
|
.map((file) => AttachmentItemComposerWidget(
|
||||||
|
imagePaths: _imagePaths,
|
||||||
fileIcon: file.getIcon(_imagePaths),
|
fileIcon: file.getIcon(_imagePaths),
|
||||||
fileName: file.fileName,
|
fileName: file.fileName,
|
||||||
fileSize: filesize(file.fileSize),
|
fileSize: filesize(file.fileSize),
|
||||||
@@ -83,6 +86,7 @@ class _AttachmentComposerWidgetState extends State<AttachmentComposerWidget> {
|
|||||||
percentUploading: file.percentUploading,
|
percentUploading: file.percentUploading,
|
||||||
uploadTaskId: file.uploadTaskId,
|
uploadTaskId: file.uploadTaskId,
|
||||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction,
|
onDeleteAttachmentAction: widget.onDeleteAttachmentAction,
|
||||||
|
onPreviewAttachmentAction: widget.onPreviewAttachmentAction,
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import 'package:model/account/account_request.dart';
|
|||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/download_datasource.dart';
|
import 'package:tmail_ui_user/features/download/data/datasource/download_datasource.dart';
|
||||||
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
|
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
|
||||||
|
|
||||||
class DownloadDatasourceImpl extends DownloadDatasource {
|
class DownloadDatasourceImpl extends DownloadDatasource {
|
||||||
+38
-2
@@ -10,12 +10,12 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
|||||||
import 'package:model/account/account_request.dart';
|
import 'package:model/account/account_request.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/data/datasource/download_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/download_datasource.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
|
||||||
|
|
||||||
class DownloadRepositoryImpl extends DownloadRepository {
|
class DownloadRepositoryImpl extends DownloadRepository {
|
||||||
final DownloadDatasource _downloadDatasource;
|
final DownloadDatasource _downloadDatasource;
|
||||||
@@ -131,4 +131,40 @@ class DownloadRepositoryImpl extends DownloadRepository {
|
|||||||
return _emailDataSource[DataSourceType.session]!
|
return _emailDataSource[DataSourceType.session]!
|
||||||
.getPreviewEMLContentInMemory(keyStored);
|
.getPreviewEMLContentInMemory(keyStored);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DownloadedResponse> exportAttachment(
|
||||||
|
Attachment attachment,
|
||||||
|
AccountId accountId,
|
||||||
|
String baseDownloadUrl,
|
||||||
|
AccountRequest accountRequest,
|
||||||
|
CancelToken cancelToken,
|
||||||
|
) {
|
||||||
|
return _emailDataSource[DataSourceType.network]!.exportAttachment(
|
||||||
|
attachment,
|
||||||
|
accountId,
|
||||||
|
baseDownloadUrl,
|
||||||
|
accountRequest,
|
||||||
|
cancelToken,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DownloadedResponse> exportAllAttachments(
|
||||||
|
AccountId accountId,
|
||||||
|
EmailId emailId,
|
||||||
|
String baseDownloadAllUrl,
|
||||||
|
String outputFileName,
|
||||||
|
AccountRequest accountRequest,
|
||||||
|
CancelToken cancelToken,
|
||||||
|
) {
|
||||||
|
return _emailDataSource[DataSourceType.network]!.exportAllAttachments(
|
||||||
|
accountId,
|
||||||
|
emailId,
|
||||||
|
baseDownloadAllUrl,
|
||||||
|
outputFileName,
|
||||||
|
accountRequest,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class DownloadAttachmentInteractorIsNull implements Exception {}
|
||||||
|
|
||||||
|
class CapabilityDownloadAllNotSupportedException implements Exception {}
|
||||||
|
|
||||||
|
class DownloadUrlIsNullException implements Exception {}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
enum DownloadSourceView {
|
||||||
|
emailView,
|
||||||
|
composerView;
|
||||||
|
}
|
||||||
+18
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:core/data/network/download/downloaded_response.dart';
|
||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
||||||
@@ -59,4 +60,21 @@ abstract class DownloadRepository {
|
|||||||
Future<void> removePreviewEmailEMLContentShared(String keyStored);
|
Future<void> removePreviewEmailEMLContentShared(String keyStored);
|
||||||
|
|
||||||
Future<EMLPreviewer> getPreviewEMLContentInMemory(String keyStored);
|
Future<EMLPreviewer> getPreviewEMLContentInMemory(String keyStored);
|
||||||
|
|
||||||
|
Future<DownloadedResponse> exportAttachment(
|
||||||
|
Attachment attachment,
|
||||||
|
AccountId accountId,
|
||||||
|
String baseDownloadUrl,
|
||||||
|
AccountRequest accountRequest,
|
||||||
|
CancelToken cancelToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<DownloadedResponse> exportAllAttachments(
|
||||||
|
AccountId accountId,
|
||||||
|
EmailId emailId,
|
||||||
|
String baseDownloadAllUrl,
|
||||||
|
String outputFileName,
|
||||||
|
AccountRequest accountRequest,
|
||||||
|
CancelToken cancelToken,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
|
||||||
|
class DownloadAndGettingHtmlContentFromAttachment extends LoadingState {
|
||||||
|
DownloadAndGettingHtmlContentFromAttachment({
|
||||||
|
required this.blobId,
|
||||||
|
this.sourceView,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Id? blobId;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [blobId, sourceView];
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadAndGetHtmlContentFromAttachmentSuccess extends UIState {
|
||||||
|
DownloadAndGetHtmlContentFromAttachmentSuccess({
|
||||||
|
required this.sanitizedHtmlContent,
|
||||||
|
required this.htmlAttachmentTitle,
|
||||||
|
required this.attachment,
|
||||||
|
required this.accountId,
|
||||||
|
required this.session,
|
||||||
|
this.sourceView,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String sanitizedHtmlContent;
|
||||||
|
final String htmlAttachmentTitle;
|
||||||
|
final Attachment attachment;
|
||||||
|
final AccountId accountId;
|
||||||
|
final Session session;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
sanitizedHtmlContent,
|
||||||
|
htmlAttachmentTitle,
|
||||||
|
attachment,
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
sourceView,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadAndGetHtmlContentFromAttachmentFailure extends FeatureFailure {
|
||||||
|
DownloadAndGetHtmlContentFromAttachmentFailure({
|
||||||
|
super.exception,
|
||||||
|
required this.blobId,
|
||||||
|
this.sourceView,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Id? blobId;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [blobId, sourceView];
|
||||||
|
}
|
||||||
+47
-9
@@ -4,6 +4,7 @@ import 'package:core/presentation/state/success.dart';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
|
||||||
class IdleDownloadAttachmentForWeb extends UIState {}
|
class IdleDownloadAttachmentForWeb extends UIState {}
|
||||||
|
|
||||||
@@ -13,11 +14,24 @@ class StartDownloadAttachmentForWeb extends UIState {
|
|||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
final CancelToken? cancelToken;
|
final CancelToken? cancelToken;
|
||||||
final bool previewerSupported;
|
final bool previewerSupported;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
StartDownloadAttachmentForWeb(this.taskId, this.attachment, [this.cancelToken, this.previewerSupported = false]);
|
StartDownloadAttachmentForWeb(
|
||||||
|
this.taskId,
|
||||||
|
this.attachment, [
|
||||||
|
this.cancelToken,
|
||||||
|
this.previewerSupported = false,
|
||||||
|
this.sourceView,
|
||||||
|
]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [taskId, attachment, cancelToken, previewerSupported];
|
List<Object?> get props => [
|
||||||
|
taskId,
|
||||||
|
attachment,
|
||||||
|
cancelToken,
|
||||||
|
previewerSupported,
|
||||||
|
sourceView,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadingAttachmentForWeb extends UIState {
|
class DownloadingAttachmentForWeb extends UIState {
|
||||||
@@ -27,22 +41,25 @@ class DownloadingAttachmentForWeb extends UIState {
|
|||||||
final double progress;
|
final double progress;
|
||||||
final int downloaded;
|
final int downloaded;
|
||||||
final int total;
|
final int total;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
DownloadingAttachmentForWeb(
|
DownloadingAttachmentForWeb(
|
||||||
this.taskId,
|
this.taskId,
|
||||||
this.attachment,
|
this.attachment,
|
||||||
this.progress,
|
this.progress,
|
||||||
this.downloaded,
|
this.downloaded,
|
||||||
this.total
|
this.total,
|
||||||
|
this.sourceView,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [
|
List<Object?> get props => [
|
||||||
taskId,
|
taskId,
|
||||||
attachment,
|
attachment,
|
||||||
progress,
|
progress,
|
||||||
downloaded,
|
downloaded,
|
||||||
total
|
total,
|
||||||
|
sourceView,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +69,24 @@ class DownloadAttachmentForWebSuccess extends UIState {
|
|||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
final Uint8List bytes;
|
final Uint8List bytes;
|
||||||
final bool previewerSupported;
|
final bool previewerSupported;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
DownloadAttachmentForWebSuccess(this.taskId, this.attachment, this.bytes, this.previewerSupported);
|
DownloadAttachmentForWebSuccess(
|
||||||
|
this.taskId,
|
||||||
|
this.attachment,
|
||||||
|
this.bytes,
|
||||||
|
this.previewerSupported,
|
||||||
|
this.sourceView,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [taskId, attachment, bytes, previewerSupported];
|
List<Object?> get props => [
|
||||||
|
taskId,
|
||||||
|
attachment,
|
||||||
|
bytes,
|
||||||
|
previewerSupported,
|
||||||
|
sourceView,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadAttachmentForWebFailure extends FeatureFailure {
|
class DownloadAttachmentForWebFailure extends FeatureFailure {
|
||||||
@@ -64,14 +94,22 @@ class DownloadAttachmentForWebFailure extends FeatureFailure {
|
|||||||
final DownloadTaskId? taskId;
|
final DownloadTaskId? taskId;
|
||||||
final Attachment? attachment;
|
final Attachment? attachment;
|
||||||
final CancelToken? cancelToken;
|
final CancelToken? cancelToken;
|
||||||
|
final DownloadSourceView? sourceView;
|
||||||
|
|
||||||
DownloadAttachmentForWebFailure({
|
DownloadAttachmentForWebFailure({
|
||||||
this.attachment,
|
this.attachment,
|
||||||
this.taskId,
|
this.taskId,
|
||||||
this.cancelToken,
|
this.cancelToken,
|
||||||
super.exception
|
this.sourceView,
|
||||||
|
super.exception,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [attachment, taskId, cancelToken, ...super.props];
|
List<Object?> get props => [
|
||||||
|
attachment,
|
||||||
|
taskId,
|
||||||
|
cancelToken,
|
||||||
|
sourceView,
|
||||||
|
...super.props,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
|
||||||
|
class GettingHtmlContentFromUploadFile extends LoadingState {}
|
||||||
|
|
||||||
|
class GetHtmlContentFromUploadFileSuccess extends UIState {
|
||||||
|
GetHtmlContentFromUploadFileSuccess({
|
||||||
|
required this.sanitizedHtmlContent,
|
||||||
|
required this.htmlAttachmentTitle,
|
||||||
|
required this.attachment,
|
||||||
|
required this.accountId,
|
||||||
|
required this.session,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String sanitizedHtmlContent;
|
||||||
|
final String htmlAttachmentTitle;
|
||||||
|
final Attachment attachment;
|
||||||
|
final AccountId? accountId;
|
||||||
|
final Session? session;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
sanitizedHtmlContent,
|
||||||
|
htmlAttachmentTitle,
|
||||||
|
attachment,
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetHtmlContentFromUploadFileFailure extends FeatureFailure {
|
||||||
|
GetHtmlContentFromUploadFileFailure({super.exception});
|
||||||
|
}
|
||||||
+2
-2
@@ -8,8 +8,8 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
|||||||
class ParsingEmailByBlobId extends LoadingState {}
|
class ParsingEmailByBlobId extends LoadingState {}
|
||||||
|
|
||||||
class ParseEmailByBlobIdSuccess extends UIState {
|
class ParseEmailByBlobIdSuccess extends UIState {
|
||||||
final AccountId? accountId;
|
final AccountId accountId;
|
||||||
final Session? session;
|
final Session session;
|
||||||
final String ownEmailAddress;
|
final String ownEmailAddress;
|
||||||
final Email email;
|
final Email email;
|
||||||
final Id blobId;
|
final Id blobId;
|
||||||
+6
-2
@@ -3,20 +3,23 @@ import 'package:core/presentation/state/success.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
class PreviewingEmailFromEmlFile extends LoadingState {}
|
class PreviewingEmailFromEmlFile extends LoadingState {}
|
||||||
|
|
||||||
class PreviewEmailFromEmlFileSuccess extends UIState {
|
class PreviewEmailFromEmlFileSuccess extends UIState {
|
||||||
final EMLPreviewer emlPreviewer;
|
final EMLPreviewer emlPreviewer;
|
||||||
final AccountId? accountId;
|
final AccountId accountId;
|
||||||
final Session? session;
|
final Session session;
|
||||||
final String ownEmailAddress;
|
final String ownEmailAddress;
|
||||||
|
final AppLocalizations appLocalizations;
|
||||||
|
|
||||||
PreviewEmailFromEmlFileSuccess(
|
PreviewEmailFromEmlFileSuccess(
|
||||||
this.emlPreviewer,
|
this.emlPreviewer,
|
||||||
this.accountId,
|
this.accountId,
|
||||||
this.session,
|
this.session,
|
||||||
this.ownEmailAddress,
|
this.ownEmailAddress,
|
||||||
|
this.appLocalizations,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -25,6 +28,7 @@ class PreviewEmailFromEmlFileSuccess extends UIState {
|
|||||||
accountId,
|
accountId,
|
||||||
session,
|
session,
|
||||||
ownEmailAddress,
|
ownEmailAddress,
|
||||||
|
appLocalizations,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
+2
-2
@@ -13,11 +13,11 @@ import 'package:model/account/authentication_type.dart';
|
|||||||
import 'package:model/account/password.dart';
|
import 'package:model/account/password.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_all_attachments_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_all_attachments_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class DownloadAllAttachmentsForWebInteractor {
|
class DownloadAllAttachmentsForWebInteractor {
|
||||||
const DownloadAllAttachmentsForWebInteractor(
|
const DownloadAllAttachmentsForWebInteractor(
|
||||||
+42
-19
@@ -7,14 +7,16 @@ import 'package:core/utils/app_logger.dart';
|
|||||||
import 'package:core/utils/string_convert.dart';
|
import 'package:core/utils/string_convert.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_html_content_from_attachment_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_and_get_html_content_from_attachment_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
|
|
||||||
class GetHtmlContentFromAttachmentInteractor {
|
class DownloadAndGetHtmlContentFromAttachmentInteractor {
|
||||||
GetHtmlContentFromAttachmentInteractor(
|
DownloadAndGetHtmlContentFromAttachmentInteractor(
|
||||||
this._downloadAttachmentForWebInteractor,
|
this._downloadAttachmentForWebInteractor,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -22,31 +24,41 @@ class GetHtmlContentFromAttachmentInteractor {
|
|||||||
|
|
||||||
Stream<Either<Failure, Success>> execute(
|
Stream<Either<Failure, Success>> execute(
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
|
Session session,
|
||||||
Attachment attachment,
|
Attachment attachment,
|
||||||
DownloadTaskId taskId,
|
DownloadTaskId taskId,
|
||||||
String baseDownloadUrl,
|
String baseDownloadUrl,
|
||||||
TransformConfiguration transformConfiguration,
|
TransformConfiguration transformConfiguration, {
|
||||||
) async* {
|
DownloadSourceView? sourceView,
|
||||||
|
}) async* {
|
||||||
try {
|
try {
|
||||||
yield Right(GettingHtmlContentFromAttachment(attachment: attachment));
|
yield Right(DownloadAndGettingHtmlContentFromAttachment(
|
||||||
|
blobId: attachment.blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
|
));
|
||||||
final downloadState = await _downloadAttachmentForWebInteractor.execute(
|
final downloadState = await _downloadAttachmentForWebInteractor.execute(
|
||||||
taskId,
|
taskId,
|
||||||
attachment,
|
attachment,
|
||||||
accountId,
|
accountId,
|
||||||
baseDownloadUrl,
|
baseDownloadUrl,
|
||||||
|
sourceView: sourceView,
|
||||||
).last;
|
).last;
|
||||||
|
|
||||||
Either<Failure, Success>? sanitizeState;
|
Either<Failure, Success>? sanitizeState;
|
||||||
await downloadState.fold(
|
await downloadState.fold(
|
||||||
(failure) {
|
(failure) {
|
||||||
sanitizeState = Left(GetHtmlContentFromAttachmentFailure(
|
sanitizeState = Left(DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
exception: failure is FeatureFailure ? failure.exception : null,
|
exception: failure is FeatureFailure ? failure.exception : null,
|
||||||
attachment: attachment,
|
blobId: attachment.blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
(success) async {
|
(success) async {
|
||||||
if (success is! DownloadAttachmentForWebSuccess) {
|
if (success is! DownloadAttachmentForWebSuccess) {
|
||||||
sanitizeState = Right(GettingHtmlContentFromAttachment(attachment: attachment));
|
sanitizeState = Right(DownloadAndGettingHtmlContentFromAttachment(
|
||||||
|
blobId: attachment.blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
final htmlContent = StringConvert.decodeFromBytes(
|
final htmlContent = StringConvert.decodeFromBytes(
|
||||||
success.bytes,
|
success.bytes,
|
||||||
@@ -57,6 +69,9 @@ class GetHtmlContentFromAttachmentInteractor {
|
|||||||
htmlContent,
|
htmlContent,
|
||||||
transformConfiguration,
|
transformConfiguration,
|
||||||
attachment,
|
attachment,
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
sourceView,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -65,17 +80,18 @@ class GetHtmlContentFromAttachmentInteractor {
|
|||||||
if (sanitizeState != null) {
|
if (sanitizeState != null) {
|
||||||
yield sanitizeState!;
|
yield sanitizeState!;
|
||||||
} else {
|
} else {
|
||||||
yield Left(GetHtmlContentFromAttachmentFailure(
|
yield Left(DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
exception: null,
|
exception: null,
|
||||||
attachment: attachment,
|
blobId: attachment.blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('GetHtmlContentFromAttachmentInteractor:exception: $e');
|
logError('GetHtmlContentFromAttachmentInteractor:exception: $e');
|
||||||
yield Left(GetHtmlContentFromAttachmentFailure(
|
yield Left(DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
exception: e,
|
exception: e,
|
||||||
attachment: attachment,
|
blobId: attachment.blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,21 +100,28 @@ class GetHtmlContentFromAttachmentInteractor {
|
|||||||
String htmlContent,
|
String htmlContent,
|
||||||
TransformConfiguration transformConfiguration,
|
TransformConfiguration transformConfiguration,
|
||||||
Attachment attachment,
|
Attachment attachment,
|
||||||
|
AccountId accountId,
|
||||||
|
Session session,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final sanitizedHtmlContent = await _downloadAttachmentForWebInteractor
|
final sanitizedHtmlContent = await _downloadAttachmentForWebInteractor
|
||||||
.downloadRepository
|
.downloadRepository
|
||||||
.sanitizeHtmlContent(htmlContent, transformConfiguration);
|
.sanitizeHtmlContent(htmlContent, transformConfiguration);
|
||||||
|
|
||||||
return Right(GetHtmlContentFromAttachmentSuccess(
|
return Right(DownloadAndGetHtmlContentFromAttachmentSuccess(
|
||||||
sanitizedHtmlContent: sanitizedHtmlContent,
|
sanitizedHtmlContent: sanitizedHtmlContent,
|
||||||
htmlAttachmentTitle: attachment.generateFileName(),
|
htmlAttachmentTitle: attachment.generateFileName(),
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
sourceView: sourceView,
|
||||||
));
|
));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Left(GetHtmlContentFromAttachmentFailure(
|
return Left(DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
exception: e,
|
exception: e,
|
||||||
attachment: attachment,
|
blobId: attachment.blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+18
-5
@@ -11,11 +11,12 @@ import 'package:model/account/authentication_type.dart';
|
|||||||
import 'package:model/account/password.dart';
|
import 'package:model/account/password.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class DownloadAttachmentForWebInteractor {
|
class DownloadAttachmentForWebInteractor {
|
||||||
final DownloadRepository downloadRepository;
|
final DownloadRepository downloadRepository;
|
||||||
@@ -37,10 +38,20 @@ class DownloadAttachmentForWebInteractor {
|
|||||||
StreamController<Either<Failure, Success>>? onReceiveController,
|
StreamController<Either<Failure, Success>>? onReceiveController,
|
||||||
CancelToken? cancelToken,
|
CancelToken? cancelToken,
|
||||||
bool previewerSupported = false,
|
bool previewerSupported = false,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
}) async* {
|
}) async* {
|
||||||
try {
|
try {
|
||||||
yield Right<Failure, Success>(StartDownloadAttachmentForWeb(taskId, attachment, cancelToken, previewerSupported));
|
final loadingState = Right<Failure, Success>(
|
||||||
onReceiveController?.add(Right(StartDownloadAttachmentForWeb(taskId, attachment, cancelToken, previewerSupported)));
|
StartDownloadAttachmentForWeb(
|
||||||
|
taskId,
|
||||||
|
attachment,
|
||||||
|
cancelToken,
|
||||||
|
previewerSupported,
|
||||||
|
sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
yield loadingState;
|
||||||
|
onReceiveController?.add(loadingState);
|
||||||
|
|
||||||
final currentAccount = await _accountRepository.getCurrentAccount();
|
final currentAccount = await _accountRepository.getCurrentAccount();
|
||||||
AccountRequest? accountRequest;
|
AccountRequest? accountRequest;
|
||||||
@@ -72,6 +83,7 @@ class DownloadAttachmentForWebInteractor {
|
|||||||
attachment,
|
attachment,
|
||||||
bytesDownloaded,
|
bytesDownloaded,
|
||||||
previewerSupported,
|
previewerSupported,
|
||||||
|
sourceView,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
@@ -79,8 +91,9 @@ class DownloadAttachmentForWebInteractor {
|
|||||||
DownloadAttachmentForWebFailure(
|
DownloadAttachmentForWebFailure(
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
taskId: taskId,
|
taskId: taskId,
|
||||||
exception: exception,
|
sourceView: sourceView,
|
||||||
cancelToken: cancelToken,
|
cancelToken: cancelToken,
|
||||||
|
exception: exception,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+10
-10
@@ -9,31 +9,31 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
|||||||
import 'package:model/account/account_request.dart';
|
import 'package:model/account/account_request.dart';
|
||||||
import 'package:model/account/authentication_type.dart';
|
import 'package:model/account/authentication_type.dart';
|
||||||
import 'package:model/account/password.dart';
|
import 'package:model/account/password.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/export_all_attachments_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/export_all_attachments_state.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||||
|
|
||||||
class ExportAllAttachmentsInteractor {
|
class ExportAllAttachmentsInteractor {
|
||||||
const ExportAllAttachmentsInteractor(
|
const ExportAllAttachmentsInteractor(
|
||||||
this._emailRepository,
|
this._downloadRepository,
|
||||||
this._accountRepository,
|
this._accountRepository,
|
||||||
this._authenticationOIDCRepository,
|
this._authenticationOIDCRepository,
|
||||||
this.credentialRepository,
|
this._credentialRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
final EmailRepository _emailRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
final AccountRepository _accountRepository;
|
final AccountRepository _accountRepository;
|
||||||
final AuthenticationOIDCRepository _authenticationOIDCRepository;
|
final AuthenticationOIDCRepository _authenticationOIDCRepository;
|
||||||
final CredentialRepository credentialRepository;
|
final CredentialRepository _credentialRepository;
|
||||||
|
|
||||||
Stream<Either<Failure, Success>> execute(
|
Stream<Either<Failure, Success>> execute(
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
String baseDownloadAllUrl,
|
String baseDownloadAllUrl,
|
||||||
String outputFileName,
|
String outputFileName,
|
||||||
{CancelToken? cancelToken}
|
CancelToken cancelToken,
|
||||||
) async* {
|
) async* {
|
||||||
try {
|
try {
|
||||||
yield Right(ExportingAllAttachments());
|
yield Right(ExportingAllAttachments());
|
||||||
@@ -43,20 +43,20 @@ class ExportAllAttachmentsInteractor {
|
|||||||
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
|
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
|
||||||
accountRequest = AccountRequest.withOidc(token: tokenOidc);
|
accountRequest = AccountRequest.withOidc(token: tokenOidc);
|
||||||
} else {
|
} else {
|
||||||
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
|
final authenticationInfoCache = await _credentialRepository.getAuthenticationInfoStored();
|
||||||
accountRequest = AccountRequest.withBasic(
|
accountRequest = AccountRequest.withBasic(
|
||||||
userName: UserName(authenticationInfoCache.username),
|
userName: UserName(authenticationInfoCache.username),
|
||||||
password: Password(authenticationInfoCache.password),
|
password: Password(authenticationInfoCache.password),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final result = await _emailRepository.exportAllAttachments(
|
final result = await _downloadRepository.exportAllAttachments(
|
||||||
accountId,
|
accountId,
|
||||||
emailId,
|
emailId,
|
||||||
baseDownloadAllUrl,
|
baseDownloadAllUrl,
|
||||||
outputFileName,
|
outputFileName,
|
||||||
accountRequest,
|
accountRequest,
|
||||||
cancelToken: cancelToken,
|
cancelToken,
|
||||||
);
|
);
|
||||||
|
|
||||||
yield Right(ExportAllAttachmentsSuccess(result));
|
yield Right(ExportAllAttachmentsSuccess(result));
|
||||||
+8
-8
@@ -6,21 +6,21 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/user_name.dart';
|
import 'package:jmap_dart_client/jmap/core/user_name.dart';
|
||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/export_attachment_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/export_attachment_state.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||||
|
|
||||||
class ExportAttachmentInteractor {
|
class ExportAttachmentInteractor {
|
||||||
final EmailRepository emailRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
final CredentialRepository credentialRepository;
|
final CredentialRepository _credentialRepository;
|
||||||
final AccountRepository _accountRepository;
|
final AccountRepository _accountRepository;
|
||||||
final AuthenticationOIDCRepository _authenticationOIDCRepository;
|
final AuthenticationOIDCRepository _authenticationOIDCRepository;
|
||||||
|
|
||||||
ExportAttachmentInteractor(
|
ExportAttachmentInteractor(
|
||||||
this.emailRepository,
|
this._downloadRepository,
|
||||||
this.credentialRepository,
|
this._credentialRepository,
|
||||||
this._accountRepository,
|
this._accountRepository,
|
||||||
this._authenticationOIDCRepository,
|
this._authenticationOIDCRepository,
|
||||||
);
|
);
|
||||||
@@ -40,14 +40,14 @@ class ExportAttachmentInteractor {
|
|||||||
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
|
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
|
||||||
accountRequest = AccountRequest.withOidc(token: tokenOidc);
|
accountRequest = AccountRequest.withOidc(token: tokenOidc);
|
||||||
} else {
|
} else {
|
||||||
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
|
final authenticationInfoCache = await _credentialRepository.getAuthenticationInfoStored();
|
||||||
accountRequest = AccountRequest.withBasic(
|
accountRequest = AccountRequest.withBasic(
|
||||||
userName: UserName(authenticationInfoCache.username),
|
userName: UserName(authenticationInfoCache.username),
|
||||||
password: Password(authenticationInfoCache.password),
|
password: Password(authenticationInfoCache.password),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final downloadedResponse = await emailRepository.exportAttachment(
|
final downloadedResponse = await _downloadRepository.exportAttachment(
|
||||||
attachment,
|
attachment,
|
||||||
accountId,
|
accountId,
|
||||||
baseDownloadUrl,
|
baseDownloadUrl,
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/dom/sanitize_hyper_link_tag_in_html_transformers.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
||||||
|
import 'package:core/utils/string_convert.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/get_html_content_from_upload_file_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||||
|
|
||||||
|
class GetHtmlContentFromUploadFileInteractor {
|
||||||
|
final DownloadRepository _downloadRepository;
|
||||||
|
|
||||||
|
GetHtmlContentFromUploadFileInteractor(this._downloadRepository);
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> execute({
|
||||||
|
required UploadFileState uploadFile,
|
||||||
|
required Session? session,
|
||||||
|
required AccountId? accountId,
|
||||||
|
}) async* {
|
||||||
|
try {
|
||||||
|
yield Right(GettingHtmlContentFromUploadFile());
|
||||||
|
|
||||||
|
final htmlContent = StringConvert.decodeFromBytes(
|
||||||
|
uploadFile.file!.bytes!,
|
||||||
|
charset: uploadFile.attachment!.charset,
|
||||||
|
isHtml: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final sanitizedHtmlContent =
|
||||||
|
await _downloadRepository.sanitizeHtmlContent(
|
||||||
|
htmlContent,
|
||||||
|
TransformConfiguration.create(
|
||||||
|
customDomTransformers: [SanitizeHyperLinkTagInHtmlTransformer()],
|
||||||
|
customTextTransformers: [
|
||||||
|
const StandardizeHtmlSanitizingTransformers()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
yield Right(GetHtmlContentFromUploadFileSuccess(
|
||||||
|
sanitizedHtmlContent: sanitizedHtmlContent,
|
||||||
|
htmlAttachmentTitle: uploadFile.attachment!.generateFileName(),
|
||||||
|
attachment: uploadFile.attachment!,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
));
|
||||||
|
} catch (e) {
|
||||||
|
yield Left(GetHtmlContentFromUploadFileFailure(exception: e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_preview_email_eml_content_shared_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/get_preview_email_eml_content_shared_state.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class GetPreviewEmailEMLContentSharedInteractor {
|
class GetPreviewEmailEMLContentSharedInteractor {
|
||||||
final DownloadRepository _downloadRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_preview_eml_content_in_memory_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/get_preview_eml_content_in_memory_state.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class GetPreviewEmlContentInMemoryInteractor {
|
class GetPreviewEmlContentInMemoryInteractor {
|
||||||
final DownloadRepository _downloadRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/move_preview_eml_content_from_persistent_to_memory_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/move_preview_eml_content_from_persistent_to_memory_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class MovePreviewEmlContentFromPersistentToMemoryInteractor {
|
class MovePreviewEmlContentFromPersistentToMemoryInteractor {
|
||||||
final DownloadRepository _downloadRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
+2
-2
@@ -4,8 +4,8 @@ import 'package:dartz/dartz.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/parse_email_by_blob_id_state.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class ParseEmailByBlobIdInteractor {
|
class ParseEmailByBlobIdInteractor {
|
||||||
final DownloadRepository _downloadRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
+3
-2
@@ -3,9 +3,9 @@ import 'package:core/presentation/state/success.dart';
|
|||||||
import 'package:core/utils/platform_info.dart';
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/preview_email_from_eml_file_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class PreviewEmailFromEmlFileInteractor {
|
class PreviewEmailFromEmlFileInteractor {
|
||||||
final DownloadRepository _downloadRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
@@ -43,6 +43,7 @@ class PreviewEmailFromEmlFileInteractor {
|
|||||||
previewEmailEMLRequest.accountId,
|
previewEmailEMLRequest.accountId,
|
||||||
previewEmailEMLRequest.session,
|
previewEmailEMLRequest.session,
|
||||||
previewEmailEMLRequest.ownEmailAddress,
|
previewEmailEMLRequest.ownEmailAddress,
|
||||||
|
previewEmailEMLRequest.appLocalizations,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/remove_preview_email_eml_content_shared_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/remove_preview_email_eml_content_shared_state.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
class RemovePreviewEmailEmlContentSharedInteractor {
|
class RemovePreviewEmailEmlContentSharedInteractor {
|
||||||
final DownloadRepository _downloadRepository;
|
final DownloadRepository _downloadRepository;
|
||||||
+38
-14
@@ -3,6 +3,22 @@ import 'package:get/get.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
|
import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart';
|
import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart';
|
||||||
import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart';
|
import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/data/datasource/download_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/data/datasource_impl/download_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/data/repository/download_repository_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_all_attachments_for_web_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_and_get_html_content_from_attachment_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/export_all_attachments_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/export_attachment_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_html_content_from_upload_file_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_preview_email_eml_content_shared_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_preview_eml_content_in_memory_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/move_preview_eml_content_from_persistent_to_memory_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/parse_email_by_blob_id_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/preview_email_from_eml_file_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/remove_preview_email_eml_content_shared_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
||||||
@@ -11,22 +27,9 @@ import 'package:tmail_ui_user/features/email/data/datasource_impl/email_session_
|
|||||||
import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasource_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasource_impl.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/download_datasource.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/download_datasource_impl.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/download_repository_impl.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
|
||||||
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
|
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
|
||||||
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
|
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
|
||||||
|
|
||||||
@@ -84,6 +87,22 @@ class DownloadInteractorBindings extends InteractorsBindings {
|
|||||||
Get.find<CredentialRepository>(),
|
Get.find<CredentialRepository>(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Get.lazyPut(
|
||||||
|
() => ExportAttachmentInteractor(
|
||||||
|
Get.find<DownloadRepository>(),
|
||||||
|
Get.find<CredentialRepository>(),
|
||||||
|
Get.find<AccountRepository>(),
|
||||||
|
Get.find<AuthenticationOIDCRepository>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Get.lazyPut(
|
||||||
|
() => ExportAllAttachmentsInteractor(
|
||||||
|
Get.find<DownloadRepository>(),
|
||||||
|
Get.find<AccountRepository>(),
|
||||||
|
Get.find<AuthenticationOIDCRepository>(),
|
||||||
|
Get.find<CredentialRepository>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
Get.lazyPut(
|
Get.lazyPut(
|
||||||
() => ParseEmailByBlobIdInteractor(Get.find<DownloadRepository>()),
|
() => ParseEmailByBlobIdInteractor(Get.find<DownloadRepository>()),
|
||||||
);
|
);
|
||||||
@@ -91,7 +110,7 @@ class DownloadInteractorBindings extends InteractorsBindings {
|
|||||||
() => PreviewEmailFromEmlFileInteractor(Get.find<DownloadRepository>()),
|
() => PreviewEmailFromEmlFileInteractor(Get.find<DownloadRepository>()),
|
||||||
);
|
);
|
||||||
Get.lazyPut(
|
Get.lazyPut(
|
||||||
() => GetHtmlContentFromAttachmentInteractor(
|
() => DownloadAndGetHtmlContentFromAttachmentInteractor(
|
||||||
Get.find<DownloadAttachmentForWebInteractor>(),
|
Get.find<DownloadAttachmentForWebInteractor>(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -116,6 +135,11 @@ class DownloadInteractorBindings extends InteractorsBindings {
|
|||||||
Get.find<DownloadRepository>(),
|
Get.find<DownloadRepository>(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Get.lazyPut(
|
||||||
|
() => GetHtmlContentFromUploadFileInteractor(
|
||||||
|
Get.find<DownloadRepository>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:core/data/network/download/download_manager.dart';
|
||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:core/utils/print_utils.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:model/download/download_task_id.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_all_attachments_for_web_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_and_get_html_content_from_attachment_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/export_all_attachments_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/export_attachment_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/get_html_content_from_upload_file_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/parse_email_by_blob_id_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/preview_email_from_eml_file_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_all_attachments_for_web_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_and_get_html_content_from_attachment_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/export_all_attachments_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/export_attachment_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_html_content_from_upload_file_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/parse_email_by_blob_id_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/preview_email_from_eml_file_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/download_attachment_download_controller_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/preview_attachment_download_controller_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
|
typedef UpdateDownloadTaskStateCallback = DownloadTaskState Function(DownloadTaskState currentState);
|
||||||
|
|
||||||
|
class DownloadController extends BaseController {
|
||||||
|
final DownloadManager downloadManager;
|
||||||
|
final PrintUtils printUtils;
|
||||||
|
final DownloadAttachmentForWebInteractor downloadAttachmentForWebInteractor;
|
||||||
|
final DownloadAllAttachmentsForWebInteractor
|
||||||
|
downloadAllAttachmentsForWebInteractor;
|
||||||
|
final ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor;
|
||||||
|
final PreviewEmailFromEmlFileInteractor previewEmailFromEmlFileInteractor;
|
||||||
|
final DownloadAndGetHtmlContentFromAttachmentInteractor
|
||||||
|
downloadAndGetHtmlContentFromAttachmentInteractor;
|
||||||
|
final GetHtmlContentFromUploadFileInteractor
|
||||||
|
getHtmlContentFromUploadFileInteractor;
|
||||||
|
final ExportAttachmentInteractor exportAttachmentInteractor;
|
||||||
|
final ExportAllAttachmentsInteractor exportAllAttachmentsInteractor;
|
||||||
|
|
||||||
|
DownloadController(
|
||||||
|
this.downloadManager,
|
||||||
|
this.printUtils,
|
||||||
|
this.downloadAttachmentForWebInteractor,
|
||||||
|
this.downloadAllAttachmentsForWebInteractor,
|
||||||
|
this.parseEmailByBlobIdInteractor,
|
||||||
|
this.previewEmailFromEmlFileInteractor,
|
||||||
|
this.downloadAndGetHtmlContentFromAttachmentInteractor,
|
||||||
|
this.getHtmlContentFromUploadFileInteractor,
|
||||||
|
this.exportAttachmentInteractor,
|
||||||
|
this.exportAllAttachmentsInteractor,
|
||||||
|
);
|
||||||
|
|
||||||
|
final listDownloadTaskState = RxList<DownloadTaskState>();
|
||||||
|
final hideDownloadTaskbar = RxBool(false);
|
||||||
|
final downloadUIAction = Rxn<DownloadUIAction>();
|
||||||
|
|
||||||
|
final downloadProgressStateController =
|
||||||
|
StreamController<Either<Failure, Success>>.broadcast();
|
||||||
|
StreamSubscription<Either<Failure, Success>>?
|
||||||
|
_downloadProgressStateSubscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
_registerDownloadProgressState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _registerDownloadProgressState() {
|
||||||
|
_downloadProgressStateSubscription = downloadProgressStateController.stream
|
||||||
|
.listen(_onDownloadProgressStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onDownloadProgressStateChanged(Either<Failure, Success> state) {
|
||||||
|
state.fold((_) => null, (success) {
|
||||||
|
if (success is StartDownloadAttachmentForWeb) {
|
||||||
|
_handleStartSingleDownload(success);
|
||||||
|
} else if (success is DownloadingAttachmentForWeb) {
|
||||||
|
_updateDownloadProgress(
|
||||||
|
success.taskId,
|
||||||
|
success.progress,
|
||||||
|
success.downloaded,
|
||||||
|
success.total,
|
||||||
|
);
|
||||||
|
} else if (success is StartDownloadAllAttachmentsForWeb) {
|
||||||
|
_handleStartAllDownload(success);
|
||||||
|
} else if (success is DownloadingAllAttachmentsForWeb) {
|
||||||
|
_updateDownloadProgress(
|
||||||
|
success.taskId,
|
||||||
|
success.progress,
|
||||||
|
success.downloaded,
|
||||||
|
success.total,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleStartSingleDownload(StartDownloadAttachmentForWeb success) {
|
||||||
|
if (success.previewerSupported) return;
|
||||||
|
|
||||||
|
addDownloadTask(
|
||||||
|
DownloadTaskState(
|
||||||
|
taskId: success.taskId,
|
||||||
|
attachment: success.attachment,
|
||||||
|
onCancel: success.cancelToken?.cancel,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (_hasValidContext) {
|
||||||
|
appToast.showToastMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).your_download_has_started,
|
||||||
|
leadingSVGIconColor: AppColor.primaryColor,
|
||||||
|
leadingSVGIcon: imagePaths.icDownload,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleStartAllDownload(StartDownloadAllAttachmentsForWeb success) {
|
||||||
|
addDownloadTask(
|
||||||
|
DownloadTaskState(
|
||||||
|
taskId: success.taskId,
|
||||||
|
attachment: success.attachment,
|
||||||
|
onCancel: () => success.cancelToken?.cancel(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (_hasValidContext) {
|
||||||
|
appToast.showToastSuccessMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).creatingAnArchiveForDownloading,
|
||||||
|
leadingSVGIconColor: Colors.white,
|
||||||
|
leadingSVGIcon: imagePaths.icDownloadAll,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateDownloadProgress(
|
||||||
|
DownloadTaskId taskId,
|
||||||
|
double progress,
|
||||||
|
int downloaded,
|
||||||
|
int total,
|
||||||
|
) {
|
||||||
|
final percent = progress.round();
|
||||||
|
log('$runtimeType::_updateDownloadProgress(): $percent%');
|
||||||
|
|
||||||
|
updateDownloadTaskByTaskId(taskId, (currentTask) {
|
||||||
|
return currentTask.copyWith(
|
||||||
|
progress: progress,
|
||||||
|
downloaded: downloaded,
|
||||||
|
total: total,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get _hasValidContext =>
|
||||||
|
currentOverlayContext != null && currentContext != null;
|
||||||
|
|
||||||
|
bool get notEmptyListDownloadTask => listDownloadTaskState.isNotEmpty;
|
||||||
|
|
||||||
|
void addDownloadTask(DownloadTaskState task) {
|
||||||
|
log('DownloadController::addDownloadTask(): ${task.taskId}');
|
||||||
|
listDownloadTaskState.add(task);
|
||||||
|
hideDownloadTaskbar.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDownloadTaskByTaskId(
|
||||||
|
DownloadTaskId downloadTaskId,
|
||||||
|
UpdateDownloadTaskStateCallback updateDownloadTaskCallback,
|
||||||
|
) {
|
||||||
|
final matchIndex = listDownloadTaskState
|
||||||
|
.indexWhere((task) => task.taskId == downloadTaskId);
|
||||||
|
if (matchIndex >= 0) {
|
||||||
|
listDownloadTaskState[matchIndex] = updateDownloadTaskCallback(listDownloadTaskState[matchIndex]);
|
||||||
|
listDownloadTaskState.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteDownloadTask(DownloadTaskId taskId) {
|
||||||
|
log('DownloadController::deleteDownloadTask(): $taskId');
|
||||||
|
final matchIndex = listDownloadTaskState
|
||||||
|
.indexWhere((task) => task.taskId == taskId);
|
||||||
|
if (matchIndex >= 0) {
|
||||||
|
listDownloadTaskState.removeAt(matchIndex);
|
||||||
|
listDownloadTaskState.refresh();
|
||||||
|
}
|
||||||
|
if (listDownloadTaskState.isEmpty) {
|
||||||
|
hideDownloadTaskbar.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pushDownloadUIAction(DownloadUIAction action) {
|
||||||
|
downloadUIAction.value = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearDownloadUIAction() {
|
||||||
|
downloadUIAction.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void handleSuccessViewState(Success success) {
|
||||||
|
if (success is DownloadAttachmentForWebSuccess) {
|
||||||
|
handleDownloadAttachmentForWebSuccess(success);
|
||||||
|
} else if (success is StartDownloadAttachmentForWeb &&
|
||||||
|
success.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(UpdateAttachmentsViewStateAction(
|
||||||
|
success.attachment.blobId,
|
||||||
|
Right<Failure, Success>(success),
|
||||||
|
));
|
||||||
|
} else if (success is DownloadingAttachmentForWeb &&
|
||||||
|
success.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(UpdateAttachmentsViewStateAction(
|
||||||
|
success.attachment.blobId,
|
||||||
|
Right<Failure, Success>(success),
|
||||||
|
));
|
||||||
|
} else if (success is DownloadAllAttachmentsForWebSuccess) {
|
||||||
|
deleteDownloadTask(success.taskId);
|
||||||
|
} else if (success is ParseEmailByBlobIdSuccess) {
|
||||||
|
handleParseEmailByBlobIdSuccess(
|
||||||
|
context: currentContext,
|
||||||
|
accountId: success.accountId,
|
||||||
|
session: success.session,
|
||||||
|
ownEmailAddress: success.ownEmailAddress,
|
||||||
|
blobId: success.blobId,
|
||||||
|
email: success.email,
|
||||||
|
);
|
||||||
|
} else if (success is PreviewEmailFromEmlFileSuccess) {
|
||||||
|
handlePreviewEmailFromEmlFileSuccess(success);
|
||||||
|
} else if (success is DownloadAndGetHtmlContentFromAttachmentSuccess) {
|
||||||
|
handleDownloadAndGetHtmlContentFromAttachmentSuccess(success);
|
||||||
|
} else if (success is DownloadAndGettingHtmlContentFromAttachment &&
|
||||||
|
success.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(
|
||||||
|
UpdateAttachmentsViewStateAction(
|
||||||
|
success.blobId,
|
||||||
|
Right<Failure, Success>(success),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (success is ExportAttachmentSuccess) {
|
||||||
|
exportAttachmentSuccessAction(success.downloadedResponse);
|
||||||
|
} else if (success is ExportAllAttachmentsSuccess) {
|
||||||
|
exportAllAttachmentsSuccessAction(success.downloadedResponse.filePath);
|
||||||
|
} else if (success is GetHtmlContentFromUploadFileSuccess) {
|
||||||
|
handleGetHtmlContentFromUploadFileSuccess(success);
|
||||||
|
} else {
|
||||||
|
super.handleSuccessViewState(success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void handleFailureViewState(Failure failure) {
|
||||||
|
if (failure is DownloadAllAttachmentsForWebFailure) {
|
||||||
|
downloadAllAttachmentsForWebFailure(failureState: failure);
|
||||||
|
} else if (failure is DownloadAttachmentForWebFailure) {
|
||||||
|
downloadAttachmentForWebFailureAction(failureState: failure);
|
||||||
|
} else if (failure is ParseEmailByBlobIdFailure) {
|
||||||
|
handleParseEmailByBlobIdFailure(failure);
|
||||||
|
} else if (failure is PreviewEmailFromEmlFileFailure) {
|
||||||
|
handlePreviewEmailFromEMLFileFailure(failure);
|
||||||
|
} else if (failure is GetHtmlContentFromUploadFileFailure ||
|
||||||
|
failure is DownloadAndGetHtmlContentFromAttachmentFailure) {
|
||||||
|
handlePreviewHtmlFileFailure(failureState: failure);
|
||||||
|
} else if (failure is ExportAttachmentFailure) {
|
||||||
|
exportAttachmentFailureAction(failure);
|
||||||
|
} else if (failure is ExportAllAttachmentsFailure) {
|
||||||
|
exportAllAttachmentsFailureAction(failure);
|
||||||
|
} else {
|
||||||
|
super.handleFailureViewState(failure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
_downloadProgressStateSubscription?.cancel();
|
||||||
|
_downloadProgressStateSubscription = null;
|
||||||
|
downloadProgressStateController.close();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
+631
@@ -0,0 +1,631 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:core/data/network/download/downloaded_response.dart';
|
||||||
|
import 'package:core/domain/exceptions/download_file_exception.dart';
|
||||||
|
import 'package:core/presentation/extensions/media_type_extension.dart';
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:core/presentation/views/dialog/downloading_file_dialog_builder.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:core/utils/platform_info.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:http_parser/http_parser.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:model/download/download_task_id.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:model/email/eml_attachment.dart';
|
||||||
|
import 'package:model/email/presentation_email.dart';
|
||||||
|
import 'package:model/extensions/presentation_email_extension.dart';
|
||||||
|
import 'package:model/extensions/session_extension.dart';
|
||||||
|
import 'package:open_file/open_file.dart' as open_file;
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/exceptions/download_attachment_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_all_attachments_for_web_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/export_all_attachments_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/export_attachment_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/preview_attachment_download_controller_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_item_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
|
typedef OnDownloadWebFileAction = void Function(String name, Uint8List bytes);
|
||||||
|
|
||||||
|
extension DownloadAttachmentDownloadControllerExtension on DownloadController {
|
||||||
|
void downloadAttachment({
|
||||||
|
required Attachment attachment,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
bool previewerSupported = false,
|
||||||
|
bool showBottomDownloadProgressBar = false,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
|
}) {
|
||||||
|
if (PlatformInfo.isWeb) {
|
||||||
|
downloadAttachmentForWeb(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
previewerSupported: previewerSupported,
|
||||||
|
onReceiveController: showBottomDownloadProgressBar
|
||||||
|
? downloadProgressStateController
|
||||||
|
: null,
|
||||||
|
sourceView: sourceView,
|
||||||
|
);
|
||||||
|
} else if (PlatformInfo.isMobile) {
|
||||||
|
exportAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log('$runtimeType::downloadAttachment: THE PLATFORM IS SUPPORTED');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> downloadAllAttachments({
|
||||||
|
required String outputFileName,
|
||||||
|
required EmailId? emailId,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
bool showBottomDownloadProgressBar = false,
|
||||||
|
}) async {
|
||||||
|
if (PlatformInfo.isWeb) {
|
||||||
|
downloadAllAttachmentsForWeb(
|
||||||
|
outputFileName: outputFileName,
|
||||||
|
emailId: emailId,
|
||||||
|
session: session,
|
||||||
|
accountId: accountId,
|
||||||
|
onReceiveController: showBottomDownloadProgressBar
|
||||||
|
? downloadProgressStateController
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
} else if (PlatformInfo.isMobile) {
|
||||||
|
exportAllAttachments(
|
||||||
|
outputFileName: outputFileName,
|
||||||
|
emailId: emailId,
|
||||||
|
session: session,
|
||||||
|
accountId: accountId,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log('$runtimeType::downloadAllAttachments: THE PLATFORM IS SUPPORTED');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportAttachment({
|
||||||
|
required Attachment attachment,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
}) {
|
||||||
|
final cancelToken = CancelToken();
|
||||||
|
|
||||||
|
showDownloadingFileDialog(
|
||||||
|
attachmentName: attachment.name ?? '',
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ExportAttachmentFailure(NotFoundSessionException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ExportAttachmentFailure(NotFoundAccountIdException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final baseDownloadUrl = session.getSafetyDownloadUrl(
|
||||||
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
exportAttachmentInteractor.execute(
|
||||||
|
attachment,
|
||||||
|
accountId,
|
||||||
|
baseDownloadUrl,
|
||||||
|
cancelToken,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showDownloadingFileDialog({
|
||||||
|
required String attachmentName,
|
||||||
|
required CancelToken cancelToken,
|
||||||
|
}) {
|
||||||
|
Get.dialog(
|
||||||
|
PointerInterceptor(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final appLocalizations = AppLocalizations.of(context);
|
||||||
|
return (DownloadingFileDialogBuilder()
|
||||||
|
..key(const Key('downloading_file_dialog'))
|
||||||
|
..title(appLocalizations.preparing_to_export)
|
||||||
|
..content(appLocalizations.downloading_file(attachmentName))
|
||||||
|
..actionText(appLocalizations.cancel)
|
||||||
|
..addCancelDownloadActionClick(() {
|
||||||
|
cancelToken.cancel([
|
||||||
|
appLocalizations.user_cancel_download_file,
|
||||||
|
]);
|
||||||
|
popBack();
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
barrierDismissible: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadAttachmentForWeb({
|
||||||
|
required Attachment attachment,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
bool previewerSupported = false,
|
||||||
|
StreamController<Either<Failure, Success>>? onReceiveController,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
|
}) {
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAttachmentForWebFailure(
|
||||||
|
attachment: attachment,
|
||||||
|
exception: NotFoundSessionException(),
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAttachmentForWebFailure(
|
||||||
|
attachment: attachment,
|
||||||
|
exception: NotFoundAccountIdException(),
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final generateTaskId = DownloadTaskId(uuid.v4());
|
||||||
|
final baseDownloadUrl = session.getSafetyDownloadUrl(
|
||||||
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
|
);
|
||||||
|
final cancelToken = CancelToken();
|
||||||
|
|
||||||
|
consumeState(downloadAttachmentForWebInteractor.execute(
|
||||||
|
generateTaskId,
|
||||||
|
attachment,
|
||||||
|
accountId,
|
||||||
|
baseDownloadUrl,
|
||||||
|
onReceiveController: onReceiveController,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
previewerSupported: previewerSupported,
|
||||||
|
sourceView: sourceView,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportAttachmentSuccessAction(DownloadedResponse downloadedResponse) {
|
||||||
|
popBack();
|
||||||
|
_openDownloadedPreviewWorkGroupDocument(
|
||||||
|
filePath: downloadedResponse.filePath,
|
||||||
|
mediaType: downloadedResponse.mediaType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openDownloadedPreviewWorkGroupDocument({
|
||||||
|
required String filePath,
|
||||||
|
MediaType? mediaType,
|
||||||
|
}) async {
|
||||||
|
if (mediaType == null) {
|
||||||
|
await _saveFileToStorage(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final openResult = await open_file.OpenFile.open(
|
||||||
|
filePath,
|
||||||
|
type: Platform.isAndroid ? mediaType.mimeType : null,
|
||||||
|
// "xdg" is default value
|
||||||
|
linuxDesktopName:
|
||||||
|
Platform.isIOS ? mediaType.getDocumentUti().value ?? 'xdg' : 'xdg',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (openResult.type != open_file.ResultType.done) {
|
||||||
|
await _saveFileToStorage(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _saveFileToStorage(String filePath) async {
|
||||||
|
final params = SaveFileDialogParams(sourceFilePath: filePath);
|
||||||
|
await FlutterFileDialog.saveFile(params: params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportAllAttachmentsSuccessAction(String filePath) {
|
||||||
|
popBack();
|
||||||
|
_saveFileToStorage(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportAllAttachmentsFailureAction(dynamic exception) {
|
||||||
|
if (exception is CancelDownloadFileException) {
|
||||||
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
|
appToast.showToastWarningMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).user_cancel_download_file,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
popBack();
|
||||||
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
|
appToast.showToastErrorMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).attachment_download_failed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportAttachmentFailureAction(dynamic exception) {
|
||||||
|
if (exception is CancelDownloadFileException) {
|
||||||
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
|
appToast.showToastWarningMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).user_cancel_download_file,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Get.isDialogOpen == true) {
|
||||||
|
popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
|
appToast.showToastErrorMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).attachment_download_failed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadAttachmentForWebFailureAction({
|
||||||
|
required DownloadAttachmentForWebFailure failureState,
|
||||||
|
}) {
|
||||||
|
closeDialogLoading();
|
||||||
|
|
||||||
|
if (failureState.taskId != null) {
|
||||||
|
deleteDownloadTask(failureState.taskId!);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failureState.attachment != null &&
|
||||||
|
failureState.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(
|
||||||
|
UpdateAttachmentsViewStateAction(
|
||||||
|
failureState.attachment?.blobId,
|
||||||
|
Left<Failure, Success>(failureState),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentOverlayContext == null || currentContext == null) return;
|
||||||
|
|
||||||
|
final appLocalizations = AppLocalizations.of(currentContext!);
|
||||||
|
String message = appLocalizations.attachment_download_failed;
|
||||||
|
if (failureState.attachment is EMLAttachment) {
|
||||||
|
message = appLocalizations.downloadMessageAsEMLFailed;
|
||||||
|
} else if (failureState.cancelToken?.isCancelled == true) {
|
||||||
|
message = appLocalizations.downloadAttachmentHasBeenCancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
appToast.showToastErrorMessage(currentOverlayContext!, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadAllAttachmentsForWebFailure({
|
||||||
|
required DownloadAllAttachmentsForWebFailure failureState,
|
||||||
|
}) {
|
||||||
|
deleteDownloadTask(failureState.taskId);
|
||||||
|
|
||||||
|
if (currentOverlayContext == null || currentContext == null) return;
|
||||||
|
|
||||||
|
final appLocalizations = AppLocalizations.of(currentContext!);
|
||||||
|
final message = failureState.cancelToken?.isCancelled == true
|
||||||
|
? appLocalizations.downloadAttachmentHasBeenCancelled
|
||||||
|
: appLocalizations.attachment_download_failed;
|
||||||
|
|
||||||
|
appToast.showToastErrorMessage(currentOverlayContext!, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadFileWeb({
|
||||||
|
required String fileName,
|
||||||
|
required Uint8List fileBytes,
|
||||||
|
}) {
|
||||||
|
downloadManager.createAnchorElementDownloadFileWeb(
|
||||||
|
fileBytes,
|
||||||
|
fileName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadAttachmentInEMLPreview({
|
||||||
|
required OnDownloadAttachmentFileAction onDownloadAction,
|
||||||
|
required Uri? uri,
|
||||||
|
}) {
|
||||||
|
if (uri == null) return;
|
||||||
|
|
||||||
|
final attachment = EmailUtils.parsingAttachmentByUri(uri);
|
||||||
|
if (attachment == null) return;
|
||||||
|
|
||||||
|
onDownloadAction(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exportAllAttachments({
|
||||||
|
required String outputFileName,
|
||||||
|
required EmailId? emailId,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
}) {
|
||||||
|
final cancelToken = CancelToken();
|
||||||
|
|
||||||
|
showDownloadingFileDialog(
|
||||||
|
attachmentName: outputFileName,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ExportAllAttachmentsFailure(
|
||||||
|
exception: NotFoundSessionException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ExportAllAttachmentsFailure(
|
||||||
|
exception: NotFoundAccountIdException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emailId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ExportAllAttachmentsFailure(
|
||||||
|
exception: NotFoundEmailException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final downloadAllSupported = session.isDownloadAllSupported(accountId);
|
||||||
|
if (!downloadAllSupported) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ExportAllAttachmentsFailure(
|
||||||
|
exception: CapabilityDownloadAllNotSupportedException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final baseDownloadAllUrl =
|
||||||
|
session.getDownloadAllCapability(accountId)!.endpoint!;
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
exportAllAttachmentsInteractor.execute(
|
||||||
|
accountId,
|
||||||
|
emailId,
|
||||||
|
baseDownloadAllUrl,
|
||||||
|
outputFileName,
|
||||||
|
cancelToken,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadAllAttachmentsForWeb({
|
||||||
|
required String outputFileName,
|
||||||
|
required EmailId? emailId,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
bool previewerSupported = false,
|
||||||
|
StreamController<Either<Failure, Success>>? onReceiveController,
|
||||||
|
}) {
|
||||||
|
final taskId = DownloadTaskId(uuid.v4());
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAllAttachmentsForWebFailure(
|
||||||
|
exception: NotFoundSessionException(),
|
||||||
|
taskId: taskId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAllAttachmentsForWebFailure(
|
||||||
|
exception: NotFoundAccountIdException(),
|
||||||
|
taskId: taskId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emailId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAllAttachmentsForWebFailure(
|
||||||
|
exception: NotFoundEmailException(),
|
||||||
|
taskId: taskId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final downloadAllSupported = session.isDownloadAllSupported(accountId);
|
||||||
|
|
||||||
|
if (!downloadAllSupported) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAllAttachmentsForWebFailure(
|
||||||
|
exception: CapabilityDownloadAllNotSupportedException(),
|
||||||
|
taskId: taskId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final baseDownloadAllUrl =
|
||||||
|
session.getDownloadAllCapability(accountId)!.endpoint!;
|
||||||
|
|
||||||
|
final downloadAttachment = Attachment(
|
||||||
|
name: outputFileName,
|
||||||
|
type: MediaType('application', 'zip'),
|
||||||
|
);
|
||||||
|
|
||||||
|
final cancelToken = CancelToken();
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
downloadAllAttachmentsForWebInteractor.execute(
|
||||||
|
accountId,
|
||||||
|
emailId,
|
||||||
|
baseDownloadAllUrl,
|
||||||
|
downloadAttachment,
|
||||||
|
taskId,
|
||||||
|
onReceiveController: onReceiveController,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadMessageAsEML({
|
||||||
|
required PresentationEmail presentationEmail,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
bool showBottomDownloadProgressBar = false,
|
||||||
|
}) {
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAttachmentForWebFailure(
|
||||||
|
exception: NotFoundSessionException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAttachmentForWebFailure(
|
||||||
|
exception: NotFoundAccountIdException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final emlAttachment = presentationEmail.createEMLAttachment();
|
||||||
|
if (emlAttachment.blobId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAttachmentForWebFailure(
|
||||||
|
exception: NotFoundEmailBlobIdException(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final generateTaskId = DownloadTaskId(uuid.v4());
|
||||||
|
final baseDownloadUrl = session.getSafetyDownloadUrl(
|
||||||
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
|
);
|
||||||
|
final cancelToken = CancelToken();
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
downloadAttachmentForWebInteractor.execute(
|
||||||
|
generateTaskId,
|
||||||
|
emlAttachment,
|
||||||
|
accountId,
|
||||||
|
baseDownloadUrl,
|
||||||
|
onReceiveController: showBottomDownloadProgressBar
|
||||||
|
? downloadProgressStateController
|
||||||
|
: null,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
previewerSupported: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDownloadAttachmentForWebSuccess(
|
||||||
|
DownloadAttachmentForWebSuccess success,
|
||||||
|
) {
|
||||||
|
closeDialogLoading();
|
||||||
|
|
||||||
|
if (success.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(UpdateAttachmentsViewStateAction(
|
||||||
|
success.attachment.blobId,
|
||||||
|
Right<Failure, Success>(success),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteDownloadTask(success.taskId);
|
||||||
|
|
||||||
|
if (!success.previewerSupported) {
|
||||||
|
downloadFileWeb(
|
||||||
|
fileBytes: success.bytes,
|
||||||
|
fileName: success.attachment.generateFileName(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success.attachment.isImage) {
|
||||||
|
previewImageFile(
|
||||||
|
fileName: success.attachment.generateFileName(),
|
||||||
|
imageBytes: success.bytes,
|
||||||
|
context: currentContext,
|
||||||
|
onDownloadWebFileAction: (name, bytes) => downloadFileWeb(
|
||||||
|
fileName: name,
|
||||||
|
fileBytes: bytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (success.attachment.isText || success.attachment.isJson) {
|
||||||
|
previewPlainTextFile(
|
||||||
|
fileName: success.attachment.generateFileName(),
|
||||||
|
fileBytes: success.bytes,
|
||||||
|
context: currentContext,
|
||||||
|
onDownloadWebFileAction: (name, bytes) => downloadFileWeb(
|
||||||
|
fileName: name,
|
||||||
|
fileBytes: bytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+763
@@ -0,0 +1,763 @@
|
|||||||
|
import 'package:core/domain/exceptions/web_session_exception.dart';
|
||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/dom/sanitize_hyper_link_tag_in_html_transformers.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
||||||
|
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:core/utils/html/html_utils.dart';
|
||||||
|
import 'package:core/utils/platform_info.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:model/download/download_task_id.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:model/extensions/session_extension.dart';
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/exceptions/download_attachment_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_and_get_html_content_from_attachment_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/get_html_content_from_upload_file_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/parse_email_by_blob_id_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/preview_email_from_eml_file_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/download_attachment_download_controller_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
||||||
|
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/email/presentation/widgets/attachment_item_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/pdf_viewer/pdf_viewer.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email_previewer/email_previewer_dialog_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
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/routes/route_utils.dart';
|
||||||
|
import 'package:twake_previewer_flutter/core/constants/supported_charset.dart';
|
||||||
|
import 'package:twake_previewer_flutter/core/previewer_options/options/previewer_state.dart';
|
||||||
|
import 'package:twake_previewer_flutter/core/previewer_options/options/top_bar_options.dart';
|
||||||
|
import 'package:twake_previewer_flutter/core/previewer_options/previewer_options.dart';
|
||||||
|
import 'package:twake_previewer_flutter/twake_image_previewer/twake_image_previewer.dart';
|
||||||
|
import 'package:twake_previewer_flutter/twake_plain_text_previewer/twake_plain_text_previewer.dart';
|
||||||
|
|
||||||
|
typedef OnPreviewOrDownloadAttachmentAction = void Function(
|
||||||
|
Attachment attachment,
|
||||||
|
bool isPreviewSupported,
|
||||||
|
);
|
||||||
|
|
||||||
|
extension PreviewAttachmentDownloadControllerExtension on DownloadController {
|
||||||
|
void previewAttachment({
|
||||||
|
required BuildContext context,
|
||||||
|
required Attachment attachment,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
required String ownEmailAddress,
|
||||||
|
required OnPreviewOrDownloadAttachmentAction onPreviewOrDownloadAction,
|
||||||
|
bool isDialogLoadingVisible = false,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
|
}) {
|
||||||
|
final appLocalizations = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
if (PlatformInfo.isWeb && attachment.isPDFFile) {
|
||||||
|
_previewPDFFile(
|
||||||
|
context: context,
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
} else if (attachment.isEMLFile) {
|
||||||
|
_preparePreviewEMLFile(
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
ownEmailAddress: ownEmailAddress,
|
||||||
|
blobId: attachment.blobId,
|
||||||
|
);
|
||||||
|
} else if (attachment.isHTMLFile) {
|
||||||
|
_preparePreviewHtmlFile(
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
session: session,
|
||||||
|
accountId: accountId,
|
||||||
|
attachment: attachment,
|
||||||
|
isDialogLoadingVisible: isDialogLoadingVisible,
|
||||||
|
sourceView: sourceView,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (isDialogLoadingVisible) {
|
||||||
|
showDialogLoading(appLocalizations);
|
||||||
|
}
|
||||||
|
onPreviewOrDownloadAction(
|
||||||
|
attachment,
|
||||||
|
attachment.isPreviewSupported,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void previewUploadFile({
|
||||||
|
required BuildContext context,
|
||||||
|
required UploadFileState uploadFile,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
required String ownEmailAddress,
|
||||||
|
required OnPreviewOrDownloadAttachmentAction onPreviewOrDownloadAction,
|
||||||
|
bool isDialogLoadingVisible = false,
|
||||||
|
}) {
|
||||||
|
final attachment = uploadFile.attachment;
|
||||||
|
final appLocalizations = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
if (attachment == null) {
|
||||||
|
showPreviewNotAvailableToastMessage(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlatformInfo.isWeb && attachment.isPDFFile == true) {
|
||||||
|
_previewPDFFile(
|
||||||
|
context: context,
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment.isEMLFile == true) {
|
||||||
|
_preparePreviewEMLFile(
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
ownEmailAddress: ownEmailAddress,
|
||||||
|
blobId: attachment.blobId,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment.isHTMLFile == true) {
|
||||||
|
if (uploadFile.file?.bytes != null) {
|
||||||
|
_preparePreviewHtmlFileByUploadFile(
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
uploadFile: uploadFile,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
isDialogLoadingVisible: isDialogLoadingVisible,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_preparePreviewHtmlFile(
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
isDialogLoadingVisible: isDialogLoadingVisible,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment.isImage == true && uploadFile.file?.bytes != null) {
|
||||||
|
previewImageFile(
|
||||||
|
fileName: attachment.generateFileName(),
|
||||||
|
imageBytes: uploadFile.file!.bytes!,
|
||||||
|
context: context,
|
||||||
|
onDownloadWebFileAction: (fileName, fileBytes) => downloadFileWeb(
|
||||||
|
fileName: fileName,
|
||||||
|
fileBytes: fileBytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((attachment.isText == true || attachment.isJson == true) &&
|
||||||
|
uploadFile.file?.bytes != null) {
|
||||||
|
previewPlainTextFile(
|
||||||
|
fileName: attachment.generateFileName(),
|
||||||
|
fileBytes: uploadFile.file!.bytes!,
|
||||||
|
context: context,
|
||||||
|
onDownloadWebFileAction: (fileName, fileBytes) => downloadFileWeb(
|
||||||
|
fileName: fileName,
|
||||||
|
fileBytes: fileBytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uploadFile.file?.bytes != null) {
|
||||||
|
downloadFileWeb(
|
||||||
|
fileName: attachment.generateFileName(),
|
||||||
|
fileBytes: uploadFile.file!.bytes!,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDialogLoadingVisible) {
|
||||||
|
showDialogLoading(appLocalizations);
|
||||||
|
}
|
||||||
|
onPreviewOrDownloadAction(attachment, attachment.isPreviewSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _previewPDFFile({
|
||||||
|
required BuildContext context,
|
||||||
|
required Attachment attachment,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
}) async {
|
||||||
|
final downloadUrl = session?.getSafetyDownloadUrl(
|
||||||
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (accountId == null || session == null || downloadUrl == null) {
|
||||||
|
showPreviewNotAvailableToastMessage(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Get.generalDialog(
|
||||||
|
barrierColor: Colors.black.withValues(alpha: 0.8),
|
||||||
|
pageBuilder: (_, __, ___) {
|
||||||
|
return PointerInterceptor(
|
||||||
|
child: PDFViewer(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId,
|
||||||
|
downloadUrl: downloadUrl,
|
||||||
|
downloadAction: (bytes, name) =>
|
||||||
|
downloadFileWeb(fileName: name, fileBytes: bytes),
|
||||||
|
printAction: printUtils.printPDFFile,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _preparePreviewEMLFile({
|
||||||
|
required AppLocalizations appLocalizations,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
required String ownEmailAddress,
|
||||||
|
required Id? blobId,
|
||||||
|
}) {
|
||||||
|
showDialogLoading(appLocalizations);
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ParseEmailByBlobIdFailure(NotFoundSessionException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ParseEmailByBlobIdFailure(NotFoundAccountIdException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blobId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: ParseEmailByBlobIdFailure(NotFoundBlobIdException([])),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
parseEmailByBlobIdInteractor.execute(
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
ownEmailAddress,
|
||||||
|
blobId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _preparePreviewHtmlFile({
|
||||||
|
required AppLocalizations appLocalizations,
|
||||||
|
required Session? session,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Attachment attachment,
|
||||||
|
bool isDialogLoadingVisible = false,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
|
}) {
|
||||||
|
if (isDialogLoadingVisible) {
|
||||||
|
showDialogLoading(appLocalizations);
|
||||||
|
}
|
||||||
|
|
||||||
|
final downloadUrl = session?.getSafetyDownloadUrl(
|
||||||
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
|
);
|
||||||
|
final blobId = attachment.blobId;
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
|
exception: NotFoundSessionException(),
|
||||||
|
blobId: blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
|
exception: NotFoundAccountIdException(),
|
||||||
|
blobId: blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blobId == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
|
exception: NotFoundBlobIdException([]),
|
||||||
|
blobId: blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downloadUrl == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: DownloadAndGetHtmlContentFromAttachmentFailure(
|
||||||
|
exception: DownloadUrlIsNullException(),
|
||||||
|
blobId: blobId,
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
downloadAndGetHtmlContentFromAttachmentInteractor.execute(
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
attachment,
|
||||||
|
DownloadTaskId(blobId.value),
|
||||||
|
downloadUrl,
|
||||||
|
TransformConfiguration.create(
|
||||||
|
customDomTransformers: [SanitizeHyperLinkTagInHtmlTransformer()],
|
||||||
|
customTextTransformers: [
|
||||||
|
const StandardizeHtmlSanitizingTransformers()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
sourceView: sourceView,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _preparePreviewHtmlFileByUploadFile({
|
||||||
|
required AppLocalizations appLocalizations,
|
||||||
|
required UploadFileState uploadFile,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
bool isDialogLoadingVisible = false,
|
||||||
|
}) {
|
||||||
|
if (isDialogLoadingVisible) {
|
||||||
|
showDialogLoading(appLocalizations);
|
||||||
|
}
|
||||||
|
consumeState(
|
||||||
|
getHtmlContentFromUploadFileInteractor.execute(
|
||||||
|
uploadFile: uploadFile,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleParseEmailByBlobIdSuccess({
|
||||||
|
required BuildContext? context,
|
||||||
|
required AccountId accountId,
|
||||||
|
required Session session,
|
||||||
|
required String ownEmailAddress,
|
||||||
|
required Id blobId,
|
||||||
|
required Email email,
|
||||||
|
}) {
|
||||||
|
if (context == null) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: PreviewEmailFromEmlFileFailure(NotFoundContextException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final downloadUrl = session.getDownloadUrl(
|
||||||
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (downloadUrl.isEmpty) {
|
||||||
|
emitFailure(
|
||||||
|
controller: this,
|
||||||
|
failure: PreviewEmailFromEmlFileFailure(DownloadUrlIsNullException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeState(
|
||||||
|
previewEmailFromEmlFileInteractor.execute(
|
||||||
|
PreviewEmailEMLRequest(
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
ownEmailAddress: ownEmailAddress,
|
||||||
|
blobId: blobId,
|
||||||
|
email: email,
|
||||||
|
locale: Localizations.localeOf(context),
|
||||||
|
appLocalizations: AppLocalizations.of(context),
|
||||||
|
baseDownloadUrl: downloadUrl,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleParseEmailByBlobIdFailure(ParseEmailByBlobIdFailure failure) {
|
||||||
|
closeDialogLoading();
|
||||||
|
toastManager.showMessageFailure(failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePreviewEmailFromEMLFileFailure(
|
||||||
|
PreviewEmailFromEmlFileFailure failure,
|
||||||
|
) {
|
||||||
|
closeDialogLoading();
|
||||||
|
toastManager.showMessageFailure(failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleGetHtmlContentFromUploadFileSuccess(
|
||||||
|
GetHtmlContentFromUploadFileSuccess success,
|
||||||
|
) {
|
||||||
|
closeDialogLoading();
|
||||||
|
|
||||||
|
previewHtmlFile(
|
||||||
|
attachment: success.attachment,
|
||||||
|
title: success.htmlAttachmentTitle,
|
||||||
|
content: success.sanitizedHtmlContent,
|
||||||
|
openMailToLink: (uri) async {
|
||||||
|
if (uri == null) return;
|
||||||
|
pushDownloadUIAction(OpenComposerFromMailtoLinkAction(uri));
|
||||||
|
},
|
||||||
|
onDownloadAction: (attachment) => downloadAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: success.accountId,
|
||||||
|
session: success.session,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDownloadAndGetHtmlContentFromAttachmentSuccess(
|
||||||
|
DownloadAndGetHtmlContentFromAttachmentSuccess success,
|
||||||
|
) {
|
||||||
|
if (success.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(
|
||||||
|
UpdateAttachmentsViewStateAction(
|
||||||
|
success.attachment.blobId,
|
||||||
|
Right<Failure, Success>(success),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDialogLoading();
|
||||||
|
|
||||||
|
previewHtmlFile(
|
||||||
|
attachment: success.attachment,
|
||||||
|
title: success.htmlAttachmentTitle,
|
||||||
|
content: success.sanitizedHtmlContent,
|
||||||
|
openMailToLink: (uri) async {
|
||||||
|
if (uri == null) return;
|
||||||
|
pushDownloadUIAction(OpenComposerFromMailtoLinkAction(uri));
|
||||||
|
},
|
||||||
|
onDownloadAction: (attachment) => downloadAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: success.accountId,
|
||||||
|
session: success.session,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePreviewEmailFromEmlFileSuccess(
|
||||||
|
PreviewEmailFromEmlFileSuccess success,
|
||||||
|
) {
|
||||||
|
previewEMLFile(
|
||||||
|
emlPreviewer: success.emlPreviewer,
|
||||||
|
context: currentContext,
|
||||||
|
onMailtoAction: (uri) async {
|
||||||
|
if (uri == null) return;
|
||||||
|
pushDownloadUIAction(OpenComposerFromMailtoLinkAction(uri));
|
||||||
|
},
|
||||||
|
onDownloadAction: (uri) async => downloadAttachmentInEMLPreview(
|
||||||
|
uri: uri,
|
||||||
|
onDownloadAction: (attachment) => downloadAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: success.accountId,
|
||||||
|
session: success.session,
|
||||||
|
)),
|
||||||
|
onPreviewAction: (uri) async => openEMLPreviewer(
|
||||||
|
accountId: success.accountId,
|
||||||
|
session: success.session,
|
||||||
|
ownEmailAddress: success.ownEmailAddress,
|
||||||
|
uri: uri,
|
||||||
|
appLocalizations: success.appLocalizations,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void previewEMLFile({
|
||||||
|
required EMLPreviewer emlPreviewer,
|
||||||
|
required BuildContext? context,
|
||||||
|
required OnMailtoDelegateAction onMailtoAction,
|
||||||
|
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
||||||
|
required OnPreviewEMLDelegateAction onPreviewAction,
|
||||||
|
}) {
|
||||||
|
closeDialogLoading();
|
||||||
|
|
||||||
|
if (PlatformInfo.isWeb) {
|
||||||
|
bool isOpen = HtmlUtils.openNewWindowByUrl(
|
||||||
|
RouteUtils.createUrlWebLocationBar(
|
||||||
|
AppRoutes.emailEMLPreviewer,
|
||||||
|
previewId: emlPreviewer.id,
|
||||||
|
).toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isOpen) {
|
||||||
|
toastManager.showMessageFailure(
|
||||||
|
PreviewEmailFromEmlFileFailure(CannotOpenNewWindowException()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (PlatformInfo.isMobile) {
|
||||||
|
if (context == null) {
|
||||||
|
toastManager.showMessageFailure(
|
||||||
|
PreviewEmailFromEmlFileFailure(NotFoundContextException()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlatformInfo.isAndroid) {
|
||||||
|
showModalSheetToPreviewEMLAttachment(
|
||||||
|
context: context,
|
||||||
|
emlPreviewer: emlPreviewer,
|
||||||
|
onMailtoAction: onMailtoAction,
|
||||||
|
onDownloadAction: onDownloadAction,
|
||||||
|
onPreviewAction: onPreviewAction,
|
||||||
|
);
|
||||||
|
} else if (PlatformInfo.isIOS) {
|
||||||
|
showDialogToPreviewEMLAttachment(
|
||||||
|
context: context,
|
||||||
|
emlPreviewer: emlPreviewer,
|
||||||
|
onMailtoAction: onMailtoAction,
|
||||||
|
onDownloadAction: onDownloadAction,
|
||||||
|
onPreviewAction: onPreviewAction,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showModalSheetToPreviewEMLAttachment({
|
||||||
|
required BuildContext context,
|
||||||
|
required EMLPreviewer emlPreviewer,
|
||||||
|
required OnMailtoDelegateAction onMailtoAction,
|
||||||
|
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
||||||
|
required OnPreviewEMLDelegateAction onPreviewAction,
|
||||||
|
}) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
showDragHandle: true,
|
||||||
|
useSafeArea: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(20.0),
|
||||||
|
topRight: Radius.circular(20.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
builder: (_) {
|
||||||
|
return DraggableScrollableSheet(
|
||||||
|
initialChildSize: 1.0,
|
||||||
|
builder: (context, ___) => EmailPreviewerDialogView(
|
||||||
|
emlPreviewer: emlPreviewer,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
onMailtoDelegateAction: onMailtoAction,
|
||||||
|
onPreviewEMLDelegateAction: onPreviewAction,
|
||||||
|
onDownloadAttachmentDelegateAction: onDownloadAction,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showDialogToPreviewEMLAttachment({
|
||||||
|
required BuildContext context,
|
||||||
|
required EMLPreviewer emlPreviewer,
|
||||||
|
required OnMailtoDelegateAction onMailtoAction,
|
||||||
|
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
||||||
|
required OnPreviewEMLDelegateAction onPreviewAction,
|
||||||
|
}) {
|
||||||
|
Get.dialog(
|
||||||
|
EmailPreviewerDialogView(
|
||||||
|
emlPreviewer: emlPreviewer,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
onMailtoDelegateAction: onMailtoAction,
|
||||||
|
onPreviewEMLDelegateAction: onPreviewAction,
|
||||||
|
onDownloadAttachmentDelegateAction: onDownloadAction,
|
||||||
|
),
|
||||||
|
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePreviewHtmlFileFailure({required Failure failureState}) {
|
||||||
|
if (failureState is DownloadAndGetHtmlContentFromAttachmentFailure &&
|
||||||
|
failureState.sourceView == DownloadSourceView.emailView) {
|
||||||
|
pushDownloadUIAction(
|
||||||
|
UpdateAttachmentsViewStateAction(
|
||||||
|
failureState.blobId,
|
||||||
|
Left<Failure, Success>(failureState),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDialogLoading();
|
||||||
|
|
||||||
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
|
appToast.showToastErrorMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!)
|
||||||
|
.thisHtmlAttachmentCannotBePreviewed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void previewImageFile({
|
||||||
|
required String fileName,
|
||||||
|
required Uint8List imageBytes,
|
||||||
|
required BuildContext? context,
|
||||||
|
required OnDownloadWebFileAction onDownloadWebFileAction,
|
||||||
|
}) {
|
||||||
|
log('$runtimeType::previewImageFile: Attachment fileName is $fileName');
|
||||||
|
if (context == null) return;
|
||||||
|
|
||||||
|
Navigator.of(context).push(
|
||||||
|
GetDialogRoute(
|
||||||
|
pageBuilder: (context, _, __) => PointerInterceptor(
|
||||||
|
child: TwakeImagePreviewer(
|
||||||
|
bytes: imageBytes,
|
||||||
|
zoomable: true,
|
||||||
|
previewerOptions: const PreviewerOptions(
|
||||||
|
previewerState: PreviewerState.success,
|
||||||
|
),
|
||||||
|
topBarOptions: TopBarOptions(
|
||||||
|
title: fileName,
|
||||||
|
onClose: () => Navigator.maybePop(context),
|
||||||
|
onDownload: () => onDownloadWebFileAction(fileName, imageBytes),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
barrierDismissible: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void previewPlainTextFile({
|
||||||
|
required String fileName,
|
||||||
|
required Uint8List fileBytes,
|
||||||
|
required BuildContext? context,
|
||||||
|
required OnDownloadWebFileAction onDownloadWebFileAction,
|
||||||
|
}) {
|
||||||
|
log('$runtimeType::previewPlainTextFile: Attachment fileName is $fileName');
|
||||||
|
if (context == null) return;
|
||||||
|
|
||||||
|
Navigator.of(context).push(
|
||||||
|
GetDialogRoute(
|
||||||
|
pageBuilder: (context, _, __) => PointerInterceptor(
|
||||||
|
child: TwakePlainTextPreviewer(
|
||||||
|
supportedCharset: SupportedCharset.utf8,
|
||||||
|
bytes: fileBytes,
|
||||||
|
previewerOptions: PreviewerOptions(
|
||||||
|
previewerState: PreviewerState.success,
|
||||||
|
width: context.width * 0.8,
|
||||||
|
),
|
||||||
|
topBarOptions: TopBarOptions(
|
||||||
|
title: fileName,
|
||||||
|
onClose: () => Navigator.maybePop(context),
|
||||||
|
onDownload: () => onDownloadWebFileAction(fileName, fileBytes),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
barrierDismissible: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void previewHtmlFile({
|
||||||
|
required Attachment attachment,
|
||||||
|
required String title,
|
||||||
|
required String content,
|
||||||
|
required OnMailtoDelegateAction openMailToLink,
|
||||||
|
required OnDownloadAttachmentFileAction onDownloadAction,
|
||||||
|
}) {
|
||||||
|
Get.dialog(
|
||||||
|
HtmlAttachmentPreviewer(
|
||||||
|
title: title,
|
||||||
|
htmlContent: content,
|
||||||
|
mailToClicked: openMailToLink,
|
||||||
|
downloadAttachmentClicked: () => onDownloadAction(attachment),
|
||||||
|
responsiveUtils: responsiveUtils,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> openEMLPreviewer({
|
||||||
|
required AppLocalizations appLocalizations,
|
||||||
|
required Uri? uri,
|
||||||
|
required AccountId? accountId,
|
||||||
|
required Session? session,
|
||||||
|
required String ownEmailAddress,
|
||||||
|
}) async {
|
||||||
|
if (uri == null) return;
|
||||||
|
|
||||||
|
final blobId = uri.path;
|
||||||
|
if (blobId.isEmpty) return;
|
||||||
|
|
||||||
|
_preparePreviewEMLFile(
|
||||||
|
appLocalizations: appLocalizations,
|
||||||
|
accountId: accountId,
|
||||||
|
session: session,
|
||||||
|
ownEmailAddress: ownEmailAddress,
|
||||||
|
blobId: Id(blobId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showDialogLoading(AppLocalizations appLocalizations) {
|
||||||
|
SmartDialog.showLoading(
|
||||||
|
msg: appLocalizations.loadingPleaseWait,
|
||||||
|
maskColor: Colors.black38,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeDialogLoading() {
|
||||||
|
if (SmartDialog.checkExist()) {
|
||||||
|
SmartDialog.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showPreviewNotAvailableToastMessage(BuildContext context) {
|
||||||
|
appToast.showToastErrorMessage(
|
||||||
|
context,
|
||||||
|
AppLocalizations.of(context).noPreviewAvailable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,11 +57,12 @@ import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart';
|
import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_all_attachments_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_all_attachments_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
|
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
@@ -343,12 +344,18 @@ class EmailAPI with HandleSetErrorMixin, MailAPIMixin {
|
|||||||
progress = (downloaded / total) * 100;
|
progress = (downloaded / total) * 100;
|
||||||
}
|
}
|
||||||
log('EmailAPI::downloadFileForWeb(): progress = ${progress.round()}%');
|
log('EmailAPI::downloadFileForWeb(): progress = ${progress.round()}%');
|
||||||
onReceiveController?.add(Right(DownloadingAttachmentForWeb(
|
onReceiveController?.add(
|
||||||
taskId,
|
Right(
|
||||||
attachment,
|
DownloadingAttachmentForWeb(
|
||||||
progress,
|
taskId,
|
||||||
downloaded,
|
attachment,
|
||||||
total)));
|
progress,
|
||||||
|
downloaded,
|
||||||
|
total,
|
||||||
|
DownloadSourceView.emailView,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:core/data/model/source_type/data_source_type.dart';
|
import 'package:core/data/model/source_type/data_source_type.dart';
|
||||||
import 'package:core/data/network/download/downloaded_response.dart';
|
|
||||||
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
@@ -14,8 +13,6 @@ import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
|
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:model/account/account_request.dart';
|
|
||||||
import 'package:model/email/attachment.dart';
|
|
||||||
import 'package:model/email/email_content.dart';
|
import 'package:model/email/email_content.dart';
|
||||||
import 'package:model/email/mark_star_action.dart';
|
import 'package:model/email/mark_star_action.dart';
|
||||||
import 'package:model/email/read_actions.dart';
|
import 'package:model/email/read_actions.dart';
|
||||||
@@ -135,22 +132,6 @@ class EmailRepositoryImpl extends EmailRepository {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<DownloadedResponse> exportAttachment(
|
|
||||||
Attachment attachment,
|
|
||||||
AccountId accountId,
|
|
||||||
String baseDownloadUrl,
|
|
||||||
AccountRequest accountRequest,
|
|
||||||
CancelToken cancelToken
|
|
||||||
) {
|
|
||||||
return emailDataSource[DataSourceType.network]!.exportAttachment(
|
|
||||||
attachment,
|
|
||||||
accountId,
|
|
||||||
baseDownloadUrl,
|
|
||||||
accountRequest,
|
|
||||||
cancelToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<({
|
Future<({
|
||||||
List<EmailId> emailIdsSuccess,
|
List<EmailId> emailIdsSuccess,
|
||||||
@@ -494,22 +475,6 @@ class EmailRepositoryImpl extends EmailRepository {
|
|||||||
return _printFileDataSource.printEmail(emailPrint);
|
return _printFileDataSource.printEmail(emailPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<DownloadedResponse> exportAllAttachments(
|
|
||||||
AccountId accountId,
|
|
||||||
EmailId emailId,
|
|
||||||
String baseDownloadAllUrl,
|
|
||||||
String outputFileName,
|
|
||||||
AccountRequest accountRequest, {
|
|
||||||
CancelToken? cancelToken,
|
|
||||||
}) => emailDataSource[DataSourceType.network]!.exportAllAttachments(
|
|
||||||
accountId,
|
|
||||||
emailId,
|
|
||||||
baseDownloadAllUrl,
|
|
||||||
outputFileName,
|
|
||||||
accountRequest,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest) {
|
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest) {
|
||||||
return emailDataSource[DataSourceType.local]!.generateEntireMessageAsDocument(entireMessageRequest);
|
return emailDataSource[DataSourceType.local]!.generateEntireMessageAsDocument(entireMessageRequest);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
class DownloadAttachmentInteractorIsNull implements Exception {}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:core/data/network/download/downloaded_response.dart';
|
|
||||||
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:email_recovery/email_recovery/email_recovery_action.dart';
|
import 'package:email_recovery/email_recovery/email_recovery_action.dart';
|
||||||
@@ -12,8 +11,6 @@ import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
|
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:model/account/account_request.dart';
|
|
||||||
import 'package:model/email/attachment.dart';
|
|
||||||
import 'package:model/email/email_content.dart';
|
import 'package:model/email/email_content.dart';
|
||||||
import 'package:model/email/mark_star_action.dart';
|
import 'package:model/email/mark_star_action.dart';
|
||||||
import 'package:model/email/read_actions.dart';
|
import 'package:model/email/read_actions.dart';
|
||||||
@@ -52,14 +49,6 @@ abstract class EmailRepository {
|
|||||||
ReadActions readActions,
|
ReadActions readActions,
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<DownloadedResponse> exportAttachment(
|
|
||||||
Attachment attachment,
|
|
||||||
AccountId accountId,
|
|
||||||
String baseDownloadUrl,
|
|
||||||
AccountRequest accountRequest,
|
|
||||||
CancelToken cancelToken
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<({
|
Future<({
|
||||||
List<EmailId> emailIdsSuccess,
|
List<EmailId> emailIdsSuccess,
|
||||||
Map<Id, SetError> mapErrors,
|
Map<Id, SetError> mapErrors,
|
||||||
@@ -170,14 +159,5 @@ abstract class EmailRepository {
|
|||||||
|
|
||||||
Future<void> printEmail(EmailPrint emailPrint);
|
Future<void> printEmail(EmailPrint emailPrint);
|
||||||
|
|
||||||
Future<DownloadedResponse> exportAllAttachments(
|
|
||||||
AccountId accountId,
|
|
||||||
EmailId emailId,
|
|
||||||
String baseDownloadAllUrl,
|
|
||||||
String outputFileName,
|
|
||||||
AccountRequest accountRequest,
|
|
||||||
{CancelToken? cancelToken}
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);
|
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);
|
||||||
}
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
|
||||||
import 'package:core/presentation/state/success.dart';
|
|
||||||
import 'package:model/email/attachment.dart';
|
|
||||||
|
|
||||||
class GettingHtmlContentFromAttachment extends LoadingState {
|
|
||||||
GettingHtmlContentFromAttachment({required this.attachment});
|
|
||||||
|
|
||||||
final Attachment attachment;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [attachment];
|
|
||||||
}
|
|
||||||
|
|
||||||
class GetHtmlContentFromAttachmentSuccess extends UIState {
|
|
||||||
GetHtmlContentFromAttachmentSuccess({
|
|
||||||
required this.sanitizedHtmlContent,
|
|
||||||
required this.htmlAttachmentTitle,
|
|
||||||
required this.attachment,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String sanitizedHtmlContent;
|
|
||||||
final String htmlAttachmentTitle;
|
|
||||||
final Attachment attachment;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [
|
|
||||||
sanitizedHtmlContent,
|
|
||||||
htmlAttachmentTitle,
|
|
||||||
attachment,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
class GetHtmlContentFromAttachmentFailure extends FeatureFailure {
|
|
||||||
GetHtmlContentFromAttachmentFailure({super.exception, required this.attachment});
|
|
||||||
|
|
||||||
final Attachment attachment;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [attachment];
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart';
|
|
||||||
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_email_content_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_email_read_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
|
||||||
@@ -22,12 +20,10 @@ class EmailBindings extends Bindings {
|
|||||||
Get.put(SingleEmailController(
|
Get.put(SingleEmailController(
|
||||||
Get.find<GetEmailContentInteractor>(),
|
Get.find<GetEmailContentInteractor>(),
|
||||||
Get.find<MarkAsEmailReadInteractor>(),
|
Get.find<MarkAsEmailReadInteractor>(),
|
||||||
Get.find<ExportAttachmentInteractor>(),
|
|
||||||
Get.find<MarkAsStarEmailInteractor>(),
|
Get.find<MarkAsStarEmailInteractor>(),
|
||||||
Get.find<GetAllIdentitiesInteractor>(),
|
Get.find<GetAllIdentitiesInteractor>(),
|
||||||
Get.find<StoreOpenedEmailInteractor>(),
|
Get.find<StoreOpenedEmailInteractor>(),
|
||||||
Get.find<PrintEmailInteractor>(),
|
Get.find<PrintEmailInteractor>(),
|
||||||
Get.find<ExportAllAttachmentsInteractor>(),
|
|
||||||
currentEmailId: currentEmailId,
|
currentEmailId: currentEmailId,
|
||||||
), tag: tag);
|
), tag: tag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
|||||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart';
|
|
||||||
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_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_entire_message_as_document_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/get_stored_email_state_interactor.dart';
|
||||||
@@ -26,9 +24,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_
|
|||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
|
||||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
|
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
|
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart';
|
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart';
|
||||||
@@ -111,23 +106,12 @@ class EmailInteractorBindings extends InteractorsBindings {
|
|||||||
void bindingsInteractor() {
|
void bindingsInteractor() {
|
||||||
Get.lazyPut(() => GetEmailContentInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => GetEmailContentInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => ExportAttachmentInteractor(
|
|
||||||
Get.find<EmailRepository>(),
|
|
||||||
Get.find<CredentialRepository>(),
|
|
||||||
Get.find<AccountRepository>(),
|
|
||||||
Get.find<AuthenticationOIDCRepository>(),
|
|
||||||
));
|
|
||||||
Get.lazyPut(() => MoveToMailboxInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => MoveToMailboxInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => MarkAsStarEmailInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => MarkAsStarEmailInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => GetStoredEmailStateInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => GetStoredEmailStateInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => StoreOpenedEmailInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => StoreOpenedEmailInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => PrintEmailInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => PrintEmailInteractor(Get.find<EmailRepository>()));
|
||||||
IdentityInteractorsBindings().dependencies();
|
IdentityInteractorsBindings().dependencies();
|
||||||
Get.lazyPut(() => ExportAllAttachmentsInteractor(
|
|
||||||
Get.find<EmailRepository>(),
|
|
||||||
Get.find<AccountRepository>(),
|
|
||||||
Get.find<AuthenticationOIDCRepository>(),
|
|
||||||
Get.find<CredentialRepository>()));
|
|
||||||
if (PlatformInfo.isIOS) {
|
if (PlatformInfo.isIOS) {
|
||||||
Get.lazyPut(() => GetEntireMessageAsDocumentInteractor(
|
Get.lazyPut(() => GetEntireMessageAsDocumentInteractor(
|
||||||
Get.find<EmailRepository>(),
|
Get.find<EmailRepository>(),
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:core/core.dart';
|
import 'package:core/core.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/text/new_line_transformer.dart';
|
import 'package:core/presentation/utils/html_transformer/text/new_line_transformer.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_unescape_html_transformer.dart';
|
import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_unescape_html_transformer.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
@@ -26,12 +23,12 @@ import 'package:jmap_dart_client/jmap/mdn/disposition.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/mdn/mdn.dart';
|
import 'package:jmap_dart_client/jmap/mdn/mdn.dart';
|
||||||
import 'package:model/error_type_handler/unknown_uri_exception.dart';
|
import 'package:model/error_type_handler/unknown_uri_exception.dart';
|
||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
import 'package:open_file/open_file.dart' as open_file;
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart';
|
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart';
|
||||||
import 'package:tmail_ui_user/features/base/state/button_state.dart';
|
import 'package:tmail_ui_user/features/base/state/button_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart';
|
import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/event_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/event_action.dart';
|
||||||
@@ -43,9 +40,6 @@ import 'package:tmail_ui_user/features/email/domain/state/calendar_event_counter
|
|||||||
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_maybe_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_maybe_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reject_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reject_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reply_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reply_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/export_all_attachments_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/export_attachment_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_entire_message_as_document_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/get_entire_message_as_document_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
|
||||||
@@ -57,8 +51,6 @@ import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_stat
|
|||||||
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_counter_accept_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_counter_accept_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reject_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reject_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart';
|
|
||||||
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_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_entire_message_as_document_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_email_read_interactor.dart';
|
||||||
@@ -71,7 +63,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_
|
|||||||
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
|
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/bindings/calendar_event_interactor_bindings.dart';
|
import 'package:tmail_ui_user/features/email/presentation/bindings/calendar_event_interactor_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interactor_bindings.dart';
|
import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interactor_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_attendee_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_attendee_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_organizer_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_organizer_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/handle_mail_action_by_shortcut_action_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/handle_mail_action_by_shortcut_action_extension.dart';
|
||||||
@@ -84,12 +75,11 @@ import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscrib
|
|||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
|
||||||
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_attachment_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
||||||
@@ -121,12 +111,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
|
|
||||||
final GetEmailContentInteractor _getEmailContentInteractor;
|
final GetEmailContentInteractor _getEmailContentInteractor;
|
||||||
final MarkAsEmailReadInteractor _markAsEmailReadInteractor;
|
final MarkAsEmailReadInteractor _markAsEmailReadInteractor;
|
||||||
final ExportAttachmentInteractor _exportAttachmentInteractor;
|
|
||||||
final MarkAsStarEmailInteractor _markAsStarEmailInteractor;
|
final MarkAsStarEmailInteractor _markAsStarEmailInteractor;
|
||||||
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
|
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
|
||||||
final StoreOpenedEmailInteractor _storeOpenedEmailInteractor;
|
final StoreOpenedEmailInteractor _storeOpenedEmailInteractor;
|
||||||
final PrintEmailInteractor _printEmailInteractor;
|
final PrintEmailInteractor _printEmailInteractor;
|
||||||
final ExportAllAttachmentsInteractor _exportAllAttachmentsInteractor;
|
|
||||||
final EmailId? _currentEmailId;
|
final EmailId? _currentEmailId;
|
||||||
|
|
||||||
CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor;
|
CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor;
|
||||||
@@ -193,12 +181,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
SingleEmailController(
|
SingleEmailController(
|
||||||
this._getEmailContentInteractor,
|
this._getEmailContentInteractor,
|
||||||
this._markAsEmailReadInteractor,
|
this._markAsEmailReadInteractor,
|
||||||
this._exportAttachmentInteractor,
|
|
||||||
this._markAsStarEmailInteractor,
|
this._markAsStarEmailInteractor,
|
||||||
this._getAllIdentitiesInteractor,
|
this._getAllIdentitiesInteractor,
|
||||||
this._storeOpenedEmailInteractor,
|
this._storeOpenedEmailInteractor,
|
||||||
this._printEmailInteractor,
|
this._printEmailInteractor, {
|
||||||
this._exportAllAttachmentsInteractor, {
|
|
||||||
EmailId? currentEmailId,
|
EmailId? currentEmailId,
|
||||||
}) : _currentEmailId = currentEmailId;
|
}) : _currentEmailId = currentEmailId;
|
||||||
|
|
||||||
@@ -236,10 +222,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
_getEmailContentOfflineSuccess(success);
|
_getEmailContentOfflineSuccess(success);
|
||||||
} else if (success is MarkAsEmailReadSuccess) {
|
} else if (success is MarkAsEmailReadSuccess) {
|
||||||
_handleMarkAsEmailReadCompleted(success);
|
_handleMarkAsEmailReadCompleted(success);
|
||||||
} else if (success is ExportAttachmentSuccess) {
|
|
||||||
_exportAttachmentSuccessAction(success);
|
|
||||||
} else if (success is ExportAllAttachmentsSuccess) {
|
|
||||||
_exportAllAttachmentsSuccessAction(success);
|
|
||||||
} else if (success is MarkAsStarEmailSuccess) {
|
} else if (success is MarkAsStarEmailSuccess) {
|
||||||
_markAsEmailStarSuccess(success);
|
_markAsEmailStarSuccess(success);
|
||||||
} else if (success is GetAllIdentitiesSuccess) {
|
} else if (success is GetAllIdentitiesSuccess) {
|
||||||
@@ -267,10 +249,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
void handleFailureViewState(Failure failure) {
|
void handleFailureViewState(Failure failure) {
|
||||||
if (failure is MarkAsEmailReadFailure) {
|
if (failure is MarkAsEmailReadFailure) {
|
||||||
_handleMarkAsEmailReadFailure(failure);
|
_handleMarkAsEmailReadFailure(failure);
|
||||||
} else if (failure is ExportAttachmentFailure) {
|
|
||||||
_exportAttachmentFailureAction(failure);
|
|
||||||
} else if (failure is ExportAllAttachmentsFailure) {
|
|
||||||
_exportAllAttachmentsFailureAction(failure);
|
|
||||||
} else if (failure is ParseCalendarEventFailure) {
|
} else if (failure is ParseCalendarEventFailure) {
|
||||||
_handleParseCalendarEventFailure(failure);
|
_handleParseCalendarEventFailure(failure);
|
||||||
} else if (failure is GetEmailContentFailure) {
|
} else if (failure is GetEmailContentFailure) {
|
||||||
@@ -697,173 +675,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
_threadDetailController?.markCollapsedEmailReadSuccess(success);
|
_threadDetailController?.markCollapsedEmailReadSuccess(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exportAttachment(Attachment attachment) {
|
|
||||||
final cancelToken = CancelToken();
|
|
||||||
_showDownloadingFileDialog(attachment.name ?? '', cancelToken: cancelToken);
|
|
||||||
_exportAttachmentAction(attachment, cancelToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showDownloadingFileDialog(String attachmentName, {CancelToken? cancelToken}) {
|
|
||||||
if (cancelToken != null) {
|
|
||||||
Get.dialog(
|
|
||||||
PointerInterceptor(
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final appLocalizations = AppLocalizations.of(context);
|
|
||||||
return (DownloadingFileDialogBuilder()
|
|
||||||
..key(const Key('downloading_file_dialog'))
|
|
||||||
..title(appLocalizations.preparing_to_export)
|
|
||||||
..content(appLocalizations.downloading_file(attachmentName))
|
|
||||||
..actionText(appLocalizations.cancel)
|
|
||||||
..addCancelDownloadActionClick(() {
|
|
||||||
cancelToken.cancel([
|
|
||||||
appLocalizations.user_cancel_download_file,
|
|
||||||
]);
|
|
||||||
popBack();
|
|
||||||
}))
|
|
||||||
.build();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
barrierDismissible: false,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Get.dialog(
|
|
||||||
PointerInterceptor(
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final appLocalizations = AppLocalizations.of(context);
|
|
||||||
return (DownloadingFileDialogBuilder()
|
|
||||||
..key(const Key('downloading_file_for_web_dialog'))
|
|
||||||
..title(appLocalizations.preparing_to_save)
|
|
||||||
..content(
|
|
||||||
appLocalizations.downloading_file(attachmentName),
|
|
||||||
))
|
|
||||||
.build();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exportAttachmentAction(Attachment attachment, CancelToken cancelToken) {
|
|
||||||
if (accountId != null && session != null) {
|
|
||||||
try {
|
|
||||||
final baseDownloadUrl = session!.getDownloadUrl(
|
|
||||||
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
|
||||||
);
|
|
||||||
consumeState(_exportAttachmentInteractor.execute(
|
|
||||||
attachment,
|
|
||||||
accountId!,
|
|
||||||
baseDownloadUrl,
|
|
||||||
cancelToken,
|
|
||||||
));
|
|
||||||
} catch (e) {
|
|
||||||
logError('SingleEmailController::_exportAttachmentAction(): $e');
|
|
||||||
consumeState(Stream.value(Left(ExportAttachmentFailure(e))));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
consumeState(Stream.value(Left(ExportAttachmentFailure(NotFoundAccountIdException()))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void exportAllAttachments(String outputFileName) {
|
|
||||||
final cancelToken = CancelToken();
|
|
||||||
_showDownloadingFileDialog(outputFileName, cancelToken: cancelToken);
|
|
||||||
_exportAllAttachmentsAction(outputFileName, cancelToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exportAllAttachmentsAction(String outputFileName, CancelToken cancelToken) {
|
|
||||||
if (accountId == null || session == null) {
|
|
||||||
consumeState(Stream.value(Left(ExportAllAttachmentsFailure(
|
|
||||||
exception: NotFoundSessionException(),
|
|
||||||
))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final downloadAllSupported = session!.isDownloadAllSupported(accountId);
|
|
||||||
if (!downloadAllSupported) {
|
|
||||||
consumeState(Stream.value(Left(ExportAllAttachmentsFailure())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final baseDownloadAllUrl = session!.getDownloadAllCapability(accountId)!.endpoint!;
|
|
||||||
consumeState(_exportAllAttachmentsInteractor.execute(
|
|
||||||
accountId!,
|
|
||||||
currentEmail!.id!,
|
|
||||||
baseDownloadAllUrl,
|
|
||||||
outputFileName,
|
|
||||||
cancelToken: cancelToken,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exportAttachmentFailureAction(ExportAttachmentFailure failure) {
|
|
||||||
if (failure.exception is! CancelDownloadFileException) {
|
|
||||||
if (Get.isDialogOpen == true) {
|
|
||||||
popBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentOverlayContext != null && currentContext != null) {
|
|
||||||
appToast.showToastErrorMessage(
|
|
||||||
currentOverlayContext!,
|
|
||||||
AppLocalizations.of(currentContext!).attachment_download_failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exportAttachmentSuccessAction(ExportAttachmentSuccess success) async {
|
|
||||||
popBack();
|
|
||||||
_openDownloadedPreviewWorkGroupDocument(success.downloadedResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exportAllAttachmentsFailureAction(ExportAllAttachmentsFailure failure) {
|
|
||||||
if (failure.exception is! CancelDownloadFileException) {
|
|
||||||
popBack();
|
|
||||||
|
|
||||||
if (currentOverlayContext != null && currentContext != null) {
|
|
||||||
appToast.showToastErrorMessage(
|
|
||||||
currentOverlayContext!,
|
|
||||||
AppLocalizations.of(currentContext!).attachment_download_failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exportAllAttachmentsSuccessAction(ExportAllAttachmentsSuccess success) {
|
|
||||||
popBack();
|
|
||||||
_saveFileToStorage(success.downloadedResponse.filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _openDownloadedPreviewWorkGroupDocument(DownloadedResponse downloadedResponse) async {
|
|
||||||
log('SingleEmailController::_openDownloadedPreviewWorkGroupDocument(): $downloadedResponse');
|
|
||||||
final filePath = downloadedResponse.filePath;
|
|
||||||
final mediaType = downloadedResponse.mediaType;
|
|
||||||
|
|
||||||
if (mediaType == null) {
|
|
||||||
_saveFileToStorage(filePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final openResult = await open_file.OpenFile.open(
|
|
||||||
filePath,
|
|
||||||
type: Platform.isAndroid ? mediaType.mimeType : null,
|
|
||||||
// "xdg" is default value
|
|
||||||
linuxDesktopName: Platform.isIOS
|
|
||||||
? mediaType.getDocumentUti().value ?? 'xdg'
|
|
||||||
: 'xdg',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (openResult.type != open_file.ResultType.done) {
|
|
||||||
logError('SingleEmailController::_openDownloadedPreviewWorkGroupDocument(): no preview available');
|
|
||||||
_saveFileToStorage(filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _saveFileToStorage(String filePath) async {
|
|
||||||
final params = SaveFileDialogParams(sourceFilePath: filePath);
|
|
||||||
await FlutterFileDialog.saveFile(params: params);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDownloadAllSupported() {
|
bool isDownloadAllSupported() {
|
||||||
return session?.isDownloadAllSupported(accountId) ?? false;
|
return session?.isDownloadAllSupported(accountId) ?? false;
|
||||||
}
|
}
|
||||||
@@ -1059,7 +870,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
_printEmail(presentationEmail);
|
_printEmail(presentationEmail);
|
||||||
break;
|
break;
|
||||||
case EmailActionType.downloadMessageAsEML:
|
case EmailActionType.downloadMessageAsEML:
|
||||||
mailboxDashBoardController.downloadMessageAsEML(presentationEmail);
|
mailboxDashBoardController.downloadMessageAsEML(
|
||||||
|
presentationEmail: presentationEmail,
|
||||||
|
showBottomDownloadProgressBar: true,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case EmailActionType.editAsNewEmail:
|
case EmailActionType.editAsNewEmail:
|
||||||
_editAsNewEmail(presentationEmail);
|
_editAsNewEmail(presentationEmail);
|
||||||
@@ -1100,8 +914,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> openMailToLink(Uri? uri) =>
|
void openMailToLink(Uri? uri) {
|
||||||
mailboxDashBoardController.openMailToLink(uri);
|
if (uri == null) return;
|
||||||
|
mailboxDashBoardController.openComposerFromMailToLink(uri);
|
||||||
|
}
|
||||||
|
|
||||||
void deleteEmailPermanently(PresentationEmail email) {
|
void deleteEmailPermanently(PresentationEmail email) {
|
||||||
emailActionReactor.deleteEmailPermanently(
|
emailActionReactor.deleteEmailPermanently(
|
||||||
@@ -1618,68 +1434,36 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
Attachment attachment,
|
Attachment attachment,
|
||||||
{bool previewerSupported = false}
|
{bool previewerSupported = false}
|
||||||
) {
|
) {
|
||||||
if (PlatformInfo.isWeb) {
|
mailboxDashBoardController.downloadAttachment(
|
||||||
mailboxDashBoardController.downloadAttachmentForWeb(
|
attachment: attachment,
|
||||||
attachment: attachment,
|
previewerSupported: previewerSupported,
|
||||||
previewerSupported: previewerSupported,
|
showBottomDownloadProgressBar: true,
|
||||||
);
|
sourceView: DownloadSourceView.emailView,
|
||||||
} else if (PlatformInfo.isMobile) {
|
);
|
||||||
exportAttachment(attachment);
|
|
||||||
} else {
|
|
||||||
log('$runtimeType::handleDownloadAttachmentAction: THE PLATFORM IS SUPPORTED');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDownloadAllAttachmentsAction(String outputFileName) {
|
void handleDownloadAllAttachmentsAction(String outputFileName) {
|
||||||
if (PlatformInfo.isWeb) {
|
mailboxDashBoardController.downloadAllAttachments(
|
||||||
mailboxDashBoardController.downloadAllAttachmentsForWeb(
|
outputFileName: outputFileName,
|
||||||
outputFileName: outputFileName,
|
emailId: currentEmail?.id,
|
||||||
currentEmail: currentEmail,
|
showBottomDownloadProgressBar: true,
|
||||||
);
|
);
|
||||||
} else if (PlatformInfo.isMobile) {
|
|
||||||
exportAllAttachments(outputFileName);
|
|
||||||
} else {
|
|
||||||
log('EmailView::handleDownloadAllAttachmentsAction: THE PLATFORM IS SUPPORTED');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleViewAttachmentAction(BuildContext context, Attachment attachment) {
|
void handleViewAttachmentAction(BuildContext context, Attachment attachment) {
|
||||||
mailboxDashBoardController.previewAttachmentAction(
|
mailboxDashBoardController.previewAttachment(
|
||||||
context: context,
|
context: context,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
onDownloadAttachment: (attachment) {
|
sourceView: DownloadSourceView.emailView,
|
||||||
|
onPreviewOrDownloadAction: (attachment, isPreview) {
|
||||||
handleDownloadAttachmentAction(
|
handleDownloadAttachmentAction(
|
||||||
attachment,
|
attachment,
|
||||||
previewerSupported: attachment.isPreviewSupported,
|
previewerSupported: isPreview,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _openEMLPreviewer(BuildContext context, Uri? uri) async {
|
|
||||||
log('SingleEmailController::_openEMLPreviewer:uri = $uri');
|
|
||||||
if (uri == null) return;
|
|
||||||
|
|
||||||
final blobId = uri.path;
|
|
||||||
log('SingleEmailController::_openEMLPreviewer:blobId = $blobId');
|
|
||||||
if (blobId.isEmpty) return;
|
|
||||||
|
|
||||||
mailboxDashBoardController.previewEMLFileAction(
|
|
||||||
appLocalizations: AppLocalizations.of(context),
|
|
||||||
blobId: Id(blobId),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _downloadAttachmentInEMLPreview(Uri? uri) async {
|
|
||||||
log('SingleEmailController::_downloadAttachmentInEMLPreview:uri = $uri');
|
|
||||||
if (uri == null) return;
|
|
||||||
|
|
||||||
final attachment = EmailUtils.parsingAttachmentByUri(uri);
|
|
||||||
if (attachment == null) return;
|
|
||||||
|
|
||||||
handleDownloadAttachmentAction(attachment);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleMailToAttendees(CalendarOrganizer? organizer, List<CalendarAttendee>? attendees) {
|
void handleMailToAttendees(CalendarOrganizer? organizer, List<CalendarAttendee>? attendees) {
|
||||||
List<EmailAddress> listEmailAddressAttendees = [];
|
List<EmailAddress> listEmailAddressAttendees = [];
|
||||||
|
|
||||||
@@ -1745,9 +1529,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
content: success.messageDocument,
|
content: success.messageDocument,
|
||||||
),
|
),
|
||||||
imagePaths: imagePaths,
|
imagePaths: imagePaths,
|
||||||
onMailtoAction: openMailToLink,
|
onMailtoAction: (uri) async => openMailToLink(uri),
|
||||||
onPreviewAction: (uri) => _openEMLPreviewer(context, uri),
|
onDownloadFileAction: handleDownloadAttachmentAction,
|
||||||
onDownloadAction: _downloadAttachmentInEMLPreview,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onFailure: (_) {
|
onFailure: (_) {
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
Obx(() => CalendarEventDetailWidget(
|
Obx(() => CalendarEventDetailWidget(
|
||||||
calendarEvent: calendarEvent,
|
calendarEvent: calendarEvent,
|
||||||
emailContent: controller.currentEmailLoaded.value?.htmlContent ?? '',
|
emailContent: controller.currentEmailLoaded.value?.htmlContent ?? '',
|
||||||
onMailtoDelegateAction: controller.openMailToLink,
|
onMailtoDelegateAction: (uri) async => controller.openMailToLink(uri),
|
||||||
presentationEmail: controller.currentEmail,
|
presentationEmail: controller.currentEmail,
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
isInsideThreadDetailView: isInsideThreadDetailView,
|
isInsideThreadDetailView: isInsideThreadDetailView,
|
||||||
@@ -385,7 +385,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
contentPadding: 0,
|
contentPadding: 0,
|
||||||
useDefaultFontStyle: true,
|
useDefaultFontStyle: true,
|
||||||
maxHtmlContentHeight: ConstantsUI.htmlContentMaxHeight,
|
maxHtmlContentHeight: ConstantsUI.htmlContentMaxHeight,
|
||||||
onMailtoDelegateAction: controller.openMailToLink,
|
onMailtoDelegateAction: (uri) async => controller.openMailToLink(uri),
|
||||||
onHtmlContentClippedAction: controller.onHtmlContentClippedAction,
|
onHtmlContentClippedAction: controller.onHtmlContentClippedAction,
|
||||||
onScrollHorizontalEnd: controller.onScrollHorizontalEnd,
|
onScrollHorizontalEnd: controller.onScrollHorizontalEnd,
|
||||||
keepAlive: isInsideThreadDetailView,
|
keepAlive: isInsideThreadDetailView,
|
||||||
@@ -423,7 +423,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
direction: AppUtils.getCurrentDirection(context),
|
direction: AppUtils.getCurrentDirection(context),
|
||||||
contentPadding: 0,
|
contentPadding: 0,
|
||||||
useDefaultFontStyle: true,
|
useDefaultFontStyle: true,
|
||||||
onMailtoDelegateAction: controller.openMailToLink,
|
onMailtoDelegateAction: (uri) async => controller.openMailToLink(uri),
|
||||||
keepAlive: isInsideThreadDetailView,
|
keepAlive: isInsideThreadDetailView,
|
||||||
enableQuoteToggle: true,
|
enableQuoteToggle: true,
|
||||||
onScrollHorizontalEnd: controller.onScrollHorizontalEnd,
|
onScrollHorizontalEnd: controller.onScrollHorizontalEnd,
|
||||||
@@ -474,8 +474,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
),
|
),
|
||||||
onTapShowAllAttachmentFile: controller.showAllAttachmentsAction,
|
onTapShowAllAttachmentFile: controller.showAllAttachmentsAction,
|
||||||
onTapHideAllAttachments: controller.hideAllAttachmentsAction,
|
onTapHideAllAttachments: controller.hideAllAttachmentsAction,
|
||||||
showDownloadAllAttachmentsButton:
|
showDownloadAllAttachmentsButton: controller.downloadAllButtonIsEnabled(),
|
||||||
controller.downloadAllButtonIsEnabled(),
|
|
||||||
onTapDownloadAllButton: () =>
|
onTapDownloadAllButton: () =>
|
||||||
controller.handleDownloadAllAttachmentsAction(
|
controller.handleDownloadAllAttachmentsAction(
|
||||||
'TwakeMail-${DateTime.now()}',
|
'TwakeMail-${DateTime.now()}',
|
||||||
|
|||||||
@@ -1,444 +0,0 @@
|
|||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:core/core.dart';
|
|
||||||
import 'package:dartz/dartz.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
|
||||||
import 'package:model/download/download_task_id.dart';
|
|
||||||
import 'package:model/email/attachment.dart';
|
|
||||||
import 'package:model/extensions/session_extension.dart';
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_html_content_from_attachment_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
|
|
||||||
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/email/presentation/widgets/pdf_viewer/pdf_viewer.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email_previewer/email_previewer_dialog_view.dart';
|
|
||||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|
||||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
|
||||||
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
|
||||||
import 'package:tmail_ui_user/main/utils/toast_manager.dart';
|
|
||||||
|
|
||||||
typedef OnDownloadAttachmentAction = void Function(Attachment attachment);
|
|
||||||
|
|
||||||
mixin PreviewAttachmentMixin {
|
|
||||||
final DownloadManager _downloadManager = Get.find<DownloadManager>();
|
|
||||||
final PrintUtils _printUtils = Get.find<PrintUtils>();
|
|
||||||
final AppToast _appToast = Get.find<AppToast>();
|
|
||||||
final ToastManager _toastManager = Get.find<ToastManager>();
|
|
||||||
final DynamicUrlInterceptors _dynamicUrlInterceptors =
|
|
||||||
Get.find<DynamicUrlInterceptors>();
|
|
||||||
|
|
||||||
void previewAttachmentAction({
|
|
||||||
required BuildContext context,
|
|
||||||
required Attachment attachment,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
required String ownEmailAddress,
|
|
||||||
required BaseController controller,
|
|
||||||
required ParseEmailByBlobIdInteractor parseEmailInteractor,
|
|
||||||
required GetHtmlContentFromAttachmentInteractor getHtmlInteractor,
|
|
||||||
required OnDownloadAttachmentAction onDownloadAttachment,
|
|
||||||
}) {
|
|
||||||
if (PlatformInfo.isWeb && attachment.isPDFFile) {
|
|
||||||
_previewPDFFile(
|
|
||||||
context: context,
|
|
||||||
attachment: attachment,
|
|
||||||
accountId: accountId,
|
|
||||||
session: session,
|
|
||||||
);
|
|
||||||
} else if (attachment.isEMLFile) {
|
|
||||||
previewEMLFileAction(
|
|
||||||
appLocalizations: AppLocalizations.of(context),
|
|
||||||
accountId: accountId,
|
|
||||||
session: session,
|
|
||||||
ownEmailAddress: ownEmailAddress,
|
|
||||||
blobId: attachment.blobId,
|
|
||||||
controller: controller,
|
|
||||||
parseEmailByBlobIdInteractor: parseEmailInteractor,
|
|
||||||
);
|
|
||||||
} else if (attachment.isHTMLFile) {
|
|
||||||
_previewHtmlFileAction(
|
|
||||||
session: session,
|
|
||||||
accountId: accountId,
|
|
||||||
attachment: attachment,
|
|
||||||
controller: controller,
|
|
||||||
getHtmlInteractor: getHtmlInteractor,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onDownloadAttachment(attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _previewPDFFile({
|
|
||||||
required BuildContext context,
|
|
||||||
required Attachment attachment,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
}) async {
|
|
||||||
if (accountId == null || session == null) {
|
|
||||||
_appToast.showToastErrorMessage(
|
|
||||||
context,
|
|
||||||
AppLocalizations.of(context).noPreviewAvailable,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final downloadUrl = session.getDownloadUrl(
|
|
||||||
jmapUrl: _dynamicUrlInterceptors.jmapUrl,
|
|
||||||
);
|
|
||||||
|
|
||||||
await Get.generalDialog(
|
|
||||||
barrierColor: Colors.black.withValues(alpha: 0.8),
|
|
||||||
pageBuilder: (_, __, ___) {
|
|
||||||
return PointerInterceptor(
|
|
||||||
child: PDFViewer(
|
|
||||||
attachment: attachment,
|
|
||||||
accountId: accountId,
|
|
||||||
downloadUrl: downloadUrl,
|
|
||||||
downloadAction: _downloadPDFFile,
|
|
||||||
printAction: _printPDFFile,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
if (context.mounted) {
|
|
||||||
_appToast.showToastErrorMessage(
|
|
||||||
context,
|
|
||||||
AppLocalizations.of(context).noPreviewAvailable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _downloadPDFFile(Uint8List bytes, String fileName) {
|
|
||||||
_downloadManager.createAnchorElementDownloadFileWeb(bytes, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _printPDFFile(Uint8List bytes, String fileName) async {
|
|
||||||
await _printUtils.printPDFFile(bytes, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void previewEMLFileAction({
|
|
||||||
required AppLocalizations appLocalizations,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
required String ownEmailAddress,
|
|
||||||
required Id? blobId,
|
|
||||||
required ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor,
|
|
||||||
required BaseController controller,
|
|
||||||
}) {
|
|
||||||
SmartDialog.showLoading(
|
|
||||||
msg: appLocalizations.loadingPleaseWait,
|
|
||||||
maskColor: Colors.black38,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (session == null) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: ParseEmailByBlobIdFailure(NotFoundSessionException()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accountId == null) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: ParseEmailByBlobIdFailure(NotFoundAccountIdException()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blobId == null) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: ParseEmailByBlobIdFailure(NotFoundBlobIdException([])),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.consumeState(
|
|
||||||
parseEmailByBlobIdInteractor.execute(
|
|
||||||
accountId,
|
|
||||||
session,
|
|
||||||
ownEmailAddress,
|
|
||||||
blobId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
({
|
|
||||||
bool canDownloadAttachment,
|
|
||||||
AccountId? accountId,
|
|
||||||
String? downloadUrl,
|
|
||||||
Id? blobId,
|
|
||||||
}) evaluateAttachment({
|
|
||||||
required Session? session,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Attachment attachment,
|
|
||||||
}) {
|
|
||||||
String? downloadUrl;
|
|
||||||
try {
|
|
||||||
downloadUrl = session?.getDownloadUrl(
|
|
||||||
jmapUrl: _dynamicUrlInterceptors.jmapUrl,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
downloadUrl = null;
|
|
||||||
}
|
|
||||||
final blobId = attachment.blobId;
|
|
||||||
|
|
||||||
if (accountId == null || downloadUrl == null || blobId == null) {
|
|
||||||
return (
|
|
||||||
canDownloadAttachment: false,
|
|
||||||
accountId: accountId,
|
|
||||||
downloadUrl: downloadUrl,
|
|
||||||
blobId: blobId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
canDownloadAttachment: true,
|
|
||||||
accountId: accountId,
|
|
||||||
downloadUrl: downloadUrl,
|
|
||||||
blobId: blobId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _previewHtmlFileAction({
|
|
||||||
required Session? session,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Attachment attachment,
|
|
||||||
required BaseController controller,
|
|
||||||
required GetHtmlContentFromAttachmentInteractor getHtmlInteractor,
|
|
||||||
}) {
|
|
||||||
final attachmentEvaluation = evaluateAttachment(
|
|
||||||
accountId: accountId,
|
|
||||||
session: session,
|
|
||||||
attachment: attachment,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!attachmentEvaluation.canDownloadAttachment) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: GetHtmlContentFromAttachmentFailure(
|
|
||||||
exception: null,
|
|
||||||
attachment: attachment,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.consumeState(
|
|
||||||
getHtmlInteractor.execute(
|
|
||||||
attachmentEvaluation.accountId!,
|
|
||||||
attachment,
|
|
||||||
DownloadTaskId(attachmentEvaluation.blobId!.value),
|
|
||||||
attachmentEvaluation.downloadUrl!,
|
|
||||||
TransformConfiguration.create(
|
|
||||||
customDomTransformers: [SanitizeHyperLinkTagInHtmlTransformer()],
|
|
||||||
customTextTransformers: [
|
|
||||||
const StandardizeHtmlSanitizingTransformers()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _emitFailure({
|
|
||||||
required BaseController controller,
|
|
||||||
required FeatureFailure failure,
|
|
||||||
}) {
|
|
||||||
controller.consumeState(Stream.value(Left(failure)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleParseEmailByBlobIdSuccess({
|
|
||||||
required BuildContext? context,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
required String ownEmailAddress,
|
|
||||||
required Id blobId,
|
|
||||||
required Email email,
|
|
||||||
required BaseController controller,
|
|
||||||
required PreviewEmailFromEmlFileInteractor previewInteractor,
|
|
||||||
}) {
|
|
||||||
if (session == null) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: PreviewEmailFromEmlFileFailure(NotFoundSessionException()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accountId == null) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: PreviewEmailFromEmlFileFailure(NotFoundAccountIdException()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context == null) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: PreviewEmailFromEmlFileFailure(NotFoundContextException()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
controller.consumeState(previewInteractor.execute(
|
|
||||||
PreviewEmailEMLRequest(
|
|
||||||
accountId: accountId,
|
|
||||||
session: session,
|
|
||||||
ownEmailAddress: ownEmailAddress,
|
|
||||||
blobId: blobId,
|
|
||||||
email: email,
|
|
||||||
locale: Localizations.localeOf(context),
|
|
||||||
appLocalizations: AppLocalizations.of(context),
|
|
||||||
baseDownloadUrl: session.getDownloadUrl(
|
|
||||||
jmapUrl: _dynamicUrlInterceptors.jmapUrl,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
} catch (e) {
|
|
||||||
_emitFailure(
|
|
||||||
controller: controller,
|
|
||||||
failure: PreviewEmailFromEmlFileFailure(e),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleParseEmailByBlobIdFailure(ParseEmailByBlobIdFailure failure) {
|
|
||||||
SmartDialog.dismiss();
|
|
||||||
_toastManager.showMessageFailure(failure);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handlePreviewEmailFromEMLFileFailure(
|
|
||||||
PreviewEmailFromEmlFileFailure failure,
|
|
||||||
) {
|
|
||||||
SmartDialog.dismiss();
|
|
||||||
_toastManager.showMessageFailure(failure);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handlePreviewEmailFromEMLFileSuccess({
|
|
||||||
required EMLPreviewer emlPreviewer,
|
|
||||||
required BuildContext? context,
|
|
||||||
required ImagePaths imagePaths,
|
|
||||||
required OnMailtoDelegateAction onMailtoAction,
|
|
||||||
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
|
||||||
required OnPreviewEMLDelegateAction onPreviewAction,
|
|
||||||
}) {
|
|
||||||
SmartDialog.dismiss();
|
|
||||||
|
|
||||||
if (PlatformInfo.isWeb) {
|
|
||||||
bool isOpen = HtmlUtils.openNewWindowByUrl(
|
|
||||||
RouteUtils.createUrlWebLocationBar(
|
|
||||||
AppRoutes.emailEMLPreviewer,
|
|
||||||
previewId: emlPreviewer.id,
|
|
||||||
).toString(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isOpen) {
|
|
||||||
_toastManager.showMessageFailure(
|
|
||||||
PreviewEmailFromEmlFileFailure(CannotOpenNewWindowException()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (PlatformInfo.isMobile) {
|
|
||||||
if (context == null) {
|
|
||||||
_toastManager.showMessageFailure(
|
|
||||||
PreviewEmailFromEmlFileFailure(NotFoundContextException()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlatformInfo.isAndroid) {
|
|
||||||
showModalSheetToPreviewEMLAttachment(
|
|
||||||
context: context,
|
|
||||||
emlPreviewer: emlPreviewer,
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
onMailtoAction: onMailtoAction,
|
|
||||||
onDownloadAction: onDownloadAction,
|
|
||||||
onPreviewAction: onPreviewAction,
|
|
||||||
);
|
|
||||||
} else if (PlatformInfo.isIOS) {
|
|
||||||
showDialogToPreviewEMLAttachment(
|
|
||||||
context: context,
|
|
||||||
emlPreviewer: emlPreviewer,
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
onMailtoAction: onMailtoAction,
|
|
||||||
onDownloadAction: onDownloadAction,
|
|
||||||
onPreviewAction: onPreviewAction,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showModalSheetToPreviewEMLAttachment({
|
|
||||||
required BuildContext context,
|
|
||||||
required EMLPreviewer emlPreviewer,
|
|
||||||
required ImagePaths imagePaths,
|
|
||||||
required OnMailtoDelegateAction onMailtoAction,
|
|
||||||
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
|
||||||
required OnPreviewEMLDelegateAction onPreviewAction,
|
|
||||||
}) {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
showDragHandle: true,
|
|
||||||
useSafeArea: true,
|
|
||||||
isScrollControlled: true,
|
|
||||||
shape: const RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(20.0),
|
|
||||||
topRight: Radius.circular(20.0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
builder: (_) {
|
|
||||||
return DraggableScrollableSheet(
|
|
||||||
initialChildSize: 1.0,
|
|
||||||
builder: (context, ___) => EmailPreviewerDialogView(
|
|
||||||
emlPreviewer: emlPreviewer,
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
onMailtoDelegateAction: onMailtoAction,
|
|
||||||
onPreviewEMLDelegateAction: onPreviewAction,
|
|
||||||
onDownloadAttachmentDelegateAction: onDownloadAction,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showDialogToPreviewEMLAttachment({
|
|
||||||
required BuildContext context,
|
|
||||||
required EMLPreviewer emlPreviewer,
|
|
||||||
required ImagePaths imagePaths,
|
|
||||||
required OnMailtoDelegateAction onMailtoAction,
|
|
||||||
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
|
||||||
required OnPreviewEMLDelegateAction onPreviewAction,
|
|
||||||
}) {
|
|
||||||
Get.dialog(
|
|
||||||
EmailPreviewerDialogView(
|
|
||||||
emlPreviewer: emlPreviewer,
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
onMailtoDelegateAction: onMailtoAction,
|
|
||||||
onPreviewEMLDelegateAction: onPreviewAction,
|
|
||||||
onDownloadAttachmentDelegateAction: onDownloadAction,
|
|
||||||
),
|
|
||||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,8 +14,8 @@ import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
|
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_html_content_from_attachment_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_and_get_html_content_from_attachment_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
@@ -83,11 +83,11 @@ class EmailUtils {
|
|||||||
return state?.fold(
|
return state?.fold(
|
||||||
(failure) {
|
(failure) {
|
||||||
return failure is DownloadAttachmentForWebFailure
|
return failure is DownloadAttachmentForWebFailure
|
||||||
|| failure is GetHtmlContentFromAttachmentFailure;
|
|| failure is DownloadAndGetHtmlContentFromAttachmentFailure;
|
||||||
},
|
},
|
||||||
(success) {
|
(success) {
|
||||||
return success is DownloadAttachmentForWebSuccess
|
return success is DownloadAttachmentForWebSuccess
|
||||||
|| success is GetHtmlContentFromAttachmentSuccess
|
|| success is DownloadAndGetHtmlContentFromAttachmentSuccess
|
||||||
|| success is IdleDownloadAttachmentForWeb;
|
|| success is IdleDownloadAttachmentForWeb;
|
||||||
}) ?? false;
|
}) ?? false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import 'package:get/get.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/exceptions/download_attachment_exceptions.dart';
|
import 'package:tmail_ui_user/features/download/domain/exceptions/download_attachment_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
import 'package:twake_previewer_flutter/core/previewer_options/options/loading_options.dart';
|
import 'package:twake_previewer_flutter/core/previewer_options/options/loading_options.dart';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import 'package:core/presentation/extensions/color_extension.dart';
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
|
|
||||||
class DownloadAttachmentLoadingBar extends StatelessWidget {
|
class DownloadAttachmentLoadingBar extends StatelessWidget {
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import 'package:core/data/network/download/download_manager.dart';
|
import 'package:core/data/network/download/download_manager.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_preview_email_eml_content_shared_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_preview_eml_content_in_memory_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/move_preview_eml_content_from_persistent_to_memory_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/parse_email_by_blob_id_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/preview_email_from_eml_file_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/remove_preview_email_eml_content_shared_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email_previewer/email_previewer_controller.dart';
|
import 'package:tmail_ui_user/features/email_previewer/email_previewer_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart';
|
import 'package:tmail_ui_user/features/download/presentation/bindings/download_interactor_bindings.dart';
|
||||||
|
|
||||||
class EmailPreviewerBindings extends Bindings {
|
class EmailPreviewerBindings extends Bindings {
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -20,18 +20,18 @@ import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dar
|
|||||||
import 'package:tmail_ui_user/features/caching/exceptions/local_storage_exception.dart';
|
import 'package:tmail_ui_user/features/caching/exceptions/local_storage_exception.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/download_attachment_for_web_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_preview_email_eml_content_shared_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/get_preview_email_eml_content_shared_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_preview_eml_content_in_memory_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/get_preview_eml_content_in_memory_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/parse_email_by_blob_id_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/preview_email_from_eml_file_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_preview_email_eml_content_shared_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_preview_eml_content_in_memory_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/move_preview_eml_content_from_persistent_to_memory_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/parse_email_by_blob_id_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/preview_email_from_eml_file_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/remove_preview_email_eml_content_shared_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
|
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/email/presentation/model/eml_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import 'package:core/presentation/views/html_viewer/html_content_viewer_on_web_w
|
|||||||
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_preview_email_eml_content_shared_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/get_preview_email_eml_content_shared_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_preview_eml_content_in_memory_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/get_preview_eml_content_in_memory_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/preview_email_from_eml_file_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/email_previewer/download_attachment_loading_bar.dart';
|
import 'package:tmail_ui_user/features/email_previewer/download_attachment_loading_bar.dart';
|
||||||
import 'package:tmail_ui_user/features/email_previewer/email_previewer_controller.dart';
|
import 'package:tmail_ui_user/features/email_previewer/email_previewer_controller.dart';
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'package:core/presentation/state/failure.dart';
|
|||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
|
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
|
||||||
|
|
||||||
class DownloadUIAction extends UIAction {
|
class DownloadUIAction extends UIAction {
|
||||||
@@ -24,19 +23,10 @@ class UpdateAttachmentsViewStateAction extends DownloadUIAction {
|
|||||||
List<Object?> get props => [blobId, viewState];
|
List<Object?> get props => [blobId, viewState];
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadAttachmentsQuicklyAction extends DownloadUIAction {
|
class OpenComposerFromMailtoLinkAction extends DownloadUIAction {
|
||||||
DownloadAttachmentsQuicklyAction(this.attachment);
|
OpenComposerFromMailtoLinkAction(this.uri);
|
||||||
|
|
||||||
final Attachment attachment;
|
final Uri uri;
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [attachment];
|
|
||||||
}
|
|
||||||
|
|
||||||
class OpenMailtoLinkFromPreviewAttachmentAction extends DownloadUIAction {
|
|
||||||
OpenMailtoLinkFromPreviewAttachmentAction(this.uri);
|
|
||||||
|
|
||||||
final Uri? uri;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uri];
|
List<Object?> get props => [uri];
|
||||||
|
|||||||
+16
-9
@@ -17,6 +17,8 @@ import 'package:tmail_ui_user/features/composer/data/repository/contact_reposito
|
|||||||
import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart';
|
import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/export_all_attachments_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/export_attachment_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/print_file_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/print_file_datasource.dart';
|
||||||
@@ -32,15 +34,16 @@ import 'package:tmail_ui_user/features/email/data/repository/email_repository_im
|
|||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_permanently_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_permanently_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_all_attachments_for_web_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_attachment_for_web_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/download_and_get_html_content_from_attachment_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/usecase/get_html_content_from_upload_file_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_restored_deleted_message_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/get_restored_deleted_message_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_email_read_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/parse_email_by_blob_id_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/preview_email_from_eml_file_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/restore_deleted_message_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/restore_deleted_message_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.dart';
|
import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.dart';
|
||||||
@@ -99,10 +102,10 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_re
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_last_time_dismissed_spam_reported_interactor.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_last_time_dismissed_spam_reported_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_spam_report_state_interactor.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_spam_report_state_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart';
|
import 'package:tmail_ui_user/features/download/presentation/bindings/download_interactor_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
||||||
@@ -175,12 +178,16 @@ class MailboxDashBoardBindings extends BaseBindings {
|
|||||||
Get.find<GetAppGridLinagraEcosystemInteractor>(),
|
Get.find<GetAppGridLinagraEcosystemInteractor>(),
|
||||||
));
|
));
|
||||||
Get.put(DownloadController(
|
Get.put(DownloadController(
|
||||||
|
Get.find<DownloadManager>(),
|
||||||
|
Get.find<PrintUtils>(),
|
||||||
Get.find<DownloadAttachmentForWebInteractor>(),
|
Get.find<DownloadAttachmentForWebInteractor>(),
|
||||||
Get.find<DownloadAllAttachmentsForWebInteractor>(),
|
Get.find<DownloadAllAttachmentsForWebInteractor>(),
|
||||||
Get.find<DownloadManager>(),
|
|
||||||
Get.find<ParseEmailByBlobIdInteractor>(),
|
Get.find<ParseEmailByBlobIdInteractor>(),
|
||||||
Get.find<PreviewEmailFromEmlFileInteractor>(),
|
Get.find<PreviewEmailFromEmlFileInteractor>(),
|
||||||
Get.find<GetHtmlContentFromAttachmentInteractor>(),
|
Get.find<DownloadAndGetHtmlContentFromAttachmentInteractor>(),
|
||||||
|
Get.find<GetHtmlContentFromUploadFileInteractor>(),
|
||||||
|
Get.find<ExportAttachmentInteractor>(),
|
||||||
|
Get.find<ExportAllAttachmentsInteractor>(),
|
||||||
));
|
));
|
||||||
Get.put(SearchController(
|
Get.put(SearchController(
|
||||||
Get.find<QuickSearchEmailInteractor>(),
|
Get.find<QuickSearchEmailInteractor>(),
|
||||||
|
|||||||
-617
@@ -1,617 +0,0 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:core/data/network/config/dynamic_url_interceptors.dart';
|
|
||||||
import 'package:core/data/network/download/download_manager.dart';
|
|
||||||
import 'package:core/presentation/extensions/color_extension.dart';
|
|
||||||
import 'package:core/presentation/state/failure.dart';
|
|
||||||
import 'package:core/presentation/state/success.dart';
|
|
||||||
import 'package:core/utils/app_logger.dart';
|
|
||||||
import 'package:core/utils/platform_info.dart';
|
|
||||||
import 'package:dartz/dartz.dart';
|
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
|
|
||||||
import 'package:http_parser/http_parser.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
|
||||||
import 'package:model/download/download_task_id.dart';
|
|
||||||
import 'package:model/email/attachment.dart';
|
|
||||||
import 'package:model/email/eml_attachment.dart';
|
|
||||||
import 'package:model/email/presentation_email.dart';
|
|
||||||
import 'package:model/extensions/presentation_email_extension.dart';
|
|
||||||
import 'package:model/extensions/session_extension.dart';
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_all_attachments_for_web_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/get_html_content_from_attachment_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/mixin/preview_attachment_mixin.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart';
|
|
||||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
|
||||||
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
|
||||||
import 'package:twake_previewer_flutter/core/constants/supported_charset.dart';
|
|
||||||
import 'package:twake_previewer_flutter/core/previewer_options/options/previewer_state.dart';
|
|
||||||
import 'package:twake_previewer_flutter/core/previewer_options/options/top_bar_options.dart';
|
|
||||||
import 'package:twake_previewer_flutter/core/previewer_options/previewer_options.dart';
|
|
||||||
import 'package:twake_previewer_flutter/twake_image_previewer/twake_image_previewer.dart';
|
|
||||||
import 'package:twake_previewer_flutter/twake_plain_text_previewer/twake_plain_text_previewer.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
typedef UpdateDownloadTaskStateCallback = DownloadTaskState Function(DownloadTaskState currentState);
|
|
||||||
|
|
||||||
class DownloadController extends BaseController with PreviewAttachmentMixin {
|
|
||||||
final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor;
|
|
||||||
final DownloadAllAttachmentsForWebInteractor
|
|
||||||
_downloadAllAttachmentsForWebInteractor;
|
|
||||||
final DownloadManager _downloadManager;
|
|
||||||
final ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor;
|
|
||||||
final PreviewEmailFromEmlFileInteractor previewEmailFromEmlFileInteractor;
|
|
||||||
final GetHtmlContentFromAttachmentInteractor
|
|
||||||
getHtmlContentFromAttachmentInteractor;
|
|
||||||
|
|
||||||
DownloadController(
|
|
||||||
this._downloadAttachmentForWebInteractor,
|
|
||||||
this._downloadAllAttachmentsForWebInteractor,
|
|
||||||
this._downloadManager,
|
|
||||||
this.parseEmailByBlobIdInteractor,
|
|
||||||
this.previewEmailFromEmlFileInteractor,
|
|
||||||
this.getHtmlContentFromAttachmentInteractor,
|
|
||||||
);
|
|
||||||
|
|
||||||
final listDownloadTaskState = RxList<DownloadTaskState>();
|
|
||||||
final hideDownloadTaskbar = RxBool(false);
|
|
||||||
final downloadUIAction = Rxn<DownloadUIAction>();
|
|
||||||
|
|
||||||
final _downloadProgressStateController =
|
|
||||||
StreamController<Either<Failure, Success>>.broadcast();
|
|
||||||
StreamSubscription<Either<Failure, Success>>?
|
|
||||||
_downloadProgressStateSubscription;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onInit() {
|
|
||||||
super.onInit();
|
|
||||||
_registerDownloadProgressState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _registerDownloadProgressState() {
|
|
||||||
_downloadProgressStateSubscription = _downloadProgressStateController.stream
|
|
||||||
.listen(_onDownloadProgressStateChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onDownloadProgressStateChanged(Either<Failure, Success> state) {
|
|
||||||
state.fold((_) => null, (success) {
|
|
||||||
if (success is StartDownloadAttachmentForWeb) {
|
|
||||||
_handleStartSingleDownload(success);
|
|
||||||
} else if (success is DownloadingAttachmentForWeb) {
|
|
||||||
_updateDownloadProgress(
|
|
||||||
success.taskId,
|
|
||||||
success.progress,
|
|
||||||
success.downloaded,
|
|
||||||
success.total,
|
|
||||||
);
|
|
||||||
} else if (success is StartDownloadAllAttachmentsForWeb) {
|
|
||||||
_handleStartAllDownload(success);
|
|
||||||
} else if (success is DownloadingAllAttachmentsForWeb) {
|
|
||||||
_updateDownloadProgress(
|
|
||||||
success.taskId,
|
|
||||||
success.progress,
|
|
||||||
success.downloaded,
|
|
||||||
success.total,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleStartSingleDownload(StartDownloadAttachmentForWeb success) {
|
|
||||||
if (success.previewerSupported) return;
|
|
||||||
|
|
||||||
addDownloadTask(
|
|
||||||
DownloadTaskState(
|
|
||||||
taskId: success.taskId,
|
|
||||||
attachment: success.attachment,
|
|
||||||
onCancel: success.cancelToken?.cancel,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_hasValidContext) {
|
|
||||||
appToast.showToastMessage(
|
|
||||||
currentOverlayContext!,
|
|
||||||
AppLocalizations.of(currentContext!).your_download_has_started,
|
|
||||||
leadingSVGIconColor: AppColor.primaryColor,
|
|
||||||
leadingSVGIcon: imagePaths.icDownload,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleStartAllDownload(StartDownloadAllAttachmentsForWeb success) {
|
|
||||||
addDownloadTask(
|
|
||||||
DownloadTaskState(
|
|
||||||
taskId: success.taskId,
|
|
||||||
attachment: success.attachment,
|
|
||||||
onCancel: () => success.cancelToken?.cancel(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_hasValidContext) {
|
|
||||||
appToast.showToastSuccessMessage(
|
|
||||||
currentOverlayContext!,
|
|
||||||
AppLocalizations.of(currentContext!).creatingAnArchiveForDownloading,
|
|
||||||
leadingSVGIconColor: Colors.white,
|
|
||||||
leadingSVGIcon: imagePaths.icDownloadAll,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateDownloadProgress(
|
|
||||||
DownloadTaskId taskId,
|
|
||||||
double progress,
|
|
||||||
int downloaded,
|
|
||||||
int total,
|
|
||||||
) {
|
|
||||||
final percent = progress.round();
|
|
||||||
log('$runtimeType::_updateDownloadProgress(): $percent%');
|
|
||||||
|
|
||||||
updateDownloadTaskByTaskId(taskId, (currentTask) {
|
|
||||||
return currentTask.copyWith(
|
|
||||||
progress: progress,
|
|
||||||
downloaded: downloaded,
|
|
||||||
total: total,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get _hasValidContext =>
|
|
||||||
currentOverlayContext != null && currentContext != null;
|
|
||||||
|
|
||||||
bool get notEmptyListDownloadTask => listDownloadTaskState.isNotEmpty;
|
|
||||||
|
|
||||||
void addDownloadTask(DownloadTaskState task) {
|
|
||||||
log('DownloadController::addDownloadTask(): ${task.taskId}');
|
|
||||||
listDownloadTaskState.add(task);
|
|
||||||
hideDownloadTaskbar.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateDownloadTaskByTaskId(
|
|
||||||
DownloadTaskId downloadTaskId,
|
|
||||||
UpdateDownloadTaskStateCallback updateDownloadTaskCallback,
|
|
||||||
) {
|
|
||||||
final matchIndex = listDownloadTaskState
|
|
||||||
.indexWhere((task) => task.taskId == downloadTaskId);
|
|
||||||
if (matchIndex >= 0) {
|
|
||||||
listDownloadTaskState[matchIndex] = updateDownloadTaskCallback(listDownloadTaskState[matchIndex]);
|
|
||||||
listDownloadTaskState.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteDownloadTask(DownloadTaskId taskId) {
|
|
||||||
log('DownloadController::deleteDownloadTask(): $taskId');
|
|
||||||
final matchIndex = listDownloadTaskState
|
|
||||||
.indexWhere((task) => task.taskId == taskId);
|
|
||||||
if (matchIndex >= 0) {
|
|
||||||
listDownloadTaskState.removeAt(matchIndex);
|
|
||||||
listDownloadTaskState.refresh();
|
|
||||||
}
|
|
||||||
if (listDownloadTaskState.isEmpty) {
|
|
||||||
hideDownloadTaskbar.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadAttachmentForWeb({
|
|
||||||
required Attachment attachment,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
bool previewerSupported = false,
|
|
||||||
}) {
|
|
||||||
if (accountId == null || session == null) {
|
|
||||||
consumeState(Stream.value(
|
|
||||||
Left(DownloadAttachmentForWebFailure(
|
|
||||||
attachment: attachment,
|
|
||||||
exception: NotFoundSessionException(),
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final generateTaskId = DownloadTaskId(uuid.v4());
|
|
||||||
try {
|
|
||||||
final baseDownloadUrl = session.getDownloadUrl(
|
|
||||||
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
|
||||||
);
|
|
||||||
final cancelToken = CancelToken();
|
|
||||||
consumeState(_downloadAttachmentForWebInteractor.execute(
|
|
||||||
generateTaskId,
|
|
||||||
attachment,
|
|
||||||
accountId,
|
|
||||||
baseDownloadUrl,
|
|
||||||
onReceiveController: _downloadProgressStateController,
|
|
||||||
cancelToken: cancelToken,
|
|
||||||
previewerSupported: previewerSupported,
|
|
||||||
));
|
|
||||||
} catch (e) {
|
|
||||||
consumeState(Stream.value(
|
|
||||||
Left(DownloadAttachmentForWebFailure(
|
|
||||||
attachment: attachment,
|
|
||||||
taskId: generateTaskId,
|
|
||||||
exception: e,
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadAllAttachmentsForWeb({
|
|
||||||
required String outputFileName,
|
|
||||||
required PresentationEmail? currentEmail,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
bool previewerSupported = false,
|
|
||||||
}) {
|
|
||||||
final taskId = DownloadTaskId(uuid.v4());
|
|
||||||
|
|
||||||
if (accountId == null || session == null) {
|
|
||||||
consumeState(Stream.value(
|
|
||||||
Left(DownloadAllAttachmentsForWebFailure(
|
|
||||||
exception: NotFoundSessionException(),
|
|
||||||
taskId: taskId,
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final downloadAllSupported = session.isDownloadAllSupported(accountId);
|
|
||||||
final emailId = currentEmail?.id;
|
|
||||||
|
|
||||||
if (!downloadAllSupported || emailId == null) {
|
|
||||||
consumeState(Stream.value(
|
|
||||||
Left(DownloadAllAttachmentsForWebFailure(taskId: taskId)),
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final baseDownloadAllUrl = session.getDownloadAllCapability(accountId)!.endpoint!;
|
|
||||||
final downloadAttachment = Attachment(
|
|
||||||
name: outputFileName,
|
|
||||||
type: MediaType('application', 'zip'),
|
|
||||||
);
|
|
||||||
final cancelToken = CancelToken();
|
|
||||||
consumeState(_downloadAllAttachmentsForWebInteractor.execute(
|
|
||||||
accountId,
|
|
||||||
emailId,
|
|
||||||
baseDownloadAllUrl,
|
|
||||||
downloadAttachment,
|
|
||||||
taskId,
|
|
||||||
onReceiveController: _downloadProgressStateController,
|
|
||||||
cancelToken: cancelToken,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadMessageAsEML({
|
|
||||||
required PresentationEmail presentationEmail,
|
|
||||||
required AccountId? accountId,
|
|
||||||
required Session? session,
|
|
||||||
}) {
|
|
||||||
if (accountId == null || session == null) return;
|
|
||||||
|
|
||||||
final emlAttachment = presentationEmail.createEMLAttachment();
|
|
||||||
if (emlAttachment.blobId == null) {
|
|
||||||
consumeState(Stream.value(
|
|
||||||
Left(DownloadAttachmentForWebFailure(
|
|
||||||
exception: NotFoundEmailBlobIdException(),
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final generateTaskId = DownloadTaskId(const Uuid().v4());
|
|
||||||
try {
|
|
||||||
final baseDownloadUrl = session.getDownloadUrl(
|
|
||||||
jmapUrl: getBinding<DynamicUrlInterceptors>()?.jmapUrl,
|
|
||||||
);
|
|
||||||
final cancelToken = CancelToken();
|
|
||||||
consumeState(_downloadAttachmentForWebInteractor.execute(
|
|
||||||
generateTaskId,
|
|
||||||
emlAttachment,
|
|
||||||
accountId,
|
|
||||||
baseDownloadUrl,
|
|
||||||
onReceiveController: _downloadProgressStateController,
|
|
||||||
cancelToken: cancelToken,
|
|
||||||
previewerSupported: false,
|
|
||||||
));
|
|
||||||
} catch (e) {
|
|
||||||
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(
|
|
||||||
attachment: emlAttachment,
|
|
||||||
taskId: generateTaskId,
|
|
||||||
exception: e,
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _pushDownloadUIAction(DownloadUIAction action) {
|
|
||||||
downloadUIAction.value = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleDownloadAttachmentForWebSuccess(
|
|
||||||
DownloadAttachmentForWebSuccess success,
|
|
||||||
) {
|
|
||||||
_pushDownloadUIAction(UpdateAttachmentsViewStateAction(
|
|
||||||
success.attachment.blobId,
|
|
||||||
Right<Failure, Success>(success),
|
|
||||||
));
|
|
||||||
|
|
||||||
deleteDownloadTask(success.taskId);
|
|
||||||
|
|
||||||
if (!success.previewerSupported) {
|
|
||||||
_downloadManager.createAnchorElementDownloadFileWeb(
|
|
||||||
success.bytes,
|
|
||||||
success.attachment.generateFileName(),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success.attachment.isImage) {
|
|
||||||
_previewImageFile(attachment: success.attachment, bytes: success.bytes);
|
|
||||||
} else if (success.attachment.isText || success.attachment.isJson) {
|
|
||||||
_previewTextPlainFile(
|
|
||||||
attachment: success.attachment,
|
|
||||||
bytes: success.bytes,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _downloadAttachmentQuickly(Attachment attachment) {
|
|
||||||
if (PlatformInfo.isWeb) {
|
|
||||||
_pushDownloadUIAction(DownloadAttachmentsQuicklyAction(attachment));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _previewImageFile({
|
|
||||||
required Uint8List bytes,
|
|
||||||
required Attachment attachment,
|
|
||||||
}) {
|
|
||||||
if (currentContext == null) return;
|
|
||||||
|
|
||||||
Navigator.of(currentContext!).push(GetDialogRoute(
|
|
||||||
pageBuilder: (context, _, __) => PointerInterceptor(
|
|
||||||
child: TwakeImagePreviewer(
|
|
||||||
bytes: bytes,
|
|
||||||
zoomable: true,
|
|
||||||
previewerOptions: const PreviewerOptions(
|
|
||||||
previewerState: PreviewerState.success,
|
|
||||||
),
|
|
||||||
topBarOptions: TopBarOptions(
|
|
||||||
title: attachment.generateFileName(),
|
|
||||||
onClose: () => Navigator.maybePop(context),
|
|
||||||
onDownload: currentContext == null
|
|
||||||
? null
|
|
||||||
: () => _downloadAttachmentQuickly(attachment),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
barrierDismissible: false,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _previewTextPlainFile({
|
|
||||||
required Uint8List bytes,
|
|
||||||
required Attachment attachment,
|
|
||||||
}) {
|
|
||||||
if (currentContext == null) return;
|
|
||||||
|
|
||||||
Navigator.of(currentContext!).push(GetDialogRoute(
|
|
||||||
pageBuilder: (context, _, __) => PointerInterceptor(
|
|
||||||
child: TwakePlainTextPreviewer(
|
|
||||||
supportedCharset: SupportedCharset.utf8,
|
|
||||||
bytes: bytes,
|
|
||||||
previewerOptions: PreviewerOptions(
|
|
||||||
previewerState: PreviewerState.success,
|
|
||||||
width: currentContext == null ? 200 : currentContext!.width * 0.8,
|
|
||||||
),
|
|
||||||
topBarOptions: TopBarOptions(
|
|
||||||
title: attachment.generateFileName(),
|
|
||||||
onClose: () => Navigator.maybePop(context),
|
|
||||||
onDownload: currentContext == null
|
|
||||||
? null
|
|
||||||
: () => _downloadAttachmentQuickly(attachment),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
barrierDismissible: false,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearDownloadUIAction() {
|
|
||||||
downloadUIAction.value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _downloadAllAttachmentsForWebFailure(
|
|
||||||
DownloadAllAttachmentsForWebFailure failure,
|
|
||||||
) {
|
|
||||||
deleteDownloadTask(failure.taskId);
|
|
||||||
|
|
||||||
if (currentOverlayContext == null || currentContext == null) return;
|
|
||||||
|
|
||||||
final appLocalizations = AppLocalizations.of(currentContext!);
|
|
||||||
|
|
||||||
String message = failure.cancelToken?.isCancelled == true
|
|
||||||
? appLocalizations.downloadAttachmentHasBeenCancelled
|
|
||||||
: appLocalizations.attachment_download_failed;
|
|
||||||
|
|
||||||
appToast.showToastErrorMessage(currentOverlayContext!, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _downloadAttachmentForWebFailureAction(DownloadAttachmentForWebFailure failure) {
|
|
||||||
if (failure.taskId != null) {
|
|
||||||
deleteDownloadTask(failure.taskId!);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failure.attachment != null) {
|
|
||||||
_pushDownloadUIAction(
|
|
||||||
UpdateAttachmentsViewStateAction(
|
|
||||||
failure.attachment?.blobId,
|
|
||||||
Left<Failure, Success>(failure),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentOverlayContext == null || currentContext == null) return;
|
|
||||||
|
|
||||||
final appLocalizations = AppLocalizations.of(currentContext!);
|
|
||||||
|
|
||||||
String message = appLocalizations.attachment_download_failed;
|
|
||||||
if (failure.attachment is EMLAttachment) {
|
|
||||||
message = appLocalizations.downloadMessageAsEMLFailed;
|
|
||||||
} else if (failure.cancelToken?.isCancelled == true) {
|
|
||||||
message = appLocalizations.downloadAttachmentHasBeenCancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
appToast.showToastErrorMessage(currentOverlayContext!, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void handleSuccessViewState(Success success) {
|
|
||||||
if (success is DownloadAttachmentForWebSuccess) {
|
|
||||||
_handleDownloadAttachmentForWebSuccess(success);
|
|
||||||
} else if (success is StartDownloadAttachmentForWeb) {
|
|
||||||
_pushDownloadUIAction(UpdateAttachmentsViewStateAction(
|
|
||||||
success.attachment.blobId,
|
|
||||||
Right<Failure, Success>(success),
|
|
||||||
));
|
|
||||||
} else if (success is DownloadingAttachmentForWeb) {
|
|
||||||
_pushDownloadUIAction(UpdateAttachmentsViewStateAction(
|
|
||||||
success.attachment.blobId,
|
|
||||||
Right<Failure, Success>(success),
|
|
||||||
));
|
|
||||||
} else if (success is DownloadAllAttachmentsForWebSuccess) {
|
|
||||||
deleteDownloadTask(success.taskId);
|
|
||||||
} else if (success is ParseEmailByBlobIdSuccess) {
|
|
||||||
handleParseEmailByBlobIdSuccess(
|
|
||||||
context: currentContext,
|
|
||||||
accountId: success.accountId,
|
|
||||||
session: success.session,
|
|
||||||
ownEmailAddress: success.ownEmailAddress,
|
|
||||||
blobId: success.blobId,
|
|
||||||
email: success.email,
|
|
||||||
controller: this,
|
|
||||||
previewInteractor: previewEmailFromEmlFileInteractor,
|
|
||||||
);
|
|
||||||
} else if (success is PreviewEmailFromEmlFileSuccess) {
|
|
||||||
handlePreviewEmailFromEMLFileSuccess(
|
|
||||||
emlPreviewer: success.emlPreviewer,
|
|
||||||
context: currentContext,
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
onMailtoAction: _openMailtoLink,
|
|
||||||
onDownloadAction: (uri) async {
|
|
||||||
if (uri == null) return;
|
|
||||||
|
|
||||||
final attachment = EmailUtils.parsingAttachmentByUri(uri);
|
|
||||||
if (attachment == null) return;
|
|
||||||
|
|
||||||
_downloadAttachmentQuickly(attachment);
|
|
||||||
},
|
|
||||||
onPreviewAction: (uri) async {
|
|
||||||
if (currentContext != null && uri?.path.isNotEmpty == true) {
|
|
||||||
previewEMLFileAction(
|
|
||||||
appLocalizations: AppLocalizations.of(currentContext!),
|
|
||||||
accountId: success.accountId,
|
|
||||||
session: success.session,
|
|
||||||
ownEmailAddress: success.ownEmailAddress,
|
|
||||||
blobId: Id(uri!.path),
|
|
||||||
controller: this,
|
|
||||||
parseEmailByBlobIdInteractor: parseEmailByBlobIdInteractor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else if (success is GetHtmlContentFromAttachmentSuccess) {
|
|
||||||
_pushDownloadUIAction(
|
|
||||||
UpdateAttachmentsViewStateAction(
|
|
||||||
success.attachment.blobId,
|
|
||||||
Right<Failure, Success>(success),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Get.dialog(HtmlAttachmentPreviewer(
|
|
||||||
title: success.htmlAttachmentTitle,
|
|
||||||
htmlContent: success.sanitizedHtmlContent,
|
|
||||||
mailToClicked: _openMailtoLink,
|
|
||||||
downloadAttachmentClicked: () =>
|
|
||||||
_downloadAttachmentQuickly(success.attachment),
|
|
||||||
responsiveUtils: responsiveUtils,
|
|
||||||
));
|
|
||||||
} else if (success is GettingHtmlContentFromAttachment) {
|
|
||||||
_pushDownloadUIAction(
|
|
||||||
UpdateAttachmentsViewStateAction(
|
|
||||||
success.attachment.blobId,
|
|
||||||
Right<Failure, Success>(success),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
super.handleSuccessViewState(success);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void handleFailureViewState(Failure failure) {
|
|
||||||
if (failure is DownloadAllAttachmentsForWebFailure) {
|
|
||||||
_downloadAllAttachmentsForWebFailure(failure);
|
|
||||||
} else if (failure is DownloadAttachmentForWebFailure) {
|
|
||||||
_downloadAttachmentForWebFailureAction(failure);
|
|
||||||
} else if (failure is ParseEmailByBlobIdFailure) {
|
|
||||||
handleParseEmailByBlobIdFailure(failure);
|
|
||||||
} else if (failure is PreviewEmailFromEmlFileFailure) {
|
|
||||||
handlePreviewEmailFromEMLFileFailure(failure);
|
|
||||||
} else if (failure is GetHtmlContentFromAttachmentFailure) {
|
|
||||||
_handleGetHtmlContentFromAttachmentFailure(failure);
|
|
||||||
} else {
|
|
||||||
super.handleFailureViewState(failure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleGetHtmlContentFromAttachmentFailure(
|
|
||||||
GetHtmlContentFromAttachmentFailure failure,
|
|
||||||
) {
|
|
||||||
_pushDownloadUIAction(
|
|
||||||
UpdateAttachmentsViewStateAction(
|
|
||||||
failure.attachment.blobId,
|
|
||||||
Left<Failure, Success>(failure),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (currentOverlayContext != null && currentContext != null) {
|
|
||||||
appToast.showToastErrorMessage(
|
|
||||||
currentOverlayContext!,
|
|
||||||
AppLocalizations.of(currentContext!)
|
|
||||||
.thisHtmlAttachmentCannotBePreviewed,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _openMailtoLink(Uri? uri) async {
|
|
||||||
_pushDownloadUIAction(OpenMailtoLinkFromPreviewAttachmentAction(uri));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onClose() {
|
|
||||||
_downloadProgressStateSubscription?.cancel();
|
|
||||||
_downloadProgressStateSubscription = null;
|
|
||||||
_downloadProgressStateController.close();
|
|
||||||
super.onClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-7
@@ -50,6 +50,7 @@ import 'package:tmail_ui_user/features/composer/presentation/manager/composer_ma
|
|||||||
import 'package:tmail_ui_user/features/composer/presentation/model/compose_action_mode.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/compose_action_mode.dart';
|
||||||
import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart';
|
import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart';
|
||||||
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
|
||||||
@@ -113,7 +114,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_e
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart' as search;
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart' as search;
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/cleanup_recent_search_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/cleanup_recent_search_extension.dart';
|
||||||
@@ -121,7 +121,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_action_type_for_email_selection.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_action_type_for_email_selection.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_clear_mailbox_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_clear_mailbox_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_extension.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preferences_setting_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preferences_setting_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_reactive_obx_variable_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_reactive_obx_variable_extension.dart';
|
||||||
@@ -765,11 +764,8 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
_downloadUIActionWorker = ever(
|
_downloadUIActionWorker = ever(
|
||||||
downloadController.downloadUIAction,
|
downloadController.downloadUIAction,
|
||||||
(action) {
|
(action) {
|
||||||
if (action is DownloadAttachmentsQuicklyAction) {
|
if (action is OpenComposerFromMailtoLinkAction) {
|
||||||
downloadAttachmentForWeb(attachment: action.attachment);
|
openComposerFromMailToLink(action.uri);
|
||||||
downloadController.clearDownloadUIAction();
|
|
||||||
} else if (action is OpenMailtoLinkFromPreviewAttachmentAction) {
|
|
||||||
openMailToLink(action.uri);
|
|
||||||
downloadController.clearDownloadUIAction();
|
downloadController.clearDownloadUIAction();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:model/email/presentation_email.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/download_attachment_download_controller_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
|
|
||||||
|
extension HandleDownloadAttachmentExtension on MailboxDashBoardController {
|
||||||
|
void downloadMessageAsEML({
|
||||||
|
required PresentationEmail presentationEmail,
|
||||||
|
bool showBottomDownloadProgressBar = false,
|
||||||
|
}) =>
|
||||||
|
downloadController.downloadMessageAsEML(
|
||||||
|
presentationEmail: presentationEmail,
|
||||||
|
accountId: accountId.value,
|
||||||
|
session: sessionCurrent,
|
||||||
|
showBottomDownloadProgressBar: showBottomDownloadProgressBar,
|
||||||
|
);
|
||||||
|
|
||||||
|
void downloadAttachment({
|
||||||
|
required Attachment attachment,
|
||||||
|
bool previewerSupported = false,
|
||||||
|
bool showBottomDownloadProgressBar = false,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
|
}) =>
|
||||||
|
downloadController.downloadAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
accountId: accountId.value,
|
||||||
|
session: sessionCurrent,
|
||||||
|
previewerSupported: previewerSupported,
|
||||||
|
showBottomDownloadProgressBar: showBottomDownloadProgressBar,
|
||||||
|
sourceView: sourceView,
|
||||||
|
);
|
||||||
|
|
||||||
|
void downloadAllAttachments({
|
||||||
|
required String outputFileName,
|
||||||
|
required EmailId? emailId,
|
||||||
|
bool showBottomDownloadProgressBar = false,
|
||||||
|
}) =>
|
||||||
|
downloadController.downloadAllAttachments(
|
||||||
|
outputFileName: outputFileName,
|
||||||
|
emailId: emailId,
|
||||||
|
accountId: accountId.value,
|
||||||
|
session: sessionCurrent,
|
||||||
|
showBottomDownloadProgressBar: showBottomDownloadProgressBar,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import 'package:model/email/attachment.dart';
|
|
||||||
import 'package:model/email/presentation_email.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
|
||||||
|
|
||||||
extension HandleDownloadExtension on MailboxDashBoardController {
|
|
||||||
void downloadMessageAsEML(PresentationEmail presentationEmail) {
|
|
||||||
downloadController.downloadMessageAsEML(
|
|
||||||
presentationEmail: presentationEmail,
|
|
||||||
accountId: accountId.value,
|
|
||||||
session: sessionCurrent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadAttachmentForWeb({
|
|
||||||
required Attachment attachment,
|
|
||||||
bool previewerSupported = false,
|
|
||||||
}) {
|
|
||||||
downloadController.downloadAttachmentForWeb(
|
|
||||||
attachment: attachment,
|
|
||||||
accountId: accountId.value,
|
|
||||||
session: sessionCurrent,
|
|
||||||
previewerSupported: previewerSupported,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadAllAttachmentsForWeb({
|
|
||||||
required String outputFileName,
|
|
||||||
PresentationEmail? currentEmail,
|
|
||||||
}) {
|
|
||||||
downloadController.downloadAllAttachmentsForWeb(
|
|
||||||
outputFileName: outputFileName,
|
|
||||||
currentEmail: currentEmail,
|
|
||||||
accountId: accountId.value,
|
|
||||||
session: sessionCurrent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+40
-27
@@ -2,48 +2,53 @@ import 'package:core/presentation/resources/image_paths.dart';
|
|||||||
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
|
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/mixin/preview_attachment_mixin.dart';
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/download_attachment_download_controller_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/download/presentation/extensions/preview_attachment_download_controller_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_item_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_attachment_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
||||||
|
|
||||||
extension HandlePreviewAttachmentExtension on MailboxDashBoardController {
|
extension HandlePreviewAttachmentExtension on MailboxDashBoardController {
|
||||||
void previewAttachmentAction({
|
void previewAttachment({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required Attachment attachment,
|
required Attachment attachment,
|
||||||
required OnDownloadAttachmentAction onDownloadAttachment,
|
required OnPreviewOrDownloadAttachmentAction onPreviewOrDownloadAction,
|
||||||
|
bool isDialogLoadingVisible = false,
|
||||||
|
DownloadSourceView? sourceView,
|
||||||
}) =>
|
}) =>
|
||||||
downloadController.previewAttachmentAction(
|
downloadController.previewAttachment(
|
||||||
context: context,
|
context: context,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
accountId: accountId.value,
|
accountId: accountId.value,
|
||||||
session: sessionCurrent,
|
session: sessionCurrent,
|
||||||
ownEmailAddress: ownEmailAddress.value,
|
ownEmailAddress: ownEmailAddress.value,
|
||||||
controller: downloadController,
|
sourceView: sourceView,
|
||||||
parseEmailInteractor: downloadController.parseEmailByBlobIdInteractor,
|
onPreviewOrDownloadAction: onPreviewOrDownloadAction,
|
||||||
getHtmlInteractor:
|
isDialogLoadingVisible: isDialogLoadingVisible,
|
||||||
downloadController.getHtmlContentFromAttachmentInteractor,
|
|
||||||
onDownloadAttachment: onDownloadAttachment,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void previewEMLFileAction({
|
void previewUploadFile({
|
||||||
required AppLocalizations appLocalizations,
|
required BuildContext context,
|
||||||
required Id? blobId,
|
required UploadFileState uploadFile,
|
||||||
|
required OnPreviewOrDownloadAttachmentAction onPreviewOrDownloadAction,
|
||||||
|
bool isDialogLoadingVisible = false,
|
||||||
}) =>
|
}) =>
|
||||||
downloadController.previewEMLFileAction(
|
downloadController.previewUploadFile(
|
||||||
appLocalizations: appLocalizations,
|
context: context,
|
||||||
|
uploadFile: uploadFile,
|
||||||
accountId: accountId.value,
|
accountId: accountId.value,
|
||||||
session: sessionCurrent,
|
session: sessionCurrent,
|
||||||
ownEmailAddress: ownEmailAddress.value,
|
ownEmailAddress: ownEmailAddress.value,
|
||||||
blobId: blobId,
|
onPreviewOrDownloadAction: onPreviewOrDownloadAction,
|
||||||
controller: downloadController,
|
isDialogLoadingVisible: isDialogLoadingVisible,
|
||||||
parseEmailByBlobIdInteractor:
|
|
||||||
downloadController.parseEmailByBlobIdInteractor,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void showDialogToPreviewEMLAttachment({
|
void showDialogToPreviewEMLAttachment({
|
||||||
@@ -51,24 +56,32 @@ extension HandlePreviewAttachmentExtension on MailboxDashBoardController {
|
|||||||
required EMLPreviewer emlPreviewer,
|
required EMLPreviewer emlPreviewer,
|
||||||
required ImagePaths imagePaths,
|
required ImagePaths imagePaths,
|
||||||
required OnMailtoDelegateAction onMailtoAction,
|
required OnMailtoDelegateAction onMailtoAction,
|
||||||
required OnDownloadAttachmentDelegateAction onDownloadAction,
|
required OnDownloadAttachmentFileAction onDownloadFileAction,
|
||||||
required OnPreviewEMLDelegateAction onPreviewAction,
|
|
||||||
}) =>
|
}) =>
|
||||||
downloadController.showDialogToPreviewEMLAttachment(
|
downloadController.showDialogToPreviewEMLAttachment(
|
||||||
context: context,
|
context: context,
|
||||||
emlPreviewer: emlPreviewer,
|
emlPreviewer: emlPreviewer,
|
||||||
imagePaths: imagePaths,
|
|
||||||
onMailtoAction: onMailtoAction,
|
onMailtoAction: onMailtoAction,
|
||||||
onDownloadAction: onDownloadAction,
|
onPreviewAction: (uri) => downloadController.openEMLPreviewer(
|
||||||
onPreviewAction: onPreviewAction,
|
appLocalizations: AppLocalizations.of(context),
|
||||||
|
uri: uri,
|
||||||
|
accountId: accountId.value,
|
||||||
|
session: sessionCurrent,
|
||||||
|
ownEmailAddress: ownEmailAddress.value,
|
||||||
|
),
|
||||||
|
onDownloadAction: (uri) async => downloadController.downloadAttachmentInEMLPreview(
|
||||||
|
uri: uri,
|
||||||
|
onDownloadAction: (attachment) => downloadAttachment(
|
||||||
|
attachment: attachment,
|
||||||
|
)
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> openMailToLink(Uri? uri) async {
|
void openComposerFromMailToLink(Uri uri) {
|
||||||
if (uri == null) return;
|
|
||||||
final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(
|
final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(
|
||||||
uri.toString(),
|
uri.toString(),
|
||||||
);
|
);
|
||||||
log('$runtimeType::openMailToLink(): ${uri.toString()}');
|
log('$runtimeType::openComposerFromMailToLink(): ${uri.toString()}');
|
||||||
if (!RouteUtils.canOpenComposerFromNavigationRouter(navigationRouter)) {
|
if (!RouteUtils.canOpenComposerFromNavigationRouter(navigationRouter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,6 +267,11 @@ class UploadController extends BaseController {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UploadFileState? getUploadFileId(UploadTaskId id) {
|
||||||
|
return listUploadAttachments
|
||||||
|
.firstWhereOrNull((fileState) => fileState.uploadTaskId == id);
|
||||||
|
}
|
||||||
|
|
||||||
Set<EmailBodyPart>? generateAttachments() {
|
Set<EmailBodyPart>? generateAttachments() {
|
||||||
if (attachmentsUploaded.isEmpty) {
|
if (attachmentsUploaded.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import 'package:tmail_ui_user/features/email/domain/exceptions/calendar_event_ex
|
|||||||
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reply_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reply_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart';
|
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/parse_email_by_blob_id_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/preview_email_from_eml_file_state.dart';
|
||||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
|
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
|
||||||
import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart';
|
import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart';
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ extension SessionExtension on Session {
|
|||||||
return downloadUrlDecode;
|
return downloadUrlDecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getSafetyDownloadUrl({String? jmapUrl}) {
|
||||||
|
try {
|
||||||
|
return getDownloadUrl(jmapUrl: jmapUrl);
|
||||||
|
} catch(_) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Uri getUploadUri(AccountId accountId, {String? jmapUrl}) {
|
Uri getUploadUri(AccountId accountId, {String? jmapUrl}) {
|
||||||
final Uri uploadUrlValid;
|
final Uri uploadUrlValid;
|
||||||
if (jmapUrl != null) {
|
if (jmapUrl != null) {
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import 'package:jmap_dart_client/jmap/core/id.dart';
|
|||||||
import 'package:mockito/annotations.dart';
|
import 'package:mockito/annotations.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:model/extensions/session_extension.dart';
|
import 'package:model/extensions/session_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
|
import 'package:tmail_ui_user/features/download/domain/state/parse_email_by_blob_id_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
|
import 'package:tmail_ui_user/features/download/domain/usecase/parse_email_by_blob_id_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart';
|
import 'package:tmail_ui_user/features/download/domain/repository/download_repository.dart';
|
||||||
|
|
||||||
import '../../../../fixtures/account_fixtures.dart';
|
import '../../../../fixtures/account_fixtures.dart';
|
||||||
import '../../../../fixtures/email_fixtures.dart';
|
import '../../../../fixtures/email_fixtures.dart';
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ import 'package:tmail_ui_user/features/email/domain/state/get_email_content_stat
|
|||||||
import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_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/calendar_event_accept_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reject_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reject_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart';
|
|
||||||
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_email_content_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_email_read_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
|
||||||
@@ -45,7 +43,7 @@ import 'package:tmail_ui_user/features/login/data/network/interceptors/authoriza
|
|||||||
import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart';
|
import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
|
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart';
|
import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
||||||
@@ -72,7 +70,6 @@ const fallbackGenerators = {
|
|||||||
@GenerateNiceMocks([
|
@GenerateNiceMocks([
|
||||||
MockSpec<GetEmailContentInteractor>(),
|
MockSpec<GetEmailContentInteractor>(),
|
||||||
MockSpec<MarkAsEmailReadInteractor>(),
|
MockSpec<MarkAsEmailReadInteractor>(),
|
||||||
MockSpec<ExportAttachmentInteractor>(),
|
|
||||||
MockSpec<MarkAsStarEmailInteractor>(),
|
MockSpec<MarkAsStarEmailInteractor>(),
|
||||||
MockSpec<GetAllIdentitiesInteractor>(),
|
MockSpec<GetAllIdentitiesInteractor>(),
|
||||||
MockSpec<StoreOpenedEmailInteractor>(),
|
MockSpec<StoreOpenedEmailInteractor>(),
|
||||||
@@ -100,7 +97,6 @@ const fallbackGenerators = {
|
|||||||
MockSpec<CalendarEventDataSource>(),
|
MockSpec<CalendarEventDataSource>(),
|
||||||
MockSpec<DioClient>(),
|
MockSpec<DioClient>(),
|
||||||
MockSpec<TwakeAppManager>(),
|
MockSpec<TwakeAppManager>(),
|
||||||
MockSpec<ExportAllAttachmentsInteractor>(),
|
|
||||||
MockSpec<FileUploader>(),
|
MockSpec<FileUploader>(),
|
||||||
])
|
])
|
||||||
void main() {
|
void main() {
|
||||||
@@ -108,7 +104,6 @@ void main() {
|
|||||||
|
|
||||||
final getEmailContentInteractor = MockGetEmailContentInteractor();
|
final getEmailContentInteractor = MockGetEmailContentInteractor();
|
||||||
final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor();
|
final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor();
|
||||||
final exportAttachmentInteractor = MockExportAttachmentInteractor();
|
|
||||||
final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor();
|
final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor();
|
||||||
final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor();
|
final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor();
|
||||||
final storeOpenedEmailInteractor = MockStoreOpenedEmailInteractor();
|
final storeOpenedEmailInteractor = MockStoreOpenedEmailInteractor();
|
||||||
@@ -132,8 +127,6 @@ void main() {
|
|||||||
final mockToastManager = MockToastManager();
|
final mockToastManager = MockToastManager();
|
||||||
final mockTwakeAppManager = MockTwakeAppManager();
|
final mockTwakeAppManager = MockTwakeAppManager();
|
||||||
|
|
||||||
final exportAllAttachmentsInteractor = MockExportAllAttachmentsInteractor();
|
|
||||||
|
|
||||||
late SingleEmailController singleEmailController;
|
late SingleEmailController singleEmailController;
|
||||||
|
|
||||||
final testAccountId = AccountId(Id('123'));
|
final testAccountId = AccountId(Id('123'));
|
||||||
@@ -178,12 +171,10 @@ void main() {
|
|||||||
singleEmailController = SingleEmailController(
|
singleEmailController = SingleEmailController(
|
||||||
getEmailContentInteractor,
|
getEmailContentInteractor,
|
||||||
markAsEmailReadInteractor,
|
markAsEmailReadInteractor,
|
||||||
exportAttachmentInteractor,
|
|
||||||
markAsStarEmailInteractor,
|
markAsStarEmailInteractor,
|
||||||
getAllIdentitiesInteractor,
|
getAllIdentitiesInteractor,
|
||||||
storeOpenedEmailInteractor,
|
storeOpenedEmailInteractor,
|
||||||
printEmailInteractor,
|
printEmailInteractor,
|
||||||
exportAllAttachmentsInteractor,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_e
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
||||||
|
|||||||
+1
-1
@@ -68,7 +68,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_re
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_re
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
|
import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user