enable remove suggestion tag in from field
This commit is contained in:
@@ -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!
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+43
-42
@@ -27,9 +27,8 @@ class AdvancedFilterController extends GetxController {
|
||||
final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs;
|
||||
final hasAttachment = false.obs;
|
||||
final listEmailAddressInit = RxList<EmailAddress>();
|
||||
final listTagFromSelected = RxList<String>();
|
||||
final listTagToSelected = RxList<String>();
|
||||
|
||||
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<SearchController>();
|
||||
final SearchController searchController = Get.find<SearchController>();
|
||||
final MailboxDashBoardController _mailboxDashBoardController =
|
||||
Get.find<MailboxDashBoardController>();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
? 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() ?? '')
|
||||
|
||||
+72
-18
@@ -26,16 +26,16 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
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<AdvancedFilterController>
|
||||
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<AdvancedFilterController>
|
||||
Widget _buildSuggestionFilterField({
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required BuildContext context,
|
||||
required List<String> listTagSelected,
|
||||
required List<String> listTagInitial,
|
||||
required Set<String> listTagSelected,
|
||||
required Set<String> listTagInitial,
|
||||
}) {
|
||||
final child = [
|
||||
SizedBox(
|
||||
@@ -204,7 +208,32 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
},
|
||||
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<AdvancedFilterController>
|
||||
},
|
||||
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<AdvancedFilterController>
|
||||
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(
|
||||
|
||||
+88
-37
@@ -7,15 +7,19 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
class AdvancedSearchFilterFormBottomView
|
||||
extends GetWidget<AdvancedFilterController> {
|
||||
const AdvancedSearchFilterFormBottomView({Key? key}) : super(key: key);
|
||||
const AdvancedSearchFilterFormBottomView({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ResponsiveUtils _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
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<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) {
|
||||
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),
|
||||
|
||||
+13
-8
@@ -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),
|
||||
|
||||
+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: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<String> listTagSelected;
|
||||
final List<String> initialTags;
|
||||
final Set<String> initialTags;
|
||||
final Future<List<EmailAddress>> Function(String) optionsBuilder;
|
||||
final Function(String) onChange;
|
||||
final Function(String) onDeleteTag;
|
||||
final Function(String) onAddTag;
|
||||
|
||||
@override
|
||||
State<TextFieldAutoCompleteEmailAddress> createState() =>
|
||||
@@ -32,20 +37,23 @@ class _TextFieldAutoCompleteEmailAddressState
|
||||
extends State<TextFieldAutoCompleteEmailAddress> {
|
||||
final double _distanceToField = 380;
|
||||
final ImagePaths _imagePaths = Get.find<ImagePaths>();
|
||||
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<EmailAddress>(
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,10 +165,25 @@ class ThreadView extends GetWidget<ThreadController> 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) {
|
||||
|
||||
Reference in New Issue
Block a user