enable remove suggestion tag in from field
This commit is contained in:
@@ -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!
|
||||||
|
]
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+43
-42
@@ -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() ?? '')
|
||||||
|
|||||||
+72
-18
@@ -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(
|
||||||
|
|||||||
+88
-37
@@ -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),
|
||||||
|
|||||||
+13
-8
@@ -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),
|
||||||
|
|||||||
+36
-31
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user