TF-2989 Fix drag and drop text within composer is broken

This commit is contained in:
dab246
2024-07-12 17:46:58 +07:00
committed by Dat H. Pham
parent 01561e3167
commit 34cbb155bd
4 changed files with 162 additions and 133 deletions
@@ -385,22 +385,42 @@ class ComposerController extends BaseController with DragDropFileMixin implement
});
_subscriptionOnDragEnter = html.window.onDragEnter.listen((event) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.active;
event.preventDefault();
if (_validateFilesTransfer(event.dataTransfer.types)) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.active;
}
});
_subscriptionOnDragOver = html.window.onDragOver.listen((event) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.active;
event.preventDefault();
if (_validateFilesTransfer(event.dataTransfer.types)) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.active;
}
});
_subscriptionOnDragLeave = html.window.onDragLeave.listen((event) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.inActive;
event.preventDefault();
if (_validateFilesTransfer(event.dataTransfer.types)) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.inActive;
}
});
_subscriptionOnDrop = html.window.onDrop.listen((event) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.inActive;
event.preventDefault();
if (_validateFilesTransfer(event.dataTransfer.types)) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.inActive;
}
});
}
bool _validateFilesTransfer(List<dynamic>? types) {
return types?.any((type) => type == 'Files') ?? false;
}
Future<void> _saveComposerCacheOnWebAction() async {
_autoCreateEmailTag();
@@ -2091,8 +2111,10 @@ class ComposerController extends BaseController with DragDropFileMixin implement
}
}
void handleOnDragEnterHtmlEditorWeb() {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.active;
void handleOnDragEnterHtmlEditorWeb(List<dynamic>? types) {
if (_validateFilesTransfer(types)) {
mailboxDashBoardController.localFileDraggableAppState.value = DraggableAppState.active;
}
}
void onLocalFileDropZoneListener({
@@ -653,133 +653,139 @@ class ComposerView extends GetWidget<ComposerController> {
),
Expanded(
child: LayoutBuilder(
builder: (context, constraintsEditor) {
return Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ComposerStyle.borderColor,
width: 1
)
),
color: ComposerStyle.backgroundEditorColor
),
child: Stack(
children: [
Column(
children: [
Expanded(
child: Padding(
padding: ComposerStyle.tabletEditorPadding,
child: Obx(() => WebEditorView(
editorController: controller.richTextWebController!.editorController,
arguments: controller.composerArguments.value,
contentViewState: controller.emailContentsViewState.value,
currentWebContent: controller.textEditorWeb,
onInitial: controller.handleInitHtmlEditorWeb,
onChangeContent: controller.onChangeTextEditorWeb,
onFocus: controller.handleOnFocusHtmlEditorWeb,
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
onEditorSettings: controller.richTextWebController!.onEditorSettingsChange,
onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged,
width: constraints.maxWidth,
height: constraints.maxHeight,
onDragEnter: controller.handleOnDragEnterHtmlEditorWeb,
)),
builder: (context, constraintsBody) {
return Stack(
children: [
Column(
children: [
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ComposerStyle.borderColor,
width: 1
)
),
color: ComposerStyle.backgroundEditorColor
),
child: Column(
children: [
Expanded(
child: Padding(
padding: ComposerStyle.tabletEditorPadding,
child: Obx(() => WebEditorView(
editorController: controller.richTextWebController!.editorController,
arguments: controller.composerArguments.value,
contentViewState: controller.emailContentsViewState.value,
currentWebContent: controller.textEditorWeb,
onInitial: controller.handleInitHtmlEditorWeb,
onChangeContent: controller.onChangeTextEditorWeb,
onFocus: controller.handleOnFocusHtmlEditorWeb,
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
onEditorSettings: controller.richTextWebController!.onEditorSettingsChange,
onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged,
width: constraints.maxWidth,
height: constraints.maxHeight,
onDragEnter: controller.handleOnDragEnterHtmlEditorWeb,
)),
),
),
Obx(() {
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(() {
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
return ToolbarRichTextWebBuilder(
richTextWebController: controller.richTextWebController!,
padding: ComposerStyle.richToolbarPadding,
decoration: const BoxDecoration(
color: ComposerStyle.richToolbarColor,
boxShadow: ComposerStyle.richToolbarShadow
),
);
} else {
return const SizedBox.shrink();
}
})
],
),
),
Obx(() {
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(() {
if (controller.richTextWebController!.isFormattingOptionsEnabled) {
return ToolbarRichTextWebBuilder(
richTextWebController: controller.richTextWebController!,
padding: ComposerStyle.richToolbarPadding,
decoration: const BoxDecoration(
color: ComposerStyle.richToolbarColor,
boxShadow: ComposerStyle.richToolbarShadow
),
);
} else {
return const SizedBox.shrink();
}
})
],
),
Align(
alignment: AlignmentDirectional.topCenter,
child: Obx(() => InsertImageLoadingBarWidget(
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
viewState: controller.viewState.value,
padding: ComposerStyle.insertImageLoadingBarPadding,
),
Obx(() => BottomBarComposerWidget(
isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled,
isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled,
hasReadReceipt: controller.hasRequestReadReceipt.value,
openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
showCodeViewAction: controller.richTextWebController!.toggleCodeView,
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
sendMessageAction: () => controller.handleClickSendButton(context),
requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context),
)),
),
Obx(() {
if (controller.mailboxDashBoardController.isAttachmentDraggableAppActive) {
return Positioned.fill(
child: PointerInterceptor(
child: AttachmentDropZoneWidget(
imagePaths: controller.imagePaths,
width: constraintsEditor.maxWidth,
height: constraintsEditor.maxHeight,
onAttachmentDropZoneListener: controller.onAttachmentDropZoneListener,
)
),
);
} else {
return const SizedBox.shrink();
}
}),
Obx(() {
if (controller.mailboxDashBoardController.isLocalFileDraggableAppActive) {
return Positioned.fill(
child: PointerInterceptor(
child: LocalFileDropZoneWidget(
imagePaths: controller.imagePaths,
width: constraintsEditor.maxWidth,
height: constraintsEditor.maxHeight,
onLocalFileDropZoneListener: (details) =>
controller.onLocalFileDropZoneListener(
context: context,
details: details,
maxWidth: constraintsEditor.maxWidth,
),
)
),
);
} else {
return const SizedBox.shrink();
}
}),
],
),
],
),
Align(
alignment: AlignmentDirectional.topCenter,
child: Obx(() => InsertImageLoadingBarWidget(
uploadInlineViewState: controller.uploadController.uploadInlineViewState.value,
viewState: controller.viewState.value,
padding: ComposerStyle.insertImageLoadingBarPadding,
)),
),
Obx(() {
if (controller.mailboxDashBoardController.isAttachmentDraggableAppActive) {
return Positioned.fill(
child: PointerInterceptor(
child: AttachmentDropZoneWidget(
imagePaths: controller.imagePaths,
width: constraintsBody.maxWidth,
height: constraintsBody.maxHeight,
onAttachmentDropZoneListener: controller.onAttachmentDropZoneListener,
)
),
);
} else {
return const SizedBox.shrink();
}
}),
Obx(() {
if (controller.mailboxDashBoardController.isLocalFileDraggableAppActive) {
return Positioned.fill(
child: PointerInterceptor(
child: LocalFileDropZoneWidget(
imagePaths: controller.imagePaths,
width: constraintsBody.maxWidth,
height: constraintsBody.maxHeight,
onLocalFileDropZoneListener: (details) =>
controller.onLocalFileDropZoneListener(
context: context,
details: details,
maxWidth: constraintsBody.maxWidth,
),
)
),
);
} else {
return const SizedBox.shrink();
}
}),
],
);
}
},
),
),
Obx(() => BottomBarComposerWidget(
isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled,
isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled,
hasReadReceipt: controller.hasRequestReadReceipt.value,
openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
showCodeViewAction: controller.richTextWebController!.toggleCodeView,
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
sendMessageAction: () => controller.handleClickSendButton(context),
requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context),
)),
)
]),
);
},
@@ -14,6 +14,8 @@ import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_c
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
typedef OnDragEnterListener = Function(List<dynamic>? types);
class WebEditorView extends StatelessWidget with EditorViewMixin {
final HtmlEditorController editorController;
@@ -29,7 +31,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
final OnEditorTextSizeChanged? onEditorTextSizeChanged;
final double? width;
final double? height;
final VoidCallback? onDragEnter;
final OnDragEnterListener? onDragEnter;
const WebEditorView({
super.key,
@@ -5,6 +5,7 @@ import 'package:core/utils/app_logger.dart';
import 'package:core/utils/html/html_utils.dart';
import 'package:flutter/material.dart';
import 'package:html_editor_enhanced/html_editor.dart';
import 'package:tmail_ui_user/features/composer/presentation/view/web/web_editor_view.dart';
import 'package:universal_html/html.dart' hide VoidCallback;
typedef OnChangeContentEditorAction = Function(String? text);
@@ -27,7 +28,7 @@ class WebEditorWidget extends StatefulWidget {
final OnEditorTextSizeChanged? onEditorTextSizeChanged;
final double? width;
final double? height;
final VoidCallback? onDragEnter;
final OnDragEnterListener? onDragEnter;
const WebEditorWidget({
super.key,
@@ -63,8 +64,6 @@ class _WebEditorState extends State<WebEditorWidget> {
bool _dropListenerRegistered = false;
Function(Event)? _dropListener;
@override
void initState() {
super.initState();
@@ -175,7 +174,7 @@ class _WebEditorState extends State<WebEditorWidget> {
HtmlUtils.lineHeight100Percent.name
),
onDragEnter: widget.onDragEnter,
onDragLeave: () {},
onDragLeave: (_) {},
),
);
}