mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-24 03:58:49 +03:00
Add ability to respond to notifications on macOS
This commit is contained in:
parent
9138119dc4
commit
07e8f64903
11 changed files with 307 additions and 99 deletions
|
@ -13,3 +13,6 @@ KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
PenaltyReturnTypeOnItsOwnLine: 0
|
PenaltyReturnTypeOnItsOwnLine: 0
|
||||||
|
---
|
||||||
|
BasedOnStyle: WebKit
|
||||||
|
Language: ObjC
|
|
@ -629,9 +629,9 @@ set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC})
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa -framework UserNotifications")
|
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 src/emoji/MacHelper.h)
|
set(SRC_FILES ${SRC_FILES} src/notifications/NotificationManagerProxy.h src/notifications/MacNotificationDelegate.h src/notifications/MacNotificationDelegate.mm src/notifications/ManagerMac.mm src/notifications/ManagerMac.cpp src/emoji/MacHelper.mm src/emoji/MacHelper.h)
|
||||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
|
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
|
||||||
set_source_files_properties( src/notifications/ManagerMac.mm src/emoji/MacHelper.mm src/emoji/MacHelper.h PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
set_source_files_properties( src/notifications/NotificationManagerProxy.h src/notifications/MacNotificationDelegate.h src/notifications/MacNotificationDelegate.mm src/notifications/ManagerMac.mm src/emoji/MacHelper.mm src/emoji/MacHelper.h PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||||
endif()
|
endif()
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
|
|
|
@ -152,16 +152,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QObject *parent)
|
||||||
connect(notificationsManager,
|
connect(notificationsManager,
|
||||||
&NotificationsManager::sendNotificationReply,
|
&NotificationsManager::sendNotificationReply,
|
||||||
this,
|
this,
|
||||||
[this](const QString &roomid, const QString &eventid, const QString &body) {
|
&ChatPage::sendNotificationReply);
|
||||||
view_manager_->queueReply(roomid, eventid, body);
|
|
||||||
auto exWin = MainWindow::instance()->windowForRoom(roomid);
|
|
||||||
if (exWin) {
|
|
||||||
exWin->requestActivate();
|
|
||||||
} else {
|
|
||||||
view_manager_->rooms()->setCurrentRoom(roomid);
|
|
||||||
MainWindow::instance()->requestActivate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
this,
|
this,
|
||||||
|
@ -1583,6 +1574,19 @@ ChatPage::handleMatrixUri(QString uri)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ChatPage::sendNotificationReply(const QString &roomid, const QString &eventid, const QString &body)
|
||||||
|
{
|
||||||
|
view_manager_->queueReply(roomid, eventid, body);
|
||||||
|
auto exWin = MainWindow::instance()->windowForRoom(roomid);
|
||||||
|
if (exWin) {
|
||||||
|
exWin->requestActivate();
|
||||||
|
} else {
|
||||||
|
view_manager_->rooms()->setCurrentRoom(roomid);
|
||||||
|
MainWindow::instance()->requestActivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ChatPage::handleMatrixUri(const QUrl &uri)
|
ChatPage::handleMatrixUri(const QUrl &uri)
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,6 +105,7 @@ public slots:
|
||||||
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
|
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
|
||||||
void decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescription keyDesc,
|
void decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescription keyDesc,
|
||||||
const SecretsToDecrypt &secrets);
|
const SecretsToDecrypt &secrets);
|
||||||
|
void sendNotificationReply(const QString &roomid, const QString &eventid, const QString &body);
|
||||||
signals:
|
signals:
|
||||||
void connectionLost();
|
void connectionLost();
|
||||||
void connectionRestored();
|
void connectionRestored();
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
#include "emoji/MacHelper.h"
|
#include "emoji/MacHelper.h"
|
||||||
|
#include "notifications/Manager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GSTREAMER_AVAILABLE) && (defined(Q_OS_MAC) || defined(Q_OS_WINDOWS))
|
#if defined(GSTREAMER_AVAILABLE) && (defined(Q_OS_MAC) || defined(Q_OS_WINDOWS))
|
||||||
|
@ -389,6 +390,10 @@ main(int argc, char *argv[])
|
||||||
// Temporary solution for the emoji picker until
|
// Temporary solution for the emoji picker until
|
||||||
// nheko has a proper menu bar with more functionality.
|
// nheko has a proper menu bar with more functionality.
|
||||||
MacHelper::initializeMenus();
|
MacHelper::initializeMenus();
|
||||||
|
|
||||||
|
// Need to set up notification delegate so users can respond to messages from within the
|
||||||
|
// notification itself.
|
||||||
|
NotificationsManager::attachToMacNotifCenter();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nhlog::ui()->info("starting nheko {}", nheko::version);
|
nhlog::ui()->info("starting nheko {}", nheko::version);
|
||||||
|
|
20
src/notifications/MacNotificationDelegate.h
Normal file
20
src/notifications/MacNotificationDelegate.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "notifications/Manager.h"
|
||||||
|
#include "notifications/NotificationManagerProxy.h"
|
||||||
|
#include <mtx/responses/notifications.hpp>
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UserNotifications/UserNotifications.h>
|
||||||
|
|
||||||
|
@interface MacNotificationDelegate : NSObject <UNUserNotificationCenterDelegate> {
|
||||||
|
std::unique_ptr<NotificationManagerProxy> mProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithProxy:(std::unique_ptr<NotificationManagerProxy>&&)proxy;
|
||||||
|
@end
|
47
src/notifications/MacNotificationDelegate.mm
Normal file
47
src/notifications/MacNotificationDelegate.mm
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#import "notifications/MacNotificationDelegate.h"
|
||||||
|
|
||||||
|
#include <QString.h>
|
||||||
|
|
||||||
|
#include "ChatPage.h"
|
||||||
|
|
||||||
|
@implementation MacNotificationDelegate
|
||||||
|
|
||||||
|
- (id)initWithProxy: (std::unique_ptr<NotificationManagerProxy>&&)proxy
|
||||||
|
{
|
||||||
|
if(self = [super init]) {
|
||||||
|
mProxy = std::move(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||||
|
didReceiveNotificationResponse:(UNNotificationResponse*)response
|
||||||
|
withCompletionHandler:(void (^)())completionHandler
|
||||||
|
{
|
||||||
|
if ([response.actionIdentifier isEqualToString:@"ReplyAction"]) {
|
||||||
|
if ([response respondsToSelector:@selector(userText)]) {
|
||||||
|
UNTextInputNotificationResponse* textResponse = (UNTextInputNotificationResponse*)response;
|
||||||
|
NSString* textValue = [textResponse userText];
|
||||||
|
NSString* eventId = [[[textResponse notification] request] identifier];
|
||||||
|
NSString* roomId = [[[[textResponse notification] request] content] threadIdentifier];
|
||||||
|
mProxy->notificationReplied(QString::fromNSString(roomId), QString::fromNSString(eventId), QString::fromNSString(textValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||||
|
willPresentNotification:(UNNotification*)notification
|
||||||
|
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
completionHandler(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -78,7 +78,13 @@ private:
|
||||||
const QString &event_id,
|
const QString &event_id,
|
||||||
const QString &subtitle,
|
const QString &subtitle,
|
||||||
const QString &informativeText,
|
const QString &informativeText,
|
||||||
const QString &bodyImagePath);
|
const QString &bodyImagePath,
|
||||||
|
const QString &respondStr,
|
||||||
|
const QString &sendStr,
|
||||||
|
const QString &placeholder);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void attachToMacNotifCenter();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WINDOWS)
|
#if defined(Q_OS_WINDOWS)
|
||||||
|
|
|
@ -40,12 +40,20 @@ NotificationsManager::postNotification(const mtx::responses::Notification ¬if
|
||||||
const auto isEncrypted = std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
|
const auto isEncrypted = std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
|
||||||
¬ification.event) != nullptr;
|
¬ification.event) != nullptr;
|
||||||
const auto isReply = utils::isReply(notification.event);
|
const auto isReply = utils::isReply(notification.event);
|
||||||
|
|
||||||
|
// Putting these here to pass along since I'm not sure how
|
||||||
|
// our translate step interacts with .mm files
|
||||||
|
const auto respondStr = QObject::tr("Respond");
|
||||||
|
const auto sendStr = QObject::tr("Send");
|
||||||
|
const auto placeholder = QObject::tr("Write a message...");
|
||||||
|
|
||||||
if (isEncrypted) {
|
if (isEncrypted) {
|
||||||
// TODO: decrypt this message if the decryption setting is on in the UserSettings
|
// TODO: decrypt this message if the decryption setting is on in the UserSettings
|
||||||
const QString messageInfo = (isReply ? tr("%1 replied with an encrypted message")
|
const QString messageInfo = (isReply ? tr("%1 replied with an encrypted message")
|
||||||
: tr("%1 sent an encrypted message"))
|
: tr("%1 sent an encrypted message"))
|
||||||
.arg(sender);
|
.arg(sender);
|
||||||
objCxxPostNotification(room_name, room_id, event_id, messageInfo, "", "");
|
objCxxPostNotification(
|
||||||
|
room_name, room_id, event_id, messageInfo, "", "", respondStr, sendStr, placeholder);
|
||||||
} else {
|
} else {
|
||||||
const QString messageInfo =
|
const QString messageInfo =
|
||||||
(isReply ? tr("%1 replied to a message") : tr("%1 sent a message")).arg(sender);
|
(isReply ? tr("%1 replied to a message") : tr("%1 sent a message")).arg(sender);
|
||||||
|
@ -53,17 +61,34 @@ NotificationsManager::postNotification(const mtx::responses::Notification ¬if
|
||||||
MxcImageProvider::download(
|
MxcImageProvider::download(
|
||||||
QString::fromStdString(mtx::accessors::url(notification.event)).remove("mxc://"),
|
QString::fromStdString(mtx::accessors::url(notification.event)).remove("mxc://"),
|
||||||
QSize(200, 80),
|
QSize(200, 80),
|
||||||
[this, notification, room_name, room_id, event_id, messageInfo](
|
[this,
|
||||||
QString, QSize, QImage, QString imgPath) {
|
notification,
|
||||||
|
room_name,
|
||||||
|
room_id,
|
||||||
|
event_id,
|
||||||
|
messageInfo,
|
||||||
|
respondStr,
|
||||||
|
sendStr,
|
||||||
|
placeholder](QString, QSize, QImage, QString imgPath) {
|
||||||
objCxxPostNotification(room_name,
|
objCxxPostNotification(room_name,
|
||||||
room_id,
|
room_id,
|
||||||
event_id,
|
event_id,
|
||||||
messageInfo,
|
messageInfo,
|
||||||
formatNotification(notification),
|
formatNotification(notification),
|
||||||
imgPath);
|
imgPath,
|
||||||
|
respondStr,
|
||||||
|
sendStr,
|
||||||
|
placeholder);
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
objCxxPostNotification(
|
objCxxPostNotification(room_name,
|
||||||
room_name, room_id, event_id, messageInfo, formatNotification(notification), "");
|
room_id,
|
||||||
|
event_id,
|
||||||
|
messageInfo,
|
||||||
|
formatNotification(notification),
|
||||||
|
"",
|
||||||
|
respondStr,
|
||||||
|
sendStr,
|
||||||
|
placeholder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
#include "notifications/Manager.h"
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#include "ChatPage.h"
|
||||||
|
|
||||||
#import <AppKit/NSImage.h>
|
#import <AppKit/NSImage.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
#import <UserNotifications/UserNotifications.h>
|
#import <UserNotifications/UserNotifications.h>
|
||||||
|
|
||||||
#include <QtMac>
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QtMac>
|
||||||
|
|
||||||
@interface UNNotificationAttachment (UNNotificationAttachmentAdditions)
|
@interface UNNotificationAttachment (UNNotificationAttachmentAdditions)
|
||||||
+ (UNNotificationAttachment *) createFromImageData:(NSData*)imgData identifier:(NSString *)imageFileIdentifier options:(NSDictionary*)attachmentOptions;
|
+ (UNNotificationAttachment*)createFromImageData:(NSData*)imgData
|
||||||
|
identifier:(NSString*)imageFileIdentifier
|
||||||
|
options:
|
||||||
|
(NSDictionary*)attachmentOptions;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation UNNotificationAttachment (UNNotificationAttachmentAdditions)
|
@implementation UNNotificationAttachment (UNNotificationAttachmentAdditions)
|
||||||
+ (UNNotificationAttachment *) createFromImageData:(NSData*)imgData identifier:(NSString *)imageFileIdentifier options:(NSDictionary*)attachmentOptions {
|
+ (UNNotificationAttachment*)createFromImageData:(NSData*)imgData
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
identifier:(NSString*)imageFileIdentifier
|
||||||
NSString *tmpSubFolderName = [[NSProcessInfo processInfo] globallyUniqueString];
|
options:
|
||||||
NSURL *tmpSubFolderURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tmpSubFolderName] isDirectory:true];
|
(NSDictionary*)attachmentOptions
|
||||||
NSError *error = nil;
|
{
|
||||||
[fileManager createDirectoryAtURL:tmpSubFolderURL withIntermediateDirectories:true attributes:nil error:&error];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
if(error) {
|
NSString* tmpSubFolderName =
|
||||||
NSLog(@"%@",[error localizedDescription]);
|
[[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;
|
return nil;
|
||||||
}
|
}
|
||||||
NSURL *fileURL = [tmpSubFolderURL URLByAppendingPathComponent:imageFileIdentifier];
|
NSURL* fileURL =
|
||||||
|
[tmpSubFolderURL URLByAppendingPathComponent:imageFileIdentifier];
|
||||||
[imgData writeToURL:fileURL atomically:true];
|
[imgData writeToURL:fileURL atomically:true];
|
||||||
UNNotificationAttachment *imageAttachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:fileURL options:attachmentOptions error:&error];
|
UNNotificationAttachment* imageAttachment =
|
||||||
if(error) {
|
[UNNotificationAttachment attachmentWithIdentifier:@""
|
||||||
NSLog(@"%@",[error localizedDescription]);
|
URL:fileURL
|
||||||
|
options:attachmentOptions
|
||||||
|
error:&error];
|
||||||
|
if (error) {
|
||||||
|
NSLog(@"%@", [error localizedDescription]);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
return imageAttachment;
|
return imageAttachment;
|
||||||
|
}
|
||||||
}
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NotificationsManager::NotificationsManager(QObject *parent): QObject(parent)
|
NotificationsManager::NotificationsManager(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void NotificationsManager::objCxxPostNotification(
|
||||||
NotificationsManager::objCxxPostNotification(const QString &room_name,
|
const QString& room_name,
|
||||||
const QString &room_id,
|
const QString& room_id,
|
||||||
const QString &event_id,
|
const QString& event_id,
|
||||||
const QString &subtitle,
|
const QString& subtitle,
|
||||||
const QString &informativeText,
|
const QString& informativeText,
|
||||||
const QString &bodyImagePath)
|
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;
|
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
|
[center requestAuthorizationWithOptions:options
|
||||||
completionHandler:^(BOOL granted, NSError * _Nullable error) {
|
completionHandler:^(BOOL granted,
|
||||||
|
NSError* _Nullable error) {
|
||||||
if (!granted) {
|
if (!granted) {
|
||||||
NSLog(@"No notification access");
|
NSLog(@"No notification access");
|
||||||
if (error) {
|
if (error) {
|
||||||
NSLog(@"%@",[error localizedDescription]);
|
NSLog(@"%@", [error localizedDescription]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
|
UNTextInputNotificationAction* replyAction = [UNTextInputNotificationAction actionWithIdentifier:@"ReplyAction"
|
||||||
|
title:respondStr.toNSString()
|
||||||
|
options:UNNotificationActionOptionNone
|
||||||
|
textInputButtonTitle:sendStr.toNSString()
|
||||||
|
textInputPlaceholder:placeholder.toNSString()];
|
||||||
|
|
||||||
content.title = room_name.toNSString();
|
UNNotificationCategory* category = [UNNotificationCategory categoryWithIdentifier:@"ReplyCategory"
|
||||||
content.subtitle = subtitle.toNSString();
|
actions:@[ replyAction ]
|
||||||
content.body = informativeText.toNSString();
|
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.sound = [UNNotificationSound defaultSound];
|
||||||
content.threadIdentifier = room_id.toNSString();
|
content.threadIdentifier = threadIdentifier;
|
||||||
|
content.categoryIdentifier = @"ReplyCategory";
|
||||||
|
|
||||||
if (!bodyImagePath.isEmpty()) {
|
if ([imgUrl length] != 0) {
|
||||||
NSURL *imageURL = [NSURL fileURLWithPath:bodyImagePath.toNSString()];
|
NSURL* imageURL = [NSURL fileURLWithPath:imgUrl];
|
||||||
NSData *img = [NSData dataWithContentsOfURL:imageURL];
|
NSData* img = [NSData dataWithContentsOfURL:imageURL];
|
||||||
NSArray *attachments = [NSMutableArray array];
|
NSArray* attachments = [NSMutableArray array];
|
||||||
UNNotificationAttachment *attachment = [UNNotificationAttachment createFromImageData:img identifier:@"attachment_image.jpeg" options:nil];
|
UNNotificationAttachment* attachment = [UNNotificationAttachment
|
||||||
|
createFromImageData:img
|
||||||
|
identifier:@"attachment_image.jpeg"
|
||||||
|
options:nil];
|
||||||
if (attachment) {
|
if (attachment) {
|
||||||
attachments = [NSMutableArray arrayWithObjects: attachment, nil];
|
attachments = [NSMutableArray arrayWithObjects:attachment, nil];
|
||||||
content.attachments = attachments;
|
content.attachments = attachments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNNotificationRequest *notificationRequest = [UNNotificationRequest requestWithIdentifier:event_id.toNSString() content:content trigger:nil];
|
UNNotificationRequest* notificationRequest =
|
||||||
|
[UNNotificationRequest requestWithIdentifier:identifier
|
||||||
|
content:content
|
||||||
|
trigger:nil];
|
||||||
|
|
||||||
[center addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) {
|
[center addNotificationRequest:notificationRequest
|
||||||
|
withCompletionHandler:^(NSError* _Nullable error) {
|
||||||
if (error != nil) {
|
if (error != nil) {
|
||||||
NSLog(@"Unable to Add Notification Request");
|
NSLog(@"Unable to Add Notification Request: %@", [error localizedDescription]);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[content autorelease];
|
[content autorelease];
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
//unused
|
void NotificationsManager::attachToMacNotifCenter()
|
||||||
void
|
|
||||||
NotificationsManager::actionInvoked(uint, QString)
|
|
||||||
{
|
{
|
||||||
|
UNUserNotificationCenter* center =
|
||||||
|
[UNUserNotificationCenter currentNotificationCenter];
|
||||||
|
|
||||||
|
std::unique_ptr<NotificationManagerProxy> proxy = std::make_unique<NotificationManagerProxy>();
|
||||||
|
|
||||||
|
connect(proxy.get(), &NotificationManagerProxy::notificationReplied, ChatPage::instance(), &ChatPage::sendNotificationReply);
|
||||||
|
|
||||||
|
MacNotificationDelegate* notifDelegate = [[MacNotificationDelegate alloc] initWithProxy:std::move(proxy)];
|
||||||
|
|
||||||
|
center.delegate = notifDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
// unused
|
||||||
NotificationsManager::notificationReplied(uint, QString)
|
void NotificationsManager::actionInvoked(uint, QString) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void NotificationsManager::notificationReplied(uint, QString) { }
|
||||||
NotificationsManager::notificationClosed(uint, uint)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void NotificationsManager::notificationClosed(uint, uint) { }
|
||||||
NotificationsManager::removeNotification(const QString &, const QString &)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
void NotificationsManager::removeNotification(const QString&, const QString&) { }
|
||||||
|
|
22
src/notifications/NotificationManagerProxy.h
Normal file
22
src/notifications/NotificationManagerProxy.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class NotificationManagerProxy final : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
NotificationManagerProxy(QObject *parent = nullptr)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void notificationReplied(const QString &room, const QString &event, const QString &reply);
|
||||||
|
};
|
Loading…
Reference in a new issue