TF-3427 Fix subject was not in print & click outside context menu can not close

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-01-17 18:30:29 +07:00
committed by Dat H. Pham
parent 778c138a10
commit 395b24e58f
18 changed files with 356 additions and 261 deletions
@@ -0,0 +1,59 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class HighlightSVGIconOnHover extends StatefulWidget {
final String icon;
final double size;
final double borderRadius;
final Color? iconColor;
final EdgeInsetsGeometry? padding;
final String? tooltipMessage;
const HighlightSVGIconOnHover({
Key? key,
required this.icon,
this.size = 20.0,
this.borderRadius = 5.0,
this.iconColor,
this.padding,
this.tooltipMessage,
}) : super(key: key);
@override
State<HighlightSVGIconOnHover> createState() => _HighlightSVGIconOnHoverState();
}
class _HighlightSVGIconOnHoverState extends State<HighlightSVGIconOnHover> {
bool _isHovered = false;
@override
Widget build(BuildContext context) {
final child = MouseRegion(
onEnter: (_) => setState(() => _isHovered = true),
onExit: (_) => setState(() => _isHovered = false),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)),
color: _isHovered ? Theme.of(context).hoverColor : null,
),
padding: widget.padding ?? const EdgeInsets.all(5),
child: SvgPicture.asset(
widget.icon,
width: widget.size,
height: widget.size,
fit: BoxFit.fill,
colorFilter: widget.iconColor?.asFilter(),
),
),
);
if (widget.tooltipMessage != null) {
return Tooltip(
message: widget.tooltipMessage,
child: child,
);
}
return child;
}
}
+34 -31
View File
@@ -34,37 +34,40 @@ class PopupItemWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PointerInterceptor(
child: InkWell(
onTap: onCallbackAction,
child: Container(
height: PopupItemWidgetStyle.height,
constraints: const BoxConstraints(minWidth: PopupItemWidgetStyle.minWidth),
padding: padding,
child: Row(children: [
SvgPicture.asset(
_iconAction,
width: iconSize ?? PopupItemWidgetStyle.iconSize,
height: iconSize ?? PopupItemWidgetStyle.iconSize,
fit: BoxFit.fill,
colorFilter: colorIcon?.asFilter()
),
const SizedBox(width: PopupItemWidgetStyle.space),
Expanded(child: Text(
_nameAction,
style: styleName ?? PopupItemWidgetStyle.labelTextStyle
)),
if (isSelected == true && selectedIcon != null)
Padding(
padding: PopupItemWidgetStyle.iconSelectedPadding,
child: SvgPicture.asset(
selectedIcon!,
width: PopupItemWidgetStyle.selectedIconSize,
height: PopupItemWidgetStyle.selectedIconSize,
fit: BoxFit.fill
),
)
]),
)
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: onCallbackAction,
child: Container(
height: PopupItemWidgetStyle.height,
constraints: const BoxConstraints(minWidth: PopupItemWidgetStyle.minWidth),
padding: padding,
child: Row(children: [
SvgPicture.asset(
_iconAction,
width: iconSize ?? PopupItemWidgetStyle.iconSize,
height: iconSize ?? PopupItemWidgetStyle.iconSize,
fit: BoxFit.fill,
colorFilter: colorIcon?.asFilter()
),
const SizedBox(width: PopupItemWidgetStyle.space),
Expanded(child: Text(
_nameAction,
style: styleName ?? PopupItemWidgetStyle.labelTextStyle
)),
if (isSelected == true && selectedIcon != null)
Padding(
padding: PopupItemWidgetStyle.iconSelectedPadding,
child: SvgPicture.asset(
selectedIcon!,
width: PopupItemWidgetStyle.selectedIconSize,
height: PopupItemWidgetStyle.selectedIconSize,
fit: BoxFit.fill
),
)
]),
)
),
),
);
}
@@ -11,6 +11,9 @@ class PopupMenuOverlayWidget extends StatelessWidget {
final double? borderRadius;
final Color? backgroundColor;
final CustomPopupMenuController? controller;
final bool arrangeAsList;
final PreferredPosition? position;
final EdgeInsetsGeometry? padding;
const PopupMenuOverlayWidget({
Key? key,
@@ -20,6 +23,9 @@ class PopupMenuOverlayWidget extends StatelessWidget {
this.borderRadius,
this.backgroundColor,
this.controller,
this.position = PreferredPosition.bottom,
this.arrangeAsList = false,
this.padding,
}) : super(key: key);
@override
@@ -36,14 +42,17 @@ class PopupMenuOverlayWidget extends StatelessWidget {
decoration: BoxDecoration(
color: backgroundColor ?? Colors.white,
borderRadius: BorderRadius.circular(borderRadius ?? 12)),
padding: const EdgeInsets.symmetric(horizontal: 5),
child: Wrap(children: listButtonAction),
padding: padding,
clipBehavior: Clip.antiAlias,
child: arrangeAsList
? IntrinsicWidth(child: Column(children: listButtonAction))
: Wrap(children: listButtonAction)
),
),
);
},
pressType: PressType.singleClick,
position: PreferredPosition.bottom,
position: position,
barrierColor: Colors.transparent,
arrowSize: 0.0,
verticalMargin: 8,
@@ -4,6 +4,7 @@ import 'dart:math';
import 'package:collection/collection.dart';
import 'package:core/core.dart';
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
import 'package:dartz/dartz.dart';
import 'package:desktop_drop/desktop_drop.dart';
import 'package:dio/dio.dart';
@@ -184,6 +185,7 @@ class ComposerController extends BaseController
RichTextMobileTabletController? richTextMobileTabletController;
RichTextWebController? richTextWebController;
CustomPopupMenuController? menuMoreOptionController;
final ScrollController scrollController = ScrollController();
final ScrollController scrollControllerEmailAddress = ScrollController();
@@ -237,6 +239,7 @@ class ComposerController extends BaseController
if (PlatformInfo.isWeb) {
richTextWebController = getBinding<RichTextWebController>();
responsiveContainerKey = GlobalKey();
menuMoreOptionController = CustomPopupMenuController();
} else {
richTextMobileTabletController = getBinding<RichTextMobileTabletController>();
}
@@ -277,6 +280,8 @@ class ComposerController extends BaseController
if (PlatformInfo.isWeb) {
richTextWebController = null;
responsiveContainerKey = null;
menuMoreOptionController?.dispose();
menuMoreOptionController = null;
} else {
richTextMobileTabletController = null;
}
@@ -476,7 +481,7 @@ class ComposerController extends BaseController
outboxMailboxId: mailboxDashBoardController.outboxMailbox?.mailboxId,
sentMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent],
draftsMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleDrafts],
draftsEmailId: _getDraftEmailId(),
draftsEmailId: getDraftEmailId(),
answerForwardEmailId: composerArguments.value!.presentationEmail?.id,
unsubscribeEmailId: composerArguments.value!.previousEmailId,
messageId: composerArguments.value!.messageId,
@@ -1046,7 +1051,7 @@ class ComposerController extends BaseController
inlineAttachments: uploadController.mapInlineAttachments,
outboxMailboxId: mailboxDashBoardController.outboxMailbox?.mailboxId,
sentMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent],
draftsEmailId: _getDraftEmailId(),
draftsEmailId: getDraftEmailId(),
answerForwardEmailId: composerArguments.value!.presentationEmail?.id,
unsubscribeEmailId: composerArguments.value!.previousEmailId,
messageId: composerArguments.value!.messageId,
@@ -2000,6 +2005,9 @@ class ComposerController extends BaseController
FocusManager.instance.primaryFocus?.unfocus();
richTextWebController?.editorController.setFocus();
richTextWebController?.closeAllMenuPopup();
if (menuMoreOptionController?.menuIsShowing == true) {
menuMoreOptionController?.hideMenu();
}
}
void handleOnMouseDownHtmlEditorWeb() {
@@ -2277,7 +2285,7 @@ class ComposerController extends BaseController
popBack();
final emailContent = await getContentInEditor();
final draftEmailId = _getDraftEmailId();
final draftEmailId = getDraftEmailId();
log('ComposerController::_handleSaveMessageToDraft: draftEmailId = $draftEmailId');
final cancelToken = CancelToken();
final resultState = await _showSavingMessageToDraftsDialog(
@@ -2306,7 +2314,7 @@ class ComposerController extends BaseController
}
}
EmailId? _getDraftEmailId() {
EmailId? getDraftEmailId() {
if (_emailIdEditing != null &&
_emailIdEditing != composerArguments.value!.presentationEmail?.id) {
return _emailIdEditing;
@@ -48,6 +48,7 @@ class ComposerView extends GetWidget<ComposerController> {
children: [
if (controller.responsiveUtils.isLandscapeMobile(context))
Obx(() => LandscapeAppBarComposerWidget(
imagePaths: controller.imagePaths,
isSendButtonEnabled: controller.isEnableEmailSendButton.value,
onCloseViewAction: () => controller.handleClickCloseComposer(context),
sendMessageAction: () => controller.handleClickSendButton(context),
@@ -73,6 +74,7 @@ class ComposerView extends GetWidget<ComposerController> {
))
else
Obx(() => AppBarComposerWidget(
imagePaths: controller.imagePaths,
isSendButtonEnabled: controller.isEnableEmailSendButton.value,
onCloseViewAction: () => controller.handleClickCloseComposer(context),
sendMessageAction: () => controller.handleClickSendButton(context),
@@ -1,11 +1,9 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/views/responsive/responsive_widget.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/composer_print_draft_extension.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
@@ -26,8 +24,6 @@ import 'package:tmail_ui_user/features/composer/presentation/widgets/web/from_co
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/local_file_drop_zone_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/toolbar_rich_text_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class ComposerView extends GetWidget<ComposerController> {
@@ -50,18 +46,18 @@ class ComposerView extends GetWidget<ComposerController> {
isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled,
openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
isSendButtonEnabled: controller.isEnableEmailSendButton.value,
hasRequestReadReceipt: controller.hasRequestReadReceipt.value,
isPrintDraftEnabled: controller.isEmailChanged.value,
menuMoreOptionController: controller.menuMoreOptionController!,
onCloseViewAction: () => controller.handleClickCloseComposer(context),
attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
sendMessageAction: () => controller.handleClickSendButton(context),
openContextMenuAction: (position) {
controller.openPopupMenuAction(
context,
position,
_createMoreOptionPopupItems(context),
radius: ComposerStyle.popupMenuRadius
);
},
toggleCodeViewAction: controller.richTextWebController!.toggleCodeView,
printDraftAction: () => controller.printDraft(context),
toggleRequestReadReceiptAction: () => controller.toggleRequestReadReceipt(context),
saveToDraftsAction: () => controller.handleClickSaveAsDraftsButton(context),
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
)),
ConstrainedBox(
constraints: BoxConstraints(
@@ -523,14 +519,10 @@ class ComposerView extends GetWidget<ComposerController> {
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
sendMessageAction: () => controller.handleClickSendButton(context),
isPrintDraftEnabled: controller.isEmailChanged.isTrue,
openContextMenuAction: (position) {
controller.openPopupMenuAction(
context,
position,
_createMoreOptionPopupItemsOnDesktop(context),
radius: ComposerStyle.popupMenuRadius,
);
},
toggleCodeViewAction: controller.richTextWebController!.toggleCodeView,
menuMoreOptionController: controller.menuMoreOptionController!,
printDraftAction: () => controller.printDraft(context),
toggleRequestReadReceiptAction: () => controller.toggleRequestReadReceipt(context),
)),
],
),
@@ -810,14 +802,10 @@ class ComposerView extends GetWidget<ComposerController> {
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
sendMessageAction: () => controller.handleClickSendButton(context),
isPrintDraftEnabled: controller.isEmailChanged.isTrue,
openContextMenuAction: (position) {
controller.openPopupMenuAction(
context,
position,
_createMoreOptionPopupItemsOnDesktop(context),
radius: ComposerStyle.popupMenuRadius,
);
},
toggleCodeViewAction: controller.richTextWebController!.toggleCodeView,
menuMoreOptionController: controller.menuMoreOptionController!,
printDraftAction: () => controller.printDraft(context),
toggleRequestReadReceiptAction: () => controller.toggleRequestReadReceipt(context),
)),
],
),
@@ -877,136 +865,4 @@ class ComposerView extends GetWidget<ComposerController> {
)
);
}
List<PopupMenuEntry> _createMoreOptionPopupItems(BuildContext context) {
return [
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icStyleCodeView,
AppLocalizations.of(context).embedCode,
styleName: ComposerStyle.popupItemTextStyle,
colorIcon: ComposerStyle.popupItemIconColor,
padding: ComposerStyle.popupItemPadding,
selectedIcon: controller.imagePaths.icFilterSelected,
isSelected: controller.richTextWebController?.codeViewEnabled,
onCallbackAction: () {
popBack();
controller.richTextWebController?.toggleCodeView();
}
)
),
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icReadReceipt,
AppLocalizations.of(context).requestReadReceipt,
styleName: ComposerStyle.popupItemTextStyle,
padding: ComposerStyle.popupItemPadding,
colorIcon: ComposerStyle.popupItemIconColor,
selectedIcon: controller.imagePaths.icFilterSelected,
isSelected: controller.hasRequestReadReceipt.value,
onCallbackAction: () {
popBack();
controller.toggleRequestReadReceipt(context);
}
)
),
if (controller.isEmailChanged.isTrue)
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icPrinter,
AppLocalizations.of(context).print,
colorIcon: AppColor.steelGrayA540,
styleName: ComposerStyle.popupItemTextStyle,
padding: ComposerStyle.popupItemPadding,
onCallbackAction: () {
popBack();
controller.printDraft(context);
},
),
),
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icSaveToDraft,
AppLocalizations.of(context).saveAsDraft,
colorIcon: ComposerStyle.popupItemIconColor,
styleName: ComposerStyle.popupItemTextStyle,
padding: ComposerStyle.popupItemPadding,
onCallbackAction: () {
popBack();
controller.handleClickSaveAsDraftsButton(context);
}
)
),
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icDeleteMailbox,
AppLocalizations.of(context).delete,
colorIcon: ComposerStyle.popupItemIconColor,
styleName: ComposerStyle.popupItemTextStyle,
padding: ComposerStyle.popupItemPadding,
onCallbackAction: () {
popBack();
controller.handleClickDeleteComposer(context);
},
)
),
];
}
List<PopupMenuEntry> _createMoreOptionPopupItemsOnDesktop(BuildContext context) {
return [
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icStyleCodeView,
AppLocalizations.of(context).embedCode,
styleName: ComposerStyle.popupItemTextStyle,
colorIcon: ComposerStyle.popupItemIconColor,
padding: ComposerStyle.popupItemPadding,
selectedIcon: controller.imagePaths.icFilterSelected,
isSelected: controller.richTextWebController?.codeViewEnabled,
onCallbackAction: () {
popBack();
controller.richTextWebController?.toggleCodeView();
},
),
),
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icReadReceipt,
AppLocalizations.of(context).requestReadReceipt,
styleName: ComposerStyle.popupItemTextStyle,
padding: ComposerStyle.popupItemPadding,
colorIcon: ComposerStyle.popupItemIconColor,
selectedIcon: controller.imagePaths.icFilterSelected,
isSelected: controller.hasRequestReadReceipt.value,
onCallbackAction: () {
popBack();
controller.toggleRequestReadReceipt(context);
},
),
),
if (controller.isEmailChanged.isTrue)
PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemWidget(
controller.imagePaths.icPrinter,
AppLocalizations.of(context).print,
colorIcon: ComposerStyle.popupItemIconColor,
styleName: ComposerStyle.popupItemTextStyle,
padding: ComposerStyle.popupItemPadding,
onCallbackAction: () {
popBack();
controller.printDraft(context);
},
),
),
];
}
}
@@ -4,6 +4,7 @@ import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/utils/app_logger.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/extensions/identity_extension.dart';
import 'package:model/extensions/list_email_address_extension.dart';
import 'package:model/extensions/presentation_email_extension.dart';
@@ -13,6 +14,7 @@ import 'package:tmail_ui_user/features/composer/presentation/composer_controller
import 'package:tmail_ui_user/features/composer/presentation/model/draft_email_print.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/print_draft_dialog_view.dart';
import 'package:tmail_ui_user/features/email/domain/state/print_email_state.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension ComposerPrintDraftExtension on ComposerController {
@@ -59,8 +61,26 @@ extension ComposerPrintDraftExtension on ComposerController {
required Locale locale,
required String emailContent,
}) {
final presentationEmail = composerArguments.value!.presentationEmail;
final presentationEmail = composerArguments.value?.presentationEmail;
final emailActionType = composerArguments.value?.emailActionType;
String receiveTime = '';
if (emailActionType == EmailActionType.editDraft) {
receiveTime = presentationEmail?.getReceivedAt(
locale.toLanguageTag(),
pattern: presentationEmail.receivedAt
?.value
.toLocal()
.toPatternForPrinting(locale.toLanguageTag()),
) ?? '';
} else {
final currentTime = DateTime.now();
receiveTime = currentTime.formatDate(
locale: locale.toLanguageTag(),
pattern: currentTime.toPatternForPrinting(locale.toLanguageTag()),
);
}
log('ComposerPrintDraftExtension::_showPrintDraftsDialog:receiveTime = $receiveTime | emailActionType = $emailActionType');
final childWidget = PointerInterceptor(
child: PrintDraftDialogView(
emailPrint: DraftEmailPrint(
@@ -68,7 +88,6 @@ extension ComposerPrintDraftExtension on ComposerController {
userName: mailboxDashBoardController.userEmail,
attachments: uploadController.allAttachmentsUploaded,
emailContent: emailContent,
locale: locale.toLanguageTag(),
fromPrefix: appLocalizations.from_email_address_prefix,
toPrefix: appLocalizations.to_email_address_prefix,
ccPrefix: appLocalizations.cc_email_address_prefix,
@@ -79,14 +98,8 @@ extension ComposerPrintDraftExtension on ComposerController {
ccAddress: listCcEmailAddress.toSet().toEscapeHtmlStringUseCommaSeparator(),
bccAddress: listBccEmailAddress.toSet().toEscapeHtmlStringUseCommaSeparator(),
sender: identitySelected.value?.toEmailAddress(),
receiveTime: presentationEmail?.getReceivedAt(
locale.toLanguageTag(),
pattern: presentationEmail.receivedAt
?.value
.toLocal()
.toPatternForPrinting(locale.toLanguageTag()),
) ?? '',
subject: presentationEmail?.subject,
receiveTime: receiveTime,
subject: subjectEmail.value ?? '',
),
printEmailInteractor: printEmailInteractor,
),
@@ -324,6 +324,7 @@ mixin RichTextButtonMixin {
_imagePaths,
(paragraph) => richTextController.applyParagraphType(paragraph)))
.toList(),
padding: const EdgeInsets.symmetric(horizontal: 5),
iconButton: buildWrapIconStyleText(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
spacing: 3,
@@ -344,6 +345,7 @@ mixin RichTextButtonMixin {
_imagePaths,
(orderType) => richTextController.applyOrderListType(orderType)))
.toList(),
padding: const EdgeInsets.symmetric(horizontal: 5),
iconButton: buildWrapIconStyleText(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
spacing: 3,
@@ -6,7 +6,6 @@ class DraftEmailPrint extends EmailPrint {
required super.appName,
required super.userName,
required super.emailContent,
required super.locale,
required super.fromPrefix,
required super.toPrefix,
required super.ccPrefix,
@@ -10,11 +10,19 @@ class MobileAppBarComposerWidgetStyle {
static const double richTextIconSize = 28;
static const Color backgroundColor = AppColor.colorComposerAppBar;
static const Color iconColor = AppColor.colorMobileRichButtonComposer;
static const Color iconColor = AppColor.steelGrayA540;
static const Color popupItemIconColor = AppColor.steelGrayA540;
static const Color selectedBackgroundColor = AppColor.colorSelected;
static const Color selectedIconColor = AppColor.primaryColor;
static const Color selectedIconColor = AppColor.blue700;
static const EdgeInsetsGeometry padding = EdgeInsetsDirectional.symmetric(horizontal: 12);
static const EdgeInsetsGeometry iconPadding = EdgeInsetsDirectional.all(3);
static const EdgeInsetsGeometry richTextIconPadding = EdgeInsetsDirectional.all(5);
static const EdgeInsetsGeometry popupItemPadding = EdgeInsetsDirectional.symmetric(horizontal: 12);
static const TextStyle popupItemTextStyle = TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w500,
);
}
@@ -22,9 +22,16 @@ class BottomBarComposerWidgetStyle {
static const EdgeInsetsGeometry iconPadding = EdgeInsetsDirectional.all(5);
static const EdgeInsetsGeometry sendButtonPadding = EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 24);
static const EdgeInsetsGeometry richTextIconPadding = EdgeInsetsDirectional.all(2);
static const EdgeInsetsGeometry popupItemPadding = EdgeInsetsDirectional.symmetric(horizontal: 12);
static const TextStyle sendButtonTextStyle = TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15,
color: Colors.white,
);
static const TextStyle popupItemTextStyle = TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w500,
);
}
@@ -1,13 +1,14 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnOpenContextMenuAction = Function(RelativeRect position);
class AppBarComposerWidget extends StatelessWidget {
final ImagePaths imagePaths;
final bool isSendButtonEnabled;
final bool isNetworkConnectionAvailable;
final VoidCallback onCloseViewAction;
@@ -17,10 +18,9 @@ class AppBarComposerWidget extends StatelessWidget {
final VoidCallback openRichToolbarAction;
final OnOpenContextMenuAction openContextMenuAction;
final _imagePaths = Get.find<ImagePaths>();
AppBarComposerWidget({
const AppBarComposerWidget({
super.key,
required this.imagePaths,
required this.isSendButtonEnabled,
required this.onCloseViewAction,
required this.sendMessageAction,
@@ -40,7 +40,7 @@ class AppBarComposerWidget extends StatelessWidget {
child: Row(
children: [
TMailButtonWidget.fromIcon(
icon: _imagePaths.icCancel,
icon: imagePaths.icCancel,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).saveAndClose,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
@@ -49,7 +49,7 @@ class AppBarComposerWidget extends StatelessWidget {
),
const Spacer(),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icRichToolbar,
icon: imagePaths.icRichToolbar,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.richTextIconSize,
@@ -61,7 +61,7 @@ class AppBarComposerWidget extends StatelessWidget {
...[
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icAttachFile,
icon: imagePaths.icAttachFile,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
@@ -70,7 +70,7 @@ class AppBarComposerWidget extends StatelessWidget {
),
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icInsertImage,
icon: imagePaths.icInsertImage,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
@@ -81,8 +81,8 @@ class AppBarComposerWidget extends StatelessWidget {
],
TMailButtonWidget.fromIcon(
icon: isSendButtonEnabled
? _imagePaths.icSendMobile
: _imagePaths.icSendDisable,
? imagePaths.icSendMobile
: imagePaths.icSendDisable,
backgroundColor: Colors.transparent,
padding: MobileAppBarComposerWidgetStyle.iconPadding,
iconSize: MobileAppBarComposerWidgetStyle.sendButtonIconSize,
@@ -91,7 +91,7 @@ class AppBarComposerWidget extends StatelessWidget {
),
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icMore,
icon: imagePaths.icMore,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
padding: MobileAppBarComposerWidgetStyle.iconPadding,
@@ -1,13 +1,13 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/app_bar_composer_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class LandscapeAppBarComposerWidget extends StatelessWidget {
final ImagePaths imagePaths;
final bool isSendButtonEnabled;
final bool isNetworkConnectionAvailable;
final VoidCallback onCloseViewAction;
@@ -17,10 +17,9 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
final VoidCallback openRichToolbarAction;
final OnOpenContextMenuAction openContextMenuAction;
final _imagePaths = Get.find<ImagePaths>();
LandscapeAppBarComposerWidget({
const LandscapeAppBarComposerWidget({
super.key,
required this.imagePaths,
required this.isSendButtonEnabled,
required this.onCloseViewAction,
required this.sendMessageAction,
@@ -43,7 +42,7 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
child: Row(
children: [
TMailButtonWidget.fromIcon(
icon: _imagePaths.icCancel,
icon: imagePaths.icCancel,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).saveAndClose,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
@@ -52,7 +51,7 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
),
const Spacer(),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icRichToolbar,
icon: imagePaths.icRichToolbar,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.richTextIconSize,
@@ -64,7 +63,7 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
...[
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icAttachFile,
icon: imagePaths.icAttachFile,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
@@ -73,7 +72,7 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
),
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icInsertImage,
icon: imagePaths.icInsertImage,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
@@ -84,8 +83,8 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
],
TMailButtonWidget.fromIcon(
icon: isSendButtonEnabled
? _imagePaths.icSendMobile
: _imagePaths.icSendDisable,
? imagePaths.icSendMobile
: imagePaths.icSendDisable,
backgroundColor: Colors.transparent,
padding: MobileAppBarComposerWidgetStyle.iconPadding,
iconSize: MobileAppBarComposerWidgetStyle.sendButtonIconSize,
@@ -94,7 +93,7 @@ class LandscapeAppBarComposerWidget extends StatelessWidget {
),
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: _imagePaths.icMore,
icon: imagePaths.icMore,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
padding: MobileAppBarComposerWidgetStyle.iconPadding,
@@ -1,8 +1,11 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/base/widget/highlight_svg_icon_on_hover.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/web/bottom_bar_composer_widget_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class BottomBarComposerWidget extends StatelessWidget {
@@ -12,13 +15,16 @@ class BottomBarComposerWidget extends StatelessWidget {
final bool isPrintDraftEnabled;
final bool isFormattingOptionsEnabled;
final bool hasReadReceipt;
final CustomPopupMenuController menuMoreOptionController;
final VoidCallback openRichToolbarAction;
final VoidCallback attachFileAction;
final VoidCallback insertImageAction;
final VoidCallback deleteComposerAction;
final VoidCallback saveToDraftAction;
final VoidCallback sendMessageAction;
final OnOpenContextMenuAction openContextMenuAction;
final VoidCallback toggleCodeViewAction;
final VoidCallback toggleRequestReadReceiptAction;
final VoidCallback printDraftAction;
const BottomBarComposerWidget({
super.key,
@@ -27,13 +33,16 @@ class BottomBarComposerWidget extends StatelessWidget {
required this.isPrintDraftEnabled,
required this.isFormattingOptionsEnabled,
required this.hasReadReceipt,
required this.menuMoreOptionController,
required this.openRichToolbarAction,
required this.attachFileAction,
required this.insertImageAction,
required this.deleteComposerAction,
required this.saveToDraftAction,
required this.sendMessageAction,
required this.openContextMenuAction,
required this.toggleCodeViewAction,
required this.toggleRequestReadReceiptAction,
required this.printDraftAction,
});
@override
@@ -84,13 +93,56 @@ class BottomBarComposerWidget extends StatelessWidget {
),
),
const SizedBox(width: BottomBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: imagePaths.icMore,
iconColor: BottomBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: BottomBarComposerWidgetStyle.iconSize,
tooltipMessage: AppLocalizations.of(context).more,
onTapActionAtPositionCallback: openContextMenuAction,
PopupMenuOverlayWidget(
controller: menuMoreOptionController,
iconButton: HighlightSVGIconOnHover(
icon: imagePaths.icMore,
size: BottomBarComposerWidgetStyle.iconSize,
iconColor: BottomBarComposerWidgetStyle.iconColor,
tooltipMessage: AppLocalizations.of(context).more,
),
listButtonAction: [
PopupItemWidget(
imagePaths.icStyleCodeView,
AppLocalizations.of(context).embedCode,
styleName: BottomBarComposerWidgetStyle.popupItemTextStyle,
colorIcon: BottomBarComposerWidgetStyle.iconColor,
padding: BottomBarComposerWidgetStyle.popupItemPadding,
selectedIcon: imagePaths.icFilterSelected,
isSelected: isCodeViewEnabled,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
toggleCodeViewAction();
},
),
PopupItemWidget(
imagePaths.icReadReceipt,
AppLocalizations.of(context).requestReadReceipt,
styleName: BottomBarComposerWidgetStyle.popupItemTextStyle,
padding: BottomBarComposerWidgetStyle.popupItemPadding,
colorIcon: BottomBarComposerWidgetStyle.iconColor,
selectedIcon: imagePaths.icFilterSelected,
isSelected: hasReadReceipt,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
toggleRequestReadReceiptAction();
},
),
if (isPrintDraftEnabled)
PopupItemWidget(
imagePaths.icPrinter,
AppLocalizations.of(context).print,
colorIcon: BottomBarComposerWidgetStyle.iconColor,
styleName: BottomBarComposerWidgetStyle.popupItemTextStyle,
padding: BottomBarComposerWidgetStyle.popupItemPadding,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
printDraftAction();
},
),
],
arrangeAsList: true,
position: null,
),
const Spacer(),
TMailButtonWidget.fromIcon(
@@ -1,23 +1,32 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/base/widget/highlight_svg_icon_on_hover.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnOpenContextMenuAction = Function(RelativeRect position);
class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
final ImagePaths imagePaths;
final bool isCodeViewEnabled;
final bool isSendButtonEnabled;
final bool isFormattingOptionsEnabled;
final bool hasRequestReadReceipt;
final bool isPrintDraftEnabled;
final CustomPopupMenuController menuMoreOptionController;
final VoidCallback onCloseViewAction;
final VoidCallback attachFileAction;
final VoidCallback insertImageAction;
final VoidCallback sendMessageAction;
final OnOpenContextMenuAction openContextMenuAction;
final VoidCallback openRichToolbarAction;
final VoidCallback toggleCodeViewAction;
final VoidCallback toggleRequestReadReceiptAction;
final VoidCallback printDraftAction;
final VoidCallback saveToDraftsAction;
final VoidCallback deleteComposerAction;
const MobileResponsiveAppBarComposerWidget({
super.key,
@@ -25,12 +34,19 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
required this.isCodeViewEnabled,
required this.isFormattingOptionsEnabled,
required this.isSendButtonEnabled,
required this.hasRequestReadReceipt,
required this.isPrintDraftEnabled,
required this.menuMoreOptionController,
required this.openRichToolbarAction,
required this.onCloseViewAction,
required this.attachFileAction,
required this.insertImageAction,
required this.sendMessageAction,
required this.openContextMenuAction,
required this.toggleCodeViewAction,
required this.toggleRequestReadReceiptAction,
required this.printDraftAction,
required this.saveToDraftsAction,
required this.deleteComposerAction,
});
@override
@@ -94,13 +110,78 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
onTapActionCallback: sendMessageAction,
),
const SizedBox(width: MobileAppBarComposerWidgetStyle.space),
TMailButtonWidget.fromIcon(
icon: imagePaths.icMore,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
backgroundColor: Colors.transparent,
iconSize: MobileAppBarComposerWidgetStyle.iconSize,
tooltipMessage: AppLocalizations.of(context).more,
onTapActionAtPositionCallback: openContextMenuAction,
PopupMenuOverlayWidget(
controller: menuMoreOptionController,
iconButton: HighlightSVGIconOnHover(
icon: imagePaths.icMore,
size: MobileAppBarComposerWidgetStyle.iconSize,
iconColor: MobileAppBarComposerWidgetStyle.iconColor,
tooltipMessage: AppLocalizations.of(context).more,
),
listButtonAction: [
PopupItemWidget(
imagePaths.icStyleCodeView,
AppLocalizations.of(context).embedCode,
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
colorIcon: MobileAppBarComposerWidgetStyle.iconColor,
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
selectedIcon: imagePaths.icFilterSelected,
isSelected: isCodeViewEnabled,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
toggleCodeViewAction();
},
),
PopupItemWidget(
imagePaths.icReadReceipt,
AppLocalizations.of(context).requestReadReceipt,
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
selectedIcon: imagePaths.icFilterSelected,
isSelected: hasRequestReadReceipt,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
toggleRequestReadReceiptAction();
},
),
if (isPrintDraftEnabled)
PopupItemWidget(
imagePaths.icPrinter,
AppLocalizations.of(context).print,
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
printDraftAction();
},
),
PopupItemWidget(
imagePaths.icSaveToDraft,
AppLocalizations.of(context).saveAsDraft,
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
saveToDraftsAction();
},
),
PopupItemWidget(
imagePaths.icDeleteMailbox,
AppLocalizations.of(context).delete,
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
onCallbackAction: () {
menuMoreOptionController.hideMenu();
deleteComposerAction();
},
),
],
arrangeAsList: true,
position: null,
),
],
),
@@ -212,6 +212,7 @@ class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin
_imagePaths,
(paragraph) => richTextWebController.applyParagraphType(paragraph)))
.toList(),
padding: const EdgeInsets.symmetric(horizontal: 5),
iconButton: buildWrapIconStyleText(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
spacing: 3,
@@ -235,6 +236,7 @@ class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin
_imagePaths,
(orderType) => richTextWebController.applyOrderListType(orderType)))
.toList(),
padding: const EdgeInsets.symmetric(horizontal: 5),
iconButton: buildWrapIconStyleText(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
spacing: 3,
@@ -6,7 +6,6 @@ class EmailPrint with EquatableMixin {
final String appName;
final String userName;
final String emailContent;
final String locale;
final String toPrefix;
final String fromPrefix;
final String ccPrefix;
@@ -26,7 +25,6 @@ class EmailPrint with EquatableMixin {
required this.appName,
required this.userName,
required this.emailContent,
required this.locale,
required this.fromPrefix,
required this.toPrefix,
required this.ccPrefix,
@@ -48,7 +46,6 @@ class EmailPrint with EquatableMixin {
appName,
userName,
emailContent,
locale,
fromPrefix,
toPrefix,
ccPrefix,
@@ -74,7 +71,6 @@ extension EmailPrintExtension on EmailPrint {
emailContent: newEmailContent,
titleAttachment: titleAttachment,
receiveTime: receiveTime,
locale: locale,
fromPrefix: fromPrefix,
toPrefix: toPrefix,
ccPrefix: ccPrefix,
@@ -1752,7 +1752,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
userName: mailboxDashBoardController.userEmail,
attachments: currentEmailLoaded.value!.attachments,
emailContent: currentEmailLoaded.value!.htmlContent,
locale: locale.toLanguageTag(),
fromPrefix: appLocalizations.from_email_address_prefix,
toPrefix: appLocalizations.to_email_address_prefix,
ccPrefix: appLocalizations.cc_email_address_prefix,