diff --git a/assets/images/ic_mark_as_important.svg b/assets/images/ic_mark_as_important.svg new file mode 100644 index 000000000..728317347 --- /dev/null +++ b/assets/images/ic_mark_as_important.svg @@ -0,0 +1,5 @@ + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 7f1acc88b..bfcba1b50 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -226,6 +226,7 @@ class ImagePaths { String get icCopy => _getImagePath('ic_copy.svg'); String get icSubaddressingAllow => _getImagePath('ic_subaddressing_allow.svg'); String get icSubaddressingDisallow => _getImagePath('ic_subaddressing_disallow.svg'); + String get icMarkAsImportant => _getImagePath('ic_mark_as_important.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index f9780b057..5777e1323 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -137,6 +137,7 @@ class ComposerController extends BaseController final identitySelected = Rxn(); final listFromIdentities = RxList(); final isEmailChanged = Rx(false); + final isMarkAsImportant = Rx(false); final LocalFilePickerInteractor _localFilePickerInteractor; final LocalImagePickerInteractor _localImagePickerInteractor; diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index 8f52c5a72..5d9b91c28 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -8,6 +8,7 @@ import 'package:get/get.dart'; import 'package:model/email/prefix_email_address.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/mark_as_important_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart'; @@ -452,11 +453,14 @@ class ComposerView extends GetWidget { ) ), Obx(() => TabletBottomBarComposerWidget( + imagePaths: controller.imagePaths, hasReadReceipt: controller.hasRequestReadReceipt.value, + isMarkAsImportant: controller.isMarkAsImportant.value, deleteComposerAction: () => controller.handleClickDeleteComposer(context), saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), sendMessageAction: () => controller.handleClickSendButton(context), requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + toggleMarkAsImportantAction: () => controller.toggleMarkAsImportant(context), )), ] ) @@ -493,6 +497,22 @@ class ComposerView extends GetWidget { List _createMoreOptionPopupItems(BuildContext context) { return [ + PopupMenuItem( + padding: EdgeInsets.zero, + child: PopupItemWidget( + iconAction: controller.imagePaths.icMarkAsImportant, + nameAction: AppLocalizations.of(context).markAsImportant, + styleName: ComposerStyle.popupItemTextStyle, + padding: ComposerStyle.popupItemPadding, + colorIcon: ComposerStyle.popupItemIconColor, + selectedIcon: controller.imagePaths.icFilterSelected, + isSelected: controller.isMarkAsImportant.value, + onCallbackAction: () { + popBack(); + controller.toggleMarkAsImportant(context); + }, + ), + ), PopupMenuItem( padding: EdgeInsets.zero, child: PopupItemWidget( diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 21cb1eaeb..2d248a0a8 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -6,6 +6,7 @@ import 'package:model/email/prefix_email_address.dart'; import 'package:pointer_interceptor/pointer_interceptor.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/extensions/mark_as_important_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/composer/presentation/view/web/desktop_responsive_container_view.dart'; @@ -47,6 +48,7 @@ class ComposerView extends GetWidget { openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, isSendButtonEnabled: controller.isEnableEmailSendButton.value, hasRequestReadReceipt: controller.hasRequestReadReceipt.value, + isMarkAsImportant: controller.isMarkAsImportant.value, isEmailChanged: controller.isEmailChanged.value, menuMoreOptionController: controller.menuMoreOptionController!, onCloseViewAction: () => controller.handleClickCloseComposer(context), @@ -56,6 +58,7 @@ class ComposerView extends GetWidget { toggleCodeViewAction: controller.richTextWebController!.toggleCodeView, printDraftAction: () => controller.printDraft(context), toggleRequestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + toggleMarkAsImportantAction: () => controller.toggleMarkAsImportant(context), saveToDraftsAction: () => controller.handleClickSaveAsDraftsButton(context), deleteComposerAction: () => controller.handleClickDeleteComposer(context), )), @@ -562,6 +565,7 @@ class ComposerView extends GetWidget { isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, hasReadReceipt: controller.hasRequestReadReceipt.value, + isMarkAsImportant: controller.isMarkAsImportant.value, openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, attachFileAction: () => controller.openFilePickerByType(context, FileType.any), insertImageAction: () => controller.insertImage(context, constraints.maxWidth), @@ -573,6 +577,7 @@ class ComposerView extends GetWidget { menuMoreOptionController: controller.menuMoreOptionController!, printDraftAction: () => controller.printDraft(context), toggleRequestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + toggleMarkAsImportantAction: () => controller.toggleMarkAsImportant(context), )), ], ), @@ -870,6 +875,7 @@ class ComposerView extends GetWidget { isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, hasReadReceipt: controller.hasRequestReadReceipt.value, + isMarkAsImportant: controller.isMarkAsImportant.value, openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, attachFileAction: () => controller.openFilePickerByType(context, FileType.any), insertImageAction: () => controller.insertImage(context, constraints.maxWidth), @@ -881,6 +887,7 @@ class ComposerView extends GetWidget { menuMoreOptionController: controller.menuMoreOptionController!, printDraftAction: () => controller.printDraft(context), toggleRequestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + toggleMarkAsImportantAction: () => controller.toggleMarkAsImportant(context), )), ], ), diff --git a/lib/features/composer/presentation/extensions/mark_as_important_extension.dart b/lib/features/composer/presentation/extensions/mark_as_important_extension.dart new file mode 100644 index 000000000..284c6a9b3 --- /dev/null +++ b/lib/features/composer/presentation/extensions/mark_as_important_extension.dart @@ -0,0 +1,17 @@ + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +extension MarkAsImportantExtension on ComposerController { + void toggleMarkAsImportant(BuildContext context) { + isMarkAsImportant.toggle(); + + appToast.showToastSuccessMessage( + context, + isMarkAsImportant.isTrue + ? AppLocalizations.of(context).markAsImportantIsEnabled + : AppLocalizations.of(context).markAsImportantIsDisabled); + } +} \ No newline at end of file diff --git a/lib/features/composer/presentation/widgets/mobile/tablet_bottom_bar_composer_widget.dart b/lib/features/composer/presentation/widgets/mobile/tablet_bottom_bar_composer_widget.dart index 6dbbd8876..7ee7b4e7e 100644 --- a/lib/features/composer/presentation/widgets/mobile/tablet_bottom_bar_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/mobile/tablet_bottom_bar_composer_widget.dart @@ -1,27 +1,30 @@ 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/tablet_bottom_bar_composer_widget_style.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class TabletBottomBarComposerWidget extends StatelessWidget { + final ImagePaths imagePaths; final bool hasReadReceipt; + final bool isMarkAsImportant; final VoidCallback deleteComposerAction; final VoidCallback saveToDraftAction; final VoidCallback sendMessageAction; final VoidCallback requestReadReceiptAction; + final VoidCallback toggleMarkAsImportantAction; - final _imagePaths = Get.find(); - - TabletBottomBarComposerWidget({ + const TabletBottomBarComposerWidget({ super.key, + required this.imagePaths, required this.hasReadReceipt, + required this.isMarkAsImportant, required this.deleteComposerAction, required this.saveToDraftAction, required this.sendMessageAction, required this.requestReadReceiptAction, + required this.toggleMarkAsImportantAction, }); @override @@ -33,7 +36,7 @@ class TabletBottomBarComposerWidget extends StatelessWidget { children: [ const Spacer(), TMailButtonWidget.fromIcon( - icon: _imagePaths.icDeleteMailbox, + icon: imagePaths.icDeleteMailbox, borderRadius: TabletBottomBarComposerWidgetStyle.iconRadius, padding: TabletBottomBarComposerWidgetStyle.iconPadding, iconSize: TabletBottomBarComposerWidgetStyle.iconSize, @@ -42,7 +45,21 @@ class TabletBottomBarComposerWidget extends StatelessWidget { ), const SizedBox(width: TabletBottomBarComposerWidgetStyle.space), TMailButtonWidget.fromIcon( - icon: _imagePaths.icReadReceipt, + icon: imagePaths.icMarkAsImportant, + borderRadius: TabletBottomBarComposerWidgetStyle.iconRadius, + padding: TabletBottomBarComposerWidgetStyle.iconPadding, + iconSize: TabletBottomBarComposerWidgetStyle.iconSize, + iconColor: isMarkAsImportant + ? TabletBottomBarComposerWidgetStyle.selectedIconColor + : TabletBottomBarComposerWidgetStyle.iconColor, + tooltipMessage: isMarkAsImportant + ? AppLocalizations.of(context).turnOffMarkAsImportant + : AppLocalizations.of(context).turnOnMarkAsImportant, + onTapActionCallback: toggleMarkAsImportantAction, + ), + const SizedBox(width: TabletBottomBarComposerWidgetStyle.space), + TMailButtonWidget.fromIcon( + icon: imagePaths.icReadReceipt, borderRadius: TabletBottomBarComposerWidgetStyle.iconRadius, padding: TabletBottomBarComposerWidgetStyle.iconPadding, iconSize: TabletBottomBarComposerWidgetStyle.iconSize, @@ -56,7 +73,7 @@ class TabletBottomBarComposerWidget extends StatelessWidget { ), const SizedBox(width: TabletBottomBarComposerWidgetStyle.space), TMailButtonWidget.fromIcon( - icon: _imagePaths.icSaveToDraft, + icon: imagePaths.icSaveToDraft, borderRadius: TabletBottomBarComposerWidgetStyle.iconRadius, padding: TabletBottomBarComposerWidgetStyle.iconPadding, iconSize: TabletBottomBarComposerWidgetStyle.iconSize, @@ -66,7 +83,7 @@ class TabletBottomBarComposerWidget extends StatelessWidget { const SizedBox(width: TabletBottomBarComposerWidgetStyle.sendButtonSpace), TMailButtonWidget( text: AppLocalizations.of(context).send, - icon: _imagePaths.icSend, + icon: imagePaths.icSend, iconAlignment: TextDirection.rtl, padding: TabletBottomBarComposerWidgetStyle.sendButtonPadding, iconSize: TabletBottomBarComposerWidgetStyle.iconSize, diff --git a/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart b/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart index d939de42a..fa34e7f3a 100644 --- a/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart @@ -16,6 +16,7 @@ class BottomBarComposerWidget extends StatelessWidget { final bool isEmailChanged; final bool isFormattingOptionsEnabled; final bool hasReadReceipt; + final bool isMarkAsImportant; final CustomPopupMenuController menuMoreOptionController; final VoidCallback openRichToolbarAction; final VoidCallback attachFileAction; @@ -26,6 +27,7 @@ class BottomBarComposerWidget extends StatelessWidget { final VoidCallback toggleCodeViewAction; final VoidCallback toggleRequestReadReceiptAction; final VoidCallback printDraftAction; + final VoidCallback toggleMarkAsImportantAction; const BottomBarComposerWidget({ super.key, @@ -34,6 +36,7 @@ class BottomBarComposerWidget extends StatelessWidget { required this.isEmailChanged, required this.isFormattingOptionsEnabled, required this.hasReadReceipt, + required this.isMarkAsImportant, required this.menuMoreOptionController, required this.openRichToolbarAction, required this.attachFileAction, @@ -44,6 +47,7 @@ class BottomBarComposerWidget extends StatelessWidget { required this.toggleCodeViewAction, required this.toggleRequestReadReceiptAction, required this.printDraftAction, + required this.toggleMarkAsImportantAction, }); @override @@ -103,6 +107,19 @@ class BottomBarComposerWidget extends StatelessWidget { tooltipMessage: AppLocalizations.of(context).more, ), listButtonAction: [ + PopupItemWidget( + iconAction: imagePaths.icMarkAsImportant, + nameAction: AppLocalizations.of(context).markAsImportant, + styleName: BottomBarComposerWidgetStyle.popupItemTextStyle, + padding: BottomBarComposerWidgetStyle.popupItemPadding, + colorIcon: BottomBarComposerWidgetStyle.iconColor, + selectedIcon: imagePaths.icFilterSelected, + isSelected: isMarkAsImportant, + onCallbackAction: () { + menuMoreOptionController.hideMenu(); + toggleMarkAsImportantAction(); + }, + ), PopupItemWidget( iconAction: imagePaths.icStyleCodeView, nameAction: AppLocalizations.of(context).embedCode, diff --git a/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart b/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart index 35d57e7cf..d2c22550f 100644 --- a/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart @@ -16,6 +16,7 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget { final bool isSendButtonEnabled; final bool isFormattingOptionsEnabled; final bool hasRequestReadReceipt; + final bool isMarkAsImportant; final bool isEmailChanged; final CustomPopupMenuController menuMoreOptionController; final VoidCallback onCloseViewAction; @@ -28,6 +29,7 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget { final VoidCallback printDraftAction; final VoidCallback saveToDraftsAction; final VoidCallback deleteComposerAction; + final VoidCallback toggleMarkAsImportantAction; const MobileResponsiveAppBarComposerWidget({ super.key, @@ -36,6 +38,7 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget { required this.isFormattingOptionsEnabled, required this.isSendButtonEnabled, required this.hasRequestReadReceipt, + required this.isMarkAsImportant, required this.isEmailChanged, required this.menuMoreOptionController, required this.openRichToolbarAction, @@ -48,6 +51,7 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget { required this.printDraftAction, required this.saveToDraftsAction, required this.deleteComposerAction, + required this.toggleMarkAsImportantAction, }); @override @@ -120,6 +124,19 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget { tooltipMessage: AppLocalizations.of(context).more, ), listButtonAction: [ + PopupItemWidget( + iconAction: imagePaths.icMarkAsImportant, + nameAction: AppLocalizations.of(context).markAsImportant, + styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle, + padding: MobileAppBarComposerWidgetStyle.popupItemPadding, + colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor, + selectedIcon: imagePaths.icFilterSelected, + isSelected: isMarkAsImportant, + onCallbackAction: () { + menuMoreOptionController.hideMenu(); + toggleMarkAsImportantAction(); + }, + ), PopupItemWidget( iconAction: imagePaths.icStyleCodeView, nameAction: AppLocalizations.of(context).embedCode, diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 41f30b532..888345a31 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4309,5 +4309,35 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "markAsImportant": "Mark as important", + "@markAsImportant": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "markAsImportantIsEnabled": "Mark as important is enabled", + "@markAsImportantIsEnabled": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "markAsImportantIsDisabled": "Mark as important is disabled", + "@markAsImportantIsDisabled": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "turnOnMarkAsImportant": "Turn on mark as important", + "@turnOnMarkAsImportant": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "turnOffMarkAsImportant": "Turn off mark as important", + "@turnOffMarkAsImportant": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 70cf8d1c0..c9e3b461a 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -4520,4 +4520,39 @@ class AppLocalizations { name: 'sizeAscending', ); } + + String get markAsImportant { + return Intl.message( + 'Mark as important', + name: 'markAsImportant', + ); + } + + String get markAsImportantIsEnabled { + return Intl.message( + 'Mark as important is enabled', + name: 'markAsImportantIsEnabled', + ); + } + + String get markAsImportantIsDisabled { + return Intl.message( + 'Mark as important is disabled', + name: 'markAsImportantIsDisabled', + ); + } + + String get turnOnMarkAsImportant { + return Intl.message( + 'Turn on mark as important', + name: 'turnOnMarkAsImportant', + ); + } + + String get turnOffMarkAsImportant { + return Intl.message( + 'Turn off mark as important', + name: 'turnOffMarkAsImportant', + ); + } }