TF-3759 Always show dot icon when open popup menu of more action in email item widget
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
+5
-5
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:model/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart';
|
||||
@@ -10,7 +10,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
extension HandleEmailMoreActionExtension on SearchEmailController {
|
||||
void handleEmailMoreAction(
|
||||
Future<void> handleEmailMoreAction(
|
||||
BuildContext context,
|
||||
PresentationEmail presentationEmail,
|
||||
RelativeRect? position,
|
||||
@@ -24,7 +24,7 @@ extension HandleEmailMoreActionExtension on SearchEmailController {
|
||||
if (!isDrafts) EmailActionType.editAsNewEmail,
|
||||
];
|
||||
|
||||
if (listEmailActions.isEmpty) return;
|
||||
if (listEmailActions.isEmpty) return Future.value();
|
||||
|
||||
if (position == null) {
|
||||
final contextMenuActions = listEmailActions
|
||||
@@ -35,7 +35,7 @@ extension HandleEmailMoreActionExtension on SearchEmailController {
|
||||
))
|
||||
.toList();
|
||||
|
||||
openBottomSheetContextMenuAction(
|
||||
return openBottomSheetContextMenuAction(
|
||||
context: context,
|
||||
itemActions: contextMenuActions,
|
||||
onContextMenuActionClick: (menuAction) {
|
||||
@@ -70,7 +70,7 @@ extension HandleEmailMoreActionExtension on SearchEmailController {
|
||||
);
|
||||
}).toList();
|
||||
|
||||
openPopupMenuAction(context, position, popupMenuItems);
|
||||
return openPopupMenuAction(context, position, popupMenuItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:model/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/popup_menu_item_email_action.dart';
|
||||
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
extension HandleEmailActionExtension on SearchEmailController {
|
||||
void handleEmailMoreActionClick(
|
||||
BuildContext context,
|
||||
RelativeRect position,
|
||||
PresentationEmail presentationEmail,
|
||||
) {
|
||||
final mailboxContain = presentationEmail.mailboxContain;
|
||||
final isDrafts = mailboxContain?.isDrafts ?? false;
|
||||
final isSpam = mailboxContain?.isSpam ?? false;
|
||||
|
||||
final popupMenuItems = [
|
||||
isSpam ? EmailActionType.unSpam : EmailActionType.moveToSpam,
|
||||
if (isDrafts == false) EmailActionType.editAsNewEmail,
|
||||
].map((actionType) {
|
||||
return PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupMenuItemActionWidget(
|
||||
menuAction: PopupMenuItemEmailAction(
|
||||
actionType,
|
||||
AppLocalizations.of(context),
|
||||
imagePaths,
|
||||
),
|
||||
menuActionClick: (menuAction) {
|
||||
popBack();
|
||||
pressEmailAction(
|
||||
context,
|
||||
menuAction.action,
|
||||
presentationEmail,
|
||||
mailboxContain: mailboxContain,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
|
||||
openPopupMenuAction(context, position, popupMenuItems);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_til
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
typedef OnPressEmailActionClick = void Function(EmailActionType, PresentationEmail);
|
||||
typedef OnMoreActionClick = void Function(PresentationEmail, RelativeRect?);
|
||||
typedef OnMoreActionClick = Future<void> Function(PresentationEmail, RelativeRect?);
|
||||
|
||||
mixin BaseEmailItemTile {
|
||||
|
||||
|
||||
@@ -609,7 +609,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
);
|
||||
}
|
||||
|
||||
void _handleEmailContextMenuAction(
|
||||
Future<void> _handleEmailContextMenuAction(
|
||||
BuildContext context,
|
||||
PresentationEmail presentationEmail,
|
||||
RelativeRect? position
|
||||
@@ -639,7 +639,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
))
|
||||
.toList();
|
||||
|
||||
controller.openBottomSheetContextMenuAction(
|
||||
return controller.openBottomSheetContextMenuAction(
|
||||
context: context,
|
||||
itemActions: contextMenuActions,
|
||||
onContextMenuActionClick: (menuAction) {
|
||||
@@ -672,7 +672,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
);
|
||||
}).toList();
|
||||
|
||||
controller.openPopupMenuAction(context, position, popupMenuItems);
|
||||
return controller.openPopupMenuAction(context, position, popupMenuItems);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:model/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/mixin/base_email_item_tile.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class DesktopListEmailActionHoverWidget extends StatefulWidget {
|
||||
final PresentationEmail presentationEmail;
|
||||
final bool isHovered;
|
||||
final bool canDeletePermanently;
|
||||
final bool isSearchEmailRunning;
|
||||
final PresentationMailbox? mailboxContain;
|
||||
final OnPressEmailActionClick? emailActionClick;
|
||||
final OnMoreActionClick? onMoreActionClick;
|
||||
|
||||
const DesktopListEmailActionHoverWidget({
|
||||
super.key,
|
||||
required this.presentationEmail,
|
||||
required this.isHovered,
|
||||
required this.canDeletePermanently,
|
||||
required this.isSearchEmailRunning,
|
||||
required this.mailboxContain,
|
||||
required this.emailActionClick,
|
||||
required this.onMoreActionClick,
|
||||
});
|
||||
|
||||
@override
|
||||
State<DesktopListEmailActionHoverWidget> createState() =>
|
||||
_DesktopListEmailActionHoverWidgetState();
|
||||
}
|
||||
|
||||
class _DesktopListEmailActionHoverWidgetState
|
||||
extends State<DesktopListEmailActionHoverWidget> with BaseEmailItemTile {
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
bool _popupMenuVisible = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final listActionWidget = [
|
||||
if (widget.isHovered) ...[
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icOpenInNewTab,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).openInNewTab,
|
||||
onTapActionCallback: () => widget.emailActionClick?.call(
|
||||
EmailActionType.openInNewTab,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
if (!widget.presentationEmail.isDraft)
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: widget.presentationEmail.hasRead
|
||||
? _imagePaths.icUnread
|
||||
: _imagePaths.icRead,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: widget.presentationEmail.hasRead
|
||||
? AppLocalizations.of(context).mark_as_unread
|
||||
: AppLocalizations.of(context).mark_as_read,
|
||||
onTapActionCallback: () => widget.emailActionClick?.call(
|
||||
widget.presentationEmail.hasRead
|
||||
? EmailActionType.markAsUnread
|
||||
: EmailActionType.markAsRead,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
if (widget.mailboxContain != null &&
|
||||
widget.mailboxContain?.isDrafts == false) ...[
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icMove,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).move,
|
||||
onTapActionCallback: () => widget.emailActionClick?.call(
|
||||
EmailActionType.moveToMailbox,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
],
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icDeleteComposer,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: 16,
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: widget.canDeletePermanently
|
||||
? AppLocalizations.of(context).delete_permanently
|
||||
: AppLocalizations.of(context).move_to_trash,
|
||||
onTapActionCallback: () => widget.emailActionClick?.call(
|
||||
widget.canDeletePermanently
|
||||
? EmailActionType.deletePermanently
|
||||
: EmailActionType.moveToTrash,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (_shouldShowPopupMenu) ...[
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icMoreVertical,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: _popupMenuVisible
|
||||
? Theme.of(context).colorScheme.outline.withOpacity(0.08)
|
||||
: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).more,
|
||||
onTapActionAtPositionCallback: (position) {
|
||||
if (_responsiveUtils.isScreenWithShortestSide(context)) {
|
||||
widget.onMoreActionClick?.call(widget.presentationEmail, null);
|
||||
} else {
|
||||
_onPopupMenuVisibleChange(true);
|
||||
|
||||
widget.onMoreActionClick
|
||||
?.call(widget.presentationEmail, position)
|
||||
.whenComplete(() => _onPopupMenuVisibleChange(false));
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
] else ...[
|
||||
buildMailboxContain(
|
||||
context,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
if (widget.presentationEmail.hasAttachment == true)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8),
|
||||
child: buildIconAttachment(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 20, start: 8),
|
||||
child: buildDateTime(context, widget.presentationEmail),
|
||||
),
|
||||
]
|
||||
];
|
||||
|
||||
if (listActionWidget.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Row(children: listActionWidget);
|
||||
}
|
||||
|
||||
double _getIconSize() => 18;
|
||||
|
||||
EdgeInsets _getPaddingIcon(BuildContext context) {
|
||||
return const EdgeInsets.all(5);
|
||||
}
|
||||
|
||||
bool get _shouldShowPopupMenu => widget.isHovered || _popupMenuVisible;
|
||||
|
||||
void _onPopupMenuVisibleChange(bool visible) {
|
||||
if (_popupMenuVisible != visible && mounted) {
|
||||
setState(() {
|
||||
_popupMenuVisible = visible;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/extensions/tap_down_details_extension.dart';
|
||||
import 'package:core/presentation/views/button/icon_button_web.dart';
|
||||
import 'package:core/presentation/views/responsive/responsive_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -12,7 +11,8 @@ import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
import 'package:model/mailbox/select_mode.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/mixin/base_email_item_tile.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/widgets/desktop_list_email_action_hover_widget.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/widgets/web_tablet_body_email_item_widget.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class EmailTileBuilder extends StatefulWidget {
|
||||
@@ -174,142 +174,19 @@ class _EmailTileBuilderState extends State<EmailTileBuilder> with BaseEmailItem
|
||||
)
|
||||
),
|
||||
),
|
||||
tablet: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
EmailActionType.preview,
|
||||
widget.presentationEmail
|
||||
),
|
||||
hoverColor: Theme.of(context).colorScheme.outline.withOpacity(0.08),
|
||||
onHover: (value) => _hoverNotifier.value = value,
|
||||
child: Container(
|
||||
padding: widget.padding ?? _getPaddingItem(context),
|
||||
decoration: _getDecorationItem(),
|
||||
alignment: Alignment.center,
|
||||
child: Stack(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
EmailActionType.selection,
|
||||
widget.presentationEmail
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 8, end: 12),
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: _hoverNotifier,
|
||||
builder: (context, value, child) {
|
||||
return _buildAvatarIcon(
|
||||
context: context,
|
||||
isHovered: value
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
Expanded(child: Column(children: [
|
||||
Row(children: [
|
||||
if (!widget.presentationEmail.hasRead)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 5),
|
||||
child: buildIconUnreadStatus(),
|
||||
),
|
||||
Expanded(
|
||||
child: buildInformationSender(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
widget.mailboxContain,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.searchQuery
|
||||
)
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _hoverNotifier,
|
||||
builder: (context, value, child) {
|
||||
if (value) {
|
||||
return const SizedBox(width: 120);
|
||||
} else {
|
||||
return _buildDateTimeForMobileTabletScreen(context);
|
||||
}
|
||||
}
|
||||
),
|
||||
]),
|
||||
const SizedBox(height: 2),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.presentationEmail.hasCalendarEvent)
|
||||
buildCalendarEventIcon(
|
||||
context: context,
|
||||
presentationEmail: widget.presentationEmail
|
||||
),
|
||||
if (widget.presentationEmail.isMarkAsImportant && widget.isSenderImportantFlagEnabled)
|
||||
buildMarkAsImportantIcon(context),
|
||||
Expanded(
|
||||
child: buildEmailTitle(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.searchQuery
|
||||
)
|
||||
),
|
||||
buildMailboxContain(
|
||||
context,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.presentationEmail
|
||||
),
|
||||
if (widget.presentationEmail.hasStarred)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8),
|
||||
child: buildIconStar(),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: buildEmailPartialContent(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.searchQuery
|
||||
)
|
||||
),
|
||||
]),
|
||||
]))
|
||||
]
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _hoverNotifier,
|
||||
builder: (context, value, child) {
|
||||
if (value) {
|
||||
return Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: Transform(
|
||||
transform: Matrix4.translationValues(
|
||||
0.0,
|
||||
widget.selectAllMode == SelectMode.INACTIVE ? -5.0 : 0.0,
|
||||
0.0
|
||||
),
|
||||
child: _buildListActionButtonWhenHover(context)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
tablet: WebTabletBodyEmailItemWidget(
|
||||
presentationEmail: widget.presentationEmail,
|
||||
selectAllMode: widget.selectAllMode,
|
||||
canDeletePermanently: canDeletePermanently,
|
||||
isSearchEmailRunning: widget.isSearchEmailRunning,
|
||||
isShowingEmailContent: widget.isShowingEmailContent,
|
||||
isDrag: widget.isDrag,
|
||||
isSenderImportantFlagEnabled: widget.isSenderImportantFlagEnabled,
|
||||
padding: widget.padding,
|
||||
searchQuery: widget.searchQuery,
|
||||
mailboxContain: widget.mailboxContain,
|
||||
emailActionClick: widget.emailActionClick,
|
||||
onMoreActionClick: widget.onMoreActionClick,
|
||||
),
|
||||
desktop: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
@@ -440,12 +317,16 @@ class _EmailTileBuilderState extends State<EmailTileBuilder> with BaseEmailItem
|
||||
const SizedBox(width: 16),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _hoverNotifier,
|
||||
builder: (context, value, child) {
|
||||
if (value) {
|
||||
return _buildListActionButtonWhenHover(context);
|
||||
} else {
|
||||
return _buildDateTimeForDesktopScreen(context);
|
||||
}
|
||||
builder: (_, value, __) {
|
||||
return DesktopListEmailActionHoverWidget(
|
||||
presentationEmail: widget.presentationEmail,
|
||||
isHovered: value,
|
||||
canDeletePermanently: canDeletePermanently,
|
||||
isSearchEmailRunning: widget.isSearchEmailRunning,
|
||||
mailboxContain: widget.mailboxContain,
|
||||
emailActionClick: widget.emailActionClick,
|
||||
onMoreActionClick: widget.onMoreActionClick,
|
||||
);
|
||||
}
|
||||
),
|
||||
]),
|
||||
@@ -481,121 +362,10 @@ class _EmailTileBuilderState extends State<EmailTileBuilder> with BaseEmailItem
|
||||
}
|
||||
}
|
||||
|
||||
double _getIconSize(BuildContext context) {
|
||||
return responsiveUtils.isDesktop(context) ? 18 : 16;
|
||||
}
|
||||
|
||||
EdgeInsets _getPaddingIcon(BuildContext context) {
|
||||
return const EdgeInsets.all(5);
|
||||
}
|
||||
|
||||
Widget _buildListActionButtonWhenHover(BuildContext context) {
|
||||
return Row(children: [
|
||||
buildSVGIconButton(
|
||||
icon: imagePaths.icOpenInNewTab,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(context),
|
||||
padding: _getPaddingIcon(context),
|
||||
tooltip: AppLocalizations.of(context).openInNewTab,
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
EmailActionType.openInNewTab,
|
||||
widget.presentationEmail
|
||||
)
|
||||
),
|
||||
if(!widget.presentationEmail.isDraft)
|
||||
buildSVGIconButton(
|
||||
icon: widget.presentationEmail.hasRead ? imagePaths.icUnread: imagePaths.icRead,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(context),
|
||||
padding: _getPaddingIcon(context),
|
||||
tooltip: widget.presentationEmail.hasRead
|
||||
? AppLocalizations.of(context).mark_as_unread
|
||||
: AppLocalizations.of(context).mark_as_read,
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
widget.presentationEmail.hasRead ? EmailActionType.markAsUnread : EmailActionType.markAsRead,
|
||||
widget.presentationEmail
|
||||
)
|
||||
),
|
||||
if (widget.mailboxContain != null && widget.mailboxContain?.isDrafts == false)
|
||||
... [
|
||||
buildSVGIconButton(
|
||||
icon: imagePaths.icMove,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(context),
|
||||
padding: _getPaddingIcon(context),
|
||||
tooltip: AppLocalizations.of(context).move,
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
EmailActionType.moveToMailbox,
|
||||
widget.presentationEmail
|
||||
)
|
||||
),
|
||||
],
|
||||
buildSVGIconButton(
|
||||
icon: imagePaths.icDeleteComposer,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: responsiveUtils.isDesktop(context) ? 16 : 14,
|
||||
padding: _getPaddingIcon(context),
|
||||
tooltip: canDeletePermanently
|
||||
? AppLocalizations.of(context).delete_permanently
|
||||
: AppLocalizations.of(context).move_to_trash,
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
canDeletePermanently ? EmailActionType.deletePermanently : EmailActionType.moveToTrash,
|
||||
widget.presentationEmail
|
||||
)
|
||||
),
|
||||
buildSVGIconButton(
|
||||
icon: imagePaths.icMore,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(context),
|
||||
padding: _getPaddingIcon(context),
|
||||
tooltip: AppLocalizations.of(context).more,
|
||||
onTapDown: (tapDetails) {
|
||||
if (responsiveUtils.isScreenWithShortestSide(context)) {
|
||||
widget.onMoreActionClick?.call(widget.presentationEmail, null);
|
||||
} else {
|
||||
widget.onMoreActionClick?.call(widget.presentationEmail, tapDetails.getPosition(context));
|
||||
}
|
||||
}
|
||||
),
|
||||
if (responsiveUtils.isDesktop(context)) const SizedBox(width: 16),
|
||||
]);
|
||||
}
|
||||
|
||||
bool get canDeletePermanently {
|
||||
return widget.mailboxContain?.isTrash == true || widget.mailboxContain?.isDrafts == true || widget.mailboxContain?.isSpam == true;
|
||||
}
|
||||
|
||||
Widget _buildDateTimeForDesktopScreen(BuildContext context) {
|
||||
return Row(children: [
|
||||
buildMailboxContain(
|
||||
context,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.presentationEmail
|
||||
),
|
||||
if (widget.presentationEmail.hasAttachment == true)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8),
|
||||
child: buildIconAttachment()),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 20, start: 8),
|
||||
child: buildDateTime(context, widget.presentationEmail))
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _buildDateTimeForMobileTabletScreen(BuildContext context) {
|
||||
return Row(children: [
|
||||
buildIconAnsweredOrForwarded(width: 16, height: 16, presentationEmail: widget.presentationEmail),
|
||||
if (widget.presentationEmail.hasAttachment == true)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8),
|
||||
child: buildIconAttachment()),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4, start: 8),
|
||||
child: buildDateTime(context, widget.presentationEmail)),
|
||||
buildIconChevron()
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _buildSubjectAndContent() {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return Row(children: [
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:model/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
import 'package:model/mailbox/select_mode.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/mixin/base_email_item_tile.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class WebTabletBodyEmailItemWidget extends StatefulWidget {
|
||||
final PresentationEmail presentationEmail;
|
||||
final SelectMode selectAllMode;
|
||||
final bool canDeletePermanently;
|
||||
final bool isSearchEmailRunning;
|
||||
final bool isShowingEmailContent;
|
||||
final bool isShowDateTimeView;
|
||||
final bool isDrag;
|
||||
final bool isSenderImportantFlagEnabled;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final SearchQuery? searchQuery;
|
||||
final PresentationMailbox? mailboxContain;
|
||||
final OnPressEmailActionClick? emailActionClick;
|
||||
final OnMoreActionClick? onMoreActionClick;
|
||||
|
||||
const WebTabletBodyEmailItemWidget({
|
||||
super.key,
|
||||
required this.presentationEmail,
|
||||
required this.selectAllMode,
|
||||
required this.canDeletePermanently,
|
||||
required this.isSearchEmailRunning,
|
||||
required this.isShowingEmailContent,
|
||||
required this.isDrag,
|
||||
required this.isSenderImportantFlagEnabled,
|
||||
required this.padding,
|
||||
required this.searchQuery,
|
||||
required this.mailboxContain,
|
||||
required this.emailActionClick,
|
||||
required this.onMoreActionClick,
|
||||
this.isShowDateTimeView = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<WebTabletBodyEmailItemWidget> createState() =>
|
||||
_WebTabletBodyEmailItemWidgetState();
|
||||
}
|
||||
|
||||
class _WebTabletBodyEmailItemWidgetState
|
||||
extends State<WebTabletBodyEmailItemWidget> with BaseEmailItemTile {
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
bool _isHover = false;
|
||||
bool _popupMenuVisible = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
EmailActionType.preview,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
hoverColor: Theme.of(context).colorScheme.outline.withOpacity(0.08),
|
||||
onHover: (value) {
|
||||
setState(() {
|
||||
_isHover = value;
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
padding: widget.padding ?? _getPaddingItem(context),
|
||||
decoration: _getDecorationItem(),
|
||||
alignment: Alignment.center,
|
||||
child: Stack(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.emailActionClick?.call(
|
||||
EmailActionType.selection,
|
||||
widget.presentationEmail),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
top: 8,
|
||||
end: 12,
|
||||
),
|
||||
child: _buildAvatarIcon(
|
||||
context: context,
|
||||
isHovered: _isHover,
|
||||
))),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(children: [
|
||||
if (!widget.presentationEmail.hasRead)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 5),
|
||||
child: buildIconUnreadStatus(),
|
||||
),
|
||||
Expanded(
|
||||
child: buildInformationSender(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
widget.mailboxContain,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.searchQuery,
|
||||
),
|
||||
),
|
||||
if (_shouldShowPopupMenu)
|
||||
const SizedBox(width: 120)
|
||||
else
|
||||
_buildDateTimeForMobileTabletScreen(context),
|
||||
]),
|
||||
const SizedBox(height: 2),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.presentationEmail.hasCalendarEvent)
|
||||
buildCalendarEventIcon(
|
||||
context: context,
|
||||
presentationEmail: widget.presentationEmail,
|
||||
),
|
||||
if (widget.presentationEmail.isMarkAsImportant &&
|
||||
widget.isSenderImportantFlagEnabled)
|
||||
buildMarkAsImportantIcon(context),
|
||||
Expanded(
|
||||
child: buildEmailTitle(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.searchQuery,
|
||||
),
|
||||
),
|
||||
buildMailboxContain(
|
||||
context,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
if (widget.presentationEmail.hasStarred)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
start: 8,
|
||||
),
|
||||
child: buildIconStar(),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: buildEmailPartialContent(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
widget.isSearchEmailRunning,
|
||||
widget.searchQuery,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: Transform(
|
||||
transform: Matrix4.translationValues(
|
||||
0.0,
|
||||
widget.selectAllMode == SelectMode.INACTIVE ? -5.0 : 0.0,
|
||||
0.0,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
if (_isHover) ...[
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icOpenInNewTab,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage:
|
||||
AppLocalizations.of(context).openInNewTab,
|
||||
onTapActionCallback: () =>
|
||||
widget.emailActionClick?.call(
|
||||
EmailActionType.openInNewTab,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
if (!widget.presentationEmail.isDraft)
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: widget.presentationEmail.hasRead
|
||||
? _imagePaths.icUnread
|
||||
: _imagePaths.icRead,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: widget.presentationEmail.hasRead
|
||||
? AppLocalizations.of(context).mark_as_unread
|
||||
: AppLocalizations.of(context).mark_as_read,
|
||||
onTapActionCallback: () =>
|
||||
widget.emailActionClick?.call(
|
||||
widget.presentationEmail.hasRead
|
||||
? EmailActionType.markAsUnread
|
||||
: EmailActionType.markAsRead,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
if (widget.mailboxContain != null &&
|
||||
widget.mailboxContain?.isDrafts == false) ...[
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icMove,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).move,
|
||||
onTapActionCallback: () =>
|
||||
widget.emailActionClick?.call(
|
||||
EmailActionType.moveToMailbox,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
],
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icDeleteComposer,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: 14,
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: widget.canDeletePermanently
|
||||
? AppLocalizations.of(context).delete_permanently
|
||||
: AppLocalizations.of(context).move_to_trash,
|
||||
onTapActionCallback: () =>
|
||||
widget.emailActionClick?.call(
|
||||
widget.canDeletePermanently
|
||||
? EmailActionType.deletePermanently
|
||||
: EmailActionType.moveToTrash,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (_shouldShowPopupMenu)
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: _imagePaths.icMoreVertical,
|
||||
iconColor: ItemEmailTileStyles.actionIconColor,
|
||||
iconSize: _getIconSize(),
|
||||
padding: _getPaddingIcon(context),
|
||||
backgroundColor: _popupMenuVisible
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.outline
|
||||
.withOpacity(0.08)
|
||||
: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).more,
|
||||
onTapActionAtPositionCallback: (position) {
|
||||
if (_responsiveUtils
|
||||
.isScreenWithShortestSide(context)) {
|
||||
widget.onMoreActionClick
|
||||
?.call(widget.presentationEmail, null);
|
||||
} else {
|
||||
_onPopupMenuVisibleChange(true);
|
||||
|
||||
widget.onMoreActionClick
|
||||
?.call(widget.presentationEmail, position)
|
||||
.whenComplete(
|
||||
() => _onPopupMenuVisibleChange(false));
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
EdgeInsetsGeometry _getPaddingItem(BuildContext context) {
|
||||
if (responsiveUtils.isDesktop(context)) {
|
||||
return const EdgeInsets.symmetric(vertical: 4);
|
||||
} else if (responsiveUtils.isTablet(context)) {
|
||||
return const EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 24);
|
||||
} else {
|
||||
return const EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 12);
|
||||
}
|
||||
}
|
||||
|
||||
BoxDecoration? _getDecorationItem() {
|
||||
if (((widget.selectAllMode == SelectMode.ACTIVE &&
|
||||
widget.presentationEmail.selectMode == SelectMode.ACTIVE) ||
|
||||
widget.isDrag) &&
|
||||
responsiveUtils.isDesktop(context)) {
|
||||
return const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
color: AppColor.blue100,
|
||||
);
|
||||
} else if (widget.isShowingEmailContent &&
|
||||
responsiveUtils.isTabletLarge(context)) {
|
||||
return const BoxDecoration(color: AppColor.blue100);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildAvatarIcon({
|
||||
required BuildContext context,
|
||||
bool isHovered = false,
|
||||
double? iconSize,
|
||||
TextStyle? textStyle,
|
||||
}) {
|
||||
if (widget.presentationEmail.isSelected ||
|
||||
(responsiveUtils.isScreenWithShortestSide(context) &&
|
||||
widget.selectAllMode == SelectMode.ACTIVE) ||
|
||||
isHovered) {
|
||||
return buildIconAvatarSelection(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
iconSize: iconSize ?? 48,
|
||||
textStyle: textStyle,
|
||||
);
|
||||
} else {
|
||||
return buildIconAvatarText(
|
||||
widget.presentationEmail,
|
||||
iconSize: iconSize ?? 48,
|
||||
textStyle: textStyle,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildDateTimeForMobileTabletScreen(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
buildIconAnsweredOrForwarded(
|
||||
width: 16,
|
||||
height: 16,
|
||||
presentationEmail: widget.presentationEmail,
|
||||
),
|
||||
if (widget.presentationEmail.hasAttachment == true)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8),
|
||||
child: buildIconAttachment(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 4, start: 8),
|
||||
child: buildDateTime(
|
||||
context,
|
||||
widget.presentationEmail,
|
||||
),
|
||||
),
|
||||
buildIconChevron(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
double _getIconSize() => 16;
|
||||
|
||||
EdgeInsets _getPaddingIcon(BuildContext context) {
|
||||
return const EdgeInsets.all(5);
|
||||
}
|
||||
|
||||
bool get _shouldShowPopupMenu => _isHover || _popupMenuVisible;
|
||||
|
||||
void _onPopupMenuVisibleChange(bool visible) {
|
||||
if (_popupMenuVisible != visible && mounted) {
|
||||
setState(() {
|
||||
_popupMenuVisible = visible;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user