TF-2717 Write widgets test for RecipientComposerWidget
This commit is contained in:
@@ -49,7 +49,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
? controller.insertImage(context, constraints.maxWidth)
|
? controller.insertImage(context, constraints.maxWidth)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: MobileAppBarComposerWidgetStyle.backgroundColor,
|
backgroundColor: MobileAppBarComposerWidgetStyle.backgroundColor,
|
||||||
childBuilder: (context) => SafeArea(
|
childBuilder: (context, constraints) => SafeArea(
|
||||||
left: !controller.responsiveUtils.isLandscapeMobile(context),
|
left: !controller.responsiveUtils.isLandscapeMobile(context),
|
||||||
right: !controller.responsiveUtils.isLandscapeMobile(context),
|
right: !controller.responsiveUtils.isLandscapeMobile(context),
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -110,6 +110,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
Obx(() => RecipientComposerWidget(
|
Obx(() => RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.to,
|
prefix: PrefixEmailAddress.to,
|
||||||
listEmailAddress: controller.listToEmailAddress,
|
listEmailAddress: controller.listToEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
fromState: controller.fromRecipientState.value,
|
fromState: controller.fromRecipientState.value,
|
||||||
ccState: controller.ccRecipientState.value,
|
ccState: controller.ccRecipientState.value,
|
||||||
bccState: controller.bccRecipientState.value,
|
bccState: controller.bccRecipientState.value,
|
||||||
@@ -134,6 +136,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
return RecipientComposerWidget(
|
return RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.cc,
|
prefix: PrefixEmailAddress.cc,
|
||||||
listEmailAddress: controller.listCcEmailAddress,
|
listEmailAddress: controller.listCcEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.ccAddressExpandMode.value,
|
expandMode: controller.ccAddressExpandMode.value,
|
||||||
controller: controller.ccEmailAddressController,
|
controller: controller.ccEmailAddressController,
|
||||||
focusNode: controller.ccAddressFocusNode,
|
focusNode: controller.ccAddressFocusNode,
|
||||||
@@ -158,6 +162,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
return RecipientComposerWidget(
|
return RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.bcc,
|
prefix: PrefixEmailAddress.bcc,
|
||||||
listEmailAddress: controller.listBccEmailAddress,
|
listEmailAddress: controller.listBccEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.bccAddressExpandMode.value,
|
expandMode: controller.bccAddressExpandMode.value,
|
||||||
controller: controller.bccEmailAddressController,
|
controller: controller.bccEmailAddressController,
|
||||||
focusNode: controller.bccAddressFocusNode,
|
focusNode: controller.bccAddressFocusNode,
|
||||||
@@ -264,6 +270,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.to,
|
prefix: PrefixEmailAddress.to,
|
||||||
listEmailAddress: controller.listToEmailAddress,
|
listEmailAddress: controller.listToEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
fromState: controller.fromRecipientState.value,
|
fromState: controller.fromRecipientState.value,
|
||||||
ccState: controller.ccRecipientState.value,
|
ccState: controller.ccRecipientState.value,
|
||||||
bccState: controller.bccRecipientState.value,
|
bccState: controller.bccRecipientState.value,
|
||||||
@@ -287,6 +295,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.cc,
|
prefix: PrefixEmailAddress.cc,
|
||||||
listEmailAddress: controller.listCcEmailAddress,
|
listEmailAddress: controller.listCcEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.ccAddressExpandMode.value,
|
expandMode: controller.ccAddressExpandMode.value,
|
||||||
controller: controller.ccEmailAddressController,
|
controller: controller.ccEmailAddressController,
|
||||||
focusNode: controller.ccAddressFocusNode,
|
focusNode: controller.ccAddressFocusNode,
|
||||||
@@ -306,6 +316,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.bcc,
|
prefix: PrefixEmailAddress.bcc,
|
||||||
listEmailAddress: controller.listBccEmailAddress,
|
listEmailAddress: controller.listBccEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.bccAddressExpandMode.value,
|
expandMode: controller.bccAddressExpandMode.value,
|
||||||
controller: controller.bccEmailAddressController,
|
controller: controller.bccEmailAddressController,
|
||||||
focusNode: controller.bccAddressFocusNode,
|
focusNode: controller.bccAddressFocusNode,
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.to,
|
prefix: PrefixEmailAddress.to,
|
||||||
listEmailAddress: controller.listToEmailAddress,
|
listEmailAddress: controller.listToEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
fromState: controller.fromRecipientState.value,
|
fromState: controller.fromRecipientState.value,
|
||||||
ccState: controller.ccRecipientState.value,
|
ccState: controller.ccRecipientState.value,
|
||||||
bccState: controller.bccRecipientState.value,
|
bccState: controller.bccRecipientState.value,
|
||||||
@@ -110,6 +112,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.cc,
|
prefix: PrefixEmailAddress.cc,
|
||||||
listEmailAddress: controller.listCcEmailAddress,
|
listEmailAddress: controller.listCcEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.ccAddressExpandMode.value,
|
expandMode: controller.ccAddressExpandMode.value,
|
||||||
controller: controller.ccEmailAddressController,
|
controller: controller.ccEmailAddressController,
|
||||||
focusNode: controller.ccAddressFocusNode,
|
focusNode: controller.ccAddressFocusNode,
|
||||||
@@ -130,6 +134,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.bcc,
|
prefix: PrefixEmailAddress.bcc,
|
||||||
listEmailAddress: controller.listBccEmailAddress,
|
listEmailAddress: controller.listBccEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.bccAddressExpandMode.value,
|
expandMode: controller.bccAddressExpandMode.value,
|
||||||
controller: controller.bccEmailAddressController,
|
controller: controller.bccEmailAddressController,
|
||||||
focusNode: controller.bccAddressFocusNode,
|
focusNode: controller.bccAddressFocusNode,
|
||||||
@@ -305,6 +311,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.to,
|
prefix: PrefixEmailAddress.to,
|
||||||
listEmailAddress: controller.listToEmailAddress,
|
listEmailAddress: controller.listToEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
fromState: controller.fromRecipientState.value,
|
fromState: controller.fromRecipientState.value,
|
||||||
ccState: controller.ccRecipientState.value,
|
ccState: controller.ccRecipientState.value,
|
||||||
bccState: controller.bccRecipientState.value,
|
bccState: controller.bccRecipientState.value,
|
||||||
@@ -328,6 +336,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.cc,
|
prefix: PrefixEmailAddress.cc,
|
||||||
listEmailAddress: controller.listCcEmailAddress,
|
listEmailAddress: controller.listCcEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.ccAddressExpandMode.value,
|
expandMode: controller.ccAddressExpandMode.value,
|
||||||
controller: controller.ccEmailAddressController,
|
controller: controller.ccEmailAddressController,
|
||||||
focusNode: controller.ccAddressFocusNode,
|
focusNode: controller.ccAddressFocusNode,
|
||||||
@@ -348,6 +358,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.bcc,
|
prefix: PrefixEmailAddress.bcc,
|
||||||
listEmailAddress: controller.listBccEmailAddress,
|
listEmailAddress: controller.listBccEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.bccAddressExpandMode.value,
|
expandMode: controller.bccAddressExpandMode.value,
|
||||||
controller: controller.bccEmailAddressController,
|
controller: controller.bccEmailAddressController,
|
||||||
focusNode: controller.bccAddressFocusNode,
|
focusNode: controller.bccAddressFocusNode,
|
||||||
@@ -562,6 +574,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.to,
|
prefix: PrefixEmailAddress.to,
|
||||||
listEmailAddress: controller.listToEmailAddress,
|
listEmailAddress: controller.listToEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
fromState: controller.fromRecipientState.value,
|
fromState: controller.fromRecipientState.value,
|
||||||
ccState: controller.ccRecipientState.value,
|
ccState: controller.ccRecipientState.value,
|
||||||
bccState: controller.bccRecipientState.value,
|
bccState: controller.bccRecipientState.value,
|
||||||
@@ -585,6 +599,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.cc,
|
prefix: PrefixEmailAddress.cc,
|
||||||
listEmailAddress: controller.listCcEmailAddress,
|
listEmailAddress: controller.listCcEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.ccAddressExpandMode.value,
|
expandMode: controller.ccAddressExpandMode.value,
|
||||||
controller: controller.ccEmailAddressController,
|
controller: controller.ccEmailAddressController,
|
||||||
focusNode: controller.ccAddressFocusNode,
|
focusNode: controller.ccAddressFocusNode,
|
||||||
@@ -605,6 +621,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
RecipientComposerWidget(
|
RecipientComposerWidget(
|
||||||
prefix: PrefixEmailAddress.bcc,
|
prefix: PrefixEmailAddress.bcc,
|
||||||
listEmailAddress: controller.listBccEmailAddress,
|
listEmailAddress: controller.listBccEmailAddress,
|
||||||
|
imagePaths: controller.imagePaths,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
expandMode: controller.bccAddressExpandMode.value,
|
expandMode: controller.bccAddressExpandMode.value,
|
||||||
controller: controller.bccEmailAddressController,
|
controller: controller.bccEmailAddressController,
|
||||||
focusNode: controller.bccAddressFocusNode,
|
focusNode: controller.bccAddressFocusNode,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ typedef OnInsertImageAction = Function(BoxConstraints constraints);
|
|||||||
|
|
||||||
class MobileContainerView extends StatelessWidget {
|
class MobileContainerView extends StatelessWidget {
|
||||||
|
|
||||||
final Widget Function(BuildContext context) childBuilder;
|
final Widget Function(BuildContext context, BoxConstraints constraints) childBuilder;
|
||||||
final rich_composer.RichTextController keyboardRichTextController;
|
final rich_composer.RichTextController keyboardRichTextController;
|
||||||
final VoidCallback onCloseViewAction;
|
final VoidCallback onCloseViewAction;
|
||||||
final VoidCallback? onAttachFileAction;
|
final VoidCallback? onAttachFileAction;
|
||||||
@@ -69,7 +69,7 @@ class MobileContainerView extends StatelessWidget {
|
|||||||
paddingChild: isKeyboardVisible
|
paddingChild: isKeyboardVisible
|
||||||
? MobileContainerViewStyle.keyboardToolbarPadding
|
? MobileContainerViewStyle.keyboardToolbarPadding
|
||||||
: EdgeInsets.zero,
|
: EdgeInsets.zero,
|
||||||
child: childBuilder(context),
|
child: childBuilder(context, constraints),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import 'package:core/utils/app_logger.dart';
|
|||||||
import 'package:core/utils/platform_info.dart';
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.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';
|
||||||
import 'package:model/extensions/email_address_extension.dart';
|
import 'package:model/extensions/email_address_extension.dart';
|
||||||
@@ -41,6 +40,8 @@ class RecipientComposerWidget extends StatefulWidget {
|
|||||||
|
|
||||||
final PrefixEmailAddress prefix;
|
final PrefixEmailAddress prefix;
|
||||||
final List<EmailAddress> listEmailAddress;
|
final List<EmailAddress> listEmailAddress;
|
||||||
|
final ImagePaths imagePaths;
|
||||||
|
final double maxWidth;
|
||||||
final ExpandMode expandMode;
|
final ExpandMode expandMode;
|
||||||
final PrefixRecipientState fromState;
|
final PrefixRecipientState fromState;
|
||||||
final PrefixRecipientState ccState;
|
final PrefixRecipientState ccState;
|
||||||
@@ -66,6 +67,8 @@ class RecipientComposerWidget extends StatefulWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.prefix,
|
required this.prefix,
|
||||||
required this.listEmailAddress,
|
required this.listEmailAddress,
|
||||||
|
required this.imagePaths,
|
||||||
|
required this.maxWidth,
|
||||||
this.ccState = PrefixRecipientState.disabled,
|
this.ccState = PrefixRecipientState.disabled,
|
||||||
this.bccState = PrefixRecipientState.disabled,
|
this.bccState = PrefixRecipientState.disabled,
|
||||||
this.fromState = PrefixRecipientState.disabled,
|
this.fromState = PrefixRecipientState.disabled,
|
||||||
@@ -99,8 +102,6 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
|||||||
bool _isDragging = false;
|
bool _isDragging = false;
|
||||||
late List<EmailAddress> _currentListEmailAddress;
|
late List<EmailAddress> _currentListEmailAddress;
|
||||||
|
|
||||||
final _imagePaths = Get.find<ImagePaths>();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -117,250 +118,255 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(builder: (context, constraints) {
|
return Container(
|
||||||
return Container(
|
decoration: const BoxDecoration(
|
||||||
decoration: const BoxDecoration(
|
border: Border(
|
||||||
border: Border(
|
bottom: BorderSide(
|
||||||
bottom: BorderSide(
|
color: RecipientComposerWidgetStyle.borderColor,
|
||||||
color: RecipientComposerWidgetStyle.borderColor,
|
width: 1
|
||||||
width: 1
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
padding: widget.padding,
|
),
|
||||||
margin: widget.margin,
|
padding: widget.padding,
|
||||||
child: Row(
|
margin: widget.margin,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Row(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Padding(
|
children: [
|
||||||
padding: RecipientComposerWidgetStyle.labelMargin,
|
Padding(
|
||||||
child: Text(
|
padding: RecipientComposerWidgetStyle.labelMargin,
|
||||||
'${widget.prefix.asName(context)}:',
|
child: Text(
|
||||||
style: RecipientComposerWidgetStyle.labelTextStyle
|
'${widget.prefix.asName(context)}:',
|
||||||
),
|
key: Key('prefix_${widget.prefix.name}_recipient_composer_widget'),
|
||||||
|
style: RecipientComposerWidgetStyle.labelTextStyle
|
||||||
),
|
),
|
||||||
const SizedBox(width: RecipientComposerWidgetStyle.space),
|
),
|
||||||
Expanded(
|
const SizedBox(width: RecipientComposerWidgetStyle.space),
|
||||||
child: FocusScope(
|
Expanded(
|
||||||
child: Focus(
|
child: FocusScope(
|
||||||
onFocusChange: (focus) => widget.onFocusEmailAddressChangeAction?.call(widget.prefix, focus),
|
child: Focus(
|
||||||
onKey: (focusNode, event) {
|
onFocusChange: (focus) => widget.onFocusEmailAddressChangeAction?.call(widget.prefix, focus),
|
||||||
if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) {
|
onKey: (focusNode, event) {
|
||||||
widget.nextFocusNode?.requestFocus();
|
if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) {
|
||||||
widget.onFocusNextAddressAction?.call();
|
widget.nextFocusNode?.requestFocus();
|
||||||
return KeyEventResult.handled;
|
widget.onFocusNextAddressAction?.call();
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
},
|
||||||
|
child: StatefulBuilder(
|
||||||
|
builder: (context, stateSetter) {
|
||||||
|
if (PlatformInfo.isWeb) {
|
||||||
|
return DragTarget<DraggableEmailAddress>(
|
||||||
|
builder: (context, candidateData, rejectedData) {
|
||||||
|
return TagEditor<SuggestionEmailAddress>(
|
||||||
|
key: widget.keyTagEditor,
|
||||||
|
length: _collapsedListEmailAddress.length,
|
||||||
|
controller: widget.controller,
|
||||||
|
focusNode: widget.focusNode,
|
||||||
|
enableBorder: _isDragging,
|
||||||
|
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,
|
||||||
|
cursorColor: RecipientComposerWidgetStyle.cursorColor,
|
||||||
|
suggestionsBoxElevation: RecipientComposerWidgetStyle.suggestionsBoxElevation,
|
||||||
|
suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
|
||||||
|
suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius,
|
||||||
|
suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
|
||||||
|
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
|
||||||
|
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
|
||||||
|
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
|
||||||
|
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
|
||||||
|
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
|
||||||
|
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
|
||||||
|
onTapOutside: (_) {},
|
||||||
|
inputDecoration: const InputDecoration(border: InputBorder.none),
|
||||||
|
tagBuilder: (context, index) {
|
||||||
|
final currentEmailAddress = _currentListEmailAddress[index];
|
||||||
|
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
||||||
|
|
||||||
|
return RecipientTagItemWidget(
|
||||||
|
index: index,
|
||||||
|
imagePaths: widget.imagePaths,
|
||||||
|
prefix: widget.prefix,
|
||||||
|
currentEmailAddress: currentEmailAddress,
|
||||||
|
currentListEmailAddress: _currentListEmailAddress,
|
||||||
|
collapsedListEmailAddress: _collapsedListEmailAddress,
|
||||||
|
isLatestEmail: isLatestEmail,
|
||||||
|
isCollapsed: _isCollapse,
|
||||||
|
isLatestTagFocused: _lastTagFocused,
|
||||||
|
maxWidth: widget.maxWidth,
|
||||||
|
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
|
||||||
|
onShowFullAction: widget.onShowFullListEmailAddressAction,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
|
||||||
|
findSuggestions: _findSuggestions,
|
||||||
|
useDefaultHighlight: false,
|
||||||
|
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
|
||||||
|
return RecipientSuggestionItemWidget(
|
||||||
|
imagePaths: widget.imagePaths,
|
||||||
|
suggestionState: suggestionEmailAddress.state,
|
||||||
|
emailAddress: suggestionEmailAddress.emailAddress,
|
||||||
|
suggestionValid: suggestionValid,
|
||||||
|
highlight: highlight,
|
||||||
|
onSelectedAction: (emailAddress) {
|
||||||
|
stateSetter(() => _currentListEmailAddress.add(emailAddress));
|
||||||
|
_updateListEmailAddressAction();
|
||||||
|
tagEditorState.resetTextField();
|
||||||
|
tagEditorState.closeSuggestionBox();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onAccept: (draggableEmailAddress) => _handleAcceptDraggableEmailAddressAction(draggableEmailAddress, stateSetter),
|
||||||
|
onLeave: (draggableEmailAddress) {
|
||||||
|
if (_isDragging) {
|
||||||
|
stateSetter(() => _isDragging = false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMove: (details) {
|
||||||
|
if (!_isDragging) {
|
||||||
|
stateSetter(() => _isDragging = true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return TagEditor<SuggestionEmailAddress>(
|
||||||
|
key: widget.keyTagEditor,
|
||||||
|
length: _collapsedListEmailAddress.length,
|
||||||
|
controller: widget.controller,
|
||||||
|
focusNode: widget.focusNode,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
textInputAction: TextInputAction.done,
|
||||||
|
debounceDuration: RecipientComposerWidgetStyle.suggestionDebounceDuration,
|
||||||
|
tagSpacing: RecipientComposerWidgetStyle.tagSpacing,
|
||||||
|
minTextFieldWidth: RecipientComposerWidgetStyle.minTextFieldWidth,
|
||||||
|
resetTextOnSubmitted: true,
|
||||||
|
autoScrollToInput: false,
|
||||||
|
cursorColor: RecipientComposerWidgetStyle.cursorColor,
|
||||||
|
suggestionsBoxElevation: RecipientComposerWidgetStyle.suggestionsBoxElevation,
|
||||||
|
suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
|
||||||
|
suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius,
|
||||||
|
suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
|
||||||
|
suggestionBoxWidth: _getSuggestionBoxWidth(widget.maxWidth),
|
||||||
|
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
|
||||||
|
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
|
||||||
|
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
|
||||||
|
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
|
||||||
|
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
|
||||||
|
onTapOutside: (_) {},
|
||||||
|
inputDecoration: const InputDecoration(border: InputBorder.none),
|
||||||
|
tagBuilder: (context, index) {
|
||||||
|
final currentEmailAddress = _currentListEmailAddress[index];
|
||||||
|
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
||||||
|
|
||||||
|
return RecipientTagItemWidget(
|
||||||
|
index: index,
|
||||||
|
imagePaths: widget.imagePaths,
|
||||||
|
prefix: widget.prefix,
|
||||||
|
currentEmailAddress: currentEmailAddress,
|
||||||
|
currentListEmailAddress: _currentListEmailAddress,
|
||||||
|
collapsedListEmailAddress: _collapsedListEmailAddress,
|
||||||
|
isLatestEmail: isLatestEmail,
|
||||||
|
isCollapsed: _isCollapse,
|
||||||
|
isLatestTagFocused: _lastTagFocused,
|
||||||
|
maxWidth: widget.maxWidth,
|
||||||
|
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
|
||||||
|
onShowFullAction: widget.onShowFullListEmailAddressAction,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
|
||||||
|
findSuggestions: _findSuggestions,
|
||||||
|
useDefaultHighlight: false,
|
||||||
|
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
|
||||||
|
return RecipientSuggestionItemWidget(
|
||||||
|
imagePaths: widget.imagePaths,
|
||||||
|
suggestionState: suggestionEmailAddress.state,
|
||||||
|
emailAddress: suggestionEmailAddress.emailAddress,
|
||||||
|
suggestionValid: suggestionValid,
|
||||||
|
highlight: highlight,
|
||||||
|
onSelectedAction: (emailAddress) {
|
||||||
|
stateSetter(() => _currentListEmailAddress.add(emailAddress));
|
||||||
|
_updateListEmailAddressAction();
|
||||||
|
tagEditorState.resetTextField();
|
||||||
|
tagEditorState.closeSuggestionBox();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return KeyEventResult.ignored;
|
|
||||||
},
|
},
|
||||||
child: StatefulBuilder(
|
|
||||||
builder: (context, stateSetter) {
|
|
||||||
if (PlatformInfo.isWeb) {
|
|
||||||
return DragTarget<DraggableEmailAddress>(
|
|
||||||
builder: (context, candidateData, rejectedData) {
|
|
||||||
return TagEditor<SuggestionEmailAddress>(
|
|
||||||
key: widget.keyTagEditor,
|
|
||||||
length: _collapsedListEmailAddress.length,
|
|
||||||
controller: widget.controller,
|
|
||||||
focusNode: widget.focusNode,
|
|
||||||
enableBorder: _isDragging,
|
|
||||||
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,
|
|
||||||
cursorColor: RecipientComposerWidgetStyle.cursorColor,
|
|
||||||
suggestionsBoxElevation: RecipientComposerWidgetStyle.suggestionsBoxElevation,
|
|
||||||
suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
|
|
||||||
suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius,
|
|
||||||
suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
|
|
||||||
suggestionBoxWidth: _getSuggestionBoxWidth(constraints.maxWidth),
|
|
||||||
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
|
|
||||||
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
|
|
||||||
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
|
|
||||||
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
|
|
||||||
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
|
|
||||||
onTapOutside: (_) {},
|
|
||||||
inputDecoration: const InputDecoration(border: InputBorder.none),
|
|
||||||
tagBuilder: (context, index) {
|
|
||||||
final currentEmailAddress = _currentListEmailAddress[index];
|
|
||||||
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
|
||||||
|
|
||||||
return RecipientTagItemWidget(
|
|
||||||
prefix: widget.prefix,
|
|
||||||
currentEmailAddress: currentEmailAddress,
|
|
||||||
currentListEmailAddress: _currentListEmailAddress,
|
|
||||||
collapsedListEmailAddress: _collapsedListEmailAddress,
|
|
||||||
isLatestEmail: isLatestEmail,
|
|
||||||
isCollapsed: _isCollapse,
|
|
||||||
isLatestTagFocused: _lastTagFocused,
|
|
||||||
maxWidth: constraints.maxWidth,
|
|
||||||
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
|
|
||||||
onShowFullAction: widget.onShowFullListEmailAddressAction,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
|
|
||||||
findSuggestions: _findSuggestions,
|
|
||||||
useDefaultHighlight: false,
|
|
||||||
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
|
|
||||||
return RecipientSuggestionItemWidget(
|
|
||||||
suggestionState: suggestionEmailAddress.state,
|
|
||||||
emailAddress: suggestionEmailAddress.emailAddress,
|
|
||||||
suggestionValid: suggestionValid,
|
|
||||||
highlight: highlight,
|
|
||||||
onSelectedAction: (emailAddress) {
|
|
||||||
stateSetter(() => _currentListEmailAddress.add(emailAddress));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
tagEditorState.resetTextField();
|
|
||||||
tagEditorState.closeSuggestionBox();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onAccept: (draggableEmailAddress) => _handleAcceptDraggableEmailAddressAction(draggableEmailAddress, stateSetter),
|
|
||||||
onLeave: (draggableEmailAddress) {
|
|
||||||
if (_isDragging) {
|
|
||||||
stateSetter(() => _isDragging = false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMove: (details) {
|
|
||||||
if (!_isDragging) {
|
|
||||||
stateSetter(() => _isDragging = true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return TagEditor<SuggestionEmailAddress>(
|
|
||||||
key: widget.keyTagEditor,
|
|
||||||
length: _collapsedListEmailAddress.length,
|
|
||||||
controller: widget.controller,
|
|
||||||
focusNode: widget.focusNode,
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
textInputAction: TextInputAction.done,
|
|
||||||
debounceDuration: RecipientComposerWidgetStyle.suggestionDebounceDuration,
|
|
||||||
tagSpacing: RecipientComposerWidgetStyle.tagSpacing,
|
|
||||||
minTextFieldWidth: RecipientComposerWidgetStyle.minTextFieldWidth,
|
|
||||||
resetTextOnSubmitted: true,
|
|
||||||
autoScrollToInput: false,
|
|
||||||
cursorColor: RecipientComposerWidgetStyle.cursorColor,
|
|
||||||
suggestionsBoxElevation: RecipientComposerWidgetStyle.suggestionsBoxElevation,
|
|
||||||
suggestionsBoxBackgroundColor: RecipientComposerWidgetStyle.suggestionsBoxBackgroundColor,
|
|
||||||
suggestionsBoxRadius: RecipientComposerWidgetStyle.suggestionsBoxRadius,
|
|
||||||
suggestionsBoxMaxHeight: RecipientComposerWidgetStyle.suggestionsBoxMaxHeight,
|
|
||||||
suggestionBoxWidth: _getSuggestionBoxWidth(constraints.maxWidth),
|
|
||||||
textStyle: RecipientComposerWidgetStyle.inputTextStyle,
|
|
||||||
onFocusTagAction: (focused) => _handleFocusTagAction.call(focused, stateSetter),
|
|
||||||
onDeleteTagAction: () => _handleDeleteLatestTagAction.call(stateSetter),
|
|
||||||
onSelectOptionAction: (item) => _handleSelectOptionAction.call(item, stateSetter),
|
|
||||||
onSubmitted: (value) => _handleSubmitTagAction.call(value, stateSetter),
|
|
||||||
onTapOutside: (_) {},
|
|
||||||
inputDecoration: const InputDecoration(border: InputBorder.none),
|
|
||||||
tagBuilder: (context, index) {
|
|
||||||
final currentEmailAddress = _currentListEmailAddress[index];
|
|
||||||
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
|
|
||||||
|
|
||||||
return RecipientTagItemWidget(
|
|
||||||
prefix: widget.prefix,
|
|
||||||
currentEmailAddress: currentEmailAddress,
|
|
||||||
currentListEmailAddress: _currentListEmailAddress,
|
|
||||||
collapsedListEmailAddress: _collapsedListEmailAddress,
|
|
||||||
isLatestEmail: isLatestEmail,
|
|
||||||
isCollapsed: _isCollapse,
|
|
||||||
isLatestTagFocused: _lastTagFocused,
|
|
||||||
maxWidth: constraints.maxWidth,
|
|
||||||
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, stateSetter),
|
|
||||||
onShowFullAction: widget.onShowFullListEmailAddressAction,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onTagChanged: (value) => _handleOnTagChangeAction.call(value, stateSetter),
|
|
||||||
findSuggestions: _findSuggestions,
|
|
||||||
useDefaultHighlight: false,
|
|
||||||
suggestionBuilder: (context, tagEditorState, suggestionEmailAddress, index, length, highlight, suggestionValid) {
|
|
||||||
return RecipientSuggestionItemWidget(
|
|
||||||
suggestionState: suggestionEmailAddress.state,
|
|
||||||
emailAddress: suggestionEmailAddress.emailAddress,
|
|
||||||
suggestionValid: suggestionValid,
|
|
||||||
highlight: highlight,
|
|
||||||
onSelectedAction: (emailAddress) {
|
|
||||||
stateSetter(() => _currentListEmailAddress.add(emailAddress));
|
|
||||||
_updateListEmailAddressAction();
|
|
||||||
tagEditorState.resetTextField();
|
|
||||||
tagEditorState.closeSuggestionBox();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
const SizedBox(width: RecipientComposerWidgetStyle.space),
|
),
|
||||||
if (widget.prefix == PrefixEmailAddress.to)
|
const SizedBox(width: RecipientComposerWidgetStyle.space),
|
||||||
if (PlatformInfo.isWeb)
|
if (widget.prefix == PrefixEmailAddress.to)
|
||||||
...[
|
if (PlatformInfo.isWeb)
|
||||||
if (widget.fromState == PrefixRecipientState.disabled)
|
...[
|
||||||
TMailButtonWidget.fromText(
|
if (widget.fromState == PrefixRecipientState.disabled)
|
||||||
text: AppLocalizations.of(context).from_email_address_prefix,
|
TMailButtonWidget.fromText(
|
||||||
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
text: AppLocalizations.of(context).from_email_address_prefix,
|
||||||
backgroundColor: Colors.transparent,
|
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
||||||
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
|
||||||
margin: RecipientComposerWidgetStyle.recipientMargin,
|
|
||||||
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.from),
|
|
||||||
),
|
|
||||||
if (widget.ccState == PrefixRecipientState.disabled)
|
|
||||||
TMailButtonWidget.fromText(
|
|
||||||
text: AppLocalizations.of(context).cc_email_address_prefix,
|
|
||||||
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
|
||||||
margin: RecipientComposerWidgetStyle.recipientMargin,
|
|
||||||
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.cc),
|
|
||||||
),
|
|
||||||
if (widget.bccState == PrefixRecipientState.disabled)
|
|
||||||
TMailButtonWidget.fromText(
|
|
||||||
text: AppLocalizations.of(context).bcc_email_address_prefix,
|
|
||||||
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
|
||||||
margin: RecipientComposerWidgetStyle.recipientMargin,
|
|
||||||
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.bcc),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
else if (PlatformInfo.isMobile)
|
|
||||||
...[
|
|
||||||
TMailButtonWidget.fromIcon(
|
|
||||||
icon: _isAllRecipientInputEnabled
|
|
||||||
? _imagePaths.icChevronUp
|
|
||||||
: _imagePaths.icChevronDownOutline,
|
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
iconSize: 24,
|
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
||||||
padding: const EdgeInsets.all(5),
|
margin: RecipientComposerWidgetStyle.recipientMargin,
|
||||||
iconColor: AppColor.colorLabelComposer,
|
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.from),
|
||||||
margin: RecipientComposerWidgetStyle.enableRecipientButtonMargin,
|
),
|
||||||
onTapActionCallback: () => widget.onEnableAllRecipientsInputAction?.call(_isAllRecipientInputEnabled),
|
if (widget.ccState == PrefixRecipientState.disabled)
|
||||||
)
|
TMailButtonWidget.fromText(
|
||||||
]
|
text: AppLocalizations.of(context).cc_email_address_prefix,
|
||||||
else if (PlatformInfo.isWeb)
|
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
||||||
TMailButtonWidget.fromIcon(
|
backgroundColor: Colors.transparent,
|
||||||
icon: _imagePaths.icClose,
|
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
||||||
backgroundColor: Colors.transparent,
|
margin: RecipientComposerWidgetStyle.recipientMargin,
|
||||||
iconColor: RecipientComposerWidgetStyle.deleteRecipientFieldIconColor,
|
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.cc),
|
||||||
iconSize: RecipientComposerWidgetStyle.deleteRecipientFieldIconSize,
|
),
|
||||||
padding: RecipientComposerWidgetStyle.deleteRecipientFieldIconPadding,
|
if (widget.bccState == PrefixRecipientState.disabled)
|
||||||
margin: RecipientComposerWidgetStyle.recipientMargin,
|
TMailButtonWidget.fromText(
|
||||||
onTapActionCallback: () => widget.onDeleteEmailAddressTypeAction?.call(widget.prefix),
|
text: AppLocalizations.of(context).bcc_email_address_prefix,
|
||||||
)
|
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
||||||
]
|
backgroundColor: Colors.transparent,
|
||||||
),
|
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
||||||
);
|
margin: RecipientComposerWidgetStyle.recipientMargin,
|
||||||
});
|
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.bcc),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
else if (PlatformInfo.isMobile)
|
||||||
|
...[
|
||||||
|
TMailButtonWidget.fromIcon(
|
||||||
|
icon: _isAllRecipientInputEnabled
|
||||||
|
? widget.imagePaths.icChevronUp
|
||||||
|
: widget.imagePaths.icChevronDownOutline,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
iconSize: 24,
|
||||||
|
padding: const EdgeInsets.all(5),
|
||||||
|
iconColor: AppColor.colorLabelComposer,
|
||||||
|
margin: RecipientComposerWidgetStyle.enableRecipientButtonMargin,
|
||||||
|
onTapActionCallback: () => widget.onEnableAllRecipientsInputAction?.call(_isAllRecipientInputEnabled),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
else if (PlatformInfo.isWeb)
|
||||||
|
TMailButtonWidget.fromIcon(
|
||||||
|
icon: widget.imagePaths.icClose,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
iconColor: RecipientComposerWidgetStyle.deleteRecipientFieldIconColor,
|
||||||
|
iconSize: RecipientComposerWidgetStyle.deleteRecipientFieldIconSize,
|
||||||
|
padding: RecipientComposerWidgetStyle.deleteRecipientFieldIconPadding,
|
||||||
|
margin: RecipientComposerWidgetStyle.recipientMargin,
|
||||||
|
onTapActionCallback: () => widget.onDeleteEmailAddressTypeAction?.call(widget.prefix),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get _isCollapse => _currentListEmailAddress.length > 1 && widget.expandMode == ExpandMode.COLLAPSE;
|
bool get _isCollapse => _currentListEmailAddress.length > 1 && widget.expandMode == ExpandMode.COLLAPSE;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:core/presentation/extensions/color_extension.dart';
|
|||||||
import 'package:core/presentation/resources/image_paths.dart';
|
import 'package:core/presentation/resources/image_paths.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:get/get.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';
|
||||||
import 'package:super_tag_editor/widgets/rich_text_widget.dart';
|
import 'package:super_tag_editor/widgets/rich_text_widget.dart';
|
||||||
@@ -17,16 +16,16 @@ class RecipientSuggestionItemWidget extends StatelessWidget {
|
|||||||
|
|
||||||
final SuggestionEmailState suggestionState;
|
final SuggestionEmailState suggestionState;
|
||||||
final EmailAddress emailAddress;
|
final EmailAddress emailAddress;
|
||||||
|
final ImagePaths imagePaths;
|
||||||
final String? suggestionValid;
|
final String? suggestionValid;
|
||||||
final bool highlight;
|
final bool highlight;
|
||||||
final OnSelectedRecipientSuggestionAction? onSelectedAction;
|
final OnSelectedRecipientSuggestionAction? onSelectedAction;
|
||||||
|
|
||||||
final _imagePaths = Get.find<ImagePaths>();
|
const RecipientSuggestionItemWidget({
|
||||||
|
|
||||||
RecipientSuggestionItemWidget({
|
|
||||||
super.key,
|
super.key,
|
||||||
required this.suggestionState,
|
required this.suggestionState,
|
||||||
required this.emailAddress,
|
required this.emailAddress,
|
||||||
|
required this.imagePaths,
|
||||||
this.suggestionValid,
|
this.suggestionValid,
|
||||||
this.highlight = false,
|
this.highlight = false,
|
||||||
this.onSelectedAction,
|
this.onSelectedAction,
|
||||||
@@ -61,7 +60,7 @@ class RecipientSuggestionItemWidget extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
trailing: SvgPicture.asset(
|
trailing: SvgPicture.asset(
|
||||||
_imagePaths.icFilterSelected,
|
imagePaths.icFilterSelected,
|
||||||
width: RecipientSuggestionItemWidgetStyle.selectedIconSize,
|
width: RecipientSuggestionItemWidgetStyle.selectedIconSize,
|
||||||
height: RecipientSuggestionItemWidgetStyle.selectedIconSize,
|
height: RecipientSuggestionItemWidgetStyle.selectedIconSize,
|
||||||
fit: BoxFit.fill
|
fit: BoxFit.fill
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import 'package:core/utils/direction_utils.dart';
|
|||||||
import 'package:core/utils/platform_info.dart';
|
import 'package:core/utils/platform_info.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:get/get.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';
|
||||||
import 'package:model/extensions/email_address_extension.dart';
|
import 'package:model/extensions/email_address_extension.dart';
|
||||||
@@ -23,7 +22,9 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
final bool isCollapsed;
|
final bool isCollapsed;
|
||||||
final bool isLatestTagFocused;
|
final bool isLatestTagFocused;
|
||||||
final bool isLatestEmail;
|
final bool isLatestEmail;
|
||||||
|
final ImagePaths imagePaths;
|
||||||
final double? maxWidth;
|
final double? maxWidth;
|
||||||
|
final int index;
|
||||||
final PrefixEmailAddress prefix;
|
final PrefixEmailAddress prefix;
|
||||||
final EmailAddress currentEmailAddress;
|
final EmailAddress currentEmailAddress;
|
||||||
final List<EmailAddress> currentListEmailAddress;
|
final List<EmailAddress> currentListEmailAddress;
|
||||||
@@ -31,14 +32,14 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
final OnShowFullListEmailAddressAction? onShowFullAction;
|
final OnShowFullListEmailAddressAction? onShowFullAction;
|
||||||
final OnDeleteTagAction? onDeleteTagAction;
|
final OnDeleteTagAction? onDeleteTagAction;
|
||||||
|
|
||||||
final _imagePaths = Get.find<ImagePaths>();
|
const RecipientTagItemWidget({
|
||||||
|
|
||||||
RecipientTagItemWidget({
|
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.index,
|
||||||
required this.prefix,
|
required this.prefix,
|
||||||
required this.currentEmailAddress,
|
required this.currentEmailAddress,
|
||||||
required this.currentListEmailAddress,
|
required this.currentListEmailAddress,
|
||||||
required this.collapsedListEmailAddress,
|
required this.collapsedListEmailAddress,
|
||||||
|
required this.imagePaths,
|
||||||
this.isCollapsed = false,
|
this.isCollapsed = false,
|
||||||
this.isLatestTagFocused = false,
|
this.isLatestTagFocused = false,
|
||||||
this.isLatestEmail = false,
|
this.isLatestEmail = false,
|
||||||
@@ -50,6 +51,7 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
key: Key('recipient_tag_item_${prefix.name}_$index'),
|
||||||
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -77,12 +79,17 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
label: Text(
|
label: Text(
|
||||||
|
key: Key('label_recipient_tag_item_${prefix.name}_$index'),
|
||||||
currentEmailAddress.asString(),
|
currentEmailAddress.asString(),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||||
),
|
),
|
||||||
deleteIcon: SvgPicture.asset(_imagePaths.icClose, fit: BoxFit.fill),
|
deleteIcon: SvgPicture.asset(
|
||||||
|
imagePaths.icClose,
|
||||||
|
key: Key('delete_icon_recipient_tag_item_${prefix.name}_$index'),
|
||||||
|
fit: BoxFit.fill
|
||||||
|
),
|
||||||
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
|
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
|
||||||
backgroundColor: _getTagBackgroundColor(),
|
backgroundColor: _getTagBackgroundColor(),
|
||||||
side: _getTagBorderSide(),
|
side: _getTagBorderSide(),
|
||||||
@@ -91,6 +98,7 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
avatar: currentEmailAddress.displayName.isNotEmpty
|
avatar: currentEmailAddress.displayName.isNotEmpty
|
||||||
? GradientCircleAvatarIcon(
|
? GradientCircleAvatarIcon(
|
||||||
|
key: Key('avatar_icon_recipient_tag_item_${prefix.name}_$index'),
|
||||||
colors: currentEmailAddress.avatarColors,
|
colors: currentEmailAddress.avatarColors,
|
||||||
label: currentEmailAddress.displayName.firstLetterToUpperCase,
|
label: currentEmailAddress.displayName.firstLetterToUpperCase,
|
||||||
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
|
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
|
||||||
@@ -116,13 +124,18 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
vertical: DirectionUtils.isDirectionRTLByHasAnyRtl(currentEmailAddress.asString()) ? 0 : 2
|
vertical: DirectionUtils.isDirectionRTLByHasAnyRtl(currentEmailAddress.asString()) ? 0 : 2
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
|
key: Key('label_recipient_tag_item_${prefix.name}_$index'),
|
||||||
currentEmailAddress.asString(),
|
currentEmailAddress.asString(),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
deleteIcon: SvgPicture.asset(_imagePaths.icClose, fit: BoxFit.fill),
|
deleteIcon: SvgPicture.asset(
|
||||||
|
imagePaths.icClose,
|
||||||
|
key: Key('delete_icon_recipient_tag_item_${prefix.name}_$index'),
|
||||||
|
fit: BoxFit.fill
|
||||||
|
),
|
||||||
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
|
labelStyle: RecipientTagItemWidgetStyle.labelTextStyle,
|
||||||
backgroundColor: _getTagBackgroundColor(),
|
backgroundColor: _getTagBackgroundColor(),
|
||||||
side: _getTagBorderSide(),
|
side: _getTagBorderSide(),
|
||||||
@@ -131,6 +144,7 @@ class RecipientTagItemWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
avatar: currentEmailAddress.displayName.isNotEmpty
|
avatar: currentEmailAddress.displayName.isNotEmpty
|
||||||
? GradientCircleAvatarIcon(
|
? GradientCircleAvatarIcon(
|
||||||
|
key: Key('avatar_icon_recipient_tag_item_${prefix.name}_$index'),
|
||||||
colors: currentEmailAddress.avatarColors,
|
colors: currentEmailAddress.avatarColors,
|
||||||
label: currentEmailAddress.displayName.firstLetterToUpperCase,
|
label: currentEmailAddress.displayName.firstLetterToUpperCase,
|
||||||
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
|
labelFontSize: RecipientTagItemWidgetStyle.avatarLabelFontSize,
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
import 'package:core/presentation/resources/image_paths.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
|
import 'package:model/email/prefix_email_address.dart';
|
||||||
|
import 'package:super_tag_editor/tag_editor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_tag_item_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations_delegate.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/localization_service.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('recipient_composer_widget test', () {
|
||||||
|
final imagePaths = ImagePaths();
|
||||||
|
final keyEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||||
|
const prefix = PrefixEmailAddress.to;
|
||||||
|
|
||||||
|
Widget makeTestableWidget({required Widget child}) {
|
||||||
|
return GetMaterialApp(
|
||||||
|
localizationsDelegates: const [
|
||||||
|
AppLocalizationsDelegate(),
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
|
],
|
||||||
|
supportedLocales: LocalizationService.supportedLocales,
|
||||||
|
home: Scaffold(body: child),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
testWidgets('RecipientComposerWidget renders correctly', (tester) async {
|
||||||
|
final listEmailAddress = <EmailAddress>[];
|
||||||
|
|
||||||
|
final widget = makeTestableWidget(
|
||||||
|
child: RecipientComposerWidget(
|
||||||
|
prefix: prefix,
|
||||||
|
listEmailAddress: listEmailAddress,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
maxWidth: 360,
|
||||||
|
keyTagEditor: keyEmailTagEditor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(widget);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
final recipientComposerWidgetFinder = find.byType(RecipientComposerWidget);
|
||||||
|
|
||||||
|
expect(recipientComposerWidgetFinder, findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('RecipientComposerWidget renders list email address correctly', (tester) async {
|
||||||
|
final listEmailAddress = <EmailAddress>[
|
||||||
|
EmailAddress(null, 'test1@example.com'),
|
||||||
|
EmailAddress(null, 'test2@example.com'),
|
||||||
|
];
|
||||||
|
|
||||||
|
final widget = makeTestableWidget(
|
||||||
|
child: RecipientComposerWidget(
|
||||||
|
prefix: prefix,
|
||||||
|
listEmailAddress: listEmailAddress,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
maxWidth: 360,
|
||||||
|
keyTagEditor: keyEmailTagEditor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(widget);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(RecipientTagItemWidget), findsNWidgets(2));
|
||||||
|
expect(find.text('test1@example.com'), findsOneWidget);
|
||||||
|
expect(find.text('test2@example.com'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('RecipientTagItemWidget should have a `maxWidth` equal to the RecipientComposerWidget\'s `maxWidth`', (tester) async {
|
||||||
|
final listEmailAddress = <EmailAddress>[
|
||||||
|
EmailAddress('test1', 'test1@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 recipientTagItemWidgetFinder = find.byKey(Key('recipient_tag_item_${prefix.name}_0'));
|
||||||
|
|
||||||
|
final Container recipientTagItemWidget = tester.widget(recipientTagItemWidgetFinder);
|
||||||
|
|
||||||
|
expect(recipientTagItemWidgetFinder, findsOneWidget);
|
||||||
|
expect(recipientTagItemWidget.constraints!.maxWidth, 360);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('RecipientTagItemWidget should have all the components (AvatarIcon, Label, DeleteIcon)', (tester) async {
|
||||||
|
final listEmailAddress = <EmailAddress>[
|
||||||
|
EmailAddress('test1', 'test1@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 recipientTagItemWidgetFinder = find.byKey(Key('recipient_tag_item_${prefix.name}_0'));
|
||||||
|
final labelRecipientTagItemWidgetFinder = find.byKey(Key('label_recipient_tag_item_${prefix.name}_0'));
|
||||||
|
final deleteIconRecipientTagItemWidgetFinder = find.byKey(Key('delete_icon_recipient_tag_item_${prefix.name}_0'));
|
||||||
|
final avatarIconRecipientTagItemWidgetFinder = find.byKey(Key('avatar_icon_recipient_tag_item_${prefix.name}_0'));
|
||||||
|
|
||||||
|
final Size recipientTagItemWidgetSize = tester.getSize(recipientTagItemWidgetFinder);
|
||||||
|
final Size labelRecipientTagItemWidgetSize = tester.getSize(labelRecipientTagItemWidgetFinder);
|
||||||
|
final Size deleteIconRecipientTagItemWidgetSize = tester.getSize(deleteIconRecipientTagItemWidgetFinder);
|
||||||
|
final Size avatarIconRecipientTagItemWidgetSize = tester.getSize(avatarIconRecipientTagItemWidgetFinder);
|
||||||
|
|
||||||
|
log('recipient_composer_widget_test::main: TagSize = $recipientTagItemWidgetSize | LabelTagSize = $labelRecipientTagItemWidgetSize | DeleteIconTagSize = $deleteIconRecipientTagItemWidgetSize | AvatarIconTagSize = $avatarIconRecipientTagItemWidgetSize');
|
||||||
|
|
||||||
|
expect(labelRecipientTagItemWidgetFinder, findsOneWidget);
|
||||||
|
expect(deleteIconRecipientTagItemWidgetFinder, findsOneWidget);
|
||||||
|
expect(avatarIconRecipientTagItemWidgetFinder, findsOneWidget);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
labelRecipientTagItemWidgetSize.width + deleteIconRecipientTagItemWidgetSize.width + avatarIconRecipientTagItemWidgetSize.width,
|
||||||
|
lessThanOrEqualTo(recipientTagItemWidgetSize.width)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('RecipientComponentWidget should have all the components (PrefixLabel, RecipientTagItemWidget)', (tester) async {
|
||||||
|
final listEmailAddress = <EmailAddress>[
|
||||||
|
EmailAddress('test1', 'test1@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 prefixRecipientComposerWidgetFinder = find.byKey(Key('prefix_${prefix.name}_recipient_composer_widget'));
|
||||||
|
final recipientTagItemWidgetFinder = find.byKey(Key('recipient_tag_item_${prefix.name}_0'));
|
||||||
|
|
||||||
|
final Size prefixRecipientComposerWidgetSize = tester.getSize(prefixRecipientComposerWidgetFinder);
|
||||||
|
final Size recipientTagItemWidgetSize = tester.getSize(prefixRecipientComposerWidgetFinder);
|
||||||
|
|
||||||
|
log('recipient_composer_widget_test::main: PrefixLabelSize = $prefixRecipientComposerWidgetSize | TagSize = $recipientTagItemWidgetSize');
|
||||||
|
|
||||||
|
expect(prefixRecipientComposerWidgetFinder, findsOneWidget);
|
||||||
|
expect(recipientTagItemWidgetFinder, findsOneWidget);
|
||||||
|
expect(
|
||||||
|
prefixRecipientComposerWidgetSize.width + recipientTagItemWidgetSize.width,
|
||||||
|
lessThanOrEqualTo(360)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user