From 912df2920e17b5506028cb007923ab8a20f8f1eb Mon Sep 17 00:00:00 2001 From: Joseph Donofry Date: Mon, 1 Nov 2021 20:48:51 -0400 Subject: [PATCH] Update macOS notifications to use UserNotifications framework --- CMakeLists.txt | 2 +- src/notifications/Manager.h | 6 ++-- src/notifications/ManagerMac.cpp | 18 +++++++--- src/notifications/ManagerMac.mm | 57 +++++++++++++++++++++++--------- 4 files changed, 60 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9bdeec1..520a6f95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -591,7 +591,7 @@ include(Translations) set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC}) if (APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa -framework UserNotifications") set(SRC_FILES ${SRC_FILES} src/notifications/ManagerMac.mm src/notifications/ManagerMac.cpp src/emoji/MacHelper.mm) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") set_source_files_properties( src/notifications/ManagerMac.mm src/emoji/MacHelper.mm PROPERTIES SKIP_PRECOMPILE_HEADERS ON) diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h index 4e24dd1b..da930296 100644 --- a/src/notifications/Manager.h +++ b/src/notifications/Manager.h @@ -77,10 +77,12 @@ private: private: // Objective-C(++) doesn't like to do lots of regular C++, so the actual notification // posting is split out - void objCxxPostNotification(const QString &title, + void objCxxPostNotification(const QString &room_name, + const QString &room_id, + const QString &event_id, const QString &subtitle, const QString &informativeText, - const QImage &bodyImage); + const QString &bodyImagePath); #endif #if defined(Q_OS_WINDOWS) diff --git a/src/notifications/ManagerMac.cpp b/src/notifications/ManagerMac.cpp index f69cec2c..30948dae 100644 --- a/src/notifications/ManagerMac.cpp +++ b/src/notifications/ManagerMac.cpp @@ -33,6 +33,9 @@ NotificationsManager::postNotification(const mtx::responses::Notification ¬if cache::displayName(QString::fromStdString(notification.room_id), QString::fromStdString(mtx::accessors::sender(notification.event))); + const auto room_id = QString::fromStdString(notification.room_id); + const auto event_id = QString::fromStdString(mtx::accessors::event_id(notification.event)); + const auto isEncrypted = std::get_if>( ¬ification.event) != nullptr; const auto isReply = utils::isReply(notification.event); @@ -41,7 +44,7 @@ NotificationsManager::postNotification(const mtx::responses::Notification ¬if const QString messageInfo = (isReply ? tr("%1 replied with an encrypted message") : tr("%1 sent an encrypted message")) .arg(sender); - objCxxPostNotification(room_name, messageInfo, "", QImage()); + objCxxPostNotification(room_name, room_id, event_id, messageInfo, "", ""); } else { const QString messageInfo = (isReply ? tr("%1 replied to a message") : tr("%1 sent a message")).arg(sender); @@ -49,12 +52,17 @@ NotificationsManager::postNotification(const mtx::responses::Notification ¬if MxcImageProvider::download( QString::fromStdString(mtx::accessors::url(notification.event)).remove("mxc://"), QSize(200, 80), - [this, notification, room_name, messageInfo](QString, QSize, QImage image, QString) { - objCxxPostNotification( - room_name, messageInfo, formatNotification(notification), image); + [this, notification, room_name, room_id, event_id, messageInfo]( + QString, QSize, QImage, QString imgPath) { + objCxxPostNotification(room_name, + room_id, + event_id, + messageInfo, + formatNotification(notification), + imgPath); }); else objCxxPostNotification( - room_name, messageInfo, formatNotification(notification), QImage()); + room_name, room_id, event_id, messageInfo, formatNotification(notification), ""); } } diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm index 33b7b6af..b5ef3bfe 100644 --- a/src/notifications/ManagerMac.mm +++ b/src/notifications/ManagerMac.mm @@ -2,38 +2,65 @@ #import #import +#import #include #include -@interface NSUserNotification (CFIPrivate) -- (void)set_identityImage:(NSImage *)image; -@end - NotificationsManager::NotificationsManager(QObject *parent): QObject(parent) { } void -NotificationsManager::objCxxPostNotification(const QString &title, +NotificationsManager::objCxxPostNotification(const QString &room_name, + const QString &room_id, + const QString &event_id, const QString &subtitle, const QString &informativeText, - const QImage &bodyImage) + const QString &bodyImagePath) { + UNAuthorizationOptions options = UNAuthorizationOptionAlert + UNAuthorizationOptionSound; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - NSUserNotification *notif = [[NSUserNotification alloc] init]; + [center requestAuthorizationWithOptions:options + completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (!granted) { + NSLog(@"No notification access"); + if (error) { + NSLog(@"%@",[error localizedDescription]); + } + } + }]; - notif.title = title.toNSString(); - notif.subtitle = subtitle.toNSString(); - notif.informativeText = informativeText.toNSString(); - notif.soundName = NSUserNotificationDefaultSoundName; + UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; - if (!bodyImage.isNull()) - notif.contentImage = [[NSImage alloc] initWithCGImage: bodyImage.toCGImage() size: NSZeroSize]; + content.title = room_name.toNSString(); + content.subtitle = subtitle.toNSString(); + content.body = informativeText.toNSString(); + content.sound = [UNNotificationSound defaultSound]; + content.threadIdentifier = room_id.toNSString(); - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notif]; - [notif autorelease]; + if (!bodyImagePath.isEmpty()) { + NSError * _Nullable error; + NSURL *imageURL = [NSURL URLWithString:bodyImagePath.toNSString()]; + NSArray* attachments = [NSMutableArray array]; + UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:imageURL options:nil error:&error]; + if (error) { + NSLog(@"%@",[error localizedDescription]); + } + content.attachments = [attachments arrayByAddingObject:attachment]; + } + + 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"); + } + }]; + + [content autorelease]; } //unused