diff --git a/assets/images/ic_download_attachment.svg b/assets/images/ic_download_attachment.svg
new file mode 100644
index 000000000..91b55b9d6
--- /dev/null
+++ b/assets/images/ic_download_attachment.svg
@@ -0,0 +1,5 @@
+
diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart
index 230e9a979..b6c3a3fb4 100644
--- a/core/lib/presentation/extensions/color_extension.dart
+++ b/core/lib/presentation/extensions/color_extension.dart
@@ -46,9 +46,9 @@ extension AppColor on Color {
static const bgMailboxListMail = Color(0xFFFBFBFF);
static const bgMessenger = Color(0xFFF2F2F5);
static const textButtonColor = Color(0xFF182952);
- static const attachmentFileBorderColor = Color(0xFFEAEAEA);
- static const attachmentFileNameColor = Color(0xFF182952);
- static const attachmentFileSizeColor = Color(0xFF7E869B);
+ static const attachmentFileBorderColor = Color(0x1F000000);
+ static const attachmentFileNameColor = Color(0xFF000000);
+ static const attachmentFileSizeColor = Color(0xFF818C99);
static const avatarColor = Color(0xFFF8F8F8);
static const avatarTextColor = Color(0xFF3840F7);
static const sentTimeTextColorUnRead = Color(0xFF182952);
@@ -152,6 +152,8 @@ extension AppColor on Color {
static const colorShadowLayerTop = Color(0x1F000000);
static const colorDividerHorizontal = Color(0x1F000000);
static const colorEmailAddressFull = Color(0xFF818C99);
+ static const colorTitleHeaderAttachment = Color(0xFF818C99);
+ static const colorAttachmentIcon = Color(0xFFAEB7C2);
static const mapGradientColor = [
[Color(0xFF21D4FD), Color(0xFFB721FF)],
diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart
index c6b586381..bb2adf646 100644
--- a/core/lib/presentation/resources/image_paths.dart
+++ b/core/lib/presentation/resources/image_paths.dart
@@ -162,6 +162,7 @@ class ImagePaths {
String get icAddEmailForward => _getImagePath('ic_add_email_forwards.svg');
String get icChevronDownOutline => _getImagePath('ic_chevron_down_outline.svg');
String get icUndo => _getImagePath('ic_undo.svg');
+ String get icDownloadAttachment => _getImagePath('ic_download_attachment.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart
index 6502a0108..30563db71 100644
--- a/lib/features/composer/presentation/composer_view.dart
+++ b/lib/features/composer/presentation/composer_view.dart
@@ -708,7 +708,7 @@ class ComposerView extends GetWidget
child: Text(
expandModeAttachment == ExpandMode.EXPAND
? AppLocalizations.of(context).hide
- : '${AppLocalizations.of(context).show_all} (${uploadFilesState.length})',
+ : '${AppLocalizations.of(context).showAll} (${uploadFilesState.length})',
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: AppColor.colorTextButton)),
onPressed: () => controller.toggleDisplayAttachments()
)
diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart
index 3cc3ef723..8145721fc 100644
--- a/lib/features/composer/presentation/composer_view_web.dart
+++ b/lib/features/composer/presentation/composer_view_web.dart
@@ -704,7 +704,7 @@ class ComposerView extends GetWidget
child: Text(
expandModeAttachment == ExpandMode.EXPAND
? AppLocalizations.of(context).hide
- : '${AppLocalizations.of(context).show_all} (${uploadFilesState.length})',
+ : '${AppLocalizations.of(context).showAll} (${uploadFilesState.length})',
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: AppColor.colorTextButton)),
onPressed: () => controller.toggleDisplayAttachments()
)
diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart
index a5697439b..1f40e3227 100644
--- a/lib/features/email/presentation/email_controller.dart
+++ b/lib/features/email/presentation/email_controller.dart
@@ -84,6 +84,8 @@ class EmailController extends BaseController with AppLoaderMixin {
bool get isDisplayFullEmailAddress => emailAddressExpandMode.value == ExpandMode.EXPAND;
+ bool get isDisplayFullAttachments => attachmentsExpandMode.value == ExpandMode.EXPAND;
+
EmailController(
this._getEmailContentInteractor,
this._markAsEmailReadInteractor,
diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart
index 6c42eb236..d91398aeb 100644
--- a/lib/features/email/presentation/email_view.dart
+++ b/lib/features/email/presentation/email_view.dart
@@ -1,7 +1,6 @@
import 'package:core/core.dart';
import 'package:filesize/filesize.dart';
import 'package:flutter/cupertino.dart';
-import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
@@ -579,115 +578,112 @@ class EmailView extends GetWidget with NetworkConnectionMixin {
});
}
- int _getAttachmentLimitDisplayed(BuildContext context) {
- if (responsiveUtils.isMobile(context)
- || responsiveUtils.isLandscapeMobile(context)) {
- return 2;
- } else if (responsiveUtils.isTablet(context) ||
- responsiveUtils.isLandscapeTablet(context)) {
- return 3;
- } else {
- return 4;
- }
- }
-
Widget _buildAttachmentsBody(BuildContext context, List attachments) {
- final attachmentLimitDisplayed = _getAttachmentLimitDisplayed(context);
- final countAttachments = _getListAttachmentsSize(
- context,
- controller.attachmentsExpandMode.value,
- attachments,
- attachmentLimitDisplayed);
- final isExpand = controller.attachmentsExpandMode.value == ExpandMode.EXPAND
- && attachments.length > attachmentLimitDisplayed;
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- if (isExpand)
- Padding(
- padding: EdgeInsets.zero,
- child: _buildAttachmentsHeader(context, attachments)),
- GridView.builder(
- key: const Key('list_attachment'),
- primary: false,
- shrinkWrap: true,
- padding: EdgeInsets.only(top: isExpand ? 0 : 16, bottom: 16),
- itemCount: countAttachments,
- gridDelegate: SliverGridDelegateFixedHeight(
- height: 60,
- crossAxisCount: attachmentLimitDisplayed,
- crossAxisSpacing: 16.0,
- mainAxisSpacing: 8.0),
- itemBuilder: (context, index) =>
- (AttachmentFileTileBuilder(
- imagePaths,
- attachments[index],
- attachments.length,
- attachmentLimitDisplayed)
- ..setExpandMode((countAttachments - 1 == index) ? controller.attachmentsExpandMode.value : null)
- ..onExpandAttachmentActionClick(() => controller.toggleDisplayAttachmentsAction())
- ..onDownloadAttachmentFileActionClick((attachment) {
- if (kIsWeb) {
- controller.downloadAttachmentForWeb(context, attachment);
- } else {
- controller.exportAttachment(context, attachment);
- }
- }))
- .build())
- ],
+ return Container(
+ color: Colors.white,
+ padding: const EdgeInsets.only(left: 16, right: 16, bottom: 12, top: 10),
+ child: Column(crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ _buildAttachmentsHeader(context, attachments),
+ _buildAttachmentsList(context, attachments, controller.isDisplayFullAttachments)
+ ],
+ ),
);
}
- int _getListAttachmentsSize(
- BuildContext context,
- ExpandMode expandMode,
- List attachments,
- int limitDisplayAttachment
- ) {
- if (attachments.length > limitDisplayAttachment) {
- return expandMode == ExpandMode.EXPAND
- ? attachments.length
- : attachments.sublist(0, limitDisplayAttachment).length;
- } else {
- return attachments.length;
- }
- }
-
Widget _buildAttachmentsHeader(BuildContext context, List attachments) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- AppLocalizations.of(context).count_attachment(attachments.length),
- style: const TextStyle(fontSize: 12, color: AppColor.baseTextColor)),
- Padding(
- padding: const EdgeInsets.only(left: 8),
- child: Text(
- '(${filesize(attachments.totalSize(), 1)})',
- style: const TextStyle(fontSize: 12, color: AppColor.nameUserColor, fontWeight: FontWeight.w500)))
- ],
- ),
- if (attachments.length > 2)
- Padding(
- padding: const EdgeInsets.only(left: 8),
- child: IconButton(
- icon: SvgPicture.asset(imagePaths.icExpandAttachment,
- width: 20,
- height: 20,
- color: AppColor.primaryColor,
- fit: BoxFit.fill),
- onPressed: () => controller.toggleDisplayAttachmentsAction()
+ return Container(
+ color: Colors.white,
+ child: Row(
+ children: [
+ Expanded(child: Container(
+ margin: const EdgeInsets.symmetric(vertical: 4),
+ child: Row(children: [
+ SvgPicture.asset(imagePaths.icAttachment,
+ width: 20,
+ height: 20,
+ color: AppColor.colorAttachmentIcon,
+ fit: BoxFit.fill),
+ const SizedBox(width: 5),
+ Expanded(child: Text(
+ AppLocalizations.of(context).titleHeaderAttachment(
+ attachments.length,
+ filesize(attachments.totalSize(), 1)),
+ style: const TextStyle(
+ fontSize: 15,
+ fontWeight: FontWeight.normal,
+ color: AppColor.colorTitleHeaderAttachment)))
+ ])
+ )),
+ if (attachments.length > 2)
+ Obx(() => Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: controller.toggleDisplayAttachmentsAction,
+ customBorder: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
+ child: Text(
+ controller.isDisplayFullAttachments
+ ? AppLocalizations.of(context).hide
+ : AppLocalizations.of(context).showAll,
+ style: const TextStyle(
+ fontSize: 13,
+ color: AppColor.colorTextButton,
+ fontWeight: FontWeight.normal)),
+ ),
+ ),
))
- ],
+ ],
+ ),
);
}
+ Widget _buildAttachmentsList(
+ BuildContext context,
+ List attachments,
+ bool isDisplayAll
+ ) {
+ return LayoutBuilder(builder: (context, constraints) {
+ if (isDisplayAll) {
+ return Wrap(
+ runSpacing: 12,
+ children: attachments
+ .map((attachment) => AttachmentFileTileBuilder(
+ attachment,
+ onDownloadAttachmentFileActionClick: (attachment) {
+ if (BuildUtils.isWeb) {
+ controller.downloadAttachmentForWeb(context, attachment);
+ } else {
+ controller.exportAttachment(context, attachment);
+ }
+ }))
+ .toList());
+ } else {
+ return Container(
+ height: 60,
+ color: Colors.transparent,
+ child: ListView.builder(
+ key: const Key('list_attachment_minimize_in_email'),
+ shrinkWrap: true,
+ physics: const ClampingScrollPhysics(),
+ scrollDirection: Axis.horizontal,
+ itemCount: attachments.length,
+ itemBuilder: (context, index) => AttachmentFileTileBuilder(
+ attachments[index],
+ onDownloadAttachmentFileActionClick: (attachment) {
+ if (BuildUtils.isWeb) {
+ controller.downloadAttachmentForWeb(context, attachment);
+ } else {
+ controller.exportAttachment(context, attachment);
+ }
+ })
+ )
+ );
+ }
+ });
+ }
+
Widget _buildEmailContent(BuildContext context, BoxConstraints constraints) {
return Obx(() {
if (controller.emailContents.isNotEmpty) {
diff --git a/lib/features/email/presentation/widgets/attachment_file_tile_builder.dart b/lib/features/email/presentation/widgets/attachment_file_tile_builder.dart
index 7829d8e5b..40fd78531 100644
--- a/lib/features/email/presentation/widgets/attachment_file_tile_builder.dart
+++ b/lib/features/email/presentation/widgets/attachment_file_tile_builder.dart
@@ -3,157 +3,102 @@ import 'package:core/core.dart';
import 'package:filesize/filesize.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
typedef OnDownloadAttachmentFileActionClick = void Function(Attachment attachment);
typedef OnExpandAttachmentActionClick = void Function();
-class AttachmentFileTileBuilder {
+class AttachmentFileTileBuilder extends StatelessWidget{
- final ImagePaths _imagePaths;
final Attachment _attachment;
- final int _attachmentSize;
- final int _limitDisplayAttachment;
- ExpandMode? _expandMode;
+ final OnDownloadAttachmentFileActionClick? onDownloadAttachmentFileActionClick;
- OnDownloadAttachmentFileActionClick? _onDownloadAttachmentFileActionClick;
- OnExpandAttachmentActionClick? _onExpandAttachmentActionClick;
+ const AttachmentFileTileBuilder(
+ this._attachment, {
+ Key? key,
+ this.onDownloadAttachmentFileActionClick,
+ }) : super(key: key);
- Widget? buttonAction;
- double? heightItem;
+ @override
+ Widget build(BuildContext context) {
+ final imagePaths = Get.find();
+ final responsiveUtils = Get.find();
- AttachmentFileTileBuilder(
- this._imagePaths,
- this._attachment,
- this._attachmentSize,
- this._limitDisplayAttachment,
- );
-
- void onDownloadAttachmentFileActionClick(OnDownloadAttachmentFileActionClick onDownloadAttachmentFileActionClick) {
- _onDownloadAttachmentFileActionClick = onDownloadAttachmentFileActionClick;
- }
-
- void onExpandAttachmentActionClick(OnExpandAttachmentActionClick onExpandAttachmentActionClick) {
- _onExpandAttachmentActionClick = onExpandAttachmentActionClick;
- }
-
- void setExpandMode(ExpandMode? expandMode) {
- _expandMode = expandMode;
- }
-
- void addButtonAction(Widget action) {
- buttonAction = action;
- }
-
- void height(double height) {
- heightItem = height;
- }
-
- Widget build() {
- return Theme(
- data: ThemeData(
- splashColor: Colors.transparent ,
- highlightColor: Colors.transparent),
- child: Container(
- key: const Key('attach_file_tile'),
- alignment: Alignment.center,
- margin: EdgeInsets.only(top:heightItem != null ? 8 : 0),
- height: heightItem,
- padding: EdgeInsets.zero,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8),
- border: Border.all(color: AppColor.attachmentFileBorderColor),
- color: Colors.white),
- child: MediaQuery(
- data: const MediaQueryData(padding: EdgeInsets.zero),
- child: Stack(
- alignment: AlignmentDirectional.bottomEnd,
- children: [
- ListTile(
- contentPadding: EdgeInsets.zero,
- focusColor: AppColor.primaryColor,
- hoverColor: AppColor.primaryColor,
- onTap: () {
- if (_onDownloadAttachmentFileActionClick != null) {
- _onDownloadAttachmentFileActionClick!(_attachment);
- }},
- leading: Padding(
- padding: const EdgeInsets.only(left: 8, bottom: BuildUtils.isWeb ? 6 : 14),
- child: SvgPicture.asset(
- _attachment.getIcon(_imagePaths),
- width: 40,
- height: 40,
- fit: BoxFit.fill),
+ return Padding(
+ padding: const EdgeInsets.only(right: 12),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () => onDownloadAttachmentFileActionClick?.call(_attachment),
+ customBorder: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
+ child: Container(
+ padding: const EdgeInsets.all(8),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(10),
+ border: Border.all(color: AppColor.attachmentFileBorderColor),
+ color: Colors.transparent),
+ width: responsiveUtils.isMobile(context) ? 224 : 250,
+ height: 60,
+ child: Stack(
+ children: [
+ Positioned.fill(
+ child: Row(children: [
+ SvgPicture.asset(
+ _attachment.getIcon(imagePaths),
+ width: 44,
+ height: 44,
+ fit: BoxFit.fill),
+ const SizedBox(width: 8),
+ Expanded(child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ _attachment.name ?? '',
+ maxLines: 1,
+ overflow: CommonTextStyle.defaultTextOverFlow,
+ softWrap: CommonTextStyle.defaultSoftWrap,
+ style: const TextStyle(
+ fontSize: 14,
+ color: AppColor.attachmentFileNameColor,
+ fontWeight: FontWeight.normal),
+ ),
+ const SizedBox(height: 4),
+ Text(
+ filesize(_attachment.size?.value),
+ maxLines: 1,
+ overflow: CommonTextStyle.defaultTextOverFlow,
+ softWrap: CommonTextStyle.defaultSoftWrap,
+ style: const TextStyle(
+ fontSize: 12,
+ color: AppColor.attachmentFileSizeColor,
+ fontWeight: FontWeight.normal),
+ )
+ ]
+ ))
+ ]),
),
- title: Transform(
- transform: Matrix4.translationValues(
- BuildUtils.isWeb ? 0.0 : -8.0,
- BuildUtils.isWeb ? -8.0 : -10.0,
- 0.0),
- child: Text(
- _attachment.name ?? '',
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- style: const TextStyle(fontSize: 12, color: AppColor.attachmentFileNameColor, fontWeight: FontWeight.w500),
- )),
- subtitle: _attachment.size != null && _attachment.size?.value != 0
- ? Transform(
- transform: Matrix4.translationValues(
- BuildUtils.isWeb ? 0.0 : -8.0,
- BuildUtils.isWeb ? -8.0 : -10.0,
- 0.0),
- child: Text(
- filesize(_attachment.size?.value),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- style: const TextStyle(fontSize: 12, color: AppColor.attachmentFileSizeColor)))
- : null,
- trailing: buttonAction != null
- ? Transform(
- transform: Matrix4.translationValues(-5.0, heightItem != null ? -6.0 : 0.0, 0.0),
- child: buttonAction)
- : null
- ),
- if (buttonAction == null)
- Transform(
- transform: Matrix4.translationValues(5.0, 5.0, 0.0),
- child: IconButton(
- icon: SvgPicture.asset(
- _imagePaths.icDownload,
+ Align(
+ alignment: Alignment.bottomRight,
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ customBorder: const CircleBorder(),
+ child: SvgPicture.asset(
+ imagePaths.icDownloadAttachment,
width: 24,
height: 24,
color: AppColor.primaryColor,
fit: BoxFit.fill),
- onPressed: () {
- if (_onDownloadAttachmentFileActionClick != null) {
- _onDownloadAttachmentFileActionClick!(_attachment);
- }
- }
- )),
- if (_attachmentSize > _limitDisplayAttachment && _expandMode == ExpandMode.COLLAPSE) _buildItemBackground()
- ]
- )
- )
- )
- );
- }
-
- Widget _buildItemBackground() {
- return GestureDetector(
- onTap: () {
- if (_onExpandAttachmentActionClick != null) {
- _onExpandAttachmentActionClick!();
- }
- },
- child: Stack(
- alignment: AlignmentDirectional.center,
- children: [
- Container(color: AppColor.backgroundCountAttachment),
- Text(
- '+${_attachmentSize - _limitDisplayAttachment + 1}',
- style: const TextStyle(fontSize: 16, color: Colors.white, fontWeight: FontWeight.bold))
- ],
+ onTap: () => onDownloadAttachmentFileActionClick?.call(_attachment)
+ ),
+ ),
+ ),
+ ]
+ )
+ ),
+ ),
),
);
}
diff --git a/lib/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart b/lib/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart
index 421149a89..535a80ec7 100644
--- a/lib/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart
+++ b/lib/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart
@@ -28,7 +28,13 @@ class BottomBarMailWidgetBuilder extends StatelessWidget {
return Container(
alignment: Alignment.center,
- color: Colors.white,
+ decoration: responsiveUtils.isWebDesktop(context)
+ ? const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.only(
+ bottomRight: Radius.circular(20),
+ bottomLeft: Radius.circular(20)))
+ : const BoxDecoration(color: Colors.white),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb
index a2ecbfa27..8354f3183 100644
--- a/lib/l10n/intl_messages.arb
+++ b/lib/l10n/intl_messages.arb
@@ -1,5 +1,5 @@
{
- "@@last_modified": "2022-10-12T11:51:14.324607",
+ "@@last_modified": "2022-10-12T16:44:35.025767",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -358,14 +358,16 @@
"placeholders_order": [],
"placeholders": {}
},
- "count_attachment": "{count} attachments",
- "@count_attachment": {
+ "titleHeaderAttachment": "{count} Attachments ({totalSize}):",
+ "@titleHeaderAttachment": {
"type": "text",
"placeholders_order": [
- "count"
+ "count",
+ "totalSize"
],
"placeholders": {
- "count": {}
+ "count": {},
+ "totalSize": {}
}
},
"attach_file_prepare_text": "Preparing to attach file...",
@@ -792,8 +794,8 @@
"placeholders_order": [],
"placeholders": {}
},
- "show_all": "Show all",
- "@show_all": {
+ "showAll": "Show all",
+ "@showAll": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart
index 7759b15b9..c9285e6fe 100644
--- a/lib/main/localizations/app_localizations.dart
+++ b/lib/main/localizations/app_localizations.dart
@@ -374,11 +374,11 @@ class AppLocalizations {
);
}
- String count_attachment(int count) {
+ String titleHeaderAttachment(int count, String totalSize) {
return Intl.message(
- '$count attachments',
- name: 'count_attachment',
- args: [count]
+ '$count Attachments ($totalSize):',
+ name: 'titleHeaderAttachment',
+ args: [count, totalSize]
);
}
@@ -821,10 +821,10 @@ class AppLocalizations {
name: 'attachments');
}
- String get show_all {
+ String get showAll {
return Intl.message(
'Show all',
- name: 'show_all');
+ name: 'showAll');
}
String get message_dialog_send_email_without_a_subject {