From 432c482155fc0aedf45afc13f1e9f8870c7815e7 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 5 Feb 2026 13:03:18 +0700 Subject: [PATCH] feat: Re-use `AddLabelToEmailMixin` for logic add label to email in EmailView --- .../presentation/action/email_ui_action.dart | 20 ++ .../presentation/bindings/email_bindings.dart | 4 - .../bindings/email_interactor_bindings.dart | 10 +- .../controller/single_email_controller.dart | 37 +-- .../email/presentation/email_view.dart | 12 +- .../handle_label_for_email_extension.dart | 214 +-------------- .../mixin/add_label_to_email_mixin.dart | 255 ++++++++++++++++++ .../email_action_interactor_bindings.dart | 17 ++ .../bindings/mailbox_dashboard_bindings.dart | 19 +- .../mailbox_dashboard_controller.dart | 40 ++- .../labels/handle_logic_label_extension.dart | 41 ++- .../handle_email_more_action_extension.dart | 14 +- .../thread/presentation/thread_view.dart | 13 +- .../single_email_controller_test.dart | 10 +- 14 files changed, 443 insertions(+), 263 deletions(-) create mode 100644 lib/features/labels/presentation/mixin/add_label_to_email_mixin.dart create mode 100644 lib/features/mailbox_dashboard/presentation/bindings/email_action_interactor_bindings.dart diff --git a/lib/features/email/presentation/action/email_ui_action.dart b/lib/features/email/presentation/action/email_ui_action.dart index d459ac5ea..7c491f3de 100644 --- a/lib/features/email/presentation/action/email_ui_action.dart +++ b/lib/features/email/presentation/action/email_ui_action.dart @@ -1,6 +1,7 @@ import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:labels/model/label.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/email/presentation_email.dart'; @@ -127,3 +128,22 @@ class RemoveLabelFromEmailAction extends EmailUIAction { @override List get props => [emailId, label]; } + +class SyncUpdateLabelForEmailOnMemory extends EmailUIAction { + final EmailId emailId; + final KeyWordIdentifier labelKeyword; + final bool shouldRemove; + + SyncUpdateLabelForEmailOnMemory({ + required this.emailId, + required this.labelKeyword, + required this.shouldRemove, + }); + + @override + List get props => [ + emailId, + labelKeyword, + shouldRemove, + ]; +} diff --git a/lib/features/email/presentation/bindings/email_bindings.dart b/lib/features/email/presentation/bindings/email_bindings.dart index f7b305a07..76d48df76 100644 --- a/lib/features/email/presentation/bindings/email_bindings.dart +++ b/lib/features/email/presentation/bindings/email_bindings.dart @@ -1,11 +1,9 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/add_a_label_to_an_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_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/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/remove_a_label_from_an_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/email_interactor_bindings.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; @@ -25,8 +23,6 @@ class EmailBindings extends Bindings { Get.find(), Get.find(), Get.find(), - Get.find(), - Get.find(), Get.find(), currentEmailId: currentEmailId, ), tag: tag); diff --git a/lib/features/email/presentation/bindings/email_interactor_bindings.dart b/lib/features/email/presentation/bindings/email_interactor_bindings.dart index 013fa0590..a5cc2beaf 100644 --- a/lib/features/email/presentation/bindings/email_interactor_bindings.dart +++ b/lib/features/email/presentation/bindings/email_interactor_bindings.dart @@ -16,7 +16,6 @@ import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/add_a_label_to_an_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_entire_message_as_document_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_stored_email_state_interactor.dart'; @@ -24,7 +23,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_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/print_email_interactor.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/remove_a_label_from_an_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; @@ -37,6 +35,7 @@ import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart'; import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_isolate_worker.dart'; import 'package:tmail_ui_user/features/mailbox/data/repository/mailbox_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/email_action_interactor_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_interactors_bindings.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_worker_queue.dart'; @@ -119,12 +118,7 @@ class EmailInteractorBindings extends InteractorsBindings { Get.find(), )); } - Get.lazyPut( - () => AddALabelToAnEmailInteractor(Get.find()), - ); - Get.lazyPut( - () => RemoveALabelFromAnEmailInteractor(Get.find()), - ); + EmailActionInteractorBindings(Get.find()).dependencies(); } @override diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index d37642d75..1efd7cae9 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -35,7 +35,6 @@ import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/send_receipt_to_sender_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/view_entire_message_request.dart'; -import 'package:tmail_ui_user/features/email/domain/state/add_a_label_to_an_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/calendar_event_accept_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/calendar_event_counter_accept_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/calendar_event_maybe_state.dart'; @@ -47,10 +46,8 @@ import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_sta import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/print_email_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/remove_a_label_from_an_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/send_receipt_to_sender_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/add_a_label_to_an_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_counter_accept_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reject_interactor.dart'; @@ -61,7 +58,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_ import 'package:tmail_ui_user/features/email/domain/usecases/maybe_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/remove_a_label_from_an_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/send_receipt_to_sender_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; @@ -121,8 +117,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final StoreOpenedEmailInteractor _storeOpenedEmailInteractor; final PrintEmailInteractor _printEmailInteractor; - final AddALabelToAnEmailInteractor addALabelToAnEmailInteractor; - final RemoveALabelFromAnEmailInteractor removeALabelFromAnEmailInteractor; final EmailId? _currentEmailId; CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor; @@ -192,8 +186,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { this._markAsStarEmailInteractor, this._getAllIdentitiesInteractor, this._storeOpenedEmailInteractor, - this.addALabelToAnEmailInteractor, - this.removeALabelFromAnEmailInteractor, this._printEmailInteractor, { EmailId? currentEmailId, }) : _currentEmailId = currentEmailId; @@ -250,10 +242,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _handlePrintEmailSuccess(success); } else if (success is CalendarEventReplySuccess) { calendarEventSuccess(success); - } else if (success is AddALabelToAnEmailSuccess) { - handleAddLabelToEmailSuccess(success); - } else if (success is RemoveALabelFromAnEmailSuccess) { - handleRemoveLabelFromEmailSuccess(success); } else { super.handleSuccessViewState(success); } @@ -271,10 +259,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _showMessageWhenEmailPrintingFailed(failure); } else if (failure is CalendarEventReplyFailure) { _calendarEventFailure(failure); - } else if (failure is AddALabelToAnEmailFailure) { - handleAddLabelToEmailFailure(failure); - } else if (failure is RemoveALabelFromAnEmailFailure) { - handleRemoveLabelFromEmailFailure(failure); } else { super.handleFailureViewState(failure); } @@ -364,7 +348,23 @@ class SingleEmailController extends BaseController with AppLoaderMixin { action.emailId != _currentEmailId) { return; } - toggleLabelToEmail(action.emailId, action.label, false); + mailboxDashBoardController.toggleLabelToEmail( + action.emailId, + action.label, + false, + ); + } else if (action is SyncUpdateLabelForEmailOnMemory) { + mailboxDashBoardController.clearEmailUIAction(); + if (_currentEmailId == null || + action.emailId != _currentEmailId) { + return; + } + + syncLabelToSelectedEmailOnMemory( + emailId: action.emailId, + labelKeyword: action.labelKeyword, + remove: action.shouldRemove, + ); } })); @@ -914,7 +914,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { break; case EmailActionType.labelAs: if (!isLabelAvailable) return; - openAddLabelToEmailDialogModal(presentationEmail); + mailboxDashBoardController + .openAddLabelToEmailDialogModal(presentationEmail); break; default: break; diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index e08c428bb..df41e4981 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -109,8 +109,8 @@ class EmailView extends GetWidget { openBottomSheetContextMenu: controller.mailboxDashBoardController.openBottomSheetContextMenu, openPopupMenu: controller.mailboxDashBoardController.openPopupMenuActionGroup, onSelectLabelAction: (label, isSelected) => - controller.toggleLabelToEmail( - presentationEmail.id!, + controller.onToggleLabelAction( + presentationEmail.id, label, isSelected, ), @@ -275,8 +275,8 @@ class EmailView extends GetWidget { imagePaths: controller.imagePaths, isMobileResponsive: isMobileResponsive, labels: emailLabels, - onDeleteLabelAction: (label) => controller.toggleLabelToEmail( - presentationEmail.id!, + onDeleteLabelAction: (label) => controller.onToggleLabelAction( + presentationEmail.id, label, false, ), @@ -320,8 +320,8 @@ class EmailView extends GetWidget { openBottomSheetContextMenu: controller.mailboxDashBoardController.openBottomSheetContextMenu, openPopupMenu: controller.mailboxDashBoardController.openPopupMenuActionGroup, onSelectLabelAction: (label, isSelected) => - controller.toggleLabelToEmail( - presentationEmail.id!, + controller.onToggleLabelAction( + presentationEmail.id, label, isSelected, ), diff --git a/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart b/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart index 6264ba13d..b3ebf9abd 100644 --- a/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart +++ b/lib/features/email/presentation/extensions/handle_label_for_email_extension.dart @@ -1,118 +1,33 @@ +import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; -import 'package:jmap_dart_client/jmap/account_id.dart'; -import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; -import 'package:labels/extensions/label_extension.dart'; import 'package:labels/model/label.dart'; -import 'package:model/email/presentation_email.dart'; -import 'package:tmail_ui_user/features/email/domain/state/add_a_label_to_an_email_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/remove_a_label_from_an_email_state.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/email_loaded_extension.dart'; -import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart'; -import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; -import 'package:tmail_ui_user/features/labels/domain/exceptions/label_exceptions.dart'; -import 'package:tmail_ui_user/features/labels/presentation/widgets/add_label_to_email_modal.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/map_keywords_extension.dart'; import 'package:tmail_ui_user/features/thread/domain/extensions/presentation_email_map_extension.dart'; import 'package:tmail_ui_user/features/thread_detail/domain/extensions/list_email_in_thread_detail_info_extension.dart'; -import 'package:tmail_ui_user/main/routes/dialog_router.dart'; extension HandleLabelForEmailExtension on SingleEmailController { bool get isLabelAvailable { return mailboxDashBoardController.isLabelAvailable; } - void toggleLabelToEmail(EmailId emailId, Label label, bool isSelected) { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; - - if (isSelected) { - _addALabelToAnEmail( - session: session, - accountId: accountId, - emailId: emailId, - label: label, - ); - } else { - _removeALabelFromAnEmail( - session: session, - accountId: accountId, - emailId: emailId, - label: label, - ); - } - } - - void _addALabelToAnEmail({ - required Session? session, - required AccountId? accountId, - required Label label, - required EmailId emailId, - }) { - final labelDisplay = label.safeDisplayName; - - if (session == null) { - emitFailure( - controller: this, - failure: AddALabelToAnEmailFailure( - exception: NotFoundSessionException(), - labelDisplay: labelDisplay, - ), - ); + void onToggleLabelAction(EmailId? emailId, Label label, bool isSelected) { + if (emailId == null) { + logWarning('HandleLabelForEmailExtension::onToggleLabelAction: Email id is null'); return; } - - if (accountId == null) { - emitFailure( - controller: this, - failure: AddALabelToAnEmailFailure( - exception: NotFoundAccountIdException(), - labelDisplay: labelDisplay, - ), - ); - return; - } - - final labelKeyword = label.keyword; - if (labelKeyword == null) { - emitFailure( - controller: this, - failure: AddALabelToAnEmailFailure( - exception: const LabelKeywordIsNull(), - labelDisplay: labelDisplay, - ), - ); - return; - } - - consumeState(addALabelToAnEmailInteractor.execute( - session, - accountId, + mailboxDashBoardController.toggleLabelToEmail( emailId, - labelKeyword, - label.safeDisplayName, - )); - } - - void handleAddLabelToEmailSuccess(AddALabelToAnEmailSuccess success) { - toastManager.showMessageSuccess(success); - - _autoSyncLabelToSelectedEmailOnMemory( - emailId: success.emailId, - labelKeyword: success.labelKeyword, - remove: false, + label, + isSelected, ); } - void handleAddLabelToEmailFailure(AddALabelToAnEmailFailure failure) { - toastManager.showMessageFailure(failure); - } - - void _autoSyncLabelToSelectedEmailOnMemory({ + void syncLabelToSelectedEmailOnMemory({ required EmailId emailId, required KeyWordIdentifier labelKeyword, required bool remove, @@ -150,12 +65,6 @@ extension HandleLabelForEmailExtension on SingleEmailController { labelKeyword: labelKeyword, remove: remove, ); - - _notifyLabelUpdated( - emailId: emailId, - labelKeyword: labelKeyword, - remove: remove, - ); } void _updateLabelOnSelectedEmailIfNeeded({ @@ -216,111 +125,4 @@ extension HandleLabelForEmailExtension on SingleEmailController { remove: remove, ); } - - void _notifyLabelUpdated({ - required EmailId emailId, - required KeyWordIdentifier labelKeyword, - required bool remove, - }) { - mailboxDashBoardController.updateEmailFlagByEmailIds( - [emailId], - isLabelAdded: !remove, - labelKeyword: labelKeyword, - ); - - mailboxDashBoardController.labelController.isLabelSettingEnabled.refresh(); - } - - Future openAddLabelToEmailDialogModal(PresentationEmail email) async { - if (!isLabelAvailable) return; - final labels = mailboxDashBoardController.labelController.labels; - final emailLabels = email.getLabelList(labels); - final emailId = email.id; - if (emailId == null || labels.isEmpty) { - return; - } - - await DialogRouter().openDialogModal( - child: AddLabelToEmailModal( - labels: labels, - emailLabels: emailLabels, - emailIds: [emailId], - onAddLabelToEmailsCallback: (emailIds, label, isSelected) { - if (emailIds.length == 1) { - toggleLabelToEmail(emailIds.first, label, isSelected); - } - }, - ), - dialogLabel: 'add-label-to-email-modal', - ); - } - - void _removeALabelFromAnEmail({ - required Session? session, - required AccountId? accountId, - required Label label, - required EmailId emailId, - }) { - final labelDisplay = label.safeDisplayName; - - if (session == null) { - emitFailure( - controller: this, - failure: RemoveALabelFromAnEmailFailure( - exception: NotFoundSessionException(), - labelDisplay: labelDisplay, - ), - ); - return; - } - - if (accountId == null) { - emitFailure( - controller: this, - failure: RemoveALabelFromAnEmailFailure( - exception: NotFoundAccountIdException(), - labelDisplay: labelDisplay, - ), - ); - return; - } - - final labelKeyword = label.keyword; - if (labelKeyword == null) { - emitFailure( - controller: this, - failure: RemoveALabelFromAnEmailFailure( - exception: const LabelKeywordIsNull(), - labelDisplay: labelDisplay, - ), - ); - return; - } - - consumeState(removeALabelFromAnEmailInteractor.execute( - session, - accountId, - emailId, - labelKeyword, - label.safeDisplayName, - )); - } - - void handleRemoveLabelFromEmailSuccess( - RemoveALabelFromAnEmailSuccess success, - ) { - toastManager.showMessageSuccess(success); - - _autoSyncLabelToSelectedEmailOnMemory( - emailId: success.emailId, - labelKeyword: success.labelKeyword, - remove: true, - ); - } - - void handleRemoveLabelFromEmailFailure( - RemoveALabelFromAnEmailFailure failure, - ) { - toastManager.showMessageFailure(failure); - } } diff --git a/lib/features/labels/presentation/mixin/add_label_to_email_mixin.dart b/lib/features/labels/presentation/mixin/add_label_to_email_mixin.dart new file mode 100644 index 000000000..b9532d2db --- /dev/null +++ b/lib/features/labels/presentation/mixin/add_label_to_email_mixin.dart @@ -0,0 +1,255 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; +import 'package:labels/extensions/label_extension.dart'; +import 'package:labels/model/label.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/base/mixin/emit_state_mixin.dart'; +import 'package:tmail_ui_user/features/email/domain/state/add_a_label_to_an_email_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/remove_a_label_from_an_email_state.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/add_a_label_to_an_email_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/remove_a_label_from_an_email_interactor.dart'; +import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart'; +import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; +import 'package:tmail_ui_user/features/labels/domain/exceptions/label_exceptions.dart'; +import 'package:tmail_ui_user/features/labels/presentation/widgets/add_label_to_email_modal.dart'; +import 'package:tmail_ui_user/features/thread/domain/exceptions/thread_exceptions.dart'; +import 'package:tmail_ui_user/main/routes/dialog_router.dart'; +import 'package:tmail_ui_user/main/utils/toast_manager.dart'; + +typedef OnSyncLabelForEmail = void Function( + EmailId emailId, + KeyWordIdentifier labelKeyword, + bool shouldRemove, +); + +mixin AddLabelToEmailMixin on EmitStateMixin { + bool get isCurrentLabelAvailable; + + List