TF-2520 Handle print email to pdf
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
@@ -43,6 +43,8 @@ export 'utils/config/errors.dart';
|
||||
export 'data/utils/compress_file_utils.dart';
|
||||
export 'utils/platform_info.dart';
|
||||
export 'utils/option_param_mixin.dart';
|
||||
export 'utils/file_utils.dart';
|
||||
export 'utils/print_utils.dart';
|
||||
|
||||
// Views
|
||||
export 'presentation/views/text/slogan_builder.dart';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class PrintAttachment with EquatableMixin {
|
||||
final String iconSvg;
|
||||
final String name;
|
||||
final String size;
|
||||
|
||||
PrintAttachment({
|
||||
required this.iconSvg,
|
||||
required this.name,
|
||||
required this.size
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
iconSvg,
|
||||
name,
|
||||
size
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:core/data/model/print_attachment.dart';
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:htmltopdfwidgets/htmltopdfwidgets.dart' as pw;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:printing/printing.dart';
|
||||
|
||||
class PrintUtils {
|
||||
final pw.HTMLToPdf _htmlToPdf;
|
||||
final ImagePaths _imagePaths;
|
||||
|
||||
PrintUtils(this._htmlToPdf, this._imagePaths);
|
||||
|
||||
Future<pw.Widget> _createEmailContentWidget(String htmlDocument) async {
|
||||
try {
|
||||
final List<pw.Widget> bodyWidgets = await _htmlToPdf.convert(htmlDocument);
|
||||
|
||||
return pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
...bodyWidgets
|
||||
]
|
||||
);
|
||||
} catch (e) {
|
||||
logError('PrintUtils::_createEmailContentWidget: Exception: $e');
|
||||
return pw.Text(htmlDocument);
|
||||
}
|
||||
}
|
||||
|
||||
List<pw.Widget> _createBodyWidgets({
|
||||
required pw.Context context,
|
||||
required String logoAppSvg,
|
||||
required String appName,
|
||||
required String userName,
|
||||
required String title,
|
||||
required String htmlDocument,
|
||||
required String senderName,
|
||||
required String senderEmailAddress,
|
||||
required String dateTime,
|
||||
required String toPrefix,
|
||||
required String ccPrefix,
|
||||
required String bccPrefix,
|
||||
required String replyToPrefix,
|
||||
required String titleAttachment,
|
||||
required pw.Widget contentWidget,
|
||||
String? toAddress,
|
||||
String? ccAddress,
|
||||
String? bccAddress,
|
||||
String? replyToAddress,
|
||||
List<PrintAttachment>? listAttachment,
|
||||
}) {
|
||||
return [
|
||||
pw.Container(
|
||||
padding: const pw.EdgeInsets.symmetric(horizontal: 32),
|
||||
child: pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
_createUserInformationRow(
|
||||
context: context,
|
||||
logoAppSvg: logoAppSvg,
|
||||
appName: appName,
|
||||
userName: userName
|
||||
),
|
||||
_createPageDivider(),
|
||||
if (title.isNotEmpty)
|
||||
...[
|
||||
_createTitleRow(
|
||||
context: context,
|
||||
title: title
|
||||
),
|
||||
_createPageDivider(),
|
||||
],
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Row(
|
||||
children: [
|
||||
pw.Expanded(
|
||||
child: _createSenderWidget(
|
||||
context: context,
|
||||
name: senderName,
|
||||
emailAddress: senderEmailAddress
|
||||
)
|
||||
),
|
||||
_createDateTimeWidget(
|
||||
context: context,
|
||||
dateTime: dateTime
|
||||
)
|
||||
]
|
||||
),
|
||||
if (replyToAddress?.isNotEmpty == true)
|
||||
_createRecipientRow(
|
||||
prefix: replyToPrefix,
|
||||
emailAddress: replyToAddress!
|
||||
),
|
||||
if (toAddress?.isNotEmpty == true)
|
||||
_createRecipientRow(
|
||||
prefix: toPrefix,
|
||||
emailAddress: toAddress!
|
||||
),
|
||||
if (ccAddress?.isNotEmpty == true)
|
||||
_createRecipientRow(
|
||||
prefix: ccPrefix,
|
||||
emailAddress: ccAddress!
|
||||
),
|
||||
if (bccAddress?.isNotEmpty == true)
|
||||
_createRecipientRow(
|
||||
prefix: bccPrefix,
|
||||
emailAddress: bccAddress!
|
||||
),
|
||||
pw.Padding(
|
||||
padding: const pw.EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 24),
|
||||
child: contentWidget
|
||||
),
|
||||
if (listAttachment?.isNotEmpty == true)
|
||||
...[
|
||||
_createPageDivider(),
|
||||
pw.SizedBox(height: 12),
|
||||
_createAttachmentTitle(
|
||||
context: context,
|
||||
title: titleAttachment,
|
||||
totalAttachments: listAttachment!.length
|
||||
),
|
||||
pw.SizedBox(height: 4),
|
||||
...listAttachment.map((attachment) => _createAttachmentRow(
|
||||
context: context,
|
||||
attachment: attachment
|
||||
))
|
||||
]
|
||||
]
|
||||
)
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
pw.Widget _createPageDivider() {
|
||||
return pw.Padding(
|
||||
padding: const pw.EdgeInsets.only(top: 12),
|
||||
child: pw.Divider()
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createPageHeader({
|
||||
required pw.Context context,
|
||||
required String appName,
|
||||
required String title,
|
||||
required String locale,
|
||||
}) {
|
||||
final currentTime = DateFormat('MM/dd/yyyy, h:mm a', locale).format(DateTime.now());
|
||||
return pw.Padding(
|
||||
padding: const pw.EdgeInsets.all(20),
|
||||
child: pw.Row(
|
||||
children: [
|
||||
pw.Text(
|
||||
currentTime,
|
||||
style: pw.Theme.of(context).defaultTextStyle.copyWith(
|
||||
fontSize: 8,
|
||||
color: pw.PdfColor.fromInt(AppColor.colorTextBody.value)
|
||||
)
|
||||
),
|
||||
pw.SizedBox(width: 16),
|
||||
pw.Expanded(
|
||||
child: pw.Text(
|
||||
'$appName - $title',
|
||||
textAlign: pw.TextAlign.center,
|
||||
maxLines: 1,
|
||||
style: pw.Theme.of(context).defaultTextStyle.copyWith(
|
||||
fontSize: 8,
|
||||
color: pw.PdfColor.fromInt(AppColor.colorTextBody.value)
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createUserInformationRow({
|
||||
required pw.Context context,
|
||||
required String logoAppSvg,
|
||||
required String appName,
|
||||
required String userName,
|
||||
}) {
|
||||
return pw.Row(
|
||||
children: [
|
||||
pw.SvgImage(
|
||||
svg: logoAppSvg,
|
||||
width: 32,
|
||||
height: 32
|
||||
),
|
||||
pw.SizedBox(width: 12),
|
||||
pw.Text(
|
||||
appName,
|
||||
style: pw.Theme.of(context).header0
|
||||
),
|
||||
pw.Spacer(),
|
||||
pw.SizedBox(width: 12),
|
||||
pw.Text(
|
||||
userName,
|
||||
style: pw.Theme.of(context).header4
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createTitleRow({
|
||||
required pw.Context context,
|
||||
required String title,
|
||||
}) {
|
||||
return pw.Padding(
|
||||
padding: const pw.EdgeInsets.only(top: 12),
|
||||
child: pw.Text(
|
||||
title,
|
||||
style: pw.Theme.of(context).header3
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createSenderWidget({
|
||||
required pw.Context context,
|
||||
required String name,
|
||||
required String emailAddress,
|
||||
}) {
|
||||
return pw.Row(
|
||||
children: [
|
||||
if (name.isNotEmpty)
|
||||
pw.Padding(
|
||||
padding: const pw.EdgeInsetsDirectional.only(end: 4),
|
||||
child: pw.Text(
|
||||
name,
|
||||
style: pw.Theme.of(context).header4
|
||||
)
|
||||
),
|
||||
pw.Text('<$emailAddress>')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createDateTimeWidget({
|
||||
required pw.Context context,
|
||||
required String dateTime,
|
||||
}) {
|
||||
return pw.Text(
|
||||
dateTime,
|
||||
style: pw.Theme.of(context).defaultTextStyle.copyWith(
|
||||
fontSize: 10,
|
||||
color: pw.PdfColor.fromInt(AppColor.colorTextBody.value)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createRecipientRow({
|
||||
required String prefix,
|
||||
required String emailAddress,
|
||||
}) {
|
||||
return pw.Row(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Text('$prefix:'),
|
||||
pw.SizedBox(width: 4),
|
||||
pw.Expanded(child: pw.Text(emailAddress))
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createAttachmentTitle({
|
||||
required pw.Context context,
|
||||
required String title,
|
||||
required int totalAttachments,
|
||||
}) {
|
||||
return pw.Text(
|
||||
'$totalAttachments $title',
|
||||
style: pw.Theme.of(context).header4
|
||||
);
|
||||
}
|
||||
|
||||
pw.Widget _createAttachmentRow({
|
||||
required pw.Context context,
|
||||
required PrintAttachment attachment,
|
||||
}) {
|
||||
return pw.Padding(
|
||||
padding: const pw.EdgeInsets.only(top: 8),
|
||||
child: pw.Row(
|
||||
children: [
|
||||
pw.SvgImage(
|
||||
svg: attachment.iconSvg,
|
||||
width: 24,
|
||||
height: 24
|
||||
),
|
||||
pw.SizedBox(width: 8),
|
||||
pw.Expanded(
|
||||
child: pw.Column(
|
||||
mainAxisSize: pw.MainAxisSize.min,
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Text(
|
||||
attachment.name,
|
||||
style: pw.Theme.of(context).header4
|
||||
),
|
||||
pw.Text(attachment.size)
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> printEmailToPDF({
|
||||
required String appName,
|
||||
required String userName,
|
||||
required String title,
|
||||
required String emailContent,
|
||||
required String senderName,
|
||||
required String senderEmailAddress,
|
||||
required String locale,
|
||||
required String dateTime,
|
||||
required String toPrefix,
|
||||
required String ccPrefix,
|
||||
required String bccPrefix,
|
||||
required String replyToPrefix,
|
||||
required String titleAttachment,
|
||||
String? toAddress,
|
||||
String? ccAddress,
|
||||
String? bccAddress,
|
||||
String? replyToAddress,
|
||||
List<PrintAttachment>? listAttachment,
|
||||
}) async {
|
||||
return await Printing.layoutPdf(onLayout: (pw.PdfPageFormat format) async {
|
||||
final googleInterRegularFont = await PdfGoogleFonts.interRegular();
|
||||
final googleInterBoldFont = await PdfGoogleFonts.interBold();
|
||||
final logoAppSvg = await rootBundle.loadString(_imagePaths.icTMailLogo);
|
||||
final contentWidget = await _createEmailContentWidget(emailContent);
|
||||
|
||||
final pdfDocument = pw.Document();
|
||||
|
||||
pdfDocument.addPage(
|
||||
pw.MultiPage(
|
||||
pageFormat: pw.PdfPageFormat.standard,
|
||||
orientation: pw.PageOrientation.portrait,
|
||||
theme: pw.ThemeData(
|
||||
defaultTextStyle: pw.TextStyle(
|
||||
font: googleInterRegularFont,
|
||||
fontSize: 12,
|
||||
color: pw.PdfColors.black
|
||||
),
|
||||
header3: pw.TextStyle(
|
||||
font: googleInterBoldFont,
|
||||
fontSize: 14,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: pw.PdfColors.black
|
||||
),
|
||||
header4: pw.TextStyle(
|
||||
font: googleInterBoldFont,
|
||||
fontSize: 12,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: pw.PdfColors.black
|
||||
),
|
||||
),
|
||||
margin: pw.EdgeInsets.zero,
|
||||
build: (context) => _createBodyWidgets(
|
||||
context: context,
|
||||
contentWidget: contentWidget,
|
||||
logoAppSvg: logoAppSvg,
|
||||
appName: appName,
|
||||
userName: userName,
|
||||
title: title,
|
||||
htmlDocument: emailContent,
|
||||
senderName: senderName,
|
||||
senderEmailAddress: senderEmailAddress,
|
||||
dateTime: dateTime,
|
||||
toPrefix: toPrefix,
|
||||
ccPrefix: ccPrefix,
|
||||
bccPrefix: toPrefix,
|
||||
replyToPrefix: replyToPrefix,
|
||||
toAddress: toAddress,
|
||||
ccAddress: ccAddress,
|
||||
bccAddress: bccAddress,
|
||||
replyToAddress: replyToAddress,
|
||||
titleAttachment: titleAttachment,
|
||||
listAttachment: listAttachment
|
||||
),
|
||||
header: (context) => _createPageHeader(
|
||||
context: context,
|
||||
appName: appName,
|
||||
title: title,
|
||||
locale: locale,
|
||||
),
|
||||
)
|
||||
);
|
||||
return await pdfDocument.save();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.10"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -17,6 +25,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
barcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: barcode
|
||||
sha256: "91b143666f7bb13636f716b6d4e412e372ab15ff7969799af8c9e30a382e9385"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.6"
|
||||
bidi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bidi
|
||||
sha256: "1a7d0c696324b2089f72e7671fd1f1f64fef44c980f3cebc84e803967c597b63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -65,6 +89,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -73,6 +105,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.3+7"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -328,6 +368,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.15.3"
|
||||
htmltopdfwidgets:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: htmltopdfwidgets
|
||||
sha256: "990e3002fbbfaf307555f1991bed61b6228d7053b7e1945815c7a68f56bbda81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -344,6 +392,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.7"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -464,6 +520,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
pdf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pdf
|
||||
sha256: "243f05342fc0bdf140eba5b069398985cdbdd3dbb1d776cf43d5ea29cc570ba6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.8"
|
||||
pdf_widget_wrapper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pdf_widget_wrapper
|
||||
sha256: e9d31fd7782ce28ae346b127ea7d1cd748d799bddee379f31191693610e23749
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -496,6 +568,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.1"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.4"
|
||||
printing:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: printing
|
||||
sha256: "1c99cab90ebcc1fff65831d264627d5b529359d563e53f33ab9b8117f2d280bc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.12.0"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: qr
|
||||
sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
||||
@@ -75,6 +75,10 @@ dependencies:
|
||||
|
||||
linkify: 5.0.0
|
||||
|
||||
htmltopdfwidgets: 1.0.3
|
||||
|
||||
printing: 5.12.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in New Issue
Block a user