enable remove suggestion tag in from field

This commit is contained in:
ManhNTX
2022-07-01 06:49:27 +07:00
committed by Dat H. Pham
parent 0f46a1c899
commit 263ee35a0a
9 changed files with 374 additions and 169 deletions
@@ -2,23 +2,24 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
typedef OnOpenSearchViewAction = Function(); typedef OnOpenSearchViewAction = Function();
class SearchBarView { class SearchBarView {
OnOpenSearchViewAction? _onOpenSearchViewAction; OnOpenSearchViewAction? _onOpenSearchViewAction;
final ImagePaths _imagePaths; final ImagePaths _imagePaths;
double? _heightSearchBar; double? _heightSearchBar;
EdgeInsets? _padding; EdgeInsets? _padding;
EdgeInsets? _margin; EdgeInsets? _margin;
String? _hintTextSearch; String? _hintTextSearch;
double? _maxSizeWidth; double? _maxSizeWidth;
Widget? _rightButton;
SearchBarView(this._imagePaths);
SearchBarView(this._imagePaths);
void addOnOpenSearchViewAction(OnOpenSearchViewAction onOpenSearchViewAction) { void addOnOpenSearchViewAction(OnOpenSearchViewAction onOpenSearchViewAction) {
_onOpenSearchViewAction = onOpenSearchViewAction; _onOpenSearchViewAction = onOpenSearchViewAction;
@@ -32,6 +33,10 @@ class SearchBarView {
_padding = padding; _padding = padding;
} }
void addRightButton(Widget rightButton) {
_rightButton = rightButton;
}
void addMargin(EdgeInsets margin) { void addMargin(EdgeInsets margin) {
_margin = margin; _margin = margin;
} }
@@ -55,26 +60,29 @@ class SearchBarView {
color: AppColor.colorBgSearchBar), color: AppColor.colorBgSearchBar),
padding: _padding ?? EdgeInsets.zero, padding: _padding ?? EdgeInsets.zero,
margin: _margin ?? EdgeInsets.zero, margin: _margin ?? EdgeInsets.zero,
child: InkWell( child: Row(
onTap: () => _onOpenSearchViewAction?.call(), mainAxisAlignment: MainAxisAlignment.center,
borderRadius: BorderRadius.all(Radius.circular(10)), children: [
child: Row( SizedBox(width: 8),
mainAxisAlignment: MainAxisAlignment.center, buildIconWeb(
children: [ splashRadius: 15,
SizedBox(width: 8), minSize: 40,
buildIconWeb( iconPadding: EdgeInsets.zero,
splashRadius: 15, icon: SvgPicture.asset(_imagePaths.icSearchBar, width: 16, height: 16, fit: BoxFit.fill),
minSize: 40, onTap: () => _onOpenSearchViewAction?.call()),
iconPadding: EdgeInsets.zero, Expanded(
icon: SvgPicture.asset(_imagePaths.icSearchBar, width: 16, height: 16, fit: BoxFit.fill), child: InkWell(
onTap: () => _onOpenSearchViewAction?.call()), onTap: () => _onOpenSearchViewAction?.call(),
Expanded(child: child: Text(
Text( _hintTextSearch ?? '',
_hintTextSearch ?? '', maxLines: 1,
maxLines: 1, style: TextStyle(fontSize: kIsWeb ? 15 : 17, color: AppColor.colorHintSearchBar)),
style: TextStyle(fontSize: kIsWeb ? 15 : 17, color: AppColor.colorHintSearchBar))) ),
] ),
)), if(_rightButton != null)
_rightButton!
]
),
); );
} }
} }
@@ -27,9 +27,8 @@ class AdvancedFilterController extends GetxController {
final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs; final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs;
final hasAttachment = false.obs; final hasAttachment = false.obs;
final listEmailAddressInit = RxList<EmailAddress>(); final listEmailAddressInit = RxList<EmailAddress>();
final listTagFromSelected = RxList<String>(); final lastTextForm = ''.obs;
final listTagToSelected = RxList<String>(); final lastTextTo = ''.obs;
TextEditingController subjectFilterInputController = TextEditingController(); TextEditingController subjectFilterInputController = TextEditingController();
TextEditingController hasKeyWordFilterInputController = TextEditingController hasKeyWordFilterInputController =
TextEditingController(); TextEditingController();
@@ -40,7 +39,7 @@ class AdvancedFilterController extends GetxController {
ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource _contactSuggestionSource =
ContactSuggestionSource.tMailContact; ContactSuggestionSource.tMailContact;
final SearchController _searchController = Get.find<SearchController>(); final SearchController searchController = Get.find<SearchController>();
final MailboxDashBoardController _mailboxDashBoardController = final MailboxDashBoardController _mailboxDashBoardController =
Get.find<MailboxDashBoardController>(); Get.find<MailboxDashBoardController>();
@@ -52,7 +51,7 @@ class AdvancedFilterController extends GetxController {
} }
SearchEmailFilter get searchEmailFilter => SearchEmailFilter get searchEmailFilter =>
_searchController.searchEmailFilter.value; searchController.searchEmailFilter.value;
@override @override
void onReady() async { void onReady() async {
@@ -64,52 +63,55 @@ class AdvancedFilterController extends GetxController {
} }
void selectOpenAdvanceSearch() { void selectOpenAdvanceSearch() {
_searchController.isAdvancedSearchViewOpen.toggle(); searchController.isAdvancedSearchViewOpen.toggle();
} }
void cleanSearchFilter(BuildContext context) { void cleanSearchFilter(BuildContext context) {
_searchController.cleanSearchFilter(); searchController.cleanSearchFilter();
dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime; dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime;
listTagFromSelected.clear();
listTagToSelected.clear();
subjectFilterInputController.text = ''; subjectFilterInputController.text = '';
hasKeyWordFilterInputController.text = ''; hasKeyWordFilterInputController.text = '';
notKeyWordFilterInputController.text = ''; notKeyWordFilterInputController.text = '';
dateFilterInputController.text = ''; dateFilterInputController.text = '';
hasAttachment.value = false; hasAttachment.value = false;
_searchController.isAdvancedSearchHasApply.value = false; searchController.isAdvancedSearchHasApply.value = false;
_searchController.isAdvancedSearchViewOpen.toggle(); searchController.isAdvancedSearchViewOpen.toggle();
_mailboxDashBoardController.searchEmail( _mailboxDashBoardController.searchEmail(
context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value)); context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value));
} }
void _updateFilterEmailFromAdvancedSearchView() { void _updateFilterEmailFromAdvancedSearchView() {
if (listTagFromSelected.isNotEmpty) {
_searchController.updateFilterEmail(
from: listTagFromSelected.toSet());
} else {
_searchController.updateFilterEmail(from: {});
}
if (listTagToSelected.isNotEmpty) {
_searchController.updateFilterEmail(
to: listTagToSelected.toSet());
} else {
_searchController.updateFilterEmail(to: {});
}
if (hasKeyWordFilterInputController.text.isNotEmpty) { if (hasKeyWordFilterInputController.text.isNotEmpty) {
_searchController.updateFilterEmail( searchController.updateFilterEmail(hasKeyword: hasKeyWordFilterInputController.text.split(',').toSet());
hasKeyword: hasKeyWordFilterInputController.text.split(',').toSet());
} else { } else {
_searchController.updateFilterEmail(hasKeyword: {}); searchController.updateFilterEmail(hasKeyword: {});
}
if (notKeyWordFilterInputController.text.isNotEmpty) {
_searchController.updateFilterEmail(
notKeyword: notKeyWordFilterInputController.text.split(',').toSet());
} else {
_searchController.updateFilterEmail(notKeyword: {});
} }
_searchController.updateFilterEmail( if (notKeyWordFilterInputController.text.isNotEmpty) {
searchController.updateFilterEmail(notKeyword: notKeyWordFilterInputController.text.split(',').toSet());
} else {
searchController.updateFilterEmail(notKeyword: {});
}
if(lastTextForm.isNotEmpty && !searchController.searchEmailFilter.value.from.contains(lastTextForm.value)){
print(lastTextForm);
searchController.updateFilterEmail(
from: searchController.searchEmailFilter.value.from..add(lastTextForm.value),
);
lastTextForm.value = '';
}
if(lastTextTo.isNotEmpty && !searchController.searchEmailFilter.value.to.contains(lastTextTo.value)){
searchController.updateFilterEmail(
to: searchController.searchEmailFilter.value.to..add(lastTextTo.value),
);
lastTextTo.value = '';
}
searchController.updateFilterEmail(
subject: subject:
StringConvert.writeEmptyToNull(subjectFilterInputController.text), StringConvert.writeEmptyToNull(subjectFilterInputController.text),
emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value, emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value,
@@ -123,7 +125,7 @@ class AdvancedFilterController extends GetxController {
arguments: DestinationPickerArguments( arguments: DestinationPickerArguments(
_mailboxDashBoardController.accountId.value!, _mailboxDashBoardController.accountId.value!,
MailboxActions.moveEmail)); MailboxActions.moveEmail));
_searchController.updateFilterEmail(mailbox: destinationMailbox); searchController.updateFilterEmail(mailbox: destinationMailbox);
mailBoxFilterInputController.text = mailBoxFilterInputController.text =
StringConvert.writeNullToEmpty(destinationMailbox.name?.name); StringConvert.writeNullToEmpty(destinationMailbox.name?.name);
} }
@@ -132,9 +134,8 @@ class AdvancedFilterController extends GetxController {
_updateFilterEmailFromAdvancedSearchView(); _updateFilterEmailFromAdvancedSearchView();
_mailboxDashBoardController.searchEmail( _mailboxDashBoardController.searchEmail(
context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value)); context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value));
_searchController.isAdvancedSearchViewOpen.toggle(); searchController.isAdvancedSearchViewOpen.toggle();
_searchController.isAdvancedSearchHasApply.value = searchController.isAdvancedSearchHasApply.value = _checkAdvancedSearchHasApply();
_checkAdvancedSearchHasApply();
} }
void _checkContactPermission() async { void _checkContactPermission() async {
@@ -173,18 +174,18 @@ class AdvancedFilterController extends GetxController {
} }
bool _checkAdvancedSearchHasApply() { bool _checkAdvancedSearchHasApply() {
return listTagFromSelected.isNotEmpty || return searchEmailFilter.from.isNotEmpty ||
listTagToSelected.isNotEmpty || searchEmailFilter.to.isNotEmpty ||
subjectFilterInputController.text.isNotEmpty || subjectFilterInputController.text.isNotEmpty ||
hasKeyWordFilterInputController.text.isNotEmpty || hasKeyWordFilterInputController.text.isNotEmpty ||
notKeyWordFilterInputController.text.isNotEmpty || notKeyWordFilterInputController.text.isNotEmpty ||
dateFilterInputController.text.isNotEmpty || searchEmailFilter.emailReceiveTimeType != EmailReceiveTimeType.allTime ||
mailBoxFilterInputController.text.isNotEmpty || searchEmailFilter.mailbox != _mailboxDashBoardController.selectedMailbox.value ||
hasAttachment.isTrue; hasAttachment.isTrue;
} }
void initSearchFilterField(BuildContext context) { void initSearchFilterField(BuildContext context) {
_searchController.updateFilterEmail( searchController.updateFilterEmail(
mailbox: _mailboxDashBoardController.selectedMailbox.value); mailbox: _mailboxDashBoardController.selectedMailbox.value);
subjectFilterInputController.text = subjectFilterInputController.text =
StringConvert.writeNullToEmpty(searchEmailFilter.subject); StringConvert.writeNullToEmpty(searchEmailFilter.subject);
@@ -0,0 +1,51 @@
import 'package:textfield_tags/textfield_tags.dart';
class CustomController extends TextfieldTagsController {
CustomController() : super();
late Function(String)? actionRemoveTag;
late Function(String)? actionAddTag;
late Function(String)? actionChangeText;
//create your own methods
void setActionRemoveTag(Function(String) action) {
actionRemoveTag = action;
}
void setActionAddTag(Function(String) action) {
actionAddTag = action;
}
void setActionChangeText(Function(String) action) {
actionChangeText = action;
}
@override
set removeTag(String tag) {
actionRemoveTag?.call(tag);
super.removeTag = tag;
}
@override
void onTagDelete(String tag) {
actionRemoveTag?.call(tag);
super.onTagDelete(tag);
}
@override
void onChanged(String value) {
final ts = [' ', ','];
final separator = ts.cast<String?>().firstWhere(
(element) => value.contains(element!) && value.indexOf(element) != 0,
orElse: () => null);
actionChangeText?.call(value);
if (separator != null) {
final splits = value.split(separator);
final indexer = splits.length > 1 ? splits.length - 2 : splits.length - 1;
final val = splits.elementAt(indexer).trim();
if(val.isNotEmpty){
actionAddTag?.call(val);
}
}
super.onChanged(value);
}
}
@@ -167,11 +167,26 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
Obx(() => !searchController.isSearchActive() ? const Spacer() : const SizedBox.shrink()), Obx(() => !searchController.isSearchActive() ? const Spacer() : const SizedBox.shrink()),
Obx(() => searchController.isSearchActive() Obx(() => searchController.isSearchActive()
? Expanded(child: _buildSearchForm(context)) ? Expanded(child: _buildSearchForm(context))
: (SearchBarView(imagePaths) : PortalTarget(
..hintTextSearch(AppLocalizations.of(context).search_emails) visible: controller.searchController.isAdvancedSearchViewOpen.isTrue,
..maxSizeWidth(240) anchor: const Aligned(
..addOnOpenSearchViewAction(() => searchController.enableSearch())) follower: Alignment.topRight,
.build()), target: Alignment.bottomRight,
widthFactor: 3,
backup: Aligned(
follower: Alignment.topRight,
target: Alignment.bottomRight,
widthFactor: 3,
),
),
portalFollower: responsiveUtils.isMobile(context) ? const SizedBox.shrink() : const AdvancedSearchFilterOverlay(),
child: (SearchBarView(imagePaths)
..hintTextSearch(AppLocalizations.of(context).search_emails)
..maxSizeWidth(240)
..addOnOpenSearchViewAction(() => searchController.enableSearch())
..addRightButton(IconOpenAdvancedSearchWidget(context)))
.build(),
)),
Obx(() => !searchController.isSearchActive() ? const SizedBox(width: 16) : const SizedBox.shrink()), Obx(() => !searchController.isSearchActive() ? const SizedBox(width: 16) : const SizedBox.shrink()),
Obx(() => (AvatarBuilder() Obx(() => (AvatarBuilder()
..text(controller.userProfile.value?.getAvatarText() ?? '') ..text(controller.userProfile.value?.getAvatarText() ?? '')
@@ -26,16 +26,16 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
child: Column( child: Column(
children: [ children: [
_buildSuggestionFilterField( _buildSuggestionFilterField(
listTagSelected: controller.listTagFromSelected, listTagSelected: controller.searchEmailFilter.from,
context: context, context: context,
advancedSearchFilterField: AdvancedSearchFilterField.form, advancedSearchFilterField: AdvancedSearchFilterField.form,
listTagInitial: controller.searchEmailFilter.from.toList() listTagInitial: controller.searchEmailFilter.from,
), ),
_buildSuggestionFilterField( _buildSuggestionFilterField(
listTagSelected: controller.listTagToSelected, listTagSelected: controller.searchEmailFilter.to,
context: context, context: context,
advancedSearchFilterField: AdvancedSearchFilterField.to, advancedSearchFilterField: AdvancedSearchFilterField.to,
listTagInitial: controller.searchEmailFilter.to.toList() listTagInitial: controller.searchEmailFilter.to,
), ),
_buildFilterField( _buildFilterField(
textEditingController: controller.subjectFilterInputController, textEditingController: controller.subjectFilterInputController,
@@ -91,11 +91,15 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
fontSize: 15, fontSize: 15,
color: Colors.black, color: Colors.black,
fontWeight: FontWeight.w500))), fontWeight: FontWeight.w500))),
if (e == if (e == controller.dateFilterSelectedFormAdvancedSearch.value)
controller.dateFilterSelectedFormAdvancedSearch.value) ...[ ...[
const SizedBox(width: 12), const SizedBox(width: 12),
SvgPicture.asset(_imagePaths.icFilterSelected, SvgPicture.asset(
width: 16, height: 16, fit: BoxFit.fill), _imagePaths.icFilterSelected,
width: 16,
height: 16,
fit: BoxFit.fill,
),
] ]
]), ]),
onTap: () { onTap: () {
@@ -182,8 +186,8 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Widget _buildSuggestionFilterField({ Widget _buildSuggestionFilterField({
required AdvancedSearchFilterField advancedSearchFilterField, required AdvancedSearchFilterField advancedSearchFilterField,
required BuildContext context, required BuildContext context,
required List<String> listTagSelected, required Set<String> listTagSelected,
required List<String> listTagInitial, required Set<String> listTagInitial,
}) { }) {
final child = [ final child = [
SizedBox( SizedBox(
@@ -204,7 +208,32 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
}, },
advancedSearchFilterField: advancedSearchFilterField, advancedSearchFilterField: advancedSearchFilterField,
initialTags: listTagInitial, initialTags: listTagInitial,
listTagSelected: listTagSelected, onAddTag: (value) {
if (advancedSearchFilterField == AdvancedSearchFilterField.form) {
controller.searchEmailFilter.from.add(value);
}
if (advancedSearchFilterField == AdvancedSearchFilterField.to) {
controller.searchEmailFilter.to.add(value);
}
},
onDeleteTag: (tag) {
if (advancedSearchFilterField == AdvancedSearchFilterField.form) {
controller.searchEmailFilter.from.remove(tag);
controller.lastTextForm.value = '';
}
if (advancedSearchFilterField == AdvancedSearchFilterField.to) {
controller.searchEmailFilter.to.remove(tag);
controller.lastTextTo.value = '';
}
},
onChange: (value) {
if (advancedSearchFilterField == AdvancedSearchFilterField.form) {
controller.lastTextForm.value = value;
}
if (advancedSearchFilterField == AdvancedSearchFilterField.to) {
controller.lastTextTo.value = value;
}
},
) )
: Expanded( : Expanded(
child: TextFieldAutoCompleteEmailAddress( child: TextFieldAutoCompleteEmailAddress(
@@ -213,7 +242,33 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
}, },
advancedSearchFilterField: advancedSearchFilterField, advancedSearchFilterField: advancedSearchFilterField,
initialTags: listTagInitial, initialTags: listTagInitial,
listTagSelected: listTagSelected, onAddTag: (value) {
if (advancedSearchFilterField == AdvancedSearchFilterField.form) {
controller.searchEmailFilter.from.add(value.trim());
}
if (advancedSearchFilterField == AdvancedSearchFilterField.to) {
controller.searchEmailFilter.to.add(value.trim());
}
},
onChange: (value) {
if (advancedSearchFilterField == AdvancedSearchFilterField.form) {
controller.lastTextForm.value = value.trim();
}
if (advancedSearchFilterField == AdvancedSearchFilterField.to) {
controller.lastTextTo.value = value.trim();
}
},
onDeleteTag: (tag) {
if (advancedSearchFilterField == AdvancedSearchFilterField.form) {
controller.searchEmailFilter.from.remove(tag);
controller.lastTextForm.value = '';
}
if (advancedSearchFilterField == AdvancedSearchFilterField.to) {
controller.searchEmailFilter.to.remove(tag);
controller.lastTextTo.value = '';
}
},
), ),
) )
]; ];
@@ -267,8 +322,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
fontSize: 14, fontSize: 14,
color: AppColor.colorHintSearchBar, color: AppColor.colorHintSearchBar,
), ),
suffixIconConstraints: suffixIconConstraints: const BoxConstraints(minHeight: 24, minWidth: 24),
const BoxConstraints(minHeight: 24, minWidth: 24),
suffixIcon: isSelectFormList suffixIcon: isSelectFormList
? buildIconWeb( ? buildIconWeb(
icon: SvgPicture.asset( icon: SvgPicture.asset(
@@ -7,15 +7,19 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class AdvancedSearchFilterFormBottomView class AdvancedSearchFilterFormBottomView
extends GetWidget<AdvancedFilterController> { extends GetWidget<AdvancedFilterController> {
const AdvancedSearchFilterFormBottomView({Key? key}) : super(key: key); const AdvancedSearchFilterFormBottomView({
Key? key,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ResponsiveUtils _responsiveUtils = Get.find<ResponsiveUtils>(); final ResponsiveUtils _responsiveUtils = Get.find<ResponsiveUtils>();
return Padding( return Padding(
padding: EdgeInsets.only(top: _responsiveUtils.isMobile(context) ? 8 : 20), padding:
EdgeInsets.only(top: _responsiveUtils.isMobile(context) ? 8 : 20),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (_responsiveUtils.isMobile(context)) if (_responsiveUtils.isMobile(context))
_buildCheckboxHasAttachment(context), _buildCheckboxHasAttachment(context),
@@ -26,31 +30,11 @@ class AdvancedSearchFilterFormBottomView
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
if (!_responsiveUtils.isMobile(context)) if (!_responsiveUtils.isMobile(context))...[
Expanded(child: _buildCheckboxHasAttachment(context)), _buildCheckboxHasAttachment(context),
_buildButton( const Spacer(),
onAction: () { ],
controller.cleanSearchFilter(context); ..._buildListButton(context, _responsiveUtils),
popBack();
},
colorButton: Colors.transparent,
colorText: AppColor.colorMessageConfirmDialog,
text: AppLocalizations.of(context).clearFilter,
context: context,
responsiveUtils: _responsiveUtils,
),
const SizedBox(width: 12),
_buildButton(
onAction: () {
controller.applyAdvancedSearchFilter(context);
popBack();
},
colorButton: AppColor.primaryColor,
colorText: AppColor.primaryLightColor,
text: AppLocalizations.of(context).search,
context: context,
responsiveUtils: _responsiveUtils,
),
], ],
), ),
], ],
@@ -58,16 +42,80 @@ class AdvancedSearchFilterFormBottomView
); );
} }
List<Widget> _buildListButton(
BuildContext context, ResponsiveUtils responsiveUtils) {
if (responsiveUtils.isMobile(context)) {
return [
Expanded(
child: _buildButton(
onAction: () {
controller.cleanSearchFilter(context);
popBack();
},
colorButton: AppColor.primaryColor.withOpacity(0.06),
colorText: AppColor.primaryColor,
text: AppLocalizations.of(context).clearFilter,
context: context,
responsiveUtils: responsiveUtils,
),
),
const SizedBox(width: 12),
Expanded(
child: _buildButton(
onAction: () {
controller.applyAdvancedSearchFilter(context);
popBack();
},
colorButton: AppColor.primaryColor,
colorText: AppColor.primaryLightColor,
text: AppLocalizations.of(context).search,
context: context,
responsiveUtils: responsiveUtils,
),
),
];
} else {
return [
_buildButton(
onAction: () {
controller.cleanSearchFilter(context);
popBack();
},
colorButton: AppColor.primaryColor.withOpacity(0.06),
colorText: AppColor.primaryColor,
text: AppLocalizations.of(context).clearFilter,
context: context,
responsiveUtils: responsiveUtils,
),
const SizedBox(width: 12),
_buildButton(
onAction: () {
controller.applyAdvancedSearchFilter(context);
popBack();
},
colorButton: AppColor.primaryColor,
colorText: AppColor.primaryLightColor,
text: AppLocalizations.of(context).search,
context: context,
responsiveUtils: responsiveUtils,
),
];
}
}
Widget _buildCheckboxHasAttachment(BuildContext context) { Widget _buildCheckboxHasAttachment(BuildContext context) {
return Obx( return Obx(
() => CheckboxListTile( () => SizedBox(
contentPadding: EdgeInsets.zero, width: 220,
controlAffinity: ListTileControlAffinity.leading, child: CheckboxListTile(
value: controller.hasAttachment.value, contentPadding: EdgeInsets.zero,
onChanged: (value) { controlAffinity: ListTileControlAffinity.leading,
controller.hasAttachment.value = value ?? false; value: controller.hasAttachment.value,
}, onChanged: (value) {
title: Text(AppLocalizations.of(context).hasAttachment), controller.hasAttachment.value = value ?? false;
},
title: Text(AppLocalizations.of(context).hasAttachment),
),
), ),
); );
} }
@@ -87,8 +135,11 @@ class AdvancedSearchFilterFormBottomView
}, },
child: Container( child: Container(
height: 44, height: 44,
padding: const EdgeInsets.symmetric(horizontal: 26), padding: EdgeInsets.symmetric(
constraints: BoxConstraints(maxWidth: responsiveUtils.isMobile(context) ? double.infinity : 144), horizontal: responsiveUtils.isMobile(context) ? 0 : 26),
constraints: BoxConstraints(
maxWidth:
responsiveUtils.isMobile(context) ? double.infinity : 144),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), color: colorButton), borderRadius: BorderRadius.circular(10), color: colorButton),
@@ -10,18 +10,23 @@ class AdvancedSearchFilterOverlay extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Container( child: Container(
constraints: const BoxConstraints(
minWidth: 660,
maxHeight: 568,
),
width: 660, width: 660,
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
padding: const EdgeInsets.all(32), padding: const EdgeInsets.all(32),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: const [ boxShadow: const [
BoxShadow( BoxShadow(
color: AppColor.colorShadowBgContentEmail, color: AppColor.colorShadowBgContentEmail,
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5)), spreadRadius: 1,
] blurRadius: 1,
), offset: Offset(0, 0.5)),
]),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 12),
@@ -8,20 +8,25 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/extensions/email_address_extension.dart'; import 'package:model/extensions/email_address_extension.dart';
import 'package:textfield_tags/textfield_tags.dart'; import 'package:textfield_tags/textfield_tags.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/custom_tf_tag_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class TextFieldAutoCompleteEmailAddress extends StatefulWidget { class TextFieldAutoCompleteEmailAddress extends StatefulWidget {
const TextFieldAutoCompleteEmailAddress({ const TextFieldAutoCompleteEmailAddress({
Key? key, Key? key,
required this.advancedSearchFilterField, required this.advancedSearchFilterField,
required this.listTagSelected,
required this.initialTags, required this.initialTags,
required this.optionsBuilder, required this.optionsBuilder,
required this.onChange,
required this.onDeleteTag,
required this.onAddTag,
}) : super(key: key); }) : super(key: key);
final AdvancedSearchFilterField advancedSearchFilterField; final AdvancedSearchFilterField advancedSearchFilterField;
final List<String> listTagSelected; final Set<String> initialTags;
final List<String> initialTags;
final Future<List<EmailAddress>> Function(String) optionsBuilder; final Future<List<EmailAddress>> Function(String) optionsBuilder;
final Function(String) onChange;
final Function(String) onDeleteTag;
final Function(String) onAddTag;
@override @override
State<TextFieldAutoCompleteEmailAddress> createState() => State<TextFieldAutoCompleteEmailAddress> createState() =>
@@ -32,20 +37,23 @@ class _TextFieldAutoCompleteEmailAddressState
extends State<TextFieldAutoCompleteEmailAddress> { extends State<TextFieldAutoCompleteEmailAddress> {
final double _distanceToField = 380; final double _distanceToField = 380;
final ImagePaths _imagePaths = Get.find<ImagePaths>(); final ImagePaths _imagePaths = Get.find<ImagePaths>();
late TextfieldTagsController _controller; late CustomController _controller;
@override @override
void initState() { void initState() {
_controller = TextfieldTagsController(); _controller = CustomController();
_controller.addListener(() { _controller.setActionRemoveTag((tag) {
if(_controller.hasTags){ widget.onDeleteTag.call(tag);
widget.listTagSelected.addAll(_controller.getTags!); });
} _controller.setActionAddTag((tag) {
widget.onAddTag.call(tag);
});
_controller.setActionChangeText((tag) {
widget.onChange.call(tag);
}); });
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Autocomplete<EmailAddress>( return Autocomplete<EmailAddress>(
@@ -85,7 +93,7 @@ class _TextFieldAutoCompleteEmailAddressState
}, },
fieldViewBuilder: (context, ttec, tfn, onFieldSubmitted) { fieldViewBuilder: (context, ttec, tfn, onFieldSubmitted) {
return TextFieldTags( return TextFieldTags(
initialTags: widget.initialTags, initialTags: widget.initialTags.toList(),
textEditingController: ttec, textEditingController: ttec,
focusNode: tfn, focusNode: tfn,
textfieldTagsController: _controller, textfieldTagsController: _controller,
@@ -123,28 +131,27 @@ class _TextFieldAutoCompleteEmailAddressState
Radius.circular(10), Radius.circular(10),
), ),
), ),
hintText: hintText: widget.advancedSearchFilterField.getHintText(context),
widget.advancedSearchFilterField.getHintText(context),
hintStyle: const TextStyle( hintStyle: const TextStyle(
fontSize: 14, fontSize: 14,
color: AppColor.colorHintSearchBar, color: AppColor.colorHintSearchBar,
), ),
prefixIconConstraints: prefixIconConstraints: BoxConstraints(maxWidth: _distanceToField * 0.74),
BoxConstraints(maxWidth: _distanceToField * 0.74), prefixIcon: tags.isNotEmpty ? SingleChildScrollView(
prefixIcon: tags.isNotEmpty padding: const EdgeInsets.symmetric(horizontal: 10),
? SingleChildScrollView( controller: sc,
padding: const EdgeInsets.symmetric(horizontal: 10), scrollDirection: Axis.horizontal,
controller: sc, child: Row(
scrollDirection: Axis.horizontal, children: tags.map((String tag) {
child: Row( return _buildTagItem(context, tag, onTagDelete);
children: tags.map((String tag) { }).toList()),
return _buildTagItem(context, tag, onTagDelete); )
}).toList()),
)
: null, : null,
), ),
onChanged: onChanged, onChanged: (value) {
onSubmitted: (tag){ onChanged?.call(value);
},
onSubmitted: (tag) {
onSubmitted?.call(tag); onSubmitted?.call(tag);
}, },
); );
@@ -250,9 +257,8 @@ class _TextFieldAutoCompleteEmailAddressState
fontWeight: FontWeight.normal)), fontWeight: FontWeight.normal)),
const SizedBox(width: 4), const SizedBox(width: 4),
GestureDetector( GestureDetector(
onTap: (){ onTap: () {
onTagDelete.call(tag); onTagDelete.call(tag);
widget.listTagSelected.remove(tag);
}, },
child: SvgPicture.asset( child: SvgPicture.asset(
_imagePaths.icClose, _imagePaths.icClose,
@@ -281,6 +287,5 @@ class _TextFieldAutoCompleteEmailAddressState
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
_controller.dispose();
} }
} }
@@ -165,10 +165,25 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
} }
Widget _buildSearchFormInActive(BuildContext context) { Widget _buildSearchFormInActive(BuildContext context) {
return (SearchBarView(_imagePaths) return PortalTarget(
..hintTextSearch(AppLocalizations.of(context).search_emails) visible: controller.searchController.isAdvancedSearchViewOpen.isTrue,
..addOnOpenSearchViewAction(() => controller.enableSearch(context))) anchor: const Aligned(
.build(); follower: Alignment.topLeft,
target: Alignment.bottomLeft,
widthFactor: 1,
backup: Aligned(
follower: Alignment.topLeft,
target: Alignment.bottomLeft,
widthFactor: 1,
),
),
portalFollower: _responsiveUtils.isMobile(context) ? const SizedBox.shrink() : const AdvancedSearchFilterOverlay(),
child: (SearchBarView(_imagePaths)
..hintTextSearch(AppLocalizations.of(context).search_emails)
..addOnOpenSearchViewAction(() => controller.enableSearch(context))
..addRightButton(IconOpenAdvancedSearchWidget(context)))
.build(),
);
} }
Widget _buildSearchFormActive(BuildContext context) { Widget _buildSearchFormActive(BuildContext context) {