summary refs log tree commit diff
path: root/src/notifications
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-03-17 19:08:17 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2021-03-17 19:18:07 +0100
commite5d75c814b2175dc37beabff3b0421de59a3e93e (patch)
tree97670bfa02e365ef527ad18fad3d66e16c3ef8d2 /src/notifications
parentRefactor image download code to be reusable (diff)
downloadnheko-e5d75c814b2175dc37beabff3b0421de59a3e93e.tar.xz
Clean up notification code a bit
Diffstat (limited to 'src/notifications')
-rw-r--r--src/notifications/Manager.cpp104
-rw-r--r--src/notifications/Manager.h12
-rw-r--r--src/notifications/ManagerLinux.cpp126
-rw-r--r--src/notifications/ManagerMac.cpp37
-rw-r--r--src/notifications/ManagerWin.cpp21
5 files changed, 119 insertions, 181 deletions
diff --git a/src/notifications/Manager.cpp b/src/notifications/Manager.cpp

index 30e74d33..322213dd 100644 --- a/src/notifications/Manager.cpp +++ b/src/notifications/Manager.cpp
@@ -2,89 +2,35 @@ #include "Cache.h" #include "EventAccessors.h" -#include "Logging.h" -#include "MatrixClient.h" #include "Utils.h" -#include <QFile> -#include <QImage> -#include <QStandardPaths> - -#include <mtxclient/crypto/client.hpp> - QString -NotificationsManager::cacheImage(const mtx::events::collections::TimelineEvents &event) +NotificationsManager::getMessageTemplate(const mtx::responses::Notification &notification) { - const auto url = mtx::accessors::url(event); - auto encryptionInfo = mtx::accessors::file(event); - - auto filename = QString::fromStdString(mtx::accessors::body(event)); - QString path{QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + - filename}; - - bool downloadComplete = false; - - http::client()->download( - url, - [&downloadComplete, &path, url, encryptionInfo](const std::string &data, - const std::string &, - const std::string &, - mtx::http::RequestErr err) { - if (err) { - nhlog::net()->warn("failed to retrieve image {}: {} {}", - url, - err->matrix_error.error, - static_cast<int>(err->status_code)); - // the image doesn't exist, so delete the path - path.clear(); - downloadComplete = true; - return; - } - - try { - auto temp = data; - if (encryptionInfo) - temp = mtx::crypto::to_string( - mtx::crypto::decrypt_file(temp, encryptionInfo.value())); - - QFile file{path}; - - if (!file.open(QIODevice::WriteOnly)) { - path.clear(); - downloadComplete = true; - return; - } - - // delete any existing file content - file.resize(0); - - // resize the image - QImage img{utils::readImage(QByteArray{temp.data()})}; - - if (img.isNull()) { - path.clear(); - downloadComplete = true; - return; - } - -#ifdef NHEKO_DBUS_SYS // the images in D-Bus notifications are to be 200x100 max - img.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation) - .save(&file); -#else - img.save(&file); -#endif // NHEKO_DBUS_SYS - - file.close(); - - downloadComplete = true; - return; - } catch (const std::exception &e) { - nhlog::ui()->warn("Error while caching file to: {}", e.what()); - } - }); + const auto sender = + cache::displayName(QString::fromStdString(notification.room_id), + QString::fromStdString(mtx::accessors::sender(notification.event))); - while (!downloadComplete) - continue; + // TODO: decrypt this message if the decryption setting is on in the UserSettings + if (auto msg = std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>( + &notification.event); + msg != nullptr) { + return tr("%1 sent an encrypted message").arg(sender); + } - return path.toHtmlEscaped(); + if (mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) { + return tr("* %1 %2", + "Format an emote message in a notification, %1 is the sender, %2 the " + "message") + .arg(sender); + } else if (utils::isReply(notification.event)) { + return tr("%1 replied: %2", + "Format a reply in a notification. %1 is the sender, %2 the message") + .arg(sender); + } else { + return tr("%1: %2", + "Format a normal message in a notification. %1 is the sender, %2 the " + "message") + .arg(sender); + } } diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h
index a1ef9f98..416530e0 100644 --- a/src/notifications/Manager.h +++ b/src/notifications/Manager.h
@@ -43,14 +43,15 @@ public: signals: void notificationClicked(const QString roomId, const QString eventId); void sendNotificationReply(const QString roomId, const QString eventId, const QString body); + void systemPostNotificationCb(const QString &room_id, + const QString &event_id, + const QString &roomName, + const QString &text, + const QImage &icon); public slots: void removeNotification(const QString &roomId, const QString &eventId); -private: - QString cacheImage(const mtx::events::collections::TimelineEvents &event); - QString formatNotification(const mtx::responses::Notification &notification); - #if defined(NHEKO_DBUS_SYS) public: void closeNotifications(QString roomId); @@ -95,6 +96,9 @@ private slots: void actionInvoked(uint id, QString action); void notificationClosed(uint id, uint reason); void notificationReplied(uint id, QString reply); + +private: + QString getMessageTemplate(const mtx::responses::Notification &notification); }; #if defined(NHEKO_DBUS_SYS) diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp
index 5581252d..2b0e56e2 100644 --- a/src/notifications/ManagerLinux.cpp +++ b/src/notifications/ManagerLinux.cpp
@@ -8,6 +8,7 @@ #include <QDebug> #include <QImage> #include <QRegularExpression> +#include <QStringBuilder> #include <QTextDocumentFragment> #include <functional> @@ -17,6 +18,7 @@ #include "Cache.h" #include "EventAccessors.h" +#include "MxcImageProvider.h" #include "Utils.h" NotificationsManager::NotificationsManager(QObject *parent) @@ -59,6 +61,12 @@ NotificationsManager::NotificationsManager(QObject *parent) "NotificationReplied", this, SLOT(notificationReplied(uint, QString))); + + connect(this, + &NotificationsManager::systemPostNotificationCb, + this, + &NotificationsManager::systemPostNotification, + Qt::QueuedConnection); } void @@ -69,9 +77,61 @@ NotificationsManager::postNotification(const mtx::responses::Notification &notif const auto event_id = QString::fromStdString(mtx::accessors::event_id(notification.event)); const auto room_name = QString::fromStdString(cache::singleRoomInfo(notification.room_id).name); - const auto text = formatNotification(notification); - systemPostNotification(room_id, event_id, room_name, text, icon); + auto postNotif = [this, room_id, event_id, room_name, icon](QString text) { + emit systemPostNotificationCb(room_id, event_id, room_name, text, icon); + }; + + QString template_ = getMessageTemplate(notification); + // TODO: decrypt this message if the decryption setting is on in the UserSettings + if (std::holds_alternative<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>( + notification.event)) { + postNotif(template_); + return; + } + + if (hasMarkup_) { + if (hasImages_ && mtx::accessors::msg_type(notification.event) == + mtx::events::MessageType::Image) { + MxcImageProvider::download( + QString::fromStdString(mtx::accessors::url(notification.event)) + .remove("mxc://"), + QSize(200, 80), + [postNotif, notification, template_]( + QString, QSize, QImage, QString imgPath) { + if (imgPath.isEmpty()) + postNotif(template_ + .arg(utils::stripReplyFallbacks( + notification.event, {}, {}) + .quoted_formatted_body) + .replace("<em>", "<i>") + .replace("</em>", "</i>") + .replace("<strong>", "<b>") + .replace("</strong>", "</b>")); + else + postNotif(template_.arg( + QStringLiteral("<br><img src=\"file:///") % imgPath % + "\" alt=\"" % + mtx::accessors::formattedBodyWithFallback( + notification.event) % + "\">")); + }); + return; + } + + postNotif( + template_ + .arg( + utils::stripReplyFallbacks(notification.event, {}, {}).quoted_formatted_body) + .replace("<em>", "<i>") + .replace("</em>", "</i>") + .replace("<strong>", "<b>") + .replace("</strong>", "</b>")); + return; + } + + postNotif( + template_.arg(utils::stripReplyFallbacks(notification.event, {}, {}).quoted_body)); } /** @@ -183,68 +243,6 @@ NotificationsManager::notificationClosed(uint id, uint reason) } /** - * @param text This should be an HTML-formatted string. - * - * If D-Bus says that notifications can have body markup, this function will - * automatically format the notification to follow the supported HTML subset - * specified at https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/Markup/ - */ -QString -NotificationsManager::formatNotification(const mtx::responses::Notification &notification) -{ - const auto sender = - cache::displayName(QString::fromStdString(notification.room_id), - QString::fromStdString(mtx::accessors::sender(notification.event))); - - // TODO: decrypt this message if the decryption setting is on in the UserSettings - if (auto msg = std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>( - &notification.event); - msg != nullptr) - return tr("%1 sent an encrypted message").arg(sender); - - const auto messageLeadIn = - ((mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) - ? "* " + sender + " " - : sender + - (utils::isReply(notification.event) - ? tr(" replied", - "Used to denote that this message is a reply to another " - "message. Displayed as 'foo replied: message'.") - : "") + - ": "); - - if (hasMarkup_) { - if (hasImages_ && mtx::accessors::msg_type(notification.event) == - mtx::events::MessageType::Image) { - QString imgPath = cacheImage(notification.event); - if (imgPath.isNull()) - return mtx::accessors::formattedBodyWithFallback(notification.event) - .prepend(messageLeadIn); - else - return QString("<img src=\"file:///" + imgPath + "\" alt=\"" + - mtx::accessors::formattedBodyWithFallback( - notification.event) + - "\">") - .prepend(messageLeadIn); - } - - return mtx::accessors::formattedBodyWithFallback(notification.event) - .prepend(messageLeadIn) - .replace("<em>", "<i>") - .replace("</em>", "</i>") - .replace("<strong>", "<b>") - .replace("</strong>", "</b>") - .replace(QRegularExpression("(<mx-reply>.+\\<\\/mx-reply\\>)"), ""); - } - - return QTextDocumentFragment::fromHtml( - mtx::accessors::formattedBodyWithFallback(notification.event) - .replace(QRegularExpression("<mx-reply>.+</mx-reply>"), "")) - .toPlainText() - .prepend(messageLeadIn); -} - -/** * Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify * * This function is from the Clementine project (see diff --git a/src/notifications/ManagerMac.cpp b/src/notifications/ManagerMac.cpp
index de5d0875..3a6becad 100644 --- a/src/notifications/ManagerMac.cpp +++ b/src/notifications/ManagerMac.cpp
@@ -5,6 +5,7 @@ #include "Cache.h" #include "EventAccessors.h" +#include "MxcImageProvider.h" #include "Utils.h" #include <mtx/responses/notifications.hpp> @@ -14,17 +15,7 @@ QString NotificationsManager::formatNotification(const mtx::responses::Notification &notification) { - const auto sender = - cache::displayName(QString::fromStdString(notification.room_id), - QString::fromStdString(mtx::accessors::sender(notification.event))); - - return QTextDocumentFragment::fromHtml( - mtx::accessors::formattedBodyWithFallback(notification.event) - .replace(QRegularExpression("<mx-reply>.+</mx-reply>"), "")) - .toPlainText() - .prepend((mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) - ? "* " + sender + " " - : ""); + return utils::stripReplyFallbacks(notification.event, {}, {}).quoted_body; } void @@ -39,25 +30,33 @@ NotificationsManager::postNotification(const mtx::responses::Notification &notif cache::displayName(QString::fromStdString(notification.room_id), QString::fromStdString(mtx::accessors::sender(notification.event))); - QImage image; - if (mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Image) - image = QImage{cacheImage(notification.event)}; - const auto isEncrypted = std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>( &notification.event) != nullptr; const auto isReply = utils::isReply(notification.event); - 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, messageInfo, "", image); + objCxxPostNotification(room_name, messageInfo, "", QImage()); } else { const QString messageInfo = (isReply ? tr("%1 replied to a message") : tr("%1 sent a message")).arg(sender); - objCxxPostNotification( - room_name, messageInfo, formatNotification(notification), image); + if (mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Image) + 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); + }); + else + objCxxPostNotification( + room_name, messageInfo, formatNotification(notification), QImage()); } } diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp
index baafb6dc..d37bff67 100644 --- a/src/notifications/ManagerWin.cpp +++ b/src/notifications/ManagerWin.cpp
@@ -108,20 +108,11 @@ NotificationsManager::formatNotification(const mtx::responses::Notification &not cache::displayName(QString::fromStdString(notification.room_id), QString::fromStdString(mtx::accessors::sender(notification.event))); - const auto messageLeadIn = - ((mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) - ? "* " + sender + " " - : sender + - (utils::isReply(notification.event) - ? tr(" replied", - "Used to denote that this message is a reply to another " - "message. Displayed as 'foo replied: message'.") - : "") + - ": "); + const auto template_ = getMessageTemplate(notification); + if (std::holds_alternative<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>( + notification.event)) { + return template_; + } - return QTextDocumentFragment::fromHtml( - mtx::accessors::formattedBodyWithFallback(notification.event) - .replace(QRegularExpression("<mx-reply>.+</mx-reply>"), "")) - .toPlainText() - .prepend(messageLeadIn); + return template_.arg(utils::stripReplyFallbacks(notification.event, {}, {}).quoted_body); }