diff --git a/IceCubesApp/IceCubesApp.entitlements b/IceCubesApp/IceCubesApp.entitlements
index 34019c5a..cb44e4cc 100644
--- a/IceCubesApp/IceCubesApp.entitlements
+++ b/IceCubesApp/IceCubesApp.entitlements
@@ -8,6 +8,8 @@
app-usage
+ com.apple.developer.usernotifications.communication
+
com.apple.security.app-sandbox
com.apple.security.application-groups
diff --git a/IceCubesApp/Info.plist b/IceCubesApp/Info.plist
index ce5b4fc9..996b6f26 100644
--- a/IceCubesApp/Info.plist
+++ b/IceCubesApp/Info.plist
@@ -17,6 +17,10 @@
ITSAppUsesNonExemptEncryption
+ NSUserActivityTypes
+
+ INSendMessageIntent
+
UIBackgroundModes
remote-notification
diff --git a/IceCubesNotifications/Info.plist b/IceCubesNotifications/Info.plist
index 57421ebf..63aff942 100644
--- a/IceCubesNotifications/Info.plist
+++ b/IceCubesNotifications/Info.plist
@@ -4,6 +4,13 @@
NSExtension
+ NSExtensionAttributes
+
+ IntentsSupported
+
+ INSendMessageIntent
+
+
NSExtensionPointIdentifier
com.apple.usernotifications.service
NSExtensionPrincipalClass
diff --git a/IceCubesNotifications/NotificationService.swift b/IceCubesNotifications/NotificationService.swift
index 32193399..c878c309 100644
--- a/IceCubesNotifications/NotificationService.swift
+++ b/IceCubesNotifications/NotificationService.swift
@@ -5,6 +5,8 @@ import KeychainSwift
import Models
import UIKit
import UserNotifications
+import Intents
+import Network
@MainActor
class NotificationService: UNNotificationServiceExtension {
@@ -15,7 +17,7 @@ class NotificationService: UNNotificationServiceExtension {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
- if let bestAttemptContent {
+ if var bestAttemptContent {
let privateKey = PushNotificationsService.shared.notificationsPrivateKeyAsKey
let auth = PushNotificationsService.shared.notificationsAuthKeyAsKey
@@ -57,12 +59,13 @@ class NotificationService: UNNotificationServiceExtension {
bestAttemptContent.body = notification.body.escape()
bestAttemptContent.userInfo["plaintext"] = plaintextData
bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "glass.caf"))
+
let preferences = UserPreferences.shared
preferences.pushNotificationsCount += 1
bestAttemptContent.badge = .init(integerLiteral: preferences.pushNotificationsCount)
-
+
if let urlString = notification.icon,
let url = URL(string: urlString)
{
@@ -75,8 +78,16 @@ class NotificationService: UNNotificationServiceExtension {
if let (data, _) = try? await URLSession.shared.data(for: .init(url: url)) {
if let image = UIImage(data: data) {
try? image.pngData()?.write(to: fileURL)
- if let attachment = try? UNNotificationAttachment(identifier: filename, url: fileURL, options: nil) {
- bestAttemptContent.attachments = [attachment]
+
+ if let remoteNotification = await toRemoteNotification(localNotification: notification) {
+ let intent = buildMessageIntent(remoteNotification: remoteNotification, avatarURL: fileURL)
+ bestAttemptContent = try bestAttemptContent.updating(from: intent) as! UNMutableNotificationContent
+ let newBody = "\(bestAttemptContent.userInfo["i"] as? String ?? "") \n\(notification.title)\n\(notification.body.escape())"
+ bestAttemptContent.body = newBody
+ } else {
+ if let attachment = try? UNNotificationAttachment(identifier: filename, url: fileURL, options: nil) {
+ bestAttemptContent.attachments = [attachment]
+ }
}
}
contentHandler(bestAttemptContent)
@@ -89,4 +100,37 @@ class NotificationService: UNNotificationServiceExtension {
}
}
}
+
+ private func toRemoteNotification(localNotification: MastodonPushNotification) async -> Models.Notification? {
+ do {
+ if let account = AppAccountsManager.shared.availableAccounts.first(where: { $0.oauthToken?.accessToken == localNotification.accessToken }) {
+ let client = Client(server: account.server, oauthToken: account.oauthToken)
+ let remoteNotification: Models.Notification = try await client.get(endpoint: Notifications.notification(id: String(localNotification.notificationID)))
+ return remoteNotification
+ }
+ } catch {
+ return nil
+ }
+ return nil
+ }
+
+ private func buildMessageIntent(remoteNotification: Models.Notification, avatarURL: URL) -> INSendMessageIntent {
+ let handle = INPersonHandle(value: remoteNotification.account.id, type: .unknown)
+ let avatar = INImage(url: avatarURL)
+ let sender = INPerson(personHandle: handle,
+ nameComponents: nil,
+ displayName: remoteNotification.account.safeDisplayName,
+ image: avatar,
+ contactIdentifier: nil,
+ customIdentifier: nil)
+ let intent = INSendMessageIntent(recipients: nil,
+ outgoingMessageType: .outgoingMessageText,
+ content: nil,
+ speakableGroupName: nil,
+ conversationIdentifier: remoteNotification.account.id,
+ serviceName: nil,
+ sender: sender,
+ attachments: nil)
+ return intent
+ }
}