TF-4013 Expand all recipients fields when focus

(cherry picked from commit 0eb80e70bb22e7b6f1bb8552aa6ecd6ca9ab304f)
This commit is contained in:
dab246
2025-10-06 14:44:40 +07:00
committed by Dat H. Pham
parent dd1d1f10fd
commit 69d2e59f35
8 changed files with 212 additions and 254 deletions
@@ -151,6 +151,7 @@ class ComposerController extends BaseController
final bccRecipientState = PrefixRecipientState.disabled.obs; final bccRecipientState = PrefixRecipientState.disabled.obs;
final replyToRecipientState = PrefixRecipientState.disabled.obs; final replyToRecipientState = PrefixRecipientState.disabled.obs;
final recipientsCollapsedState = PrefixRecipientState.disabled.obs; final recipientsCollapsedState = PrefixRecipientState.disabled.obs;
final prefixRootState = PrefixEmailAddress.to.obs;
final identitySelected = Rxn<Identity>(); final identitySelected = Rxn<Identity>();
final listFromIdentities = RxList<Identity>(); final listFromIdentities = RxList<Identity>();
final isEmailChanged = Rx<bool>(false); final isEmailChanged = Rx<bool>(false);
@@ -245,7 +246,6 @@ class ComposerController extends BaseController
EmailActionType? savedActionType; EmailActionType? savedActionType;
int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete; int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete;
EmailId? currentTemplateEmailId; EmailId? currentTemplateEmailId;
PrefixEmailAddress prefixRootState = PrefixEmailAddress.to;
@visibleForTesting @visibleForTesting
int? get savedEmailDraftHash => _savedEmailDraftHash; int? get savedEmailDraftHash => _savedEmailDraftHash;
@@ -1521,11 +1521,18 @@ class ComposerController extends BaseController
replyToRecipientState.value = PrefixRecipientState.enabled; replyToRecipientState.value = PrefixRecipientState.enabled;
break; break;
} }
updatePrefixRootState();
} }
void deleteEmailAddressType(PrefixEmailAddress prefixEmailAddress) { void deleteEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
updateListEmailAddress(prefixEmailAddress, <EmailAddress>[]); updateListEmailAddress(prefixEmailAddress, <EmailAddress>[]);
switch(prefixEmailAddress) { switch(prefixEmailAddress) {
case PrefixEmailAddress.to:
toRecipientState.value = PrefixRecipientState.disabled;
toAddressFocusNode = FocusNode();
toEmailAddressController.clear();
break;
case PrefixEmailAddress.cc: case PrefixEmailAddress.cc:
ccRecipientState.value = PrefixRecipientState.disabled; ccRecipientState.value = PrefixRecipientState.disabled;
ccAddressFocusNode = FocusNode(); ccAddressFocusNode = FocusNode();
@@ -1544,6 +1551,8 @@ class ComposerController extends BaseController
default: default:
break; break;
} }
updatePrefixRootState();
} }
void _collapseAllRecipient() { void _collapseAllRecipient() {
@@ -874,10 +874,10 @@ class ComposerView extends GetWidget<ComposerController> {
required FocusNode? nextFocusNode, required FocusNode? nextFocusNode,
bool isMobile = false, bool isMobile = false,
}) { }) {
return RecipientComposerWidget( return Obx(() => RecipientComposerWidget(
composerId: composerId, composerId: composerId,
prefix: prefix, prefix: prefix,
prefixRootState: controller.prefixRootState, prefixRootState: controller.prefixRootState.value,
fromState: controller.fromRecipientState.value, fromState: controller.fromRecipientState.value,
toState: controller.toRecipientState.value, toState: controller.toRecipientState.value,
ccState: controller.ccRecipientState.value, ccState: controller.ccRecipientState.value,
@@ -906,11 +906,11 @@ class ComposerView extends GetWidget<ComposerController> {
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
onFocusNextAddressAction: controller.handleFocusNextAddressAction, onFocusNextAddressAction: controller.handleFocusNextAddressAction,
onRemoveDraggableEmailAddressAction: onRemoveDraggableEmailAddressAction:
controller.removeDraggableEmailAddress, controller.removeDraggableEmailAddress,
onEditRecipientAction: controller.onEditRecipient, onEditRecipientAction: controller.onEditRecipient,
onClearFocusAction: controller.onClearFocusAction, onClearFocusAction: controller.onClearFocusAction,
onAddEmailAddressTypeAction: controller.addEmailAddressType, onAddEmailAddressTypeAction: controller.addEmailAddressType,
onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType,
); ));
} }
} }
@@ -27,7 +27,6 @@ extension HandleRecipientsCollapsedExtensions on ComposerController {
listReplyToEmailAddress.isNotEmpty; listReplyToEmailAddress.isNotEmpty;
void showFullRecipients() { void showFullRecipients() {
updatePrefixRootState();
recipientsCollapsedState.value = PrefixRecipientState.disabled; recipientsCollapsedState.value = PrefixRecipientState.disabled;
if (listToEmailAddress.isNotEmpty) { if (listToEmailAddress.isNotEmpty) {
@@ -50,27 +49,28 @@ extension HandleRecipientsCollapsedExtensions on ComposerController {
replyToAddressExpandMode.value = ExpandMode.EXPAND; replyToAddressExpandMode.value = ExpandMode.EXPAND;
} }
updatePrefixRootState();
requestFocusRecipientInput(); requestFocusRecipientInput();
} }
void updatePrefixRootState() { void updatePrefixRootState() {
if (listToEmailAddress.isNotEmpty) { if (toRecipientState.value == PrefixRecipientState.enabled) {
prefixRootState = PrefixEmailAddress.to; prefixRootState.value = PrefixEmailAddress.to;
return; return;
} }
if (listCcEmailAddress.isNotEmpty) { if (ccRecipientState.value == PrefixRecipientState.enabled) {
prefixRootState = PrefixEmailAddress.cc; prefixRootState.value = PrefixEmailAddress.cc;
return; return;
} }
if (listBccEmailAddress.isNotEmpty) { if (bccRecipientState.value == PrefixRecipientState.enabled) {
prefixRootState = PrefixEmailAddress.bcc; prefixRootState.value = PrefixEmailAddress.bcc;
return; return;
} }
if (listReplyToEmailAddress.isNotEmpty) { if (replyToRecipientState.value == PrefixRecipientState.enabled) {
prefixRootState = PrefixEmailAddress.replyTo; prefixRootState.value = PrefixEmailAddress.replyTo;
} }
} }
@@ -3,6 +3,7 @@ import 'package:core/presentation/extensions/string_extension.dart';
import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart'; import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart';
import 'package:extended_text/extended_text.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';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
@@ -46,10 +47,22 @@ class DraggableRecipientTagWidget extends StatelessWidget {
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Flexible( Flexible(
child: Text( child: ExtendedText(
emailAddress.asString(), emailAddress.asString(),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflowWidget: TextOverflowWidget(
position: TextOverflowPosition.middle,
clearType: TextOverflowClearType.clipRect,
child: Text(
'...',
style: ThemeUtils.textStyleInter400.copyWith(
color: Colors.white,
fontSize: 17,
height: 1.0,
letterSpacing: -0.17,
),
),
),
style: ThemeUtils.textStyleInter400.copyWith( style: ThemeUtils.textStyleInter400.copyWith(
color: Colors.white, color: Colors.white,
fontSize: 17, fontSize: 17,
@@ -1,6 +1,7 @@
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/extensions/string_extension.dart'; import 'package:core/presentation/extensions/string_extension.dart';
import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart'; import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart';
import 'package:extended_text/extended_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/extensions/email_address_extension.dart'; import 'package:model/extensions/email_address_extension.dart';
@@ -39,12 +40,19 @@ class RecipientCollapsedItemWidget extends StatelessWidget {
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Flexible( Flexible(
child: Text( child: ExtendedText(
emailAddress.asString(), emailAddress.asString(),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflowWidget: TextOverflowWidget(
position: TextOverflowPosition.middle,
clearType: TextOverflowClearType.clipRect,
child: Text(
'...',
style: RecipientTagItemWidgetStyle.labelTextStyle,
),
),
style: RecipientTagItemWidgetStyle.labelTextStyle, style: RecipientTagItemWidgetStyle.labelTextStyle,
), )
), ),
], ],
), ),
@@ -179,92 +179,118 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
onKeyEvent: PlatformInfo.isWeb ? _recipientInputOnKeyListener : null, onKeyEvent: PlatformInfo.isWeb ? _recipientInputOnKeyListener : null,
child: StatefulBuilder( child: StatefulBuilder(
builder: (context, stateSetter) { builder: (context, stateSetter) {
final tagEditor = TagEditor<SuggestionEmailAddress>(
key: widget.keyTagEditor,
length: _currentListEmailAddress.length,
controller: widget.controller,
focusNode: widget.focusNode,
enableBorder: _isDragging,
borderRadius: RecipientComposerWidgetStyle.enableBorderRadius,
enableBorderColor: RecipientComposerWidgetStyle.enableBorderColor,
focusedBorderColor: _isDragging
? RecipientComposerWidgetStyle.enableBorderColor
: null,
autofocus: PlatformInfo.isWeb
? widget.prefix != PrefixEmailAddress.to &&
_currentListEmailAddress.isEmpty
: false,
focusNodeKeyboard: widget.focusNodeKeyboard,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
debounceDuration:
RecipientComposerWidgetStyle.suggestionDebounceDuration,
tagSpacing: RecipientComposerWidgetStyle.tagSpacing,
minTextFieldWidth: RecipientComposerWidgetStyle.minTextFieldWidth,
resetTextOnSubmitted: true,
autoScrollToInput: false,
autoHideTextInputField: true,
cursorColor: RecipientComposerWidgetStyle.cursorColor,
suggestionsBoxElevation:
RecipientComposerWidgetStyle.suggestionsBoxElevation,
suggestionsBoxBackgroundColor:
RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
suggestionsBoxRadius:
RecipientComposerWidgetStyle.suggestionsBoxRadius,
suggestionsBoxMaxHeight:
RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
suggestionItemHeight:
RecipientComposerWidgetStyle.suggestionBoxItemHeight,
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
onFocusTagAction: (index) =>
_handleFocusTagAction.call(index, stateSetter),
onDeleteTagAction: (index) =>
_handleDeleteLatestTagAction.call(index, stateSetter),
onSelectOptionAction: (item) =>
_handleSelectOptionAction.call(item, stateSetter),
onSubmitted: (value) =>
_handleSubmitTagAction.call(value, stateSetter),
onTapOutside: (_) {},
onFocusTextInput: () {
widget.onShowFullListEmailAddressAction?.call(widget.prefix);
},
inputDecoration: const InputDecoration(border: InputBorder.none),
tagBuilder: (context, index) {
final currentEmailAddress = _currentListEmailAddress[index];
return RecipientTagItemWidget(
index: index,
imagePaths: widget.imagePaths,
prefix: widget.prefix,
composerId: widget.composerId,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress,
isCollapsed: _isCollapse,
isTagFocused: _tagIndexFocused == index,
maxWidth: widget.maxWidth,
isMobile: _responsiveUtils.isMobile(context),
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
onShowFullAction: widget.onShowFullListEmailAddressAction,
onEditRecipientAction: widget.onEditRecipientAction,
onClearFocusAction: widget.onClearFocusAction,
);
},
onTagChanged: (value) =>
_handleOnTagChangeAction.call(value, stateSetter),
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(
imagePaths: widget.imagePaths,
suggestionState: suggestionEmailAddress.state,
emailAddress: _subAddressingValidatedEmailAddress(
suggestionEmailAddress.emailAddress),
suggestionValid: suggestionValid,
highlight: highlight,
onSelectedAction: (emailAddress) {
stateSetter(() => _currentListEmailAddress.add(emailAddress));
_updateListEmailAddressAction();
tagEditorState.resetTextField();
tagEditorState.closeSuggestionBox();
},
);
},
);
if (PlatformInfo.isWeb || widget.isTestingForWeb) { if (PlatformInfo.isWeb || widget.isTestingForWeb) {
return DragTarget<DraggableEmailAddress>( return DragTarget<DraggableEmailAddress>(
builder: (context, candidateData, rejectedData) { builder: (context, candidateData, rejectedData) {
return TagEditor<SuggestionEmailAddress>( return tagEditor;
key: widget.keyTagEditor,
length: _collapsedListEmailAddress.length,
controller: widget.controller,
focusNode: widget.focusNode,
enableBorder: _isDragging,
focusNodeKeyboard: widget.focusNodeKeyboard,
borderRadius: RecipientComposerWidgetStyle.enableBorderRadius,
enableBorderColor: RecipientComposerWidgetStyle.enableBorderColor,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
debounceDuration: RecipientComposerWidgetStyle.suggestionDebounceDuration,
tagSpacing: RecipientComposerWidgetStyle.tagSpacing,
autofocus: widget.prefix != PrefixEmailAddress.to && _currentListEmailAddress.isEmpty,
minTextFieldWidth: RecipientComposerWidgetStyle.minTextFieldWidth,
resetTextOnSubmitted: true,
autoScrollToInput: false,
autoHideTextInputField: true,
cursorColor: RecipientComposerWidgetStyle.cursorColor,
suggestionsBoxElevation: RecipientComposerWidgetStyle.suggestionsBoxElevation,
suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius,
suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
suggestionItemHeight: RecipientComposerWidgetStyle.suggestionBoxItemHeight,
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
onFocusTagAction: (index) => _handleFocusTagAction.call(index, stateSetter),
onDeleteTagAction: (index) => _handleDeleteLatestTagAction.call(index, stateSetter),
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
onTapOutside: (_) {},
onFocusTextInput: () {
if (_isCollapse) {
widget.onShowFullListEmailAddressAction?.call(widget.prefix);
}
},
inputDecoration: const InputDecoration(border: InputBorder.none),
tagBuilder: (context, index) {
final currentEmailAddress = _currentListEmailAddress[index];
return RecipientTagItemWidget(
index: index,
imagePaths: widget.imagePaths,
prefix: widget.prefix,
composerId: widget.composerId,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress,
isCollapsed: _isCollapse,
isTagFocused: _tagIndexFocused == index,
maxWidth: widget.maxWidth,
isMobile: _responsiveUtils.isMobile(context),
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
onShowFullAction: widget.onShowFullListEmailAddressAction,
onEditRecipientAction: widget.onEditRecipientAction,
onClearFocusAction: widget.onClearFocusAction,
);
},
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
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(
imagePaths: widget.imagePaths,
suggestionState: suggestionEmailAddress.state,
emailAddress: _subAddressingValidatedEmailAddress(suggestionEmailAddress.emailAddress),
suggestionValid: suggestionValid,
highlight: highlight,
onSelectedAction: (emailAddress) {
stateSetter(() => _currentListEmailAddress.add(emailAddress));
_updateListEmailAddressAction();
tagEditorState.resetTextField();
tagEditorState.closeSuggestionBox();
},
);
},
);
}, },
onAcceptWithDetails: (draggableEmailAddress) => _handleAcceptDraggableEmailAddressAction(draggableEmailAddress.data, stateSetter), onAcceptWithDetails: (draggableEmailAddress) => _handleAcceptDraggableEmailAddressAction(draggableEmailAddress.data, stateSetter),
onLeave: (draggableEmailAddress) { onLeave: (draggableEmailAddress) {
@@ -279,85 +305,7 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
}, },
); );
} else { } else {
return TagEditor<SuggestionEmailAddress>( return tagEditor;
key: widget.keyTagEditor,
length: _collapsedListEmailAddress.length,
controller: widget.controller,
focusNode: widget.focusNode,
focusNodeKeyboard: widget.focusNodeKeyboard,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
debounceDuration: RecipientComposerWidgetStyle.suggestionDebounceDuration,
tagSpacing: RecipientComposerWidgetStyle.tagSpacing,
minTextFieldWidth: RecipientComposerWidgetStyle.minTextFieldWidth,
resetTextOnSubmitted: true,
autoScrollToInput: false,
autoHideTextInputField: true,
cursorColor: RecipientComposerWidgetStyle.cursorColor,
suggestionsBoxElevation: RecipientComposerWidgetStyle.suggestionsBoxElevation,
suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius,
suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
suggestionItemHeight: RecipientComposerWidgetStyle.suggestionBoxItemHeight,
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
onFocusTagAction: (index) => _handleFocusTagAction.call(index, stateSetter),
onDeleteTagAction: (index) => _handleDeleteLatestTagAction.call(index, stateSetter),
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
onTapOutside: (_) {},
onFocusTextInput: () {
if (_isCollapse) {
widget.onShowFullListEmailAddressAction?.call(widget.prefix);
}
},
inputDecoration: const InputDecoration(border: InputBorder.none),
tagBuilder: (context, index) {
final currentEmailAddress = _currentListEmailAddress[index];
return RecipientTagItemWidget(
index: index,
imagePaths: widget.imagePaths,
prefix: widget.prefix,
composerId: widget.composerId,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
collapsedListEmailAddress: _collapsedListEmailAddress,
isCollapsed: _isCollapse,
isTagFocused: _tagIndexFocused == index,
maxWidth: widget.maxWidth,
isMobile: _responsiveUtils.isMobile(context),
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
onShowFullAction: widget.onShowFullListEmailAddressAction,
onEditRecipientAction: widget.onEditRecipientAction,
onClearFocusAction: widget.onClearFocusAction,
);
},
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
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(
imagePaths: widget.imagePaths,
suggestionState: suggestionEmailAddress.state,
emailAddress: _subAddressingValidatedEmailAddress(suggestionEmailAddress.emailAddress),
suggestionValid: suggestionValid,
highlight: highlight,
onSelectedAction: (emailAddress) {
stateSetter(() => _currentListEmailAddress.add(emailAddress));
_updateListEmailAddressAction();
tagEditorState.resetTextField();
tagEditorState.closeSuggestionBox();
},
);
},
);
} }
}, },
) )
@@ -4,6 +4,7 @@ import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart'; import 'package:core/presentation/views/avatar/gradient_circle_avatar_icon.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/platform_info.dart'; import 'package:core/utils/platform_info.dart';
import 'package:extended_text/extended_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/prefix_email_address.dart'; import 'package:model/email/prefix_email_address.dart';
@@ -94,6 +95,9 @@ class RecipientTagItemWidget extends StatelessWidget {
), ),
onClearFocusAction: onClearFocusAction, onClearFocusAction: onClearFocusAction,
child: Container( child: Container(
key: PlatformInfo.isWeb
? Key('recipient_tag_item_${prefix.name}_$index')
: null,
constraints: const BoxConstraints(maxWidth: 267), constraints: const BoxConstraints(maxWidth: 267),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all( borderRadius: const BorderRadius.all(
@@ -116,13 +120,28 @@ class RecipientTagItemWidget extends StatelessWidget {
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Flexible( Flexible(
child: Text( child: PlatformInfo.isWeb
key: Key('label_recipient_tag_item_${prefix.name}_$index'), ? ExtendedText(
currentEmailAddress.asString(), key: Key('label_recipient_tag_item_${prefix.name}_$index'),
maxLines: 1, currentEmailAddress.asString(),
overflow: TextOverflow.ellipsis, maxLines: 1,
style: RecipientTagItemWidgetStyle.labelTextStyle, overflowWidget: TextOverflowWidget(
), position: TextOverflowPosition.middle,
clearType: TextOverflowClearType.clipRect,
child: Text(
'...',
style: RecipientTagItemWidgetStyle.labelTextStyle,
),
),
style: RecipientTagItemWidgetStyle.labelTextStyle,
)
: Text(
key: Key('label_recipient_tag_item_${prefix.name}_$index'),
currentEmailAddress.asString(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: RecipientTagItemWidgetStyle.labelTextStyle,
),
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
TMailButtonWidget.fromIcon( TMailButtonWidget.fromIcon(
@@ -167,29 +186,33 @@ class RecipientTagItemWidget extends StatelessWidget {
); );
} }
return Container( if (PlatformInfo.isWeb) {
key: Key('recipient_tag_item_${prefix.name}_$index'), return tagWidget;
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity), } else {
child: Row( return Container(
mainAxisSize: MainAxisSize.min, key: Key('recipient_tag_item_${prefix.name}_$index'),
children: [ constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
Flexible(child: tagWidget), child: Row(
if (isCollapsed) mainAxisSize: MainAxisSize.min,
TMailButtonWidget.fromText( children: [
key: Key('counter_recipient_tag_item_${prefix.name}_$index'), Flexible(child: tagWidget),
margin: _counterMargin, if (isCollapsed)
text: '+$countRecipients', TMailButtonWidget.fromText(
onTapActionCallback: () => onShowFullAction?.call(prefix), key: Key('counter_recipient_tag_item_${prefix.name}_$index'),
borderRadius: RecipientTagItemWidgetStyle.radius, margin: _counterMargin,
textStyle: RecipientTagItemWidgetStyle.labelTextStyle, text: '+$countRecipients',
padding: PlatformInfo.isWeb || isTestingForWeb onTapActionCallback: () => onShowFullAction?.call(prefix),
? RecipientTagItemWidgetStyle.counterPadding borderRadius: RecipientTagItemWidgetStyle.radius,
: RecipientTagItemWidgetStyle.mobileCounterPadding, textStyle: RecipientTagItemWidgetStyle.labelTextStyle,
backgroundColor: AppColor.colorEmailAddressTag, padding: PlatformInfo.isWeb || isTestingForWeb
) ? RecipientTagItemWidgetStyle.counterPadding
] : RecipientTagItemWidgetStyle.mobileCounterPadding,
), backgroundColor: AppColor.colorEmailAddressTag,
); ),
],
),
);
}
} }
EdgeInsetsGeometry? get _counterMargin { EdgeInsetsGeometry? get _counterMargin {
@@ -409,49 +409,6 @@ void main() {
expect(isExceededTextOverflow, equals(true)); expect(isExceededTextOverflow, equals(true));
}); });
testWidgets('WHEN EmailAddress has address short AND display name is NULL\n'
'RecipientTagItemWidget SHOULD have text display full', (tester) async {
final listEmailAddress = <EmailAddress>[
EmailAddress(null, 'test123@example.com'),
];
final widget = makeTestableWidget(
child: RecipientComposerWidget(
prefix: prefix,
listEmailAddress: listEmailAddress,
imagePaths: imagePaths,
maxWidth: 360,
keyTagEditor: keyEmailTagEditor,
),
);
await tester.pumpWidget(widget);
await tester.pumpAndSettle();
final labelRecipientTagItemWidgetFinder = find.byKey(Key('label_recipient_tag_item_${prefix.name}_0'));
final labelRecipientTagItemWidget = tester.widget<Text>(labelRecipientTagItemWidgetFinder);
final labelTagWidth = tester.getSize(labelRecipientTagItemWidgetFinder).width;
expect(labelRecipientTagItemWidget.overflow, equals(TextOverflow.ellipsis));
final TextPainter textPainter = TextPainter(
maxLines: labelRecipientTagItemWidget.maxLines,
textDirection: labelRecipientTagItemWidget.textDirection ?? TextDirection.ltr,
text: TextSpan(
text: labelRecipientTagItemWidget.data,
style: labelRecipientTagItemWidget.style,
locale: labelRecipientTagItemWidget.locale
),
);
textPainter.layout(maxWidth: labelTagWidth);
bool isExceededTextOverflow = textPainter.didExceedMaxLines;
log('recipient_composer_widget_test::main: LABEL_TAB_WIDTH = $labelTagWidth | TextPainterWidth = ${textPainter.width} | isExceededTextOverflow = $isExceededTextOverflow');
expect(isExceededTextOverflow, equals(false));
});
testWidgets('ToRecipientComponentWidget should display prefix To label correctly when the locale is fr-FR', (tester) async { testWidgets('ToRecipientComponentWidget should display prefix To label correctly when the locale is fr-FR', (tester) async {
final listEmailAddress = <EmailAddress>[ final listEmailAddress = <EmailAddress>[
EmailAddress('test1', 'test1@example.com'), EmailAddress('test1', 'test1@example.com'),