From 4b4c321397e0681f306eade889e0fab6dbbe94f5 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 7 Jan 2021 10:44:59 +0100 Subject: [PATCH] Allow inline replies from notifications on linux --- src/ChatPage.cpp | 8 ++++++ src/notifications/Manager.h | 2 ++ src/notifications/ManagerLinux.cpp | 42 +++++++++++++++++++++------- src/timeline/InputBar.h | 2 +- src/timeline/TimelineViewManager.cpp | 12 ++++++++ src/timeline/TimelineViewManager.h | 3 ++ 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 37248022..4e87349a 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -282,6 +282,14 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) room_list_->highlightSelectedRoom(roomid); activateWindow(); }); + connect(¬ificationsManager, + &NotificationsManager::sendNotificationReply, + this, + [this](const QString &roomid, const QString &eventid, const QString &body) { + view_manager_->queueReply(roomid, eventid, body); + room_list_->highlightSelectedRoom(roomid); + activateWindow(); + }); setGroupViewState(userSettings_->groupView()); diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h index e6be5953..b5347bd6 100644 --- a/src/notifications/Manager.h +++ b/src/notifications/Manager.h @@ -36,6 +36,7 @@ public: signals: void notificationClicked(const QString roomId, const QString eventId); + void sendNotificationReply(const QString roomId, const QString eventId, const QString body); public slots: void removeNotification(const QString &roomId, const QString &eventId); @@ -58,6 +59,7 @@ private: private slots: void actionInvoked(uint id, QString action); void notificationClosed(uint id, uint reason); + void notificationReplied(uint id, QString reply); }; #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp index b9eca1a8..b5e9a6a4 100644 --- a/src/notifications/ManagerLinux.cpp +++ b/src/notifications/ManagerLinux.cpp @@ -28,6 +28,12 @@ NotificationsManager::NotificationsManager(QObject *parent) "NotificationClosed", this, SLOT(notificationClosed(uint, uint))); + QDBusConnection::sessionBus().connect("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + "NotificationReplied", + this, + SLOT(notificationReplied(uint, QString))); } void @@ -56,14 +62,19 @@ NotificationsManager::showNotification(const QString summary, hints["image-data"] = image; hints["sound-name"] = "message-new-instant"; QList argumentList; - argumentList << "nheko"; // app_name - argumentList << (uint)0; // replace_id - argumentList << ""; // app_icon - argumentList << summary; // summary - argumentList << text; // body - argumentList << (QStringList("default") << "reply"); // actions - argumentList << hints; // hints - argumentList << (int)-1; // timeout in ms + argumentList << "nheko"; // app_name + argumentList << (uint)0; // replace_id + argumentList << ""; // app_icon + argumentList << summary; // summary + argumentList << text; // body + // The list of actions has always the action name and then a localized version of that + // action. Currently we just use an empty string for that. + // TODO(Nico): Look into what to actually put there. + argumentList << (QStringList("default") << "" + << "inline-reply" + << ""); // actions + argumentList << hints; // hints + argumentList << (int)-1; // timeout in ms static QDBusInterface notifyApp("org.freedesktop.Notifications", "/org/freedesktop/Notifications", @@ -121,9 +132,20 @@ NotificationsManager::removeNotification(const QString &roomId, const QString &e void NotificationsManager::actionInvoked(uint id, QString action) { - if (action == "default" && notificationIds.contains(id)) { + if (notificationIds.contains(id)) { roomEventId idEntry = notificationIds[id]; - emit notificationClicked(idEntry.roomId, idEntry.eventId); + if (action == "default") { + emit notificationClicked(idEntry.roomId, idEntry.eventId); + } + } +} + +void +NotificationsManager::notificationReplied(uint id, QString reply) +{ + if (notificationIds.contains(id)) { + roomEventId idEntry = notificationIds[id]; + emit sendNotificationReply(idEntry.roomId, idEntry.eventId, reply); } } diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index 27aa4bc3..89ca34fe 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -42,6 +42,7 @@ public slots: void openFileSelection(); bool uploading() const { return uploading_; } void callButton(); + void message(QString body); QObject *completerFor(QString completerName); @@ -54,7 +55,6 @@ signals: void uploadingChanged(bool value); private: - void message(QString body); void emote(QString body); void command(QString name, QString args); void image(const QString &filename, diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index f31b5ea5..f10c2c0d 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -508,6 +508,18 @@ TimelineViewManager::initWithMessages(const std::vector &roomIds) addRoom(roomId); } +void +TimelineViewManager::queueReply(const QString &roomid, + const QString &repliedToEvent, + const QString &replyBody) +{ + auto room = models.find(roomid); + if (room != models.end()) { + room.value()->setReply(repliedToEvent); + room.value()->input()->message(replyBody); + } +} + void TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey) { diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index f346acf8..1cec0939 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -120,6 +120,9 @@ public slots: } void updateColorPalette(); + void queueReply(const QString &roomid, + const QString &repliedToEvent, + const QString &replyBody); void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey); void queueCallMessage(const QString &roomid, const mtx::events::msg::CallInvite &); void queueCallMessage(const QString &roomid, const mtx::events::msg::CallCandidates &);