TF-3002 [WEB] Update unselected icon color for filter message button

This commit is contained in:
dab246
2024-09-13 16:06:27 +07:00
committed by Dat H. Pham
parent 0efbece76f
commit 442140d360
10 changed files with 341 additions and 99 deletions
@@ -226,7 +226,13 @@ extension AppColor on Color {
static const colorEmailTileCheckboxUnhover = Color(0xFFAEB7C2);
static const colorEmailTileHoverWeb = Color(0xFFDFEEFF);
static const colorSearchFilterButton = Color(0xFFECEEF1);
static const colorSearchFilterTitle = Color(0xFF686E76);
static const colorSearchFilterIcon = Color(0xFF686E76);
static const colorSuggestionSearchFilterButton = Color(0xFFEBEDF0);
static const colorFilterMessageButton = Color(0xFFEBEDF0);
static const colorFilterMessageIcon = Color(0xFF686E76);
static const colorFilterMessageTitle = Color(0xFF686E76);
static const colorStarredSearchFilterIcon = Color(0xFFFFCC00);
static const mapGradientColor = [
[Color(0xFF21D4FD), Color(0xFFB721FF)],
@@ -19,11 +19,13 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dash
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/filter_message_button_style.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/mailbox_dashboard_view_web_style.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/download/download_task_item_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/mark_mailbox_as_read_loading_banner.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/navigation_bar/navigation_bar_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_filters/filter_message_button.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart';
@@ -258,16 +260,18 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return Row(children: [
Obx(() {
if (controller.isRefreshingAllMailboxAndEmail) {
return const TMailContainerWidget(
return TMailContainerWidget(
borderRadius: 10,
padding: EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 8.5),
child: CupertinoLoadingWidget(size: 16));
backgroundColor: AppColor.colorFilterMessageButton.withOpacity(0.6),
padding: const EdgeInsetsDirectional.symmetric(vertical: 8, horizontal: 8.5),
child: const CupertinoLoadingWidget(size: 16));
} else {
return TMailButtonWidget.fromIcon(
key: const Key('refresh_all_mailbox_and_email_button'),
icon: controller.imagePaths.icRefresh,
borderRadius: 10,
iconSize: 16,
backgroundColor: AppColor.colorFilterMessageButton.withOpacity(0.6),
onTapActionCallback: controller.refreshMailboxAction,
);
}
@@ -287,6 +291,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
width: 16,
height: 16,
fit: BoxFit.fill,
colorFilter: AppColor.colorFilterMessageIcon.asFilter(),
),
label: Text(
AppLocalizations.of(context).selectAllMessagesOfThisPage,
@@ -294,7 +299,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
overflow: TextOverflow.ellipsis
),
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.colorButtonHeaderThread,
backgroundColor: AppColor.colorFilterMessageButton.withOpacity(0.6),
shadowColor: Colors.transparent,
padding: const EdgeInsetsDirectional.symmetric(horizontal: 12, vertical: 8),
shape: const RoundedRectangleBorder(
@@ -303,7 +308,11 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
elevation: 0.0,
foregroundColor: AppColor.colorTextButtonHeaderThread,
maximumSize: const Size.fromWidth(250),
textStyle: const TextStyle(fontSize: 12),
textStyle: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.colorFilterMessageTitle
),
),
),
),
@@ -316,6 +325,11 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
key: const Key('mark_as_read_emails_button'),
text: AppLocalizations.of(context).mark_all_as_read,
icon: controller.imagePaths.icSelectAll,
iconColor: AppColor.colorFilterMessageIcon,
textStyle: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.colorFilterMessageTitle),
borderRadius: 10,
margin: const EdgeInsetsDirectional.only(start: 16),
iconSize: 16,
@@ -327,34 +341,20 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
}
}),
Obx(() {
final filterMessageCurrent = controller.filterMessageOption.value;
if (controller.validateNoEmailsInTrashAndSpamFolder()) {
return const SizedBox.shrink();
} else {
return TMailButtonWidget(
key: const Key('filter_emails_button'),
text: controller.filterMessageOption.value == FilterMessageOption.all
? AppLocalizations.of(context).filter_messages
: controller.filterMessageOption.value.getTitle(context),
icon: controller.filterMessageOption.value.getIconSelected(controller.imagePaths),
borderRadius: 10,
iconSize: 16,
margin: const EdgeInsetsDirectional.only(start: 16),
padding: const EdgeInsetsDirectional.symmetric(horizontal: 12, vertical: 8),
backgroundColor: controller.filterMessageOption.value.getBackgroundColor(),
textStyle: controller.filterMessageOption.value.getTextStyle(),
trailingIcon: controller.imagePaths.icArrowDown,
onTapActionAtPositionCallback: (position) {
return controller.openPopupMenuAction(
context,
position,
popupMenuFilterEmailActionTile(
context,
controller.filterMessageOption.value,
(option) => controller.dispatchAction(FilterMessageAction(context, option)),
isSearchEmailRunning: controller.searchController.isSearchEmailRunning
)
);
},
return Padding(
padding: FilterMessageButtonStyle.buttonMargin,
child: FilterMessageButton(
filterMessageOption: filterMessageCurrent,
imagePaths: controller.imagePaths,
isSelected: filterMessageCurrent != FilterMessageOption.all,
onSelectFilterMessageOptionAction: _onSelectFilterMessageOptionAction,
onDeleteFilterMessageOptionAction: (_) => _onDeleteFilterMessageOptionAction(context),
),
);
}
}),
@@ -365,6 +365,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
icon: controller.imagePaths.icRecoverDeletedMessages,
borderRadius: 10,
iconSize: 16,
backgroundColor: AppColor.colorFilterMessageButton.withOpacity(0.6),
margin: const EdgeInsetsDirectional.only(start: 16),
onTapActionCallback: () => controller.gotoEmailRecovery(),
);
@@ -381,10 +382,34 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return const SizedBox.shrink();
}
})
]);
}
void _onSelectFilterMessageOptionAction(
BuildContext context,
FilterMessageOption filterMessageCurrent,
RelativeRect buttonPosition
) {
controller.openPopupMenuAction(
context,
buttonPosition,
popupMenuFilterEmailActionTile(
context,
filterMessageCurrent,
(filterMessageSelected) {
controller.dispatchAction(FilterMessageAction(
context,
filterMessageSelected));
},
isSearchEmailRunning: controller.searchController.isSearchEmailRunning
)
);
}
void _onDeleteFilterMessageOptionAction(BuildContext context) {
controller.dispatchAction(FilterMessageAction(context, FilterMessageOption.all));
}
Widget _buildDownloadTaskStateWidget() {
return Obx(() {
final listDownloadTasks = controller.downloadController.listDownloadTaskState;
@@ -54,12 +54,12 @@ mixin FilterEmailPopupMenuMixin {
Function(FilterMessageOption)? onCallBack
) {
return InkWell(
onTap: () => onCallBack?.call(option == optionSelected ? FilterMessageOption.all : option),
onTap: () => onCallBack?.call(option),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: SizedBox(
child: Row(children: [
SvgPicture.asset(option.getIcon(_imagePaths),
SvgPicture.asset(option.getContextMenuIcon(_imagePaths),
width: 20,
height: 20,
fit: BoxFit.fill,
@@ -103,7 +103,11 @@ enum QuickSearchFilter {
if (isSelected) {
return AppColor.primaryColor;
} else {
return AppColor.colorTextBody;
if (this == QuickSearchFilter.starred) {
return AppColor.colorStarredSearchFilterIcon;
} else {
return AppColor.colorSearchFilterIcon;
}
}
}
@@ -0,0 +1,25 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
class FilterMessageButtonStyle {
static const double iconSize = 16;
static const double arrowDownIconSize = 18;
static const double deleteIconSize = 10;
static const double spaceSize = 8;
static EdgeInsetsGeometry getButtonPadding(bool isSelected) {
if (isSelected) {
return const EdgeInsetsDirectional.only(start: 12, end: 4, top: 4, bottom: 4);
} else {
return const EdgeInsets.symmetric(horizontal: 12, vertical: 8);
}
}
static const EdgeInsetsGeometry elementPadding = EdgeInsetsDirectional.only(start: 8);
static const EdgeInsetsGeometry buttonMargin = EdgeInsetsDirectional.only(start: 16);
static const BorderRadius borderRadius = BorderRadius.all(Radius.circular(10));
static const TextStyle titleStyle = TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.colorFilterMessageTitle);
}
@@ -19,5 +19,5 @@ class SearchFilterButtonStyle {
static const TextStyle titleStyle = TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.colorTextButtonHeaderThread);
color: AppColor.colorSearchFilterTitle);
}
@@ -0,0 +1,142 @@
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:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/filter_message_button_style.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
typedef OnSelectFilterMessageOptionAction = Function(
BuildContext context,
FilterMessageOption filterMessageOption,
RelativeRect buttonPosition);
typedef OnDeleteFilterMessageOptionAction = Function(FilterMessageOption filterMessageOption);
class FilterMessageButton extends StatelessWidget {
static const int _titleCharactersMaximum = 20;
final FilterMessageOption filterMessageOption;
final bool isSelected;
final ImagePaths imagePaths;
final OnSelectFilterMessageOptionAction? onSelectFilterMessageOptionAction;
final OnDeleteFilterMessageOptionAction? onDeleteFilterMessageOptionAction;
const FilterMessageButton({
super.key,
required this.filterMessageOption,
required this.imagePaths,
this.isSelected = false,
this.onSelectFilterMessageOptionAction,
this.onDeleteFilterMessageOptionAction,
});
@override
Widget build(BuildContext context) {
final filterMessageTitle = filterMessageOption.getTitle(context);
final deleteButtonWidget = TMailButtonWidget.fromIcon(
icon: imagePaths.icDeleteSelection,
iconSize: FilterMessageButtonStyle.deleteIconSize,
iconColor: AppColor.colorFilterMessageIcon,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.transparent,
onTapActionCallback: () => onDeleteFilterMessageOptionAction?.call(filterMessageOption),
);
final listComponentsWidget = [
SvgPicture.asset(
filterMessageOption.getIcon(imagePaths),
width: FilterMessageButtonStyle.iconSize,
height: FilterMessageButtonStyle.iconSize,
colorFilter: filterMessageOption.getIconColor().asFilter(),
fit: BoxFit.fill
),
const SizedBox(width: FilterMessageButtonStyle.spaceSize),
Text(
filterMessageTitle.length > _titleCharactersMaximum
? '${filterMessageTitle.substring(0, _titleCharactersMaximum)}...'
: filterMessageTitle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: FilterMessageButtonStyle.titleStyle,
),
Padding(
padding: FilterMessageButtonStyle.elementPadding,
child: SvgPicture.asset(
imagePaths.icDropDown,
width: FilterMessageButtonStyle.arrowDownIconSize,
height: FilterMessageButtonStyle.arrowDownIconSize,
colorFilter: AppColor.colorFilterMessageIcon.asFilter(),
fit: BoxFit.fill
),
),
];
final childItem = _buildContainerForComponents(
children: [
... listComponentsWidget,
if (isSelected) deleteButtonWidget,
]
);
if (onSelectFilterMessageOptionAction == null) {
return childItem;
}
if (!isSelected) {
return Material(
type: MaterialType.transparency,
child: InkWell(
onTapDown: (details) => _onTapDownAction(context, details),
borderRadius: FilterMessageButtonStyle.borderRadius,
child: childItem
),
);
}
return _buildContainerForComponents(
children: [
InkWell(
onTapDown: (details) => _onTapDownAction(context, details),
borderRadius: FilterMessageButtonStyle.borderRadius,
child: Row(
mainAxisSize: MainAxisSize.min,
children: listComponentsWidget,
),
),
if (isSelected) deleteButtonWidget,
]
);
}
Widget _buildContainerForComponents({required List<Widget> children}) {
return Container(
decoration: BoxDecoration(
borderRadius: FilterMessageButtonStyle.borderRadius,
color: filterMessageOption.getBackgroundColor(isSelected: isSelected)
),
padding: FilterMessageButtonStyle.getButtonPadding(isSelected),
child: Row(
mainAxisSize: MainAxisSize.min,
children: children
)
);
}
void _onTapDownAction(BuildContext context, TapDownDetails details) {
final screenSize = MediaQuery.sizeOf(context);
final offset = details.globalPosition;
final position = RelativeRect.fromLTRB(
offset.dx,
offset.dy,
screenSize.width - offset.dx,
screenSize.height - offset.dy);
onSelectFilterMessageOptionAction?.call(
context,
filterMessageOption,
position);
}
}
@@ -70,68 +70,100 @@ class SearchFilterButton extends StatelessWidget {
listAddressOfTo: listAddressOfTo,
);
final childItem = Container(
decoration: BoxDecoration(
borderRadius: SearchFilterButtonStyle.borderRadius,
color: backgroundColor ?? searchFilter.getBackgroundColor(isFilterSelected: isSelected)),
padding: buttonPadding ?? SearchFilterButtonStyle.getButtonPadding(isSelected),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
searchFilter.getIcon(imagePaths, isSelected: isSelected),
width: SearchFilterButtonStyle.iconSize,
height: SearchFilterButtonStyle.iconSize,
colorFilter: searchFilter.getIconColor(isSelected: isSelected).asFilter(),
fit: BoxFit.fill),
const SizedBox(width: SearchFilterButtonStyle.spaceSize),
Text(
filterTitle.length > _titleCharactersMaximum
? '${filterTitle.substring(0, _titleCharactersMaximum)}...'
: filterTitle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: SearchFilterButtonStyle.titleStyle,
),
if (searchFilter.isArrowDownIconSupported())
Padding(
padding: SearchFilterButtonStyle.elementPadding,
child: SvgPicture.asset(
imagePaths.icDropDown,
width: SearchFilterButtonStyle.iconSize,
height: SearchFilterButtonStyle.iconSize,
colorFilter: AppColor.colorTextBody.asFilter(),
fit: BoxFit.fill),
),
if (isSelected)
TMailButtonWidget.fromIcon(
icon: imagePaths.icDeleteSelection,
iconSize: SearchFilterButtonStyle.deleteIconSize,
iconColor: AppColor.colorTextBody,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.transparent,
onTapActionCallback: () => onDeleteSearchFilterAction?.call(searchFilter),
),
]
)
final deleteButtonWidget = TMailButtonWidget.fromIcon(
icon: imagePaths.icDeleteSelection,
iconSize: SearchFilterButtonStyle.deleteIconSize,
iconColor: AppColor.colorTextBody,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.transparent,
onTapActionCallback: () => onDeleteSearchFilterAction?.call(searchFilter),
);
if (onSelectSearchFilterAction != null) {
final listComponentsWidget = <Widget>[
SvgPicture.asset(
searchFilter.getIcon(imagePaths, isSelected: isSelected),
width: SearchFilterButtonStyle.iconSize,
height: SearchFilterButtonStyle.iconSize,
colorFilter: searchFilter.getIconColor(isSelected: isSelected).asFilter(),
fit: BoxFit.fill
),
const SizedBox(width: SearchFilterButtonStyle.spaceSize),
Text(
filterTitle.length > _titleCharactersMaximum
? '${filterTitle.substring(0, _titleCharactersMaximum)}...'
: filterTitle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: SearchFilterButtonStyle.titleStyle,
),
if (searchFilter.isArrowDownIconSupported())
Padding(
padding: SearchFilterButtonStyle.elementPadding,
child: SvgPicture.asset(
imagePaths.icDropDown,
width: SearchFilterButtonStyle.iconSize,
height: SearchFilterButtonStyle.iconSize,
colorFilter: AppColor.colorTextBody.asFilter(),
fit: BoxFit.fill
),
),
];
final childItem = _buildContainerForComponents(
children: [
...listComponentsWidget,
if (isSelected) deleteButtonWidget,
]
);
if (onSelectSearchFilterAction == null) {
return childItem;
}
if (!searchFilter.isOnTapWithPositionActionSupported()) {
return Material(
type: MaterialType.transparency,
child: InkWell(
onTap: searchFilter.isOnTapWithPositionActionSupported()
? null
: () => _onTapAction(context),
onTapDown: searchFilter.isOnTapWithPositionActionSupported()
onTap: !searchFilter.isOnTapWithPositionActionSupported()
? () => _onTapAction(context)
: null,
onTapDown: searchFilter.isOnTapWithPositionActionSupported() && !isSelected
? (details) => _onTapDownAction(context, details)
: null,
borderRadius: SearchFilterButtonStyle.borderRadius,
child: childItem),
child: childItem
),
);
} else {
return childItem;
}
return _buildContainerForComponents(
children: [
InkWell(
onTapDown: (details) => _onTapDownAction(context, details),
child: Row(
mainAxisSize: MainAxisSize.min,
children: listComponentsWidget
),
),
if (isSelected) deleteButtonWidget,
]
);
}
Widget _buildContainerForComponents({required List<Widget> children}) {
return Container(
decoration: BoxDecoration(
borderRadius: SearchFilterButtonStyle.borderRadius,
color: backgroundColor ?? searchFilter.getBackgroundColor(
isFilterSelected: isSelected
)
),
padding: buttonPadding ?? SearchFilterButtonStyle.getButtonPadding(isSelected),
child: Row(
mainAxisSize: MainAxisSize.min,
children: children
)
);
}
void _onTapAction(BuildContext context) {
@@ -43,7 +43,7 @@ extension FilterMessageOptionExtension on FilterMessageOption {
String getTitle(BuildContext context) {
switch(this) {
case FilterMessageOption.all:
return '';
return AppLocalizations.of(context).filter_messages;
case FilterMessageOption.unread:
return AppLocalizations.of(context).with_unread;
case FilterMessageOption.attachments:
@@ -92,7 +92,7 @@ extension FilterMessageOptionExtension on FilterMessageOption {
}
}
String getIcon(ImagePaths imagePaths) {
String getContextMenuIcon(ImagePaths imagePaths) {
switch(this) {
case FilterMessageOption.all:
return '';
@@ -105,7 +105,7 @@ extension FilterMessageOptionExtension on FilterMessageOption {
}
}
String getIconSelected(ImagePaths imagePaths) {
String getIcon(ImagePaths imagePaths) {
switch(this) {
case FilterMessageOption.all:
return imagePaths.icFilterAdvanced;
@@ -116,14 +116,22 @@ extension FilterMessageOptionExtension on FilterMessageOption {
}
}
Color getBackgroundColor() {
Color getIconColor() {
switch(this) {
case FilterMessageOption.all:
return AppColor.colorButtonHeaderThread;
return AppColor.colorFilterMessageIcon;
case FilterMessageOption.unread:
case FilterMessageOption.attachments:
case FilterMessageOption.starred:
return AppColor.colorItemEmailSelectedDesktop;
return AppColor.primaryColor;
}
}
Color getBackgroundColor({bool isSelected = false}) {
if (isSelected) {
return AppColor.primaryColor.withOpacity(0.06);
} else {
return AppColor.colorFilterMessageButton.withOpacity(0.6);
}
}
@@ -131,16 +139,16 @@ extension FilterMessageOptionExtension on FilterMessageOption {
switch(this) {
case FilterMessageOption.all:
return const TextStyle(
fontSize: 12,
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.colorTextButtonHeaderThread);
color: AppColor.colorFilterMessageTitle);
case FilterMessageOption.unread:
case FilterMessageOption.attachments:
case FilterMessageOption.starred:
return const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColor.colorTextButton);
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.primaryColor);
}
}
}
@@ -320,7 +320,7 @@ class ThreadView extends GetWidget<ThreadController>
return listFilter.map((filter) => (FilterMessageCupertinoActionSheetActionBuilder(
Key('filter_email_${filter.name}'),
SvgPicture.asset(
filter.getIcon(controller.imagePaths),
filter.getContextMenuIcon(controller.imagePaths),
width: 20,
height: 20,
fit: BoxFit.fill,