diff --git a/core/lib/presentation/views/search/search_bar_view.dart b/core/lib/presentation/views/search/search_bar_view.dart index 9b2ff5867..004205e15 100644 --- a/core/lib/presentation/views/search/search_bar_view.dart +++ b/core/lib/presentation/views/search/search_bar_view.dart @@ -2,23 +2,24 @@ import 'package:core/core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; typedef OnOpenSearchViewAction = Function(); class SearchBarView { - OnOpenSearchViewAction? _onOpenSearchViewAction; + OnOpenSearchViewAction? _onOpenSearchViewAction; - final ImagePaths _imagePaths; + final ImagePaths _imagePaths; double? _heightSearchBar; EdgeInsets? _padding; EdgeInsets? _margin; String? _hintTextSearch; double? _maxSizeWidth; + Widget? _rightButton; - SearchBarView(this._imagePaths); + + SearchBarView(this._imagePaths); void addOnOpenSearchViewAction(OnOpenSearchViewAction onOpenSearchViewAction) { _onOpenSearchViewAction = onOpenSearchViewAction; @@ -32,6 +33,10 @@ class SearchBarView { _padding = padding; } + void addRightButton(Widget rightButton) { + _rightButton = rightButton; + } + void addMargin(EdgeInsets margin) { _margin = margin; } @@ -55,26 +60,29 @@ class SearchBarView { color: AppColor.colorBgSearchBar), padding: _padding ?? EdgeInsets.zero, margin: _margin ?? EdgeInsets.zero, - child: InkWell( - onTap: () => _onOpenSearchViewAction?.call(), - borderRadius: BorderRadius.all(Radius.circular(10)), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(width: 8), - buildIconWeb( - splashRadius: 15, - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset(_imagePaths.icSearchBar, width: 16, height: 16, fit: BoxFit.fill), - onTap: () => _onOpenSearchViewAction?.call()), - Expanded(child: - Text( - _hintTextSearch ?? '', - maxLines: 1, - style: TextStyle(fontSize: kIsWeb ? 15 : 17, color: AppColor.colorHintSearchBar))) - ] - )), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(width: 8), + buildIconWeb( + splashRadius: 15, + minSize: 40, + iconPadding: EdgeInsets.zero, + icon: SvgPicture.asset(_imagePaths.icSearchBar, width: 16, height: 16, fit: BoxFit.fill), + onTap: () => _onOpenSearchViewAction?.call()), + Expanded( + child: InkWell( + onTap: () => _onOpenSearchViewAction?.call(), + child: Text( + _hintTextSearch ?? '', + maxLines: 1, + style: TextStyle(fontSize: kIsWeb ? 15 : 17, color: AppColor.colorHintSearchBar)), + ), + ), + if(_rightButton != null) + _rightButton! + ] + ), ); } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart index ef3cee9eb..b9f6ea094 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart @@ -27,9 +27,8 @@ class AdvancedFilterController extends GetxController { final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs; final hasAttachment = false.obs; final listEmailAddressInit = RxList(); - final listTagFromSelected = RxList(); - final listTagToSelected = RxList(); - + final lastTextForm = ''.obs; + final lastTextTo = ''.obs; TextEditingController subjectFilterInputController = TextEditingController(); TextEditingController hasKeyWordFilterInputController = TextEditingController(); @@ -40,7 +39,7 @@ class AdvancedFilterController extends GetxController { ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact; - final SearchController _searchController = Get.find(); + final SearchController searchController = Get.find(); final MailboxDashBoardController _mailboxDashBoardController = Get.find(); @@ -52,7 +51,7 @@ class AdvancedFilterController extends GetxController { } SearchEmailFilter get searchEmailFilter => - _searchController.searchEmailFilter.value; + searchController.searchEmailFilter.value; @override void onReady() async { @@ -64,52 +63,55 @@ class AdvancedFilterController extends GetxController { } void selectOpenAdvanceSearch() { - _searchController.isAdvancedSearchViewOpen.toggle(); + searchController.isAdvancedSearchViewOpen.toggle(); } void cleanSearchFilter(BuildContext context) { - _searchController.cleanSearchFilter(); + searchController.cleanSearchFilter(); dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime; - listTagFromSelected.clear(); - listTagToSelected.clear(); subjectFilterInputController.text = ''; hasKeyWordFilterInputController.text = ''; notKeyWordFilterInputController.text = ''; dateFilterInputController.text = ''; hasAttachment.value = false; - _searchController.isAdvancedSearchHasApply.value = false; - _searchController.isAdvancedSearchViewOpen.toggle(); + searchController.isAdvancedSearchHasApply.value = false; + searchController.isAdvancedSearchViewOpen.toggle(); _mailboxDashBoardController.searchEmail( context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value)); } 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) { - _searchController.updateFilterEmail( - hasKeyword: hasKeyWordFilterInputController.text.split(',').toSet()); + searchController.updateFilterEmail(hasKeyword: hasKeyWordFilterInputController.text.split(',').toSet()); } else { - _searchController.updateFilterEmail(hasKeyword: {}); - } - if (notKeyWordFilterInputController.text.isNotEmpty) { - _searchController.updateFilterEmail( - notKeyword: notKeyWordFilterInputController.text.split(',').toSet()); - } else { - _searchController.updateFilterEmail(notKeyword: {}); + searchController.updateFilterEmail(hasKeyword: {}); } - _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: StringConvert.writeEmptyToNull(subjectFilterInputController.text), emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value, @@ -123,7 +125,7 @@ class AdvancedFilterController extends GetxController { arguments: DestinationPickerArguments( _mailboxDashBoardController.accountId.value!, MailboxActions.moveEmail)); - _searchController.updateFilterEmail(mailbox: destinationMailbox); + searchController.updateFilterEmail(mailbox: destinationMailbox); mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(destinationMailbox.name?.name); } @@ -132,9 +134,8 @@ class AdvancedFilterController extends GetxController { _updateFilterEmailFromAdvancedSearchView(); _mailboxDashBoardController.searchEmail( context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value)); - _searchController.isAdvancedSearchViewOpen.toggle(); - _searchController.isAdvancedSearchHasApply.value = - _checkAdvancedSearchHasApply(); + searchController.isAdvancedSearchViewOpen.toggle(); + searchController.isAdvancedSearchHasApply.value = _checkAdvancedSearchHasApply(); } void _checkContactPermission() async { @@ -173,18 +174,18 @@ class AdvancedFilterController extends GetxController { } bool _checkAdvancedSearchHasApply() { - return listTagFromSelected.isNotEmpty || - listTagToSelected.isNotEmpty || + return searchEmailFilter.from.isNotEmpty || + searchEmailFilter.to.isNotEmpty || subjectFilterInputController.text.isNotEmpty || hasKeyWordFilterInputController.text.isNotEmpty || notKeyWordFilterInputController.text.isNotEmpty || - dateFilterInputController.text.isNotEmpty || - mailBoxFilterInputController.text.isNotEmpty || + searchEmailFilter.emailReceiveTimeType != EmailReceiveTimeType.allTime || + searchEmailFilter.mailbox != _mailboxDashBoardController.selectedMailbox.value || hasAttachment.isTrue; } void initSearchFilterField(BuildContext context) { - _searchController.updateFilterEmail( + searchController.updateFilterEmail( mailbox: _mailboxDashBoardController.selectedMailbox.value); subjectFilterInputController.text = StringConvert.writeNullToEmpty(searchEmailFilter.subject); diff --git a/lib/features/mailbox_dashboard/presentation/controller/custom_tf_tag_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/custom_tf_tag_controller.dart new file mode 100644 index 000000000..2fdaf583b --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/controller/custom_tf_tag_controller.dart @@ -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().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); + } +} diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index 709765b0f..524873416 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -167,11 +167,26 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { Obx(() => !searchController.isSearchActive() ? const Spacer() : const SizedBox.shrink()), Obx(() => searchController.isSearchActive() ? Expanded(child: _buildSearchForm(context)) - : (SearchBarView(imagePaths) - ..hintTextSearch(AppLocalizations.of(context).search_emails) - ..maxSizeWidth(240) - ..addOnOpenSearchViewAction(() => searchController.enableSearch())) - .build()), + : PortalTarget( + visible: controller.searchController.isAdvancedSearchViewOpen.isTrue, + anchor: const Aligned( + follower: Alignment.topRight, + 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(() => (AvatarBuilder() ..text(controller.userProfile.value?.getAvatarText() ?? '') diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart index 06bade9e6..69c1019dc 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart @@ -26,16 +26,16 @@ class AdvancedSearchInputForm extends GetWidget child: Column( children: [ _buildSuggestionFilterField( - listTagSelected: controller.listTagFromSelected, - context: context, - advancedSearchFilterField: AdvancedSearchFilterField.form, - listTagInitial: controller.searchEmailFilter.from.toList() + listTagSelected: controller.searchEmailFilter.from, + context: context, + advancedSearchFilterField: AdvancedSearchFilterField.form, + listTagInitial: controller.searchEmailFilter.from, ), _buildSuggestionFilterField( - listTagSelected: controller.listTagToSelected, - context: context, - advancedSearchFilterField: AdvancedSearchFilterField.to, - listTagInitial: controller.searchEmailFilter.to.toList() + listTagSelected: controller.searchEmailFilter.to, + context: context, + advancedSearchFilterField: AdvancedSearchFilterField.to, + listTagInitial: controller.searchEmailFilter.to, ), _buildFilterField( textEditingController: controller.subjectFilterInputController, @@ -91,11 +91,15 @@ class AdvancedSearchInputForm extends GetWidget fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500))), - if (e == - controller.dateFilterSelectedFormAdvancedSearch.value) ...[ + if (e == controller.dateFilterSelectedFormAdvancedSearch.value) + ...[ const SizedBox(width: 12), - SvgPicture.asset(_imagePaths.icFilterSelected, - width: 16, height: 16, fit: BoxFit.fill), + SvgPicture.asset( + _imagePaths.icFilterSelected, + width: 16, + height: 16, + fit: BoxFit.fill, + ), ] ]), onTap: () { @@ -182,8 +186,8 @@ class AdvancedSearchInputForm extends GetWidget Widget _buildSuggestionFilterField({ required AdvancedSearchFilterField advancedSearchFilterField, required BuildContext context, - required List listTagSelected, - required List listTagInitial, + required Set listTagSelected, + required Set listTagInitial, }) { final child = [ SizedBox( @@ -204,7 +208,32 @@ class AdvancedSearchInputForm extends GetWidget }, advancedSearchFilterField: advancedSearchFilterField, 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( child: TextFieldAutoCompleteEmailAddress( @@ -213,7 +242,33 @@ class AdvancedSearchInputForm extends GetWidget }, advancedSearchFilterField: advancedSearchFilterField, 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 fontSize: 14, color: AppColor.colorHintSearchBar, ), - suffixIconConstraints: - const BoxConstraints(minHeight: 24, minWidth: 24), + suffixIconConstraints: const BoxConstraints(minHeight: 24, minWidth: 24), suffixIcon: isSelectFormList ? buildIconWeb( icon: SvgPicture.asset( diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart index 7e0d19c04..ff9a02cb5 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart @@ -7,15 +7,19 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class AdvancedSearchFilterFormBottomView extends GetWidget { - const AdvancedSearchFilterFormBottomView({Key? key}) : super(key: key); + const AdvancedSearchFilterFormBottomView({ + Key? key, + }) : super(key: key); @override Widget build(BuildContext context) { final ResponsiveUtils _responsiveUtils = Get.find(); return Padding( - padding: EdgeInsets.only(top: _responsiveUtils.isMobile(context) ? 8 : 20), + padding: + EdgeInsets.only(top: _responsiveUtils.isMobile(context) ? 8 : 20), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ if (_responsiveUtils.isMobile(context)) _buildCheckboxHasAttachment(context), @@ -26,31 +30,11 @@ class AdvancedSearchFilterFormBottomView crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.max, children: [ - if (!_responsiveUtils.isMobile(context)) - Expanded(child: _buildCheckboxHasAttachment(context)), - _buildButton( - onAction: () { - controller.cleanSearchFilter(context); - 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, - ), + if (!_responsiveUtils.isMobile(context))...[ + _buildCheckboxHasAttachment(context), + const Spacer(), + ], + ..._buildListButton(context, _responsiveUtils), ], ), ], @@ -58,16 +42,80 @@ class AdvancedSearchFilterFormBottomView ); } + List _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) { return Obx( - () => CheckboxListTile( - contentPadding: EdgeInsets.zero, - controlAffinity: ListTileControlAffinity.leading, - value: controller.hasAttachment.value, - onChanged: (value) { - controller.hasAttachment.value = value ?? false; - }, - title: Text(AppLocalizations.of(context).hasAttachment), + () => SizedBox( + width: 220, + child: CheckboxListTile( + contentPadding: EdgeInsets.zero, + controlAffinity: ListTileControlAffinity.leading, + value: controller.hasAttachment.value, + onChanged: (value) { + controller.hasAttachment.value = value ?? false; + }, + title: Text(AppLocalizations.of(context).hasAttachment), + ), ), ); } @@ -87,8 +135,11 @@ class AdvancedSearchFilterFormBottomView }, child: Container( height: 44, - padding: const EdgeInsets.symmetric(horizontal: 26), - constraints: BoxConstraints(maxWidth: responsiveUtils.isMobile(context) ? double.infinity : 144), + padding: EdgeInsets.symmetric( + horizontal: responsiveUtils.isMobile(context) ? 0 : 26), + constraints: BoxConstraints( + maxWidth: + responsiveUtils.isMobile(context) ? double.infinity : 144), alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: colorButton), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_overlay.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_overlay.dart index ae73993f3..29c551c7b 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_overlay.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_overlay.dart @@ -10,18 +10,23 @@ class AdvancedSearchFilterOverlay extends StatelessWidget { return Padding( padding: const EdgeInsets.only(top: 8), child: Container( + constraints: const BoxConstraints( + minWidth: 660, + maxHeight: 568, + ), width: 660, height: MediaQuery.of(context).size.height, padding: const EdgeInsets.all(32), decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: const [ - BoxShadow( - color: AppColor.colorShadowBgContentEmail, - spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5)), - ] - ), + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: const [ + BoxShadow( + color: AppColor.colorShadowBgContentEmail, + spreadRadius: 1, + blurRadius: 1, + offset: Offset(0, 0.5)), + ]), child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 12), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart index 1f6b5c7a2..1355cc1eb 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart @@ -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: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/controller/custom_tf_tag_controller.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class TextFieldAutoCompleteEmailAddress extends StatefulWidget { - const TextFieldAutoCompleteEmailAddress({ + const TextFieldAutoCompleteEmailAddress({ Key? key, required this.advancedSearchFilterField, - required this.listTagSelected, required this.initialTags, required this.optionsBuilder, + required this.onChange, + required this.onDeleteTag, + required this.onAddTag, }) : super(key: key); final AdvancedSearchFilterField advancedSearchFilterField; - final List listTagSelected; - final List initialTags; + final Set initialTags; final Future> Function(String) optionsBuilder; + final Function(String) onChange; + final Function(String) onDeleteTag; + final Function(String) onAddTag; @override State createState() => @@ -32,20 +37,23 @@ class _TextFieldAutoCompleteEmailAddressState extends State { final double _distanceToField = 380; final ImagePaths _imagePaths = Get.find(); - late TextfieldTagsController _controller; + late CustomController _controller; @override void initState() { - _controller = TextfieldTagsController(); - _controller.addListener(() { - if(_controller.hasTags){ - widget.listTagSelected.addAll(_controller.getTags!); - } + _controller = CustomController(); + _controller.setActionRemoveTag((tag) { + widget.onDeleteTag.call(tag); + }); + _controller.setActionAddTag((tag) { + widget.onAddTag.call(tag); + }); + _controller.setActionChangeText((tag) { + widget.onChange.call(tag); }); super.initState(); } - @override Widget build(BuildContext context) { return Autocomplete( @@ -85,7 +93,7 @@ class _TextFieldAutoCompleteEmailAddressState }, fieldViewBuilder: (context, ttec, tfn, onFieldSubmitted) { return TextFieldTags( - initialTags: widget.initialTags, + initialTags: widget.initialTags.toList(), textEditingController: ttec, focusNode: tfn, textfieldTagsController: _controller, @@ -123,28 +131,27 @@ class _TextFieldAutoCompleteEmailAddressState Radius.circular(10), ), ), - hintText: - widget.advancedSearchFilterField.getHintText(context), + hintText: widget.advancedSearchFilterField.getHintText(context), hintStyle: const TextStyle( fontSize: 14, color: AppColor.colorHintSearchBar, ), - prefixIconConstraints: - BoxConstraints(maxWidth: _distanceToField * 0.74), - prefixIcon: tags.isNotEmpty - ? SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 10), - controller: sc, - scrollDirection: Axis.horizontal, - child: Row( - children: tags.map((String tag) { - return _buildTagItem(context, tag, onTagDelete); - }).toList()), - ) + prefixIconConstraints: BoxConstraints(maxWidth: _distanceToField * 0.74), + prefixIcon: tags.isNotEmpty ? SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 10), + controller: sc, + scrollDirection: Axis.horizontal, + child: Row( + children: tags.map((String tag) { + return _buildTagItem(context, tag, onTagDelete); + }).toList()), + ) : null, ), - onChanged: onChanged, - onSubmitted: (tag){ + onChanged: (value) { + onChanged?.call(value); + }, + onSubmitted: (tag) { onSubmitted?.call(tag); }, ); @@ -250,9 +257,8 @@ class _TextFieldAutoCompleteEmailAddressState fontWeight: FontWeight.normal)), const SizedBox(width: 4), GestureDetector( - onTap: (){ + onTap: () { onTagDelete.call(tag); - widget.listTagSelected.remove(tag); }, child: SvgPicture.asset( _imagePaths.icClose, @@ -281,6 +287,5 @@ class _TextFieldAutoCompleteEmailAddressState @override void dispose() { super.dispose(); - _controller.dispose(); } } diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 3d8155c8c..b51660c86 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -165,10 +165,25 @@ class ThreadView extends GetWidget with AppLoaderMixin, } Widget _buildSearchFormInActive(BuildContext context) { - return (SearchBarView(_imagePaths) - ..hintTextSearch(AppLocalizations.of(context).search_emails) - ..addOnOpenSearchViewAction(() => controller.enableSearch(context))) - .build(); + return PortalTarget( + visible: controller.searchController.isAdvancedSearchViewOpen.isTrue, + anchor: const Aligned( + 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) {