diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index 29747fbe..336ea7c3 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -56,6 +56,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
: QWidget(parent)
, isConnected_(true)
, userSettings_{userSettings}
+ , notificationsManager(this)
{
setObjectName("chatPage");
@@ -541,6 +542,15 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
room_list_->setRoomFilter(communities_[communityId]->getRoomList());
});
+ connect(¬ificationsManager,
+ &NotificationsManager::notificationClicked,
+ this,
+ [this](const QString &roomid, const QString &eventid) {
+ Q_UNUSED(eventid)
+ room_list_->highlightSelectedRoom(roomid);
+ activateWindow();
+ });
+
setGroupViewState(userSettings_->isGroupViewEnabled());
connect(userSettings_.data(),
@@ -998,11 +1008,14 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res)
if (isRoomActive(room_id))
continue;
- NotificationsManager::postNotification(
+ notificationsManager.postNotification(
+ room_id,
+ QString::fromStdString(event_id),
QString::fromStdString(
cache::client()->singleRoomInfo(item.room_id).name),
Cache::displayName(room_id, user_id),
- utils::event_body(item.event));
+ utils::event_body(item.event),
+ cache::client()->getRoomAvatar(room_id));
}
} catch (const lmdb::error &e) {
nhlog::db()->warn("error while sending desktop notification: {}", e.what());
diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp
index a913128e..80fdb9d8 100644
--- a/src/notifications/ManagerLinux.cpp
+++ b/src/notifications/ManagerLinux.cpp
@@ -1,7 +1,158 @@
#include "notifications/Manager.h"
+#include <QImage>
+#include <QDebug>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusMetaType>
+#include <QtDBus/QDBusConnection>
+
+NotificationsManager::NotificationsManager(QObject *parent) :
+ QObject(parent),
+ dbus(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ QDBusConnection::sessionBus(),
+ this)
+{
+ qDBusRegisterMetaType<QImage>();
+
+ //connectSlot("ActionInvoked", SLOT(actionInvoked(uint, QString)));
+ //connectSlot("NotificationClosed", SLOT(notificationClosed(uint, uint)));
+ QDBusConnection::sessionBus().connect(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ "ActionInvoked",
+ this,
+ SLOT(actionInvoked(uint, QString)));
+ QDBusConnection::sessionBus().connect(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ "NotificationClosed",
+ this,
+ SLOT(notificationClosed(uint, uint)));
+}
+
+void
+NotificationsManager::postNotification(const QString &roomid,
+ const QString &eventid,
+ const QString &roomname,
+ const QString &sender,
+ const QString &text,
+ const QImage &icon)
+{
+ uint id = showNotification(roomname, sender+": "+text, icon);
+ notificationIds[id] = roomEventId{roomid,eventid};
+}
+/**
+ * This function is based on code from
+ * https://github.com/rohieb/StratumsphereTrayIcon
+ * Copyright (C) 2012 Roland Hieber <rohieb@rohieb.name>
+ * Licensed under the GNU General Public License, version 3
+ */
+uint
+NotificationsManager::showNotification(const QString summary, const QString text, const QImage image)
+{
+ QVariantMap hints;
+ hints["image_data"] = image;
+ QList<QVariant> 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)0; // timeout in ms
+
+ static QDBusInterface notifyApp(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications");
+ QDBusMessage reply = notifyApp.callWithArgumentList(
+ QDBus::AutoDetect,
+ "Notify",
+ argumentList);
+ if(reply.type() == QDBusMessage::ErrorMessage) {
+ qDebug() << "D-Bus Error:" << reply.errorMessage();
+ return 0;
+ } else {
+ return reply.arguments().first().toUInt();
+ }
+ return true;
+}
+
void
-NotificationsManager::postNotification(const QString &, const QString &, const QString &)
+NotificationsManager::actionInvoked(uint id, QString action)
{
- // TODO: To be implemented
+ if (action == "default" && notificationIds.contains(id)) {
+ roomEventId idEntry = notificationIds[id];
+ emit notificationClicked(idEntry.roomId, idEntry.eventId);
+ }
+}
+
+void
+NotificationsManager::notificationClosed(uint id, uint reason)
+{
+ Q_UNUSED(reason);
+ notificationIds.remove(id);
+}
+
+/**
+ * Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify
+ *
+ * This function is from the Clementine project (see
+ * http://www.clementine-player.org) and licensed under the GNU General Public
+ * License, version 3 or later.
+ *
+ * Copyright 2010, David Sansome <me@davidsansome.com>
+ */
+QDBusArgument& operator<<(QDBusArgument& arg, const QImage& image) {
+ if(image.isNull()) {
+ arg.beginStructure();
+ arg << 0 << 0 << 0 << false << 0 << 0 << QByteArray();
+ arg.endStructure();
+ return arg;
+ }
+
+ QImage scaled = image.scaledToHeight(100, Qt::SmoothTransformation);
+ scaled = scaled.convertToFormat(QImage::Format_ARGB32);
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ // ABGR -> ARGB
+ QImage i = scaled.rgbSwapped();
+#else
+ // ABGR -> GBAR
+ QImage i(scaled.size(), scaled.format());
+ for (int y = 0; y < i.height(); ++y) {
+ QRgb* p = (QRgb*) scaled.scanLine(y);
+ QRgb* q = (QRgb*) i.scanLine(y);
+ QRgb* end = p + scaled.width();
+ while (p < end) {
+ *q = qRgba(qGreen(*p), qBlue(*p), qAlpha(*p), qRed(*p));
+ p++;
+ q++;
+ }
+ }
+#endif
+
+ arg.beginStructure();
+ arg << i.width();
+ arg << i.height();
+ arg << i.bytesPerLine();
+ arg << i.hasAlphaChannel();
+ int channels = i.isGrayscale() ? 1 : (i.hasAlphaChannel() ? 4 : 3);
+ arg << i.depth() / channels;
+ arg << channels;
+ arg << QByteArray(reinterpret_cast<const char*>(i.bits()), i.byteCount());
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument& operator>>(const QDBusArgument& arg, QImage&) {
+ // This is needed to link but shouldn't be called.
+ Q_ASSERT(0);
+ return arg;
}
diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm
index 48fb46ca..66ef713f 100644
--- a/src/notifications/ManagerMac.mm
+++ b/src/notifications/ManagerMac.mm
@@ -7,16 +7,42 @@
- (void)set_identityImage:(NSImage *)image;
@end
+NotificationsManager::NotificationsManager(QObject *parent): QObject(parent)
+{
+
+}
+
void
-NotificationsManager::postNotification(const QString &roomName, const QString &userName, const QString &message)
+NotificationsManager::postNotification(
+ const QString &roomId,
+ const QString &eventId,
+ const QString &roomName,
+ const QString &senderName,
+ const QString &text,
+ const QImage &icon)
{
+ Q_UNUSED(roomId);
+ Q_UNUSED(eventId);
+ Q_UNUSED(icon);
+
NSUserNotification * notif = [[NSUserNotification alloc] init];
notif.title = roomName.toNSString();
- notif.subtitle = QString("%1 sent a message").arg(userName).toNSString();
- notif.informativeText = message.toNSString();
+ notif.subtitle = QString("%1 sent a message").arg(senderName).toNSString();
+ notif.informativeText = text.toNSString();
notif.soundName = NSUserNotificationDefaultSoundName;
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notif];
[notif autorelease];
}
+
+//unused
+void
+NotificationsManager::actionInvoked(uint, QString)
+{
+}
+
+void
+NotificationsManager::notificationClosed(uint, uint)
+{
+}
diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp
index 7503e852..90367d9a 100644
--- a/src/notifications/ManagerWin.cpp
+++ b/src/notifications/ManagerWin.cpp
@@ -27,15 +27,25 @@ init()
}
}
+NotificationsManager::NotificationsManager(QObject *parent): QObject(parent)
+{
+
+}
+
void
-NotificationsManager::postNotification(const QString &room, const QString &user, const QString &msg)
+NotificationsManager::postNotification(const QString &, //roomid
+ const QString &, //eventid
+ const QString &roomname,
+ const QString &sender,
+ const QString &text,
+ const QImage &) //icon
{
if (!isInitialized)
init();
auto templ = WinToastTemplate(WinToastTemplate::ImageAndText02);
- if (room != user)
- templ.setTextField(QString("%1 - %2").arg(user).arg(room).toStdWString(),
+ if (roomname != sender)
+ templ.setTextField(QString("%1 - %2").arg(sender).arg(roomname).toStdWString(),
WinToastTemplate::FirstLine);
else
templ.setTextField(QString("%1").arg(user).toStdWString(),
@@ -46,3 +56,14 @@ NotificationsManager::postNotification(const QString &room, const QString &user,
WinToast::instance()->showToast(templ, new CustomHandler());
}
+
+//unused
+void
+NotificationsManager::actionInvoked(uint, QString)
+{
+}
+
+void
+NotificationsManager::notificationClosed(uint, uint)
+{
+}
|