From 84b7239ad03b8561249257e2d6b8a401afb74aaf Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 25 Dec 2023 00:03:48 +0700 Subject: [PATCH] TF-2384 Handle open email detailed when click notification on background mode Signed-off-by: dab246 (cherry picked from commit 72db39c87dbd8f06bfbb417e4fed4d384da356ea) --- ios/Runner/AppDelegate.swift | 19 +++++++++++++++ .../home/presentation/home_controller.dart | 24 +++++++++++++++---- .../mailbox_dashboard_controller.dart | 15 ++++++++++-- .../model/preview_email_arguments.dart | 15 ++++++++++++ .../controller/fcm_message_controller.dart | 6 ++--- .../presentation/services/fcm_receiver.dart | 13 ++++++++++ .../presentation/services/fcm_service.dart | 16 ++++++++++--- .../presentation/utils/fcm_utils.dart | 2 ++ 8 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 lib/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 4c34d1dd0..37dc26dac 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -7,12 +7,16 @@ import flutter_local_notifications @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { + var notificationInteractionChannel: FlutterMethodChannel? + override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) + createNotificationInteractionChannel() + if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate } @@ -94,7 +98,13 @@ import flutter_local_notifications } override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { + TwakeLogger.shared.log(message: "AppDelegate::userNotificationCenter::didReceive::response: \(response)") updateAppBadger(currentBadgeCount: UIApplication.shared.applicationIconBadgeNumber) + + if let emailId = response.notification.request.content.userInfo[JmapConstants.EMAIL_ID] as? String { + self.notificationInteractionChannel?.invokeMethod("openEmail", arguments: emailId) + } + completionHandler() } } @@ -124,4 +134,13 @@ extension AppDelegate { private func isAppForegroundActive() -> Bool { return UIApplication.shared.applicationState == .active } + + private func createNotificationInteractionChannel() { + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + + self.notificationInteractionChannel = FlutterMethodChannel( + name: "notification_interaction_channel", + binaryMessenger: controller.binaryMessenger + ) + } } diff --git a/lib/features/home/presentation/home_controller.dart b/lib/features/home/presentation/home_controller.dart index a563ee36c..663a66bdd 100644 --- a/lib/features/home/presentation/home_controller.dart +++ b/lib/features/home/presentation/home_controller.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/account/personal_account.dart'; import 'package:model/email/email_content.dart'; @@ -19,6 +20,7 @@ import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cac import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart'; import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart'; import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_utils.dart'; @@ -40,6 +42,7 @@ class HomeController extends ReloadableController { ); PersonalAccount? currentAccount; + EmailId? _emailIdPreview; @override void onInit() { @@ -47,6 +50,9 @@ class HomeController extends ReloadableController { _initFlutterDownloader(); _registerReceivingSharingIntent(); } + if (PlatformInfo.isIOS && Get.arguments is EmailId) { + _emailIdPreview = Get.arguments; + } super.onInit(); } @@ -58,10 +64,20 @@ class HomeController extends ReloadableController { @override void handleReloaded(Session session) { - popAndPush( - RouteUtils.generateNavigationRoute(AppRoutes.dashboard), - arguments: session - ); + if (_emailIdPreview != null) { + popAndPush( + RouteUtils.generateNavigationRoute(AppRoutes.dashboard), + arguments: PreviewEmailArguments( + session: session, + emailId: _emailIdPreview! + ) + ); + } else { + popAndPush( + RouteUtils.generateNavigationRoute(AppRoutes.dashboard), + arguments: session + ); + } } void _initFlutterDownloader() { 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 1d30c98e3..f0bfff02d 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -84,6 +84,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/comp import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/refresh_action_view_event.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; @@ -112,6 +113,7 @@ import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_ema 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/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/features/sending_queue/domain/model/sending_email.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/state/get_all_sending_email_state.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/state/update_sending_email_state.dart'; @@ -438,7 +440,7 @@ class MailboxDashBoardController extends ReloadableController { }); _refreshActionEventController.stream - .debounceTime(const Duration(milliseconds: FcmService.durationMessageComing)) + .debounceTime(const Duration(milliseconds: FcmUtils.durationMessageComing)) .listen(_handleRefreshActionWhenBackToApp); _registerLocalNotificationStreamListener(); @@ -462,6 +464,8 @@ class MailboxDashBoardController extends ReloadableController { _handleSession(arguments); } else if (arguments is MailtoArguments) { _handleMailtoURL(arguments); + } else if (arguments is PreviewEmailArguments) { + _handleOpenEmailAction(arguments); } else { dispatchRoute(DashboardRoutes.thread); reload(); @@ -532,6 +536,13 @@ class MailboxDashBoardController extends ReloadableController { _handleSession(arguments.session); } + void _handleOpenEmailAction(PreviewEmailArguments arguments) { + log('MailboxDashBoardController::_handleOpenEmailAction:arguments: $arguments'); + dispatchRoute(DashboardRoutes.waiting); + _handleSession(arguments.session); + _handleNotificationMessageFromEmailId(arguments.emailId); + } + Future _getAppVersion() async { final info = await PackageInfo.fromPlatform(); log('MailboxDashBoardController::_getAppVersion(): ${info.version}'); @@ -1718,7 +1729,7 @@ class MailboxDashBoardController extends ReloadableController { void _showWaitingView() { popAllRouteIfHave(); - dispatchRoute( DashboardRoutes.waiting); + dispatchRoute(DashboardRoutes.waiting); } void _openInboxMailboxFromNotification() { diff --git a/lib/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart b/lib/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart new file mode 100644 index 000000000..4ac7555ef --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart @@ -0,0 +1,15 @@ + +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/main/routes/router_arguments.dart'; + +class PreviewEmailArguments extends RouterArguments { + + final Session session; + final EmailId emailId; + + PreviewEmailArguments({required this.session, required this.emailId}); + + @override + List get props => [session, emailId]; +} \ No newline at end of file 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 e12a925fa..379a8851a 100644 --- a/lib/features/push_notification/presentation/controller/fcm_message_controller.dart +++ b/lib/features/push_notification/presentation/controller/fcm_message_controller.dart @@ -73,21 +73,21 @@ class FcmMessageController extends FcmBaseController { void _listenForegroundMessageStream() { FcmService.instance.foregroundMessageStreamController ?.stream - .throttleTime(const Duration(milliseconds: FcmService.durationMessageComing)) + .throttleTime(const Duration(milliseconds: FcmUtils.durationMessageComing)) .listen(_handleForegroundMessageAction); } void _listenBackgroundMessageStream() { FcmService.instance.backgroundMessageStreamController ?.stream - .throttleTime(const Duration(milliseconds: FcmService.durationMessageComing)) + .throttleTime(const Duration(milliseconds: FcmUtils.durationMessageComing)) .listen(_handleBackgroundMessageAction); } void _listenTokenStream() { FcmService.instance.fcmTokenStreamController ?.stream - .throttleTime(const Duration(milliseconds: FcmService.durationRefreshToken)) + .throttleTime(const Duration(milliseconds: FcmUtils.durationRefreshToken)) .listen(FcmTokenController.instance.onFcmTokenChanged); } diff --git a/lib/features/push_notification/presentation/services/fcm_receiver.dart b/lib/features/push_notification/presentation/services/fcm_receiver.dart index 0c35b74ac..ff7894bd4 100644 --- a/lib/features/push_notification/presentation/services/fcm_receiver.dart +++ b/lib/features/push_notification/presentation/services/fcm_receiver.dart @@ -2,6 +2,7 @@ import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/services.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/controller/fcm_message_controller.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_service.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; @@ -20,12 +21,24 @@ class FcmReceiver { static FcmReceiver get instance => _instance; + static const notificationInteractionChannel = MethodChannel('notification_interaction_channel'); + Future onInitialFcmListener() async { log('FcmReceiver::onInitialFcmListener:'); await _onHandleFcmToken(); _onForegroundMessage(); _onBackgroundMessage(); + + if (PlatformInfo.isIOS) { + notificationInteractionChannel.setMethodCallHandler((call) async { + log('FcmReceiver::onInitialFcmListener:notificationInteractionChannel: $call'); + if (call.method == 'openEmail') { + log('FcmReceiver::onInitialFcmListener:openEmail with id = ${call.arguments}'); + FcmService.instance.handleOpenEmailFromNotification(call.arguments); + } + }); + } } void _onForegroundMessage() { diff --git a/lib/features/push_notification/presentation/services/fcm_service.dart b/lib/features/push_notification/presentation/services/fcm_service.dart index 8fad4b46e..689ec1274 100644 --- a/lib/features/push_notification/presentation/services/fcm_service.dart +++ b/lib/features/push_notification/presentation/services/fcm_service.dart @@ -3,12 +3,14 @@ import 'dart:async'; import 'package:core/utils/app_logger.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/main/routes/app_routes.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +import 'package:tmail_ui_user/main/routes/route_utils.dart'; class FcmService { - static const int durationMessageComing = 2000; - static const int durationRefreshToken = 2000; - StreamController>? foregroundMessageStreamController; StreamController>? backgroundMessageStreamController; StreamController? fcmTokenStreamController; @@ -45,6 +47,14 @@ class FcmService { fcmTokenStreamController = StreamController.broadcast(); } + void handleOpenEmailFromNotification(String emailId) { + log('FcmService::handleOpenEmailFromNotification:emailId: $emailId'); + popAndPush( + RouteUtils.generateNavigationRoute(AppRoutes.home), + arguments: EmailId(Id(emailId)) + ); + } + void closeStream() { foregroundMessageStreamController?.close(); backgroundMessageStreamController?.close(); diff --git a/lib/features/push_notification/presentation/utils/fcm_utils.dart b/lib/features/push_notification/presentation/utils/fcm_utils.dart index eac695e36..3045cccde 100644 --- a/lib/features/push_notification/presentation/utils/fcm_utils.dart +++ b/lib/features/push_notification/presentation/utils/fcm_utils.dart @@ -31,6 +31,8 @@ class FcmUtils { TypeName.mailboxType, TypeName.emailDelivery ]; + static const int durationMessageComing = 2000; + static const int durationRefreshToken = 2000; StateChange? convertFirebaseDataMessageToStateChange(Map dataMessage) { log('FcmUtils::convertFirebaseDataMessageToStateChange():dataMessage: $dataMessage');