TF-933 Add contact From/To button to search filter

This commit is contained in:
dab246
2022-09-20 11:13:24 +07:00
committed by Dat H. Pham
parent 5d0a6e8e15
commit 09fa15289d
5 changed files with 136 additions and 12 deletions
@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.37301 6.42334C4.13339 6.21796 3.77265 6.24571 3.56727 6.48532C3.36188 6.72494 3.38963 7.08568 3.62925 7.29107L7.62925 10.7196C7.84324 10.9031 8.15901 10.9031 8.37301 10.7196L12.373 7.29107C12.6126 7.08568 12.6404 6.72494 12.435 6.48532C12.2296 6.24571 11.8689 6.21796 11.6292 6.42334L8.00113 9.53316L4.37301 6.42334Z" fill="#99A2AD"/>
</svg>

After

Width:  |  Height:  |  Size: 450 B

@@ -160,6 +160,7 @@ class ImagePaths {
String get icClock => _getImagePath('ic_clock.svg'); String get icClock => _getImagePath('ic_clock.svg');
String get icCalendar => _getImagePath('ic_calendar.svg'); String get icCalendar => _getImagePath('ic_calendar.svg');
String get icAddEmailForward => _getImagePath('ic_add_email_forwards.svg'); String get icAddEmailForward => _getImagePath('ic_add_email_forwards.svg');
String get icChevronDownOutline => _getImagePath('ic_chevron_down_outline.svg');
String _getImagePath(String imageName) { String _getImagePath(String imageName) {
return AssetsPaths.images + imageName; return AssetsPaths.images + imageName;
@@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart';
import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart';
@@ -7,9 +8,11 @@ import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
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_receive_time_type.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class SimpleSearchFilter with EquatableMixin { class SimpleSearchFilter with EquatableMixin {
final Set<String> from; final Set<String> from;
final Set<String> to;
final SearchQuery? text; final SearchQuery? text;
final PresentationMailbox? mailbox; final PresentationMailbox? mailbox;
final EmailReceiveTimeType emailReceiveTimeType; final EmailReceiveTimeType emailReceiveTimeType;
@@ -18,17 +21,20 @@ class SimpleSearchFilter with EquatableMixin {
SimpleSearchFilter({ SimpleSearchFilter({
Set<String>? from, Set<String>? from,
Set<String>? to,
EmailReceiveTimeType? emailReceiveTimeType, EmailReceiveTimeType? emailReceiveTimeType,
bool? hasAttachment, bool? hasAttachment,
this.text, this.text,
this.before, this.before,
this.mailbox, this.mailbox,
}) : from = from ?? <String>{}, }) : from = from ?? <String>{},
to = to ?? <String>{},
hasAttachment = hasAttachment ?? false, hasAttachment = hasAttachment ?? false,
emailReceiveTimeType = emailReceiveTimeType ?? EmailReceiveTimeType.allTime; emailReceiveTimeType = emailReceiveTimeType ?? EmailReceiveTimeType.allTime;
SimpleSearchFilter copyWith({ SimpleSearchFilter copyWith({
Set<String>? from, Set<String>? from,
Set<String>? to,
SearchQuery? text, SearchQuery? text,
PresentationMailbox? mailbox, PresentationMailbox? mailbox,
EmailReceiveTimeType? emailReceiveTimeType, EmailReceiveTimeType? emailReceiveTimeType,
@@ -37,6 +43,7 @@ class SimpleSearchFilter with EquatableMixin {
}) { }) {
return SimpleSearchFilter( return SimpleSearchFilter(
from: from ?? this.from, from: from ?? this.from,
to: to ?? this.to,
text: text ?? this.text, text: text ?? this.text,
mailbox: mailbox ?? this.mailbox, mailbox: mailbox ?? this.mailbox,
emailReceiveTimeType: emailReceiveTimeType ?? this.emailReceiveTimeType, emailReceiveTimeType: emailReceiveTimeType ?? this.emailReceiveTimeType,
@@ -63,6 +70,10 @@ class SimpleSearchFilter with EquatableMixin {
LogicFilterOperator( LogicFilterOperator(
Operator.AND, Operator.AND,
from.map((e) => EmailFilterCondition(from: e)).toSet()), from.map((e) => EmailFilterCondition(from: e)).toSet()),
if (to.isNotEmpty)
LogicFilterOperator(
Operator.AND,
to.map((e) => EmailFilterCondition(to: e)).toSet()),
}; };
return listEmailCondition.isNotEmpty return listEmailCondition.isNotEmpty
@@ -71,7 +82,7 @@ class SimpleSearchFilter with EquatableMixin {
} }
@override @override
List<Object?> get props => [from, text, mailbox, emailReceiveTimeType, hasAttachment, before]; List<Object?> get props => [from, to, text, mailbox, emailReceiveTimeType, hasAttachment, before];
} }
extension SearchEmailFilterExtension on SimpleSearchFilter { extension SearchEmailFilterExtension on SimpleSearchFilter {
@@ -79,6 +90,7 @@ extension SearchEmailFilterExtension on SimpleSearchFilter {
SimpleSearchFilter toSimpleSearchFilterByBefore({UTCDate? newBefore}) { SimpleSearchFilter toSimpleSearchFilterByBefore({UTCDate? newBefore}) {
return SimpleSearchFilter( return SimpleSearchFilter(
from: from, from: from,
to: to,
text: text, text: text,
mailbox: mailbox, mailbox: mailbox,
emailReceiveTimeType: emailReceiveTimeType, emailReceiveTimeType: emailReceiveTimeType,
@@ -100,5 +112,53 @@ extension SearchEmailFilterExtension on SimpleSearchFilter {
bool get searchFilterByMailboxApplied => mailbox != null; bool get searchFilterByMailboxApplied => mailbox != null;
bool get searchFilterByFromApplied => from.isNotEmpty;
bool get searchFilterByToApplied => to.isNotEmpty;
bool searchFilterByContactApplied(PrefixEmailAddress prefixEmailAddress) {
switch(prefixEmailAddress) {
case PrefixEmailAddress.from:
return searchFilterByFromApplied;
case PrefixEmailAddress.to:
return searchFilterByToApplied;
default:
return false;
}
}
Set<String> getContactApplied(PrefixEmailAddress prefixEmailAddress) {
switch(prefixEmailAddress) {
case PrefixEmailAddress.from:
return from;
case PrefixEmailAddress.to:
return to;
default:
return {};
}
}
String getNameContactApplied(PrefixEmailAddress prefixEmailAddress) {
switch(prefixEmailAddress) {
case PrefixEmailAddress.from:
return from.first;
case PrefixEmailAddress.to:
return to.first;
default:
return '';
}
}
String getNameContactDefault(BuildContext context, PrefixEmailAddress prefixEmailAddress) {
switch(prefixEmailAddress) {
case PrefixEmailAddress.from:
return AppLocalizations.of(context).from_email_address_prefix;
case PrefixEmailAddress.to:
return AppLocalizations.of(context).to_email_address_prefix;
default:
return '';
}
}
String get mailboxName => mailbox?.name?.name ?? ''; String get mailboxName => mailbox?.name?.name ?? '';
} }
@@ -441,6 +441,13 @@ class SearchEmailController extends BaseController
} }
} }
void selectContactForSearchFilter(
BuildContext context,
PrefixEmailAddress prefixEmailAddress
) async {
}
void _updateSimpleSearchFilter({ void _updateSimpleSearchFilter({
Set<String>? from, Set<String>? from,
SearchQuery? text, SearchQuery? text,
@@ -546,9 +553,7 @@ class SearchEmailController extends BaseController
void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) { void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) {
listResultSearch.value = listResultSearch listResultSearch.value = listResultSearch
.map((email) => email.id == presentationEmailSelected.id .map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
? email.toggleSelect()
: email)
.toList(); .toList();
if (listResultSearch.isAllSelectionInActive) { if (listResultSearch.isAllSelectionInActive) {
@@ -6,7 +6,6 @@ import 'package:core/presentation/utils/style_utils.dart';
import 'package:core/presentation/views/background/background_widget_builder.dart'; import 'package:core/presentation/views/background/background_widget_builder.dart';
import 'package:core/presentation/views/button/icon_button_web.dart'; import 'package:core/presentation/views/button/icon_button_web.dart';
import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/presentation/views/text/text_field_builder.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/utils/build_utils.dart'; import 'package:core/utils/build_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@@ -163,8 +162,9 @@ class SearchEmailView extends GetWidget<SearchEmailController>
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: [ children: [
_buildSearchFilterByContactButton(context, PrefixEmailAddress.from),
_buildSearchFilterByContactButton(context, PrefixEmailAddress.to),
...[ ...[
QuickSearchFilter.fromMe,
QuickSearchFilter.hasAttachment, QuickSearchFilter.hasAttachment,
QuickSearchFilter.last7Days QuickSearchFilter.last7Days
].map((filter) => _buildQuickSearchFilterButton(context, filter)), ].map((filter) => _buildQuickSearchFilterButton(context, filter)),
@@ -177,7 +177,6 @@ class SearchEmailView extends GetWidget<SearchEmailController>
Widget _buildQuickSearchFilterButton(BuildContext context, QuickSearchFilter filter) { Widget _buildQuickSearchFilterButton(BuildContext context, QuickSearchFilter filter) {
return Obx(() { return Obx(() {
final filterSelected = controller.checkQuickSearchFilterSelected(filter); final filterSelected = controller.checkQuickSearchFilterSelected(filter);
log('SearchEmailView::_buildQuickSearchFilterButton(): filterSelected: $filterSelected');
return Padding( return Padding(
padding: const EdgeInsets.only(right: 8), padding: const EdgeInsets.only(right: 8),
child: InkWell( child: InkWell(
@@ -237,9 +236,10 @@ class SearchEmailView extends GetWidget<SearchEmailController>
... [ ... [
const SizedBox(width: 4), const SizedBox(width: 4),
SvgPicture.asset( SvgPicture.asset(
_imagePaths.icChevronDown, _imagePaths.icChevronDownOutline,
width: 16, color: filterSelected
height: 16, ? AppColor.primaryColor
: AppColor.colorDefaultRichTextButton,
fit: BoxFit.fill), fit: BoxFit.fill),
] ]
]) ])
@@ -253,7 +253,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
BuildContext context, BuildContext context,
EmailReceiveTimeType? receiveTimeSelected, EmailReceiveTimeType? receiveTimeSelected,
Function(EmailReceiveTimeType?)? onCallBack Function(EmailReceiveTimeType?)? onCallBack
) { ) {
return EmailReceiveTimeType.values return EmailReceiveTimeType.values
.map((timeType) => PopupMenuItem( .map((timeType) => PopupMenuItem(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@@ -553,10 +553,65 @@ class SearchEmailView extends GetWidget<SearchEmailController>
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
SvgPicture.asset( SvgPicture.asset(
_imagePaths.icChevronDown, _imagePaths.icChevronDownOutline,
color: filterSelected
? AppColor.primaryColor
: AppColor.colorDefaultRichTextButton,
fit: BoxFit.fill),
])
),
),
);
});
}
Widget _buildSearchFilterByContactButton(BuildContext context, PrefixEmailAddress prefixEmailAddress) {
return Obx(() {
final filterSelected = controller.simpleSearchFilter.value
.searchFilterByContactApplied(prefixEmailAddress);
return Padding(
padding: const EdgeInsets.only(right: 8),
child: InkWell(
onTap: () => controller.selectContactForSearchFilter(context, prefixEmailAddress),
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: filterSelected
? AppColor.colorItemEmailSelectedDesktop
: AppColor.colorButtonHeaderThread),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
SvgPicture.asset(
filterSelected ? _imagePaths.icSelectedSB : _imagePaths.icUserSB,
width: 16, width: 16,
height: 16, height: 16,
fit: BoxFit.fill), fit: BoxFit.fill),
const SizedBox(width: 4),
Text(
filterSelected
? controller.simpleSearchFilter.value.getNameContactApplied(prefixEmailAddress)
: controller.simpleSearchFilter.value.getNameContactDefault(context, prefixEmailAddress),
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: filterSelected
? const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: AppColor.colorTextButton)
: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColor.colorTextButtonHeaderThread)
),
const SizedBox(width: 4),
SvgPicture.asset(
_imagePaths.icChevronDownOutline,
color: filterSelected
? AppColor.primaryColor
: AppColor.colorDefaultRichTextButton,
fit: BoxFit.fill),
]) ])
), ),
), ),