TF-2644 Handle total size exceeded maximum size when drag & drop multiple file to composer

This commit is contained in:
dab246
2024-03-01 17:09:09 +07:00
committed by Dat H. Pham
parent d646a5b9e4
commit 145a49d728
54 changed files with 1140 additions and 800 deletions
@@ -3,42 +3,35 @@ import 'package:core/presentation/resources/image_paths.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/email/attachment.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/web/drop_zone_widget_style.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnAddAttachmentFromDropZone = Function(Attachment attachment);
typedef OnAttachmentDropZoneListener = Function(Attachment attachment);
class DropZoneWidget extends StatefulWidget {
class AttachmentDropZoneWidget extends StatelessWidget {
final ImagePaths imagePaths;
final double? width;
final double? height;
final OnAddAttachmentFromDropZone? addAttachmentFromDropZone;
final OnAttachmentDropZoneListener? onAttachmentDropZoneListener;
const DropZoneWidget({
const AttachmentDropZoneWidget({
super.key,
required this.imagePaths,
this.width,
this.height,
this.addAttachmentFromDropZone
this.onAttachmentDropZoneListener
});
@override
State<DropZoneWidget> createState() => _DropZoneWidgetState();
}
class _DropZoneWidgetState extends State<DropZoneWidget> {
final _imagePaths = Get.find<ImagePaths>();
bool _isDragging = false;
@override
Widget build(BuildContext context) {
return DragTarget<Attachment>(
builder: (context, candidateData, rejectedData) {
if (_isDragging) {
return Padding(
builder: (context, _, __) {
return SizedBox(
width: width,
height: height,
child: Padding(
padding: DropZoneWidgetStyle.margin,
child: DottedBorder(
borderType: BorderType.RRect,
@@ -48,20 +41,18 @@ class _DropZoneWidgetState extends State<DropZoneWidget> {
dashPattern: DropZoneWidgetStyle.dashSize,
child: Container(
clipBehavior: Clip.antiAlias,
decoration: const ShapeDecoration(
decoration: ShapeDecoration(
color: DropZoneWidgetStyle.backgroundColor,
shape: RoundedRectangleBorder(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(DropZoneWidgetStyle.radius)),
),
),
width: widget.width,
height: widget.height,
padding: DropZoneWidgetStyle.padding,
alignment: AlignmentDirectional.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(_imagePaths.icDropZoneIcon),
SvgPicture.asset(imagePaths.icDropZoneIcon),
const SizedBox(height: DropZoneWidgetStyle.space),
Text(
AppLocalizations.of(context).dropFileHereToAttachThem,
@@ -71,22 +62,10 @@ class _DropZoneWidgetState extends State<DropZoneWidget> {
),
),
),
);
} else {
return SizedBox(width: widget.width, height: widget.height);
}
},
onAccept: widget.addAttachmentFromDropZone,
onLeave: (attachment) {
if (_isDragging) {
setState(() => _isDragging = false);
}
},
onMove: (details) {
if (!_isDragging) {
setState(() => _isDragging = true);
}
),
);
},
onAccept: onAttachmentDropZoneListener
);
}
}
@@ -42,6 +42,7 @@ class BottomBarComposerWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
padding: BottomBarComposerWidgetStyle.padding,
height: BottomBarComposerWidgetStyle.height,
color: BottomBarComposerWidgetStyle.backgroundColor,
child: Row(
children: [
@@ -0,0 +1,69 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/web/drop_zone_widget_style.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:desktop_drop/desktop_drop.dart';
typedef OnLocalFileDropZoneListener = Function(DropDoneDetails details);
class LocalFileDropZoneWidget extends StatelessWidget {
final ImagePaths imagePaths;
final double? width;
final double? height;
final OnLocalFileDropZoneListener? onLocalFileDropZoneListener;
const LocalFileDropZoneWidget({
super.key,
required this.imagePaths,
this.width,
this.height,
this.onLocalFileDropZoneListener
});
@override
Widget build(BuildContext context) {
return DropTarget(
onDragDone: onLocalFileDropZoneListener,
child: SizedBox(
width: width,
height: height,
child: Padding(
padding: DropZoneWidgetStyle.margin,
child: DottedBorder(
borderType: BorderType.RRect,
radius: const Radius.circular(DropZoneWidgetStyle.radius),
color: DropZoneWidgetStyle.borderColor,
strokeWidth: DropZoneWidgetStyle.borderWidth,
dashPattern: DropZoneWidgetStyle.dashSize,
child: Container(
clipBehavior: Clip.antiAlias,
decoration: ShapeDecoration(
color: DropZoneWidgetStyle.backgroundColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(DropZoneWidgetStyle.radius)),
),
),
padding: DropZoneWidgetStyle.padding,
alignment: AlignmentDirectional.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(imagePaths.icDropZoneIcon),
const SizedBox(height: DropZoneWidgetStyle.space),
Text(
AppLocalizations.of(context).dropFileHereToAttachThem,
style: DropZoneWidgetStyle.labelTextStyle,
)
]
),
),
),
),
),
);
}
}
@@ -11,8 +11,6 @@ typedef OnChangeContentEditorAction = Function(String? text);
typedef OnInitialContentEditorAction = Function(String text);
typedef OnMouseDownEditorAction = Function(BuildContext context);
typedef OnEditorSettingsChange = Function(EditorSettings settings);
typedef OnImageUploadSuccessAction = Function(FileUpload fileUpload);
typedef OnImageUploadFailureAction = Function(FileUpload? fileUpload, String? base64Str, UploadError error);
typedef OnEditorTextSizeChanged = Function(int? size);
class WebEditorWidget extends StatefulWidget {
@@ -26,11 +24,10 @@ class WebEditorWidget extends StatefulWidget {
final VoidCallback? onUnFocus;
final OnMouseDownEditorAction? onMouseDown;
final OnEditorSettingsChange? onEditorSettings;
final OnImageUploadSuccessAction? onImageUploadSuccessAction;
final OnImageUploadFailureAction? onImageUploadFailureAction;
final OnEditorTextSizeChanged? onEditorTextSizeChanged;
final double? width;
final double? height;
final VoidCallback? onDragEnter;
const WebEditorWidget({
super.key,
@@ -43,11 +40,10 @@ class WebEditorWidget extends StatefulWidget {
this.onUnFocus,
this.onMouseDown,
this.onEditorSettings,
this.onImageUploadSuccessAction,
this.onImageUploadFailureAction,
this.onEditorTextSizeChanged,
this.width,
this.height,
this.onDragEnter,
});
@override
@@ -133,6 +129,7 @@ class _WebEditorState extends State<WebEditorWidget> {
initialText: widget.content,
customBodyCssStyle: HtmlUtils.customCssStyleHtmlEditor(direction: widget.direction),
spellCheck: true,
disableDragAndDrop: true,
webInitialScripts: UnmodifiableListView([
WebScript(
name: HtmlUtils.lineHeight100Percent.name,
@@ -145,7 +142,7 @@ class _WebEditorState extends State<WebEditorWidget> {
WebScript(
name: HtmlUtils.unregisterDropListener.name,
script: HtmlUtils.unregisterDropListener.script,
),
)
])
),
htmlToolbarOptions: const HtmlToolbarOptions(
@@ -154,8 +151,8 @@ class _WebEditorState extends State<WebEditorWidget> {
),
otherOptions: OtherOptions(
height: height,
dropZoneWidth: dropZoneWidth,
dropZoneHeight: dropZoneHeight,
// dropZoneWidth: dropZoneWidth,
// dropZoneHeight: dropZoneHeight,
),
callbacks: Callbacks(
onBeforeCommand: widget.onChangeContent,
@@ -173,12 +170,12 @@ class _WebEditorState extends State<WebEditorWidget> {
onMouseDown: () => widget.onMouseDown?.call(context),
onChangeSelection: widget.onEditorSettings,
onChangeCodeview: widget.onChangeContent,
onImageUpload: widget.onImageUploadSuccessAction,
onImageUploadError: widget.onImageUploadFailureAction,
onTextFontSizeChanged: widget.onEditorTextSizeChanged,
onPaste: () => _editorController.evaluateJavascriptWeb(
HtmlUtils.lineHeight100Percent.name
),
onDragEnter: widget.onDragEnter,
onDragLeave: () {},
),
);
}