TF-3034 Prevent duplicate draft warning
This commit is contained in:
@@ -7,12 +7,12 @@ abstract class PlatformInfo {
|
|||||||
static bool isTestingForWeb = false;
|
static bool isTestingForWeb = false;
|
||||||
|
|
||||||
static bool get isWeb => kIsWeb || isTestingForWeb;
|
static bool get isWeb => kIsWeb || isTestingForWeb;
|
||||||
static bool get isLinux => !kIsWeb && defaultTargetPlatform == TargetPlatform.linux;
|
static bool get isLinux => !isWeb && defaultTargetPlatform == TargetPlatform.linux;
|
||||||
static bool get isWindows => !kIsWeb && defaultTargetPlatform == TargetPlatform.windows;
|
static bool get isWindows => !isWeb && defaultTargetPlatform == TargetPlatform.windows;
|
||||||
static bool get isMacOS => !kIsWeb && defaultTargetPlatform == TargetPlatform.macOS;
|
static bool get isMacOS => !isWeb && defaultTargetPlatform == TargetPlatform.macOS;
|
||||||
static bool get isFuchsia => !kIsWeb && defaultTargetPlatform == TargetPlatform.fuchsia;
|
static bool get isFuchsia => !isWeb && defaultTargetPlatform == TargetPlatform.fuchsia;
|
||||||
static bool get isIOS => !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS;
|
static bool get isIOS => !isWeb && defaultTargetPlatform == TargetPlatform.iOS;
|
||||||
static bool get isAndroid => !kIsWeb && defaultTargetPlatform == TargetPlatform.android;
|
static bool get isAndroid => !isWeb && defaultTargetPlatform == TargetPlatform.android;
|
||||||
static bool get isMobile => isAndroid || isIOS;
|
static bool get isMobile => isAndroid || isIOS;
|
||||||
static bool get isDesktop => isLinux || isWindows || isMacOS;
|
static bool get isDesktop => isLinux || isWindows || isMacOS;
|
||||||
static bool get isCanvasKit => isRendererCanvasKit;
|
static bool get isCanvasKit => isRendererCanvasKit;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/list_sha
|
|||||||
import 'package:tmail_ui_user/features/composer/presentation/mixin/drag_drog_file_mixin.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/mixin/drag_drog_file_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/model/saved_email_draft.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/signature_status.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/signature_status.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
||||||
@@ -109,7 +110,6 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
|
|
||||||
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||||
final networkConnectionController = Get.find<NetworkConnectionController>();
|
final networkConnectionController = Get.find<NetworkConnectionController>();
|
||||||
final _dynamicUrlInterceptors = Get.find<DynamicUrlInterceptors>();
|
|
||||||
final _beforeReconnectManager = Get.find<BeforeReconnectManager>();
|
final _beforeReconnectManager = Get.find<BeforeReconnectManager>();
|
||||||
|
|
||||||
final composerArguments = Rxn<ComposerArguments>();
|
final composerArguments = Rxn<ComposerArguments>();
|
||||||
@@ -199,6 +199,14 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
ButtonState _saveToDraftButtonState = ButtonState.enabled;
|
ButtonState _saveToDraftButtonState = ButtonState.enabled;
|
||||||
ButtonState _sendButtonState = ButtonState.enabled;
|
ButtonState _sendButtonState = ButtonState.enabled;
|
||||||
SignatureStatus _identityContentOnOpenPolicy = SignatureStatus.editedAvailable;
|
SignatureStatus _identityContentOnOpenPolicy = SignatureStatus.editedAvailable;
|
||||||
|
int? _savedEmailDraftHash;
|
||||||
|
bool _restoringSignatureButton = false;
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
bool get restoringSignatureButton => _restoringSignatureButton;
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
int? get savedEmailDraftHash => _savedEmailDraftHash;
|
||||||
|
|
||||||
late Worker uploadInlineImageWorker;
|
late Worker uploadInlineImageWorker;
|
||||||
late Worker dashboardViewStateWorker;
|
late Worker dashboardViewStateWorker;
|
||||||
@@ -330,6 +338,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
maxWithEditor = null;
|
maxWithEditor = null;
|
||||||
} else if (success is GetAlwaysReadReceiptSettingSuccess) {
|
} else if (success is GetAlwaysReadReceiptSettingSuccess) {
|
||||||
hasRequestReadReceipt.value = success.alwaysReadReceiptEnabled;
|
hasRequestReadReceipt.value = success.alwaysReadReceiptEnabled;
|
||||||
|
_initEmailDraftHash();
|
||||||
} else if (success is RestoreEmailInlineImagesSuccess) {
|
} else if (success is RestoreEmailInlineImagesSuccess) {
|
||||||
_updateEditorContent(success);
|
_updateEditorContent(success);
|
||||||
}
|
}
|
||||||
@@ -358,6 +367,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
}
|
}
|
||||||
} else if (failure is GetAlwaysReadReceiptSettingFailure) {
|
} else if (failure is GetAlwaysReadReceiptSettingFailure) {
|
||||||
hasRequestReadReceipt.value = false;
|
hasRequestReadReceipt.value = false;
|
||||||
|
_initEmailDraftHash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,16 +742,18 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
(identity) => identity.id == identityId);
|
(identity) => identity.id == identityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initIdentities(ComposerArguments composerArguments) {
|
Future<void> _initIdentities(ComposerArguments composerArguments) async {
|
||||||
listFromIdentities.value = composerArguments.identities ?? [];
|
listFromIdentities.value = composerArguments.identities ?? [];
|
||||||
final selectedIdentityFromId = _selectIdentityFromId(
|
final selectedIdentityFromId = _selectIdentityFromId(
|
||||||
composerArguments.selectedIdentityId);
|
composerArguments.selectedIdentityId);
|
||||||
if (listFromIdentities.isEmpty) {
|
if (listFromIdentities.isEmpty) {
|
||||||
_getAllIdentities();
|
_getAllIdentities();
|
||||||
} else if (selectedIdentityFromId != null) {
|
} else if (selectedIdentityFromId != null) {
|
||||||
_selectIdentity(selectedIdentityFromId);
|
await _selectIdentity(selectedIdentityFromId);
|
||||||
|
_initEmailDraftHash();
|
||||||
} else if (composerArguments.identities?.isNotEmpty == true) {
|
} else if (composerArguments.identities?.isNotEmpty == true) {
|
||||||
_selectIdentity(composerArguments.identities!.first);
|
await _selectIdentity(composerArguments.identities!.first);
|
||||||
|
_initEmailDraftHash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,8 +776,10 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
composerArguments.value?.selectedIdentityId);
|
composerArguments.value?.selectedIdentityId);
|
||||||
if (selectedIdentityFromId != null) {
|
if (selectedIdentityFromId != null) {
|
||||||
await _selectIdentity(selectedIdentityFromId);
|
await _selectIdentity(selectedIdentityFromId);
|
||||||
|
_initEmailDraftHash();
|
||||||
} else {
|
} else {
|
||||||
await _selectIdentity(listIdentitiesMayDeleted.firstOrNull);
|
await _selectIdentity(listIdentitiesMayDeleted.firstOrNull);
|
||||||
|
_initEmailDraftHash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1216,7 +1230,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
final session = mailboxDashBoardController.sessionCurrent;
|
final session = mailboxDashBoardController.sessionCurrent;
|
||||||
final accountId = mailboxDashBoardController.accountId.value;
|
final accountId = mailboxDashBoardController.accountId.value;
|
||||||
if (session != null && accountId != null) {
|
if (session != null && accountId != null) {
|
||||||
final uploadUri = session.getUploadUri(accountId, jmapUrl: _dynamicUrlInterceptors.jmapUrl);
|
final uploadUri = session.getUploadUri(accountId, jmapUrl: dynamicUrlInterceptors.jmapUrl);
|
||||||
uploadController.justUploadAttachmentsAction(
|
uploadController.justUploadAttachmentsAction(
|
||||||
uploadFiles: pickedFiles,
|
uploadFiles: pickedFiles,
|
||||||
uploadUri: uploadUri,
|
uploadUri: uploadUri,
|
||||||
@@ -1230,50 +1244,41 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
uploadController.deleteFileUploaded(uploadId);
|
uploadController.deleteFileUploaded(uploadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _validateEmailChange({
|
Future<bool> _validateEmailChange() async {
|
||||||
required BuildContext context,
|
final newDraftHash = await _hashDraftEmail();
|
||||||
required EmailActionType emailActionType,
|
|
||||||
PresentationEmail? presentationEmail,
|
|
||||||
Role? mailboxRole,
|
|
||||||
}) async {
|
|
||||||
final newEmailBody = await _getContentInEditor();
|
|
||||||
final oldEmailBody = _initTextEditor ?? '';
|
|
||||||
log('ComposerController::_validateEmailChange: newEmailBody = $newEmailBody | oldEmailBody = $oldEmailBody');
|
|
||||||
final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim());
|
|
||||||
|
|
||||||
final newEmailSubject = subjectEmail.value ?? '';
|
return _savedEmailDraftHash != newDraftHash;
|
||||||
final oldEmailSubject = emailActionType == EmailActionType.editDraft
|
}
|
||||||
? presentationEmail?.getEmailTitle().trim() ?? ''
|
|
||||||
: '';
|
|
||||||
final isEmailSubjectChanged = !oldEmailSubject.trim().isSame(newEmailSubject.trim());
|
|
||||||
|
|
||||||
final recipients = presentationEmail
|
Future<int> _hashDraftEmail() async {
|
||||||
?.generateRecipientsEmailAddressForComposer(
|
final emailContent = await _getContentInEditor();
|
||||||
emailActionType: emailActionType,
|
|
||||||
mailboxRole: mailboxRole
|
|
||||||
) ?? const Tuple3(<EmailAddress>[], <EmailAddress>[], <EmailAddress>[]);
|
|
||||||
|
|
||||||
final newToEmailAddress = listToEmailAddress;
|
final savedEmailDraft = SavedEmailDraft(
|
||||||
final oldToEmailAddress = emailActionType == EmailActionType.editDraft ? recipients.value1 : [];
|
subject: subjectEmail.value ?? '',
|
||||||
final isToEmailAddressChanged = !oldToEmailAddress.isSame(newToEmailAddress);
|
content: emailContent,
|
||||||
|
toRecipients: listToEmailAddress.toSet(),
|
||||||
|
ccRecipients: listCcEmailAddress.toSet(),
|
||||||
|
bccRecipients: listBccEmailAddress.toSet(),
|
||||||
|
identity: identitySelected.value,
|
||||||
|
attachments: uploadController.attachmentsUploaded,
|
||||||
|
hasReadReceipt: hasRequestReadReceipt.value,
|
||||||
|
);
|
||||||
|
|
||||||
final newCcEmailAddress = listCcEmailAddress;
|
return savedEmailDraft.hashCode;
|
||||||
final oldCcEmailAddress = emailActionType == EmailActionType.editDraft ? recipients.value2 : [];
|
}
|
||||||
final isCcEmailAddressChanged = !oldCcEmailAddress.isSame(newCcEmailAddress);
|
|
||||||
|
|
||||||
final newBccEmailAddress = listBccEmailAddress;
|
Future<void> _updateSavedEmailDraftHash() async {
|
||||||
final oldBccEmailAddress = emailActionType == EmailActionType.editDraft ? recipients.value3 : [];
|
_savedEmailDraftHash = await _hashDraftEmail();
|
||||||
final isBccEmailAddressChanged = !oldBccEmailAddress.isSame(newBccEmailAddress);
|
}
|
||||||
|
|
||||||
final isAttachmentsChanged = !initialAttachments.isSame(uploadController.attachmentsUploaded.toList());
|
Future<void> _initEmailDraftHash() async {
|
||||||
log('ComposerController::_validateChangeEmail: isEmailBodyChanged = $isEmailBodyChanged | isEmailSubjectChanged = $isEmailSubjectChanged | isToEmailAddressChanged = $isToEmailAddressChanged | isCcEmailAddressChanged = $isCcEmailAddressChanged | isBccEmailAddressChanged = $isBccEmailAddressChanged | isAttachmentsChanged = $isAttachmentsChanged');
|
if (composerArguments.value?.emailActionType != EmailActionType.compose
|
||||||
if (isEmailBodyChanged || isEmailSubjectChanged
|
&& composerArguments.value?.emailActionType != EmailActionType.editDraft
|
||||||
|| isToEmailAddressChanged || isCcEmailAddressChanged
|
) {
|
||||||
|| isBccEmailAddressChanged || isAttachmentsChanged) {
|
return;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
_savedEmailDraftHash = await _hashDraftEmail();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleClickSaveAsDraftsButton(BuildContext context) async {
|
void handleClickSaveAsDraftsButton(BuildContext context) async {
|
||||||
@@ -1306,10 +1311,12 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
_saveToDraftButtonState = ButtonState.enabled;
|
_saveToDraftButtonState = ButtonState.enabled;
|
||||||
_emailIdEditing = resultState.emailId;
|
_emailIdEditing = resultState.emailId;
|
||||||
mailboxDashBoardController.consumeState(Stream.value(Right<Failure, Success>(resultState)));
|
mailboxDashBoardController.consumeState(Stream.value(Right<Failure, Success>(resultState)));
|
||||||
|
_updateSavedEmailDraftHash();
|
||||||
} else if (resultState is UpdateEmailDraftsSuccess) {
|
} else if (resultState is UpdateEmailDraftsSuccess) {
|
||||||
_saveToDraftButtonState = ButtonState.enabled;
|
_saveToDraftButtonState = ButtonState.enabled;
|
||||||
_emailIdEditing = resultState.emailId;
|
_emailIdEditing = resultState.emailId;
|
||||||
mailboxDashBoardController.consumeState(Stream.value(Right<Failure, Success>(resultState)));
|
mailboxDashBoardController.consumeState(Stream.value(Right<Failure, Success>(resultState)));
|
||||||
|
_updateSavedEmailDraftHash();
|
||||||
} else if ((resultState is SaveEmailAsDraftsFailure && resultState.exception is SavingEmailToDraftsCanceledException) ||
|
} else if ((resultState is SaveEmailAsDraftsFailure && resultState.exception is SavingEmailToDraftsCanceledException) ||
|
||||||
(resultState is UpdateEmailDraftsFailure && resultState.exception is SavingEmailToDraftsCanceledException)) {
|
(resultState is UpdateEmailDraftsFailure && resultState.exception is SavingEmailToDraftsCanceledException)) {
|
||||||
_saveToDraftButtonState = ButtonState.enabled;
|
_saveToDraftButtonState = ButtonState.enabled;
|
||||||
@@ -1437,6 +1444,8 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
final selectedIdentityFromHeader = _selectIdentityFromId(identityIdFromHeader);
|
final selectedIdentityFromHeader = _selectIdentityFromId(identityIdFromHeader);
|
||||||
if (selectedIdentityFromHeader == null) return;
|
if (selectedIdentityFromHeader == null) return;
|
||||||
identitySelected.value = selectedIdentityFromHeader;
|
identitySelected.value = selectedIdentityFromHeader;
|
||||||
|
|
||||||
|
_initEmailDraftHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> restoreCollapsibleButton(String? emailContent) async {
|
Future<void> restoreCollapsibleButton(String? emailContent) async {
|
||||||
@@ -1445,6 +1454,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
final emailDocument = parse(emailContent);
|
final emailDocument = parse(emailContent);
|
||||||
final signature = emailDocument.querySelector('div.tmail-signature');
|
final signature = emailDocument.querySelector('div.tmail-signature');
|
||||||
if (signature == null) return;
|
if (signature == null) return;
|
||||||
|
_restoringSignatureButton = true;
|
||||||
await _applySignature(signature.innerHtml);
|
await _applySignature(signature.innerHtml);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('ComposerController::_restoreCollapsibleButton: $e');
|
logError('ComposerController::_restoreCollapsibleButton: $e');
|
||||||
@@ -1793,7 +1803,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
void _handleUploadInlineSuccess(SuccessAttachmentUploadState uploadState) {
|
void _handleUploadInlineSuccess(SuccessAttachmentUploadState uploadState) {
|
||||||
uploadController.clearUploadInlineViewState();
|
uploadController.clearUploadInlineViewState();
|
||||||
|
|
||||||
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
|
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
|
||||||
final accountId = mailboxDashBoardController.accountId.value;
|
final accountId = mailboxDashBoardController.accountId.value;
|
||||||
|
|
||||||
if (baseDownloadUrl != null && accountId != null) {
|
if (baseDownloadUrl != null && accountId != null) {
|
||||||
@@ -1988,6 +1998,18 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
initTextEditor(text);
|
initTextEditor(text);
|
||||||
}
|
}
|
||||||
_textEditorWeb = text;
|
_textEditorWeb = text;
|
||||||
|
|
||||||
|
_initEmailDraftHashAfterSignatureButtonRestored(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initEmailDraftHashAfterSignatureButtonRestored(String? emailContent) {
|
||||||
|
if (!_restoringSignatureButton) return;
|
||||||
|
final emailDocument = parse(emailContent);
|
||||||
|
final signatureButton = emailDocument.querySelector('button.tmail-signature-button');
|
||||||
|
if (signatureButton == null) return;
|
||||||
|
|
||||||
|
_restoringSignatureButton = false;
|
||||||
|
_initEmailDraftHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initTextEditor(String? text) {
|
void initTextEditor(String? text) {
|
||||||
@@ -2087,12 +2109,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final isChanged = await _validateEmailChange(
|
final isChanged = await _validateEmailChange();
|
||||||
context: context,
|
|
||||||
emailActionType: composerArguments.value!.emailActionType,
|
|
||||||
presentationEmail: composerArguments.value!.presentationEmail,
|
|
||||||
mailboxRole: composerArguments.value!.mailboxRole
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isChanged && context.mounted) {
|
if (isChanged && context.mounted) {
|
||||||
clearFocus(context);
|
clearFocus(context);
|
||||||
@@ -2368,6 +2385,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
|
|||||||
void _setUpRequestReadReceiptForDraftEmail(Email? email) {
|
void _setUpRequestReadReceiptForDraftEmail(Email? email) {
|
||||||
if (email?.hasRequestReadReceipt == true) {
|
if (email?.hasRequestReadReceipt == true) {
|
||||||
hasRequestReadReceipt.value = true;
|
hasRequestReadReceipt.value = true;
|
||||||
|
_initEmailDraftHash();
|
||||||
} else {
|
} else {
|
||||||
_getAlwaysReadReceiptSetting();
|
_getAlwaysReadReceiptSetting();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/identities/identity.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
|
||||||
|
class SavedEmailDraft with EquatableMixin {
|
||||||
|
final String content;
|
||||||
|
final String subject;
|
||||||
|
final Set<EmailAddress> toRecipients;
|
||||||
|
final Set<EmailAddress> ccRecipients;
|
||||||
|
final Set<EmailAddress> bccRecipients;
|
||||||
|
final List<Attachment> attachments;
|
||||||
|
final Identity? identity;
|
||||||
|
final bool hasReadReceipt;
|
||||||
|
|
||||||
|
SavedEmailDraft({
|
||||||
|
required this.content,
|
||||||
|
required this.subject,
|
||||||
|
required this.toRecipients,
|
||||||
|
required this.ccRecipients,
|
||||||
|
required this.bccRecipients,
|
||||||
|
required this.attachments,
|
||||||
|
required this.identity,
|
||||||
|
required this.hasReadReceipt,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
content,
|
||||||
|
subject,
|
||||||
|
// Prevent identical Set<EmailAddress>
|
||||||
|
{0: toRecipients},
|
||||||
|
{1: ccRecipients},
|
||||||
|
{2: bccRecipients},
|
||||||
|
attachments,
|
||||||
|
identity,
|
||||||
|
hasReadReceipt
|
||||||
|
];
|
||||||
|
}
|
||||||
+1
-1
@@ -1578,7 +1578,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ dev_dependencies:
|
|||||||
|
|
||||||
http_mock_adapter: 0.4.2
|
http_mock_adapter: 0.4.2
|
||||||
|
|
||||||
|
plugin_platform_interface: 2.1.8
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
firebase_core_platform_interface: 4.6.0
|
firebase_core_platform_interface: 4.6.0
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/identities/identity.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
|
import 'package:model/email/attachment.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/model/saved_email_draft.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('saved email draft test', () {
|
||||||
|
test(
|
||||||
|
'should tag toRecipients, ccRecipients and bccRecipients in props',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
final savedEmailDraft = SavedEmailDraft(
|
||||||
|
subject: 'subject',
|
||||||
|
content: 'content',
|
||||||
|
toRecipients: {EmailAddress('to name', 'to email')},
|
||||||
|
ccRecipients: {EmailAddress('cc name', 'cc email')},
|
||||||
|
bccRecipients: {EmailAddress('bcc name', 'bcc email')},
|
||||||
|
identity: null,
|
||||||
|
attachments: [],
|
||||||
|
hasReadReceipt: false
|
||||||
|
);
|
||||||
|
|
||||||
|
// act
|
||||||
|
final props = savedEmailDraft.props;
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(props[2], equals({0: savedEmailDraft.toRecipients}));
|
||||||
|
expect(props[3], equals({1: savedEmailDraft.ccRecipients}));
|
||||||
|
expect(props[4], equals({2: savedEmailDraft.bccRecipients}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should generate different hashcode '
|
||||||
|
'when toRecipients, ccRecipients and bccRecipients are different',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
const subject = 'subject';
|
||||||
|
const content = 'content';
|
||||||
|
final recipent = EmailAddress('recipent name', 'recipent email');
|
||||||
|
final identity = Identity();
|
||||||
|
final attachments = <Attachment>[];
|
||||||
|
const hasReadReceipt = false;
|
||||||
|
|
||||||
|
final toSavedEmailDraft = SavedEmailDraft(
|
||||||
|
subject: subject,
|
||||||
|
content: content,
|
||||||
|
toRecipients: {recipent},
|
||||||
|
ccRecipients: {},
|
||||||
|
bccRecipients: {},
|
||||||
|
identity: identity,
|
||||||
|
attachments: attachments,
|
||||||
|
hasReadReceipt: hasReadReceipt
|
||||||
|
);
|
||||||
|
|
||||||
|
final ccSavedEmailDraft = SavedEmailDraft(
|
||||||
|
subject: subject,
|
||||||
|
content: content,
|
||||||
|
toRecipients: {},
|
||||||
|
ccRecipients: {recipent},
|
||||||
|
bccRecipients: {},
|
||||||
|
identity: identity,
|
||||||
|
attachments: attachments,
|
||||||
|
hasReadReceipt: hasReadReceipt
|
||||||
|
);
|
||||||
|
|
||||||
|
final bccSavedEmailDraft = SavedEmailDraft(
|
||||||
|
subject: subject,
|
||||||
|
content: content,
|
||||||
|
toRecipients: {},
|
||||||
|
ccRecipients: {},
|
||||||
|
bccRecipients: {recipent},
|
||||||
|
identity: identity,
|
||||||
|
attachments: attachments,
|
||||||
|
hasReadReceipt: hasReadReceipt
|
||||||
|
);
|
||||||
|
|
||||||
|
// act
|
||||||
|
final toProps = toSavedEmailDraft.props;
|
||||||
|
final ccProps = ccSavedEmailDraft.props;
|
||||||
|
final bccProps = bccSavedEmailDraft.props;
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(toProps.hashCode, isNot(ccProps.hashCode));
|
||||||
|
expect(ccProps.hashCode, isNot(bccProps.hashCode));
|
||||||
|
expect(bccProps.hashCode, isNot(toProps.hashCode));
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should generate different hashcode '
|
||||||
|
'when toRecipients is updated',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
final listToRecipients = {
|
||||||
|
EmailAddress('to name', 'to email')
|
||||||
|
};
|
||||||
|
final savedEmailDraft = SavedEmailDraft(
|
||||||
|
subject: 'subject',
|
||||||
|
content: 'content',
|
||||||
|
toRecipients: listToRecipients,
|
||||||
|
ccRecipients: {EmailAddress('cc name', 'cc email')},
|
||||||
|
bccRecipients: {EmailAddress('bcc name', 'bcc email')},
|
||||||
|
identity: null,
|
||||||
|
attachments: [],
|
||||||
|
hasReadReceipt: false
|
||||||
|
);
|
||||||
|
final hashCodeBeforeChange = savedEmailDraft.hashCode;
|
||||||
|
|
||||||
|
// act
|
||||||
|
listToRecipients.add(EmailAddress('to name 2', 'to email 2'));
|
||||||
|
final hashCodeAfterChange = savedEmailDraft.hashCode;
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(hashCodeBeforeChange, isNot(hashCodeAfterChange));
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should generate same hashcode '
|
||||||
|
'when all properties are the same',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
final savedEmailDraft = SavedEmailDraft(
|
||||||
|
subject: 'subject',
|
||||||
|
content: 'content',
|
||||||
|
toRecipients: {EmailAddress('to name', 'to email')},
|
||||||
|
ccRecipients: {EmailAddress('cc name', 'cc email')},
|
||||||
|
bccRecipients: {EmailAddress('bcc name', 'bcc email')},
|
||||||
|
identity: null,
|
||||||
|
attachments: [],
|
||||||
|
hasReadReceipt: false
|
||||||
|
);
|
||||||
|
|
||||||
|
final savedEmailDraft2 = SavedEmailDraft(
|
||||||
|
subject: 'subject',
|
||||||
|
content: 'content',
|
||||||
|
toRecipients: {EmailAddress('to name', 'to email')},
|
||||||
|
ccRecipients: {EmailAddress('cc name', 'cc email')},
|
||||||
|
bccRecipients: {EmailAddress('bcc name', 'bcc email')},
|
||||||
|
identity: null,
|
||||||
|
attachments: [],
|
||||||
|
hasReadReceipt: false
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(savedEmailDraft.hashCode, equals(savedEmailDraft2.hashCode));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:rich_text_composer/rich_text_composer.dart';
|
||||||
|
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||||
|
|
||||||
|
class MockWebViewPlatform extends InAppWebViewPlatform with MockPlatformInterfaceMixin {
|
||||||
|
@override
|
||||||
|
PlatformInAppWebViewWidget createPlatformInAppWebViewWidget(
|
||||||
|
PlatformInAppWebViewWidgetCreationParams params,
|
||||||
|
) => MockWebViewWidget.implementation(params);
|
||||||
|
|
||||||
|
@override
|
||||||
|
PlatformCookieManager createPlatformCookieManager(
|
||||||
|
PlatformCookieManagerCreationParams params,
|
||||||
|
) => MockPlatformCookieManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockPlatformCookieManager extends Fake implements PlatformCookieManager {
|
||||||
|
@override
|
||||||
|
Future<bool> deleteAllCookies() async {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> setCookie({
|
||||||
|
required WebUri url,
|
||||||
|
required String name,
|
||||||
|
required String value,
|
||||||
|
String path = '/',
|
||||||
|
String? domain,
|
||||||
|
int? expiresDate,
|
||||||
|
int? maxAge,
|
||||||
|
bool? isSecure,
|
||||||
|
bool? isHttpOnly,
|
||||||
|
HTTPCookieSameSitePolicy? sameSite,
|
||||||
|
PlatformInAppWebViewController? iosBelow11WebViewController,
|
||||||
|
PlatformInAppWebViewController? webViewController,
|
||||||
|
}) async {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockWebViewWidget extends PlatformInAppWebViewWidget {
|
||||||
|
MockWebViewWidget.implementation(super.params) : super.implementation();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
T controllerFromPlatform<T>(PlatformInAppWebViewController controller) {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user