TF-3704 Re-arrange layout for mailbox item in left side bar and destination picker

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-05-05 14:40:03 +07:00
committed by Dat H. Pham
parent d5946542e0
commit fd388f1674
13 changed files with 261 additions and 224 deletions
@@ -1,7 +1,6 @@
import 'package:core/presentation/utils/style_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/count_of_emails_styles.dart';
import 'package:flutter/material.dart';
class CountOfEmailsWidget extends StatelessWidget {
@@ -16,10 +15,8 @@ class CountOfEmailsWidget extends StatelessWidget {
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontSize: CountOfEmailsStyles.textSize,
color: CountOfEmailsStyles.textColor,
fontWeight: CountOfEmailsStyles.textFontWeight
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.black,
),
);
}
@@ -1,3 +1,4 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/text/text_overflow_builder.dart';
import 'package:flutter/material.dart';
@@ -7,80 +8,128 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.d
import 'package:tmail_ui_user/features/mailbox/presentation/styles/label_mailbox_item_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_method_action_define.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/empty_mailbox_popup_dialog_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_expand_button.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/trailing_mailbox_item_widget.dart';
class LabelMailboxItemWidget extends StatelessWidget {
final ResponsiveUtils responsiveUtils;
final ImagePaths imagePaths;
final MailboxNode mailboxNode;
final bool showTrailing;
final bool isItemHovered;
final bool isSelected;
final OnClickOpenMenuMailboxNodeAction? onMenuActionClick;
final OnEmptyMailboxActionCallback? onEmptyMailboxActionCallback;
final OnClickExpandMailboxNodeAction? onClickExpandMailboxNodeAction;
const LabelMailboxItemWidget({
super.key,
required this.mailboxNode,
required this.responsiveUtils,
required this.imagePaths,
this.showTrailing = true,
this.isItemHovered = false,
this.isSelected = false,
this.onMenuActionClick,
this.onEmptyMailboxActionCallback,
this.onClickExpandMailboxNodeAction,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
final displayNameWidget = TextOverflowBuilder(
mailboxNode.item.getDisplayName(context),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: LabelMailboxItemWidgetStyles.labelFolderTextSize,
color: LabelMailboxItemWidgetStyles.labelFolderTextColor,
fontWeight: _mailboxNameTextFontWeight,
),
);
final nameWithExpandIcon = Row(
children: [
if (showTrailing)
Row(
children: [
Expanded(
child: TextOverflowBuilder(
mailboxNode.item.getDisplayName(context),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: LabelMailboxItemWidgetStyles.labelFolderTextSize,
color: LabelMailboxItemWidgetStyles.labelFolderTextColor,
fontWeight: _mailboxNameTextFontWeight
),
),
),
if (responsiveUtils.isWebDesktop(context) && mailboxNode.item.allowedHasEmptyAction)
EmptyMailboxPopupDialogWidget(
mailboxNode: mailboxNode,
onEmptyMailboxActionCallback: (mailboxNode) => onEmptyMailboxActionCallback?.call(mailboxNode),
),
TrailingMailboxItemWidget(
mailboxNode: mailboxNode,
isItemHovered: isItemHovered,
onMenuActionClick: onMenuActionClick
)
],
)
if (mailboxNode.hasChildren())
Flexible(child: displayNameWidget)
else
TextOverflowBuilder(
mailboxNode.item.getDisplayName(context),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: LabelMailboxItemWidgetStyles.labelFolderTextSize,
color: LabelMailboxItemWidgetStyles.labelFolderTextColor,
fontWeight: _mailboxNameTextFontWeight
Flexible(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: displayNameWidget,
),
),
if (mailboxNode.item.isTeamMailboxes)
if (mailboxNode.hasChildren())
MailboxExpandButton(
mailboxNode: mailboxNode,
imagePaths: imagePaths,
onExpandFolderActionClick: onClickExpandMailboxNodeAction,
),
],
);
if (!showTrailing) {
if (mailboxNode.item.isTeamMailboxes) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
nameWithExpandIcon,
TextOverflowBuilder(
mailboxNode.item.emailTeamMailBoxes,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: LabelMailboxItemWidgetStyles.labelFolderTextSize,
color: LabelMailboxItemWidgetStyles.teamMailboxEmailTextColor,
fontWeight: LabelMailboxItemWidgetStyles.labelFolderTextFontWeight,
),
),
],
);
} else {
return nameWithExpandIcon;
}
}
final trailingWidget = TrailingMailboxItemWidget(
mailboxNode: mailboxNode,
responsiveUtils: responsiveUtils,
imagePaths: imagePaths,
isItemHovered: isItemHovered,
onMenuActionClick: onMenuActionClick,
);
final childWidget = Row(
children: [
Expanded(child: nameWithExpandIcon),
if (responsiveUtils.isWebDesktop(context) &&
mailboxNode.item.allowedHasEmptyAction)
EmptyMailboxPopupDialogWidget(
mailboxNode: mailboxNode,
onEmptyMailboxActionCallback: (mailboxNode) =>
onEmptyMailboxActionCallback?.call(mailboxNode),
),
trailingWidget,
],
);
if (mailboxNode.item.isTeamMailboxes) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
childWidget,
TextOverflowBuilder(
mailboxNode.item.emailTeamMailBoxes,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: LabelMailboxItemWidgetStyles.labelFolderTextSize,
color: LabelMailboxItemWidgetStyles.teamMailboxEmailTextColor,
fontWeight: LabelMailboxItemWidgetStyles.labelFolderTextFontWeight
fontWeight: LabelMailboxItemWidgetStyles.labelFolderTextFontWeight,
),
)
],
);
),
],
);
} else {
return childWidget;
}
}
FontWeight get _mailboxNameTextFontWeight {
@@ -1,16 +1,11 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/direction_utils.dart';
import 'package:flutter/material.dart';
import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/leading_mailbox_item_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_method_action_define.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_icon_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class LeadingMailboxItemWidget extends StatelessWidget {
@@ -18,63 +13,25 @@ class LeadingMailboxItemWidget extends StatelessWidget {
final MailboxNode mailboxNode;
final SelectMode selectionMode;
final OnSelectMailboxNodeAction? onSelectMailboxFolderClick;
final OnClickExpandMailboxNodeAction? onExpandFolderActionClick;
const LeadingMailboxItemWidget({
super.key,
required this.imagePaths,
required this.mailboxNode,
this.selectionMode = SelectMode.INACTIVE,
this.onExpandFolderActionClick,
this.onSelectMailboxFolderClick,
});
@override
Widget build(BuildContext context) {
return Row(children: [
Visibility.maintain(
visible: mailboxNode.hasChildren(),
child: TMailButtonWidget.fromIcon(
icon: _getExpandIcon(context, imagePaths),
iconColor: _expandIconColor,
iconSize: 20,
padding: const EdgeInsets.all(5),
backgroundColor: Colors.transparent,
tooltipMessage: _getExpandTooltipMessage(context),
onTapActionCallback: () => onExpandFolderActionClick?.call(mailboxNode)
),
),
Transform(
transform: LeadingMailboxItemWidgetStyles.mailboxIconTransform(context),
child: MailboxIconWidget(
imagePaths: imagePaths,
mailboxNode: mailboxNode,
selectionMode: selectionMode,
onSelectMailboxFolderClick: onSelectMailboxFolderClick
)
),
]);
}
String _getExpandIcon(BuildContext context, ImagePaths imagePaths) {
if (mailboxNode.expandMode == ExpandMode.EXPAND) {
return imagePaths.icArrowBottom;
} else {
return DirectionUtils.isDirectionRTLByLanguage(context)
? imagePaths.icArrowLeft
: imagePaths.icArrowRight;
}
}
Color get _expandIconColor {
return mailboxNode.item.allowedToDisplay
? LeadingMailboxItemWidgetStyles.displayColor
: LeadingMailboxItemWidgetStyles.normalColor;
}
String _getExpandTooltipMessage(BuildContext context) {
return mailboxNode.expandMode == ExpandMode.EXPAND
? AppLocalizations.of(context).collapse
: AppLocalizations.of(context).expand;
return Transform(
transform: LeadingMailboxItemWidgetStyles.mailboxIconTransform(context),
child: MailboxIconWidget(
imagePaths: imagePaths,
mailboxNode: mailboxNode,
selectionMode: selectionMode,
onSelectMailboxFolderClick: onSelectMailboxFolderClick
)
);
}
}
@@ -0,0 +1,58 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/direction_utils.dart';
import 'package:flutter/material.dart';
import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_method_action_define.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class MailboxExpandButton extends StatelessWidget {
final MailboxNode mailboxNode;
final ImagePaths imagePaths;
final OnClickExpandMailboxNodeAction? onExpandFolderActionClick;
const MailboxExpandButton({
super.key,
required this.mailboxNode,
required this.imagePaths,
required this.onExpandFolderActionClick,
});
@override
Widget build(BuildContext context) {
return TMailButtonWidget.fromIcon(
icon: _getExpandIcon(context, imagePaths),
iconColor: _expandIconColor,
iconSize: 20,
padding: const EdgeInsets.all(5),
backgroundColor: Colors.transparent,
tooltipMessage: _getExpandTooltipMessage(context),
onTapActionCallback: () => onExpandFolderActionClick?.call(mailboxNode),
);
}
String _getExpandIcon(BuildContext context, ImagePaths imagePaths) {
if (mailboxNode.expandMode == ExpandMode.EXPAND) {
return imagePaths.icArrowBottom;
} else {
return DirectionUtils.isDirectionRTLByLanguage(context)
? imagePaths.icArrowLeft
: imagePaths.icArrowRight;
}
}
Color get _expandIconColor {
return mailboxNode.item.allowedToDisplay
? Colors.black
: AppColor.steelGray200;
}
String _getExpandTooltipMessage(BuildContext context) {
return mailboxNode.expandMode == ExpandMode.EXPAND
? AppLocalizations.of(context).collapse
: AppLocalizations.of(context).expand;
}
}
@@ -77,7 +77,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
color: backgroundColorItem
),
padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.padding,
horizontal: MailboxItemWidgetStyles.itemPadding,
vertical: MailboxItemWidgetStyles.space,
),
child: Row(
@@ -91,17 +91,18 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
mailboxNode: widget.mailboxNode,
selectionMode: widget.selectionMode,
onSelectMailboxFolderClick: widget.onSelectMailboxFolderClick,
onExpandFolderActionClick: widget.onExpandFolderActionClick,
),
const SizedBox(width: MailboxItemWidgetStyles.space),
Expanded(
child: LabelMailboxItemWidget(
responsiveUtils: _responsiveUtils,
mailboxNode: widget.mailboxNode,
imagePaths: _imagePaths,
isItemHovered: _isItemHovered,
isSelected: _isSelected,
onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
)
),
]
@@ -123,7 +124,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
color: backgroundColorItem
),
padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.padding,
horizontal: MailboxItemWidgetStyles.itemPadding,
vertical: MailboxItemWidgetStyles.space,
),
child: Row(
@@ -133,17 +134,18 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
mailboxNode: widget.mailboxNode,
selectionMode: widget.selectionMode,
onSelectMailboxFolderClick: widget.onSelectMailboxFolderClick,
onExpandFolderActionClick: widget.onExpandFolderActionClick,
),
const SizedBox(width: MailboxItemWidgetStyles.space),
Expanded(
child: LabelMailboxItemWidget(
responsiveUtils: _responsiveUtils,
mailboxNode: widget.mailboxNode,
imagePaths: _imagePaths,
isItemHovered: _isItemHovered,
isSelected: _isSelected,
onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
)
),
]
@@ -165,42 +167,37 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
color: backgroundColorItem
),
padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.padding,
horizontal: MailboxItemWidgetStyles.itemPadding,
vertical: MailboxItemWidgetStyles.space,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
child: Row(
children: [
Row(
children: [
LeadingMailboxItemWidget(
imagePaths: _imagePaths,
mailboxNode: widget.mailboxNode,
selectionMode: widget.selectionMode,
onSelectMailboxFolderClick: widget.onSelectMailboxFolderClick,
onExpandFolderActionClick: widget.onExpandFolderActionClick,
),
const SizedBox(width: MailboxItemWidgetStyles.padding),
Expanded(
child: LabelMailboxItemWidget(
responsiveUtils: _responsiveUtils,
mailboxNode: widget.mailboxNode,
isItemHovered: _isItemHovered,
isSelected: _isSelected,
onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback
)
),
if (_isSelectActionNoValid)
SvgPicture.asset(
_imagePaths.icSelectedSB,
width: MailboxItemWidgetStyles.selectionIconSize,
height: MailboxItemWidgetStyles.selectionIconSize,
fit: BoxFit.fill
)
]
LeadingMailboxItemWidget(
imagePaths: _imagePaths,
mailboxNode: widget.mailboxNode,
selectionMode: widget.selectionMode,
onSelectMailboxFolderClick: widget.onSelectMailboxFolderClick,
),
const SizedBox(width: MailboxItemWidgetStyles.padding),
Expanded(
child: LabelMailboxItemWidget(
responsiveUtils: _responsiveUtils,
mailboxNode: widget.mailboxNode,
imagePaths: _imagePaths,
isItemHovered: _isItemHovered,
isSelected: _isSelected,
onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
)
),
if (_isSelectActionNoValid)
SvgPicture.asset(
_imagePaths.icSelectedSB,
width: MailboxItemWidgetStyles.selectionIconSize,
height: MailboxItemWidgetStyles.selectionIconSize,
fit: BoxFit.fill
)
]
),
),
@@ -222,7 +219,7 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
hoverColor: AppColor.colorMailboxHovered,
child: Container(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: MailboxItemWidgetStyles.padding,
horizontal: MailboxItemWidgetStyles.itemPadding,
vertical: MailboxItemWidgetStyles.space,
),
color: widget.mailboxNode.isSelected
@@ -235,18 +232,19 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
mailboxNode: widget.mailboxNode,
selectionMode: widget.selectionMode,
onSelectMailboxFolderClick: widget.onSelectMailboxFolderClick,
onExpandFolderActionClick: widget.onExpandFolderActionClick,
),
const SizedBox(width: MailboxItemWidgetStyles.padding),
Expanded(
child: LabelMailboxItemWidget(
responsiveUtils: _responsiveUtils,
mailboxNode: widget.mailboxNode,
imagePaths: _imagePaths,
showTrailing: false,
isSelected: _isSelected,
isItemHovered: _isItemHovered,
onMenuActionClick: widget.onMenuActionClick,
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback
onEmptyMailboxActionCallback: widget.onEmptyMailboxActionCallback,
onClickExpandMailboxNodeAction: widget.onExpandFolderActionClick,
)
),
if (_isSelectActionNoValid)
@@ -256,7 +254,6 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
height: MailboxItemWidgetStyles.selectionIconSize,
fit: BoxFit.fill
),
const SizedBox(width: MailboxItemWidgetStyles.padding),
]
)
),
@@ -4,7 +4,6 @@ import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/trailing_mailbox_item_widget_styles.dart';
@@ -14,15 +13,16 @@ import 'package:tmail_ui_user/features/mailbox/presentation/widgets/count_of_ema
class TrailingMailboxItemWidget extends StatelessWidget {
final MailboxNode mailboxNode;
final ImagePaths imagePaths;
final ResponsiveUtils responsiveUtils;
final bool isItemHovered;
final OnClickOpenMenuMailboxNodeAction? onMenuActionClick;
final _imagePaths = Get.find<ImagePaths>();
final _responsiveUtils = Get.find<ResponsiveUtils>();
TrailingMailboxItemWidget({
const TrailingMailboxItemWidget({
super.key,
required this.mailboxNode,
required this.imagePaths,
required this.responsiveUtils,
this.isItemHovered = false,
this.onMenuActionClick,
});
@@ -32,16 +32,16 @@ class TrailingMailboxItemWidget extends StatelessWidget {
if (PlatformInfo.isWeb) {
if (isItemHovered) {
return TMailButtonWidget.fromIcon(
margin: _responsiveUtils.isDesktop(context) && mailboxNode.item.allowedHasEmptyAction
margin: responsiveUtils.isDesktop(context) && mailboxNode.item.allowedHasEmptyAction
? EdgeInsets.zero
: TrailingMailboxItemWidgetStyles.menuIconMargin,
icon: _imagePaths.icComposerMenu,
icon: imagePaths.icComposerMenu,
iconSize: TrailingMailboxItemWidgetStyles.menuIconSize,
padding: TrailingMailboxItemWidgetStyles.menuIconPadding,
backgroundColor: TrailingMailboxItemWidgetStyles.menuIconBackgroundColor,
onTapActionAtPositionCallback: (position) => onMenuActionClick?.call(position, mailboxNode),
);
} else if (_responsiveUtils.isDesktop(context) && mailboxNode.item.allowedHasEmptyAction) {
} else if (responsiveUtils.isDesktop(context) && mailboxNode.item.allowedHasEmptyAction) {
return const SizedBox();
} else if (mailboxNode.item.allowedToDisplayCountOfUnreadEmails) {
return Padding(