summary refs log tree commit diff
path: root/src/notifications/ManagerMac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/notifications/ManagerMac.mm')
-rw-r--r--src/notifications/ManagerMac.mm229
1 files changed, 152 insertions, 77 deletions
diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm
index d5d900a7..4865e30d 100644
--- a/src/notifications/ManagerMac.mm
+++ b/src/notifications/ManagerMac.mm
@@ -1,112 +1,187 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "notifications/NotificationManagerProxy.h"
+#include "notifications/MacNotificationDelegate.h"
 #include "notifications/Manager.h"
 
-#import <Foundation/Foundation.h>
+#include "ChatPage.h"
+
 #import <AppKit/NSImage.h>
+#import <Foundation/Foundation.h>
 #import <UserNotifications/UserNotifications.h>
 
-#include <QtMac>
 #include <QImage>
+#include <QtMac>
 
 @interface UNNotificationAttachment (UNNotificationAttachmentAdditions)
-    + (UNNotificationAttachment *) createFromImageData:(NSData*)imgData identifier:(NSString *)imageFileIdentifier options:(NSDictionary*)attachmentOptions;
++ (UNNotificationAttachment*)createFromImageData:(NSData*)imgData
+                                      identifier:(NSString*)imageFileIdentifier
+                                         options:
+                                             (NSDictionary*)attachmentOptions;
 @end
 
 @implementation UNNotificationAttachment (UNNotificationAttachmentAdditions)
-    + (UNNotificationAttachment *) createFromImageData:(NSData*)imgData identifier:(NSString *)imageFileIdentifier options:(NSDictionary*)attachmentOptions {
-        NSFileManager *fileManager = [NSFileManager defaultManager];
-        NSString *tmpSubFolderName = [[NSProcessInfo processInfo] globallyUniqueString];
-        NSURL *tmpSubFolderURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tmpSubFolderName] isDirectory:true];
-        NSError *error = nil;
-        [fileManager createDirectoryAtURL:tmpSubFolderURL withIntermediateDirectories:true attributes:nil error:&error];
-        if(error) {
-            NSLog(@"%@",[error localizedDescription]);
-            return nil;
-        }
-        NSURL *fileURL = [tmpSubFolderURL URLByAppendingPathComponent:imageFileIdentifier];
-        [imgData writeToURL:fileURL atomically:true];
-        UNNotificationAttachment *imageAttachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:fileURL options:attachmentOptions error:&error];
-        if(error) {
-            NSLog(@"%@",[error localizedDescription]);
-            return nil;
-        }
-        return imageAttachment;
-
++ (UNNotificationAttachment*)createFromImageData:(NSData*)imgData
+                                      identifier:(NSString*)imageFileIdentifier
+                                         options:
+                                             (NSDictionary*)attachmentOptions
+{
+    NSFileManager* fileManager = [NSFileManager defaultManager];
+    NSString* tmpSubFolderName =
+        [[NSProcessInfo processInfo] globallyUniqueString];
+    NSURL* tmpSubFolderURL = [NSURL
+        fileURLWithPath:[NSTemporaryDirectory()
+                            stringByAppendingPathComponent:tmpSubFolderName]
+            isDirectory:true];
+    NSError* error = nil;
+    [fileManager createDirectoryAtURL:tmpSubFolderURL
+          withIntermediateDirectories:true
+                           attributes:nil
+                                error:&error];
+    if (error) {
+        NSLog(@"%@", [error localizedDescription]);
+        return nil;
     }
+    NSURL* fileURL =
+        [tmpSubFolderURL URLByAppendingPathComponent:imageFileIdentifier];
+    [imgData writeToURL:fileURL atomically:true];
+    UNNotificationAttachment* imageAttachment =
+        [UNNotificationAttachment attachmentWithIdentifier:@""
+                                                       URL:fileURL
+                                                   options:attachmentOptions
+                                                     error:&error];
+    if (error) {
+        NSLog(@"%@", [error localizedDescription]);
+        return nil;
+    }
+    return imageAttachment;
+}
 @end
 
-NotificationsManager::NotificationsManager(QObject *parent): QObject(parent)
+NotificationsManager::NotificationsManager(QObject* parent)
+    : QObject(parent)
 {
-
 }
 
-void
-NotificationsManager::objCxxPostNotification(const QString &room_name,
-                                             const QString &room_id,
-                                             const QString &event_id,
-                                             const QString &subtitle,
-                                             const QString &informativeText,
-                                             const QString &bodyImagePath)
+void NotificationsManager::objCxxPostNotification(
+    const QString& room_name,
+    const QString& room_id,
+    const QString& event_id,
+    const QString& subtitle,
+    const QString& informativeText,
+    const QString& bodyImagePath,
+    const QString& respondStr,
+    const QString& sendStr,
+    const QString& placeholder)
 {
+    // Request permissions for alerts (the generic type of notification), sound playback,
+    // and badges (which allows the Nheko app icon to show the little red bubble with unread count).
+    // NOTE: Possible macOS bug... the 'Play sound for notification checkbox' doesn't appear in
+    // the Notifications and Focus settings unless UNAuthorizationOptionBadges is also
+    // specified
     UNAuthorizationOptions options = UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge;
-    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+    UNUserNotificationCenter* center =
+        [UNUserNotificationCenter currentNotificationCenter];
 
+    // TODO: Move this somewhere that isn't dependent on receiving a notification
+    // to actually request notification access.
     [center requestAuthorizationWithOptions:options
-    completionHandler:^(BOOL granted, NSError * _Nullable error) {
-        if (!granted) {
-            NSLog(@"No notification access");
-            if (error) {
-                NSLog(@"%@",[error localizedDescription]);
+                          completionHandler:^(BOOL granted,
+                              NSError* _Nullable error) {
+                              if (!granted) {
+                                  NSLog(@"No notification access");
+                                  if (error) {
+                                      NSLog(@"%@", [error localizedDescription]);
+                                  }
+                              }
+                          }];
+
+    UNTextInputNotificationAction* replyAction = [UNTextInputNotificationAction actionWithIdentifier:@"ReplyAction"
+                                                                                               title:respondStr.toNSString()
+                                                                                             options:UNNotificationActionOptionNone
+                                                                                textInputButtonTitle:sendStr.toNSString()
+                                                                                textInputPlaceholder:placeholder.toNSString()];
+
+    UNNotificationCategory* category = [UNNotificationCategory categoryWithIdentifier:@"ReplyCategory"
+                                                                              actions:@[ replyAction ]
+                                                                    intentIdentifiers:@[]
+                                                                              options:UNNotificationCategoryOptionNone];
+
+    NSString* title = room_name.toNSString();
+    NSString* sub = subtitle.toNSString();
+    NSString* body = informativeText.toNSString();
+    NSString* threadIdentifier = room_id.toNSString();
+    NSString* identifier = event_id.toNSString();
+    NSString* imgUrl = bodyImagePath.toNSString();
+
+    NSSet* categories = [NSSet setWithObject:category];
+    [center setNotificationCategories:categories];
+    [center getNotificationSettingsWithCompletionHandler:^(
+        UNNotificationSettings* _Nonnull settings) {
+        if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
+            UNMutableNotificationContent* content =
+                [[UNMutableNotificationContent alloc] init];
+
+            content.title = title;
+            content.subtitle = sub;
+            content.body = body;
+            content.sound = [UNNotificationSound defaultSound];
+            content.threadIdentifier = threadIdentifier;
+            content.categoryIdentifier = @"ReplyCategory";
+
+            if ([imgUrl length] != 0) {
+                NSURL* imageURL = [NSURL fileURLWithPath:imgUrl];
+                NSData* img = [NSData dataWithContentsOfURL:imageURL];
+                NSArray* attachments = [NSMutableArray array];
+                UNNotificationAttachment* attachment = [UNNotificationAttachment
+                    createFromImageData:img
+                             identifier:@"attachment_image.jpeg"
+                                options:nil];
+                if (attachment) {
+                    attachments = [NSMutableArray arrayWithObjects:attachment, nil];
+                    content.attachments = attachments;
+                }
             }
-        }
-    }];
 
-    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
-
-    content.title             = room_name.toNSString();
-    content.subtitle          = subtitle.toNSString();
-    content.body              = informativeText.toNSString();
-    content.sound             = [UNNotificationSound defaultSound];
-    content.threadIdentifier  = room_id.toNSString();
-
-    if (!bodyImagePath.isEmpty()) {
-        NSURL *imageURL = [NSURL fileURLWithPath:bodyImagePath.toNSString()];
-        NSData *img = [NSData dataWithContentsOfURL:imageURL];
-        NSArray *attachments = [NSMutableArray array];
-        UNNotificationAttachment *attachment = [UNNotificationAttachment createFromImageData:img identifier:@"attachment_image.jpeg" options:nil];
-        if (attachment) {
-            attachments = [NSMutableArray arrayWithObjects: attachment, nil];
-            content.attachments = attachments;
-        }
-    }
+            UNNotificationRequest* notificationRequest =
+                [UNNotificationRequest requestWithIdentifier:identifier
+                                                     content:content
+                                                     trigger:nil];
 
-    UNNotificationRequest *notificationRequest = [UNNotificationRequest requestWithIdentifier:event_id.toNSString() content:content trigger:nil];
+            [center addNotificationRequest:notificationRequest
+                     withCompletionHandler:^(NSError* _Nullable error) {
+                         if (error != nil) {
+                             NSLog(@"Unable to Add Notification Request: %@", [error localizedDescription]);
+                         }
+                     }];
 
-    [center addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {
-        if (error != nil) {
-            NSLog(@"Unable to Add Notification Request");
+            [content autorelease];
         }
     }];
-
-    [content autorelease];
 }
 
-//unused
-void
-NotificationsManager::actionInvoked(uint, QString)
+void NotificationsManager::attachToMacNotifCenter()
 {
-}
+    UNUserNotificationCenter* center =
+        [UNUserNotificationCenter currentNotificationCenter];
 
-void
-NotificationsManager::notificationReplied(uint, QString)
-{
-}
+    std::unique_ptr<NotificationManagerProxy> proxy = std::make_unique<NotificationManagerProxy>();
 
-void
-NotificationsManager::notificationClosed(uint, uint)
-{
+    connect(proxy.get(), &NotificationManagerProxy::notificationReplied, ChatPage::instance(), &ChatPage::sendNotificationReply);
+
+    MacNotificationDelegate* notifDelegate = [[MacNotificationDelegate alloc] initWithProxy:std::move(proxy)];
+
+    center.delegate = notifDelegate;
 }
 
-void
-NotificationsManager::removeNotification(const QString &, const QString &)
-{}
+// unused
+void NotificationsManager::actionInvoked(uint, QString) { }
+
+void NotificationsManager::notificationReplied(uint, QString) { }
+
+void NotificationsManager::notificationClosed(uint, uint) { }
 
+void NotificationsManager::removeNotification(const QString&, const QString&) { }