feat: Auto sync label from web socket
This commit is contained in:
@@ -5,6 +5,7 @@ class TypeName with EquatableMixin {
|
|||||||
static const mailboxType = TypeName('Mailbox');
|
static const mailboxType = TypeName('Mailbox');
|
||||||
static const emailType = TypeName('Email');
|
static const emailType = TypeName('Email');
|
||||||
static const emailDelivery = TypeName('EmailDelivery');
|
static const emailDelivery = TypeName('EmailDelivery');
|
||||||
|
static const labelType = TypeName('Label');
|
||||||
|
|
||||||
final String value;
|
final String value;
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ import 'package:jmap_dart_client/jmap/mail/email/set/set_email_response.dart';
|
|||||||
import 'package:model/extensions/list_id_extension.dart';
|
import 'package:model/extensions/list_id_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/session_mixin.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
|
|
||||||
typedef OnGeneratePatchObjectUpdates = Map<Id, PatchObject> Function(
|
typedef OnGeneratePatchObjectUpdates = Map<Id, PatchObject> Function(
|
||||||
List<EmailId> batchIds,
|
List<EmailId> batchIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
mixin BatchSetEmailProcessingMixin on HandleSetErrorMixin, MailAPIMixin {
|
mixin BatchSetEmailProcessingMixin
|
||||||
|
on HandleSetErrorMixin, SessionMixin, MailAPIMixin {
|
||||||
Future<
|
Future<
|
||||||
({
|
({
|
||||||
List<EmailId> emailIdsSuccess,
|
List<EmailId> emailIdsSuccess,
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/mixin/batch_set_email_processing_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/batch_set_email_processing_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/session_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart';
|
import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||||
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
import 'package:tmail_ui_user/features/download/domain/model/download_source_view.dart';
|
||||||
@@ -70,11 +71,12 @@ import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
|||||||
import 'package:uri/uri.dart';
|
import 'package:uri/uri.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class EmailAPI with
|
class EmailAPI
|
||||||
HandleSetErrorMixin,
|
with
|
||||||
MailAPIMixin,
|
HandleSetErrorMixin,
|
||||||
BatchSetEmailProcessingMixin {
|
SessionMixin,
|
||||||
|
MailAPIMixin,
|
||||||
|
BatchSetEmailProcessingMixin {
|
||||||
final HttpClient _httpClient;
|
final HttpClient _httpClient;
|
||||||
final DownloadManager _downloadManager;
|
final DownloadManager _downloadManager;
|
||||||
final DioClient _dioClient;
|
final DioClient _dioClient;
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import 'package:core/presentation/extensions/either_view_state_extension.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
|
||||||
|
import 'package:labels/extensions/list_label_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/domain/state/get_label_changes_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/presentation/label_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/presentation/utils/label_utils.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/websocket/web_socket_message.dart';
|
||||||
|
|
||||||
|
extension HandleLabelWebsocketExtension on LabelController {
|
||||||
|
void refreshLabelChanges({required jmap.State newState}) {
|
||||||
|
if (accountId == null ||
|
||||||
|
session == null ||
|
||||||
|
currentLabelState == null ||
|
||||||
|
currentLabelState == newState ||
|
||||||
|
isLabelSettingEnabled.isFalse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webSocketQueueHandler?.enqueue(WebSocketMessage(newState: newState));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> handleWebSocketMessage(WebSocketMessage message) async {
|
||||||
|
try {
|
||||||
|
final refreshViewState = await getLabelChangesInteractor!
|
||||||
|
.execute(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
currentLabelState!,
|
||||||
|
)
|
||||||
|
.last;
|
||||||
|
|
||||||
|
final refreshState =
|
||||||
|
refreshViewState.foldSuccessWithResult<GetLabelChangesSuccess>();
|
||||||
|
|
||||||
|
if (refreshState is GetLabelChangesSuccess) {
|
||||||
|
await _handleGetLabelChangesSuccess(refreshState);
|
||||||
|
} else {
|
||||||
|
onDataFailureViewState(refreshState);
|
||||||
|
}
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
logWarning(
|
||||||
|
'HandleLabelWebsocketExtension::handleWebSocketMessage: Exception $e');
|
||||||
|
onError(e, stackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLabelState != null) {
|
||||||
|
webSocketQueueHandler
|
||||||
|
?.removeMessagesUpToCurrent(currentLabelState!.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleGetLabelChangesSuccess(
|
||||||
|
GetLabelChangesSuccess success,
|
||||||
|
) async {
|
||||||
|
final result = success.changesResult;
|
||||||
|
|
||||||
|
setCurrentLabelState(result.newState);
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: labels,
|
||||||
|
created: result.createdLabels,
|
||||||
|
updated: result.updatedLabels,
|
||||||
|
destroyedIds: result.destroyedLabelIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
labels.sortByAlphabetically();
|
||||||
|
labels.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart' hide State;
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/state.dart';
|
||||||
import 'package:labels/extensions/list_label_extension.dart';
|
import 'package:labels/extensions/list_label_extension.dart';
|
||||||
import 'package:labels/model/label.dart';
|
import 'package:labels/model/label.dart';
|
||||||
import 'package:labels/utils/labels_constants.dart';
|
import 'package:labels/utils/labels_constants.dart';
|
||||||
@@ -19,12 +20,15 @@ import 'package:tmail_ui_user/features/labels/domain/usecases/create_new_label_i
|
|||||||
import 'package:tmail_ui_user/features/labels/domain/usecases/edit_label_interactor.dart';
|
import 'package:tmail_ui_user/features/labels/domain/usecases/edit_label_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/labels/domain/usecases/delete_a_label_interactor.dart';
|
import 'package:tmail_ui_user/features/labels/domain/usecases/delete_a_label_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/labels/domain/usecases/get_all_label_interactor.dart';
|
import 'package:tmail_ui_user/features/labels/domain/usecases/get_all_label_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/domain/usecases/get_label_changes_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/labels/presentation/extensions/handle_label_action_type_extension.dart';
|
import 'package:tmail_ui_user/features/labels/presentation/extensions/handle_label_action_type_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/presentation/extensions/handle_label_websocket_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/labels/presentation/label_interactor_bindings.dart';
|
import 'package:tmail_ui_user/features/labels/presentation/label_interactor_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/labels/presentation/mixin/label_context_menu_mixin.dart';
|
import 'package:tmail_ui_user/features/labels/presentation/mixin/label_context_menu_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/labels/presentation/widgets/create_new_label_modal.dart';
|
import 'package:tmail_ui_user/features/labels/presentation/widgets/create_new_label_modal.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/state/get_label_setting_state.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/state/get_label_setting_state.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_label_setting_state_interactor.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_label_setting_state_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/websocket/web_socket_queue_handler.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
import 'package:tmail_ui_user/main/exceptions/logic_exception.dart';
|
import 'package:tmail_ui_user/main/exceptions/logic_exception.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/dialog_router.dart';
|
import 'package:tmail_ui_user/main/routes/dialog_router.dart';
|
||||||
@@ -40,12 +44,26 @@ class LabelController extends BaseController with LabelContextMenuMixin {
|
|||||||
GetLabelSettingStateInteractor? _getLabelSettingStateInteractor;
|
GetLabelSettingStateInteractor? _getLabelSettingStateInteractor;
|
||||||
EditLabelInteractor? _editLabelInteractor;
|
EditLabelInteractor? _editLabelInteractor;
|
||||||
DeleteALabelInteractor? _deleteALabelInteractor;
|
DeleteALabelInteractor? _deleteALabelInteractor;
|
||||||
|
GetLabelChangesInteractor? _getLabelChangesInteractor;
|
||||||
|
|
||||||
|
WebSocketQueueHandler? _webSocketQueueHandler;
|
||||||
|
State? _currentLabelState;
|
||||||
|
AccountId? _accountId;
|
||||||
|
Session? _session;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
_initWebSocketQueueHandler();
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
bool isLabelCapabilitySupported(Session session, AccountId accountId) {
|
bool isLabelCapabilitySupported(Session session, AccountId accountId) {
|
||||||
return LabelsConstants.labelsCapability.isSupported(session, accountId);
|
return LabelsConstants.labelsCapability.isSupported(session, accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkLabelSettingState(AccountId accountId) {
|
void checkLabelSettingState(Session session, AccountId accountId) {
|
||||||
|
_session = session;
|
||||||
|
_accountId = accountId;
|
||||||
_getLabelSettingStateInteractor =
|
_getLabelSettingStateInteractor =
|
||||||
getBinding<GetLabelSettingStateInteractor>();
|
getBinding<GetLabelSettingStateInteractor>();
|
||||||
if (_getLabelSettingStateInteractor != null) {
|
if (_getLabelSettingStateInteractor != null) {
|
||||||
@@ -66,12 +84,34 @@ class LabelController extends BaseController with LabelContextMenuMixin {
|
|||||||
_createNewLabelInteractor = getBinding<CreateNewLabelInteractor>();
|
_createNewLabelInteractor = getBinding<CreateNewLabelInteractor>();
|
||||||
_editLabelInteractor = getBinding<EditLabelInteractor>();
|
_editLabelInteractor = getBinding<EditLabelInteractor>();
|
||||||
_deleteALabelInteractor = getBinding<DeleteALabelInteractor>();
|
_deleteALabelInteractor = getBinding<DeleteALabelInteractor>();
|
||||||
|
_getLabelChangesInteractor = getBinding<GetLabelChangesInteractor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
EditLabelInteractor? get editLabelInteractor => _editLabelInteractor;
|
EditLabelInteractor? get editLabelInteractor => _editLabelInteractor;
|
||||||
|
|
||||||
DeleteALabelInteractor? get deleteALabelInteractor => _deleteALabelInteractor;
|
DeleteALabelInteractor? get deleteALabelInteractor => _deleteALabelInteractor;
|
||||||
|
|
||||||
|
GetLabelChangesInteractor? get getLabelChangesInteractor =>
|
||||||
|
_getLabelChangesInteractor;
|
||||||
|
|
||||||
|
WebSocketQueueHandler? get webSocketQueueHandler =>
|
||||||
|
_webSocketQueueHandler;
|
||||||
|
|
||||||
|
AccountId? get accountId => _accountId;
|
||||||
|
|
||||||
|
Session? get session => _session;
|
||||||
|
|
||||||
|
State? get currentLabelState => _currentLabelState;
|
||||||
|
|
||||||
|
void setCurrentLabelState(State? newState) => _currentLabelState = newState;
|
||||||
|
|
||||||
|
void _initWebSocketQueueHandler() {
|
||||||
|
_webSocketQueueHandler = WebSocketQueueHandler(
|
||||||
|
processMessageCallback: handleWebSocketMessage,
|
||||||
|
onErrorCallback: onError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void getAllLabels(AccountId accountId) {
|
void getAllLabels(AccountId accountId) {
|
||||||
if (_getAllLabelInteractor == null) return;
|
if (_getAllLabelInteractor == null) return;
|
||||||
|
|
||||||
@@ -177,6 +217,11 @@ class LabelController extends BaseController with LabelContextMenuMixin {
|
|||||||
_editLabelInteractor = null;
|
_editLabelInteractor = null;
|
||||||
_deleteALabelInteractor = null;
|
_deleteALabelInteractor = null;
|
||||||
_getLabelSettingStateInteractor = null;
|
_getLabelSettingStateInteractor = null;
|
||||||
|
_webSocketQueueHandler?.dispose();
|
||||||
|
_webSocketQueueHandler = null;
|
||||||
|
_currentLabelState = null;
|
||||||
|
_accountId = null;
|
||||||
|
_session = null;
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,4 +243,28 @@ class LabelUtils {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void applyLabelChanges({
|
||||||
|
required List<Label> currentLabels,
|
||||||
|
required List<Label> created,
|
||||||
|
required List<Label> updated,
|
||||||
|
required List<Id> destroyedIds,
|
||||||
|
}) {
|
||||||
|
final idsToRemove = {
|
||||||
|
...destroyedIds,
|
||||||
|
...updated.map((label) => label.id),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (idsToRemove.isNotEmpty) {
|
||||||
|
currentLabels.removeWhere((label) => idsToRemove.contains(label.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (created.isNotEmpty) {
|
||||||
|
currentLabels.addAll(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated.isNotEmpty) {
|
||||||
|
currentLabels.addAll(updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -920,7 +920,7 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (isLabelCapabilitySupported) {
|
if (isLabelCapabilitySupported) {
|
||||||
labelController.checkLabelSettingState(currentAccountId);
|
labelController.checkLabelSettingState(session, currentAccountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2094,8 +2094,10 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
getServerSetting();
|
getServerSetting();
|
||||||
spamReportController.getSpamReportStateAction();
|
spamReportController.getSpamReportStateAction();
|
||||||
loadAIScribeConfig();
|
loadAIScribeConfig();
|
||||||
if (isLabelCapabilitySupported && accountId.value != null) {
|
if (isLabelCapabilitySupported &&
|
||||||
labelController.checkLabelSettingState(accountId.value!);
|
accountId.value != null &&
|
||||||
|
sessionCurrent != null) {
|
||||||
|
labelController.checkLabelSettingState(sessionCurrent!, accountId.value!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2174,8 +2176,10 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
getServerSetting();
|
getServerSetting();
|
||||||
spamReportController.getSpamReportStateAction();
|
spamReportController.getSpamReportStateAction();
|
||||||
loadAIScribeConfig();
|
loadAIScribeConfig();
|
||||||
if (isLabelCapabilitySupported && accountId.value != null) {
|
if (isLabelCapabilitySupported &&
|
||||||
labelController.checkLabelSettingState(accountId.value!);
|
accountId.value != null &&
|
||||||
|
sessionCurrent != null) {
|
||||||
|
labelController.checkLabelSettingState(sessionCurrent!, accountId.value!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
@@ -84,6 +84,35 @@ class StoreMailboxStateToRefreshAction extends PushNotificationStateChangeAction
|
|||||||
this.userName
|
this.userName
|
||||||
) : super(typeName, newState);
|
) : super(typeName, newState);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [typeName, newState, accountId, userName];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SynchronizeLabelOnForegroundAction
|
||||||
|
extends PushNotificationStateChangeAction {
|
||||||
|
final AccountId accountId;
|
||||||
|
|
||||||
|
SynchronizeLabelOnForegroundAction(
|
||||||
|
TypeName typeName,
|
||||||
|
jmap.State newState,
|
||||||
|
this.accountId,
|
||||||
|
) : super(typeName, newState);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [typeName, newState, accountId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class StoreLabelStateToRefreshAction extends PushNotificationStateChangeAction {
|
||||||
|
final AccountId accountId;
|
||||||
|
final UserName userName;
|
||||||
|
|
||||||
|
StoreLabelStateToRefreshAction(
|
||||||
|
TypeName typeName,
|
||||||
|
jmap.State newState,
|
||||||
|
this.accountId,
|
||||||
|
this.userName,
|
||||||
|
) : super(typeName, newState);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [typeName, newState, accountId, userName];
|
List<Object?> get props => [typeName, newState, accountId, userName];
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ import 'package:tmail_ui_user/features/push_notification/presentation/controller
|
|||||||
import 'package:tmail_ui_user/features/push_notification/presentation/controller/push_base_controller.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/controller/push_base_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/extensions/state_change_extension.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/extensions/state_change_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/label_change_listener.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_service.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_service.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
|
||||||
@@ -195,6 +196,7 @@ class FcmMessageController extends PushBaseController {
|
|||||||
userName,
|
userName,
|
||||||
emailChangeListener: EmailChangeListener.instance,
|
emailChangeListener: EmailChangeListener.instance,
|
||||||
mailboxChangeListener: MailboxChangeListener.instance,
|
mailboxChangeListener: MailboxChangeListener.instance,
|
||||||
|
labelChangeListener: LabelChangeListener.instance,
|
||||||
isForeground: false,
|
isForeground: false,
|
||||||
session: session);
|
session: session);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
|
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/action/push_notification_state_change_action.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/action/push_notification_state_change_action.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/label_change_listener.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
||||||
|
|
||||||
abstract class PushBaseController {
|
abstract class PushBaseController {
|
||||||
@@ -51,7 +52,8 @@ abstract class PushBaseController {
|
|||||||
bool isForeground = true,
|
bool isForeground = true,
|
||||||
Session? session,
|
Session? session,
|
||||||
required EmailChangeListener emailChangeListener,
|
required EmailChangeListener emailChangeListener,
|
||||||
required MailboxChangeListener mailboxChangeListener
|
required MailboxChangeListener mailboxChangeListener,
|
||||||
|
required LabelChangeListener labelChangeListener,
|
||||||
}) {
|
}) {
|
||||||
log('PushBaseController::mappingTypeStateToAction():mapTypeState: $mapTypeState');
|
log('PushBaseController::mappingTypeStateToAction():mapTypeState: $mapTypeState');
|
||||||
final listTypeName = mapTypeState.keys
|
final listTypeName = mapTypeState.keys
|
||||||
@@ -81,6 +83,22 @@ abstract class PushBaseController {
|
|||||||
if (listMailboxActions.isNotEmpty) {
|
if (listMailboxActions.isNotEmpty) {
|
||||||
mailboxChangeListener.dispatchActions(listMailboxActions);
|
mailboxChangeListener.dispatchActions(listMailboxActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final labelActions = listTypeName
|
||||||
|
.where((typeName) => typeName == TypeName.labelType)
|
||||||
|
.map((typeName) => _toPushNotificationAction(
|
||||||
|
typeName,
|
||||||
|
accountId,
|
||||||
|
userName,
|
||||||
|
mapTypeState,
|
||||||
|
isForeground,
|
||||||
|
))
|
||||||
|
.nonNulls
|
||||||
|
.toList();
|
||||||
|
log('PushBaseController::mappingTypeStateToAction():LabelActions: $labelActions');
|
||||||
|
if (labelActions.isNotEmpty) {
|
||||||
|
labelChangeListener.dispatchActions(labelActions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PushNotificationStateChangeAction? _toPushNotificationAction(
|
PushNotificationStateChangeAction? _toPushNotificationAction(
|
||||||
@@ -106,6 +124,15 @@ abstract class PushBaseController {
|
|||||||
return isForeground
|
return isForeground
|
||||||
? SynchronizeMailboxOnForegroundAction(typeName, newState, accountId)
|
? SynchronizeMailboxOnForegroundAction(typeName, newState, accountId)
|
||||||
: StoreMailboxStateToRefreshAction(typeName, newState, accountId, userName);
|
: StoreMailboxStateToRefreshAction(typeName, newState, accountId, userName);
|
||||||
|
case TypeName.labelType:
|
||||||
|
return isForeground
|
||||||
|
? SynchronizeLabelOnForegroundAction(typeName, newState, accountId)
|
||||||
|
: StoreLabelStateToRefreshAction(
|
||||||
|
typeName,
|
||||||
|
newState,
|
||||||
|
accountId,
|
||||||
|
userName,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import 'package:tmail_ui_user/features/push_notification/domain/usecases/connect
|
|||||||
import 'package:tmail_ui_user/features/push_notification/presentation/controller/push_base_controller.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/controller/push_base_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/extensions/state_change_extension.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/extensions/state_change_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/label_change_listener.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
@@ -185,7 +186,7 @@ class WebSocketController extends PushBaseController {
|
|||||||
void _enableWebSocketPush() {
|
void _enableWebSocketPush() {
|
||||||
log('WebSocketController::_enableWebSocketPush:');
|
log('WebSocketController::_enableWebSocketPush:');
|
||||||
_webSocketChannel?.sink.add(jsonEncode(WebSocketPushEnableRequest.toJson(
|
_webSocketChannel?.sink.add(jsonEncode(WebSocketPushEnableRequest.toJson(
|
||||||
dataTypes: [TypeName.emailType, TypeName.mailboxType]
|
dataTypes: [TypeName.emailType, TypeName.mailboxType, TypeName.labelType]
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +248,7 @@ class WebSocketController extends PushBaseController {
|
|||||||
accountId!,
|
accountId!,
|
||||||
emailChangeListener: EmailChangeListener.instance,
|
emailChangeListener: EmailChangeListener.instance,
|
||||||
mailboxChangeListener: MailboxChangeListener.instance,
|
mailboxChangeListener: MailboxChangeListener.instance,
|
||||||
|
labelChangeListener: LabelChangeListener.instance,
|
||||||
session!.username,
|
session!.username,
|
||||||
session: session,
|
session: session,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
|
||||||
|
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/presentation/extensions/handle_label_websocket_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/presentation/label_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/action/push_notification_state_change_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/change_listener.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
|
class LabelChangeListener extends ChangeListener {
|
||||||
|
LabelController? _labelController;
|
||||||
|
|
||||||
|
LabelChangeListener._internal() {
|
||||||
|
try {
|
||||||
|
_labelController = getBinding<LabelController>();
|
||||||
|
} catch (e) {
|
||||||
|
logError(
|
||||||
|
'LabelChangeListener::_internal(): IS NOT REGISTERED: ${e.toString()}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final LabelChangeListener _instance = LabelChangeListener._internal();
|
||||||
|
|
||||||
|
static LabelChangeListener get instance => _instance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispatchActions(List<Action> actions) {
|
||||||
|
for (var action in actions) {
|
||||||
|
if (action is SynchronizeLabelOnForegroundAction) {
|
||||||
|
_synchronizeLabelOnForegroundAction(action.newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _synchronizeLabelOnForegroundAction(jmap.State newState) {
|
||||||
|
_labelController?.refreshLabelChanges(newState: newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,13 +26,14 @@ import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
|||||||
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet_get_method.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet_get_method.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet_get_response.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet_get_response.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/session_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_id_extension.dart';
|
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_id_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
|
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
|
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/domain/model/search_emails_response.dart';
|
import 'package:tmail_ui_user/features/thread/domain/model/search_emails_response.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
|
|
||||||
class ThreadAPI with HandleSetErrorMixin, MailAPIMixin {
|
class ThreadAPI with HandleSetErrorMixin, SessionMixin, MailAPIMixin {
|
||||||
|
|
||||||
final HttpClient httpClient;
|
final HttpClient httpClient;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/mixin/batch_set_email_processing_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/batch_set_email_processing_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/session_mixin.dart';
|
||||||
|
|
||||||
import '../../../fixtures/account_fixtures.dart';
|
import '../../../fixtures/account_fixtures.dart';
|
||||||
import '../../../fixtures/session_fixtures.dart';
|
import '../../../fixtures/session_fixtures.dart';
|
||||||
@@ -55,7 +56,10 @@ class ManualMockHttpClient implements HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TestBatchSetEmailProcessing
|
class TestBatchSetEmailProcessing
|
||||||
with HandleSetErrorMixin, MailAPIMixin, BatchSetEmailProcessingMixin {}
|
with HandleSetErrorMixin,
|
||||||
|
SessionMixin,
|
||||||
|
MailAPIMixin,
|
||||||
|
BatchSetEmailProcessingMixin {}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('BatchSetEmailProcessingMixin test', () {
|
group('BatchSetEmailProcessingMixin test', () {
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart';
|
|||||||
import 'package:model/error_type_handler/set_method_error_handler_mixin.dart';
|
import 'package:model/error_type_handler/set_method_error_handler_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/session_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
|
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
|
||||||
|
|
||||||
import '../../../fixtures/account_fixtures.dart';
|
import '../../../fixtures/account_fixtures.dart';
|
||||||
import '../../../fixtures/session_fixtures.dart';
|
import '../../../fixtures/session_fixtures.dart';
|
||||||
|
|
||||||
class TestMailApiMixin with HandleSetErrorMixin, MailAPIMixin {
|
class TestMailApiMixin with HandleSetErrorMixin, SessionMixin, MailAPIMixin {
|
||||||
@override
|
@override
|
||||||
void handleSetErrors({
|
void handleSetErrors({
|
||||||
SetMethodErrors? notDestroyedError,
|
SetMethodErrors? notDestroyedError,
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
|
import 'package:labels/model/label.dart';
|
||||||
|
import 'package:tmail_ui_user/features/labels/presentation/utils/label_utils.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('LabelUtils.applyLabelChanges', () {
|
||||||
|
test('should add new labels when created list is not empty', () {
|
||||||
|
final currentLabels = <Label>[];
|
||||||
|
final newLabel = Label(id: Id('1'), displayName: 'Work');
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [newLabel],
|
||||||
|
updated: [],
|
||||||
|
destroyedIds: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.first.id?.value, '1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should update existing label when an updated label with the same ID is provided',
|
||||||
|
() {
|
||||||
|
final oldLabel = Label(id: Id('1'), displayName: 'Old Name');
|
||||||
|
final currentLabels = <Label>[oldLabel];
|
||||||
|
|
||||||
|
final updatedLabel = Label(id: Id('1'), displayName: 'New Name');
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [updatedLabel],
|
||||||
|
destroyedIds: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.first.displayName, 'New Name');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove labels when their ID is present in destroyedIds', () {
|
||||||
|
final currentLabels = <Label>[
|
||||||
|
Label(id: Id('1'), displayName: 'To Delete'),
|
||||||
|
Label(id: Id('2'), displayName: 'Keep Me'),
|
||||||
|
];
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [],
|
||||||
|
destroyedIds: [Id('1')],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.any((l) => l.id?.value == '1'), isFalse);
|
||||||
|
expect(currentLabels.any((l) => l.id?.value == '2'), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle create, update, and destroy operations simultaneously',
|
||||||
|
() {
|
||||||
|
final currentLabels = <Label>[
|
||||||
|
Label(id: Id('1'), displayName: 'Old'),
|
||||||
|
Label(id: Id('2'), displayName: 'Remove'),
|
||||||
|
];
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [Label(id: Id('3'), displayName: 'New')],
|
||||||
|
updated: [Label(id: Id('1'), displayName: 'Updated')],
|
||||||
|
destroyedIds: [Id('2')],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 2);
|
||||||
|
expect(currentLabels.any((l) => l.displayName == 'Updated'), isTrue);
|
||||||
|
expect(currentLabels.any((l) => l.displayName == 'New'), isTrue);
|
||||||
|
expect(currentLabels.any((l) => l.id?.value == '2'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should do nothing when all change lists are empty', () {
|
||||||
|
final currentLabels = <Label>[
|
||||||
|
Label(id: Id('1'), displayName: 'Existing'),
|
||||||
|
];
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [],
|
||||||
|
destroyedIds: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.first.displayName, 'Existing');
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should handle destroying IDs that do not exist in currentLabels gracefully',
|
||||||
|
() {
|
||||||
|
final currentLabels = <Label>[
|
||||||
|
Label(id: Id('1'), displayName: 'Keep Me'),
|
||||||
|
];
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [],
|
||||||
|
destroyedIds: [Id('999')],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.first.id?.value, '1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should treat updated labels as new additions if they do not exist in currentLabels (Upsert behavior)',
|
||||||
|
() {
|
||||||
|
final currentLabels = <Label>[];
|
||||||
|
final labelToUpdate = Label(id: Id('1'), displayName: 'Ghost Label');
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [labelToUpdate],
|
||||||
|
destroyedIds: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.first.displayName, 'Ghost Label');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should move updated labels to the end of the list', () {
|
||||||
|
final currentLabels = <Label>[
|
||||||
|
Label(id: Id('1'), displayName: 'A'),
|
||||||
|
Label(id: Id('2'), displayName: 'B'),
|
||||||
|
Label(id: Id('3'), displayName: 'C'),
|
||||||
|
];
|
||||||
|
|
||||||
|
final updatedLabelA = Label(id: Id('1'), displayName: 'A Updated');
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [updatedLabelA],
|
||||||
|
destroyedIds: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 3);
|
||||||
|
expect(currentLabels[0].id?.value, '2');
|
||||||
|
expect(currentLabels[1].id?.value, '3');
|
||||||
|
expect(currentLabels[2].id?.value, '1');
|
||||||
|
expect(currentLabels[2].displayName, 'A Updated');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should prioritize update over destroy if an ID appears in both lists',
|
||||||
|
() {
|
||||||
|
final currentLabels = <Label>[
|
||||||
|
Label(id: Id('1'), displayName: 'Original'),
|
||||||
|
];
|
||||||
|
|
||||||
|
final updatedLabel = Label(id: Id('1'), displayName: 'Revived');
|
||||||
|
|
||||||
|
LabelUtils.applyLabelChanges(
|
||||||
|
currentLabels: currentLabels,
|
||||||
|
created: [],
|
||||||
|
updated: [updatedLabel],
|
||||||
|
destroyedIds: [Id('1')],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(currentLabels.length, 1);
|
||||||
|
expect(currentLabels.first.displayName, 'Revived');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
+92
-6
@@ -11,6 +11,7 @@ import 'package:mockito/mockito.dart';
|
|||||||
import 'package:tmail_ui_user/features/push_notification/presentation/action/push_notification_state_change_action.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/action/push_notification_state_change_action.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/controller/push_base_controller.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/controller/push_base_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/email_change_listener.dart';
|
||||||
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/label_change_listener.dart';
|
||||||
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
|
||||||
|
|
||||||
import 'push_base_controller_test.mocks.dart';
|
import 'push_base_controller_test.mocks.dart';
|
||||||
@@ -26,6 +27,7 @@ class TestPushController extends PushBaseController {
|
|||||||
@GenerateNiceMocks([
|
@GenerateNiceMocks([
|
||||||
MockSpec<EmailChangeListener>(),
|
MockSpec<EmailChangeListener>(),
|
||||||
MockSpec<MailboxChangeListener>(),
|
MockSpec<MailboxChangeListener>(),
|
||||||
|
MockSpec<LabelChangeListener>(),
|
||||||
])
|
])
|
||||||
void main() {
|
void main() {
|
||||||
final accountId = AccountId(Id('accountId'));
|
final accountId = AccountId(Id('accountId'));
|
||||||
@@ -35,6 +37,7 @@ void main() {
|
|||||||
group('mappingTypeStateToAction:', () {
|
group('mappingTypeStateToAction:', () {
|
||||||
final emailChangeListener = MockEmailChangeListener();
|
final emailChangeListener = MockEmailChangeListener();
|
||||||
final mailboxChangeListener = MockMailboxChangeListener();
|
final mailboxChangeListener = MockMailboxChangeListener();
|
||||||
|
final labelChangeListener = MockLabelChangeListener();
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'should call emailChangeListener.dispatchActions with SynchronizeEmailOnForegroundAction '
|
'should call emailChangeListener.dispatchActions with SynchronizeEmailOnForegroundAction '
|
||||||
@@ -53,7 +56,8 @@ void main() {
|
|||||||
userName,
|
userName,
|
||||||
isForeground: true,
|
isForeground: true,
|
||||||
emailChangeListener: emailChangeListener,
|
emailChangeListener: emailChangeListener,
|
||||||
mailboxChangeListener: mailboxChangeListener
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -68,6 +72,7 @@ void main() {
|
|||||||
]),
|
]),
|
||||||
).called(1);
|
).called(1);
|
||||||
verifyNever(mailboxChangeListener.dispatchActions(any));
|
verifyNever(mailboxChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(labelChangeListener.dispatchActions(any));
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -87,7 +92,8 @@ void main() {
|
|||||||
userName,
|
userName,
|
||||||
isForeground: false,
|
isForeground: false,
|
||||||
emailChangeListener: emailChangeListener,
|
emailChangeListener: emailChangeListener,
|
||||||
mailboxChangeListener: mailboxChangeListener
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -103,6 +109,7 @@ void main() {
|
|||||||
]),
|
]),
|
||||||
).called(1);
|
).called(1);
|
||||||
verifyNever(mailboxChangeListener.dispatchActions(any));
|
verifyNever(mailboxChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(labelChangeListener.dispatchActions(any));
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -122,12 +129,14 @@ void main() {
|
|||||||
userName,
|
userName,
|
||||||
isForeground: true,
|
isForeground: true,
|
||||||
emailChangeListener: emailChangeListener,
|
emailChangeListener: emailChangeListener,
|
||||||
mailboxChangeListener: mailboxChangeListener
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
verifyNever(emailChangeListener.dispatchActions(any));
|
verifyNever(emailChangeListener.dispatchActions(any));
|
||||||
verifyNever(mailboxChangeListener.dispatchActions(any));
|
verifyNever(mailboxChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(labelChangeListener.dispatchActions(any));
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -147,7 +156,8 @@ void main() {
|
|||||||
userName,
|
userName,
|
||||||
isForeground: false,
|
isForeground: false,
|
||||||
emailChangeListener: emailChangeListener,
|
emailChangeListener: emailChangeListener,
|
||||||
mailboxChangeListener: mailboxChangeListener
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -163,6 +173,7 @@ void main() {
|
|||||||
]),
|
]),
|
||||||
).called(1);
|
).called(1);
|
||||||
verifyNever(mailboxChangeListener.dispatchActions(any));
|
verifyNever(mailboxChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(labelChangeListener.dispatchActions(any));
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -182,7 +193,8 @@ void main() {
|
|||||||
userName,
|
userName,
|
||||||
isForeground: true,
|
isForeground: true,
|
||||||
emailChangeListener: emailChangeListener,
|
emailChangeListener: emailChangeListener,
|
||||||
mailboxChangeListener: mailboxChangeListener
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -196,6 +208,7 @@ void main() {
|
|||||||
]),
|
]),
|
||||||
).called(1);
|
).called(1);
|
||||||
verifyNever(emailChangeListener.dispatchActions(any));
|
verifyNever(emailChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(labelChangeListener.dispatchActions(any));
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -215,7 +228,8 @@ void main() {
|
|||||||
userName,
|
userName,
|
||||||
isForeground: false,
|
isForeground: false,
|
||||||
emailChangeListener: emailChangeListener,
|
emailChangeListener: emailChangeListener,
|
||||||
mailboxChangeListener: mailboxChangeListener
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -230,6 +244,78 @@ void main() {
|
|||||||
]),
|
]),
|
||||||
).called(1);
|
).called(1);
|
||||||
verifyNever(emailChangeListener.dispatchActions(any));
|
verifyNever(emailChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(labelChangeListener.dispatchActions(any));
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should call labelChangeListener.dispatchActions with SynchronizeLabelOnForegroundAction '
|
||||||
|
'when mapTypeState contains labelType '
|
||||||
|
'and isForeground is true',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
final state = State('some-state');
|
||||||
|
final mapTypeState = {TypeName.labelType.value: state.value};
|
||||||
|
|
||||||
|
// act
|
||||||
|
final pushBaseController = TestPushController();
|
||||||
|
pushBaseController.mappingTypeStateToAction(
|
||||||
|
mapTypeState,
|
||||||
|
accountId,
|
||||||
|
userName,
|
||||||
|
isForeground: true,
|
||||||
|
emailChangeListener: emailChangeListener,
|
||||||
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
verify(
|
||||||
|
labelChangeListener.dispatchActions([
|
||||||
|
SynchronizeLabelOnForegroundAction(
|
||||||
|
TypeName.labelType,
|
||||||
|
state,
|
||||||
|
accountId,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
).called(1);
|
||||||
|
verifyNever(emailChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(mailboxChangeListener.dispatchActions(any));
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should call labelChangeListener.dispatchActions with StoreLabelStateToRefreshAction '
|
||||||
|
'when mapTypeState contains labelType '
|
||||||
|
'and isForeground is false',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
final state = State('some-state');
|
||||||
|
final mapTypeState = {TypeName.labelType.value: state.value};
|
||||||
|
|
||||||
|
// act
|
||||||
|
final pushBaseController = TestPushController();
|
||||||
|
pushBaseController.mappingTypeStateToAction(
|
||||||
|
mapTypeState,
|
||||||
|
accountId,
|
||||||
|
userName,
|
||||||
|
isForeground: false,
|
||||||
|
emailChangeListener: emailChangeListener,
|
||||||
|
mailboxChangeListener: mailboxChangeListener,
|
||||||
|
labelChangeListener: labelChangeListener,
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
verify(
|
||||||
|
labelChangeListener.dispatchActions([
|
||||||
|
StoreLabelStateToRefreshAction(
|
||||||
|
TypeName.labelType,
|
||||||
|
state,
|
||||||
|
accountId,
|
||||||
|
userName,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
).called(1);
|
||||||
|
verifyNever(emailChangeListener.dispatchActions(any));
|
||||||
|
verifyNever(mailboxChangeListener.dispatchActions(any));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user