From b37359af03c369f36872645a7385316086bd9ce2 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 9 Jan 2026 16:37:09 +0700 Subject: [PATCH] TF-4236 Implement remove a label from an email when click on the cross on a tag in the opened mail --- .../base/widget/labels/tag_widget.dart | 24 +++++++- .../presentation/action/email_ui_action.dart | 13 +++- .../controller/single_email_controller.dart | 7 +++ .../email/presentation/email_view.dart | 6 ++ .../widgets/email_subject_widget.dart | 60 +++++++++++++++++-- .../presentation/widgets/label_widget.dart | 17 +++++- .../get_thread_details_email_views.dart | 13 +++- .../remove_label_from_email_extension.dart | 12 ++++ .../thread_detail_collapsed_email.dart | 4 ++ 9 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 lib/features/thread_detail/presentation/extension/labels/remove_label_from_email_extension.dart diff --git a/lib/features/base/widget/labels/tag_widget.dart b/lib/features/base/widget/labels/tag_widget.dart index 3585927ed..e49cdbdd7 100644 --- a/lib/features/base/widget/labels/tag_widget.dart +++ b/lib/features/base/widget/labels/tag_widget.dart @@ -11,6 +11,8 @@ class TagWidget extends StatelessWidget { final bool isTruncateText; final bool showTooltip; final EdgeInsetsGeometry? margin; + final Widget? actionWidget; + final EdgeInsetsGeometry? padding; const TagWidget({ super.key, @@ -22,6 +24,8 @@ class TagWidget extends StatelessWidget { this.textColor, this.maxWidth, this.margin, + this.actionWidget, + this.padding, }); @override @@ -42,16 +46,32 @@ class TagWidget extends StatelessWidget { ); } - return Container( + if (actionWidget != null) { + labelText = Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: labelText), + actionWidget!, + ], + ); + } + + labelText = Container( decoration: BoxDecoration( color: backgroundColor, borderRadius: const BorderRadius.all(Radius.circular(4)), ), constraints: maxWidth != null ? BoxConstraints(maxWidth: maxWidth!) : null, - padding: EdgeInsets.symmetric(horizontal: horizontalPadding), + padding: padding ?? EdgeInsets.symmetric(horizontal: horizontalPadding), margin: margin, child: labelText, ); + + if (actionWidget != null) { + labelText = GestureDetector(onTap: () {}, child: labelText); + } + + return labelText; } } diff --git a/lib/features/email/presentation/action/email_ui_action.dart b/lib/features/email/presentation/action/email_ui_action.dart index da067d3bf..d459ac5ea 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:labels/model/label.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/email/presentation_email.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart'; @@ -115,4 +116,14 @@ class TriggerMailViewKeyboardShortcutAction extends EmailUIAction { @override List get props => [actionType, email]; -} \ No newline at end of file +} + +class RemoveLabelFromEmailAction extends EmailUIAction { + RemoveLabelFromEmailAction(this.emailId, this.label); + + final EmailId emailId; + final Label label; + + @override + List get props => [emailId, label]; +} diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index fb0eaa1cd..ed09da978 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -357,6 +357,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin { actionType: action.actionType, email: action.email, ); + } else if (action is RemoveLabelFromEmailAction) { + mailboxDashBoardController.clearEmailUIAction(); + if (_currentEmailId == null || + action.emailId != _currentEmailId) { + return; + } + toggleLabelToEmail(action.emailId, action.label, false); } })); diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index f1f077f10..5b8135e27 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -275,8 +275,14 @@ class EmailView extends GetWidget { presentationEmail: presentationEmail.copyWith( subject: threadSubject, ), + imagePaths: controller.imagePaths, isMobileResponsive: isMobileResponsive, labels: emailLabels, + onDeleteLabelAction: (label) => controller.toggleLabelToEmail( + presentationEmail.id!, + label, + false, + ), ); }), Obx(() => InformationSenderAndReceiverBuilder( diff --git a/lib/features/email/presentation/widgets/email_subject_widget.dart b/lib/features/email/presentation/widgets/email_subject_widget.dart index 4573b28ac..051947045 100644 --- a/lib/features/email/presentation/widgets/email_subject_widget.dart +++ b/lib/features/email/presentation/widgets/email_subject_widget.dart @@ -1,28 +1,49 @@ +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:labels/model/label.dart'; import 'package:model/email/presentation_email.dart'; import 'package:tmail_ui_user/features/email/presentation/styles/email_subject_styles.dart'; import 'package:tmail_ui_user/features/labels/presentation/widgets/label_widget.dart'; -class EmailSubjectWidget extends StatelessWidget { +typedef OnDeleteLabelAction = void Function(Label label); + +class EmailSubjectWidget extends StatefulWidget { final PresentationEmail presentationEmail; + final ImagePaths imagePaths; final bool isMobileResponsive; final List