TF-3189 new reply to field in the mail composer
This commit is contained in:
committed by
Dat H. Pham
parent
78be3e4d79
commit
74fc8d5d72
@@ -126,11 +126,13 @@ class ComposerController extends BaseController
|
||||
final toAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
final ccAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
final bccAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
final replyToAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
final emailContentsViewState = Rxn<Either<Failure, Success>>();
|
||||
final hasRequestReadReceipt = false.obs;
|
||||
final fromRecipientState = PrefixRecipientState.disabled.obs;
|
||||
final ccRecipientState = PrefixRecipientState.disabled.obs;
|
||||
final bccRecipientState = PrefixRecipientState.disabled.obs;
|
||||
final replyToRecipientState = PrefixRecipientState.disabled.obs;
|
||||
final identitySelected = Rxn<Identity>();
|
||||
final listFromIdentities = RxList<Identity>();
|
||||
final isEmailChanged = Rx<bool>(false);
|
||||
@@ -157,17 +159,20 @@ class ComposerController extends BaseController
|
||||
List<EmailAddress> listToEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listCcEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listBccEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listReplyToEmailAddress = <EmailAddress>[];
|
||||
ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact;
|
||||
|
||||
final subjectEmailInputController = TextEditingController();
|
||||
final toEmailAddressController = TextEditingController();
|
||||
final ccEmailAddressController = TextEditingController();
|
||||
final bccEmailAddressController = TextEditingController();
|
||||
final replyToEmailAddressController = TextEditingController();
|
||||
final searchIdentitiesInputController = TextEditingController();
|
||||
|
||||
final GlobalKey<TagsEditorState> keyToEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||
final GlobalKey<TagsEditorState> keyCcEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||
final GlobalKey<TagsEditorState> keyBccEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||
final GlobalKey<TagsEditorState> keyReplyToEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||
final GlobalKey headerEditorMobileWidgetKey = GlobalKey();
|
||||
final GlobalKey<DropdownButton2State> identityDropdownKey = GlobalKey<DropdownButton2State>();
|
||||
final double defaultPaddingCoordinateYCursorEditor = 8;
|
||||
@@ -176,10 +181,12 @@ class ComposerController extends BaseController
|
||||
FocusNode? toAddressFocusNode;
|
||||
FocusNode? ccAddressFocusNode;
|
||||
FocusNode? bccAddressFocusNode;
|
||||
FocusNode? replyToAddressFocusNode;
|
||||
FocusNode? searchIdentitiesFocusNode;
|
||||
FocusNode? toAddressFocusNodeKeyboard;
|
||||
FocusNode? ccAddressFocusNodeKeyboard;
|
||||
FocusNode? bccAddressFocusNodeKeyboard;
|
||||
FocusNode? replyToAddressFocusNodeKeyboard;
|
||||
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragEnter;
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragOver;
|
||||
@@ -305,18 +312,23 @@ class ComposerController extends BaseController
|
||||
ccAddressFocusNode = null;
|
||||
bccAddressFocusNode?.dispose();
|
||||
bccAddressFocusNode = null;
|
||||
replyToAddressFocusNode?.dispose();
|
||||
replyToAddressFocusNode = null;
|
||||
toAddressFocusNodeKeyboard?.dispose();
|
||||
toAddressFocusNodeKeyboard = null;
|
||||
ccAddressFocusNodeKeyboard?.dispose();
|
||||
ccAddressFocusNodeKeyboard = null;
|
||||
bccAddressFocusNodeKeyboard?.dispose();
|
||||
bccAddressFocusNodeKeyboard = null;
|
||||
replyToAddressFocusNodeKeyboard?.dispose();
|
||||
replyToAddressFocusNodeKeyboard = null;
|
||||
searchIdentitiesFocusNode?.dispose();
|
||||
searchIdentitiesFocusNode = null;
|
||||
subjectEmailInputController.dispose();
|
||||
toEmailAddressController.dispose();
|
||||
ccEmailAddressController.dispose();
|
||||
bccEmailAddressController.dispose();
|
||||
replyToEmailAddressController.dispose();
|
||||
uploadInlineImageWorker.dispose();
|
||||
dashboardViewStateWorker.dispose();
|
||||
scrollController.dispose();
|
||||
@@ -480,6 +492,7 @@ class ComposerController extends BaseController
|
||||
toRecipients: listToEmailAddress.toSet(),
|
||||
ccRecipients: listCcEmailAddress.toSet(),
|
||||
bccRecipients: listBccEmailAddress.toSet(),
|
||||
replyToRecipients: listReplyToEmailAddress.toSet(),
|
||||
hasRequestReadReceipt: hasRequestReadReceipt.value,
|
||||
identity: identitySelected.value,
|
||||
attachments: uploadController.attachmentsUploaded,
|
||||
@@ -507,16 +520,21 @@ class ComposerController extends BaseController
|
||||
if (bccEmailAddressController.text.isNotEmpty) {
|
||||
keyBccEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
if (replyToEmailAddressController.text.isNotEmpty) {
|
||||
keyReplyToEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
}
|
||||
|
||||
void createFocusNodeInput() {
|
||||
toAddressFocusNode = FocusNode();
|
||||
ccAddressFocusNode = FocusNode();
|
||||
bccAddressFocusNode = FocusNode();
|
||||
replyToAddressFocusNode = FocusNode();
|
||||
searchIdentitiesFocusNode = FocusNode();
|
||||
toAddressFocusNodeKeyboard = FocusNode();
|
||||
ccAddressFocusNodeKeyboard = FocusNode();
|
||||
bccAddressFocusNodeKeyboard = FocusNode();
|
||||
replyToAddressFocusNodeKeyboard = FocusNode();
|
||||
|
||||
subjectEmailInputFocusNode = FocusNode(
|
||||
onKeyEvent: PlatformInfo.isWeb ? _subjectEmailInputOnKeyListener : null,
|
||||
@@ -851,7 +869,7 @@ class ComposerController extends BaseController
|
||||
listCcEmailAddress = List.from(recipients.value2);
|
||||
listBccEmailAddress = List.from(recipients.value3);
|
||||
|
||||
if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty) {
|
||||
if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty || listReplyToEmailAddress.isNotEmpty) {
|
||||
isInitialRecipient.value = true;
|
||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
}
|
||||
@@ -866,6 +884,11 @@ class ComposerController extends BaseController
|
||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
}
|
||||
|
||||
if (listReplyToEmailAddress.isNotEmpty) {
|
||||
replyToRecipientState.value = PrefixRecipientState.enabled;
|
||||
replyToAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
}
|
||||
|
||||
_updateStatusEmailSendButton();
|
||||
}
|
||||
|
||||
@@ -883,6 +906,9 @@ class ComposerController extends BaseController
|
||||
case PrefixEmailAddress.bcc:
|
||||
listBccEmailAddress = List.from(newListEmailAddress);
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
listReplyToEmailAddress = List.from(newListEmailAddress);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -891,8 +917,9 @@ class ComposerController extends BaseController
|
||||
|
||||
void _updateStatusEmailSendButton() {
|
||||
if (listToEmailAddress.isNotEmpty
|
||||
|| listCcEmailAddress.isNotEmpty
|
||||
|| listBccEmailAddress.isNotEmpty
|
||||
|| listCcEmailAddress.isNotEmpty) {
|
||||
|| listReplyToEmailAddress.isNotEmpty) {
|
||||
isEnableEmailSendButton.value = true;
|
||||
} else {
|
||||
isEnableEmailSendButton.value = false;
|
||||
@@ -910,7 +937,8 @@ class ComposerController extends BaseController
|
||||
|
||||
if (toEmailAddressController.text.isNotEmpty
|
||||
|| ccEmailAddressController.text.isNotEmpty
|
||||
|| bccEmailAddressController.text.isNotEmpty) {
|
||||
|| bccEmailAddressController.text.isNotEmpty
|
||||
|| replyToEmailAddressController.text.isNotEmpty) {
|
||||
_collapseAllRecipient();
|
||||
_autoCreateEmailTag();
|
||||
}
|
||||
@@ -927,7 +955,7 @@ class ComposerController extends BaseController
|
||||
return;
|
||||
}
|
||||
|
||||
final allListEmailAddress = listToEmailAddress + listCcEmailAddress + listBccEmailAddress;
|
||||
final allListEmailAddress = listToEmailAddress + listCcEmailAddress + listBccEmailAddress + listReplyToEmailAddress;
|
||||
final listEmailAddressInvalid = allListEmailAddress
|
||||
.where((emailAddress) => !EmailUtils.isEmailAddressValid(emailAddress.emailAddress))
|
||||
.toList();
|
||||
@@ -939,6 +967,7 @@ class ComposerController extends BaseController
|
||||
toAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
ccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
replyToAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
},
|
||||
showAsBottomSheet: true,
|
||||
title: AppLocalizations.of(context).sending_failed,
|
||||
@@ -1058,6 +1087,7 @@ class ComposerController extends BaseController
|
||||
toRecipients: listToEmailAddress.toSet(),
|
||||
ccRecipients: listCcEmailAddress.toSet(),
|
||||
bccRecipients: listBccEmailAddress.toSet(),
|
||||
replyToRecipients: listReplyToEmailAddress.toSet(),
|
||||
hasRequestReadReceipt: hasRequestReadReceipt.value,
|
||||
identity: identitySelected.value,
|
||||
attachments: uploadController.attachmentsUploaded,
|
||||
@@ -1276,6 +1306,7 @@ class ComposerController extends BaseController
|
||||
toRecipients: listToEmailAddress.toSet(),
|
||||
ccRecipients: listCcEmailAddress.toSet(),
|
||||
bccRecipients: listBccEmailAddress.toSet(),
|
||||
replyToRecipients: listReplyToEmailAddress.toSet(),
|
||||
identity: identitySelected.value,
|
||||
attachments: uploadController.attachmentsUploaded,
|
||||
hasReadReceipt: hasRequestReadReceipt.value,
|
||||
@@ -1560,6 +1591,9 @@ class ComposerController extends BaseController
|
||||
case PrefixEmailAddress.bcc:
|
||||
bccRecipientState.value = PrefixRecipientState.enabled;
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
replyToRecipientState.value = PrefixRecipientState.enabled;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1578,6 +1612,11 @@ class ComposerController extends BaseController
|
||||
bccAddressFocusNode = FocusNode();
|
||||
bccEmailAddressController.clear();
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
replyToRecipientState.value = PrefixRecipientState.disabled;
|
||||
replyToAddressFocusNode = FocusNode();
|
||||
replyToEmailAddressController.clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1587,12 +1626,14 @@ class ComposerController extends BaseController
|
||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
replyToAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
}
|
||||
|
||||
void _autoCreateEmailTag() {
|
||||
final inputToEmail = toEmailAddressController.text;
|
||||
final inputCcEmail = ccEmailAddressController.text;
|
||||
final inputBccEmail = bccEmailAddressController.text;
|
||||
final inputReplyToEmail = replyToEmailAddressController.text;
|
||||
log('ComposerController::_autoCreateEmailTag:inputToEmail = $inputToEmail | inputCcEmail = $inputCcEmail | inputBccEmail = $inputBccEmail');
|
||||
if (inputToEmail.trim().isNotEmpty) {
|
||||
_autoCreateEmailTagForRecipientField(
|
||||
@@ -1618,6 +1659,9 @@ class ComposerController extends BaseController
|
||||
keyEmailTagEditor: keyBccEmailTagEditor,
|
||||
);
|
||||
}
|
||||
if (inputReplyToEmail.isNotEmpty) {
|
||||
_autoCreateReplyToEmailTag(inputReplyToEmail);
|
||||
}
|
||||
}
|
||||
|
||||
bool _isDuplicatedRecipient(String inputEmail, List<EmailAddress> listEmailAddress) {
|
||||
@@ -1676,6 +1720,20 @@ class ComposerController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
void _autoCreateReplyToEmailTag(String inputEmail) {
|
||||
if (!_isDuplicatedRecipient(inputEmail, listReplyToEmailAddress)) {
|
||||
final emailAddress = EmailAddress(null, inputEmail);
|
||||
listReplyToEmailAddress.add(emailAddress);
|
||||
isInitialRecipient.value = true;
|
||||
isInitialRecipient.refresh();
|
||||
_updateStatusEmailSendButton();
|
||||
}
|
||||
keyReplyToEmailTagEditor.currentState?.resetTextField();
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
keyReplyToEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
});
|
||||
}
|
||||
|
||||
void _closeSuggestionBox() {
|
||||
if (toEmailAddressController.text.isEmpty) {
|
||||
keyToEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
@@ -1686,6 +1744,9 @@ class ComposerController extends BaseController
|
||||
if (bccEmailAddressController.text.isEmpty) {
|
||||
keyBccEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
if (replyToEmailAddressController.text.isEmpty) {
|
||||
keyReplyToEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
}
|
||||
|
||||
void showFullEmailAddress(PrefixEmailAddress prefixEmailAddress) {
|
||||
@@ -1702,6 +1763,10 @@ class ComposerController extends BaseController
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
bccAddressFocusNode?.requestFocus();
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
replyToAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
replyToAddressFocusNode?.requestFocus();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1719,6 +1784,9 @@ class ComposerController extends BaseController
|
||||
case PrefixEmailAddress.bcc:
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
replyToAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1766,6 +1834,13 @@ class ComposerController extends BaseController
|
||||
);
|
||||
}
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
replyToAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
final inputReplyToEmail = replyToEmailAddressController.text;
|
||||
if (inputReplyToEmail.isNotEmpty) {
|
||||
_autoCreateReplyToEmailTag(inputReplyToEmail);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2003,12 +2078,14 @@ class ComposerController extends BaseController
|
||||
return toAddressFocusNode?.hasFocus == true ||
|
||||
ccAddressFocusNode?.hasFocus == true ||
|
||||
bccAddressFocusNode?.hasFocus == true ||
|
||||
replyToAddressFocusNode?.hasFocus == true ||
|
||||
subjectEmailInputFocusNode?.hasFocus == true;
|
||||
} else if (PlatformInfo.isMobile) {
|
||||
final isEditorFocused = (await richTextMobileTabletController?.isEditorFocused) ?? false;
|
||||
return toAddressFocusNode?.hasFocus == true ||
|
||||
ccAddressFocusNode?.hasFocus == true ||
|
||||
bccAddressFocusNode?.hasFocus == true ||
|
||||
replyToAddressFocusNode?.hasFocus == true ||
|
||||
subjectEmailInputFocusNode?.hasFocus == true ||
|
||||
isEditorFocused;
|
||||
}
|
||||
@@ -2052,6 +2129,8 @@ class ComposerController extends BaseController
|
||||
return ccAddressFocusNode;
|
||||
} else if (bccRecipientState.value == PrefixRecipientState.enabled) {
|
||||
return bccAddressFocusNode;
|
||||
} else if (replyToRecipientState.value == PrefixRecipientState.enabled) {
|
||||
return replyToAddressFocusNode;
|
||||
} else {
|
||||
return subjectEmailInputFocusNode;
|
||||
}
|
||||
@@ -2060,6 +2139,16 @@ class ComposerController extends BaseController
|
||||
FocusNode? getNextFocusOfCcEmailAddress() {
|
||||
if (bccRecipientState.value == PrefixRecipientState.enabled) {
|
||||
return bccAddressFocusNode;
|
||||
} else if (replyToRecipientState.value == PrefixRecipientState.enabled) {
|
||||
return replyToAddressFocusNode;
|
||||
} else {
|
||||
return subjectEmailInputFocusNode;
|
||||
}
|
||||
}
|
||||
|
||||
FocusNode? getNextFocusOfBccEmailAddress() {
|
||||
if (replyToRecipientState.value == PrefixRecipientState.enabled) {
|
||||
return replyToAddressFocusNode;
|
||||
} else {
|
||||
return subjectEmailInputFocusNode;
|
||||
}
|
||||
@@ -2115,6 +2204,10 @@ class ComposerController extends BaseController
|
||||
listBccEmailAddress.remove(draggableEmailAddress.emailAddress);
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
listReplyToEmailAddress.remove(draggableEmailAddress.emailAddress);
|
||||
replyToAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2380,6 +2473,7 @@ class ComposerController extends BaseController
|
||||
toRecipients: listToEmailAddress.toSet(),
|
||||
ccRecipients: listCcEmailAddress.toSet(),
|
||||
bccRecipients: listBccEmailAddress.toSet(),
|
||||
replyToRecipients: listReplyToEmailAddress.toSet(),
|
||||
hasRequestReadReceipt: hasRequestReadReceipt.value,
|
||||
identity: identitySelected.value,
|
||||
attachments: uploadController.attachmentsUploaded,
|
||||
@@ -2461,6 +2555,7 @@ class ComposerController extends BaseController
|
||||
fromRecipientState.value = isEnabled ? PrefixRecipientState.disabled : PrefixRecipientState.enabled;
|
||||
ccRecipientState.value = isEnabled ? PrefixRecipientState.disabled : PrefixRecipientState.enabled;
|
||||
bccRecipientState.value = isEnabled ? PrefixRecipientState.disabled : PrefixRecipientState.enabled;
|
||||
replyToRecipientState.value = isEnabled ? PrefixRecipientState.disabled : PrefixRecipientState.enabled;
|
||||
}
|
||||
|
||||
void _handleGetEmailContentFailure(GetEmailContentFailure failure) {
|
||||
|
||||
@@ -132,6 +132,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
fromState: controller.fromRecipientState.value,
|
||||
ccState: controller.ccRecipientState.value,
|
||||
bccState: controller.bccRecipientState.value,
|
||||
replyToState: controller.replyToRecipientState.value,
|
||||
expandMode: controller.toAddressExpandMode.value,
|
||||
controller: controller.toEmailAddressController,
|
||||
focusNode: controller.toAddressFocusNode,
|
||||
@@ -192,9 +193,9 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
focusNode: controller.bccAddressFocusNode,
|
||||
keyTagEditor: controller.keyBccEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.subjectEmailInputFocusNode,
|
||||
padding: ComposerStyle.mobileRecipientPadding,
|
||||
margin: ComposerStyle.mobileRecipientMargin,
|
||||
nextFocusNode: controller.getNextFocusOfBccEmailAddress(),
|
||||
onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange,
|
||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||
onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType,
|
||||
@@ -206,6 +207,33 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}),
|
||||
Obx(() {
|
||||
if (controller.replyToRecipientState.value == PrefixRecipientState.enabled) {
|
||||
return RecipientComposerWidget(
|
||||
prefix: PrefixEmailAddress.replyTo,
|
||||
listEmailAddress: controller.listReplyToEmailAddress,
|
||||
imagePaths: controller.imagePaths,
|
||||
maxWidth: constraints.maxWidth,
|
||||
expandMode: controller.replyToAddressExpandMode.value,
|
||||
controller: controller.replyToEmailAddressController,
|
||||
focusNode: controller.replyToAddressFocusNode,
|
||||
keyTagEditor: controller.keyReplyToEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
padding: ComposerStyle.mobileRecipientPadding,
|
||||
margin: ComposerStyle.mobileRecipientMargin,
|
||||
nextFocusNode: controller.subjectEmailInputFocusNode,
|
||||
onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange,
|
||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||
onAddEmailAddressTypeAction: controller.addEmailAddressType,
|
||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||
onFocusNextAddressAction: controller.handleFocusNextAddressAction,
|
||||
onEnableAllRecipientsInputAction: controller.handleEnableRecipientsInputAction,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}),
|
||||
SubjectComposerWidget(
|
||||
focusNode: controller.subjectEmailInputFocusNode,
|
||||
textController: controller.subjectEmailInputController,
|
||||
@@ -297,6 +325,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
fromState: controller.fromRecipientState.value,
|
||||
ccState: controller.ccRecipientState.value,
|
||||
bccState: controller.bccRecipientState.value,
|
||||
replyToState: controller.replyToRecipientState.value,
|
||||
expandMode: controller.toAddressExpandMode.value,
|
||||
controller: controller.toEmailAddressController,
|
||||
focusNode: controller.toAddressFocusNode,
|
||||
@@ -351,6 +380,27 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
focusNode: controller.bccAddressFocusNode,
|
||||
keyTagEditor: controller.keyBccEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.getNextFocusOfBccEmailAddress(),
|
||||
padding: ComposerStyle.mobileRecipientPadding,
|
||||
margin: ComposerStyle.mobileRecipientMargin,
|
||||
onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange,
|
||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||
onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType,
|
||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||
onFocusNextAddressAction: controller.handleFocusNextAddressAction,
|
||||
),
|
||||
if (controller.replyToRecipientState.value == PrefixRecipientState.enabled)
|
||||
RecipientComposerWidget(
|
||||
prefix: PrefixEmailAddress.replyTo,
|
||||
listEmailAddress: controller.listReplyToEmailAddress,
|
||||
imagePaths: controller.imagePaths,
|
||||
maxWidth: constraints.maxWidth,
|
||||
expandMode: controller.replyToAddressExpandMode.value,
|
||||
controller: controller.replyToEmailAddressController,
|
||||
focusNode: controller.replyToAddressFocusNode,
|
||||
keyTagEditor: controller.keyReplyToEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.subjectEmailInputFocusNode,
|
||||
padding: ComposerStyle.mobileRecipientPadding,
|
||||
margin: ComposerStyle.mobileRecipientMargin,
|
||||
|
||||
@@ -94,6 +94,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
fromState: controller.fromRecipientState.value,
|
||||
ccState: controller.ccRecipientState.value,
|
||||
bccState: controller.bccRecipientState.value,
|
||||
replyToState: controller.replyToRecipientState.value,
|
||||
expandMode: controller.toAddressExpandMode.value,
|
||||
controller: controller.toEmailAddressController,
|
||||
focusNode: controller.toAddressFocusNode,
|
||||
@@ -152,6 +153,29 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard,
|
||||
keyTagEditor: controller.keyBccEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.getNextFocusOfCcEmailAddress(),
|
||||
padding: ComposerStyle.mobileRecipientPadding,
|
||||
margin: ComposerStyle.mobileRecipientMargin,
|
||||
onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange,
|
||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||
onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType,
|
||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||
onFocusNextAddressAction: controller.handleFocusNextAddressAction,
|
||||
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
||||
),
|
||||
if (controller.replyToRecipientState.value == PrefixRecipientState.enabled)
|
||||
RecipientComposerWidget(
|
||||
prefix: PrefixEmailAddress.replyTo,
|
||||
listEmailAddress: controller.listReplyToEmailAddress,
|
||||
imagePaths: controller.imagePaths,
|
||||
maxWidth: constraints.maxWidth,
|
||||
expandMode: controller.replyToAddressExpandMode.value,
|
||||
controller: controller.replyToEmailAddressController,
|
||||
focusNode: controller.replyToAddressFocusNode,
|
||||
focusNodeKeyboard: controller.replyToAddressFocusNodeKeyboard,
|
||||
keyTagEditor: controller.keyReplyToEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.subjectEmailInputFocusNode,
|
||||
padding: ComposerStyle.mobileRecipientPadding,
|
||||
margin: ComposerStyle.mobileRecipientMargin,
|
||||
@@ -343,6 +367,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
fromState: controller.fromRecipientState.value,
|
||||
ccState: controller.ccRecipientState.value,
|
||||
bccState: controller.bccRecipientState.value,
|
||||
replyToState: controller.replyToRecipientState.value,
|
||||
expandMode: controller.toAddressExpandMode.value,
|
||||
controller: controller.toEmailAddressController,
|
||||
focusNode: controller.toAddressFocusNode,
|
||||
@@ -401,6 +426,29 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard,
|
||||
keyTagEditor: controller.keyBccEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.getNextFocusOfBccEmailAddress(),
|
||||
padding: ComposerStyle.desktopRecipientPadding,
|
||||
margin: ComposerStyle.desktopRecipientMargin,
|
||||
onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange,
|
||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||
onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType,
|
||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||
onFocusNextAddressAction: controller.handleFocusNextAddressAction,
|
||||
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
||||
),
|
||||
if (controller.replyToRecipientState.value == PrefixRecipientState.enabled)
|
||||
RecipientComposerWidget(
|
||||
prefix: PrefixEmailAddress.replyTo,
|
||||
listEmailAddress: controller.listReplyToEmailAddress,
|
||||
imagePaths: controller.imagePaths,
|
||||
maxWidth: constraints.maxWidth,
|
||||
expandMode: controller.replyToAddressExpandMode.value,
|
||||
controller: controller.replyToEmailAddressController,
|
||||
focusNode: controller.replyToAddressFocusNode,
|
||||
focusNodeKeyboard: controller.replyToAddressFocusNodeKeyboard,
|
||||
keyTagEditor: controller.keyReplyToEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.subjectEmailInputFocusNode,
|
||||
padding: ComposerStyle.desktopRecipientPadding,
|
||||
margin: ComposerStyle.desktopRecipientMargin,
|
||||
@@ -629,6 +677,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
fromState: controller.fromRecipientState.value,
|
||||
ccState: controller.ccRecipientState.value,
|
||||
bccState: controller.bccRecipientState.value,
|
||||
replyToState: controller.replyToRecipientState.value,
|
||||
expandMode: controller.toAddressExpandMode.value,
|
||||
controller: controller.toEmailAddressController,
|
||||
focusNode: controller.toAddressFocusNode,
|
||||
@@ -687,6 +736,29 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard,
|
||||
keyTagEditor: controller.keyBccEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.getNextFocusOfBccEmailAddress(),
|
||||
padding: ComposerStyle.tabletRecipientPadding,
|
||||
margin: ComposerStyle.tabletRecipientMargin,
|
||||
onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange,
|
||||
onShowFullListEmailAddressAction: controller.showFullEmailAddress,
|
||||
onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType,
|
||||
onUpdateListEmailAddressAction: controller.updateListEmailAddress,
|
||||
onSuggestionEmailAddress: controller.getAutoCompleteSuggestion,
|
||||
onFocusNextAddressAction: controller.handleFocusNextAddressAction,
|
||||
onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress,
|
||||
),
|
||||
if (controller.replyToRecipientState.value == PrefixRecipientState.enabled)
|
||||
RecipientComposerWidget(
|
||||
prefix: PrefixEmailAddress.replyTo,
|
||||
listEmailAddress: controller.listReplyToEmailAddress,
|
||||
imagePaths: controller.imagePaths,
|
||||
maxWidth: constraints.maxWidth,
|
||||
expandMode: controller.replyToAddressExpandMode.value,
|
||||
controller: controller.replyToEmailAddressController,
|
||||
focusNode: controller.replyToAddressFocusNode,
|
||||
focusNodeKeyboard: controller.replyToAddressFocusNodeKeyboard,
|
||||
keyTagEditor: controller.keyReplyToEmailTagEditor,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
nextFocusNode: controller.subjectEmailInputFocusNode,
|
||||
padding: ComposerStyle.tabletRecipientPadding,
|
||||
margin: ComposerStyle.tabletRecipientMargin,
|
||||
|
||||
@@ -39,7 +39,9 @@ extension CreateEmailRequestExtension on CreateEmailRequest {
|
||||
}
|
||||
|
||||
Set<EmailAddress> createReplyToRecipients() {
|
||||
if (identity?.replyTo?.isNotEmpty == true) {
|
||||
if (replyToRecipients.isNotEmpty) {
|
||||
return replyToRecipients.toSet();
|
||||
} else if (identity?.replyTo?.isNotEmpty == true) {
|
||||
return identity!.replyTo!.toSet();
|
||||
} else {
|
||||
return { EmailAddress(null, session.getOwnEmailAddress()) };
|
||||
|
||||
@@ -75,10 +75,11 @@ extension EmailActionTypeExtension on EmailActionType {
|
||||
|
||||
final subject = presentationEmail.subject?.escapeLtGtHtmlString() ?? '';
|
||||
final receivedAt = presentationEmail.receivedAt;
|
||||
final fromEmailAddress = presentationEmail.from.toEscapeHtmlStringUseCommaSeparator();
|
||||
final toEmailAddress = presentationEmail.to.toEscapeHtmlStringUseCommaSeparator();
|
||||
final ccEmailAddress = presentationEmail.cc.toEscapeHtmlStringUseCommaSeparator();
|
||||
final bccEmailAddress = presentationEmail.bcc.toEscapeHtmlStringUseCommaSeparator();
|
||||
final fromEmailAddress = presentationEmail.from.listEmailAddressToString(isFullEmailAddress: true);
|
||||
final toEmailAddress = presentationEmail.to.listEmailAddressToString(isFullEmailAddress: true);
|
||||
final ccEmailAddress = presentationEmail.cc.listEmailAddressToString(isFullEmailAddress: true);
|
||||
final bccEmailAddress = presentationEmail.bcc.listEmailAddressToString(isFullEmailAddress: true);
|
||||
final replyToEmailAddress = presentationEmail.replyTo.listEmailAddressToString(isFullEmailAddress: true);
|
||||
|
||||
if (subject.isNotEmpty) {
|
||||
headerQuoted = headerQuoted
|
||||
@@ -116,6 +117,12 @@ extension EmailActionTypeExtension on EmailActionType {
|
||||
.append(bccEmailAddress)
|
||||
.addNewLineTag();
|
||||
}
|
||||
if (replyToEmailAddress.isNotEmpty) {
|
||||
headerQuoted = headerQuoted
|
||||
.append('${appLocalizations.reply_to_email_address_prefix}: ')
|
||||
.append(replyToEmailAddress)
|
||||
.addNewLineTag();
|
||||
}
|
||||
|
||||
return headerQuoted;
|
||||
default:
|
||||
|
||||
@@ -14,6 +14,8 @@ extension PrefixEmailAddressExtension on PrefixEmailAddress {
|
||||
return AppLocalizations.of(context).cc_email_address_prefix;
|
||||
case PrefixEmailAddress.bcc:
|
||||
return AppLocalizations.of(context).bcc_email_address_prefix;
|
||||
case PrefixEmailAddress.replyTo:
|
||||
return AppLocalizations.of(context).reply_to_email_address_prefix;
|
||||
case PrefixEmailAddress.from:
|
||||
return AppLocalizations.of(context).from_email_address_prefix;
|
||||
}
|
||||
@@ -27,6 +29,8 @@ extension PrefixEmailAddressExtension on PrefixEmailAddress {
|
||||
return email.cc?.toList() ?? List.empty();
|
||||
case PrefixEmailAddress.bcc:
|
||||
return email.bcc?.toList() ?? List.empty();
|
||||
case PrefixEmailAddress.replyTo:
|
||||
return email.replyTo?.toList() ?? List.empty();
|
||||
case PrefixEmailAddress.from:
|
||||
return email.from?.toList() ?? List.empty();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class CreateEmailRequest with EquatableMixin {
|
||||
final Set<EmailAddress> toRecipients;
|
||||
final Set<EmailAddress> ccRecipients;
|
||||
final Set<EmailAddress> bccRecipients;
|
||||
final Set<EmailAddress> replyToRecipients;
|
||||
final Identity? identity;
|
||||
final List<Attachment>? attachments;
|
||||
final Map<String, Attachment>? inlineAttachments;
|
||||
@@ -47,6 +48,7 @@ class CreateEmailRequest with EquatableMixin {
|
||||
required this.toRecipients,
|
||||
required this.ccRecipients,
|
||||
required this.bccRecipients,
|
||||
required this.replyToRecipients,
|
||||
this.hasRequestReadReceipt = true,
|
||||
this.identity,
|
||||
this.attachments,
|
||||
@@ -74,6 +76,7 @@ class CreateEmailRequest with EquatableMixin {
|
||||
toRecipients,
|
||||
ccRecipients,
|
||||
bccRecipients,
|
||||
replyToRecipients,
|
||||
identity,
|
||||
hasRequestReadReceipt,
|
||||
attachments,
|
||||
|
||||
@@ -9,6 +9,7 @@ class SavedEmailDraft with EquatableMixin {
|
||||
final Set<EmailAddress> toRecipients;
|
||||
final Set<EmailAddress> ccRecipients;
|
||||
final Set<EmailAddress> bccRecipients;
|
||||
final Set<EmailAddress> replyToRecipients;
|
||||
final List<Attachment> attachments;
|
||||
final Identity? identity;
|
||||
final bool hasReadReceipt;
|
||||
@@ -19,6 +20,7 @@ class SavedEmailDraft with EquatableMixin {
|
||||
required this.toRecipients,
|
||||
required this.ccRecipients,
|
||||
required this.bccRecipients,
|
||||
required this.replyToRecipients,
|
||||
required this.attachments,
|
||||
required this.identity,
|
||||
required this.hasReadReceipt,
|
||||
@@ -31,6 +33,7 @@ class SavedEmailDraft with EquatableMixin {
|
||||
toRecipients: {},
|
||||
ccRecipients: {},
|
||||
bccRecipients: {},
|
||||
replyToRecipients: {},
|
||||
attachments: [],
|
||||
identity: null,
|
||||
hasReadReceipt: false,
|
||||
@@ -45,6 +48,7 @@ class SavedEmailDraft with EquatableMixin {
|
||||
{0: toRecipients},
|
||||
{1: ccRecipients},
|
||||
{2: bccRecipients},
|
||||
{3: replyToRecipients},
|
||||
attachments,
|
||||
identity,
|
||||
hasReadReceipt
|
||||
|
||||
@@ -156,10 +156,6 @@ class ComposerStyle {
|
||||
}
|
||||
|
||||
static double getMaxHeightEmailAddressWidget(BuildContext context, BoxConstraints constraints, ResponsiveUtils responsiveUtils) {
|
||||
if (responsiveUtils.isDesktop(context)) {
|
||||
return constraints.maxHeight > 0 ? constraints.maxHeight * 0.3 : 150.0;
|
||||
} else {
|
||||
return constraints.maxHeight > 0 ? constraints.maxHeight * 0.4 : 150.0;
|
||||
}
|
||||
return constraints.maxHeight > 0 ? constraints.maxHeight * 0.4 : 150.0;
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ class RecipientComposerWidget extends StatefulWidget {
|
||||
final PrefixRecipientState fromState;
|
||||
final PrefixRecipientState ccState;
|
||||
final PrefixRecipientState bccState;
|
||||
final PrefixRecipientState replyToState;
|
||||
final bool? isInitial;
|
||||
final FocusNode? focusNode;
|
||||
final FocusNode? focusNodeKeyboard;
|
||||
@@ -77,6 +78,7 @@ class RecipientComposerWidget extends StatefulWidget {
|
||||
@visibleForTesting this.isTestingForWeb = false,
|
||||
this.ccState = PrefixRecipientState.disabled,
|
||||
this.bccState = PrefixRecipientState.disabled,
|
||||
this.replyToState = PrefixRecipientState.disabled,
|
||||
this.fromState = PrefixRecipientState.disabled,
|
||||
this.isInitial,
|
||||
this.controller,
|
||||
@@ -368,6 +370,16 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
margin: RecipientComposerWidgetStyle.recipientMargin,
|
||||
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.bcc),
|
||||
),
|
||||
if (widget.replyToState == PrefixRecipientState.disabled)
|
||||
TMailButtonWidget.fromText(
|
||||
key: Key('prefix_${widget.prefix.name}_recipient_reply_to_button'),
|
||||
text: AppLocalizations.of(context).reply_to_email_address_prefix,
|
||||
textStyle: RecipientComposerWidgetStyle.prefixButtonTextStyle,
|
||||
backgroundColor: Colors.transparent,
|
||||
padding: RecipientComposerWidgetStyle.prefixButtonPadding,
|
||||
margin: RecipientComposerWidgetStyle.recipientMargin,
|
||||
onTapActionCallback: () => widget.onAddEmailAddressTypeAction?.call(PrefixEmailAddress.replyTo),
|
||||
),
|
||||
]
|
||||
else if (PlatformInfo.isMobile)
|
||||
TMailButtonWidget.fromIcon(
|
||||
@@ -410,7 +422,8 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
|
||||
|
||||
bool get _isAllRecipientInputEnabled => widget.fromState == PrefixRecipientState.enabled
|
||||
&& widget.ccState == PrefixRecipientState.enabled
|
||||
&& widget.bccState == PrefixRecipientState.enabled;
|
||||
&& widget.bccState == PrefixRecipientState.enabled
|
||||
&& widget.replyToState == PrefixRecipientState.enabled;
|
||||
|
||||
List<EmailAddress> get _collapsedListEmailAddress => _isCollapse
|
||||
? _currentListEmailAddress.sublist(0, 1)
|
||||
|
||||
@@ -206,6 +206,12 @@
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"reply_to_email_address_prefix": "Reply to",
|
||||
"@reply_to_email_address_prefix": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"cc_email_address_prefix": "Cc",
|
||||
"@cc_email_address_prefix": {
|
||||
"type": "text",
|
||||
|
||||
@@ -204,6 +204,13 @@ class AppLocalizations {
|
||||
);
|
||||
}
|
||||
|
||||
String get reply_to_email_address_prefix {
|
||||
return Intl.message(
|
||||
'Reply to',
|
||||
name: 'reply_to_email_address_prefix',
|
||||
);
|
||||
}
|
||||
|
||||
String get cc_email_address_prefix {
|
||||
return Intl.message(
|
||||
'Cc',
|
||||
|
||||
Reference in New Issue
Block a user