TF-4013 Expand all recipients fields when focus
(cherry picked from commit 0eb80e70bb22e7b6f1bb8552aa6ecd6ca9ab304f)
This commit is contained in:
@@ -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,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+9
-9
@@ -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'),
|
||||||
|
|||||||
Reference in New Issue
Block a user