feat(Label): Add depend on settings to register websocket for label

This commit is contained in:
dab246
2026-03-03 10:30:32 +07:00
committed by Dat H. Pham
parent a70a338608
commit 2e6e1fcdc8
11 changed files with 86 additions and 40 deletions
+11 -3
View File
@@ -379,9 +379,13 @@ abstract class BaseController extends GetxController
} }
} }
void injectWebSocket(Session? session, AccountId? accountId) { void injectWebSocket({
Session? session,
AccountId? accountId,
bool isLabelAvailable = false,
}) {
try { try {
log('$runtimeType::injectWebSocket:'); log('$runtimeType::injectWebSocket: isLabelAvailable is $isLabelAvailable');
requireCapability( requireCapability(
session!, session!,
accountId!, accountId!,
@@ -397,7 +401,11 @@ abstract class BaseController extends GetxController
throw WebSocketPushNotSupportedException(); throw WebSocketPushNotSupportedException();
} }
WebSocketInteractorBindings().dependencies(); WebSocketInteractorBindings().dependencies();
WebSocketController.instance.initialize(accountId: accountId, session: session); WebSocketController.instance.initialize(
accountId: accountId,
session: session,
isLabelAvailable: isLabelAvailable,
);
} catch(e) { } catch(e) {
logWarning('$runtimeType::injectWebSocket(): exception: $e'); logWarning('$runtimeType::injectWebSocket(): exception: $e');
} }
@@ -5,7 +5,6 @@ import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/patch_object.dart'; import 'package:jmap_dart_client/jmap/core/patch_object.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:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart';
import 'package:labels/labels.dart'; import 'package:labels/labels.dart';
import 'package:tmail_ui_user/features/base/mixin/batch_get_label_processing_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/batch_get_label_processing_mixin.dart';
@@ -19,8 +18,6 @@ import 'package:uuid/uuid.dart';
class LabelApi class LabelApi
with HandleSetErrorMixin, SessionMixin, BatchGetLabelProcessingMixin { with HandleSetErrorMixin, SessionMixin, BatchGetLabelProcessingMixin {
static const int _defaultMaxChanges = 128;
final HttpClient _httpClient; final HttpClient _httpClient;
final Uuid _uuid; final Uuid _uuid;
@@ -178,11 +175,7 @@ class LabelApi
processingInvocation, processingInvocation,
); );
final changesLabelMethod = ChangesLabelMethod( final changesLabelMethod = ChangesLabelMethod(accountId, sinceState);
accountId,
sinceState,
maxChanges: UnsignedInt(_defaultMaxChanges),
);
final changesLabelInvocation = final changesLabelInvocation =
jmapRequestBuilder.invocation(changesLabelMethod); jmapRequestBuilder.invocation(changesLabelMethod);
@@ -15,6 +15,7 @@ extension HandleLabelWebsocketExtension on LabelController {
currentLabelState == null || currentLabelState == null ||
currentLabelState == newState || currentLabelState == newState ||
isLabelSettingEnabled.isFalse) { isLabelSettingEnabled.isFalse) {
logWarning('HandleLabelWebsocketExtension::refreshLabelChanges: accountId or session or currentLabelState or newState or isLabelSettingEnabled is null');
return; return;
} }
@@ -337,9 +337,7 @@ class MailboxDashBoardController extends ReloadableController
int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete; int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete;
EmailSortOrderType currentSortOrder = SearchEmailFilter.defaultSortOrder; EmailSortOrderType currentSortOrder = SearchEmailFilter.defaultSortOrder;
PaywallController? paywallController; PaywallController? paywallController;
Worker? advancedSearchVisibleWorker; final workerObxVariables = <Worker>[];
Worker? searchInputFocusWorker;
Worker? _downloadUIActionWorker;
final StreamController<Either<Failure, Success>> progressStateController = final StreamController<Either<Failure, Success>> progressStateController =
StreamController<Either<Failure, Success>>.broadcast(); StreamController<Either<Failure, Success>>.broadcast();
@@ -394,6 +392,7 @@ class MailboxDashBoardController extends ReloadableController
_registerDeepLinks(); _registerDeepLinks();
} }
_registerStreamListener(); _registerStreamListener();
registerLabelReactiveObxListener();
BackButtonInterceptor.add(onBackButtonInterceptor, name: AppRoutes.dashboard); BackButtonInterceptor.add(onBackButtonInterceptor, name: AppRoutes.dashboard);
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
await ApplicationManager().initUserAgent(); await ApplicationManager().initUserAgent();
@@ -804,7 +803,7 @@ class MailboxDashBoardController extends ReloadableController
} }
void _registerDownloadUIActionListener() { void _registerDownloadUIActionListener() {
_downloadUIActionWorker = ever( workerObxVariables.add(ever(
downloadController.downloadUIAction, downloadController.downloadUIAction,
(action) { (action) {
if (action is OpenComposerFromMailtoLinkAction) { if (action is OpenComposerFromMailtoLinkAction) {
@@ -812,7 +811,7 @@ class MailboxDashBoardController extends ReloadableController
downloadController.clearDownloadUIAction(); downloadController.clearDownloadUIAction();
} }
}, },
); ));
} }
Future<void> _handleClickNotificationOnAndroidInTerminated() async { Future<void> _handleClickNotificationOnAndroidInTerminated() async {
@@ -895,7 +894,6 @@ class MailboxDashBoardController extends ReloadableController
injectAutoCompleteBindings(session, currentAccountId); injectAutoCompleteBindings(session, currentAccountId);
injectRuleFilterBindings(session, currentAccountId); injectRuleFilterBindings(session, currentAccountId);
injectVacationBindings(session, currentAccountId); injectVacationBindings(session, currentAccountId);
injectWebSocket(session, currentAccountId);
injectPreferencesBindings(); injectPreferencesBindings();
injectAIScribeBindings(session, currentAccountId); injectAIScribeBindings(session, currentAccountId);
if (PlatformInfo.isMobile) { if (PlatformInfo.isMobile) {
@@ -921,6 +919,8 @@ class MailboxDashBoardController extends ReloadableController
if (isLabelCapabilitySupported) { if (isLabelCapabilitySupported) {
labelController.checkLabelSettingState(session, currentAccountId); labelController.checkLabelSettingState(session, currentAccountId);
} else {
injectWebSocket(session: session, accountId: currentAccountId);
} }
} }
@@ -3420,11 +3420,17 @@ class MailboxDashBoardController extends ReloadableController
bool get isEmailListDisplayed => bool get isEmailListDisplayed =>
dashboardRoute.value == DashboardRoutes.thread; dashboardRoute.value == DashboardRoutes.thread;
void _disposeWorkerObxVariables() {
for (var worker in workerObxVariables) {
worker.dispose();
}
workerObxVariables.clear();
}
@override @override
void onClose() { void onClose() {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
listSearchFilterScrollController?.dispose(); listSearchFilterScrollController?.dispose();
disposeReactiveObxVariableListener();
} }
if (PlatformInfo.isIOS) { if (PlatformInfo.isIOS) {
_iosNotificationManager?.dispose(); _iosNotificationManager?.dispose();
@@ -3453,8 +3459,7 @@ class MailboxDashBoardController extends ReloadableController
twakeAppManager.setHasComposer(false); twakeAppManager.setHasComposer(false);
paywallController?.onClose(); paywallController?.onClose();
paywallController = null; paywallController = null;
_downloadUIActionWorker?.dispose(); _disposeWorkerObxVariables();
_downloadUIActionWorker = null;
super.onClose(); super.onClose();
} }
} }
@@ -8,15 +8,15 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/action/thread_
extension HandleReactiveObxVariableExtension on MailboxDashBoardController { extension HandleReactiveObxVariableExtension on MailboxDashBoardController {
void registerReactiveObxVariableListener() { void registerReactiveObxVariableListener() {
advancedSearchVisibleWorker = ever( workerObxVariables.add(ever(
searchController.isAdvancedSearchViewOpen, searchController.isAdvancedSearchViewOpen,
_onAdvancedSearchVisibleChanged _onAdvancedSearchVisibleChanged
); ));
searchInputFocusWorker = ever( workerObxVariables.add(ever(
searchController.isSearchInputFocused, searchController.isSearchInputFocused,
onSearchInputFocusChanged onSearchInputFocusChanged
); ));
} }
void _onAdvancedSearchVisibleChanged(bool visible) { void _onAdvancedSearchVisibleChanged(bool visible) {
@@ -52,11 +52,4 @@ extension HandleReactiveObxVariableExtension on MailboxDashBoardController {
dispatchAction(dashboardAction); dispatchAction(dashboardAction);
} }
void disposeReactiveObxVariableListener() {
advancedSearchVisibleWorker?.dispose();
advancedSearchVisibleWorker = null;
searchInputFocusWorker?.dispose();
searchInputFocusWorker = null;
}
} }
@@ -1,3 +1,4 @@
import 'package:core/utils/app_logger.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
@@ -15,4 +16,22 @@ extension HandleLogicLabelExtension on MailboxDashBoardController {
return labelController.isLabelSettingEnabled.isTrue && return labelController.isLabelSettingEnabled.isTrue &&
isLabelCapabilitySupported; isLabelCapabilitySupported;
} }
void registerLabelReactiveObxListener() {
workerObxVariables.add(
ever(
labelController.isLabelSettingEnabled,
_onLabelSettingEnabledChanged,
),
);
}
void _onLabelSettingEnabledChanged(bool isEnabled) {
log('$runtimeType::_onLabelSettingEnabledChanged: isEnabled is $isEnabled');
injectWebSocket(
session: sessionCurrent,
accountId: accountId.value,
isLabelAvailable: isEnabled,
);
}
} }
@@ -41,8 +41,19 @@ class WebSocketController extends PushBaseController {
NetworkConnectionController? _networkConnectionController; NetworkConnectionController? _networkConnectionController;
StreamSubscription<ConnectivityResult>? _connectivitySubscription; StreamSubscription<ConnectivityResult>? _connectivitySubscription;
static final List<TypeName> _mailTypePushSupported = [
TypeName.emailType,
TypeName.mailboxType,
];
static final List<TypeName> _labelTypePushSupported = [
TypeName.emailType,
TypeName.mailboxType,
TypeName.labelType,
];
int _retryRemained = 3; int _retryRemained = 3;
bool _isConnecting = false; bool _isConnecting = false;
bool _isLabelAvailable = false;
WebSocketChannel? _webSocketChannel; WebSocketChannel? _webSocketChannel;
Timer? _webSocketPingTimer; Timer? _webSocketPingTimer;
StreamSubscription? _webSocketSubscription; StreamSubscription? _webSocketSubscription;
@@ -72,10 +83,14 @@ class WebSocketController extends PushBaseController {
} }
@override @override
void initialize({AccountId? accountId, Session? session}) { void initialize({
log('WebSocketController::initialize:AccountId = ${accountId?.asString}'); AccountId? accountId,
Session? session,
bool isLabelAvailable = false,
}) {
log('WebSocketController::initialize:AccountId = ${accountId?.asString}, isLabelAvailable = $isLabelAvailable');
super.initialize(accountId: accountId, session: session); super.initialize(accountId: accountId, session: session);
_isLabelAvailable = isLabelAvailable;
_connectWebSocket(); _connectWebSocket();
_listenToAppLifeCycle(); _listenToAppLifeCycle();
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
@@ -184,9 +199,12 @@ class WebSocketController extends PushBaseController {
} }
void _enableWebSocketPush() { void _enableWebSocketPush() {
log('WebSocketController::_enableWebSocketPush:'); final dataTypes = _isLabelAvailable
? _labelTypePushSupported
: _mailTypePushSupported;
log('WebSocketController::_enableWebSocketPush: DataType is $dataTypes');
_webSocketChannel?.sink.add(jsonEncode(WebSocketPushEnableRequest.toJson( _webSocketChannel?.sink.add(jsonEncode(WebSocketPushEnableRequest.toJson(
dataTypes: [TypeName.emailType, TypeName.mailboxType, TypeName.labelType] dataTypes: dataTypes,
))); )));
} }
@@ -11,10 +11,14 @@ class LabelChangeListener extends ChangeListener {
LabelController? _labelController; LabelController? _labelController;
LabelChangeListener._internal() { LabelChangeListener._internal() {
_labelController = getBinding<LabelController>(); try {
if (_labelController == null) { _labelController = getBinding<LabelController>();
logWarning( if (_labelController == null) {
'LabelChangeListener::_internal(): LabelController IS NOT REGISTERED'); logWarning(
'LabelChangeListener::_internal(): LabelController IS NOT REGISTERED');
}
} catch (e) {
logWarning('LabelChangeListener::_internal(): $e');
} }
} }
@@ -404,6 +404,7 @@ void main() {
when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([]));
when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle)); when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle));
when(labelController.isLabelSettingEnabled).thenAnswer((_) => RxBool(false));
Get.put(mailboxDashboardController); Get.put(mailboxDashboardController);
mailboxDashboardController.onReady(); mailboxDashboardController.onReady();
@@ -451,6 +452,7 @@ void main() {
when(context.owner).thenReturn(BuildOwner(focusManager: FocusManager())); when(context.owner).thenReturn(BuildOwner(focusManager: FocusManager()));
when(context.mounted).thenReturn(true); when(context.mounted).thenReturn(true);
when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle)); when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle));
when(labelController.isLabelSettingEnabled).thenAnswer((_) => RxBool(false));
// expect query in search controller update as expected // expect query in search controller update as expected
mailboxDashboardController.searchEmailByQueryString(queryString); mailboxDashboardController.searchEmailByQueryString(queryString);
@@ -635,6 +637,7 @@ void main() {
when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([]));
when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle)); when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle));
when(labelController.isLabelSettingEnabled).thenAnswer((_) => RxBool(false));
Get.put(mailboxDashboardController); Get.put(mailboxDashboardController);
mailboxDashboardController.onReady(); mailboxDashboardController.onReady();
@@ -365,6 +365,7 @@ void main() {
when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([]));
when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle)); when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle));
when(labelController.isLabelSettingEnabled).thenAnswer((_) => RxBool(false));
searchController = SearchController( searchController = SearchController(
quickSearchEmailInteractor, quickSearchEmailInteractor,
@@ -394,6 +394,7 @@ void main() {
when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([]));
when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle)); when(downloadController.downloadUIAction).thenAnswer((_) => Rxn(DownloadUIAction.idle));
when(labelController.isLabelSettingEnabled).thenAnswer((_) => RxBool(false));
Get.put<MailboxDashBoardController>(mailboxDashboardController); Get.put<MailboxDashBoardController>(mailboxDashboardController);