Reuse widgets for advanced search form view
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
|||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/utils/theme_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
|
class DefaultButtonArrowDownFieldWidget extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String iconArrowDown;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
const DefaultButtonArrowDownFieldWidget({
|
||||||
|
super.key,
|
||||||
|
required this.text,
|
||||||
|
required this.iconArrowDown,
|
||||||
|
required this.onTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
type: MaterialType.transparency,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||||
|
focusColor: AppColor.colorMailboxHovered,
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColor.m3Neutral90,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsetsDirectional.only(start: 12, end: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: ThemeUtils.textStyleBodyBody3(
|
||||||
|
color: AppColor.m3SurfaceBackground,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SvgPicture.asset(iconArrowDown),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/default_field/default_button_arrow_down_field_widget.dart';
|
||||||
|
|
||||||
|
class DefaultButtonArrowDownFieldWithTabKeyWidget extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String iconArrowDown;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final FocusNode currentFocusNode;
|
||||||
|
final FocusNode nextFocusNode;
|
||||||
|
|
||||||
|
const DefaultButtonArrowDownFieldWithTabKeyWidget({
|
||||||
|
super.key,
|
||||||
|
required this.text,
|
||||||
|
required this.iconArrowDown,
|
||||||
|
required this.onTap,
|
||||||
|
required this.currentFocusNode,
|
||||||
|
required this.nextFocusNode,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return KeyboardListener(
|
||||||
|
focusNode: currentFocusNode,
|
||||||
|
onKeyEvent: _onKeyEvent,
|
||||||
|
child: DefaultButtonArrowDownFieldWidget(
|
||||||
|
text: text,
|
||||||
|
iconArrowDown: iconArrowDown,
|
||||||
|
onTap: onTap,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onKeyEvent(KeyEvent event) {
|
||||||
|
if (event is KeyDownEvent &&
|
||||||
|
event.logicalKey == LogicalKeyboardKey.tab) {
|
||||||
|
nextFocusNode.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import 'package:core/presentation/resources/image_paths.dart';
|
|||||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/model/search/email_receive_time_type.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/default_field/date_drop_down_button.dart';
|
import 'package:tmail_ui_user/features/base/widget/default_field/default_date_drop_down_button.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
typedef OnOpenDatPicker = void Function();
|
typedef OnOpenDatPicker = void Function();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ typedef OnTextChange = void Function(String text);
|
|||||||
class DefaultInputFieldWithTabKeyWidget extends StatelessWidget {
|
class DefaultInputFieldWithTabKeyWidget extends StatelessWidget {
|
||||||
final TextEditingController textEditingController;
|
final TextEditingController textEditingController;
|
||||||
final FocusNode currentFocusNode;
|
final FocusNode currentFocusNode;
|
||||||
final FocusNode? nextFocusNode;
|
final FocusNode nextFocusNode;
|
||||||
final String? hintText;
|
final String? hintText;
|
||||||
final OnTextChange? onTextChange;
|
final OnTextChange? onTextChange;
|
||||||
final OnTextSubmitted? onTextSubmitted;
|
final OnTextSubmitted? onTextSubmitted;
|
||||||
@@ -18,7 +18,7 @@ class DefaultInputFieldWithTabKeyWidget extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.textEditingController,
|
required this.textEditingController,
|
||||||
required this.currentFocusNode,
|
required this.currentFocusNode,
|
||||||
this.nextFocusNode,
|
required this.nextFocusNode,
|
||||||
this.hintText,
|
this.hintText,
|
||||||
this.onTextChange,
|
this.onTextChange,
|
||||||
this.onTextSubmitted,
|
this.onTextSubmitted,
|
||||||
@@ -29,7 +29,7 @@ class DefaultInputFieldWithTabKeyWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bodyWidget = KeyboardListener(
|
final bodyWidget = KeyboardListener(
|
||||||
focusNode: currentFocusNode,
|
focusNode: currentFocusNode,
|
||||||
onKeyEvent: nextFocusNode == null ? null : _onKeyEvent,
|
onKeyEvent: _onKeyEvent,
|
||||||
child: DefaultInputFieldWidget(
|
child: DefaultInputFieldWidget(
|
||||||
textEditingController: textEditingController,
|
textEditingController: textEditingController,
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
@@ -48,7 +48,7 @@ class DefaultInputFieldWithTabKeyWidget extends StatelessWidget {
|
|||||||
void _onKeyEvent(KeyEvent event) {
|
void _onKeyEvent(KeyEvent event) {
|
||||||
if (event is KeyDownEvent &&
|
if (event is KeyDownEvent &&
|
||||||
event.logicalKey == LogicalKeyboardKey.tab) {
|
event.logicalKey == LogicalKeyboardKey.tab) {
|
||||||
nextFocusNode?.requestFocus();
|
nextFocusNode.requestFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -37,6 +37,7 @@ class AdvancedFilterController extends BaseController {
|
|||||||
final startDate = Rxn<DateTime>();
|
final startDate = Rxn<DateTime>();
|
||||||
final endDate = Rxn<DateTime>();
|
final endDate = Rxn<DateTime>();
|
||||||
final sortOrderType = EmailSortOrderType.mostRecent.obs;
|
final sortOrderType = EmailSortOrderType.mostRecent.obs;
|
||||||
|
final selectedFolderName = Rxn<String>();
|
||||||
|
|
||||||
final GlobalKey<TagsEditorState> keyFromEmailTagEditor = GlobalKey<TagsEditorState>();
|
final GlobalKey<TagsEditorState> keyFromEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||||
final GlobalKey<TagsEditorState> keyToEmailTagEditor = GlobalKey<TagsEditorState>();
|
final GlobalKey<TagsEditorState> keyToEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||||
@@ -51,7 +52,6 @@ class AdvancedFilterController extends BaseController {
|
|||||||
TextEditingController subjectFilterInputController = TextEditingController();
|
TextEditingController subjectFilterInputController = TextEditingController();
|
||||||
TextEditingController hasKeyWordFilterInputController = TextEditingController();
|
TextEditingController hasKeyWordFilterInputController = TextEditingController();
|
||||||
TextEditingController notKeyWordFilterInputController = TextEditingController();
|
TextEditingController notKeyWordFilterInputController = TextEditingController();
|
||||||
TextEditingController mailBoxFilterInputController = TextEditingController();
|
|
||||||
|
|
||||||
final search.SearchController searchController = Get.find<search.SearchController>();
|
final search.SearchController searchController = Get.find<search.SearchController>();
|
||||||
final MailboxDashBoardController _mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
final MailboxDashBoardController _mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||||
@@ -206,7 +206,7 @@ class AdvancedFilterController extends BaseController {
|
|||||||
final mailboxName = context.mounted
|
final mailboxName = context.mounted
|
||||||
? _destinationMailboxSelected?.getDisplayName(context)
|
? _destinationMailboxSelected?.getDisplayName(context)
|
||||||
: _destinationMailboxSelected?.name?.name;
|
: _destinationMailboxSelected?.name?.name;
|
||||||
mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(mailboxName);
|
selectedFolderName.value = StringConvert.writeNullToEmpty(mailboxName);
|
||||||
_updateMemorySearchFilter(mailboxOption: optionOf(_destinationMailboxSelected));
|
_updateMemorySearchFilter(mailboxOption: optionOf(_destinationMailboxSelected));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ class AdvancedFilterController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
mailBoxFilterInputController.text = _memorySearchFilter.mailbox == null
|
selectedFolderName.value = _memorySearchFilter.mailbox == null
|
||||||
? AppLocalizations.of(context).allFolders
|
? AppLocalizations.of(context).allFolders
|
||||||
: StringConvert.writeNullToEmpty(
|
: StringConvert.writeNullToEmpty(
|
||||||
_memorySearchFilter.mailbox?.getDisplayName(context));
|
_memorySearchFilter.mailbox?.getDisplayName(context));
|
||||||
@@ -450,6 +450,7 @@ class AdvancedFilterController extends BaseController {
|
|||||||
endDate.value = null;
|
endDate.value = null;
|
||||||
receiveTimeType.value = EmailReceiveTimeType.allTime;
|
receiveTimeType.value = EmailReceiveTimeType.allTime;
|
||||||
hasAttachment.value = false;
|
hasAttachment.value = false;
|
||||||
|
selectedFolderName.value = null;
|
||||||
listFromEmailAddress.clear();
|
listFromEmailAddress.clear();
|
||||||
listToEmailAddress.clear();
|
listToEmailAddress.clear();
|
||||||
_destinationMailboxSelected = null;
|
_destinationMailboxSelected = null;
|
||||||
@@ -459,7 +460,6 @@ class AdvancedFilterController extends BaseController {
|
|||||||
subjectFilterInputController.clear();
|
subjectFilterInputController.clear();
|
||||||
hasKeyWordFilterInputController.clear();
|
hasKeyWordFilterInputController.clear();
|
||||||
notKeyWordFilterInputController.clear();
|
notKeyWordFilterInputController.clear();
|
||||||
mailBoxFilterInputController.clear();
|
|
||||||
fromEmailAddressController.clear();
|
fromEmailAddressController.clear();
|
||||||
toEmailAddressController.clear();
|
toEmailAddressController.clear();
|
||||||
}
|
}
|
||||||
@@ -600,7 +600,6 @@ class AdvancedFilterController extends BaseController {
|
|||||||
subjectFilterInputController.dispose();
|
subjectFilterInputController.dispose();
|
||||||
hasKeyWordFilterInputController.dispose();
|
hasKeyWordFilterInputController.dispose();
|
||||||
notKeyWordFilterInputController.dispose();
|
notKeyWordFilterInputController.dispose();
|
||||||
mailBoxFilterInputController.dispose();
|
|
||||||
toEmailAddressController.dispose();
|
toEmailAddressController.dispose();
|
||||||
fromEmailAddressController.dispose();
|
fromEmailAddressController.dispose();
|
||||||
_unregisterWorkerListener();
|
_unregisterWorkerListener();
|
||||||
|
|||||||
+2
@@ -10,6 +10,8 @@ class AdvancedSearchInputFormStyle {
|
|||||||
static const double inputFieldBorderRadius = 10;
|
static const double inputFieldBorderRadius = 10;
|
||||||
static const double inputFieldBorderWidth = 1;
|
static const double inputFieldBorderWidth = 1;
|
||||||
static const double inputFieldHeight = 40;
|
static const double inputFieldHeight = 40;
|
||||||
|
static const double labelMaxWidth = 112;
|
||||||
|
static const double labelSpace = 12;
|
||||||
|
|
||||||
static const Color inputFieldBorderColor = AppColor.m3Neutral90;
|
static const Color inputFieldBorderColor = AppColor.m3Neutral90;
|
||||||
static const Color inputFieldBackgroundColor = Colors.white;
|
static const Color inputFieldBackgroundColor = Colors.white;
|
||||||
|
|||||||
@@ -1,26 +1,41 @@
|
|||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/utils/theme_utils.dart';
|
||||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SortByDropdownStyle {
|
class SortByDropdownStyle {
|
||||||
static const int dropdownElevation = 4;
|
static const int dropdownElevation = 0;
|
||||||
|
|
||||||
static const double height = 44;
|
static const double height = 44;
|
||||||
static const double dropdownMaxHeight = 332;
|
static const double dropdownMaxHeight = 332;
|
||||||
static const double scrollbarThickness = 6;
|
static const double scrollbarThickness = 6;
|
||||||
static const double checkedIconSize = 20;
|
static const double checkedIconSize = 20;
|
||||||
|
|
||||||
static const Offset dropdownOffset = Offset(0.0, -8.0);
|
static const Offset dropdownOffset = Offset(0.0, -3.0);
|
||||||
|
|
||||||
static const BoxDecoration dropdownDecoration = BoxDecoration(
|
static BoxDecoration dropdownDecoration = BoxDecoration(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||||
color: Colors.white
|
color: Colors.white,
|
||||||
|
border: Border.all(color: AppColor.m3Tertiary60),
|
||||||
|
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 24)],
|
||||||
);
|
);
|
||||||
|
|
||||||
static const EdgeInsetsDirectional buttonPadding = EdgeInsetsDirectional.only(start: 12, end: 8);
|
static const EdgeInsetsGeometry buttonPadding = EdgeInsetsDirectional.only(
|
||||||
|
start: 12,
|
||||||
|
end: 8,
|
||||||
|
);
|
||||||
|
static const EdgeInsetsGeometry dropdownPadding = EdgeInsets.all(12);
|
||||||
static const MenuItemStyleData menuItemStyleData = MenuItemStyleData(
|
static const MenuItemStyleData menuItemStyleData = MenuItemStyleData(
|
||||||
height: height,
|
height: height,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||||
);
|
);
|
||||||
|
|
||||||
static const Radius dropdownScrollbarRadius = Radius.circular(40);
|
static const Radius dropdownScrollbarRadius = Radius.circular(40);
|
||||||
|
|
||||||
|
static TextStyle menuItemStyle = ThemeUtils.textStyleInter400.copyWith(
|
||||||
|
fontSize: 15,
|
||||||
|
height: 20 / 15,
|
||||||
|
letterSpacing: -0.15,
|
||||||
|
color: Colors.black,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
import 'package:core/presentation/extensions/color_extension.dart';
|
|
||||||
import 'package:core/presentation/utils/theme_utils.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/advanced_search_input_form_style.dart';
|
|
||||||
|
|
||||||
class TextFieldAutoCompleteEmailAddressWebStyles {
|
|
||||||
static const EdgeInsetsGeometry textInputContentPadding =
|
|
||||||
EdgeInsetsDirectional.only(
|
|
||||||
top: 14,
|
|
||||||
bottom: 14,
|
|
||||||
start: 12,
|
|
||||||
end: 8,
|
|
||||||
);
|
|
||||||
static const EdgeInsetsGeometry textInputContentPaddingWithSomeTag =
|
|
||||||
EdgeInsetsDirectional.symmetric(vertical: 14);
|
|
||||||
static const EdgeInsets tagEditorPadding = EdgeInsets.symmetric(horizontal: 12);
|
|
||||||
|
|
||||||
static const double suggestionBoxRadius = 20.0;
|
|
||||||
|
|
||||||
static const double minTextFieldWidth = 40.0;
|
|
||||||
|
|
||||||
static const double suggestionBoxElevation = 20.0;
|
|
||||||
static const double suggestionBoxMaxHeight = 350.0;
|
|
||||||
static const double suggestionBoxItemHeight = ComposerStyle.suggestionItemHeight;
|
|
||||||
|
|
||||||
static const double fieldTitleWidth = 112.0;
|
|
||||||
static const double space = 12.0;
|
|
||||||
|
|
||||||
static const InputBorder textInputBorder = OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(AdvancedSearchInputFormStyle.inputFieldBorderRadius)),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
);
|
|
||||||
|
|
||||||
static const Color textInputFillColor = Colors.white;
|
|
||||||
static const Color focusedBorderColor = AppColor.primaryColor;
|
|
||||||
static const Color suggestionBoxBackgroundColor = Colors.white;
|
|
||||||
static const Color cursorColor = AppColor.primaryColor;
|
|
||||||
|
|
||||||
static TextStyle textInputHintStyle = ThemeUtils.textStyleBodyBody3(
|
|
||||||
color: AppColor.m3Tertiary,
|
|
||||||
);
|
|
||||||
|
|
||||||
static const Duration debounceDuration = Duration(milliseconds: 150);
|
|
||||||
}
|
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/advanced_search_input_form_style.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/label_advanced_search_field_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
|
class AdvancedSearchFieldWidget extends StatelessWidget {
|
||||||
|
final FilterField filterField;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const AdvancedSearchFieldWidget({
|
||||||
|
super.key,
|
||||||
|
required this.filterField,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: AdvancedSearchInputFormStyle.inputFieldHeight,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: AdvancedSearchInputFormStyle.labelMaxWidth,
|
||||||
|
child: LabelAdvancedSearchFieldWidget(
|
||||||
|
name: filterField.getTitle(AppLocalizations.of(context)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: AdvancedSearchInputFormStyle.labelSpace),
|
||||||
|
Expanded(child: child),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+109
-359
@@ -1,157 +1,146 @@
|
|||||||
import 'package:core/core.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:get/get.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/default_field/default_autocomplete_input_field_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart';
|
import 'package:tmail_ui_user/features/base/widget/default_field/default_button_arrow_down_field_with_tab_key_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/default_field/default_date_drop_down_field_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/default_field/default_input_field_with_tab_key_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/controller/advanced_filter_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
|
import 'package:tmail_ui_user/features/base/model/filter_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/model/search/email_receive_time_type.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/advanced_search_input_form_style.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_field_widget.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/advanced_search_filter_form_bottom_view.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/default_field/date_drop_down_button.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/label_advanced_search_field_widget.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/sort_by_drop_down_button.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/sort_by_drop_down_button.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_autocomplete_email_address_web.dart';
|
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
|
||||||
|
|
||||||
class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController> {
|
||||||
with PopupContextMenuActionMixin {
|
const AdvancedSearchInputForm({Key? key}) : super(key: key);
|
||||||
AdvancedSearchInputForm({
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final appLocalizations = AppLocalizations.of(context);
|
||||||
return FocusTraversalGroup(
|
return FocusTraversalGroup(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Obx(() => TextFieldAutocompleteEmailAddressWeb(
|
AdvancedSearchFieldWidget(
|
||||||
field: FilterField.from,
|
filterField: FilterField.from,
|
||||||
listEmailAddress: controller.listFromEmailAddress,
|
child: Obx(() => DefaultAutocompleteInputFieldWidget(
|
||||||
expandMode: controller.fromAddressExpandMode.value,
|
field: FilterField.from,
|
||||||
minInputLengthAutocomplete: controller
|
listEmailAddress: controller.listFromEmailAddress,
|
||||||
.mailboxDashBoardController
|
expandMode: controller.fromAddressExpandMode.value,
|
||||||
.minInputLengthAutocomplete,
|
minInputLengthAutocomplete: controller
|
||||||
controller: controller.fromEmailAddressController,
|
.mailboxDashBoardController
|
||||||
focusNode: controller.focusManager.fromFieldFocusNode,
|
.minInputLengthAutocomplete,
|
||||||
nextFocusNode: controller.focusManager.toFieldFocusNode,
|
controller: controller.fromEmailAddressController,
|
||||||
keyTagEditor: controller.keyFromEmailTagEditor,
|
focusNode: controller.focusManager.fromFieldFocusNode,
|
||||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
nextFocusNode: controller.focusManager.toFieldFocusNode,
|
||||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
keyTagEditor: controller.keyFromEmailTagEditor,
|
||||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||||
onSearchAction: controller.onSearchAction,
|
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||||
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||||
)),
|
onSearchAction: controller.onSearchAction,
|
||||||
|
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
||||||
|
)),
|
||||||
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Obx(() => TextFieldAutocompleteEmailAddressWeb(
|
AdvancedSearchFieldWidget(
|
||||||
field: FilterField.to,
|
filterField: FilterField.to,
|
||||||
listEmailAddress: controller.listToEmailAddress,
|
child: Obx(() => DefaultAutocompleteInputFieldWidget(
|
||||||
expandMode: controller.toAddressExpandMode.value,
|
field: FilterField.to,
|
||||||
minInputLengthAutocomplete: controller
|
listEmailAddress: controller.listToEmailAddress,
|
||||||
.mailboxDashBoardController
|
expandMode: controller.toAddressExpandMode.value,
|
||||||
.minInputLengthAutocomplete,
|
minInputLengthAutocomplete: controller
|
||||||
controller: controller.toEmailAddressController,
|
.mailboxDashBoardController
|
||||||
focusNode: controller.focusManager.toFieldFocusNode,
|
.minInputLengthAutocomplete,
|
||||||
nextFocusNode: controller.focusManager.subjectFieldFocusNode,
|
controller: controller.toEmailAddressController,
|
||||||
keyTagEditor: controller.keyToEmailTagEditor,
|
focusNode: controller.focusManager.toFieldFocusNode,
|
||||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
nextFocusNode: controller.focusManager.subjectFieldFocusNode,
|
||||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
keyTagEditor: controller.keyToEmailTagEditor,
|
||||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||||
onSearchAction: controller.onSearchAction,
|
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||||
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||||
)),
|
onSearchAction: controller.onSearchAction,
|
||||||
|
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
||||||
|
)),
|
||||||
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildFilterField(
|
AdvancedSearchFieldWidget(
|
||||||
textEditingController: controller.subjectFilterInputController,
|
|
||||||
context: context,
|
|
||||||
filterField: FilterField.subject,
|
filterField: FilterField.subject,
|
||||||
currentFocusNode: controller.focusManager.subjectFieldFocusNode,
|
child: DefaultInputFieldWithTabKeyWidget(
|
||||||
nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
|
textEditingController: controller.subjectFilterInputController,
|
||||||
onTextChange: (value) => controller.onTextChanged(
|
currentFocusNode: controller.focusManager.subjectFieldFocusNode,
|
||||||
FilterField.subject,
|
nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
|
||||||
value
|
hintText: FilterField.subject.getHintText(appLocalizations),
|
||||||
|
onTextChange: (value) => controller.onTextChanged(
|
||||||
|
FilterField.subject,
|
||||||
|
value,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildFilterField(
|
AdvancedSearchFieldWidget(
|
||||||
textEditingController: controller.hasKeyWordFilterInputController,
|
|
||||||
context: context,
|
|
||||||
filterField: FilterField.hasKeyword,
|
filterField: FilterField.hasKeyword,
|
||||||
currentFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
|
child: DefaultInputFieldWithTabKeyWidget(
|
||||||
nextFocusNode: controller.focusManager.notKeywordFieldFocusNode,
|
textEditingController: controller.hasKeyWordFilterInputController,
|
||||||
onTextChange: (value) => controller.onTextChanged(
|
currentFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
|
||||||
FilterField.hasKeyword,
|
nextFocusNode: controller.focusManager.notKeywordFieldFocusNode,
|
||||||
value
|
hintText: FilterField.hasKeyword.getHintText(appLocalizations),
|
||||||
|
onTextChange: (value) => controller.onTextChanged(
|
||||||
|
FilterField.hasKeyword,
|
||||||
|
value,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildFilterField(
|
AdvancedSearchFieldWidget(
|
||||||
textEditingController: controller.notKeyWordFilterInputController,
|
|
||||||
context: context,
|
|
||||||
filterField: FilterField.notKeyword,
|
filterField: FilterField.notKeyword,
|
||||||
currentFocusNode: controller.focusManager.notKeywordFieldFocusNode,
|
child: DefaultInputFieldWithTabKeyWidget(
|
||||||
nextFocusNode: controller.focusManager.mailboxFieldFocusNode,
|
textEditingController: controller.notKeyWordFilterInputController,
|
||||||
onTextChange: (value) => controller.onTextChanged(
|
currentFocusNode: controller.focusManager.notKeywordFieldFocusNode,
|
||||||
FilterField.notKeyword,
|
nextFocusNode: controller.focusManager.mailboxFieldFocusNode,
|
||||||
value
|
hintText: FilterField.notKeyword.getHintText(appLocalizations),
|
||||||
|
onTextChange: (value) => controller.onTextChanged(
|
||||||
|
FilterField.notKeyword,
|
||||||
|
value,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildFilterField(
|
AdvancedSearchFieldWidget(
|
||||||
textEditingController: controller.mailBoxFilterInputController,
|
|
||||||
context: context,
|
|
||||||
filterField: FilterField.mailBox,
|
filterField: FilterField.mailBox,
|
||||||
isSelectFormList: true,
|
child: Obx(() => DefaultButtonArrowDownFieldWithTabKeyWidget(
|
||||||
currentFocusNode: controller.focusManager.mailboxFieldFocusNode,
|
text: controller.selectedFolderName.value ??
|
||||||
nextFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
|
AppLocalizations.of(context).allFolders,
|
||||||
mouseCursor: SystemMouseCursors.click,
|
iconArrowDown: controller.imagePaths.icDropDown,
|
||||||
onTap: () => controller.selectedMailBox(context)
|
currentFocusNode: controller.focusManager.mailboxFieldFocusNode,
|
||||||
|
nextFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
|
||||||
|
onTap: () => controller.selectedMailBox(context),
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Row(children: [
|
AdvancedSearchFieldWidget(
|
||||||
Expanded(child: _buildFilterField(
|
filterField: FilterField.date,
|
||||||
context: context,
|
child: Obx(() => DefaultDateDropDownFieldWidget(
|
||||||
filterField: FilterField.date,
|
imagePaths: controller.imagePaths,
|
||||||
isSelectFormList: true,
|
receiveTimeTypes: EmailReceiveTimeType.valuesForSearch,
|
||||||
onTap: () {
|
startDate: controller.startDate.value,
|
||||||
openContextMenuAction(
|
endDate: controller.endDate.value,
|
||||||
context,
|
receiveTimeTypeSelected: controller.receiveTimeType.value,
|
||||||
_buildEmailReceiveTimeTypeActionTiles(context),
|
onReceiveTimeSelected: (receiveTime) =>
|
||||||
);
|
controller.updateReceiveDateSearchFilter(
|
||||||
},
|
context,
|
||||||
)),
|
receiveTime,
|
||||||
const SizedBox(width: 8),
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
color: AdvancedSearchInputFormStyle.inputFieldBorderColor,
|
|
||||||
width: AdvancedSearchInputFormStyle.inputFieldBorderWidth,
|
|
||||||
),
|
|
||||||
borderRadius: const BorderRadius.all(
|
|
||||||
Radius.circular(
|
|
||||||
AdvancedSearchInputFormStyle.inputFieldBorderRadius,
|
|
||||||
),
|
),
|
||||||
),
|
onOpenDatPicker: () => controller.selectDateRange(context),
|
||||||
),
|
)),
|
||||||
height: AdvancedSearchInputFormStyle.inputFieldHeight,
|
),
|
||||||
width: AdvancedSearchInputFormStyle.inputFieldHeight,
|
|
||||||
child: TMailButtonWidget.fromIcon(
|
|
||||||
icon: controller.imagePaths.icCalendarSB,
|
|
||||||
iconSize: 22,
|
|
||||||
iconColor: AppColor.steelGray400,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
tooltipMessage: AppLocalizations.of(context).selectDate,
|
|
||||||
onTapActionCallback: () => controller.selectDateRange(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildFilterField(
|
AdvancedSearchFieldWidget(
|
||||||
context: context,
|
filterField: FilterField.sortBy,
|
||||||
filterField: FilterField.sortBy
|
child: Obx(() => SortByDropDownButton(
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
sortOrderSelected: controller.sortOrderType.value,
|
||||||
|
onSortOrderSelected: controller.updateSortOrder,
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
AdvancedSearchFilterFormBottomView(focusManager: controller.focusManager)
|
AdvancedSearchFilterFormBottomView(focusManager: controller.focusManager)
|
||||||
@@ -159,243 +148,4 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildEmailReceiveTimeTypeActionTiles(BuildContext context) {
|
|
||||||
return EmailReceiveTimeType.valuesForSearch
|
|
||||||
.map((receiveTime) => PopupMenuItem(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
child: PopupItemNoIconWidget(
|
|
||||||
receiveTime.getTitle(context),
|
|
||||||
svgIconSelected: controller.imagePaths.icFilterSelected,
|
|
||||||
maxWidth: 320,
|
|
||||||
isSelected: controller.receiveTimeType.value == receiveTime,
|
|
||||||
onCallbackAction: () => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
|
||||||
)))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildFilterField({
|
|
||||||
required BuildContext context,
|
|
||||||
required FilterField filterField,
|
|
||||||
TextEditingController? textEditingController,
|
|
||||||
VoidCallback? onTap,
|
|
||||||
bool isSelectFormList = false,
|
|
||||||
MouseCursor? mouseCursor,
|
|
||||||
FocusNode? currentFocusNode,
|
|
||||||
FocusNode? nextFocusNode,
|
|
||||||
ValueChanged<String>? onTextChange,
|
|
||||||
}) {
|
|
||||||
final child = [
|
|
||||||
SizedBox(
|
|
||||||
width: _isVerticalArrange(context) ? null : 112,
|
|
||||||
child: LabelAdvancedSearchFieldWidget(
|
|
||||||
name: filterField.getTitle(AppLocalizations.of(context)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_isVerticalArrange(context))
|
|
||||||
const SizedBox(height: 12)
|
|
||||||
else
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
if (controller.responsiveUtils.isMobile(context))
|
|
||||||
_buildTextField(
|
|
||||||
isSelectFormList: isSelectFormList,
|
|
||||||
onTap: onTap,
|
|
||||||
context: context,
|
|
||||||
mouseCursor: mouseCursor,
|
|
||||||
currentFocusNode: currentFocusNode,
|
|
||||||
nextFocusNode: nextFocusNode,
|
|
||||||
filterField: filterField,
|
|
||||||
textEditingController: textEditingController,
|
|
||||||
onTextChange: onTextChange,
|
|
||||||
)
|
|
||||||
else if (controller.responsiveUtils.landscapeTabletSupported(context))
|
|
||||||
if (filterField == FilterField.date)
|
|
||||||
Obx(() => DateDropDownButton(
|
|
||||||
imagePaths: controller.imagePaths,
|
|
||||||
receiveTimeTypes: EmailReceiveTimeType.valuesForSearch,
|
|
||||||
startDate: controller.startDate.value,
|
|
||||||
endDate: controller.endDate.value,
|
|
||||||
receiveTimeTypeSelected: controller.receiveTimeType.value,
|
|
||||||
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
|
||||||
))
|
|
||||||
else if (filterField == FilterField.sortBy)
|
|
||||||
Obx(() => SortByDropDownButton(
|
|
||||||
imagePaths: controller.imagePaths,
|
|
||||||
sortOrderSelected: controller.sortOrderType.value,
|
|
||||||
onSortOrderSelected: controller.updateSortOrder,
|
|
||||||
))
|
|
||||||
else
|
|
||||||
_buildTextField(
|
|
||||||
isSelectFormList: isSelectFormList,
|
|
||||||
onTap: onTap,
|
|
||||||
context: context,
|
|
||||||
mouseCursor: mouseCursor,
|
|
||||||
currentFocusNode: currentFocusNode,
|
|
||||||
nextFocusNode: nextFocusNode,
|
|
||||||
filterField: filterField,
|
|
||||||
textEditingController: textEditingController,
|
|
||||||
onTextChange: onTextChange,
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Expanded(
|
|
||||||
child: _buildTextFieldFilterForWeb(
|
|
||||||
isSelectFormList: isSelectFormList,
|
|
||||||
onTap: onTap,
|
|
||||||
context: context,
|
|
||||||
mouseCursor: mouseCursor,
|
|
||||||
currentFocusNode: currentFocusNode,
|
|
||||||
nextFocusNode: nextFocusNode,
|
|
||||||
filterField: filterField,
|
|
||||||
textEditingController: textEditingController,
|
|
||||||
onTextChange: onTextChange,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
];
|
|
||||||
return _isVerticalArrange(context)
|
|
||||||
? Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: child,
|
|
||||||
)
|
|
||||||
: SizedBox(
|
|
||||||
height: AdvancedSearchInputFormStyle.inputFieldHeight,
|
|
||||||
child: Row(children: child),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isVerticalArrange(BuildContext context) =>
|
|
||||||
controller.responsiveUtils.isMobile(context) ||
|
|
||||||
controller.responsiveUtils.landscapeTabletSupported(context);
|
|
||||||
|
|
||||||
Widget _buildTextFieldFilterForWeb({
|
|
||||||
required BuildContext context,
|
|
||||||
required FilterField filterField,
|
|
||||||
TextEditingController? textEditingController,
|
|
||||||
VoidCallback? onTap,
|
|
||||||
bool isSelectFormList = false,
|
|
||||||
MouseCursor? mouseCursor,
|
|
||||||
FocusNode? currentFocusNode,
|
|
||||||
FocusNode? nextFocusNode,
|
|
||||||
ValueChanged<String>? onTextChange,
|
|
||||||
}) {
|
|
||||||
switch (filterField) {
|
|
||||||
case FilterField.date:
|
|
||||||
return Obx(() => DateDropDownButton(
|
|
||||||
imagePaths: controller.imagePaths,
|
|
||||||
receiveTimeTypes: EmailReceiveTimeType.valuesForSearch,
|
|
||||||
startDate: controller.startDate.value,
|
|
||||||
endDate: controller.endDate.value,
|
|
||||||
receiveTimeTypeSelected: controller.receiveTimeType.value,
|
|
||||||
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
|
||||||
));
|
|
||||||
case FilterField.sortBy:
|
|
||||||
return Obx(() => SortByDropDownButton(
|
|
||||||
imagePaths: controller.imagePaths,
|
|
||||||
sortOrderSelected: controller.sortOrderType.value,
|
|
||||||
onSortOrderSelected: controller.updateSortOrder,
|
|
||||||
));
|
|
||||||
default:
|
|
||||||
return _buildTextField(
|
|
||||||
isSelectFormList: isSelectFormList,
|
|
||||||
onTap: onTap,
|
|
||||||
context: context,
|
|
||||||
mouseCursor: mouseCursor,
|
|
||||||
currentFocusNode: currentFocusNode,
|
|
||||||
nextFocusNode: nextFocusNode,
|
|
||||||
filterField: filterField,
|
|
||||||
textEditingController: textEditingController,
|
|
||||||
onTextChange: onTextChange,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTextField({
|
|
||||||
required BuildContext context,
|
|
||||||
required FilterField filterField,
|
|
||||||
TextEditingController? textEditingController,
|
|
||||||
VoidCallback? onTap,
|
|
||||||
bool isSelectFormList = false,
|
|
||||||
MouseCursor? mouseCursor,
|
|
||||||
FocusNode? currentFocusNode,
|
|
||||||
FocusNode? nextFocusNode,
|
|
||||||
ValueChanged<String>? onTextChange,
|
|
||||||
}) {
|
|
||||||
return KeyboardListener(
|
|
||||||
focusNode: currentFocusNode ?? FocusNode(),
|
|
||||||
onKeyEvent: (event) {
|
|
||||||
if (event is KeyDownEvent &&
|
|
||||||
event.logicalKey == LogicalKeyboardKey.tab) {
|
|
||||||
nextFocusNode?.requestFocus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: TextFieldBuilder(
|
|
||||||
controller: textEditingController,
|
|
||||||
readOnly: isSelectFormList,
|
|
||||||
mouseCursor: mouseCursor,
|
|
||||||
maxLines: 1,
|
|
||||||
textInputAction: isSelectFormList ? TextInputAction.done : TextInputAction.next,
|
|
||||||
textStyle: AdvancedSearchInputFormStyle.inputTextStyle,
|
|
||||||
onTap: onTap,
|
|
||||||
onTextSubmitted: (value) {
|
|
||||||
if (isSelectFormList) {
|
|
||||||
onTap?.call();
|
|
||||||
} else {
|
|
||||||
controller.onSearchAction();
|
|
||||||
popBack();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onTextChange: onTextChange,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxHeight: AdvancedSearchInputFormStyle.inputFieldHeight,
|
|
||||||
),
|
|
||||||
filled: true,
|
|
||||||
fillColor: AdvancedSearchInputFormStyle.inputFieldBackgroundColor,
|
|
||||||
contentPadding: const EdgeInsetsDirectional.only(start: 12, end: 8),
|
|
||||||
enabledBorder: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(AdvancedSearchInputFormStyle.inputFieldBorderRadius),
|
|
||||||
),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: AdvancedSearchInputFormStyle.inputFieldBorderWidth,
|
|
||||||
color: AdvancedSearchInputFormStyle.inputFieldBorderColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(AdvancedSearchInputFormStyle.inputFieldBorderRadius),
|
|
||||||
),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: AdvancedSearchInputFormStyle.inputFieldBorderWidth,
|
|
||||||
color: AdvancedSearchInputFormStyle.inputFieldBorderColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
focusedBorder: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(AdvancedSearchInputFormStyle.inputFieldBorderRadius),
|
|
||||||
),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
width: AdvancedSearchInputFormStyle.inputFieldBorderWidth,
|
|
||||||
color: AppColor.primaryColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
hintText: filterField.getHintText(AppLocalizations.of(context)),
|
|
||||||
hintStyle: ThemeUtils.textStyleBodyBody3(
|
|
||||||
color: filterField == FilterField.mailBox
|
|
||||||
? Colors.black
|
|
||||||
: AppColor.m3Tertiary,
|
|
||||||
),
|
|
||||||
suffixIconConstraints: const BoxConstraints(minHeight: 24, minWidth: 24),
|
|
||||||
suffixIcon: isSelectFormList
|
|
||||||
? buildIconWeb(
|
|
||||||
icon: SvgPicture.asset(
|
|
||||||
controller.imagePaths.icDropDown,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-43
@@ -1,5 +1,4 @@
|
|||||||
import 'package:core/presentation/resources/image_paths.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:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
@@ -32,30 +31,26 @@ class SortByDropDownButton extends StatelessWidget {
|
|||||||
items: EmailSortOrderType.values
|
items: EmailSortOrderType.values
|
||||||
.map((sortType) => DropdownMenuItem<EmailSortOrderType>(
|
.map((sortType) => DropdownMenuItem<EmailSortOrderType>(
|
||||||
value: sortType,
|
value: sortType,
|
||||||
|
enabled: sortType != sortOrderSelected,
|
||||||
child: PointerInterceptor(
|
child: PointerInterceptor(
|
||||||
child: Container(
|
child: Row(
|
||||||
color: Colors.transparent,
|
children: [
|
||||||
height: SortByDropdownStyle.height,
|
Expanded(
|
||||||
child: Row(
|
child: Text(
|
||||||
children: [
|
sortType.getTitle(context),
|
||||||
Expanded(
|
style: SortByDropdownStyle.menuItemStyle,
|
||||||
child: Text(
|
maxLines: 1,
|
||||||
sortType.getTitle(context),
|
overflow: TextOverflow.ellipsis,
|
||||||
style: sortType.getTextStyle(isInDropdown: true),
|
|
||||||
maxLines: 1,
|
|
||||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
|
||||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (sortType == sortOrderSelected)
|
),
|
||||||
SvgPicture.asset(
|
if (sortType == sortOrderSelected)
|
||||||
imagePaths.icChecked,
|
SvgPicture.asset(
|
||||||
width: SortByDropdownStyle.checkedIconSize,
|
imagePaths.icChecked,
|
||||||
height: SortByDropdownStyle.checkedIconSize,
|
width: SortByDropdownStyle.checkedIconSize,
|
||||||
fit: BoxFit.fill,
|
height: SortByDropdownStyle.checkedIconSize,
|
||||||
)
|
fit: BoxFit.fill,
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)).toList(),
|
)).toList(),
|
||||||
@@ -80,8 +75,7 @@ class SortByDropDownButton extends StatelessWidget {
|
|||||||
sortOrderSelected?.getTitle(context) ?? '',
|
sortOrderSelected?.getTitle(context) ?? '',
|
||||||
style: AdvancedSearchInputFormStyle.inputTextStyle,
|
style: AdvancedSearchInputFormStyle.inputTextStyle,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
overflow: TextOverflow.ellipsis,
|
||||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
SvgPicture.asset(imagePaths.icDropDown)
|
SvgPicture.asset(imagePaths.icDropDown)
|
||||||
@@ -89,35 +83,19 @@ class SortByDropDownButton extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onChanged: onSortOrderSelected,
|
onChanged: onSortOrderSelected,
|
||||||
buttonStyleData: ButtonStyleData(
|
|
||||||
height: AdvancedSearchInputFormStyle.inputFieldHeight,
|
|
||||||
padding: SortByDropdownStyle.buttonPadding,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: const BorderRadius.all(
|
|
||||||
Radius.circular(AdvancedSearchInputFormStyle.inputFieldBorderRadius),
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: AdvancedSearchInputFormStyle.inputFieldBorderColor,
|
|
||||||
width: AdvancedSearchInputFormStyle.inputFieldBorderWidth,
|
|
||||||
),
|
|
||||||
color: AdvancedSearchInputFormStyle.inputFieldBackgroundColor,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
dropdownStyleData: DropdownStyleData(
|
dropdownStyleData: DropdownStyleData(
|
||||||
maxHeight: SortByDropdownStyle.dropdownMaxHeight,
|
maxHeight: SortByDropdownStyle.dropdownMaxHeight,
|
||||||
decoration: SortByDropdownStyle.dropdownDecoration,
|
decoration: SortByDropdownStyle.dropdownDecoration,
|
||||||
elevation: SortByDropdownStyle.dropdownElevation,
|
elevation: SortByDropdownStyle.dropdownElevation,
|
||||||
offset: SortByDropdownStyle.dropdownOffset,
|
offset: SortByDropdownStyle.dropdownOffset,
|
||||||
|
padding: SortByDropdownStyle.dropdownPadding,
|
||||||
scrollbarTheme: ScrollbarThemeData(
|
scrollbarTheme: ScrollbarThemeData(
|
||||||
radius: SortByDropdownStyle.dropdownScrollbarRadius,
|
radius: SortByDropdownStyle.dropdownScrollbarRadius,
|
||||||
thickness: WidgetStateProperty.all<double>(SortByDropdownStyle.scrollbarThickness),
|
thickness: WidgetStateProperty.all<double>(SortByDropdownStyle.scrollbarThickness),
|
||||||
thumbVisibility: WidgetStateProperty.all<bool>(true),
|
thumbVisibility: WidgetStateProperty.all<bool>(true),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
iconStyleData: IconStyleData(
|
menuItemStyleData: SortByDropdownStyle.menuItemStyleData,
|
||||||
icon: SvgPicture.asset(imagePaths.icDropDown),
|
|
||||||
),
|
|
||||||
menuItemStyleData: SortByDropdownStyle.menuItemStyleData
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
-409
@@ -1,409 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:core/presentation/extensions/color_extension.dart';
|
|
||||||
import 'package:core/presentation/resources/image_paths.dart';
|
|
||||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
|
||||||
import 'package:core/utils/app_logger.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
|
||||||
import 'package:model/extensions/email_address_extension.dart';
|
|
||||||
import 'package:model/mailbox/expand_mode.dart';
|
|
||||||
import 'package:super_tag_editor/tag_editor.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
|
|
||||||
import 'package:tmail_ui_user/features/base/widget/default_field/default_autocomplete_tag_item_widget.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/advanced_search_input_form_style.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/text_field_autocomplete_email_address_web_style.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/label_advanced_search_field_widget.dart';
|
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|
||||||
import 'package:tmail_ui_user/main/utils/app_config.dart';
|
|
||||||
|
|
||||||
typedef OnSuggestionEmailAddress = Future<List<EmailAddress>> Function(String word, {int? limit});
|
|
||||||
typedef OnUpdateListEmailAddressAction = void Function(FilterField field, List<EmailAddress> newData);
|
|
||||||
typedef OnDeleteEmailAddressTypeAction = void Function(FilterField field);
|
|
||||||
typedef OnShowFullListEmailAddressAction = void Function(FilterField field);
|
|
||||||
typedef OnDeleteTagAction = void Function(EmailAddress emailAddress);
|
|
||||||
|
|
||||||
class TextFieldAutocompleteEmailAddressWeb extends StatefulWidget {
|
|
||||||
|
|
||||||
final FilterField field;
|
|
||||||
final List<EmailAddress> listEmailAddress;
|
|
||||||
final ExpandMode expandMode;
|
|
||||||
final FocusNode? focusNode;
|
|
||||||
final GlobalKey? keyTagEditor;
|
|
||||||
final FocusNode? nextFocusNode;
|
|
||||||
final EdgeInsetsGeometry? padding;
|
|
||||||
final EdgeInsetsGeometry? margin;
|
|
||||||
final OnSuggestionEmailAddress? onSuggestionEmailAddress;
|
|
||||||
final OnDeleteTagAction? onDeleteTag;
|
|
||||||
final OnUpdateListEmailAddressAction? onUpdateListEmailAddressAction;
|
|
||||||
final OnDeleteEmailAddressTypeAction? onDeleteEmailAddressTypeAction;
|
|
||||||
final OnShowFullListEmailAddressAction? onShowFullListEmailAddressAction;
|
|
||||||
final OnRemoveDraggableEmailAddressAction? onRemoveDraggableEmailAddressAction;
|
|
||||||
final TextEditingController? controller;
|
|
||||||
final VoidCallback? onSearchAction;
|
|
||||||
final int minInputLengthAutocomplete;
|
|
||||||
|
|
||||||
const TextFieldAutocompleteEmailAddressWeb({
|
|
||||||
Key? key,
|
|
||||||
required this.field,
|
|
||||||
required this.listEmailAddress,
|
|
||||||
this.expandMode = ExpandMode.EXPAND,
|
|
||||||
this.minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete,
|
|
||||||
this.focusNode,
|
|
||||||
this.keyTagEditor,
|
|
||||||
this.nextFocusNode,
|
|
||||||
this.padding,
|
|
||||||
this.margin,
|
|
||||||
this.onSuggestionEmailAddress,
|
|
||||||
this.onDeleteTag,
|
|
||||||
this.onUpdateListEmailAddressAction,
|
|
||||||
this.onDeleteEmailAddressTypeAction,
|
|
||||||
this.onShowFullListEmailAddressAction,
|
|
||||||
this.onRemoveDraggableEmailAddressAction,
|
|
||||||
this.controller,
|
|
||||||
this.onSearchAction,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<TextFieldAutocompleteEmailAddressWeb> createState() => _TextFieldAutocompleteEmailAddressWebState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocompleteEmailAddressWeb> {
|
|
||||||
final _imagePaths = Get.find<ImagePaths>();
|
|
||||||
|
|
||||||
bool _lastTagFocused = false;
|
|
||||||
bool _isDragging = false;
|
|
||||||
late List<EmailAddress> _currentListEmailAddress;
|
|
||||||
Timer? _gapBetweenTagChangedAndFindSuggestion;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_currentListEmailAddress = widget.listEmailAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(covariant TextFieldAutocompleteEmailAddressWeb oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
if (widget.listEmailAddress != oldWidget.listEmailAddress) {
|
|
||||||
_currentListEmailAddress = widget.listEmailAddress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return LayoutBuilder(
|
|
||||||
builder: ((context, constraints) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: TextFieldAutoCompleteEmailAddressWebStyles.fieldTitleWidth,
|
|
||||||
child: LabelAdvancedSearchFieldWidget(
|
|
||||||
name: widget.field.getTitle(AppLocalizations.of(context)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: TextFieldAutoCompleteEmailAddressWebStyles.space),
|
|
||||||
Expanded(
|
|
||||||
child: StatefulBuilder(
|
|
||||||
builder: ((context, setState) {
|
|
||||||
return DragTarget<DraggableEmailAddress>(
|
|
||||||
onAcceptWithDetails: (draggableEmailAddress) =>
|
|
||||||
_handleAcceptDraggableEmailAddressAction(
|
|
||||||
draggableEmailAddress.data,
|
|
||||||
setState
|
|
||||||
),
|
|
||||||
onLeave: (draggableEmailAddress) {
|
|
||||||
if (_isDragging) {
|
|
||||||
setState(() => _isDragging = false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMove: (details) {
|
|
||||||
if (!_isDragging) {
|
|
||||||
setState(() => _isDragging = true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
builder: (_, __, ___) {
|
|
||||||
return TagEditor<SuggestionEmailAddress>(
|
|
||||||
key: widget.keyTagEditor,
|
|
||||||
length: _collapsedListEmailAddress.length,
|
|
||||||
controller: widget.controller,
|
|
||||||
focusNodeKeyboard: widget.focusNode,
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
textInputAction: TextInputAction.done,
|
|
||||||
cursorColor: TextFieldAutoCompleteEmailAddressWebStyles.cursorColor,
|
|
||||||
debounceDuration: TextFieldAutoCompleteEmailAddressWebStyles.debounceDuration,
|
|
||||||
inputDecoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxHeight:
|
|
||||||
AdvancedSearchInputFormStyle.inputFieldHeight,
|
|
||||||
),
|
|
||||||
fillColor: TextFieldAutoCompleteEmailAddressWebStyles.textInputFillColor,
|
|
||||||
border: TextFieldAutoCompleteEmailAddressWebStyles.textInputBorder,
|
|
||||||
hintText: widget.field.getHintText(AppLocalizations.of(context)),
|
|
||||||
hintStyle: TextFieldAutoCompleteEmailAddressWebStyles.textInputHintStyle,
|
|
||||||
isDense: true,
|
|
||||||
contentPadding: _currentListEmailAddress.isNotEmpty
|
|
||||||
? TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPaddingWithSomeTag
|
|
||||||
: TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPadding
|
|
||||||
),
|
|
||||||
padding: _currentListEmailAddress.isNotEmpty
|
|
||||||
? TextFieldAutoCompleteEmailAddressWebStyles.tagEditorPadding
|
|
||||||
: EdgeInsets.zero,
|
|
||||||
borderRadius: AdvancedSearchInputFormStyle.inputFieldBorderRadius,
|
|
||||||
borderSize: AdvancedSearchInputFormStyle.inputFieldBorderWidth,
|
|
||||||
focusedBorderColor: TextFieldAutoCompleteEmailAddressWebStyles.focusedBorderColor,
|
|
||||||
enableBorder: true,
|
|
||||||
enableBorderColor: _isDragging
|
|
||||||
? AppColor.primaryColor
|
|
||||||
: AdvancedSearchInputFormStyle.inputFieldBorderColor,
|
|
||||||
minTextFieldWidth: TextFieldAutoCompleteEmailAddressWebStyles.minTextFieldWidth,
|
|
||||||
resetTextOnSubmitted: true,
|
|
||||||
autoScrollToInput: false,
|
|
||||||
suggestionsBoxElevation: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxElevation,
|
|
||||||
suggestionsBoxBackgroundColor: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxBackgroundColor,
|
|
||||||
suggestionsBoxRadius: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxRadius,
|
|
||||||
suggestionsBoxMaxHeight: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxMaxHeight,
|
|
||||||
suggestionItemHeight: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxItemHeight,
|
|
||||||
suggestionBoxWidth: _getSuggestionBoxWidth(constraints.maxWidth),
|
|
||||||
textStyle: AdvancedSearchInputFormStyle.inputTextStyle,
|
|
||||||
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, setState),
|
|
||||||
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(setState),
|
|
||||||
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, setState),
|
|
||||||
onSubmitted: (value) => _handleSubmitTagAction.call(value, setState),
|
|
||||||
tagBuilder: (context, index) {
|
|
||||||
final currentEmailAddress = _currentListEmailAddress.elementAt(index);
|
|
||||||
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
|
||||||
return DefaultAutocompleteTagItemWidget(
|
|
||||||
field: widget.field,
|
|
||||||
currentEmailAddress: currentEmailAddress,
|
|
||||||
currentListEmailAddress: _currentListEmailAddress,
|
|
||||||
collapsedListEmailAddress: _collapsedListEmailAddress,
|
|
||||||
isLatestEmail: isLatestEmail,
|
|
||||||
isCollapsed: _isCollapse,
|
|
||||||
isLatestTagFocused: _lastTagFocused,
|
|
||||||
iconClose: _imagePaths.icClose,
|
|
||||||
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, setState),
|
|
||||||
onShowFullAction: widget.onShowFullListEmailAddressAction,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onTagChanged: (tag) => _handleOnTagChangeAction.call(tag, setState),
|
|
||||||
findSuggestions: (queryString) => _findSuggestions(
|
|
||||||
queryString,
|
|
||||||
limit: AppConfig.defaultLimitAutocomplete,
|
|
||||||
),
|
|
||||||
isLoadMoreOnlyOnce: true,
|
|
||||||
isLoadMoreReplaceAllOld: false,
|
|
||||||
loadMoreSuggestions: _findSuggestions,
|
|
||||||
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
|
|
||||||
return RecipientSuggestionItemWidget(
|
|
||||||
imagePaths: _imagePaths,
|
|
||||||
suggestionState: suggestionEmailAddress.state,
|
|
||||||
emailAddress: suggestionEmailAddress.emailAddress,
|
|
||||||
suggestionValid: suggestionValid,
|
|
||||||
highlight: highlight,
|
|
||||||
onSelectedAction: (emailAddress) {
|
|
||||||
setState(() => _currentListEmailAddress.add(emailAddress));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
tagEditorState.resetTextField();
|
|
||||||
tagEditorState.closeSuggestionBox();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onHandleKeyEventAction: (event) {
|
|
||||||
if (event is KeyDownEvent) {
|
|
||||||
switch (event.logicalKey) {
|
|
||||||
case LogicalKeyboardKey.tab:
|
|
||||||
widget.nextFocusNode?.requestFocus();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get _isCollapse => _currentListEmailAddress.length > 1 && widget.expandMode == ExpandMode.COLLAPSE;
|
|
||||||
|
|
||||||
List<EmailAddress> get _collapsedListEmailAddress => _isCollapse
|
|
||||||
? _currentListEmailAddress.sublist(0, 1)
|
|
||||||
: _currentListEmailAddress;
|
|
||||||
|
|
||||||
FutureOr<List<SuggestionEmailAddress>> _findSuggestions(String query, {int? limit}) async {
|
|
||||||
if (_gapBetweenTagChangedAndFindSuggestion?.isActive ?? false) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
final processedQuery = query.trim();
|
|
||||||
if (processedQuery.isEmpty) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
final tmailSuggestion = List<SuggestionEmailAddress>.empty(growable: true);
|
|
||||||
if (processedQuery.length >= widget.minInputLengthAutocomplete &&
|
|
||||||
widget.onSuggestionEmailAddress != null) {
|
|
||||||
final listEmailAddress = await widget.onSuggestionEmailAddress!(
|
|
||||||
processedQuery,
|
|
||||||
limit: limit,
|
|
||||||
);
|
|
||||||
final listSuggestionEmailAddress = listEmailAddress.map((emailAddress) => _toSuggestionEmailAddress(emailAddress, _currentListEmailAddress));
|
|
||||||
tmailSuggestion.addAll(listSuggestionEmailAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmailSuggestion.addAll(_matchedSuggestionEmailAddress(processedQuery, _currentListEmailAddress));
|
|
||||||
|
|
||||||
final currentTextOnTextField = widget.controller?.text ?? '';
|
|
||||||
if (currentTextOnTextField.isEmpty) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmailSuggestion.toSet().toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isDuplicated(String inputEmail) {
|
|
||||||
if (inputEmail.isEmpty) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _currentListEmailAddress
|
|
||||||
.map((emailAddress) => emailAddress.email)
|
|
||||||
.whereNotNull()
|
|
||||||
.contains(inputEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
SuggestionEmailAddress _toSuggestionEmailAddress(EmailAddress item, List<EmailAddress> addedEmailAddresses) {
|
|
||||||
if (addedEmailAddresses.contains(item)) {
|
|
||||||
return SuggestionEmailAddress(item, state: SuggestionEmailState.duplicated);
|
|
||||||
} else {
|
|
||||||
return SuggestionEmailAddress(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterable<SuggestionEmailAddress> _matchedSuggestionEmailAddress(String query, List<EmailAddress> addedEmailAddress) {
|
|
||||||
return addedEmailAddress
|
|
||||||
.where((addedMail) => addedMail.emailAddress.contains(query))
|
|
||||||
.map((emailAddress) => SuggestionEmailAddress(
|
|
||||||
emailAddress,
|
|
||||||
state: SuggestionEmailState.duplicated
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleGapBetweenTagChangedAndFindSuggestion() {
|
|
||||||
log('_TextFieldAutocompleteEmailAddressWebState::_handleGapBetweenTagChangedAndFindSuggestion:Timeout');
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateListEmailAddressAction() {
|
|
||||||
widget.onUpdateListEmailAddressAction?.call(
|
|
||||||
widget.field,
|
|
||||||
_currentListEmailAddress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleFocusTagAction(bool focused, StateSetter stateSetter) {
|
|
||||||
if (mounted) {
|
|
||||||
stateSetter(() => _lastTagFocused = focused);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleDeleteLatestTagAction(StateSetter stateSetter) {
|
|
||||||
if (_currentListEmailAddress.isNotEmpty) {
|
|
||||||
stateSetter(_currentListEmailAddress.removeLast);
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleDeleteTagAction(EmailAddress emailAddress, StateSetter stateSetter) {
|
|
||||||
if (_currentListEmailAddress.isNotEmpty) {
|
|
||||||
stateSetter(() => _currentListEmailAddress.remove(emailAddress));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleSelectOptionAction(
|
|
||||||
SuggestionEmailAddress suggestionEmailAddress,
|
|
||||||
StateSetter stateSetter
|
|
||||||
) {
|
|
||||||
if (!_isDuplicated(suggestionEmailAddress.emailAddress.emailAddress)) {
|
|
||||||
stateSetter(() => _currentListEmailAddress.add(suggestionEmailAddress.emailAddress));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleSubmitTagAction(
|
|
||||||
String value,
|
|
||||||
StateSetter stateSetter
|
|
||||||
) {
|
|
||||||
final textTrim = value.trim();
|
|
||||||
if (textTrim.isEmpty) {
|
|
||||||
widget.onSearchAction?.call();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_isDuplicated(textTrim)) {
|
|
||||||
stateSetter(() => _currentListEmailAddress.add(EmailAddress(null, textTrim)));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleOnTagChangeAction(
|
|
||||||
String value,
|
|
||||||
StateSetter stateSetter
|
|
||||||
) {
|
|
||||||
final textTrim = value.trim();
|
|
||||||
if (!_isDuplicated(textTrim)) {
|
|
||||||
stateSetter(() => _currentListEmailAddress.add(EmailAddress(null, textTrim)));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
}
|
|
||||||
_gapBetweenTagChangedAndFindSuggestion = Timer(
|
|
||||||
const Duration(seconds: 1),
|
|
||||||
_handleGapBetweenTagChangedAndFindSuggestion
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
double? _getSuggestionBoxWidth(double maxWidth) {
|
|
||||||
if (maxWidth < ResponsiveUtils.minTabletWidth) {
|
|
||||||
final newWidth = min(maxWidth, 300.0);
|
|
||||||
return newWidth;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleAcceptDraggableEmailAddressAction(
|
|
||||||
DraggableEmailAddress draggableEmailAddress,
|
|
||||||
StateSetter stateSetter
|
|
||||||
) {
|
|
||||||
log('_TextFieldAutocompleteEmailAddressWebState::_handleAcceptDraggableEmailAddressAction:draggableEmailAddress = $draggableEmailAddress');
|
|
||||||
if (draggableEmailAddress.filterField != widget.field) {
|
|
||||||
if (!_currentListEmailAddress.contains(draggableEmailAddress.emailAddress)) {
|
|
||||||
stateSetter(() {
|
|
||||||
_currentListEmailAddress.add(draggableEmailAddress.emailAddress);
|
|
||||||
_isDragging = false;
|
|
||||||
});
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
} else if (_isDragging) {
|
|
||||||
stateSetter(() => _isDragging = false);
|
|
||||||
}
|
|
||||||
widget.onRemoveDraggableEmailAddressAction?.call(draggableEmailAddress);
|
|
||||||
} else if (_isDragging) {
|
|
||||||
stateSetter(() => _isDragging = false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-1
@@ -215,7 +215,6 @@ void main() {
|
|||||||
expect(advancedFilterController.notKeyWordFilterInputController.text, equals('hello,nice'));
|
expect(advancedFilterController.notKeyWordFilterInputController.text, equals('hello,nice'));
|
||||||
expect(advancedFilterController.receiveTimeType.value, equals(EmailReceiveTimeType.last7Days));
|
expect(advancedFilterController.receiveTimeType.value, equals(EmailReceiveTimeType.last7Days));
|
||||||
expect(advancedFilterController.sortOrderType.value, equals(EmailSortOrderType.oldest));
|
expect(advancedFilterController.sortOrderType.value, equals(EmailSortOrderType.oldest));
|
||||||
expect(advancedFilterController.mailBoxFilterInputController.text, equals('mailbox1'));
|
|
||||||
expect(advancedFilterController.hasAttachment.value, equals(true));
|
expect(advancedFilterController.hasAttachment.value, equals(true));
|
||||||
expect(advancedFilterController.listFromEmailAddress, equals([EmailAddress(null, 'user1@example.com')]));
|
expect(advancedFilterController.listFromEmailAddress, equals([EmailAddress(null, 'user1@example.com')]));
|
||||||
expect(advancedFilterController.listToEmailAddress, equals([EmailAddress(null, 'user2@example.com')]));
|
expect(advancedFilterController.listToEmailAddress, equals([EmailAddress(null, 'user2@example.com')]));
|
||||||
|
|||||||
Reference in New Issue
Block a user