Add presentation layer for GetEmailContent

This commit is contained in:
dab246
2021-08-18 17:50:53 +07:00
committed by Dat H. Pham
parent f8b8f73a86
commit 842072e0d6
33 changed files with 1107 additions and 115 deletions
@@ -2,6 +2,9 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
typedef OnBackActionClick = void Function();
@@ -11,11 +14,13 @@ class AppBarMailWidgetBuilder {
final BuildContext _context;
final ImagePaths _imagePaths;
final ResponsiveUtils _responsiveUtils;
final PresentationEmail? _presentationEmail;
AppBarMailWidgetBuilder(
this._context,
this._imagePaths,
this._responsiveUtils,
this._presentationEmail,
);
AppBarMailWidgetBuilder onBackActionClick(
@@ -28,6 +33,7 @@ class AppBarMailWidgetBuilder {
return Container(
key: Key('app_bar_messenger_widget'),
alignment: Alignment.center,
padding: EdgeInsets.zero,
color: Colors.white,
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
@@ -35,7 +41,7 @@ class AppBarMailWidgetBuilder {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (!_responsiveUtils.isDesktop(_context))
if (!_responsiveUtils.isDesktop(_context) || Get.currentRoute != AppRoutes.MAILBOX_DASHBOARD)
Expanded(child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
@@ -63,11 +69,15 @@ class AppBarMailWidgetBuilder {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ButtonBuilder(_imagePaths.icTrash).key(Key('button_delete_message')).build(),
SizedBox(width: 20),
SizedBox(width: 10),
ButtonBuilder(_imagePaths.icEyeDisable).key(Key('button_hide_message')).build(),
SizedBox(width: 20),
ButtonBuilder(_imagePaths.icStar).key(Key('button_favorite_message')).build(),
SizedBox(width: 20),
SizedBox(width: 10),
ButtonBuilder((_presentationEmail != null && _presentationEmail!.isFlaggedEmail())
? _imagePaths.icFlagged
: _imagePaths.icFlag)
.key(Key('button_favorite_message'))
.build(),
SizedBox(width: 10),
ButtonBuilder(_imagePaths.icFolder).key(Key('button_add_folder_message')).build(),
]
);
@@ -0,0 +1,70 @@
import 'package:core/core.dart';
import 'package:filesize/filesize.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/email/presentation/model/attachment_file.dart';
typedef OnOpenAttachmentFileActionClick = void Function();
class AttachmentFileTileBuilder {
final ImagePaths _imagePaths;
final AttachmentFile _attachmentFile;
OnOpenAttachmentFileActionClick? _onOpenAttachmentFileActionClick;
AttachmentFileTileBuilder(this._imagePaths, this._attachmentFile);
AttachmentFileTileBuilder onOpenAttachmentFileActionClick(
OnOpenAttachmentFileActionClick onOpenAttachmentFileActionClick) {
_onOpenAttachmentFileActionClick = onOpenAttachmentFileActionClick;
return this;
}
Widget build() {
return Theme(
data: ThemeData(
splashColor: Colors.transparent ,
highlightColor: Colors.transparent),
child: Container(
key: Key('attach_file_tile'),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.attachmentFileBorderColor),
color: Colors.white),
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: ListTile(
onTap: () {
if (_onOpenAttachmentFileActionClick != null) {
_onOpenAttachmentFileActionClick!();
}},
leading: Transform(
transform: Matrix4.translationValues(0.0, 2.0, 0.0),
child: SvgPicture.asset(_imagePaths.icAttachmentFile, width: 24, height: 24, fit: BoxFit.fill)),
title: Transform(
transform: Matrix4.translationValues(-18.0, -8.0, 0.0),
child: Text(
_attachmentFile.name ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: AppColor.attachmentFileNameColor, fontWeight: FontWeight.w500),
)),
subtitle: _attachmentFile.size != null && _attachmentFile.size?.value != 0
? Transform(
transform: Matrix4.translationValues(-18.0, -8.0, 0.0),
child: Text(
filesize(_attachmentFile.size?.value),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: AppColor.attachmentFileSizeColor)))
: null
),
)
)
);
}
}
@@ -0,0 +1,103 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:photo_view/photo_view.dart';
import 'package:tmail_ui_user/features/email/presentation/model/attachment_file.dart';
import 'package:tmail_ui_user/features/email/presentation/model/message_content.dart';
import 'package:tmail_ui_user/features/email/presentation/model/text_format.dart';
import 'package:sanitize_html/sanitize_html.dart' show sanitizeHtml;
class MessageContentTileBuilder {
final MessageContent _messageContent;
final ImagePaths _imagePaths;
final List<AttachmentFile> _attachmentInlines;
final Session? _session;
final AccountId? _accountId;
MessageContentTileBuilder(
this._messageContent,
this._imagePaths,
this._attachmentInlines,
this._session,
this._accountId,
);
Widget build() {
return Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent),
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: Center(
child: _messageContent.textFormat == TextFormat.PLAIN
? Text('${_messageContent.content}', style: TextStyle(fontSize: 12, color: AppColor.mailboxTextColor))
: HtmlWidget(
cleanHtmlMessage(_messageContent.content),
textStyle: TextStyle(fontSize: 12, color: AppColor.mailboxTextColor),
buildAsync: true,
factoryBuilder: () => _PopupPhotoViewWidgetFactory(_imagePaths),
buildAsyncBuilder: (_, snapshot) => snapshot.data ?? SizedBox(
height: 30,
width: 30,
child: CircularProgressIndicator(color: AppColor.primaryColor)),
webViewJs: false),
)
)
);
}
String getHtmlMessageText() {
final message = (_attachmentInlines.isNotEmpty && _session != null && _accountId != null && _messageContent.hasImageInlineWithCid())
? '${_messageContent.getContentHasInlineAttachment(_session!, _accountId!, _attachmentInlines)}'
: '${_messageContent.content}';
return message;
}
String cleanHtmlMessage(String message) => hasTagTable(getHtmlMessageText()) ? sanitizeHtml(getHtmlMessageText()) : message;
bool hasTagTable(String html) => html.toLowerCase().contains('</table>');
}
class _PopupPhotoViewWidgetFactory extends WidgetFactory {
final ImagePaths _imagePaths;
_PopupPhotoViewWidgetFactory(this._imagePaths);
@override
Widget? buildImageWidget(BuildMetadata meta, {String? semanticLabel, required String url}) {
final built = super.buildImageWidget(meta, semanticLabel: semanticLabel, url: url);
if (built is Image) {
return Builder(
builder: (context) => GestureDetector(
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (_) => Scaffold(
body: Stack(
children: [
PhotoView(
heroAttributes: PhotoViewHeroAttributes(tag: url),
imageProvider: built.image),
Padding(
padding: EdgeInsets.only(left: 16, top: 35),
child: IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: SvgPicture.asset(_imagePaths.icCloseMailbox, width: 30, height: 30, fit: BoxFit.fill)))
],
),
))),
child: Hero(tag: url, child: built),
),
);
}
return built;
}
}
@@ -0,0 +1,196 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:model/email/presentation_email.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnOpenExpandAddressReceiverActionClick = void Function();
class SenderAndReceiverInformationTileBuilder {
static const int LIMIT_ADDRESS_DISPLAY = 1;
final ImagePaths _imagePaths;
final BuildContext _context;
final PresentationEmail? _presentationEmail;
final ExpandMode _expandMode;
OnOpenExpandAddressReceiverActionClick? _onOpenExpandAddressReceiverActionClick;
SenderAndReceiverInformationTileBuilder(
this._context,
this._imagePaths,
this._presentationEmail,
this._expandMode,
);
SenderAndReceiverInformationTileBuilder onOpenExpandAddressReceiverActionClick(OnOpenExpandAddressReceiverActionClick onOpenExpandAddressReceiverActionClick) {
_onOpenExpandAddressReceiverActionClick = onOpenExpandAddressReceiverActionClick;
return this;
}
Widget build() {
if (_presentationEmail == null) {
return SizedBox.shrink();
}
return Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent),
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: ListTile(
leading: Transform(
transform: Matrix4.translationValues(-15.0, -8.0, 0.0),
child: AvatarBuilder()
.text('${_presentationEmail!.getAvatarText()}')
.size(40)
.iconStatus(_imagePaths.icOffline)
.build()),
title: Transform(
transform: Matrix4.translationValues(-15.0, 0.0, 0.0),
child: Text(
'${AppLocalizations.of(_context).from_email_address_prefix}: ${_presentationEmail!.getSenderName().inCaps}',
style: TextStyle(fontSize: 16, color: AppColor.nameUserColor, fontWeight: FontWeight.w500),
)),
subtitle: Transform(
transform: Matrix4.translationValues(-15.0, 0.0, 0.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_presentationEmail!.to.numberEmailAddress() > 0) _buildAddressToReceiverWidget(),
if (_presentationEmail!.cc.numberEmailAddress() > 0) _buildAddressCcReceiverWidget(),
if (_presentationEmail!.bcc.numberEmailAddress() > 0) _buildAddressBccReceiverWidget(),
Padding(
padding: EdgeInsets.only(top: 6),
child: Text(
'${_presentationEmail!.getSentTime()}',
style: TextStyle(fontSize: 12, color: AppColor.baseTextColor),
))
],
))
)
)
);
}
Widget _buildExpandAddressWidget(String typeReceiver, String nameAddress) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$typeReceiver: ',
style: TextStyle(fontSize: 12, color: AppColor.baseTextColor, fontWeight: FontWeight.w500)),
Expanded(child: Text(
'$nameAddress',
style: TextStyle(fontSize: 12, color: AppColor.baseTextColor, fontWeight: FontWeight.w500),
))
]);
}
Widget _buildCollapseAddressWidget(String typeReceiver, String nameAddress) {
return Row(
children: [
Text(
'$typeReceiver: $nameAddress',
style: TextStyle(fontSize: 12, color: AppColor.baseTextColor, fontWeight: FontWeight.w500)),
if (_expandMode == ExpandMode.COLLAPSE
&& _presentationEmail != null
&& _presentationEmail!.numberOfAllEmailAddress() > LIMIT_ADDRESS_DISPLAY)
_buildButtonExpandAddress()
]);
}
Widget _buildAddressWidget(String typeReceiver, String nameAddress) {
if (_expandMode == ExpandMode.EXPAND
|| (_presentationEmail != null && _presentationEmail!.numberOfAllEmailAddress() <= LIMIT_ADDRESS_DISPLAY)) {
return Padding(
padding: EdgeInsets.only(top: 6),
child: _buildExpandAddressWidget(typeReceiver, nameAddress));
} else {
return Padding(
padding: EdgeInsets.only(top: 6),
child: _buildCollapseAddressWidget(typeReceiver, nameAddress));
}
}
Widget _buildAddressToReceiverWidget() {
return _buildAddressWidget(
AppLocalizations.of(_context).to_email_address_prefix,
_presentationEmail!.to.listEmailAddressToString(expandMode: _expandMode, limitAddress: LIMIT_ADDRESS_DISPLAY));
}
Widget _buildAddressCcReceiverWidget() {
if (_presentationEmail!.to.numberEmailAddress() > 0) {
if (_expandMode == ExpandMode.EXPAND) {
return Padding(
padding: EdgeInsets.only(top: 6),
child: _buildExpandAddressWidget(AppLocalizations.of(_context).cc_email_address_prefix, _presentationEmail!.cc.listEmailAddressToString(expandMode: _expandMode, limitAddress: LIMIT_ADDRESS_DISPLAY)));
} else {
return SizedBox.shrink();
}
} else {
return _buildAddressWidget(
AppLocalizations.of(_context).cc_email_address_prefix,
_presentationEmail!.cc.listEmailAddressToString(expandMode: _expandMode, limitAddress: LIMIT_ADDRESS_DISPLAY));
}
}
Widget _buildAddressBccReceiverWidget() {
if (_presentationEmail!.to.numberEmailAddress() > 0) {
if (_expandMode == ExpandMode.EXPAND) {
return Padding(
padding: EdgeInsets.only(top: 6),
child: _buildExpandAddressWidget(AppLocalizations.of(_context).bcc_email_address_prefix, _presentationEmail!.bcc.listEmailAddressToString(expandMode: _expandMode, limitAddress: LIMIT_ADDRESS_DISPLAY)));
} else {
return SizedBox.shrink();
}
} else {
if (_presentationEmail!.cc.numberEmailAddress() > 0) {
if (_expandMode == ExpandMode.EXPAND) {
return Padding(
padding: EdgeInsets.only(top: 6),
child: _buildExpandAddressWidget(AppLocalizations.of(_context).bcc_email_address_prefix, _presentationEmail!.bcc.listEmailAddressToString(expandMode: _expandMode, limitAddress: LIMIT_ADDRESS_DISPLAY)));
} else {
return SizedBox.shrink();
}
} else {
return _buildAddressWidget(
AppLocalizations.of(_context).bcc_email_address_prefix,
_presentationEmail!.bcc.listEmailAddressToString(expandMode: _expandMode, limitAddress: LIMIT_ADDRESS_DISPLAY));
}
}
}
String getRemainCountAddressReceiver() {
if (_presentationEmail!.numberOfAllEmailAddress() - LIMIT_ADDRESS_DISPLAY >= 999) {
return '999';
}
return '${_presentationEmail!.numberOfAllEmailAddress() - LIMIT_ADDRESS_DISPLAY}';
}
Widget _buildButtonExpandAddress() {
return GestureDetector(
onTap: () {
if (_onOpenExpandAddressReceiverActionClick != null) {
_onOpenExpandAddressReceiverActionClick!();
}},
child: Row(
children: [
SizedBox(width: 8),
Text(
'+${getRemainCountAddressReceiver()}',
style: TextStyle(fontSize: 12, color: AppColor.baseTextColor, fontWeight: FontWeight.w500),
),
SvgPicture.asset(_imagePaths.icMoreReceiver, width: 14, height: 14, fit: BoxFit.fill),
],
),
);
}
}