Skip to content

Commit

Permalink
TF-2985 Support easily search mail from me in advanced search
Browse files Browse the repository at this point in the history
  • Loading branch information
dab246 committed Sep 18, 2024
1 parent e5e4a68 commit f548129
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:core/core.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/model.dart';
import 'package:super_tag_editor/tag_editor.dart';
Expand Down Expand Up @@ -63,6 +64,8 @@ class AdvancedFilterController extends BaseController {

late Worker _dashboardActionWorker;

UserName? get userName => _mailboxDashBoardController.sessionCurrent?.username;

@override
void onInit() {
_registerWorkerListener();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/utils/direction_utils.dart';
import 'package:flutter/material.dart';

class TextFieldAutoCompleteEmailAddressWebStyles {
static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(vertical: 8);
static const EdgeInsetsGeometry textInputContentPadding = EdgeInsetsDirectional.only(top: 16, bottom: 16, start: 12);
static const EdgeInsetsGeometry textInputContentPaddingWithMeButton = EdgeInsetsDirectional.only(top: 16, bottom: 16, start: 12, end: 60);
static const EdgeInsetsGeometry textInputContentPaddingWithSomeTag = EdgeInsetsDirectional.symmetric(vertical: 16);
static const EdgeInsets tagEditorPadding = EdgeInsets.symmetric(horizontal: 12);

static EdgeInsets getTagEditorPaddingWithMeButton(BuildContext context) {
return EdgeInsets.only(
left: DirectionUtils.isDirectionRTLByLanguage(context) ? 60 : 12,
right: DirectionUtils.isDirectionRTLByLanguage(context) ? 12 : 60,
);
}

static const double borderRadius = 10.0;
static const double suggestionBoxRadius = 20.0;

static const double borderWidth = 1.0;
static const double minTextFieldWidth = 40.0;
static const double meButtonMaxWidth = 100.0;
static const double meButtonMinWidth = 40.0;

static const double suggestionBoxElevation = 20.0;
static const double suggestionBoxMaxHeight = 350.0;
Expand Down Expand Up @@ -43,6 +54,11 @@ class TextFieldAutoCompleteEmailAddressWebStyles {
color: Colors.black,
fontWeight: FontWeight.w500,
);
static const TextStyle meButtonTextStyle = TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.w500,
);

static const Duration debounceDuration = Duration(milliseconds: 150);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Obx(() => TextFieldAutocompleteEmailAddressWeb(
field: AdvancedSearchFilterField.from,
listEmailAddress: controller.listFromEmailAddress,
userName: controller.userName,
expandMode: controller.fromAddressExpandMode.value,
controller: controller.fromEmailAddressController,
focusNode: controller.focusManager.fromFieldFocusNode,
Expand All @@ -43,6 +44,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Obx(() => TextFieldAutocompleteEmailAddressWeb(
field: AdvancedSearchFilterField.to,
listEmailAddress: controller.listToEmailAddress,
userName: controller.userName,
expandMode: controller.toAddressExpandMode.value,
controller: controller.toEmailAddressController,
focusNode: controller.focusManager.toFieldFocusNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import 'dart:math';
import 'package:collection/collection.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/app_logger.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:jmap_dart_client/jmap/core/user_name.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';
Expand All @@ -17,6 +19,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/adv
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/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';

typedef OnSuggestionEmailAddress = Future<List<EmailAddress>> Function(String word);
Expand All @@ -29,6 +32,7 @@ class TextFieldAutocompleteEmailAddressWeb extends StatefulWidget {

final AdvancedSearchFilterField field;
final List<EmailAddress> listEmailAddress;
final UserName? userName;
final ExpandMode expandMode;
final FocusNode? focusNode;
final GlobalKey? keyTagEditor;
Expand All @@ -47,6 +51,7 @@ class TextFieldAutocompleteEmailAddressWeb extends StatefulWidget {
Key? key,
required this.field,
required this.listEmailAddress,
this.userName,
this.expandMode = ExpandMode.EXPAND,
this.focusNode,
this.keyTagEditor,
Expand Down Expand Up @@ -105,89 +110,109 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
Expanded(
child: StatefulBuilder(
builder: ((context, setState) {
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,
fillColor: TextFieldAutoCompleteEmailAddressWebStyles.textInputFillColor,
border: TextFieldAutoCompleteEmailAddressWebStyles.textInputBorder,
hintText: widget.field.getHintText(context),
hintStyle: TextFieldAutoCompleteEmailAddressWebStyles.textInputHintStyle,
isDense: true,
contentPadding: _currentListEmailAddress.isNotEmpty
? TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPaddingWithSomeTag
: TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPadding
),
padding: _currentListEmailAddress.isNotEmpty
? TextFieldAutoCompleteEmailAddressWebStyles.tagEditorPadding
: EdgeInsets.zero,
borderRadius: TextFieldAutoCompleteEmailAddressWebStyles.borderRadius,
borderSize: TextFieldAutoCompleteEmailAddressWebStyles.borderWidth,
focusedBorderColor: TextFieldAutoCompleteEmailAddressWebStyles.focusedBorderColor,
enableBorder: true,
enableBorderColor: AppColor.colorInputBorderCreateMailbox,
minTextFieldWidth: TextFieldAutoCompleteEmailAddressWebStyles.minTextFieldWidth,
resetTextOnSubmitted: true,
autoScrollToInput: false,
suggestionsBoxElevation: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxElevation,
suggestionsBoxBackgroundColor: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxBackgroundColor,
suggestionsBoxRadius: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxRadius,
suggestionsBoxMaxHeight: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxMaxHeight,
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 AutoCompleteTagItemWidgetWeb(
field: widget.field,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress,
isLatestEmail: isLatestEmail,
isCollapsed: _isCollapse,
isLatestTagFocused: _lastTagFocused,
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, setState),
onShowFullAction: widget.onShowFullListEmailAddressAction,
);
},
onTagChanged: (tag) => _handleOnTagChangeAction.call(tag, setState),
findSuggestions: _findSuggestions,
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
return AutoCompleteSuggestionItemWidgetWeb(
suggestionState: suggestionEmailAddress.state,
emailAddress: suggestionEmailAddress.emailAddress,
suggestionValid: suggestionValid,
highlight: highlight,
onSelectedAction: (emailAddress) {
setState(() => _currentListEmailAddress.add(emailAddress));
_updateListEmailAddressAction();
tagEditorState.resetTextField();
tagEditorState.closeSuggestionBox();
return Stack(
alignment: AlignmentDirectional.center,
children: [
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,
fillColor: TextFieldAutoCompleteEmailAddressWebStyles.textInputFillColor,
border: TextFieldAutoCompleteEmailAddressWebStyles.textInputBorder,
hintText: widget.field.getHintText(context),
hintStyle: TextFieldAutoCompleteEmailAddressWebStyles.textInputHintStyle,
isDense: true,
contentPadding: _getInputFieldPadding()
),
padding: _getTagEditorPadding(context),
borderRadius: TextFieldAutoCompleteEmailAddressWebStyles.borderRadius,
borderSize: TextFieldAutoCompleteEmailAddressWebStyles.borderWidth,
focusedBorderColor: TextFieldAutoCompleteEmailAddressWebStyles.focusedBorderColor,
enableBorder: true,
enableBorderColor: AppColor.colorInputBorderCreateMailbox,
minTextFieldWidth: TextFieldAutoCompleteEmailAddressWebStyles.minTextFieldWidth,
resetTextOnSubmitted: true,
autoScrollToInput: false,
suggestionsBoxElevation: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxElevation,
suggestionsBoxBackgroundColor: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxBackgroundColor,
suggestionsBoxRadius: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxRadius,
suggestionsBoxMaxHeight: TextFieldAutoCompleteEmailAddressWebStyles.suggestionBoxMaxHeight,
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 AutoCompleteTagItemWidgetWeb(
field: widget.field,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress,
isLatestEmail: isLatestEmail,
isCollapsed: _isCollapse,
isLatestTagFocused: _lastTagFocused,
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, setState),
onShowFullAction: widget.onShowFullListEmailAddressAction,
);
},
);
},
onHandleKeyEventAction: (event) {
if (event is KeyDownEvent) {
switch (event.logicalKey) {
case LogicalKeyboardKey.tab:
widget.nextFocusNode?.requestFocus();
break;
default:
break;
}
}
},
onTagChanged: (tag) => _handleOnTagChangeAction.call(tag, setState),
findSuggestions: _findSuggestions,
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
return AutoCompleteSuggestionItemWidgetWeb(
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;
}
}
},
),
if (_validateMeButtonDisplayed)
PositionedDirectional(
end: 8,
child: TMailButtonWidget.fromText(
text: AppLocalizations.of(context).me,
borderRadius: TextFieldAutoCompleteEmailAddressWebStyles.borderRadius,
textStyle: TextFieldAutoCompleteEmailAddressWebStyles.meButtonTextStyle,
maxLines: 1,
textAlign: TextAlign.center,
backgroundColor: AppColor.primaryColor,
maxWidth: TextFieldAutoCompleteEmailAddressWebStyles.meButtonMaxWidth,
minWidth: TextFieldAutoCompleteEmailAddressWebStyles.meButtonMinWidth,
onTapActionCallback: () =>
_handleOnClickMeButton(
widget.userName!,
setState
),
)
)
],
);
})
),
Expand Down Expand Up @@ -340,4 +365,37 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
return null;
}
}

EdgeInsets _getTagEditorPadding(BuildContext context) {
if ( _currentListEmailAddress.isNotEmpty) {
return _validateMeButtonDisplayed
? TextFieldAutoCompleteEmailAddressWebStyles.getTagEditorPaddingWithMeButton(context)
: TextFieldAutoCompleteEmailAddressWebStyles.tagEditorPadding;
}
return EdgeInsets.zero;
}

EdgeInsetsGeometry _getInputFieldPadding() {
if ( _currentListEmailAddress.isNotEmpty) {
return TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPaddingWithSomeTag;
} else {
return _validateMeButtonDisplayed
? TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPaddingWithMeButton
: TextFieldAutoCompleteEmailAddressWebStyles.textInputContentPadding;
}
}

bool get _validateMeButtonDisplayed {
return widget.userName != null && !_isMyEmailAddressExist(widget.userName!);
}

bool _isMyEmailAddressExist(UserName userName) {
return _currentListEmailAddress
.any((emailAddress) => emailAddress.emailAddress == userName.value);
}

void _handleOnClickMeButton(UserName userName, StateSetter stateSetter) {
stateSetter(() => _currentListEmailAddress.add(EmailAddress(null, userName.value)));
_updateListEmailAddressAction();
}
}

0 comments on commit f548129

Please sign in to comment.