enable remove suggestion tag in from field

This commit is contained in:
ManhNTX
2022-07-01 06:49:27 +07:00
committed by Dat H. Pham
parent 0f46a1c899
commit 263ee35a0a
9 changed files with 374 additions and 169 deletions
@@ -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(
@@ -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),
@@ -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),
@@ -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();
}
}