TF-185 [BUG] Fix can not display all parts of email which have multiple html part
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:core/core.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -8,6 +9,8 @@ class HtmlContentViewer extends StatefulWidget {
|
|||||||
|
|
||||||
final String contentHtml;
|
final String contentHtml;
|
||||||
final int minHeight;
|
final int minHeight;
|
||||||
|
final double widthContent;
|
||||||
|
final Widget? loadingWidget;
|
||||||
|
|
||||||
/// Register this callback if you want a reference to the [InAppWebViewController].
|
/// Register this callback if you want a reference to the [InAppWebViewController].
|
||||||
final void Function(InAppWebViewController controller)? onCreated;
|
final void Function(InAppWebViewController controller)? onCreated;
|
||||||
@@ -22,7 +25,9 @@ class HtmlContentViewer extends StatefulWidget {
|
|||||||
const HtmlContentViewer({
|
const HtmlContentViewer({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.contentHtml,
|
required this.contentHtml,
|
||||||
|
required this.widthContent,
|
||||||
this.minHeight = 100,
|
this.minHeight = 100,
|
||||||
|
this.loadingWidget,
|
||||||
this.onCreated,
|
this.onCreated,
|
||||||
this.onLoadStart,
|
this.onLoadStart,
|
||||||
this.onLoadStop,
|
this.onLoadStop,
|
||||||
@@ -39,6 +44,7 @@ class _HtmlContentViewState extends State<HtmlContentViewer> {
|
|||||||
double? _documentWidth = 1.0;
|
double? _documentWidth = 1.0;
|
||||||
String? _initialPageContent;
|
String? _initialPageContent;
|
||||||
late InAppWebViewController _webViewController;
|
late InAppWebViewController _webViewController;
|
||||||
|
bool loading = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -101,15 +107,33 @@ class _HtmlContentViewState extends State<HtmlContentViewer> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final size = MediaQuery.of(context).size;
|
_documentWidth = widget.widthContent;
|
||||||
_documentWidth = size.width - 30;
|
return Stack(
|
||||||
return SizedBox(
|
alignment: AlignmentDirectional.center,
|
||||||
height: _documentHeight,
|
children: [
|
||||||
width: _documentWidth,
|
SizedBox(
|
||||||
child: _buildWebView(),
|
height: _documentHeight,
|
||||||
|
width: _documentWidth,
|
||||||
|
child: _buildWebView(),
|
||||||
|
),
|
||||||
|
if (loading) _buildLoadingView()
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildLoadingView() {
|
||||||
|
if (widget.loadingWidget != null) {
|
||||||
|
return widget.loadingWidget!;
|
||||||
|
} else {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
child: CircularProgressIndicator(color: AppColor.primaryColor)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildWebView() {
|
Widget _buildWebView() {
|
||||||
if (_initialPageContent == null || _initialPageContent?.isEmpty == true) {
|
if (_initialPageContent == null || _initialPageContent?.isEmpty == true) {
|
||||||
return Container();
|
return Container();
|
||||||
@@ -148,6 +172,9 @@ class _HtmlContentViewState extends State<HtmlContentViewer> {
|
|||||||
_documentHeight = (scrollHeight + 30.0);
|
_documentHeight = (scrollHeight + 30.0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setState(() {
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
if (widget.onLoadStop != null) {
|
if (widget.onLoadStop != null) {
|
||||||
widget.onLoadStop!(controller, uri);
|
widget.onLoadStop!(controller, uri);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,10 @@ class ComposerController extends BaseController {
|
|||||||
.addBlockTag('p', attribute: 'style=\"font-size:14px;font-style:italic;color:#182952;\"')
|
.addBlockTag('p', attribute: 'style=\"font-size:14px;font-style:italic;color:#182952;\"')
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
final trustAsHtml = composerArguments.value?.emailContent?.content ?? '';
|
final trustAsHtml = composerArguments.value?.emailContents
|
||||||
|
?.map((emailContent) => emailContent.content)
|
||||||
|
.toList()
|
||||||
|
.join('</br>') ?? '';
|
||||||
|
|
||||||
final emailQuotedHtml = '</br></br></br>$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}</br>';
|
final emailQuotedHtml = '</br></br></br>$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}</br>';
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
|
|
||||||
abstract class HtmlDataSource {
|
abstract class HtmlDataSource {
|
||||||
Future<String> transformToHtml(EmailContent emailContent);
|
Future<EmailContent> transformEmailContent(EmailContent emailContent);
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,9 @@ class HtmlDataSourceImpl extends HtmlDataSource {
|
|||||||
HtmlDataSourceImpl(this._htmlAnalyzer);
|
HtmlDataSourceImpl(this._htmlAnalyzer);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> transformToHtml(EmailContent emailContent) {
|
Future<EmailContent> transformEmailContent(EmailContent emailContent) {
|
||||||
return Future.sync(() async {
|
return Future.sync(() async {
|
||||||
return await _htmlAnalyzer.transformToHtml(emailContent);
|
return await _htmlAnalyzer.transformEmailContent(emailContent);
|
||||||
}).catchError((error) {
|
}).catchError((error) {
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import 'package:model/model.dart';
|
|||||||
|
|
||||||
class HtmlAnalyzer {
|
class HtmlAnalyzer {
|
||||||
|
|
||||||
Future<String> transformToHtml(EmailContent emailContent) async {
|
Future<EmailContent> transformEmailContent(EmailContent emailContent) async {
|
||||||
switch(emailContent.type) {
|
switch(emailContent.type) {
|
||||||
case EmailContentType.textHtml:
|
case EmailContentType.textHtml:
|
||||||
final htmlTransform = HtmlTransform(emailContent.content);
|
final htmlTransform = HtmlTransform(emailContent.content);
|
||||||
return htmlTransform.transformToHtml();
|
final htmlContent = htmlTransform.transformToHtml();
|
||||||
|
return EmailContent(emailContent.type, htmlContent);
|
||||||
default:
|
default:
|
||||||
return emailContent.content;
|
return emailContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,11 @@ class EmailRepositoryImpl extends EmailRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> transformEmailContentToHtml(EmailContent emailContent) {
|
Future<List<EmailContent>> transformEmailContent(List<EmailContent> emailContents) async {
|
||||||
return _htmlDataSource.transformToHtml(emailContent);
|
return await Future.wait(emailContents
|
||||||
|
.map((emailContent) async {
|
||||||
|
return await _htmlDataSource.transformEmailContent(emailContent);
|
||||||
|
})
|
||||||
|
.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,5 +35,5 @@ abstract class EmailRepository {
|
|||||||
MarkStarAction markStarAction
|
MarkStarAction markStarAction
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<String> transformEmailContentToHtml(EmailContent emailContent);
|
Future<List<EmailContent>> transformEmailContent(List<EmailContent> emailContents);
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,13 @@ import 'package:core/core.dart';
|
|||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
|
|
||||||
class GetEmailContentSuccess extends UIState {
|
class GetEmailContentSuccess extends UIState {
|
||||||
final EmailContent emailContent;
|
final List<EmailContent> emailContents;
|
||||||
final List<Attachment> attachments;
|
final List<Attachment> attachments;
|
||||||
|
|
||||||
GetEmailContentSuccess(this.emailContent, this.attachments);
|
GetEmailContentSuccess(this.emailContents, this.attachments);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [emailContent, attachments];
|
List<Object?> get props => [emailContents, attachments];
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetEmailContentFailure extends FeatureFailure {
|
class GetEmailContentFailure extends FeatureFailure {
|
||||||
|
|||||||
@@ -17,15 +17,8 @@ class GetEmailContentInteractor {
|
|||||||
final email = await emailRepository.getEmailContent(accountId, emailId);
|
final email = await emailRepository.getEmailContent(accountId, emailId);
|
||||||
|
|
||||||
if (email.emailContentList.isNotEmpty) {
|
if (email.emailContentList.isNotEmpty) {
|
||||||
final emailContent = email.emailContentList.first;
|
final newEmailContents = await emailRepository.transformEmailContent(email.emailContentList);
|
||||||
if (emailContent.type == EmailContentType.textHtml) {
|
yield Right<Failure, Success>(GetEmailContentSuccess(newEmailContents, email.allAttachments));
|
||||||
final contentHtml = await emailRepository.transformEmailContentToHtml(emailContent);
|
|
||||||
yield Right<Failure, Success>(GetEmailContentSuccess(
|
|
||||||
EmailContent(emailContent.type, contentHtml),
|
|
||||||
email.allAttachments));
|
|
||||||
} else {
|
|
||||||
yield Right<Failure, Success>(GetEmailContentSuccess(emailContent, email.allAttachments));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
yield Left(GetEmailContentFailure(null));
|
yield Left(GetEmailContentFailure(null));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_
|
|||||||
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/web_view_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||||
@@ -49,7 +48,7 @@ class EmailController extends BaseController {
|
|||||||
|
|
||||||
final emailAddressExpandMode = ExpandMode.COLLAPSE.obs;
|
final emailAddressExpandMode = ExpandMode.COLLAPSE.obs;
|
||||||
final attachmentsExpandMode = ExpandMode.COLLAPSE.obs;
|
final attachmentsExpandMode = ExpandMode.COLLAPSE.obs;
|
||||||
final emailContent = Rxn<EmailContent>();
|
final emailContents = <EmailContent>[].obs;
|
||||||
final attachments = <Attachment>[].obs;
|
final attachments = <Attachment>[].obs;
|
||||||
EmailId? _currentEmailId;
|
EmailId? _currentEmailId;
|
||||||
|
|
||||||
@@ -129,17 +128,14 @@ class EmailController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
||||||
emailContent.value = success.emailContent;
|
emailContents.value = success.emailContents;
|
||||||
attachments.value = success.attachments;
|
attachments.value = success.attachments;
|
||||||
if (emailContent.value != null && emailContent.value!.type == EmailContentType.textHtml) {
|
|
||||||
dispatchState(Right(WebViewLoadingState()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearEmailContent() {
|
void _clearEmailContent() {
|
||||||
toggleDisplayEmailAddressAction(expandMode: ExpandMode.COLLAPSE);
|
toggleDisplayEmailAddressAction(expandMode: ExpandMode.COLLAPSE);
|
||||||
attachmentsExpandMode.value = ExpandMode.COLLAPSE;
|
attachmentsExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
emailContent.value = null;
|
emailContents.clear();
|
||||||
attachments.clear();
|
attachments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +353,7 @@ class EmailController extends BaseController {
|
|||||||
arguments: ComposerArguments(
|
arguments: ComposerArguments(
|
||||||
emailActionType: emailActionType,
|
emailActionType: emailActionType,
|
||||||
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
|
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
|
||||||
emailContent: emailContent.value,
|
emailContents: emailContents,
|
||||||
attachments: attachments,
|
attachments: attachments,
|
||||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
||||||
session: mailboxDashBoardController.sessionCurrent!,
|
session: mailboxDashBoardController.sessionCurrent!,
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:core/core.dart';
|
import 'package:core/core.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/email_controller.dart';
|
import 'package:tmail_ui_user/features/email/presentation/email_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/web_view_state.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_widget_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_widget_builder.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_file_tile_builder.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachments_place_holder_loading_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/list_attachment_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/list_attachment_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_item_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_place_holder_loading_widget.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_place_holder_loading_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
@@ -27,21 +27,17 @@ class EmailView extends GetView {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
|
||||||
backgroundColor: AppColor.primaryLightColor,
|
backgroundColor: AppColor.primaryLightColor,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
right: false,
|
right: false,
|
||||||
left: false,
|
left: false,
|
||||||
child: Container(
|
child: Column(
|
||||||
alignment: Alignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
child: Column(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
_buildAppBar(context),
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
Expanded(child: _buildEmailBody(context)),
|
||||||
children: [
|
_buildBottomBar(context),
|
||||||
_buildAppBar(context),
|
]
|
||||||
Expanded(child: _buildEmailBody(context)),
|
|
||||||
_buildBottomBar(context),
|
|
||||||
])
|
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -116,14 +112,6 @@ class EmailView extends GetView {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLoadingView() {
|
|
||||||
return Obx(() => emailController.viewState.value.fold(
|
|
||||||
(failure) => SizedBox.shrink(),
|
|
||||||
(success) => success is LoadingState || success is WebViewLoadingState
|
|
||||||
? EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils)
|
|
||||||
: SizedBox.shrink()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildEmailMessage(BuildContext context) {
|
Widget _buildEmailMessage(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(left: 12, right: 12, top: 16, bottom: 16),
|
padding: EdgeInsets.only(left: 12, right: 12, top: 16, bottom: 16),
|
||||||
@@ -143,9 +131,8 @@ class EmailView extends GetView {
|
|||||||
emailController.emailAddressExpandMode.value)
|
emailController.emailAddressExpandMode.value)
|
||||||
.onOpenExpandAddressReceiverActionClick(() => emailController.toggleDisplayEmailAddressAction(expandMode: ExpandMode.EXPAND))
|
.onOpenExpandAddressReceiverActionClick(() => emailController.toggleDisplayEmailAddressAction(expandMode: ExpandMode.EXPAND))
|
||||||
.build()),
|
.build()),
|
||||||
_buildLoadingView(),
|
|
||||||
_buildAttachments(context),
|
_buildAttachments(context),
|
||||||
_buildEmailContent(),
|
_buildListEmailContent(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -155,8 +142,8 @@ class EmailView extends GetView {
|
|||||||
return Obx(() => emailController.viewState.value.fold(
|
return Obx(() => emailController.viewState.value.fold(
|
||||||
(failure) => SizedBox.shrink(),
|
(failure) => SizedBox.shrink(),
|
||||||
(success) {
|
(success) {
|
||||||
if (success is LoadingState || success is WebViewLoadingState) {
|
if (success is LoadingState) {
|
||||||
return SizedBox.shrink();
|
return AttachmentsPlaceHolderLoading(responsiveUtils: responsiveUtils);
|
||||||
} else {
|
} else {
|
||||||
final attachments = emailController.attachments.attachmentsWithDispositionAttachment;
|
final attachments = emailController.attachments.attachmentsWithDispositionAttachment;
|
||||||
return attachments.isNotEmpty
|
return attachments.isNotEmpty
|
||||||
@@ -272,28 +259,30 @@ class EmailView extends GetView {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmailContent() {
|
Widget _buildListEmailContent() {
|
||||||
return Obx(() {
|
return Obx(() => emailController.viewState.value.fold(
|
||||||
if (emailController.emailContent.value != null) {
|
(failure) => SizedBox.shrink(),
|
||||||
switch(emailController.emailContent.value!.type) {
|
(success) {
|
||||||
case EmailContentType.textHtml:
|
if (success is LoadingState) {
|
||||||
return HtmlContentViewer(
|
return EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils);
|
||||||
contentHtml: emailController.emailContent.value!.content,
|
} else {
|
||||||
onLoadStart: (webController, uri) => emailController.dispatchState(Right(WebViewLoadingState())),
|
if (emailController.emailContents.isNotEmpty) {
|
||||||
onLoadStop: (webController, uri) => emailController.dispatchState(Right(WebViewLoadCompletedState())),
|
return ListView.builder(
|
||||||
mailtoDelegate: (uri) async {});
|
primary: false,
|
||||||
case EmailContentType.textPlain:
|
shrinkWrap: true,
|
||||||
return Padding(
|
padding: EdgeInsets.only(top: 10),
|
||||||
padding: EdgeInsets.only(top: 16),
|
key: Key('list_email_content'),
|
||||||
child: Text(
|
itemCount: emailController.emailContents.length,
|
||||||
emailController.emailContent.value!.content,
|
itemBuilder: (context, index) =>
|
||||||
style: TextStyle(fontSize: 14, color: AppColor.nameUserColor)));
|
EmailContentItemBuilder(
|
||||||
case EmailContentType.other:
|
context,
|
||||||
|
emailController.emailContents[index],
|
||||||
|
loadingWidget: EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils)
|
||||||
|
).build());
|
||||||
|
} else {
|
||||||
return SizedBox.shrink();
|
return SizedBox.shrink();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}));
|
||||||
return SizedBox.shrink();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ import 'package:model/model.dart';
|
|||||||
class ComposerArguments with EquatableMixin {
|
class ComposerArguments with EquatableMixin {
|
||||||
final EmailActionType emailActionType;
|
final EmailActionType emailActionType;
|
||||||
final PresentationEmail? presentationEmail;
|
final PresentationEmail? presentationEmail;
|
||||||
final EmailContent? emailContent;
|
final List<EmailContent>? emailContents;
|
||||||
final List<Attachment>? attachments;
|
final List<Attachment>? attachments;
|
||||||
final Session session;
|
final Session session;
|
||||||
final UserProfile userProfile;
|
final UserProfile userProfile;
|
||||||
@@ -17,7 +17,7 @@ class ComposerArguments with EquatableMixin {
|
|||||||
ComposerArguments({
|
ComposerArguments({
|
||||||
this.emailActionType = EmailActionType.compose,
|
this.emailActionType = EmailActionType.compose,
|
||||||
this.presentationEmail,
|
this.presentationEmail,
|
||||||
this.emailContent,
|
this.emailContents,
|
||||||
this.attachments,
|
this.attachments,
|
||||||
this.mailboxRole,
|
this.mailboxRole,
|
||||||
required this.session,
|
required this.session,
|
||||||
@@ -28,8 +28,7 @@ class ComposerArguments with EquatableMixin {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [
|
List<Object?> get props => [
|
||||||
emailActionType,
|
emailActionType,
|
||||||
presentationEmail,
|
emailContents,
|
||||||
emailContent,
|
|
||||||
attachments,
|
attachments,
|
||||||
mailboxRole,
|
mailboxRole,
|
||||||
session,
|
session,
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
import 'package:core/core.dart';
|
|
||||||
|
|
||||||
class WebViewLoadingState extends UIState {
|
|
||||||
WebViewLoadingState();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebViewLoadCompletedState extends UIState {
|
|
||||||
WebViewLoadCompletedState();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [];
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
|
||||||
|
import 'package:core/core.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
const List<Color> _defaultColors = [Color.fromRGBO(0, 0, 0, 0.1), Color(0x44CCCCCC), Color.fromRGBO(0, 0, 0, 0.1)];
|
||||||
|
|
||||||
|
Decoration _radiusBoxDecoration({
|
||||||
|
required Animation animation,
|
||||||
|
bool hasCustomColors = false,
|
||||||
|
AlignmentGeometry beginAlign = Alignment.topLeft,
|
||||||
|
AlignmentGeometry endAlign = Alignment.bottomRight,
|
||||||
|
List<Color> colors = _defaultColors,
|
||||||
|
double radius = 10.0
|
||||||
|
}) {
|
||||||
|
return BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(radius),
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: beginAlign,
|
||||||
|
end: endAlign,
|
||||||
|
colors: hasCustomColors
|
||||||
|
? colors.map((color) {
|
||||||
|
return color;
|
||||||
|
}).toList()
|
||||||
|
: [
|
||||||
|
Color.fromRGBO(0, 0, 0, 0.1),
|
||||||
|
Color(0x32E5E5E5),
|
||||||
|
Color.fromRGBO(0, 0, 0, 0.1),
|
||||||
|
],
|
||||||
|
stops: [animation.value - 2, animation.value, animation.value + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
class AttachmentsPlaceHolderLoading extends StatefulWidget {
|
||||||
|
|
||||||
|
final ResponsiveUtils responsiveUtils;
|
||||||
|
|
||||||
|
const AttachmentsPlaceHolderLoading({
|
||||||
|
Key? key,
|
||||||
|
required this.responsiveUtils,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _AttachmentsPlaceHolderLoadingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AttachmentsPlaceHolderLoadingState extends State<AttachmentsPlaceHolderLoading> with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _animationController;
|
||||||
|
late Animation<double> _animation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_animationController = AnimationController(duration: Duration(seconds: 1), vsync: this)..repeat();
|
||||||
|
_animation = Tween<double>(begin: -2, end: 2)
|
||||||
|
.animate(CurvedAnimation(curve: Curves.easeInOutSine, parent: _animationController));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_animationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: _animation,
|
||||||
|
builder: (BuildContext context, Widget? child) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(top: 20),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(children: [
|
||||||
|
_placeHolderAttachment(context),
|
||||||
|
SizedBox(width: 16),
|
||||||
|
_placeHolderAttachment(context),
|
||||||
|
if (!widget.responsiveUtils.isMobile(context))
|
||||||
|
SizedBox(width: 16),
|
||||||
|
if (!widget.responsiveUtils.isMobile(context))
|
||||||
|
_placeHolderAttachment(context),
|
||||||
|
if (widget.responsiveUtils.isTablet(context))
|
||||||
|
SizedBox(width: 16),
|
||||||
|
if (widget.responsiveUtils.isTablet(context))
|
||||||
|
_placeHolderAttachment(context),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _placeHolderAttachment(BuildContext context) {
|
||||||
|
double width = MediaQuery.of(context).size.width;
|
||||||
|
final percentAttachment = widget.responsiveUtils.isMobile(context)
|
||||||
|
? 0.4
|
||||||
|
: widget.responsiveUtils.isTablet(context) ? 0.22 : 0.14;
|
||||||
|
return Container(
|
||||||
|
height: 55,
|
||||||
|
width: width * percentAttachment,
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16),
|
||||||
|
decoration: _radiusBoxDecoration(animation: _animation),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 24,
|
||||||
|
width: 24,
|
||||||
|
decoration: _radiusBoxDecoration(animation: _animation, radius: 12)),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Expanded(child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 5,
|
||||||
|
decoration: _radiusBoxDecoration(animation: _animation)),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Container(
|
||||||
|
height: 5,
|
||||||
|
decoration: _radiusBoxDecoration(animation: _animation))
|
||||||
|
],
|
||||||
|
))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
import 'package:core/core.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:model/model.dart';
|
||||||
|
|
||||||
|
class EmailContentItemBuilder {
|
||||||
|
|
||||||
|
final BuildContext _context;
|
||||||
|
final EmailContent _emailContent;
|
||||||
|
final Widget? loadingWidget;
|
||||||
|
|
||||||
|
EmailContentItemBuilder(
|
||||||
|
this._context,
|
||||||
|
this._emailContent,
|
||||||
|
{
|
||||||
|
this.loadingWidget
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget build() {
|
||||||
|
return Theme(
|
||||||
|
data: ThemeData(
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.transparent),
|
||||||
|
child: MediaQuery(
|
||||||
|
data: MediaQueryData(padding: EdgeInsets.zero),
|
||||||
|
child: _buildItem()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildItem() {
|
||||||
|
switch(_emailContent.type) {
|
||||||
|
case EmailContentType.textHtml:
|
||||||
|
return HtmlContentViewer(
|
||||||
|
widthContent: MediaQuery.of(_context).size.width,
|
||||||
|
contentHtml: _emailContent.content,
|
||||||
|
loadingWidget: loadingWidget,
|
||||||
|
mailtoDelegate: (uri) async {});
|
||||||
|
case EmailContentType.textPlain:
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: Text(
|
||||||
|
_emailContent.content,
|
||||||
|
style: TextStyle(fontSize: 14, color: AppColor.nameUserColor)));
|
||||||
|
case EmailContentType.other:
|
||||||
|
return SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-52
@@ -41,7 +41,7 @@ class EmailContentPlaceHolderLoading extends StatefulWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_EmailContentPlaceHolderLoadingState createState() => _EmailContentPlaceHolderLoadingState();
|
State<StatefulWidget> createState() => _EmailContentPlaceHolderLoadingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EmailContentPlaceHolderLoadingState extends State<EmailContentPlaceHolderLoading> with SingleTickerProviderStateMixin {
|
class _EmailContentPlaceHolderLoadingState extends State<EmailContentPlaceHolderLoading> with SingleTickerProviderStateMixin {
|
||||||
@@ -68,25 +68,11 @@ class _EmailContentPlaceHolderLoadingState extends State<EmailContentPlaceHolder
|
|||||||
animation: _animation,
|
animation: _animation,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(top: 20),
|
margin: EdgeInsets.only(top: 16),
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(children: [
|
|
||||||
_placeHolderAttachment(context),
|
|
||||||
SizedBox(width: 16),
|
|
||||||
_placeHolderAttachment(context),
|
|
||||||
if (!widget.responsiveUtils.isMobile(context))
|
|
||||||
SizedBox(width: 16),
|
|
||||||
if (!widget.responsiveUtils.isMobile(context))
|
|
||||||
_placeHolderAttachment(context),
|
|
||||||
if (widget.responsiveUtils.isTablet(context))
|
|
||||||
SizedBox(width: 16),
|
|
||||||
if (widget.responsiveUtils.isTablet(context))
|
|
||||||
_placeHolderAttachment(context),
|
|
||||||
]),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(right: 64),
|
margin: EdgeInsets.only(right: 64),
|
||||||
height: 10,
|
height: 10,
|
||||||
@@ -106,40 +92,4 @@ class _EmailContentPlaceHolderLoadingState extends State<EmailContentPlaceHolder
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _placeHolderAttachment(BuildContext context) {
|
|
||||||
double width = MediaQuery.of(context).size.width;
|
|
||||||
final percentAttachment = widget.responsiveUtils.isMobile(context)
|
|
||||||
? 0.4
|
|
||||||
: widget.responsiveUtils.isTablet(context) ? 0.22 : 0.14;
|
|
||||||
return Container(
|
|
||||||
height: 55,
|
|
||||||
width: width * percentAttachment,
|
|
||||||
margin: EdgeInsets.zero,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16),
|
|
||||||
decoration: _radiusBoxDecoration(animation: _animation),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
height: 24,
|
|
||||||
width: 24,
|
|
||||||
decoration: _radiusBoxDecoration(animation: _animation, radius: 12)),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
Expanded(child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
height: 5,
|
|
||||||
decoration: _radiusBoxDecoration(animation: _animation)),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
Container(
|
|
||||||
height: 5,
|
|
||||||
decoration: _radiusBoxDecoration(animation: _animation))
|
|
||||||
],
|
|
||||||
))
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user