mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 12:38:48 +03:00
Merge branch 'macos_notification_actions' into 'master'
Add ability to respond to notifications on macOS See merge request nheko-reborn/nheko!21
This commit is contained in:
commit
a6f53699f5
11 changed files with 307 additions and 99 deletions
|
@ -13,3 +13,6 @@ KeepEmptyLinesAtTheStartOfBlocks: false
|
|||
PointerAlignment: Right
|
||||
Cpp11BracedListStyle: true
|
||||
PenaltyReturnTypeOnItsOwnLine: 0
|
||||
---
|
||||
BasedOnStyle: WebKit
|
||||
Language: ObjC
|
|
@ -629,9 +629,9 @@ set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC})
|
|||
|
||||
if (APPLE)
|
||||
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")
|
||||
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()
|
||||
elseif (WIN32)
|
||||
file(DOWNLOAD
|
||||
|
|
|
@ -152,16 +152,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QObject *parent)
|
|||
connect(notificationsManager,
|
||||
&NotificationsManager::sendNotificationReply,
|
||||
this,
|
||||
[this](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();
|
||||
}
|
||||
});
|
||||
&ChatPage::sendNotificationReply);
|
||||
|
||||
connect(
|
||||
this,
|
||||
|
@ -1583,6 +1574,19 @@ ChatPage::handleMatrixUri(QString uri)
|
|||
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
|
||||
ChatPage::handleMatrixUri(const QUrl &uri)
|
||||
{
|
||||
|
|
|
@ -110,6 +110,7 @@ public slots:
|
|||
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
|
||||
void decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescription keyDesc,
|
||||
const SecretsToDecrypt &secrets);
|
||||
void sendNotificationReply(const QString &roomid, const QString &eventid, const QString &body);
|
||||
signals:
|
||||
void connectionLost();
|
||||
void connectionRestored();
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#if defined(Q_OS_MAC)
|
||||
#include "emoji/MacHelper.h"
|
||||
#include "notifications/Manager.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
// nheko has a proper menu bar with more functionality.
|
||||
MacHelper::initializeMenus();
|
||||
|
||||
// Need to set up notification delegate so users can respond to messages from within the
|
||||
// notification itself.
|
||||
NotificationsManager::attachToMacNotifCenter();
|
||||
#endif
|
||||
|
||||
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 &subtitle,
|
||||
const QString &informativeText,
|
||||
const QString &bodyImagePath);
|
||||
const QString &bodyImagePath,
|
||||
const QString &respondStr,
|
||||
const QString &sendStr,
|
||||
const QString &placeholder);
|
||||
|
||||
public:
|
||||
static void attachToMacNotifCenter();
|
||||
#endif
|
||||
|
||||
#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>>(
|
||||
¬ification.event) != nullptr;
|
||||
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) {
|
||||
// TODO: decrypt this message if the decryption setting is on in the UserSettings
|
||||
const QString messageInfo = (isReply ? tr("%1 replied with an encrypted message")
|
||||
: tr("%1 sent an encrypted message"))
|
||||
.arg(sender);
|
||||
objCxxPostNotification(room_name, room_id, event_id, messageInfo, "", "");
|
||||
objCxxPostNotification(
|
||||
room_name, room_id, event_id, messageInfo, "", "", respondStr, sendStr, placeholder);
|
||||
} else {
|
||||
const QString messageInfo =
|
||||
(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(
|
||||
QString::fromStdString(mtx::accessors::url(notification.event)).remove("mxc://"),
|
||||
QSize(200, 80),
|
||||
[this, notification, room_name, room_id, event_id, messageInfo](
|
||||
QString, QSize, QImage, QString imgPath) {
|
||||
[this,
|
||||
notification,
|
||||
room_name,
|
||||
room_id,
|
||||
event_id,
|
||||
messageInfo,
|
||||
respondStr,
|
||||
sendStr,
|
||||
placeholder](QString, QSize, QImage, QString imgPath) {
|
||||
objCxxPostNotification(room_name,
|
||||
room_id,
|
||||
event_id,
|
||||
messageInfo,
|
||||
formatNotification(notification),
|
||||
imgPath);
|
||||
imgPath,
|
||||
respondStr,
|
||||
sendStr,
|
||||
placeholder);
|
||||
});
|
||||
else
|
||||
objCxxPostNotification(
|
||||
room_name, room_id, event_id, messageInfo, formatNotification(notification), "");
|
||||
objCxxPostNotification(room_name,
|
||||
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"
|
||||
|
||||
#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]);
|
||||
+ (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];
|
||||
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]);
|
||||
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) {
|
||||
completionHandler:^(BOOL granted,
|
||||
NSError* _Nullable error) {
|
||||
if (!granted) {
|
||||
NSLog(@"No notification access");
|
||||
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();
|
||||
content.subtitle = subtitle.toNSString();
|
||||
content.body = informativeText.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 = room_id.toNSString();
|
||||
content.threadIdentifier = threadIdentifier;
|
||||
content.categoryIdentifier = @"ReplyCategory";
|
||||
|
||||
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 ([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];
|
||||
attachments = [NSMutableArray arrayWithObjects:attachment, nil];
|
||||
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) {
|
||||
NSLog(@"Unable to Add Notification Request");
|
||||
NSLog(@"Unable to Add Notification Request: %@", [error localizedDescription]);
|
||||
}
|
||||
}];
|
||||
|
||||
[content autorelease];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
//unused
|
||||
void
|
||||
NotificationsManager::actionInvoked(uint, QString)
|
||||
void NotificationsManager::attachToMacNotifCenter()
|
||||
{
|
||||
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
|
||||
NotificationsManager::notificationReplied(uint, QString)
|
||||
{
|
||||
}
|
||||
// unused
|
||||
void NotificationsManager::actionInvoked(uint, QString) { }
|
||||
|
||||
void
|
||||
NotificationsManager::notificationClosed(uint, uint)
|
||||
{
|
||||
}
|
||||
void NotificationsManager::notificationReplied(uint, QString) { }
|
||||
|
||||
void
|
||||
NotificationsManager::removeNotification(const QString &, const QString &)
|
||||
{}
|
||||
void NotificationsManager::notificationClosed(uint, uint) { }
|
||||
|
||||
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