feat: Auto sync label from web socket

This commit is contained in:
dab246
2026-02-03 19:20:52 +07:00
committed by Dat H. Pham
parent c49e48ae1b
commit 9c211c05ef
17 changed files with 536 additions and 24 deletions
@@ -84,6 +84,35 @@ class StoreMailboxStateToRefreshAction extends PushNotificationStateChangeAction
this.userName
) : 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
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/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/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/services/fcm_service.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
@@ -195,6 +196,7 @@ class FcmMessageController extends PushBaseController {
userName,
emailChangeListener: EmailChangeListener.instance,
mailboxChangeListener: MailboxChangeListener.instance,
labelChangeListener: LabelChangeListener.instance,
isForeground: false,
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/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/label_change_listener.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/listener/mailbox_change_listener.dart';
abstract class PushBaseController {
@@ -51,7 +52,8 @@ abstract class PushBaseController {
bool isForeground = true,
Session? session,
required EmailChangeListener emailChangeListener,
required MailboxChangeListener mailboxChangeListener
required MailboxChangeListener mailboxChangeListener,
required LabelChangeListener labelChangeListener,
}) {
log('PushBaseController::mappingTypeStateToAction():mapTypeState: $mapTypeState');
final listTypeName = mapTypeState.keys
@@ -81,6 +83,22 @@ abstract class PushBaseController {
if (listMailboxActions.isNotEmpty) {
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(
@@ -106,6 +124,15 @@ abstract class PushBaseController {
return isForeground
? SynchronizeMailboxOnForegroundAction(typeName, newState, accountId)
: StoreMailboxStateToRefreshAction(typeName, newState, accountId, userName);
case TypeName.labelType:
return isForeground
? SynchronizeLabelOnForegroundAction(typeName, newState, accountId)
: StoreLabelStateToRefreshAction(
typeName,
newState,
accountId,
userName,
);
}
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/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/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/utils/fcm_utils.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -185,7 +186,7 @@ class WebSocketController extends PushBaseController {
void _enableWebSocketPush() {
log('WebSocketController::_enableWebSocketPush:');
_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!,
emailChangeListener: EmailChangeListener.instance,
mailboxChangeListener: MailboxChangeListener.instance,
labelChangeListener: LabelChangeListener.instance,
session!.username,
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);
}
}