TF-985 Apply new design for list attachment in EmailView
This commit is contained in:
@@ -708,7 +708,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
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()
|
||||
)
|
||||
|
||||
@@ -704,7 +704,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
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()
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<EmailController> 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<Attachment> 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<Attachment> 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<Attachment> 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<Attachment> 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) {
|
||||
|
||||
@@ -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<ImagePaths>();
|
||||
final responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
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)
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user