From 61f3f7c722839a2854c59fb00bc9fd30dc4fb693 Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Sun, 23 Jun 2024 14:02:44 -0700 Subject: [PATCH] Lot of fixes, internal notification now supports actions. Signed-off-by: Dan Cunningham --- NotificationService/NotificationService.swift | 8 +-- openHAB/AppDelegate.swift | 24 +++++--- openHAB/OpenHABDataObject.swift | 1 + openHAB/OpenHABRootViewController.swift | 61 ++++++++++++------- openHAB/OpenHABWebViewController.swift | 17 ++++-- 5 files changed, 72 insertions(+), 39 deletions(-) diff --git a/NotificationService/NotificationService.swift b/NotificationService/NotificationService.swift index 06971bac..8d91e5bd 100644 --- a/NotificationService/NotificationService.swift +++ b/NotificationService/NotificationService.swift @@ -24,8 +24,8 @@ class NotificationService: UNNotificationServiceExtension { var notificationActions: [UNNotificationAction] = [] let userInfo = bestAttemptContent.userInfo os_log("handleNotification userInfo %{PUBLIC}@", log: .default, type: .info, userInfo) - - //Check if the user has defined custom actions in the payload + + // Check if the user has defined custom actions in the payload if let actionsArray = parseActions(userInfo), let category = parseCategory(userInfo) { for actionDict in actionsArray { if let action = actionDict["action"], @@ -64,10 +64,10 @@ class NotificationService: UNNotificationServiceExtension { } } } - + // check if there is an attachment to put on the notification // this should be last as we need to wait for media - // TODO we should support relative paths and try the user's openHAB (local,remote) for content + // TODO: we should support relative paths and try the user's openHAB (local,remote) for content if let attachmentURLString = userInfo["attachment-url"] as? String, let attachmentURL = URL(string: attachmentURLString) { os_log("handleNotification downloading %{PUBLIC}@", log: .default, type: .info, attachmentURLString) downloadAndAttachMedia(url: attachmentURL) { attachment in diff --git a/openHAB/AppDelegate.swift b/openHAB/AppDelegate.swift index 81a3934a..d3969742 100644 --- a/openHAB/AppDelegate.swift +++ b/openHAB/AppDelegate.swift @@ -156,7 +156,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { let userInfo = notification.request.content.userInfo os_log("Notification received while app is in foreground: %{PUBLIC}@", log: .notifications, type: .info, userInfo) - notifyNotificationListeners(userInfo) + appData.lastNotificationInfo = userInfo displayNotification(userInfo: userInfo) completionHandler([]) } @@ -167,13 +167,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD let actionIdentifier = response.actionIdentifier os_log("Notification clicked: action %{PUBLIC}@ userInfo %{PUBLIC}@", log: .notifications, type: .info, actionIdentifier, userInfo) - if actionIdentifier == UNNotificationDefaultActionIdentifier { - notifyNotificationListeners(userInfo) - } else if actionIdentifier == UNNotificationDismissActionIdentifier { - // Handle the dismissal action, nothing - } else { - userInfo["actionIdentifier"] = actionIdentifier + if actionIdentifier != UNNotificationDismissActionIdentifier { + if actionIdentifier != UNNotificationDefaultActionIdentifier { + userInfo["actionIdentifier"] = actionIdentifier + } notifyNotificationListeners(userInfo) + appData.lastNotificationInfo = userInfo } completionHandler() } @@ -206,10 +205,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD view.configureContent(title: NSLocalizedString("notification", comment: ""), body: message) view.button?.setTitle(NSLocalizedString("dismiss", comment: ""), for: .normal) view.buttonTapHandler = { _ in SwiftMessages.hide() } + // Add tap gesture recognizer to the view for actions + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.messageViewTapped)) + view.addGestureRecognizer(tapGesture) return view } } + // Action to be performed when the notification message view is tapped + @objc func messageViewTapped() { + if let userInfo = appData.lastNotificationInfo { + notifyNotificationListeners(userInfo) + SwiftMessages.hideAll() + } + } + private func notifyNotificationListeners(_ userInfo: [AnyHashable: Any]) { NotificationCenter.default.post(name: .apnsReceived, object: nil, userInfo: userInfo) } diff --git a/openHAB/OpenHABDataObject.swift b/openHAB/OpenHABDataObject.swift index 1f6d0fa7..42b537b7 100644 --- a/openHAB/OpenHABDataObject.swift +++ b/openHAB/OpenHABDataObject.swift @@ -22,6 +22,7 @@ class OpenHABDataObject: NSObject, DataObject { var openHABVersion: Int = 0 var currentWebViewPath = "" var currentView: TargetController? + var lastNotificationInfo: [AnyHashable: Any]? } extension OpenHABDataObject { diff --git a/openHAB/OpenHABRootViewController.swift b/openHAB/OpenHABRootViewController.swift index 15dfa920..28ade986 100644 --- a/openHAB/OpenHABRootViewController.swift +++ b/openHAB/OpenHABRootViewController.swift @@ -57,7 +57,6 @@ class OpenHABRootViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() os_log("OpenHABRootViewController viewDidLoad", log: .default, type: .info) - NotificationCenter.default.addObserver(self, selector: #selector(handleApnsMessage(notification:)), name: .apnsReceived, object: nil) setupSideMenu() NotificationCenter.default.addObserver(self, selector: #selector(OpenHABRootViewController.handleApsRegistration(_:)), name: NSNotification.Name("apsRegistered"), object: nil) @@ -97,6 +96,13 @@ class OpenHABRootViewController: UIViewController { // save this so we know if its changed later isDemoMode = Preferences.demomode switchToSavedView() + + // ready for push notifications + NotificationCenter.default.addObserver(self, selector: #selector(handleApnsMessage(notification:)), name: .apnsReceived, object: nil) + // check if we were launched with a notification + if let userInfo = appData?.lastNotificationInfo { + handleNotification(userInfo) + } } override func viewWillAppear(_ animated: Bool) { @@ -163,32 +169,40 @@ class OpenHABRootViewController: UIViewController { let theData = note?.userInfo if theData != nil { let prefsURL = Preferences.remoteUrl - if prefsURL.contains("openhab.org") { - guard let deviceId = theData?["deviceId"] as? String, let deviceToken = theData?["deviceToken"] as? String, let deviceName = theData?["deviceName"] as? String else { return } - os_log("Registering notifications with %{PUBLIC}@", log: .notifications, type: .info, prefsURL) - NetworkConnection.register(prefsURL: prefsURL, deviceToken: deviceToken, deviceId: deviceId, deviceName: deviceName) { response in - switch response.result { - case .success: - os_log("my.openHAB registration sent", log: .notifications, type: .info) - case let .failure(error): - os_log("my.openHAB registration failed %{PUBLIC}@ %d", log: .notifications, type: .error, error.localizedDescription, response.response?.statusCode ?? 0) + if prefsURL.contains("openhab.org") { + guard let deviceId = theData?["deviceId"] as? String, let deviceToken = theData?["deviceToken"] as? String, let deviceName = theData?["deviceName"] as? String else { return } + os_log("Registering notifications with %{PUBLIC}@", log: .notifications, type: .info, prefsURL) + NetworkConnection.register(prefsURL: prefsURL, deviceToken: deviceToken, deviceId: deviceId, deviceName: deviceName) { response in + switch response.result { + case .success: + os_log("my.openHAB registration sent", log: .notifications, type: .info) + case let .failure(error): + os_log("my.openHAB registration failed %{PUBLIC}@ %d", log: .notifications, type: .error, error.localizedDescription, response.response?.statusCode ?? 0) + } } } - } } } @objc func handleApnsMessage(notification: Notification) { - //actionIdentifier is the result of a action button being pressed - if let action = notification.userInfo?["actionIdentifier"] as? String { + // actionIdentifier is the result of a action button being pressed + if let userInfo = notification.userInfo { + handleNotification(userInfo) + } + } + + private func handleNotification(_ userInfo: [AnyHashable: Any]) { + // actionIdentifier is the result of a action button being pressed + if let action = userInfo["actionIdentifier"] as? String { + let cmd = action.split(separator: ":").dropFirst().joined(separator: ":") if action.hasPrefix("navigate") { - navigateCommandAction(action) + navigateCommandAction(cmd) } if action.hasPrefix("command") { - sendCommandAction(action) + sendCommandAction(cmd) } - } else if let navigate = notification.userInfo?["navigate"] as? String { - //the user simply clicked on the notification, but indicated a navigation in the payload + } else if let navigate = userInfo["navigate"] as? String { + // the user simply clicked on the notification, but indicated a navigation in the payload navigateCommandAction(navigate) } } @@ -196,8 +210,9 @@ class OpenHABRootViewController: UIViewController { private func navigateCommandAction(_ navigate: String) { os_log("navigateCommandAction: %{PUBLIC}@", log: .notifications, type: .info, navigate) if let index = navigate.firstIndex(of: ":") { - let type = String(navigate[..