diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index faa9d613d6..e891df52c3 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -17,6 +17,7 @@ import flutter_local_notifications GeneratedPluginRegistrant.register(with: self) createNotificationInteractionChannel() + clearApplicationNotification() if let payload = launchOptions?[.remoteNotification] as? [AnyHashable : Any], let emailId = payload[JmapConstants.EMAIL_ID] as? String, @@ -68,7 +69,7 @@ import flutter_local_notifications } override func applicationDidBecomeActive(_ application: UIApplication) { - removeAppBadger() + clearApplicationNotification() } private func handleEmailAndress(open url: URL) -> URL? { @@ -126,6 +127,13 @@ import flutter_local_notifications } return false } + + private func clearApplicationNotification() { + removeAppBadger() + let userNotificationCenter = UNUserNotificationCenter.current() + userNotificationCenter.removeAllDeliveredNotifications() + userNotificationCenter.removeAllPendingNotificationRequests() + } } extension AppDelegate { diff --git a/ios/TwakeMailNSE/NotificationService.swift b/ios/TwakeMailNSE/NotificationService.swift index e61f93521a..c14a9833ff 100644 --- a/ios/TwakeMailNSE/NotificationService.swift +++ b/ios/TwakeMailNSE/NotificationService.swift @@ -59,7 +59,7 @@ class NotificationService: UNNotificationServiceExtension { return self.notify() } - guard let oldEmailDeliveryState = keychainSharingSession.emailDeliveryState ?? keychainSharingSession.emailState, + guard let oldEmailDeliveryState = keychainSharingSession.emailDeliveryState, newEmailDeliveryState != oldEmailDeliveryState else { self.showDefaultNotification(message: NSLocalizedString(self.newEmailDefaultMessageKey, comment: "Localizable")) return self.notify() diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 7966608a71..c8855eea86 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -126,6 +126,7 @@ import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_ import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_mailbox_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_mailbox_state_to_refresh_interactor.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/controller/fcm_message_controller.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/controller/web_socket_controller.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_manager.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_service.dart'; @@ -2971,6 +2972,7 @@ class MailboxDashBoardController extends ReloadableController mapMailboxById = {}; mapDefaultMailboxIdByRole = {}; WebSocketController.instance.onClose(); + FcmMessageController.instance.onClose(); _currentEmailState = null; super.onClose(); } diff --git a/lib/features/push_notification/presentation/controller/fcm_message_controller.dart b/lib/features/push_notification/presentation/controller/fcm_message_controller.dart index 5782f3ed59..07d115542e 100644 --- a/lib/features/push_notification/presentation/controller/fcm_message_controller.dart +++ b/lib/features/push_notification/presentation/controller/fcm_message_controller.dart @@ -6,6 +6,7 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; +import 'package:flutter/material.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/user_name.dart'; @@ -32,6 +33,7 @@ import 'package:tmail_ui_user/features/push_notification/presentation/controller 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/mailbox_change_listener.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_manager.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/main/bindings/main_bindings.dart'; @@ -47,6 +49,7 @@ class FcmMessageController extends PushBaseController { TokenOidcCacheManager? _tokenOidcCacheManager; StateCacheManager? _stateCacheManager; AuthenticationInfoCacheManager? _authenticationInfoCacheManager; + AppLifecycleListener? _appLifecycleListener; FcmMessageController._internal(); @@ -60,6 +63,24 @@ class FcmMessageController extends PushBaseController { _listenTokenStream(); _listenBackgroundMessageStream(); + LocalNotificationManager.instance.clearAllNotifications(); + _listenAppLifecycle(); + } + + @override + void onClose() { + _appLifecycleListener?.dispose(); + super.onClose(); + } + + void _listenAppLifecycle() { + _appLifecycleListener = AppLifecycleListener( + onStateChange: (appLifecycleState) { + if (appLifecycleState == AppLifecycleState.resumed) { + LocalNotificationManager.instance.clearAllNotifications(); + } + }, + ); } void _listenBackgroundMessageStream() { diff --git a/lib/features/push_notification/presentation/controller/push_base_controller.dart b/lib/features/push_notification/presentation/controller/push_base_controller.dart index d555c33a9c..a2f0494017 100644 --- a/lib/features/push_notification/presentation/controller/push_base_controller.dart +++ b/lib/features/push_notification/presentation/controller/push_base_controller.dart @@ -60,7 +60,7 @@ abstract class PushBaseController { .toList(); final listEmailActions = listTypeName - .where((typeName) => typeName == TypeName.emailType || typeName == TypeName.emailDelivery) + .where((typeName) => typeName == TypeName.emailDelivery || typeName == TypeName.emailDelivery) .map((typeName) => _toPushNotificationAction(typeName, accountId, userName, mapTypeState, isForeground, session: session)) .whereNotNull() .toList(); diff --git a/lib/features/push_notification/presentation/notification/local_notification_manager.dart b/lib/features/push_notification/presentation/notification/local_notification_manager.dart index 776efaa580..6737b5a0aa 100644 --- a/lib/features/push_notification/presentation/notification/local_notification_manager.dart +++ b/lib/features/push_notification/presentation/notification/local_notification_manager.dart @@ -221,4 +221,8 @@ class LocalNotificationManager { void closeStream() { localNotificationsController.close(); } + + Future clearAllNotifications() async { + _localNotificationsPlugin.cancelAll(); + } } \ No newline at end of file diff --git a/test/features/push_notification/presentation/controller/push_base_controller_test.dart b/test/features/push_notification/presentation/controller/push_base_controller_test.dart index 72e414c639..1a6384506a 100644 --- a/test/features/push_notification/presentation/controller/push_base_controller_test.dart +++ b/test/features/push_notification/presentation/controller/push_base_controller_test.dart @@ -36,75 +36,6 @@ void main() { final emailChangeListener = MockEmailChangeListener(); final mailboxChangeListener = MockMailboxChangeListener(); - test( - 'should call emailChangeListener.dispatchActions with SynchronizeEmailOnForegroundAction ' - 'when mapTypeState contains emailType ' - 'and isForeground is true', - () { - // arrange - final state = State('some-state'); - final mapTypeState = {TypeName.emailType.value: state.value}; - - // act - final pushBaseController = TestPushController(); - pushBaseController.mappingTypeStateToAction( - mapTypeState, - accountId, - userName, - isForeground: true, - emailChangeListener: emailChangeListener, - mailboxChangeListener: mailboxChangeListener - ); - - // assert - verify( - emailChangeListener.dispatchActions([ - SynchronizeEmailOnForegroundAction( - TypeName.emailType, - state, - accountId, - null, - ), - ]), - ).called(1); - verifyNever(mailboxChangeListener.dispatchActions(any)); - }); - - test( - 'should call emailChangeListener.dispatchActions with StoreEmailStateToRefreshAction ' - 'when mapTypeState contains emailType ' - 'and isForeground is false', - () { - // arrange - final state = State('some-state'); - final mapTypeState = {TypeName.emailType.value: state.value}; - - // act - final pushBaseController = TestPushController(); - pushBaseController.mappingTypeStateToAction( - mapTypeState, - accountId, - userName, - isForeground: false, - emailChangeListener: emailChangeListener, - mailboxChangeListener: mailboxChangeListener - ); - - // assert - verify( - emailChangeListener.dispatchActions([ - StoreEmailStateToRefreshAction( - TypeName.emailType, - state, - accountId, - userName, - null, - ), - ]), - ).called(1); - verifyNever(mailboxChangeListener.dispatchActions(any)); - }); - test( 'should call emailChangeListener.dispatchActions with nothing ' 'when mapTypeState contains emailDelivery '