diff --git a/contact/lib/data/network/contact_api.dart b/contact/lib/data/network/contact_api.dart index 20ae202316..496b6066e3 100644 --- a/contact/lib/data/network/contact_api.dart +++ b/contact/lib/data/network/contact_api.dart @@ -22,7 +22,9 @@ class ContactAPI { autoCompletePattern.accountId!, ContactFilter(autoCompletePattern.word)); - autoCompleteMethod.addLimit(UnsignedInt(autoCompletePattern.limit ?? 5)); + if (autoCompletePattern.limit != null) { + autoCompleteMethod.addLimit(UnsignedInt(autoCompletePattern.limit!)); + } final autoCompleteInvocation = requestBuilder.invocation(autoCompleteMethod); final response = await (requestBuilder diff --git a/core/lib/presentation/views/text/rich_text_builder.dart b/core/lib/presentation/views/text/rich_text_builder.dart index efd4518c6e..8bab7a763e 100644 --- a/core/lib/presentation/views/text/rich_text_builder.dart +++ b/core/lib/presentation/views/text/rich_text_builder.dart @@ -8,7 +8,6 @@ class RichTextBuilder extends StatefulWidget { final TextStyle styleWord; final String? preMarkedText; final bool ensureHighlightVisible; - final bool? softWrap; const RichTextBuilder({ super.key, @@ -18,7 +17,6 @@ class RichTextBuilder extends StatefulWidget { required this.styleWord, this.preMarkedText, this.ensureHighlightVisible = false, - this.softWrap, }); @override @@ -65,7 +63,6 @@ class _RichTextBuilderState extends State with AutomaticKeepAli ), style: widget.styleOrigin, maxLines: 1, - softWrap: widget.softWrap, overflow: TextOverflow.ellipsis ); diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 3978f4e830..61501fa14d 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -1110,14 +1110,15 @@ class ComposerController extends BaseController } } - Future> getAutoCompleteSuggestion(String queryString) async { - log('ComposerController::getAutoCompleteSuggestion(): $queryString | $_contactSuggestionSource'); + Future> getAutoCompleteSuggestion(String queryString, {int? limit}) async { + log('ComposerController::getAutoCompleteSuggestion():queryString = $queryString | limit = $limit | $_contactSuggestionSource'); _getAllAutoCompleteInteractor = getBinding(); _getAutoCompleteInteractor = getBinding(); _getDeviceContactSuggestionsInteractor = getBinding(); final autoCompletePattern = AutoCompletePattern( word: queryString, + limit: limit, accountId: mailboxDashBoardController.accountId.value); if (_contactSuggestionSource == ContactSuggestionSource.all) { diff --git a/lib/features/composer/presentation/styles/composer_style.dart b/lib/features/composer/presentation/styles/composer_style.dart index 26bf5e3e15..17f1e82853 100644 --- a/lib/features/composer/presentation/styles/composer_style.dart +++ b/lib/features/composer/presentation/styles/composer_style.dart @@ -8,6 +8,7 @@ class ComposerStyle { static const double radius = 28; static const double keyboardToolBarHeight = 200; static const double popupMenuRadius = 8; + static const double suggestionItemHeight = 60; static const Color borderColor = AppColor.colorLineComposer; static const Color backgroundEditorColor = Colors.white; diff --git a/lib/features/composer/presentation/styles/recipient_composer_widget_style.dart b/lib/features/composer/presentation/styles/recipient_composer_widget_style.dart index 359c864ce8..208d9d5ca2 100644 --- a/lib/features/composer/presentation/styles/recipient_composer_widget_style.dart +++ b/lib/features/composer/presentation/styles/recipient_composer_widget_style.dart @@ -1,6 +1,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; class RecipientComposerWidgetStyle { static const double deleteRecipientFieldIconSize = 20; @@ -8,8 +9,9 @@ class RecipientComposerWidgetStyle { static const double enableBorderRadius = 10; static const double suggestionsBoxElevation = 20.0; static const double suggestionsBoxRadius = 20; - static const double suggestionsBoxMaxHeight = 350; + static const double suggestionsBoxMaxHeight = 300; static const double suggestionBoxWidth = 300; + static const double suggestionBoxItemHeight = ComposerStyle.suggestionItemHeight; static const double minTextFieldWidth = 20; static const double tagSpacing = 8; diff --git a/lib/features/composer/presentation/styles/recipient_suggestion_item_widget_style.dart b/lib/features/composer/presentation/styles/recipient_suggestion_item_widget_style.dart index 2e43758649..ddab22a1c4 100644 --- a/lib/features/composer/presentation/styles/recipient_suggestion_item_widget_style.dart +++ b/lib/features/composer/presentation/styles/recipient_suggestion_item_widget_style.dart @@ -6,7 +6,6 @@ class RecipientSuggestionItemWidgetStyle { static const double selectedIconSize = 24; static const EdgeInsetsGeometry suggestionDuplicatedMargin = EdgeInsets.all(8.0); - static const EdgeInsetsGeometry labelDuplicatedPadding = EdgeInsets.symmetric(horizontal: 8.0); static const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric(horizontal: 16.0); static const TextStyle labelTextStyle = TextStyle( diff --git a/lib/features/composer/presentation/widgets/recipient_composer_widget.dart b/lib/features/composer/presentation/widgets/recipient_composer_widget.dart index e9fdb70736..b2c3ce6a52 100644 --- a/lib/features/composer/presentation/widgets/recipient_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/recipient_composer_widget.dart @@ -27,7 +27,7 @@ import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_t import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; -typedef OnSuggestionEmailAddress = Future> Function(String word); +typedef OnSuggestionEmailAddress = Future> Function(String word, {int? limit}); typedef OnUpdateListEmailAddressAction = void Function(PrefixEmailAddress prefix, List newData); typedef OnAddEmailAddressTypeAction = void Function(PrefixEmailAddress prefix); typedef OnDeleteEmailAddressTypeAction = void Function(PrefixEmailAddress prefix); @@ -180,6 +180,7 @@ class _RecipientComposerWidgetState extends State { suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor, suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius, suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight, + suggestionItemHeight: RecipientComposerWidgetStyle.suggestionBoxItemHeight, suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth), textStyle: RecipientComposerWidgetStyle.inputTextStyle, onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter), @@ -213,7 +214,13 @@ class _RecipientComposerWidgetState extends State { ); }, onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter), - findSuggestions: _findSuggestions, + findSuggestions: (queryString) => _findSuggestions( + queryString, + limit: AppConfig.defaultLimitAutocomplete, + ), + isLoadMoreOnlyOnce: true, + isLoadMoreReplaceAllOld: false, + loadMoreSuggestions: _findSuggestions, useDefaultHighlight: false, suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) { return RecipientSuggestionItemWidget( @@ -264,6 +271,7 @@ class _RecipientComposerWidgetState extends State { suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor, suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius, suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight, + suggestionItemHeight: RecipientComposerWidgetStyle.suggestionBoxItemHeight, suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth), textStyle: RecipientComposerWidgetStyle.inputTextStyle, onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter), @@ -297,7 +305,13 @@ class _RecipientComposerWidgetState extends State { ); }, onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter), - findSuggestions: _findSuggestions, + findSuggestions: (queryString) => _findSuggestions( + queryString, + limit: AppConfig.defaultLimitAutocomplete, + ), + isLoadMoreOnlyOnce: true, + isLoadMoreReplaceAllOld: false, + loadMoreSuggestions: _findSuggestions, useDefaultHighlight: false, suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) { return RecipientSuggestionItemWidget( @@ -402,7 +416,7 @@ class _RecipientComposerWidgetState extends State { ? _currentListEmailAddress.sublist(0, 1) : _currentListEmailAddress; - FutureOr> _findSuggestions(String query) async { + FutureOr> _findSuggestions(String query, {int? limit}) async { if (_gapBetweenTagChangedAndFindSuggestion?.isActive ?? false) { return []; } @@ -415,7 +429,10 @@ class _RecipientComposerWidgetState extends State { final tmailSuggestion = List.empty(growable: true); if (processedQuery.length >= widget.minInputLengthAutocomplete && widget.onSuggestionEmailAddress != null) { - final listEmailAddress = await widget.onSuggestionEmailAddress!(processedQuery); + final listEmailAddress = await widget.onSuggestionEmailAddress!( + processedQuery, + limit: limit, + ); final listSuggestionEmailAddress = listEmailAddress .map((emailAddress) => _toSuggestionEmailAddress( emailAddress, diff --git a/lib/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart b/lib/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart index 29dc018b0d..a03a90f46e 100644 --- a/lib/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart +++ b/lib/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart @@ -1,12 +1,14 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/text/rich_text_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:super_tag_editor/widgets/rich_text_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/recipient_suggestion_item_widget_style.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/avatar_suggestion_item_widget.dart'; @@ -38,59 +40,91 @@ class RecipientSuggestionItemWidget extends StatelessWidget { margin: RecipientSuggestionItemWidgetStyle.suggestionDuplicatedMargin, decoration: const BoxDecoration( color: AppColor.colorBgMenuItemDropDownSelected, - borderRadius: BorderRadius.all(Radius.circular(RecipientSuggestionItemWidgetStyle.radius)) + borderRadius: BorderRadius.all(Radius.circular(RecipientSuggestionItemWidgetStyle.radius)), ), + height: ComposerStyle.suggestionItemHeight, child: Material( type: MaterialType.transparency, - child: ListTile( - contentPadding: RecipientSuggestionItemWidgetStyle.labelDuplicatedPadding, - leading: AvatarSuggestionItemWidget(emailAddress: emailAddress), - title: RichTextWidget( - textOrigin: emailAddress.asString(), - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - ), - subtitle: emailAddress.displayName.isNotEmpty - ? RichTextWidget( - textOrigin: emailAddress.emailAddress, - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - styleTextOrigin: RecipientSuggestionItemWidgetStyle.labelTextStyle, - styleWordSearched: RecipientSuggestionItemWidgetStyle.labelHighlightTextStyle - ) - : null, - trailing: SvgPicture.asset( - imagePaths.icFilterSelected, - width: RecipientSuggestionItemWidgetStyle.selectedIconSize, - height: RecipientSuggestionItemWidgetStyle.selectedIconSize, - fit: BoxFit.fill + child: InkWell( + onTap: () {}, + child: Padding( + padding: RecipientSuggestionItemWidgetStyle.labelPadding, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AvatarSuggestionItemWidget(emailAddress: emailAddress), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RichTextWidget( + textOrigin: emailAddress.asString(), + wordSearched: suggestionValid ?? '', + overflow: TextOverflow.ellipsis, + ), + if (emailAddress.displayName.isNotEmpty) + RichTextBuilder( + textOrigin: emailAddress.emailAddress, + wordToStyle: suggestionValid ?? '', + styleOrigin: RecipientSuggestionItemWidgetStyle.labelTextStyle, + styleWord: RecipientSuggestionItemWidgetStyle.labelHighlightTextStyle, + ), + ], + ), + ), + const SizedBox(width: 8), + SvgPicture.asset( + imagePaths.icFilterSelected, + width: RecipientSuggestionItemWidgetStyle.selectedIconSize, + height: RecipientSuggestionItemWidgetStyle.selectedIconSize, + fit: BoxFit.fill, + ), + ], + ), ), ), - ) + ), ); } else { return Container( color: highlight ? AppColor.colorItemSelected : Colors.white, + height: ComposerStyle.suggestionItemHeight, child: Material( type: MaterialType.transparency, - child: ListTile( - contentPadding: RecipientSuggestionItemWidgetStyle.labelPadding, - leading: AvatarSuggestionItemWidget(emailAddress: emailAddress), - title: RichTextWidget( - textOrigin: emailAddress.asString(), - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - ), - subtitle: emailAddress.displayName.isNotEmpty - ? RichTextWidget( - textOrigin: emailAddress.emailAddress, - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - styleTextOrigin: RecipientSuggestionItemWidgetStyle.labelTextStyle, - styleWordSearched: RecipientSuggestionItemWidgetStyle.labelHighlightTextStyle - ) - : null, + child: InkWell( onTap: () => onSelectedAction?.call(emailAddress), + child: Padding( + padding: RecipientSuggestionItemWidgetStyle.labelPadding, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AvatarSuggestionItemWidget(emailAddress: emailAddress), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RichTextWidget( + textOrigin: emailAddress.asString(), + wordSearched: suggestionValid ?? '', + overflow: TextOverflow.ellipsis, + ), + if (emailAddress.displayName.isNotEmpty) + RichTextBuilder( + textOrigin: emailAddress.emailAddress, + wordToStyle: suggestionValid ?? '', + styleOrigin: RecipientSuggestionItemWidgetStyle.labelTextStyle, + styleWord: RecipientSuggestionItemWidgetStyle.labelHighlightTextStyle, + ), + ], + ), + ), + ], + ), + ), ), ), ); diff --git a/lib/features/contact/presentation/contact_controller.dart b/lib/features/contact/presentation/contact_controller.dart index 1fe3cef38e..a91c065500 100644 --- a/lib/features/contact/presentation/contact_controller.dart +++ b/lib/features/contact/presentation/contact_controller.dart @@ -163,7 +163,6 @@ class ContactController extends BaseController with AutoCompleteResultMixin { final autoCompletePattern = AutoCompletePattern( word: queryString, - limit: 30, accountId: _accountId); if (_contactSuggestionSource == ContactSuggestionSource.all) { diff --git a/lib/features/contact/presentation/widgets/contact_suggestion_box_item.dart b/lib/features/contact/presentation/widgets/contact_suggestion_box_item.dart index 4d94c1ad69..01dd6b32c2 100644 --- a/lib/features/contact/presentation/widgets/contact_suggestion_box_item.dart +++ b/lib/features/contact/presentation/widgets/contact_suggestion_box_item.dart @@ -5,31 +5,32 @@ import 'package:core/presentation/utils/style_utils.dart'; import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.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:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; typedef SelectedContactCallbackAction = Function(EmailAddress contactSelected); class ContactSuggestionBoxItem extends StatelessWidget { + final ImagePaths imagePaths; final SuggestionEmailAddress suggestionEmailAddress; final SelectedContactCallbackAction? selectedContactCallbackAction; - final EdgeInsets? padding; final ShapeBorder? shapeBorder; - const ContactSuggestionBoxItem(this.suggestionEmailAddress, { - Key? key, - this.padding, - this.shapeBorder, - this.selectedContactCallbackAction - }) : super(key: key); + const ContactSuggestionBoxItem( + this.suggestionEmailAddress, + this.imagePaths, + { + Key? key, + this.shapeBorder, + this.selectedContactCallbackAction, + } + ) : super(key: key); @override Widget build(BuildContext context) { - final imagePaths = Get.find(); - final itemChild = Row(children: [ GradientCircleAvatarIcon( colors: suggestionEmailAddress.emailAddress.avatarColors, @@ -82,8 +83,9 @@ class ContactSuggestionBoxItem extends StatelessWidget { child: InkWell( onTap: () => selectedContactCallbackAction?.call(suggestionEmailAddress.emailAddress), customBorder: shapeBorder, - child: Padding( - padding: padding ?? const EdgeInsets.all(12), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12), + height: ComposerStyle.suggestionItemHeight, child: itemChild, ), ), @@ -91,8 +93,9 @@ class ContactSuggestionBoxItem extends StatelessWidget { } else { return Material( color: Colors.transparent, - child: Padding( - padding: padding ?? const EdgeInsets.all(12), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12), + height: ComposerStyle.suggestionItemHeight, child: itemChild, ), ); diff --git a/lib/features/email_recovery/presentation/email_recovery_controller.dart b/lib/features/email_recovery/presentation/email_recovery_controller.dart index d48991ddb2..61da363e47 100644 --- a/lib/features/email_recovery/presentation/email_recovery_controller.dart +++ b/lib/features/email_recovery/presentation/email_recovery_controller.dart @@ -229,16 +229,22 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { hasAttachment.value = value ?? false; } - Future> getAutoCompleteSuggestion(String word) async { + Future> getAutoCompleteSuggestion(String word, {int? limit}) async { log('EmailRecoveryController::getAutoCompleteSuggestion(): $word | $_contactSuggestionSource'); _getAllAutoCompleteInteractor = getBinding(); _getAutoCompleteInteractor = getBinding(); _getDeviceContactSuggestionsInteractor = getBinding(); + final autoCompletePattern = AutoCompletePattern( + word: word, + limit: limit, + accountId: _accountId + ); + if (_contactSuggestionSource == ContactSuggestionSource.all) { if (_getAllAutoCompleteInteractor != null) { return await _getAllAutoCompleteInteractor! - .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .execute(autoCompletePattern) .then((value) => value.fold( (failure) => [], (success) => success is GetAutoCompleteSuccess @@ -247,7 +253,7 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { )); } else if (_getDeviceContactSuggestionsInteractor != null) { return await _getDeviceContactSuggestionsInteractor! - .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .execute(autoCompletePattern) .then((value) => value.fold( (failure) => [], (success) => success is GetDeviceContactSuggestionsSuccess @@ -262,7 +268,7 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { return []; } else { return await _getAutoCompleteInteractor! - .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .execute(autoCompletePattern) .then((value) => value.fold( (failure) => [], (success) => success is GetAutoCompleteSuccess diff --git a/lib/features/email_recovery/presentation/styles/text_input_field/suggestion_item_widget_styles.dart b/lib/features/email_recovery/presentation/styles/text_input_field/suggestion_item_widget_styles.dart index 3997643758..c5e2b6d335 100644 --- a/lib/features/email_recovery/presentation/styles/text_input_field/suggestion_item_widget_styles.dart +++ b/lib/features/email_recovery/presentation/styles/text_input_field/suggestion_item_widget_styles.dart @@ -1,8 +1,10 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; class SuggestionItemWidgetStyles { static const double iconSelectedSize = 24.0; + static const double suggestionItemHeight = ComposerStyle.suggestionItemHeight; static const EdgeInsetsGeometry margin = EdgeInsets.all(8.0); static const EdgeInsetsGeometry contentPaddingDuplicated = EdgeInsets.symmetric( diff --git a/lib/features/email_recovery/presentation/styles/text_input_field/text_input_suggestion_field_widget_styles.dart b/lib/features/email_recovery/presentation/styles/text_input_field/text_input_suggestion_field_widget_styles.dart index 09ae82c7b6..ef86e8ed7e 100644 --- a/lib/features/email_recovery/presentation/styles/text_input_field/text_input_suggestion_field_widget_styles.dart +++ b/lib/features/email_recovery/presentation/styles/text_input_field/text_input_suggestion_field_widget_styles.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; class TextInputSuggestionFieldWidgetStyles { static const double titleWidth = 112.0; @@ -8,6 +9,7 @@ class TextInputSuggestionFieldWidgetStyles { static const double suggestionsBoxElevation = 20.0; static const double suggestionsBoxRadius = 20.0; static const double suggestionsBoxMaxHeight = 350.0; + static const double suggestionBoxItemHeight = ComposerStyle.suggestionItemHeight; static const double space = 12.0; static const double spaceMobile = 8.0; diff --git a/lib/features/email_recovery/presentation/widgets/text_input_field/suggestion_item_widget.dart b/lib/features/email_recovery/presentation/widgets/text_input_field/suggestion_item_widget.dart deleted file mode 100644 index a46c20dd5b..0000000000 --- a/lib/features/email_recovery/presentation/widgets/text_input_field/suggestion_item_widget.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:core/presentation/resources/image_paths.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:get/get.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; -import 'package:model/model.dart'; -import 'package:super_tag_editor/widgets/rich_text_widget.dart'; -import 'package:tmail_ui_user/features/email_recovery/presentation/styles/text_input_field/suggestion_item_widget_styles.dart'; -import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/avatar_suggestion_item_widget.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart'; - -typedef OnSelectedRecipientSuggestionAction = void Function(EmailAddress emailAddress); - -class SuggestionItemWidget extends StatelessWidget { - final SuggestionEmailState suggestionState; - final EmailAddress emailAddress; - final String? suggestionValid; - final bool highlight; - final OnSelectedRecipientSuggestionAction? onSelectedAction; - - final _imagePaths = Get.find(); - - SuggestionItemWidget({ - super.key, - required this.suggestionState, - required this.emailAddress, - this.highlight = false, - this.suggestionValid, - this.onSelectedAction, - }); - - @override - Widget build(BuildContext context) { - if (suggestionState == SuggestionEmailState.duplicated) { - return Container( - margin: SuggestionItemWidgetStyles.margin, - decoration: SuggestionItemWidgetStyles.decoration, - child: Material( - type: MaterialType.transparency, - child: ListTile( - contentPadding: SuggestionItemWidgetStyles.contentPaddingDuplicated, - leading: AvatarSuggestionItemWidget(emailAddress: emailAddress), - title: RichTextWidget( - textOrigin: emailAddress.asString(), - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - ), - subtitle: emailAddress.displayName.isNotEmpty - ? RichTextWidget( - textOrigin: emailAddress.emailAddress, - wordSearched: suggestionValid ?? '', - styleTextOrigin: SuggestionItemWidgetStyles.subTitleTextOriginStyle, - styleWordSearched: SuggestionItemWidgetStyles.subTitleWordSearchedStyle, - overflow: TextOverflow.ellipsis, - ) - : null, - trailing: SvgPicture.asset( - _imagePaths.icFilterSelected, - width: SuggestionItemWidgetStyles.iconSelectedSize, - height: SuggestionItemWidgetStyles.iconSelectedSize, - fit: BoxFit.fill, - ), - ), - ), - ); - } else { - return Container( - color: highlight ? AppColor.colorItemSelected : Colors.white, - child: Material( - type: MaterialType.transparency, - child: ListTile( - contentPadding: SuggestionItemWidgetStyles.contentPaddingValid, - leading: AvatarSuggestionItemWidget(emailAddress: emailAddress), - title: RichTextWidget( - textOrigin: emailAddress.asString(), - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - ), - subtitle: emailAddress.displayName.isNotEmpty - ? RichTextWidget( - textOrigin: emailAddress.emailAddress, - wordSearched: suggestionValid ?? '', - styleTextOrigin: SuggestionItemWidgetStyles.subTitleTextOriginStyle, - styleWordSearched: SuggestionItemWidgetStyles.subTitleWordSearchedStyle, - overflow: TextOverflow.ellipsis, - ) - : null, - onTap: () => onSelectedAction?.call(emailAddress), - ), - ), - ); - } - } -} \ No newline at end of file diff --git a/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart b/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart index 60e4fd33ab..315b2b016a 100644 --- a/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart +++ b/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart @@ -1,23 +1,25 @@ import 'dart:async'; import 'dart:math'; +import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/utils/app_logger.dart'; import 'package:collection/collection.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/responsive_utils.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/mailbox/expand_mode.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:super_tag_editor/tag_editor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_field.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/styles/text_input_field/text_input_suggestion_field_widget_styles.dart'; -import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/suggestion_item_widget.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/suggestion_tag_item_widget.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; -typedef OnSuggestionEmailAddress = Future> Function(String word); +typedef OnSuggestionEmailAddress = Future> Function(String word, {int? limit}); typedef OnUpdateListEmailAddressAction = void Function(EmailRecoveryField field, List newDate); typedef OnDeleteEmailAddressTypeAction = void Function(EmailRecoveryField field, EmailAddress emailAddress); typedef OnShowFullListEmailAddressAction = void Function(EmailRecoveryField field); @@ -68,6 +70,8 @@ class TextInputFieldSuggestionWidget extends StatefulWidget { } class _TextInputFieldSuggestionWidgetState extends State { + final _imagePaths = Get.find(); + bool _lastTagFocused = false; late List _currentListEmailAddress; Timer? _gapBetweenTagChangedAndFindSuggestion; @@ -138,6 +142,7 @@ class _TextInputFieldSuggestionWidgetState extends State _handleFocusTagAction.call(focused, setState), @@ -160,9 +165,16 @@ class _TextInputFieldSuggestionWidgetState extends State _handleOnTagChangeAction.call(tag, setState), - findSuggestions: _findSuggestions, + findSuggestions: (queryString) => _findSuggestions( + queryString, + limit: AppConfig.defaultLimitAutocomplete, + ), + isLoadMoreOnlyOnce: true, + isLoadMoreReplaceAllOld: false, + loadMoreSuggestions: _findSuggestions, suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) { - return SuggestionItemWidget( + return RecipientSuggestionItemWidget( + imagePaths: _imagePaths, suggestionState: suggestionEmailAddress.state, emailAddress: suggestionEmailAddress.emailAddress, suggestionValid: suggestionValid, @@ -315,7 +327,7 @@ class _TextInputFieldSuggestionWidgetState extends State> _findSuggestions(String query) async { + FutureOr> _findSuggestions(String query, {int? limit}) async { if (_gapBetweenTagChangedAndFindSuggestion?.isActive ?? false) { return []; } @@ -330,7 +342,10 @@ class _TextInputFieldSuggestionWidgetState extends State= widget.minInputLengthAutocomplete && widget.onSuggestionEmailAddress != null ) { - final listEmailAddress = await widget.onSuggestionEmailAddress!(processedQuery); + final listEmailAddress = await widget.onSuggestionEmailAddress!( + processedQuery, + limit: limit, + ); log('_TextFieldAutocompleteEmailAddressWebState::_findSuggestions: listEmailAddress: $listEmailAddress'); final listSuggestionEmailAddress = listEmailAddress.map((emailAddress) => _toSuggestionEmailAddress(emailAddress, _currentListEmailAddress)); tmailSuggestion.addAll(listSuggestionEmailAddress); diff --git a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart index 583fed6a3f..7ac8907f51 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart @@ -222,14 +222,15 @@ class AdvancedFilterController extends BaseController { _mailboxDashBoardController.handleAdvancedSearchEmail(); } - Future> getAutoCompleteSuggestion(String word) async { - log('AdvancedFilterController::getAutoCompleteSuggestion(): word = $word'); + Future> getAutoCompleteSuggestion(String word, {int? limit}) async { + log('AdvancedFilterController::getAutoCompleteSuggestion():word = $word | limit = $limit'); _getAutoCompleteInteractor = getBinding(); return await _getAutoCompleteInteractor ?.execute(AutoCompletePattern( word: word, - accountId: _mailboxDashBoardController.accountId.value + limit: limit, + accountId: _mailboxDashBoardController.accountId.value, )).then((value) => value.fold( (failure) => [], (success) => success is GetAutoCompleteSuccess diff --git a/lib/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart b/lib/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart deleted file mode 100644 index c46348b61a..0000000000 --- a/lib/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; - -class SuggestionEmailAddress with EquatableMixin { - final EmailAddress emailAddress; - final SuggestionEmailState state; - - SuggestionEmailAddress(this.emailAddress, {this.state = SuggestionEmailState.valid}); - - @override - List get props => [emailAddress, state]; -} - -enum SuggestionEmailState { - valid, - duplicated, -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/styles/autocomplete_suggestion_item_web_style.dart b/lib/features/mailbox_dashboard/presentation/styles/autocomplete_suggestion_item_web_style.dart deleted file mode 100644 index 7887066608..0000000000 --- a/lib/features/mailbox_dashboard/presentation/styles/autocomplete_suggestion_item_web_style.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:flutter/material.dart'; - -class AutoCompleteSuggestionItemWebStyle { - static const double iconSize = 24.0; - - static const EdgeInsetsGeometry margin = EdgeInsets.all(8.0); - - static const EdgeInsetsGeometry contentPaddingDuplicated = EdgeInsets.symmetric(horizontal: 8.0); - static const EdgeInsetsGeometry contentPaddingValid = EdgeInsets.symmetric(horizontal: 16.0); - - static const Decoration decoration = BoxDecoration( - color: AppColor.colorBgMenuItemDropDownSelected, - borderRadius: BorderRadius.all(Radius.circular(20)) - ); - - static const TextStyle subTitleTextOriginStyle = TextStyle( - color: AppColor.colorHintSearchBar, - fontSize: 13, - fontWeight: FontWeight.normal - ); - static const TextStyle subTitleWordSearchStyle = TextStyle( - color: Colors.black, - fontSize: 13, - fontWeight: FontWeight.bold - ); -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/styles/text_field_autocomplete_email_address_web_style.dart b/lib/features/mailbox_dashboard/presentation/styles/text_field_autocomplete_email_address_web_style.dart index 7a3ac7df98..8e82a0d593 100644 --- a/lib/features/mailbox_dashboard/presentation/styles/text_field_autocomplete_email_address_web_style.dart +++ b/lib/features/mailbox_dashboard/presentation/styles/text_field_autocomplete_email_address_web_style.dart @@ -1,5 +1,6 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; class TextFieldAutoCompleteEmailAddressWebStyles { static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(vertical: 8); @@ -15,6 +16,7 @@ class TextFieldAutoCompleteEmailAddressWebStyles { 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 = 8.0; diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/autocomplete_suggestion_item_widget_web.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/autocomplete_suggestion_item_widget_web.dart deleted file mode 100644 index 788119fbfe..0000000000 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/autocomplete_suggestion_item_widget_web.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:core/core.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.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:super_tag_editor/widgets/rich_text_widget.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/autocomplete_suggestion_item_web_style.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/avatar_suggestion_item_widget.dart'; - -typedef OnSelectedRecipientSuggestionAction = Function(EmailAddress emailAddress); - -class AutoCompleteSuggestionItemWidgetWeb extends StatelessWidget { - - final SuggestionEmailState suggestionState; - final EmailAddress emailAddress; - final String? suggestionValid; - final bool highlight; - final OnSelectedRecipientSuggestionAction? onSelectedAction; - - final _imagePaths = Get.find(); - - AutoCompleteSuggestionItemWidgetWeb({ - Key? key, - required this.suggestionState, - required this.emailAddress, - this.highlight = false, - this.suggestionValid, - this.onSelectedAction, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - if (suggestionState == SuggestionEmailState.duplicated) { - return Container( - margin: AutoCompleteSuggestionItemWebStyle.margin, - decoration: AutoCompleteSuggestionItemWebStyle.decoration, - child: Material( - type: MaterialType.transparency, - child: ListTile( - contentPadding: AutoCompleteSuggestionItemWebStyle.contentPaddingDuplicated, - leading: AvatarSuggestionItemWidget(emailAddress: emailAddress), - title: RichTextWidget( - textOrigin: emailAddress.asString(), - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - ), - subtitle: emailAddress.displayName.isNotEmpty - ? RichTextWidget( - textOrigin: emailAddress.emailAddress, - wordSearched: suggestionValid ?? '', - styleTextOrigin: AutoCompleteSuggestionItemWebStyle.subTitleTextOriginStyle, - styleWordSearched: AutoCompleteSuggestionItemWebStyle.subTitleWordSearchStyle, - overflow: TextOverflow.ellipsis, - ) - : null, - trailing: SvgPicture.asset( - _imagePaths.icFilterSelected, - width: AutoCompleteSuggestionItemWebStyle.iconSize, - height: AutoCompleteSuggestionItemWebStyle.iconSize, - fit: BoxFit.fill, - ), - ), - ), - ); - } else { - return Container( - color: highlight ? AppColor.colorItemSelected : Colors.white, - child: Material( - type: MaterialType.transparency, - child: ListTile( - contentPadding: AutoCompleteSuggestionItemWebStyle.contentPaddingValid, - leading: AvatarSuggestionItemWidget(emailAddress: emailAddress), - title: RichTextWidget( - textOrigin: emailAddress.asString(), - wordSearched: suggestionValid ?? '', - overflow: TextOverflow.ellipsis, - ), - subtitle: emailAddress.displayName.isNotEmpty - ? RichTextWidget( - textOrigin: emailAddress.emailAddress, - wordSearched: suggestionValid ?? '', - styleTextOrigin: AutoCompleteSuggestionItemWebStyle.subTitleTextOriginStyle, - styleWordSearched: AutoCompleteSuggestionItemWebStyle.subTitleWordSearchStyle, - overflow: TextOverflow.ellipsis, - ) - : null, - onTap: () => onSelectedAction?.call(emailAddress), - ), - ), - ); - } - } -} diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_autocomplete_email_address_web.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_autocomplete_email_address_web.dart index 1eeb8a7170..04fcfafec0 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_autocomplete_email_address_web.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_autocomplete_email_address_web.dart @@ -3,25 +3,27 @@ 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/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/model/search/advanced_search_filter.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.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/autocomplete_suggestion_item_widget_web.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/autocomplete_tag_item_widget_web.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; -typedef OnSuggestionEmailAddress = Future> Function(String word); +typedef OnSuggestionEmailAddress = Future> Function(String word, {int? limit}); typedef OnUpdateListEmailAddressAction = void Function(AdvancedSearchFilterField field, List newData); typedef OnDeleteEmailAddressTypeAction = void Function(AdvancedSearchFilterField field); typedef OnShowFullListEmailAddressAction = void Function(AdvancedSearchFilterField field); @@ -73,6 +75,8 @@ class TextFieldAutocompleteEmailAddressWeb extends StatefulWidget { } class _TextFieldAutocompleteEmailAddressWebState extends State { + final _imagePaths = Get.find(); + bool _lastTagFocused = false; bool _isDragging = false; late List _currentListEmailAddress; @@ -166,6 +170,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State _handleFocusTagAction.call(focused, setState), @@ -188,9 +193,16 @@ class _TextFieldAutocompleteEmailAddressWebState extends State _handleOnTagChangeAction.call(tag, setState), - findSuggestions: _findSuggestions, + findSuggestions: (queryString) => _findSuggestions( + queryString, + limit: AppConfig.defaultLimitAutocomplete, + ), + isLoadMoreOnlyOnce: true, + isLoadMoreReplaceAllOld: false, + loadMoreSuggestions: _findSuggestions, suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) { - return AutoCompleteSuggestionItemWidgetWeb( + return RecipientSuggestionItemWidget( + imagePaths: _imagePaths, suggestionState: suggestionEmailAddress.state, emailAddress: suggestionEmailAddress.emailAddress, suggestionValid: suggestionValid, @@ -233,7 +245,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State> _findSuggestions(String query) async { + FutureOr> _findSuggestions(String query, {int? limit}) async { if (_gapBetweenTagChangedAndFindSuggestion?.isActive ?? false) { return []; } @@ -246,7 +258,10 @@ class _TextFieldAutocompleteEmailAddressWebState extends State.empty(growable: true); if (processedQuery.length >= widget.minInputLengthAutocomplete && widget.onSuggestionEmailAddress != null) { - final listEmailAddress = await widget.onSuggestionEmailAddress!(processedQuery); + final listEmailAddress = await widget.onSuggestionEmailAddress!( + processedQuery, + limit: limit, + ); final listSuggestionEmailAddress = listEmailAddress.map((emailAddress) => _toSuggestionEmailAddress(emailAddress, _currentListEmailAddress)); tmailSuggestion.addAll(listSuggestionEmailAddress); } diff --git a/lib/features/manage_account/presentation/forward/controller/forward_recipient_controller.dart b/lib/features/manage_account/presentation/forward/controller/forward_recipient_controller.dart index 9def280976..cb60d6b283 100644 --- a/lib/features/manage_account/presentation/forward/controller/forward_recipient_controller.dart +++ b/lib/features/manage_account/presentation/forward/controller/forward_recipient_controller.dart @@ -52,16 +52,21 @@ class ForwardRecipientController { } } - Future> getAutoCompleteSuggestion(String word) async { - log('ForwardRecipientController::getAutoCompleteSuggestion(): $word'); + Future> getAutoCompleteSuggestion(String word, {int? limit}) async { + log('ForwardRecipientController::getAutoCompleteSuggestion():word = $word | limit = $limit'); _getAllAutoCompleteInteractor = getBinding(); _getAutoCompleteInteractor = getBinding(); _getDeviceContactSuggestionsInteractor = getBinding(); + final autoCompletePattern = AutoCompletePattern( + word: word, + limit: limit, + accountId: _accountId, + ); if (_contactSuggestionSource == ContactSuggestionSource.all) { if (_getAllAutoCompleteInteractor != null) { return await _getAllAutoCompleteInteractor! - .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .execute(autoCompletePattern) .then((value) => value.fold( (failure) => [], (success) => success is GetAutoCompleteSuccess @@ -70,7 +75,7 @@ class ForwardRecipientController { )); } else if (_getDeviceContactSuggestionsInteractor != null) { return await _getDeviceContactSuggestionsInteractor! - .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .execute(autoCompletePattern) .then((value) => value.fold( (failure) => [], (success) => success is GetDeviceContactSuggestionsSuccess @@ -85,7 +90,7 @@ class ForwardRecipientController { return []; } else { return await _getAutoCompleteInteractor! - .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .execute(autoCompletePattern) .then((value) => value.fold( (failure) => [], (success) => success is GetAutoCompleteSuccess diff --git a/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart b/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart index 0b25f2c54d..aa27346320 100644 --- a/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart +++ b/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart @@ -17,6 +17,7 @@ import 'package:super_tag_editor/tag_editor.dart'; import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; import 'package:tmail_ui_user/features/base/widget/material_text_icon_button.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/contact/presentation/widgets/contact_input_tag_item.dart'; import 'package:tmail_ui_user/features/contact/presentation/widgets/contact_suggestion_box_item.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; @@ -26,7 +27,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; import 'package:tmail_ui_user/main/utils/app_utils.dart'; -typedef OnSuggestionContactCallbackAction = Future> Function(String query); +typedef OnSuggestionContactCallbackAction = Future> Function(String query, {int? limit}); typedef OnAddListContactCallbackAction = Function(List listEmailAddress); typedef OnExceptionAddListContactCallbackAction = Function(Exception exception); @@ -62,6 +63,7 @@ class _AutocompleteContactTextFieldWithTagsState extends State(); final _imagePaths = Get.find(); final GlobalKey keyToEmailTagEditor = GlobalKey(); + final FocusNode _focusNodeKeyboard = FocusNode(); late List listEmailAddress; @@ -73,12 +75,19 @@ class _AutocompleteContactTextFieldWithTagsState extends State( key: keyToEmailTagEditor, length: listEmailAddress.length, controller: widget.controller, + focusNodeKeyboard: _focusNodeKeyboard, borderRadius: 12, backgroundColor: AppColor.colorInputBackgroundCreateMailbox, focusedBorderColor: AppColor.colorTextButton, @@ -140,12 +149,20 @@ class _AutocompleteContactTextFieldWithTagsState extends State _findSuggestions( + queryString, + limit: AppConfig.defaultLimitAutocomplete, + ), + suggestionItemHeight: ComposerStyle.suggestionItemHeight, + isLoadMoreOnlyOnce: true, + isLoadMoreReplaceAllOld: false, + loadMoreSuggestions: _findSuggestions, suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) { - return Container( + return Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: ContactSuggestionBoxItem( suggestionEmailAddress, + _imagePaths, shapeBorder: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12))), selectedContactCallbackAction: (contact) { @@ -200,7 +217,7 @@ class _AutocompleteContactTextFieldWithTagsState extends State> _findSuggestions(String query) async { + FutureOr> _findSuggestions(String query, {int? limit}) async { final processedQuery = query.trim(); if (processedQuery.isEmpty) { @@ -212,7 +229,10 @@ class _AutocompleteContactTextFieldWithTagsState extends State= widget.minInputLengthAutocomplete && widget.onSuggestionCallback != null ) { - final addedEmailAddresses = await widget.onSuggestionCallback!(processedQuery); + final addedEmailAddresses = await widget.onSuggestionCallback!( + processedQuery, + limit: limit, + ); final listSuggestionEmailAddress = addedEmailAddresses .map((emailAddress) => _toSuggestionEmailAddress(emailAddress, listEmailAddress)) .toList(); diff --git a/lib/main/utils/app_config.dart b/lib/main/utils/app_config.dart index 9f165e945f..6c3bcc0695 100644 --- a/lib/main/utils/app_config.dart +++ b/lib/main/utils/app_config.dart @@ -9,6 +9,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class AppConfig { static const int defaultMinInputLengthAutocomplete = 3; static const int warningAttachmentFileSizeInMegabytes = 10; + static const int defaultLimitAutocomplete = 8; static const String appDashboardConfigurationPath = "configurations/app_dashboard.json"; static const String appFCMConfigurationPath = "configurations/env.fcm"; diff --git a/pubspec.lock b/pubspec.lock index ec4cec04de..4903b8ff66 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1955,10 +1955,10 @@ packages: dependency: "direct main" description: name: super_tag_editor - sha256: "8e6e978c546f665be421bfdf76db3e7f31aaf10a0cf7ff4f69b71d04124e16c6" + sha256: d49a4100253de1d46d2c9b20cd7f215129f105028f6ad8a7fba388a4e3b4df9d url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.3.1" syncfusion_flutter_core: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6ab8dc03cb..defc54a369 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,9 +86,6 @@ dependencies: git: url: https://github.com/linagora/flutter-date-range-picker.git ref: main - # TODO: Move back to master after sprint 25 released - - super_tag_editor: 0.3.0 # TODO: We will change it when the PR in upstream repository will be merged # https://github.com/dietfriends/dns_client/pull/9 @@ -110,6 +107,8 @@ dependencies: ref: master ### Dependencies from pub.dev ### + super_tag_editor: 0.3.1 + cupertino_icons: 1.0.6 get: 4.6.6