diff --git a/ArtemisKit/Sources/ArtemisKit/AppDelegate.swift b/ArtemisKit/Sources/ArtemisKit/AppDelegate.swift index 77b2028a..73e984b7 100644 --- a/ArtemisKit/Sources/ArtemisKit/AppDelegate.swift +++ b/ArtemisKit/Sources/ArtemisKit/AppDelegate.swift @@ -11,6 +11,7 @@ import UIKit import UserNotifications import UserStore import PushNotifications +import Messages import Navigation import Common @@ -30,6 +31,7 @@ public class AppDelegate: UIResponder, UIApplicationDelegate { private func registerForPushNotifications() { UNUserNotificationCenter.current().delegate = self + PushNotificationHandler.registerNotificationCategories() } } @@ -88,6 +90,13 @@ extension AppDelegate: UNUserNotificationCenterDelegate { didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void ) { + guard handleNotificationResponse(response) else { + // If handleNotificationResponse returns false, we don't need to perform additional work + log.info("Handled notification action. Not opening deep link.") + completionHandler() + return + } + let userInfo = response.notification.request.content.userInfo guard let targetURL = PushNotificationResponseHandler.getTarget(userInfo: userInfo) else { log.error("Could not handle click on push notification!") @@ -103,6 +112,27 @@ extension AppDelegate: UNUserNotificationCenterDelegate { // maybe add as param in handle above completionHandler() } + + /// Handles actions triggered from a user interacting with a notification. + /// Returns whether the corresponding deep link should be opened. + private func handleNotificationResponse(_ response: UNNotificationResponse) -> Bool { + if response.actionIdentifier == PushNotificationActionIdentifiers.reply { + guard + let infoData = response + .notification.request.content + .userInfo[PushNotificationUserInfoKeys.communicationInfo] as? Data, + let communicationInfo = try? PushNotificationCommunicationInfo(with: infoData), + let textResponse = response as? UNTextInputNotificationResponse else { + return true + } + + NotificationMessageResponseHandler.handle(responseText: textResponse.userText, + info: communicationInfo) + + return false + } + return true + } } // Define initializer diff --git a/ArtemisKit/Sources/Messages/Services/NotificationMessageResponseHandler.swift b/ArtemisKit/Sources/Messages/Services/NotificationMessageResponseHandler.swift new file mode 100644 index 00000000..25e0b930 --- /dev/null +++ b/ArtemisKit/Sources/Messages/Services/NotificationMessageResponseHandler.swift @@ -0,0 +1,39 @@ +// +// NotificationMessageResponseHandler.swift +// ArtemisKit +// +// Created by Anian Schleyer on 22.02.25. +// + +import PushNotifications +import SharedModels +import UserStore + +public struct NotificationMessageResponseHandler { + public static func handle(responseText: String, info: PushNotificationCommunicationInfo) { + let courseId = info.courseId + let channelId = Int64(info.channelId) + let messageId = Int64(info.messageId) ?? 0 + Task { + var message = Message(id: messageId) + message.conversation = .channel(conversation: .init(id: channelId)) + let result = await MessagesServiceFactory.shared.sendAnswerMessage(for: courseId, + message: message, + content: responseText) + switch result { + case .failure: + // Save message to try again later in case of failure + let host = UserSessionFactory.shared.institution?.baseURL?.host() ?? "" + let repository = await MessagesRepository.shared + _ = try? await repository.insertMessage(host: host, + courseId: courseId, + conversationId: Int(channelId), + messageId: Int(messageId), + answerMessageDraft: responseText) + await repository.save() + default: + break + } + } + } +}