diff --git a/lib/features/email/presentation/styles/attachment/attachment_item_widget_style.dart b/lib/features/email/presentation/styles/attachment/attachment_item_widget_style.dart new file mode 100644 index 000000000..9410d7d4f --- /dev/null +++ b/lib/features/email/presentation/styles/attachment/attachment_item_widget_style.dart @@ -0,0 +1,35 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; + +class AttachmentItemWidgetStyle { + static const double radius = 10; + static const double mobileWidth = 224; + static const double width = 250; + static const double height = 60; + static const double iconSize = 44; + static const double space = 8; + static const double downloadIconSize = 24; + + static const EdgeInsetsGeometry padding = EdgeInsetsDirectional.only(end: 12); + static const EdgeInsetsGeometry contentPadding = EdgeInsetsDirectional.all(8); + + static const Color borderColor = AppColor.attachmentFileBorderColor; + static const Color downloadIconColor = AppColor.primaryColor; + + static const TextStyle labelTextStyle = TextStyle( + fontSize: 14, + color: AppColor.attachmentFileNameColor, + fontWeight: FontWeight.normal + ); + static const TextStyle dotsLabelTextStyle = TextStyle( + fontSize: 12, + color: AppColor.attachmentFileNameColor, + fontWeight: FontWeight.normal + ); + static const TextStyle sizeLabelTextStyle = TextStyle( + fontSize: 12, + color: AppColor.attachmentFileSizeColor, + fontWeight: FontWeight.normal + ); +} \ No newline at end of file diff --git a/lib/features/email/presentation/styles/attachment/feedback_draggable_attachment_item_widget_style.dart b/lib/features/email/presentation/styles/attachment/feedback_draggable_attachment_item_widget_style.dart new file mode 100644 index 000000000..0bc6944ed --- /dev/null +++ b/lib/features/email/presentation/styles/attachment/feedback_draggable_attachment_item_widget_style.dart @@ -0,0 +1,38 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; + +class FeedbackDraggableAttachmentItemWidgetStyle { + static const double radius = 8; + static const double iconSize = 24; + static const double space = 12; + static const double maxWidth = 300; + + static const Color backgroundColor = Colors.white; + + static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(horizontal: 16, vertical: 12); + + static const TextStyle labelTextStyle = TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w500 + ); + static const TextStyle dotsLabelTextStyle = TextStyle( + fontSize: 12, + color: Colors.black, + fontWeight: FontWeight.w500 + ); + + static const List shadows = [ + BoxShadow( + color: AppColor.colorShadowLayerBottom, + blurRadius: 96, + offset: Offset.zero + ), + BoxShadow( + color: AppColor.colorShadowLayerTop, + blurRadius: 2, + offset: Offset.zero + ), + ]; +} \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/attachment_file_tile_builder.dart b/lib/features/email/presentation/widgets/attachment_item_widget.dart similarity index 53% rename from lib/features/email/presentation/widgets/attachment_file_tile_builder.dart rename to lib/features/email/presentation/widgets/attachment_item_widget.dart index a20125a3a..8150eb238 100644 --- a/lib/features/email/presentation/widgets/attachment_file_tile_builder.dart +++ b/lib/features/email/presentation/widgets/attachment_item_widget.dart @@ -10,56 +10,61 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:model/email/attachment.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/styles/attachment/attachment_item_widget_style.dart'; typedef OnDownloadAttachmentFileActionClick = void Function(Attachment attachment); -typedef OnExpandAttachmentActionClick = void Function(); -class AttachmentFileTileBuilder extends StatelessWidget{ +class AttachmentItemWidget extends StatelessWidget { - final Attachment _attachment; - final OnDownloadAttachmentFileActionClick? onDownloadAttachmentFileActionClick; + final Attachment attachment; + final OnDownloadAttachmentFileActionClick? downloadAttachmentAction; - const AttachmentFileTileBuilder( - this._attachment, { + final _imagePaths = Get.find(); + final _responsiveUtils = Get.find(); + + AttachmentItemWidget({ Key? key, - this.onDownloadAttachmentFileActionClick, + required this.attachment, + this.downloadAttachmentAction, }) : super(key: key); @override Widget build(BuildContext context) { - final imagePaths = Get.find(); - final responsiveUtils = Get.find(); - return Padding( - padding: const EdgeInsetsDirectional.only(end: 12), + padding: AttachmentItemWidgetStyle.padding, child: Material( color: Colors.transparent, child: InkWell( - onTap: () => onDownloadAttachmentFileActionClick?.call(_attachment), - customBorder: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + onTap: () => downloadAttachmentAction?.call(attachment), + customBorder: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(AttachmentItemWidgetStyle.radius)) + ), child: Container( - padding: const EdgeInsets.all(8), + padding: AttachmentItemWidgetStyle.contentPadding, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all(color: AppColor.attachmentFileBorderColor), - color: Colors.transparent), - width: responsiveUtils.isMobile(context) ? 224 : 250, - height: 60, + borderRadius: const BorderRadius.all(Radius.circular(AttachmentItemWidgetStyle.radius)), + border: Border.all(color: AttachmentItemWidgetStyle.borderColor), + ), + width: _responsiveUtils.isMobile(context) + ? AttachmentItemWidgetStyle.mobileWidth + : AttachmentItemWidgetStyle.width, + height: AttachmentItemWidgetStyle.height, child: Stack( children: [ Positioned.fill( child: Row(children: [ SvgPicture.asset( - _attachment.getIcon(imagePaths), - width: 44, - height: 44, - fit: BoxFit.fill), - const SizedBox(width: 8), + attachment.getIcon(_imagePaths), + width: AttachmentItemWidgetStyle.iconSize, + height: AttachmentItemWidgetStyle.iconSize, + fit: BoxFit.fill + ), + const SizedBox(width: AttachmentItemWidgetStyle.space), Expanded(child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ExtendedText( - (_attachment.name ?? ''), + (attachment.name ?? ''), maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, softWrap: CommonTextStyle.defaultSoftWrap, @@ -69,29 +74,18 @@ class AttachmentFileTileBuilder extends StatelessWidget{ : TextOverflowPosition.end, child: const Text( "...", - style: TextStyle( - fontSize: 12, - color: AppColor.attachmentFileNameColor, - fontWeight: FontWeight.normal - ), + style: AttachmentItemWidgetStyle.dotsLabelTextStyle, ), ), - style: const TextStyle( - fontSize: 14, - color: AppColor.attachmentFileNameColor, - fontWeight: FontWeight.normal - ), + style: AttachmentItemWidgetStyle.labelTextStyle, ), const SizedBox(height: 4), Text( - filesize(_attachment.size?.value), + filesize(attachment.size?.value), maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, softWrap: CommonTextStyle.defaultSoftWrap, - style: const TextStyle( - fontSize: 12, - color: AppColor.attachmentFileSizeColor, - fontWeight: FontWeight.normal), + style: AttachmentItemWidgetStyle.sizeLabelTextStyle, ) ] )) @@ -104,12 +98,13 @@ class AttachmentFileTileBuilder extends StatelessWidget{ child: InkWell( customBorder: const CircleBorder(), child: SvgPicture.asset( - imagePaths.icDownloadAttachment, - width: 24, - height: 24, - colorFilter: AppColor.primaryColor.asFilter(), - fit: BoxFit.fill), - onTap: () => onDownloadAttachmentFileActionClick?.call(_attachment) + _imagePaths.icDownloadAttachment, + width: AttachmentItemWidgetStyle.downloadIconSize, + height: AttachmentItemWidgetStyle.downloadIconSize, + colorFilter: AttachmentItemWidgetStyle.downloadIconColor.asFilter(), + fit: BoxFit.fill + ), + onTap: () => downloadAttachmentAction?.call(attachment) ), ), ), diff --git a/lib/features/email/presentation/widgets/draggable_attachment_item_widget.dart b/lib/features/email/presentation/widgets/draggable_attachment_item_widget.dart new file mode 100644 index 000000000..745392dff --- /dev/null +++ b/lib/features/email/presentation/widgets/draggable_attachment_item_widget.dart @@ -0,0 +1,38 @@ + +import 'package:flutter/material.dart'; +import 'package:model/email/attachment.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_item_widget.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/feedback_draggable_attachment_item_widget.dart'; + +typedef OnDragAttachmentStarted = Function(); +typedef OnDragAttachmentEnd = Function(DraggableDetails details); + +class DraggableAttachmentItemWidget extends StatelessWidget{ + + final Attachment attachment; + final OnDragAttachmentStarted? onDragStarted; + final OnDragAttachmentEnd? onDragEnd; + final OnDownloadAttachmentFileActionClick? downloadAttachmentAction; + + const DraggableAttachmentItemWidget({ + Key? key, + required this.attachment, + this.onDragStarted, + this.onDragEnd, + this.downloadAttachmentAction, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Draggable( + data: attachment, + feedback: FeedbackDraggableAttachmentItemWidget(attachment: attachment), + onDragStarted: onDragStarted, + onDragEnd: onDragEnd, + child: AttachmentItemWidget( + attachment: attachment, + downloadAttachmentAction: downloadAttachmentAction + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/email_attachments_widget.dart b/lib/features/email/presentation/widgets/email_attachments_widget.dart index 9f64efc3c..d979593d1 100644 --- a/lib/features/email/presentation/widgets/email_attachments_widget.dart +++ b/lib/features/email/presentation/widgets/email_attachments_widget.dart @@ -1,6 +1,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -9,20 +10,23 @@ import 'package:model/email/attachment.dart'; import 'package:model/extensions/list_attachment_extension.dart'; import 'package:tmail_ui_user/features/base/widget/custom_scroll_behavior.dart'; import 'package:tmail_ui_user/features/email/presentation/styles/email_attachments_styles.dart'; -import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_file_tile_builder.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_item_widget.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/draggable_attachment_item_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -typedef OnDownloadAttachmentActionCallback = Function(BuildContext context, Attachment attachment); - class EmailAttachmentsWidget extends StatefulWidget { final List attachments; - final OnDownloadAttachmentActionCallback? onDownloadAttachmentActionCallback; + final OnDragAttachmentStarted? onDragStarted; + final OnDragAttachmentEnd? onDragEnd; + final OnDownloadAttachmentFileActionClick? downloadAttachmentAction; const EmailAttachmentsWidget({ super.key, required this.attachments, - this.onDownloadAttachmentActionCallback + this.onDragStarted, + this.onDragEnd, + this.downloadAttachmentAction }); @override @@ -95,10 +99,21 @@ class _EmailAttachmentsWidgetState extends State { Wrap( runSpacing: EmailAttachmentsStyles.listSpace, children: widget.attachments - .map((attachment) => AttachmentFileTileBuilder( - attachment, - onDownloadAttachmentFileActionClick: (attachment) => widget.onDownloadAttachmentActionCallback?.call(context, attachment) - )) + .map((attachment) { + if (PlatformInfo.isWeb) { + return DraggableAttachmentItemWidget( + attachment: attachment, + onDragStarted: widget.onDragStarted, + onDragEnd: widget.onDragEnd, + downloadAttachmentAction: widget.downloadAttachmentAction, + ); + } else { + return AttachmentItemWidget( + attachment: attachment, + downloadAttachmentAction: widget.downloadAttachmentAction + ); + } + }) .toList() ) else @@ -111,10 +126,19 @@ class _EmailAttachmentsWidgetState extends State { scrollDirection: Axis.horizontal, itemCount: widget.attachments.length, itemBuilder: (context, index) { - return AttachmentFileTileBuilder( - widget.attachments[index], - onDownloadAttachmentFileActionClick: (attachment) => widget.onDownloadAttachmentActionCallback?.call(context, attachment) - ); + if (PlatformInfo.isWeb) { + return DraggableAttachmentItemWidget( + attachment: widget.attachments[index], + onDragStarted: widget.onDragStarted, + onDragEnd: widget.onDragEnd, + downloadAttachmentAction: widget.downloadAttachmentAction + ); + } else { + return AttachmentItemWidget( + attachment: widget.attachments[index], + downloadAttachmentAction: widget.downloadAttachmentAction + ); + } } ), ) diff --git a/lib/features/email/presentation/widgets/feedback_draggable_attachment_item_widget.dart b/lib/features/email/presentation/widgets/feedback_draggable_attachment_item_widget.dart new file mode 100644 index 000000000..08a04a43a --- /dev/null +++ b/lib/features/email/presentation/widgets/feedback_draggable_attachment_item_widget.dart @@ -0,0 +1,65 @@ +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:extended_text/extended_text.dart'; +import 'package:flutter/material.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/email/presentation/extensions/attachment_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/styles/attachment/feedback_draggable_attachment_item_widget_style.dart'; + +class FeedbackDraggableAttachmentItemWidget extends StatelessWidget { + + final Attachment attachment; + + final _imagePaths = Get.find(); + + FeedbackDraggableAttachmentItemWidget({ + super.key, + required this.attachment + }); + + @override + Widget build(BuildContext context) { + return Container( + decoration: const ShapeDecoration( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(FeedbackDraggableAttachmentItemWidgetStyle.radius)), + ), + color: FeedbackDraggableAttachmentItemWidgetStyle.backgroundColor, + shadows: FeedbackDraggableAttachmentItemWidgetStyle.shadows + ), + constraints: const BoxConstraints( + maxWidth: FeedbackDraggableAttachmentItemWidgetStyle.maxWidth + ), + padding: FeedbackDraggableAttachmentItemWidgetStyle.padding, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset( + attachment.getIcon(_imagePaths), + width: FeedbackDraggableAttachmentItemWidgetStyle.iconSize, + height: FeedbackDraggableAttachmentItemWidgetStyle.iconSize, + fit: BoxFit.fill + ), + const SizedBox(width: FeedbackDraggableAttachmentItemWidgetStyle.space), + Flexible( + child: DefaultTextStyle( + style: FeedbackDraggableAttachmentItemWidgetStyle.labelTextStyle, + child: ExtendedText( + attachment.name ?? '', + maxLines: 1, + overflowWidget: const TextOverflowWidget( + position: TextOverflowPosition.middle, + child: Text( + '...', + style: FeedbackDraggableAttachmentItemWidgetStyle.dotsLabelTextStyle, + ), + ), + ), + ), + ) + ], + ), + ); + } +} \ No newline at end of file