diff --git a/src/controller.cpp b/src/controller.cpp index a591f098e..fb893454c 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -18,6 +18,7 @@ #include #include "neochatconfig.h" +#include "neochatconnection.h" #include "neochatroom.h" #include "notificationsmanager.h" #include "proxycontroller.h" @@ -168,6 +169,10 @@ void Controller::addConnection(NeoChatConnection *c) dropConnection(c); }); connect(c, &NeoChatConnection::badgeNotificationCountChanged, this, &Controller::updateBadgeNotificationCount); + connect(c, &NeoChatConnection::syncDone, this, [this, c]() { + m_notificationsManager.handleNotifications(c); + }); + connect(c, &NeoChatConnection::showInviteNotification, &m_notificationsManager, &NotificationsManager::postInviteNotification); c->sync(); @@ -178,6 +183,8 @@ void Controller::dropConnection(NeoChatConnection *c) { Q_ASSERT_X(c, __FUNCTION__, "Attempt to drop a null connection"); + c->disconnect(this); + c->disconnect(&m_notificationsManager); m_accountRegistry.drop(c); Q_EMIT connectionDropped(c); } @@ -327,6 +334,7 @@ void Controller::setActiveConnection(NeoChatConnection *connection) if (m_connection != nullptr) { m_connection->disconnect(this); + m_connection->disconnect(&m_notificationsManager); } m_connection = connection; @@ -350,7 +358,7 @@ void Controller::listenForNotifications() connect(timer, &QTimer::timeout, qGuiApp, &QGuiApplication::quit); connect(connector, &KUnifiedPush::Connector::messageReceived, [timer](const QByteArray &data) { - NotificationsManager::instance().postPushNotification(data); + m_notificationsManager.postPushNotification(data); timer->stop(); }); @@ -362,6 +370,11 @@ void Controller::listenForNotifications() #endif } +void Controller::clearInvitationNotification(const QString &roomId) +{ + m_notificationsManager.clearInvitationNotification(roomId); +} + void Controller::updateBadgeNotificationCount(NeoChatConnection *connection, int count) { if (connection == m_connection) { diff --git a/src/controller.h b/src/controller.h index 78cfab15f..955cbe9d2 100644 --- a/src/controller.h +++ b/src/controller.h @@ -7,6 +7,7 @@ #include #include "neochatconnection.h" +#include "notificationsmanager.h" #include class TrayIcon; @@ -88,6 +89,13 @@ public: */ static void listenForNotifications(); + /** + * @brief Clear an existing invite notification for the given room. + * + * Nothing happens if the given room doesn't have an invite notification. + */ + Q_INVOKABLE void clearInvitationNotification(const QString &roomId); + Q_INVOKABLE QString loadFileContent(const QString &path) const; Quotient::AccountRegistry &accounts(); @@ -123,6 +131,8 @@ private: QString m_endpoint; QStringList m_shownImages; + NotificationsManager m_notificationsManager; + private Q_SLOTS: void invokeLogin(); void setQuitOnLastWindowClosed(); diff --git a/src/neochatconnection.cpp b/src/neochatconnection.cpp index 98cefd4de..b15b4ff67 100644 --- a/src/neochatconnection.cpp +++ b/src/neochatconnection.cpp @@ -10,7 +10,6 @@ #include "jobs/neochatdeactivateaccountjob.h" #include "neochatconfig.h" #include "neochatroom.h" -#include "notificationsmanager.h" #include "spacehierarchycache.h" #include @@ -66,10 +65,6 @@ void NeoChatConnection::connectSignals() }); connect(this, &NeoChatConnection::syncDone, this, [this] { setIsOnline(true); - - connect(this, &NeoChatConnection::syncDone, this, [this]() { - NotificationsManager::instance().handleNotifications(this); - }); }); connect(this, &NeoChatConnection::networkError, this, [this]() { setIsOnline(false); @@ -114,6 +109,10 @@ void NeoChatConnection::connectSignals() Q_EMIT homeHaveHighlightNotificationsChanged(); }); }); + connect(this, &NeoChatConnection::invitedRoom, this, [this](Quotient::Room *room) { + auto r = dynamic_cast(room); + connect(r, &NeoChatRoom::showInviteNotification, this, &NeoChatConnection::showInviteNotification); + }); connect(this, &NeoChatConnection::leftRoom, this, [this](Room *room, Room *prev) { Q_UNUSED(room) if (prev && prev->isDirectChat()) { diff --git a/src/neochatconnection.h b/src/neochatconnection.h index 44724d2df..a217923cf 100644 --- a/src/neochatconnection.h +++ b/src/neochatconnection.h @@ -209,6 +209,11 @@ Q_SIGNALS: */ void errorOccured(const QString &error); + /** + * @brief Request a notification be shown for an invite to this room. + */ + void showInviteNotification(NeoChatRoom *room); + private: bool m_isOnline = true; void setIsOnline(bool isOnline); diff --git a/src/neochatroom.cpp b/src/neochatroom.cpp index 39e0a1058..d330b84b4 100644 --- a/src/neochatroom.cpp +++ b/src/neochatroom.cpp @@ -40,9 +40,7 @@ #include "events/joinrulesevent.h" #include "events/pollevent.h" #include "filetransferpseudojob.h" -#include "jobs/neochatgetcommonroomsjob.h" #include "neochatconfig.h" -#include "notificationsmanager.h" #include "roomlastmessageprovider.h" #include "spacehierarchycache.h" #include "texthandler.h" @@ -125,45 +123,8 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS updatePushNotificationState(QStringLiteral("m.push_rules")); Q_EMIT canEncryptRoomChanged(); - if (this->joinState() != JoinState::Invite) { - return; - } - auto roomMemberEvent = currentState().get(localMember().id()); - - auto showNotification = [this, roomMemberEvent] { - QImage avatar_image; - if (roomMemberEvent && !member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) { -#if Quotient_VERSION_MINOR > 8 - avatar_image = member(roomMemberEvent->senderId()).avatar(128, 128, {}); -#else - avatar_image = memberAvatar(roomMemberEvent->senderId()).get(this->connection(), 128, [] {}); -#endif - } else { - qWarning() << "using this room's avatar"; - avatar_image = avatar(128); - } - - NotificationsManager::instance().postInviteNotification(this, - displayName(), - member(roomMemberEvent->senderId()).htmlSafeDisplayName(), - avatar_image); - }; - - if (NeoChatConfig::rejectUnknownInvites()) { - auto job = this->connection()->callApi(roomMemberEvent->senderId()); - connect(job, &BaseJob::result, this, [this, job, showNotification] { - QJsonObject replyData = job->jsonData(); - if (replyData.contains(QStringLiteral("joined"))) { - const bool inAnyOfOurRooms = !replyData[QStringLiteral("joined")].toArray().isEmpty(); - if (inAnyOfOurRooms) { - showNotification(); - } else { - leaveRoom(); - } - } - }); - } else { - showNotification(); + if (this->joinState() == JoinState::Invite) { + Q_EMIT showInviteNotification(this); } }, Qt::SingleShotConnection); @@ -946,11 +907,6 @@ QCoro::Task NeoChatRoom::doDeleteMessagesByUser(const QString &user, QStri } } -void NeoChatRoom::clearInvitationNotification() -{ - NotificationsManager::instance().clearInvitationNotification(id()); -} - bool NeoChatRoom::hasParent() const { return currentState().eventsOfType("m.space.parent"_ls).size() > 0; diff --git a/src/neochatroom.h b/src/neochatroom.h index 58b8cfd88..17e79891b 100644 --- a/src/neochatroom.h +++ b/src/neochatroom.h @@ -418,8 +418,6 @@ public: bool readOnly() const; - Q_INVOKABLE void clearInvitationNotification(); - [[nodiscard]] QString joinRule() const; /** @@ -664,6 +662,14 @@ Q_SIGNALS: */ void showMessage(MessageType::Type messageType, const QString &message); + /** + * @brief Request a notification be shown for an invite to this room. + * + * @note This may later be blocked if there are any rules on where invites can + * come from, but this is not NeoChatRoom's responsibility. + */ + void showInviteNotification(NeoChatRoom *room); + public Q_SLOTS: /** * @brief Upload a file to the matrix server and post the file to the room. diff --git a/src/notificationsmanager.cpp b/src/notificationsmanager.cpp index c82e05cc5..ed30807ec 100644 --- a/src/notificationsmanager.cpp +++ b/src/notificationsmanager.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #ifdef HAVE_KIO @@ -22,6 +23,8 @@ #endif #include "controller.h" +#include "jobs/neochatgetcommonroomsjob.h" +#include "neochatconfig.h" #include "neochatconnection.h" #include "neochatroom.h" #include "roommanager.h" @@ -30,12 +33,6 @@ using namespace Quotient; -NotificationsManager &NotificationsManager::instance() -{ - static NotificationsManager _instance; - return _instance; -} - NotificationsManager::NotificationsManager(QObject *parent) : QObject(parent) { @@ -249,15 +246,57 @@ void NotificationsManager::postNotification(NeoChatRoom *room, notification->sendEvent(); } -void NotificationsManager::postInviteNotification(NeoChatRoom *rawRoom, const QString &title, const QString &sender, const QImage &icon) +void NotificationsManager::postInviteNotification(NeoChatRoom *rawRoom) { QPointer room(rawRoom); - QPixmap img; - img.convertFromImage(icon); + + const auto roomMemberEvent = room->currentState().get(room->localMember().id()); + if (roomMemberEvent == nullptr) { + return; + } + + if (NeoChatConfig::rejectUnknownInvites()) { + auto job = room->connection()->callApi(roomMemberEvent->senderId()); + connect(job, &BaseJob::result, this, [this, job, room] { + QJsonObject replyData = job->jsonData(); + if (replyData.contains(QStringLiteral("joined"))) { + const bool inAnyOfOurRooms = !replyData[QStringLiteral("joined")].toArray().isEmpty(); + if (inAnyOfOurRooms) { + doPostInviteNotification(room); + } else { + room->leaveRoom(); + } + } + }); + } else { + doPostInviteNotification(room); + } +} + +void NotificationsManager::doPostInviteNotification(QPointer room) +{ + const auto roomMemberEvent = room->currentState().get(room->localMember().id()); + if (roomMemberEvent == nullptr) { + return; + } + const auto sender = room->member(roomMemberEvent->senderId()); + + QImage avatar_image; + if (roomMemberEvent && !room->member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) { +#if Quotient_VERSION_MINOR > 8 + avatar_image = room->member(roomMemberEvent->senderId()).avatar(128, 128, {}); +#else + avatar_image = room->memberAvatar(roomMemberEvent->senderId()).get(room->connection(), 128, [] {}); +#endif + } else { + qWarning() << "using this room's avatar"; + avatar_image = room->avatar(128); + } + KNotification *notification = new KNotification(QStringLiteral("invite")); - notification->setText(i18n("%1 invited you to a room", sender)); - notification->setTitle(title); - notification->setPixmap(createNotificationImage(icon, nullptr)); + notification->setText(i18n("%1 invited you to a room", sender.htmlSafeDisplayName())); + notification->setTitle(room->displayName()); + notification->setPixmap(createNotificationImage(avatar_image, nullptr)); auto defaultAction = notification->addDefaultAction(i18n("Open this invitation in NeoChat")); connect(defaultAction, &KNotificationAction::activated, this, [notification, room]() { if (!room) { diff --git a/src/notificationsmanager.h b/src/notificationsmanager.h index 49c678695..e49fe6b72 100644 --- a/src/notificationsmanager.h +++ b/src/notificationsmanager.h @@ -34,31 +34,14 @@ class NotificationsManager : public QObject { Q_OBJECT QML_ELEMENT - QML_SINGLETON public: - static NotificationsManager &instance(); - static NotificationsManager *create(QQmlEngine *engine, QJSEngine *) - { - engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership); - return &instance(); - } - - /** - * @brief Display a native notification for an message. - */ - Q_INVOKABLE void postNotification(NeoChatRoom *room, - const QString &sender, - const QString &text, - const QImage &icon, - const QString &replyEventId, - bool canReply, - qint64 timestamp); + explicit NotificationsManager(QObject *parent = nullptr); /** * @brief Display a native notification for an invite. */ - void postInviteNotification(NeoChatRoom *room, const QString &title, const QString &sender, const QImage &icon); + void postInviteNotification(NeoChatRoom *room); /** * @brief Clear an existing invite notification for the given room. @@ -78,21 +61,26 @@ public: void handleNotifications(QPointer connection); private: - explicit NotificationsManager(QObject *parent = nullptr); - QHash m_initialTimestamp; QHash m_oldNotifications; QStringList m_connActiveJob; + QPixmap createNotificationImage(const QImage &icon, NeoChatRoom *room); bool shouldPostNotification(QPointer connection, const QJsonValue ¬ification); + void postNotification(NeoChatRoom *room, + const QString &sender, + const QString &text, + const QImage &icon, + const QString &replyEventId, + bool canReply, + qint64 timestamp); + + void doPostInviteNotification(QPointer room); QHash> m_notifications; QHash> m_invitations; private Q_SLOTS: void processNotificationJob(QPointer connection, Quotient::GetNotificationsJob *job, bool initialization); - -private: - QPixmap createNotificationImage(const QImage &icon, NeoChatRoom *room); }; diff --git a/src/qml/RoomPage.qml b/src/qml/RoomPage.qml index 92adcd08a..c291f2805 100644 --- a/src/qml/RoomPage.qml +++ b/src/qml/RoomPage.qml @@ -186,7 +186,7 @@ Kirigami.Page { target: RoomManager function onCurrentRoomChanged() { if (root.currentRoom && root.currentRoom.isInvite) { - root.currentRoom.clearInvitationNotification(); + Controller.clearInvitationNotification(root.currentRoom.id); } }