TF-1477 Improve UX for advanced and quick search
This commit is contained in:
+29
-47
@@ -4,11 +4,12 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.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/email_receive_time_type.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/date_drop_down_button.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
@@ -73,7 +74,6 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
onTap: () => controller.selectedMailBox(context)),
|
||||
Row(children: [
|
||||
Expanded(child: _buildFilterField(
|
||||
textEditingController: controller.dateFilterInputController,
|
||||
context: context,
|
||||
advancedSearchFilterField: AdvancedSearchFilterField.date,
|
||||
isSelectFormList: true,
|
||||
@@ -102,52 +102,22 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
|
||||
List<Widget> _buildEmailReceiveTimeTypeActionTiles(BuildContext context) {
|
||||
return EmailReceiveTimeType.values
|
||||
.map(
|
||||
(e) => Material(
|
||||
child: PopupMenuItem(
|
||||
child: Row(children: [
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
e.getTitle(
|
||||
context,
|
||||
startDate: controller.startDate,
|
||||
endDate: controller.endDate),
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500))),
|
||||
if (e == controller.dateFilterSelectedFormAdvancedSearch.value)
|
||||
...[
|
||||
const SizedBox(width: 12),
|
||||
SvgPicture.asset(
|
||||
_imagePaths.icFilterSelected,
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
]
|
||||
]),
|
||||
onTap: () {
|
||||
if (e != EmailReceiveTimeType.customRange) {
|
||||
controller.clearDateRangeOfFilter();
|
||||
}
|
||||
controller.dateFilterSelectedFormAdvancedSearch.value = e;
|
||||
controller.dateFilterInputController.text = e.getTitle(
|
||||
context,
|
||||
startDate: controller.startDate,
|
||||
endDate: controller.endDate);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
.map((receiveTime) => PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemNoIconWidget(
|
||||
receiveTime.getTitle(context),
|
||||
svgIconSelected: _imagePaths.icFilterSelected,
|
||||
maxWidth: 320,
|
||||
isSelected: controller.dateFilterSelectedFormAdvancedSearch.value == receiveTime,
|
||||
onCallbackAction: () => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
||||
)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Widget _buildFilterField({
|
||||
required BuildContext context,
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required TextEditingController textEditingController,
|
||||
TextEditingController? textEditingController,
|
||||
VoidCallback? onTap,
|
||||
bool isSelectFormList = false,
|
||||
MouseCursor? mouseCursor,
|
||||
@@ -180,7 +150,13 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
)
|
||||
else if (_responsiveUtils.landscapeTabletSupported(context))
|
||||
if (advancedSearchFilterField == AdvancedSearchFilterField.date)
|
||||
const DateDropDownButton()
|
||||
Obx(() => DateDropDownButton(
|
||||
_imagePaths,
|
||||
startDate: controller.startDate.value,
|
||||
endDate: controller.endDate.value,
|
||||
receiveTimeSelected: controller.dateFilterSelectedFormAdvancedSearch.value,
|
||||
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
||||
))
|
||||
else
|
||||
_buildTextField(
|
||||
isSelectFormList: isSelectFormList,
|
||||
@@ -222,7 +198,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
Widget _buildTextFieldFilterForWeb({
|
||||
required BuildContext context,
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required TextEditingController textEditingController,
|
||||
TextEditingController? textEditingController,
|
||||
VoidCallback? onTap,
|
||||
bool isSelectFormList = false,
|
||||
MouseCursor? mouseCursor,
|
||||
@@ -231,7 +207,13 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
}) {
|
||||
switch (advancedSearchFilterField) {
|
||||
case AdvancedSearchFilterField.date:
|
||||
return const DateDropDownButton();
|
||||
return Obx(() => DateDropDownButton(
|
||||
_imagePaths,
|
||||
startDate: controller.startDate.value,
|
||||
endDate: controller.endDate.value,
|
||||
receiveTimeSelected: controller.dateFilterSelectedFormAdvancedSearch.value,
|
||||
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
||||
));
|
||||
default:
|
||||
return _buildTextField(
|
||||
isSelectFormList: isSelectFormList,
|
||||
@@ -357,7 +339,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
Widget _buildTextField({
|
||||
required BuildContext context,
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required TextEditingController textEditingController,
|
||||
TextEditingController? textEditingController,
|
||||
VoidCallback? onTap,
|
||||
bool isSelectFormList = false,
|
||||
MouseCursor? mouseCursor,
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/style_utils.dart';
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
||||
|
||||
class DateDropDownButton extends StatelessWidget {
|
||||
|
||||
final ImagePaths imagePaths;
|
||||
final DateTime? startDate;
|
||||
final DateTime? endDate;
|
||||
final EmailReceiveTimeType? receiveTimeSelected;
|
||||
final Function(EmailReceiveTimeType)? onReceiveTimeSelected;
|
||||
|
||||
const DateDropDownButton(
|
||||
this.imagePaths, {
|
||||
Key? key,
|
||||
this.startDate,
|
||||
this.endDate,
|
||||
this.receiveTimeSelected,
|
||||
this.onReceiveTimeSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownButtonHideUnderline(
|
||||
child: PointerInterceptor(
|
||||
child: DropdownButton2<EmailReceiveTimeType>(
|
||||
isExpanded: true,
|
||||
items: EmailReceiveTimeType.values
|
||||
.map((item) => _buildItemMenu(context, item))
|
||||
.toList(),
|
||||
value: receiveTimeSelected,
|
||||
customButton: Container(
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: AppColor.colorInputBorderCreateMailbox,
|
||||
width: 1,
|
||||
),
|
||||
color: AppColor.colorInputBackgroundCreateMailbox
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 12, right: 10),
|
||||
child: Row(children: [
|
||||
Expanded(child: Text(
|
||||
receiveTimeSelected?.getTitle(context, startDate: startDate, endDate: endDate) ?? '',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Colors.black
|
||||
),
|
||||
maxLines: 1,
|
||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
)),
|
||||
SvgPicture.asset(imagePaths.icDropDown)
|
||||
]),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onReceiveTimeSelected?.call(value);
|
||||
}
|
||||
},
|
||||
icon: SvgPicture.asset(imagePaths.icDropDown),
|
||||
buttonPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
buttonDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: AppColor.colorInputBorderCreateMailbox,
|
||||
width: 1,
|
||||
),
|
||||
color: AppColor.colorInputBackgroundCreateMailbox,
|
||||
),
|
||||
itemHeight: 44,
|
||||
buttonHeight: 44,
|
||||
selectedItemHighlightColor: Colors.white,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
dropdownMaxHeight: 200,
|
||||
dropdownDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Colors.white,
|
||||
),
|
||||
offset: const Offset(0.0, -8.0),
|
||||
dropdownElevation: 4,
|
||||
scrollbarRadius: const Radius.circular(40),
|
||||
scrollbarThickness: 6
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
DropdownMenuItem<EmailReceiveTimeType> _buildItemMenu(
|
||||
BuildContext context,
|
||||
EmailReceiveTimeType receiveTime
|
||||
) {
|
||||
return DropdownMenuItem<EmailReceiveTimeType>(
|
||||
value: receiveTime,
|
||||
child: PointerInterceptor(
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
height: 44,
|
||||
child: Row(children: [
|
||||
Expanded(child: Text(
|
||||
receiveTime.getTitle(context),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Colors.black
|
||||
),
|
||||
maxLines: 1,
|
||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
)),
|
||||
if (receiveTime == receiveTimeSelected)
|
||||
SvgPicture.asset(
|
||||
imagePaths.icChecked,
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.fill
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,7 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/views/button/icon_button_web.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -34,9 +35,8 @@ class IconOpenAdvancedSearchWidget extends StatelessWidget {
|
||||
width: 16,
|
||||
height: 16),
|
||||
onTap: () {
|
||||
if(searchController.isAdvancedSearchViewOpen.isFalse && searchController.advancedSearchIsActivated.isFalse){
|
||||
advancedFilterController.initSearchFilterField(context);
|
||||
}
|
||||
log('IconOpenAdvancedSearchWidget::build(): clicked');
|
||||
advancedFilterController.initSearchFilterField(context);
|
||||
searchController.showAdvancedFilterView(_parentContext);
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -128,10 +128,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin {
|
||||
},
|
||||
buttonActionCallback: (filterAction) {
|
||||
if (filterAction is QuickSearchFilter) {
|
||||
dashBoardController.selectQuickSearchFilter(
|
||||
quickSearchFilter: filterAction,
|
||||
fromSuggestionBox: true,
|
||||
);
|
||||
dashBoardController.addFilterToSuggestionForm(filterAction);
|
||||
}
|
||||
},
|
||||
listActionPadding: const EdgeInsets.only(
|
||||
@@ -210,43 +207,31 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin {
|
||||
}
|
||||
|
||||
Widget buildListButtonForQuickSearchForm(BuildContext context, QuickSearchFilter filter) {
|
||||
final controller = dashBoardController.searchController;
|
||||
|
||||
return Obx(() {
|
||||
final isFilterSelected = dashBoardController.checkQuickSearchFilterSelected(
|
||||
quickSearchFilter: filter);
|
||||
final isFilterSelected = filter.isApplied(dashBoardController.searchController.listFilterOnSuggestionForm);
|
||||
|
||||
return Chip(
|
||||
labelPadding: const EdgeInsets.only(
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
right: 10),
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
right: 10),
|
||||
label: Text(
|
||||
filter.getTitle(
|
||||
context,
|
||||
receiveTimeType: controller.emailReceiveTimeType.value),
|
||||
filter.getName(context),
|
||||
maxLines: 1,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||
style: filter.getTextStyle(
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
style: filter.getTextStyle(isFilterSelected: isFilterSelected),
|
||||
),
|
||||
avatar: SvgPicture.asset(
|
||||
filter.getIcon(
|
||||
imagePaths,
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill),
|
||||
labelStyle: filter.getTextStyle(
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
backgroundColor: filter.getBackgroundColor(
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
filter.getIcon(imagePaths, isFilterSelected: isFilterSelected),
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill),
|
||||
labelStyle: filter.getTextStyle(isFilterSelected: isFilterSelected),
|
||||
backgroundColor: filter.getBackgroundColor(isFilterSelected: isFilterSelected),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(
|
||||
color: filter.getBackgroundColor(
|
||||
quickSearchFilterSelected: isFilterSelected)),
|
||||
side: BorderSide(color: filter.getBackgroundColor(isFilterSelected: isFilterSelected)),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user