TF-2666 Apply new design for edit recipient card on web

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-07-24 16:59:15 +07:00
committed by Dat H. Pham
parent 7ca3950c34
commit 6653551609
15 changed files with 420 additions and 87 deletions
@@ -1497,36 +1497,28 @@ class ComposerController extends BaseController
} else {
switch(prefixEmailAddress) {
case PrefixEmailAddress.to:
if (mailboxDashBoardController.isPopupMenuOpened.isFalse) {
toAddressExpandMode.value = ExpandMode.COLLAPSE;
}
toAddressExpandMode.value = ExpandMode.COLLAPSE;
final inputToEmail = toEmailAddressController.text;
if (inputToEmail.trim().isNotEmpty) {
autoCreateEmailTagForType(PrefixEmailAddress.to, inputToEmail);
}
break;
case PrefixEmailAddress.cc:
if (mailboxDashBoardController.isPopupMenuOpened.isFalse) {
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
}
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
final inputCcEmail = ccEmailAddressController.text;
if (inputCcEmail.trim().isNotEmpty) {
autoCreateEmailTagForType(PrefixEmailAddress.cc, inputCcEmail);
}
break;
case PrefixEmailAddress.bcc:
if (mailboxDashBoardController.isPopupMenuOpened.isFalse) {
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
}
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
final inputBccEmail = bccEmailAddressController.text;
if (inputBccEmail.trim().isNotEmpty) {
autoCreateEmailTagForType(PrefixEmailAddress.bcc, inputBccEmail);
}
break;
case PrefixEmailAddress.replyTo:
if (mailboxDashBoardController.isPopupMenuOpened.isFalse) {
replyToAddressExpandMode.value = ExpandMode.COLLAPSE;
}
replyToAddressExpandMode.value = ExpandMode.COLLAPSE;
final inputReplyToEmail = replyToEmailAddressController.text;
if (inputReplyToEmail.trim().isNotEmpty) {
autoCreateEmailTagForType(PrefixEmailAddress.replyTo, inputReplyToEmail);
@@ -1,17 +1,15 @@
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/context_item_email_address_action_type.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/email_address_action_type.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/popup_menu_item_email_address_action_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -20,9 +18,9 @@ extension HandleEditRecipientExtension on ComposerController {
BuildContext context,
PrefixEmailAddress prefix,
EmailAddress emailAddress,
RelativeRect? position,
EmailAddressActionType emailAddressActionType,
) {
if (position == null) {
if (PlatformInfo.isMobile) {
clearFocus(context);
final contextMenuActions = EmailAddressActionType.values
@@ -47,34 +45,11 @@ extension HandleEditRecipientExtension on ComposerController {
},
);
} else {
if (mailboxDashBoardController.isPopupMenuOpened.isTrue) return;
final popupMenuItems = EmailAddressActionType.values.map((type) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
menuAction: PopupMenuItemEmailAddressActionType(
type,
AppLocalizations.of(context),
imagePaths,
),
menuActionClick: (menuAction) {
popBack();
_handleEmailAddressActionTypeClick(
context,
menuAction.action,
prefix,
emailAddress,
);
},
),
);
}).toList();
mailboxDashBoardController.openPopupMenu(
_handleEmailAddressActionTypeClick(
context,
position,
popupMenuItems,
emailAddressActionType,
prefix,
emailAddress,
);
}
}
@@ -92,6 +67,9 @@ extension HandleEditRecipientExtension on ComposerController {
case EmailAddressActionType.modify:
_modifyEmailAddress(prefix, emailAddress);
break;
case EmailAddressActionType.createRule:
_createRuleFromEmailAddress(emailAddress);
break;
}
}
@@ -176,4 +154,10 @@ extension HandleEditRecipientExtension on ComposerController {
break;
}
}
Future<void> _createRuleFromEmailAddress(EmailAddress emailAddress) async {
await mailboxDashBoardController.openCreateEmailRuleView(
emailAddress: emailAddress,
);
}
}
@@ -4,7 +4,8 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum EmailAddressActionType {
copy,
modify;
modify,
createRule;
String getContextMenuTitle(AppLocalizations appLocalizations) {
switch(this) {
@@ -12,6 +13,8 @@ enum EmailAddressActionType {
return appLocalizations.copy;
case EmailAddressActionType.modify:
return appLocalizations.modifyEmailAddress;
case EmailAddressActionType.createRule:
return appLocalizations.createARule;
}
}
@@ -21,6 +24,8 @@ enum EmailAddressActionType {
return imagePaths.icCopy;
case EmailAddressActionType.modify:
return imagePaths.icEditRule;
case EmailAddressActionType.createRule:
return imagePaths.icQuickCreatingRule;
}
}
}
@@ -0,0 +1,159 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/extensions/string_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/presentation/views/dialog/confirm_dialog_button.dart';
import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:tmail_ui_user/features/base/widget/email_address_with_copy_widget.dart';
import 'package:tmail_ui_user/features/base/widget/user_avatar_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class EditRecipientsView extends StatelessWidget {
final EmailAddress emailAddress;
final ImagePaths imagePaths;
final VoidCallback onCopyAction;
final VoidCallback onEditAction;
final VoidCallback onCreateRuleAction;
final VoidCallback onCloseAction;
const EditRecipientsView({
super.key,
required this.emailAddress,
required this.imagePaths,
required this.onCopyAction,
required this.onEditAction,
required this.onCreateRuleAction,
required this.onCloseAction,
});
@override
Widget build(BuildContext context) {
return PointerInterceptor(
child: Container(
width: 361,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(16)),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
blurRadius: 8,
spreadRadius: 3,
offset: const Offset(0, 4),
),
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 3,
offset: const Offset(0, 1),
),
],
),
child: Stack(
children: [
Padding(
padding: const EdgeInsetsDirectional.only(
start: 16,
end: 24,
top: 16,
bottom: 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
UserAvatarBuilder(
username: emailAddress.asString().firstLetterToUpperCase,
size: 67,
textStyle: ThemeUtils.textStyleInter500().copyWith(
fontSize: 33.5,
height: 50.25 / 33.5,
letterSpacing: 0.31,
color: AppColor.secondaryContrastText,
),
padding: const EdgeInsetsDirectional.only(end: 21),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (emailAddress.displayName.isNotEmpty)
Padding(
padding: const EdgeInsetsDirectional.only(end: 12),
child: Text(
emailAddress.displayName,
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
color: AppColor.textPrimary,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
EmailAddressWithCopyWidget(
label: emailAddress.emailAddress,
copyLabelIcon: imagePaths.icCopy,
onCopyButtonAction: onCopyAction,
),
],
),
),
],
),
const SizedBox(height: 13),
Row(
children: [
Expanded(
child: SizedBox(
width: double.infinity,
height: 48,
child: ConfirmDialogButton(
label: AppLocalizations.of(context).editEmail,
backgroundColor: AppColor.primaryMain,
textColor: Colors.white,
onTapAction: onEditAction,
),
),
),
const SizedBox(width: 8),
Expanded(
child: SizedBox(
width: double.infinity,
height: 48,
child: ConfirmDialogButton(
label: AppLocalizations.of(context).createARule,
backgroundColor: Colors.white,
textColor: AppColor.primaryMain,
borderColor: AppColor.primaryMain,
onTapAction: onCreateRuleAction,
),
),
),
],
)
],
),
),
PositionedDirectional(
top: 0,
end: 0,
child: TMailButtonWidget.fromIcon(
icon: imagePaths.icCloseDialog,
iconSize: 24,
iconColor: AppColor.m3Tertiary,
padding: const EdgeInsets.all(10),
borderRadius: 24,
backgroundColor: Colors.transparent,
onTapActionCallback: onCloseAction,
),
),
],
),
),
);
}
}
@@ -20,6 +20,7 @@ import 'package:super_tag_editor/tag_editor.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/mail_address_extension.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/email_address_action_type.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/recipient_composer_widget_style.dart';
@@ -41,7 +42,7 @@ typedef OnEditRecipientAction = void Function(
BuildContext context,
PrefixEmailAddress prefix,
EmailAddress emailAddress,
RelativeRect? position,
EmailAddressActionType emailAddressActionType,
);
class RecipientComposerWidget extends StatefulWidget {
@@ -10,9 +10,11 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:tmail_ui_user/features/base/widget/smart_interaction_widget.dart';
import 'package:tmail_ui_user/features/base/widget/card_with_smart_interaction_overlay_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/email_address_action_type.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/recipient_tag_item_widget_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/view/edit_recipients_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/draggable_recipient_tag_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
@@ -56,16 +58,30 @@ class RecipientTagItemWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget tagWidget = SmartInteractionWidget(
onRightMouseClickAction: (position) => _onEditRecipientAction(
context,
position: position,
Widget tagWidget = CardWithSmartInteractionOverlayView(
menuBuilder: (onClose) => EditRecipientsView(
emailAddress: currentEmailAddress,
imagePaths: imagePaths,
onCopyAction: () => _onEditRecipientAction(
context,
EmailAddressActionType.copy,
),
onEditAction: () {
onClose();
_onEditRecipientAction(
context,
EmailAddressActionType.modify,
);
},
onCreateRuleAction: () {
onClose();
_onEditRecipientAction(
context,
EmailAddressActionType.createRule,
);
},
onCloseAction: onClose,
),
onDoubleClickAction: (position) => _onEditRecipientAction(
context,
position: position,
),
onLongPressAction: () => _onEditRecipientAction(context),
child: Chip(
labelPadding: EdgeInsetsDirectional.symmetric(
horizontal: 4,
@@ -186,12 +202,15 @@ class RecipientTagItemWidget extends StatelessWidget {
}
}
void _onEditRecipientAction(BuildContext context, {RelativeRect? position}) {
void _onEditRecipientAction(
BuildContext context,
EmailAddressActionType emailAddressActionType,
) {
onEditRecipientAction?.call(
context,
prefix,
currentEmailAddress,
position,
emailAddressActionType,
);
}
}