From e0272dcf46611bc61ca9aee3f7576a86a15faebc Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sun, 5 Jun 2022 17:53:33 +0200 Subject: [PATCH] Implement push notification support --- CMakeLists.txt | 2 + src/CMakeLists.txt | 8 ++++ src/controller.cpp | 57 +++++++++++++++++++++++++ src/controller.h | 9 ++++ src/notificationsmanager.cpp | 31 ++++++++++++++ src/notificationsmanager.h | 1 + src/org.kde.neochat.notifier.service.in | 5 +++ 7 files changed, 113 insertions(+) create mode 100644 src/org.kde.neochat.notifier.service.in diff --git a/CMakeLists.txt b/CMakeLists.txt index d53ff6ef8..8baf472a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,8 @@ set_package_properties(KF6Kirigami2 PROPERTIES ) find_package(KF6KirigamiAddons 0.7.2 REQUIRED) +find_package(KUnifiedPush) + if(ANDROID) find_package(OpenSSL) set_package_properties(OpenSSL PROPERTIES diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d2cf98f3..b7f9f4a07 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -333,6 +333,11 @@ endif() target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums) target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF6::I18n KF6::Kirigami2 KF6::Notifications KF6::ConfigCore KF6::ConfigGui KF6::CoreAddons KF6::SonnetCore KF6::ItemModels QuotientQt6 cmark::cmark QCoro::Core) +if(TARGET KUnifiedPush) + target_link_libraries(neochat PUBLIC KUnifiedPush) + target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH) +endif() + kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc) if(NEOCHAT_FLATPAK) @@ -438,6 +443,9 @@ endif() install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +configure_file(org.kde.neochat.notifier.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.notifier.service) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.notifier.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}) + if (NOT ANDROID AND NOT WIN32 AND NOT APPLE) install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins) endif() diff --git a/src/controller.cpp b/src/controller.cpp index c5bd7ba0e..16c44a2b2 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -14,6 +14,13 @@ #include #endif +#ifdef HAVE_KUNIFIEDPUSH +#include +#include +#include +#include +#endif + #include #include #include @@ -41,6 +48,11 @@ #include "roommanager.h" #include "windowcontroller.h" +#ifdef HAVE_KUNIFIEDPUSH +#include +#include +#endif + #if defined(Q_OS_WIN) || defined(Q_OS_MAC) #include "trayicon.h" #elif !defined(Q_OS_ANDROID) @@ -49,9 +61,54 @@ using namespace Quotient; +#ifdef HAVE_KUNIFIEDPUSH +QCoro::Task Controller::setupPush(const QString &endpoint) +{ + while (!activeConnection()) { + co_await qCoro(this, &Controller::activeConnectionChanged); + } + QUrl gatewayEndpoint(endpoint); + gatewayEndpoint.setPath("/_matrix/push/v1/notify"); + QNetworkRequest checkGateway(gatewayEndpoint); + auto reply = co_await NetworkAccessManager::instance()->get(checkGateway); + const QJsonObject replyJson = QJsonDocument::fromJson(reply->readAll()).object(); + if (replyJson["unifiedpush"]["gateway"].toString() == QStringLiteral("matrix")) { + Controller::instance().activeConnection()->callApi(endpoint, + "http", + "neochat-foo1", + "NeoChat", + "Device 1", + "en", + PostPusherJob::PusherData{{gatewayEndpoint.toString()}, " "}); + } else { + qWarning() << "There's no gateway"; + } +} +#endif + Controller::Controller(QObject *parent) : QObject(parent) { +#ifdef HAVE_KUNIFIEDPUSH + const auto serviceName = QStringLiteral("org.kde.neochat.notifier"); + if (!QDBusConnection::sessionBus().registerService(serviceName)) { + qCritical() << "Service name already in use"; + return; + } + auto connector = new KUnifiedPush::Connector(serviceName); + connect(connector, &KUnifiedPush::Connector::stateChanged, [](auto state) { + // TODO ? + }); + connect(connector, &KUnifiedPush::Connector::messageReceived, [](const auto &msg) { + NotificationsManager::instance().postPushNotification(msg); + }); + connect(connector, &KUnifiedPush::Connector::endpointChanged, [this](const auto &endpoint) { + setupPush(endpoint); + }); + + connector->registerClient(i18n("Receiving Matrix messages")); +#endif + Connection::setRoomType(); setApplicationProxy(); diff --git a/src/controller.h b/src/controller.h index 492969ea9..9eb62d828 100644 --- a/src/controller.h +++ b/src/controller.h @@ -15,6 +15,10 @@ #include #include +#ifdef HAVE_KUNIFIEDPUSH +#include +#endif + class NeoChatRoom; class TrayIcon; class QQuickTextDocument; @@ -177,6 +181,11 @@ private: explicit Controller(QObject *parent = nullptr); QPointer m_connection; + +#ifdef HAVE_KUNIFIEDPUSH + QCoro::Task setupPush(const QString &endpoint); +#endif + TrayIcon *m_trayIcon = nullptr; QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account); diff --git a/src/notificationsmanager.cpp b/src/notificationsmanager.cpp index 618bc7aaa..e1938a0bc 100644 --- a/src/notificationsmanager.cpp +++ b/src/notificationsmanager.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include @@ -326,4 +328,33 @@ QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoCha return QPixmap::fromImage(roundedImage); } +void NotificationsManager::postPushNotification(const QByteArray &message) +{ + KNotification *notification = new KNotification("message"_ls); + + const auto json = QJsonDocument::fromJson(message).object(); + + auto sender = json["notification"_ls]["sender_display_name"_ls].toString(); + auto roomName = json["notification"_ls]["room_name"_ls].toString(); + auto roomId = json["notification"_ls]["room_id"_ls].toString(); + auto text = json["notification"_ls]["content"_ls]["body"_ls].toString(); + + if (sender == roomName) { + notification->setTitle(sender); + } else { + notification->setTitle(i18n("%1 (%2)", sender, roomName)); + } + + notification->setText(text.toHtmlEscaped()); + + notification->setDefaultAction(i18n("Open NeoChat in this room")); + connect(notification, &KNotification::defaultActivated, this, [=]() { + WindowController::instance().showAndRaiseWindow(notification->xdgActivationToken()); + }); + + notification->sendEvent(); + + m_notifications.insert(roomId, notification); +} + #include "moc_notificationsmanager.cpp" diff --git a/src/notificationsmanager.h b/src/notificationsmanager.h index fd51e13c7..4a0474118 100644 --- a/src/notificationsmanager.h +++ b/src/notificationsmanager.h @@ -81,6 +81,7 @@ public: * Nothing happens if the given room doesn't have an invite notification. */ void clearInvitationNotification(const QString &roomId); + void postPushNotification(const QByteArray &message); /** * @brief Handle the notifications for the given connection. diff --git a/src/org.kde.neochat.notifier.service.in b/src/org.kde.neochat.notifier.service.in new file mode 100644 index 000000000..82e929e00 --- /dev/null +++ b/src/org.kde.neochat.notifier.service.in @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: none +# SPDX-License-Identifier: CC0-1.0 +[D-BUS Service] +Name=org.kde.neochat.notifier +Exec=@CMAKE_INSTALL_PREFIX@/bin/neochat