diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 5a453dd62..7a9d70fe6 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -108,6 +108,7 @@ extension AppColor on Color { static const colorFocusButton = Color(0x14818C99); static const colorBorderEmailAddressInvalid = Color(0xFFFF3347); static const colorBgMailboxSelected = Color(0xFF99E4E8EC); + static const colorLoading = Color(0x2999A2AD); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart index 49d23af78..67960f895 100644 --- a/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart @@ -3,6 +3,8 @@ import 'package:core/data/network/dio_client.dart'; import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart'; import 'package:html/dom.dart'; +import '../html_template.dart'; + class AddTooltipLinkTransformer extends DomTransformer { const AddTooltipLinkTransformer(); @@ -29,7 +31,7 @@ class AddTooltipLinkTransformer extends DomTransformer { if (children.isEmpty && text.isNotEmpty && url != null) { final innerHtml = element.innerHtml; final tagClass = element.attributes['class']; - element.attributes['class'] = '$tagClass tooltip'; + element.attributes['class'] = '$tagClass $nameClassToolTip'; element.innerHtml = innerHtml + textHasToolTip(url); } } diff --git a/core/lib/presentation/utils/html_transformer/html_template.dart b/core/lib/presentation/utils/html_transformer/html_template.dart index 522dd0968..e3645d643 100644 --- a/core/lib/presentation/utils/html_transformer/html_template.dart +++ b/core/lib/presentation/utils/html_transformer/html_template.dart @@ -1,6 +1,8 @@ +final nameClassToolTip = 'tmail-tooltip'; + final tooltipLinkCss = ''' - .tooltip .tooltiptext { + .$nameClassToolTip .tooltiptext { visibility: hidden; max-width: 400px; background-color: black; @@ -14,7 +16,7 @@ final tooltipLinkCss = ''' position: absolute; z-index: 1; } - .tooltip:hover .tooltiptext { + .$nameClassToolTip:hover .tooltiptext { visibility: visible; } '''; diff --git a/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart b/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart index 403c0d31c..cd11be129 100644 --- a/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart +++ b/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart @@ -6,7 +6,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/html_transformer/html_template.dart'; import 'package:core/presentation/views/html_viewer/html_viewer_controller_for_web.dart'; import 'package:core/utils/app_logger.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; import 'package:universal_html/html.dart' as html; import 'package:core/presentation/utils/shims/dart_ui.dart' as ui; @@ -227,7 +227,7 @@ class _HtmlContentViewerOnWebState extends State { width: actualWidth, child: _buildWebView(), ), - if (_isLoading) Align(alignment: Alignment.center, child: _buildLoadingView()) + if (_isLoading) Align(alignment: Alignment.topCenter, child: _buildLoadingView()) ], ); } @@ -238,7 +238,7 @@ class _HtmlContentViewerOnWebState extends State { child: SizedBox( width: 30, height: 30, - child: CircularProgressIndicator(color: AppColor.colorTextButton))); + child: CupertinoActivityIndicator(color: AppColor.colorLoading))); } Widget _buildWebView() { diff --git a/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart b/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart index 56b6f6dae..9367094d6 100644 --- a/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart +++ b/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:core/core.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -11,8 +12,7 @@ import 'dart:developer' as developer; class HtmlContentViewer extends StatefulWidget { final String contentHtml; - final double widthContent; - final Widget? loadingWidget; + final double heightContent; /// Register this callback if you want a reference to the [WebViewController]. final void Function(WebViewController controller)? onCreated; @@ -28,8 +28,7 @@ class HtmlContentViewer extends StatefulWidget { const HtmlContentViewer({ Key? key, required this.contentHtml, - required this.widthContent, - this.loadingWidget, + required this.heightContent, this.onCreated, this.urlLauncherDelegate, this.mailtoDelegate, @@ -41,8 +40,7 @@ class HtmlContentViewer extends StatefulWidget { class _HtmlContentViewState extends State { - double? _webViewHeight = 1.0; - double? _webViewWidth = 1.0; + late double actualHeight; double minHeight = 100; double minWidth = 300; String? _htmlData; @@ -52,7 +50,7 @@ class _HtmlContentViewState extends State { @override void initState() { super.initState(); - _webViewWidth = widget.widthContent; + actualHeight = widget.heightContent; _htmlData = _generateHtmlDocument(widget.contentHtml); } @@ -63,29 +61,27 @@ class _HtmlContentViewState extends State { @override Widget build(BuildContext context) { - return Stack( - children: [ - SizedBox( - height: _webViewHeight, - width: _webViewWidth, - child: _buildWebView(), - ), - if (_isLoading) Align(alignment: Alignment.center, child: _buildLoadingView()) - ], - ); + return LayoutBuilder(builder: (context, constraints) { + log('_HtmlContentViewState::build(): maxWidth: ${constraints.maxWidth}'); + return Stack( + children: [ + SizedBox( + height: actualHeight, + width: constraints.maxWidth, + child: _buildWebView()), + if (_isLoading) Align(alignment: Alignment.center, child: _buildLoadingView()) + ], + ); + }); } Widget _buildLoadingView() { - if (widget.loadingWidget != null) { - return widget.loadingWidget!; - } else { - return Padding( + return Padding( padding: EdgeInsets.all(16), child: SizedBox( width: 30, height: 30, - child: CircularProgressIndicator(color: AppColor.primaryColor))); - } + child: CupertinoActivityIndicator(color: AppColor.colorLoading))); } Widget _buildWebView() { @@ -110,7 +106,7 @@ class _HtmlContentViewState extends State { final scrollHeightWithBuffer = scrollHeight + 30.0; if (scrollHeightWithBuffer > minHeight) { setState(() { - _webViewHeight = scrollHeightWithBuffer; + actualHeight = scrollHeightWithBuffer; _isLoading = false; }); } diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 92dc20cc8..95cf30f5a 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -13,10 +13,8 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_e import 'package:tmail_ui_user/features/email/presentation/email_controller.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/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/email_action_cupertino_action_sheet_action_builder.dart'; -import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_place_holder_loading_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:filesize/filesize.dart'; @@ -197,8 +195,8 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio padding: EdgeInsets.only(right: 16), child: SelectableText( '${emailController.mailboxDashBoardController.selectedEmail.value?.getEmailTitle()}', - maxLines: 3, - minLines: 1, + maxLines: kIsWeb ? 3 : null, + minLines: kIsWeb ? 1 : null, cursorColor: AppColor.colorTextButton, style: TextStyle( fontSize: 20, @@ -237,6 +235,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio Expanded(child: _buildEmailContent(context, constraints)) else _buildEmailContent(context, constraints), + SizedBox(height: 16), ], ); }) @@ -398,7 +397,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio (failure) => SizedBox.shrink(), (success) { if (success is LoadingState) { - return AttachmentsPlaceHolderLoading(responsiveUtils: responsiveUtils); + return SizedBox.shrink(); } else { final attachments = emailController.attachments.listAttachmentsDisplayedOutSide; return attachments.isNotEmpty @@ -412,9 +411,9 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio if (responsiveUtils.isMobileDevice(context)) { return 2; } else if (responsiveUtils.isTablet(context)) { - return 4; - } else { return 3; + } else { + return 4; } } @@ -439,7 +438,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio key: Key('list_attachment'), primary: false, shrinkWrap: true, - padding: EdgeInsets.only(top: isExpand ? 0 : 16), + padding: EdgeInsets.only(top: isExpand ? 0 : 16, bottom: 16), itemCount: countAttachments, gridDelegate: SliverGridDelegateFixedHeight( height: 60, @@ -523,26 +522,27 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio (failure) => SizedBox.shrink(), (success) { if (success is LoadingState) { - return EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils); + return Padding( + padding: EdgeInsets.all(16), + child: SizedBox( + width: 30, + height: 30, + child: CupertinoActivityIndicator(color: AppColor.colorLoading))); } else { if (emailController.emailContents.isNotEmpty) { - final allEmailContents = emailController.emailContents - .map((emailContent) => emailContent.asHtml) - .toList() - .join('
'); + final allEmailContents = emailController.emailContents.asHtmlString; if (kIsWeb) { return HtmlContentViewerOnWeb( widthContent: constraints.maxWidth, - heightContent: MediaQuery.of(context).size.height, + heightContent: responsiveUtils.getSizeScreenHeight(context), contentHtml: allEmailContents, controller: HtmlViewerControllerForWeb(), mailtoDelegate: (uri) => emailController.openMailToLink(uri)); } else { return HtmlContentViewer( - widthContent: MediaQuery.of(context).size.width, + heightContent: responsiveUtils.getSizeScreenHeight(context), contentHtml: allEmailContents, - loadingWidget: EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils), mailtoDelegate: (uri) async => emailController.openMailToLink(uri)); } } else { diff --git a/lib/features/email/presentation/widgets/email_content_item_builder.dart b/lib/features/email/presentation/widgets/email_content_item_builder.dart deleted file mode 100644 index 3dab7825b..000000000 --- a/lib/features/email/presentation/widgets/email_content_item_builder.dart +++ /dev/null @@ -1,60 +0,0 @@ - -import 'package:core/core.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:model/model.dart'; - -class EmailContentItemBuilder { - - final BuildContext _context; - final EmailContent _emailContent; - final Widget? loadingWidget; - final BoxConstraints _constraints; - - EmailContentItemBuilder( - this._context, - this._emailContent, - this._constraints, - { - 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: - if (kIsWeb) { - return HtmlContentViewerOnWeb( - widthContent: _constraints.maxWidth, - heightContent: MediaQuery.of(_context).size.height, - contentHtml: _emailContent.content, - controller: HtmlViewerControllerForWeb()); - } else { - return HtmlContentViewer( - widthContent: MediaQuery.of(_context).size.width, - contentHtml: _emailContent.content, - loadingWidget: loadingWidget); - } - case EmailContentType.textPlain: - return Padding( - padding: EdgeInsets.only(top: 20), - child: SelectableText( - _emailContent.content, - style: TextStyle(fontSize: 14, color: AppColor.colorNameEmail, fontWeight: FontWeight.normal))); - case EmailContentType.other: - return SizedBox.shrink(); - } - } -} \ No newline at end of file diff --git a/lib/features/thread/presentation/widgets/email_tile_builder.dart b/lib/features/thread/presentation/widgets/email_tile_builder.dart index 4b1b2914a..a36847ee8 100644 --- a/lib/features/thread/presentation/widgets/email_tile_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_builder.dart @@ -253,44 +253,51 @@ class EmailTileBuilder { paddingIconSelect: EdgeInsets.all(5)), ), if (_selectModeAll == SelectMode.INACTIVE) SizedBox(width: 10), - Container(width: 180, child: _isSearchEnabled - ? RichTextBuilder( - _getInformationSender(), - '${_searchQuery!.value}', - TextStyle(fontSize: 15, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600), - TextStyle(fontSize: 15, color: AppColor.colorNameEmail, backgroundColor: AppColor.bgWordSearch, fontWeight: FontWeight.w600)).build() - : Text('${_getInformationSender()}', - maxLines: 1, - style: TextStyle(fontSize: 15, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600)), + Container( + width: 160, + child: _isSearchEnabled + ? RichTextBuilder( + _getInformationSender(), + '${_searchQuery!.value}', + TextStyle(fontSize: 15, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600), + TextStyle(fontSize: 15, color: AppColor.colorNameEmail, backgroundColor: AppColor.bgWordSearch, fontWeight: FontWeight.w600)).build() + : Text('${_getInformationSender()}', + maxLines: 1, + overflow: kIsWeb ? null : TextOverflow.ellipsis, + style: TextStyle(fontSize: 15, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600)), ), - SizedBox(width: 10), + SizedBox(width: 24), Expanded(child: _buildSubjectAndContent()), - SizedBox(width: 10), + SizedBox(width: 16), if (_searchStatus == SearchStatus.ACTIVE && _presentationEmail.mailboxName.isNotEmpty) Container( margin: EdgeInsets.only(left: 8), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 3), - constraints: BoxConstraints(maxWidth: 100), + constraints: BoxConstraints(maxWidth: 80), decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.backgroundCounterMailboxColor), child: Text('${_presentationEmail.mailboxName}', maxLines: 1, + overflow: kIsWeb ? null : TextOverflow.ellipsis, style: TextStyle(fontSize: 10, color: AppColor.mailboxTextColor, fontWeight: FontWeight.bold), ) ), if (_presentationEmail.hasAttachment == true) Padding(padding: EdgeInsets.only(left: 8), - child: (ButtonBuilder(_imagePaths.icAttachment) - ..paddingIcon(EdgeInsets.zero) - ..size(16)) - .build()), - Padding(padding: EdgeInsets.only(right: 20, left: 8), - child: Text('${_presentationEmail.getReceivedAt(Localizations.localeOf(_context).toLanguageTag())}', - maxLines: 1, - style: TextStyle(fontSize: 13, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal))), + child: (ButtonBuilder(_imagePaths.icAttachment) + ..paddingIcon(EdgeInsets.zero) + ..size(16)) + .build()), + Padding( + padding: EdgeInsets.only(right: 20, left: 8), + child: Text('${_presentationEmail.getReceivedAt(Localizations.localeOf(_context).toLanguageTag())}', + maxLines: 1, + textAlign: TextAlign.right, + overflow: kIsWeb ? null : TextOverflow.ellipsis, + style: TextStyle(fontSize: 13, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal))), ]), if (_selectModeAll == SelectMode.INACTIVE) Padding( - padding: EdgeInsets.only(top: 10, bottom: 10, left: 70), + padding: EdgeInsets.only(top: 7.5, bottom: 7.5, left: 70), child: Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2)), ]), ); @@ -299,24 +306,24 @@ class EmailTileBuilder { Widget _buildSubjectAndContent() { return LayoutBuilder(builder: (context, constraints) { log('EmailTileBuilder::_buildSubjectAndContent(): maxWidth(Subject+Content): ${constraints.maxWidth}'); - return Row( - children: [ - Flexible( - child: Container( - constraints: BoxConstraints(maxWidth: constraints.maxWidth / 2), - child: _isSearchEnabled - ? RichTextBuilder( - '${_presentationEmail.getEmailTitle()}', - '${_searchQuery!.value}', - TextStyle(fontSize: 13, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600), - TextStyle(fontSize: 13, backgroundColor: AppColor.bgWordSearch, color: AppColor.colorNameEmail)).build() - : Text('${_presentationEmail.getEmailTitle()}', - maxLines: 1, - style: TextStyle(fontSize: 13, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600)) - ) - ), - if (_presentationEmail.getEmailTitle().isNotEmpty) SizedBox(width: 12), - Expanded(child: _isSearchEnabled + return Row(children: [ + Container( + constraints: BoxConstraints(maxWidth: constraints.maxWidth / 2), + child: _isSearchEnabled + ? RichTextBuilder( + '${_presentationEmail.getEmailTitle()}', + '${_searchQuery!.value}', + TextStyle(fontSize: 13, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600), + TextStyle(fontSize: 13, backgroundColor: AppColor.bgWordSearch, color: AppColor.colorNameEmail)).build() + : Text('${_presentationEmail.getEmailTitle()}', + maxLines: 1, + overflow: kIsWeb ? null : TextOverflow.ellipsis, + style: TextStyle(fontSize: 13, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600)) + ), + if (_presentationEmail.getEmailTitle().isNotEmpty) SizedBox(width: 12), + Expanded( + child: Container( + child: _isSearchEnabled ? RichTextBuilder( '${_presentationEmail.getPartialContent()}', '${_searchQuery!.value}', @@ -324,9 +331,11 @@ class EmailTileBuilder { TextStyle(fontSize: 13, color: AppColor.colorContentEmail, backgroundColor: AppColor.bgWordSearch)).build() : Text('${_presentationEmail.getPartialContent()}', maxLines: 1, - style: TextStyle(fontSize: 13, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal))), - ] - ); + overflow: kIsWeb ? null : TextOverflow.ellipsis, + style: TextStyle(fontSize: 13, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal)) + ) + ), + ]); }); }