Skip to content

Commit

Permalink
Lot of fixes, internal notification now supports actions.
Browse files Browse the repository at this point in the history
Signed-off-by: Dan Cunningham <[email protected]>
  • Loading branch information
digitaldan committed Jun 23, 2024
1 parent a8de1c3 commit 61f3f7c
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 39 deletions.
8 changes: 4 additions & 4 deletions NotificationService/NotificationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down Expand Up @@ -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
Expand Down
24 changes: 17 additions & 7 deletions openHAB/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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([])
}
Expand All @@ -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()
}
Expand Down Expand Up @@ -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)
}
Expand Down
1 change: 1 addition & 0 deletions openHAB/OpenHABDataObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class OpenHABDataObject: NSObject, DataObject {
var openHABVersion: Int = 0
var currentWebViewPath = ""
var currentView: TargetController?
var lastNotificationInfo: [AnyHashable: Any]?
}

extension OpenHABDataObject {
Expand Down
61 changes: 38 additions & 23 deletions openHAB/OpenHABRootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -163,41 +169,50 @@ 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)
}
}

private func navigateCommandAction(_ navigate: String) {
os_log("navigateCommandAction: %{PUBLIC}@", log: .notifications, type: .info, navigate)
if let index = navigate.firstIndex(of: ":") {
let type = String(navigate[..<index])
let path = String(navigate[navigate.index(after: index)...])
let components = navigate.split(separator: ":")
let type = String(components.first ?? "")
let path = components.dropFirst().joined(separator: ":")
switch type {
case "mainui":
if currentView != webViewController {
Expand All @@ -207,16 +222,16 @@ class OpenHABRootViewController: UIViewController {
case "sitemap":
os_log("handleApnsMessage sitemap", log: .notifications, type: .info)
default:
print("Unknown type")
os_log("navigateCommandAction unknown", log: .notifications, type: .info)
}
}
}

private func sendCommandAction(_ action: String) {
let components = action.split(separator: ":")
if components.count == 3 {
let itemName = String(components[1])
let itemCommand = String(components[2])
if components.count == 2 {
let itemName = String(components[0])
let itemCommand = String(components[1])
OpenHABItemCache.instance.getItem(name: itemName) { item in
guard let item else {
os_log("Could not find item %{PUBLIC}@", log: .notifications, type: .info, itemName)
Expand Down
17 changes: 12 additions & 5 deletions openHAB/OpenHABWebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class OpenHABWebViewController: OpenHABViewController {
private var observation: NSKeyValueObservation?
private var sseTimer: Timer?
private var commandQueue: [String] = []
private var isWebViewLoaded = false
private var acceptsCommands = false

private var js = """
window.OHApp = {
Expand All @@ -39,6 +39,9 @@ class OpenHABWebViewController: OpenHABViewController {
sseConnected : function(connected) {
window.webkit.messageHandlers.Native.postMessage('sseConnected-' + connected);
},
ready : function() {
window.webkit.messageHandlers.Native.postMessage('ready');
},
}
"""

Expand Down Expand Up @@ -106,7 +109,7 @@ class OpenHABWebViewController: OpenHABViewController {
if let modifiedUrl = modifyUrl(orig: url) {
let request = URLRequest(url: modifiedUrl)
clearExistingPage()
isWebViewLoaded = false
acceptsCommands = false
webView.load(request)
}
}
Expand Down Expand Up @@ -164,7 +167,7 @@ class OpenHABWebViewController: OpenHABViewController {
}

public func navigateCommand(_ command: String) {
if isWebViewLoaded {
if acceptsCommands {
navigateCommandInternal(command)
} else {
commandQueue.append(command)
Expand Down Expand Up @@ -206,6 +209,9 @@ class OpenHABWebViewController: OpenHABViewController {
// support dark mode and avoid white flashing when loading
webView.isOpaque = false
webView.backgroundColor = UIColor.clear
if #available(iOS 16.4, *) {
webView.isInspectable = true
}
// watch for URL changes so we can store the last visited path
observation = webView.observe(\.url, options: [.new]) { _, _ in
if let webviewURL = webView.url {
Expand Down Expand Up @@ -242,6 +248,8 @@ extension OpenHABWebViewController: WKScriptMessageHandler {
os_log("WKScriptMessage sseConnected is true", log: OSLog.remoteAccess, type: .info)
hidePopupMessages()
sseTimer?.invalidate()
acceptsCommands = true
executeQueuedCommands()
case "sseConnected-false":
os_log("WKScriptMessage sseConnected is false", log: OSLog.remoteAccess, type: .info)
sseTimer?.invalidate()
Expand All @@ -250,6 +258,7 @@ extension OpenHABWebViewController: WKScriptMessageHandler {
self.reloadView()
}
self.showPopupMessage(seconds: 20, title: NSLocalizedString("connecting", comment: ""), message: "", theme: .error)
self.acceptsCommands = false
}
default: break
}
Expand Down Expand Up @@ -305,8 +314,6 @@ extension OpenHABWebViewController: WKNavigationDelegate {
os_log("didFinish - webView.url %{PUBLIC}@", log: .wkwebview, type: .info, String(describing: webView.url?.description))
showActivityIndicator(show: false)
hidePopupMessages()
isWebViewLoaded = true
executeQueuedCommands()
}

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
Expand Down

0 comments on commit 61f3f7c

Please sign in to comment.