diff --git a/src/main.cpp b/src/main.cpp index bb26f8530..a08f44cae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -232,7 +232,7 @@ int main(int argc, char *argv[]) auto args = arguments; args.removeFirst(); for (const auto &arg : args) { - RoomManager::instance().openResource(arg); + RoomManager::instance().resolveResource(arg); } }); #endif diff --git a/src/models/actionsmodel.cpp b/src/models/actionsmodel.cpp index cecf18739..11da2f422 100644 --- a/src/models/actionsmodel.cpp +++ b/src/models/actionsmodel.cpp @@ -235,7 +235,7 @@ QList actions{ return QString(); } Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Joining room .", "Joining room %1.", text)); - RoomManager::instance().openResource(text, "join"_ls); + RoomManager::instance().resolveResource(text, "join"_ls); return QString(); }, false, @@ -290,7 +290,7 @@ QList actions{ return QString(); } Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Joining room .", "Joining room %1.", text)); - RoomManager::instance().openResource(text, "join"_ls); + RoomManager::instance().resolveResource(text, "join"_ls); return QString(); }, false, diff --git a/src/models/notificationsmodel.cpp b/src/models/notificationsmodel.cpp index 6ee4603d2..7f7a7d018 100644 --- a/src/models/notificationsmodel.cpp +++ b/src/models/notificationsmodel.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "eventhandler.h" #include "neochatroom.h" @@ -49,6 +50,9 @@ QVariant NotificationsModel::data(const QModelIndex &index, int role) const if (role == RoomDisplayNameRole) { return m_notifications[row].roomDisplayName; } + if (role == UriRole) { + return Uri(m_notifications[row].roomId.toLatin1(), m_notifications[row].eventId.toLatin1()).toUrl(); + } return {}; } @@ -62,6 +66,7 @@ QHash NotificationsModel::roleNames() const {RoomRole, "room"}, {EventIdRole, "eventId"}, {RoomDisplayNameRole, "roomDisplayName"}, + {UriRole, "uri"}, }; } diff --git a/src/models/notificationsmodel.h b/src/models/notificationsmodel.h index f2215c428..dbda0b830 100644 --- a/src/models/notificationsmodel.h +++ b/src/models/notificationsmodel.h @@ -28,6 +28,7 @@ public: RoomRole, EventIdRole, RoomDisplayNameRole, + UriRole, }; Q_ENUM(Roles); diff --git a/src/qml/Bubble.qml b/src/qml/Bubble.qml index 27e0c088a..c5aa183ce 100644 --- a/src/qml/Bubble.qml +++ b/src/qml/Bubble.qml @@ -149,7 +149,7 @@ QQC2.Control { elide: Text.ElideRight } Accessible.name: contentItem.text - onClicked: RoomManager.visitUser(root.author.object, "mention") + onClicked: RoomManager.resolveResource(root.author.id, "mention") } QQC2.Label { text: root.timeString diff --git a/src/qml/DirectChatDrawerHeader.qml b/src/qml/DirectChatDrawerHeader.qml index 5424cda52..96d053c1b 100644 --- a/src/qml/DirectChatDrawerHeader.qml +++ b/src/qml/DirectChatDrawerHeader.qml @@ -33,7 +33,7 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter onClicked: { - RoomManager.visitUser(root.room.getUser(root.room.directChatRemoteUser.id).object, "mention") + RoomManager.resolveResource(root.room.directChatRemoteUser.id, "mention") } contentItem: KirigamiComponents.Avatar { diff --git a/src/qml/ExploreComponent.qml b/src/qml/ExploreComponent.qml index dbbe0ac59..03038ce92 100644 --- a/src/qml/ExploreComponent.qml +++ b/src/qml/ExploreComponent.qml @@ -26,7 +26,7 @@ RowLayout { if (isJoined) { RoomManager.enterRoom(root.connection.room(roomId)) } else { - RoomManager.openResource(roomId.length > 0 ? roomId : alias, "join") + RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, "join") } }) } diff --git a/src/qml/ExploreComponentMobile.qml b/src/qml/ExploreComponentMobile.qml index a2382913b..420a1a99b 100644 --- a/src/qml/ExploreComponentMobile.qml +++ b/src/qml/ExploreComponentMobile.qml @@ -57,7 +57,7 @@ ColumnLayout { if (isJoined) { RoomManager.enterRoom(root.connection.room(roomId)); } else { - RoomManager.openResource(roomId.length > 0 ? roomId : alias, "join"); + RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, "join"); } }) exploreTabBar.currentIndex = -1; diff --git a/src/qml/GlobalMenu.qml b/src/qml/GlobalMenu.qml index d6bbddcf0..2af597529 100644 --- a/src/qml/GlobalMenu.qml +++ b/src/qml/GlobalMenu.qml @@ -66,7 +66,7 @@ Labs.MenuBar { if (isJoined) { RoomManager.enterRoom(root.connection.room(roomId)) } else { - RoomManager.openResource(roomId, "join") + RoomManager.resolveResource(roomId, "join") } }) } diff --git a/src/qml/LinkPreviewDelegate.qml b/src/qml/LinkPreviewDelegate.qml index f52695fcb..29a8bd114 100644 --- a/src/qml/LinkPreviewDelegate.qml +++ b/src/qml/LinkPreviewDelegate.qml @@ -82,7 +82,7 @@ Loader { } " + (maximizeButton.checked ? root.linkPreviewer.title : titleTextMetrics.elidedText).replace("–", "—") + "" - onLinkActivated: RoomManager.openResource(link, "join") + onLinkActivated: RoomManager.resolveResource(link, "join") TextMetrics { id: titleTextMetrics diff --git a/src/qml/MessageDelegate.qml b/src/qml/MessageDelegate.qml index d5bd07b5d..45e26a40b 100644 --- a/src/qml/MessageDelegate.qml +++ b/src/qml/MessageDelegate.qml @@ -355,7 +355,7 @@ TimelineDelegate { source: root.author.avatarSource color: root.author.color - onClicked: RoomManager.visitUser(root.author.object, "mention") + onClicked: RoomManager.resolveResource(root.author.id, "mention") } Bubble { id: bubble diff --git a/src/qml/MessageDelegateContextMenu.qml b/src/qml/MessageDelegateContextMenu.qml index 80e102406..038cf7ecd 100644 --- a/src/qml/MessageDelegateContextMenu.qml +++ b/src/qml/MessageDelegateContextMenu.qml @@ -209,7 +209,7 @@ Loader { model: WebShortcutModel { id: webshortcutmodel selectedText: root.selectedText.length > 0 ? root.selectedText : root.plainText - onOpenUrl: RoomManager.visitNonMatrix(url) + onOpenUrl: RoomManager.resolveResource(url) } delegate: QQC2.MenuItem { text: model.display @@ -315,7 +315,7 @@ Loader { Layout.fillWidth: true wrapMode: Text.WordWrap - onLinkActivated: RoomManager.openResource(link, "join"); + onLinkActivated: RoomManager.resolveResource(link, "join"); } } } diff --git a/src/qml/NotificationsView.qml b/src/qml/NotificationsView.qml index 011b4ecbd..d0874287a 100644 --- a/src/qml/NotificationsView.qml +++ b/src/qml/NotificationsView.qml @@ -43,7 +43,7 @@ Kirigami.ScrollablePage { delegate: QQC2.ItemDelegate { width: parent?.width ?? 0 - onClicked: RoomManager.visitRoom(model.room, model.eventId) + onClicked: RoomManager.resolveResource(model.uri) contentItem: RowLayout { spacing: Kirigami.Units.largeSpacing diff --git a/src/qml/RichLabel.qml b/src/qml/RichLabel.qml index ad1abe6bd..59c7d93ef 100644 --- a/src/qml/RichLabel.qml +++ b/src/qml/RichLabel.qml @@ -112,7 +112,7 @@ a{ onLinkActivated: link => { spoilerRevealed = true - RoomManager.openResource(link, "join") + RoomManager.resolveResource(link, "join") } onHoveredLinkChanged: if (hoveredLink.length > 0 && hoveredLink !== "1") { applicationWindow().hoverLinkIndicator.text = hoveredLink; diff --git a/src/qml/RoomInformation.qml b/src/qml/RoomInformation.qml index f9195d778..2cfbeffe1 100644 --- a/src/qml/RoomInformation.qml +++ b/src/qml/RoomInformation.qml @@ -206,7 +206,7 @@ QQC2.ScrollView { onClicked: { userDelegate.highlighted = true; - RoomManager.visitUser(room.getUser(userDelegate.userId).object, "mention") + RoomManager.resolveResource(userDelegate.userId, "mention") } contentItem: RowLayout { diff --git a/src/qml/RoomListPage.qml b/src/qml/RoomListPage.qml index ff5691e4d..87094dffc 100644 --- a/src/qml/RoomListPage.qml +++ b/src/qml/RoomListPage.qml @@ -191,7 +191,7 @@ Kirigami.Page { if (isJoined) { RoomManager.enterRoom(root.connection.room(roomId)) } else { - RoomManager.openResource(roomId, "join") + RoomManager.resolveResource(roomId, "join") } }) } diff --git a/src/qml/SpaceHierarchyDelegate.qml b/src/qml/SpaceHierarchyDelegate.qml index 2bd5979be..afa3e9abb 100644 --- a/src/qml/SpaceHierarchyDelegate.qml +++ b/src/qml/SpaceHierarchyDelegate.qml @@ -149,7 +149,7 @@ Item { if (root.isJoined) { root.enterRoom() } else { - RoomManager.openResource(root.roomId, "join") + RoomManager.resolveResource(root.roomId, "join") } } } diff --git a/src/qml/StateComponent.qml b/src/qml/StateComponent.qml index 35d885674..acd62e17b 100644 --- a/src/qml/StateComponent.qml +++ b/src/qml/StateComponent.qml @@ -62,7 +62,7 @@ RowLayout { MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: RoomManager.openResource("https://matrix.to/#/" + root.author.id) + onClicked: RoomManager.resolveResource("https://matrix.to/#/" + root.author.id) } } @@ -73,6 +73,6 @@ RowLayout { text: `${root.authorDisplayName} ${root.text}` wrapMode: Text.WordWrap textFormat: Text.RichText - onLinkActivated: link => RoomManager.openResource(link) + onLinkActivated: link => RoomManager.resolveResource(link) } } diff --git a/src/qml/StateDelegate.qml b/src/qml/StateDelegate.qml index b14d58528..b1108a87f 100644 --- a/src/qml/StateDelegate.qml +++ b/src/qml/StateDelegate.qml @@ -156,7 +156,7 @@ TimelineDelegate { elide: Qt.ElideRight textFormat: Text.RichText wrapMode: Text.WordWrap - onLinkActivated: RoomManager.openResource(link) + onLinkActivated: RoomManager.resolveResource(link) } Item { Layout.fillWidth: true diff --git a/src/roommanager.cpp b/src/roommanager.cpp index 6d74caf78..ff6b66723 100644 --- a/src/roommanager.cpp +++ b/src/roommanager.cpp @@ -72,7 +72,12 @@ MediaMessageFilterModel *RoomManager::mediaMessageFilterModel() const return m_mediaMessageFilterModel; } -void RoomManager::openResource(const QString &idOrUri, const QString &action) +UriResolveResult RoomManager::resolveResource(const Uri &uri) +{ + return UriResolverBase::visitResource(m_connection, uri); +} + +void RoomManager::resolveResource(const QString &idOrUri, const QString &action) { Uri uri{idOrUri}; if (!uri.isValid()) { @@ -155,7 +160,7 @@ void RoomManager::loadInitialRoom() Q_ASSERT(m_connection); if (!m_arg.isEmpty()) { - openResource(m_arg); + resolveResource(m_arg); } if (m_currentRoom) { diff --git a/src/roommanager.h b/src/roommanager.h index ff53b4de1..a95ff47a3 100644 --- a/src/roommanager.h +++ b/src/roommanager.h @@ -32,6 +32,11 @@ using namespace Quotient; * @class RoomManager * * A singleton class to help manage which room is open in NeoChat. + * + * This class also inherits UriResolverBase and overrides the relevant functions to + * resolve various URIs. The base functions visitUser(), visitRoom(), etc are held + * private intentionally and instead resolveResource() should be called with either + * an appropriate URI or a Matrix ID and action. */ class RoomManager : public QObject, public UriResolverBase { @@ -106,6 +111,26 @@ public: MessageFilterModel *messageFilterModel() const; MediaMessageFilterModel *mediaMessageFilterModel() const; + /** + * @brief Resolve the given URI resource. + * + * @note It's actually Quotient::UriResolverBase::visitResource() but with Q_INVOKABLE + * and the connection grabbed from RoomManager. + * + * @sa Quotient::UriResolverBase::visitResource() + */ + Q_INVOKABLE UriResolveResult resolveResource(const Uri &uri); + + /** + * @brief Resolve the given resource. + * + * @note It's actually Quotient::UriResolverBase::visitResource() but with Q_INVOKABLE + * and the connection grabbed from RoomManager. + * + * @sa Quotient::UriResolverBase::visitResource() + */ + Q_INVOKABLE void resolveResource(const QString &idOrUri, const QString &action = {}); + bool hasOpenRoom() const; /** @@ -139,56 +164,6 @@ public: */ Q_INVOKABLE void enterSpaceHome(NeoChatRoom *spaceRoom); - // Overrided methods from UriResolverBase - /** - * @brief Resolve a user URI. - * - * This overloads Quotient::UriResolverBase::visitUser(). - * - * Called by Quotient::UriResolverBase::visitResource() when the passed URI - * identifies a Matrix user. - * - * @sa Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource() - */ - Q_INVOKABLE UriResolveResult visitUser(User *user, const QString &action) override; - - /** - * @brief Visit a room. - * - * This overloads Quotient::UriResolverBase::visitRoom(). - * - * Called by Quotient::UriResolverBase::visitResource() when the passed URI - * identifies a room or an event in a room. - * - * @sa Quotient::UriResolverBase::visitRoom(), Quotient::UriResolverBase::visitResource() - */ - Q_INVOKABLE void visitRoom(Quotient::Room *room, const QString &eventId) override; - - /** - * @brief Join a room. - * - * This overloads Quotient::UriResolverBase::joinRoom(). - * - * Called by Quotient::UriResolverBase::visitResource() when the passed URI has - * `action() == "join"` and identifies a room that the user defined by the - * Connection argument is not a member of. - * - * @sa Quotient::UriResolverBase::joinRoom(), Quotient::UriResolverBase::visitResource() - */ - void joinRoom(Quotient::Connection *account, const QString &roomAliasOrId, const QStringList &viaServers) override; - - /** - * @brief Visit a non-matrix resource. - * - * This overloads Quotient::UriResolverBase::visitNonMatrix(). - * - * Called by Quotient::UriResolverBase::visitResource() when the passed URI - * has `type() == NonMatrix` - * - * @sa Quotient::UriResolverBase::visitNonMatrix(), Quotient::UriResolverBase::visitResource() - */ - Q_INVOKABLE bool visitNonMatrix(const QUrl &url) override; - /** * @brief Knock a room. * @@ -197,16 +172,6 @@ public: */ void knockRoom(Quotient::Connection *account, const QString &roomAliasOrId, const QString &reason, const QStringList &viaServers); - /** - * @brief Open the given resource. - * - * Convenience function to call Quotient::UriResolverBase::visitResource() from - * QML if valid. - * - * @sa Quotient::UriResolverBase::visitResource() - */ - Q_INVOKABLE void openResource(const QString &idOrUri, const QString &action = {}); - /** * @brief Show a media item maximized. * @@ -388,4 +353,69 @@ private: MessageFilterModel *m_messageFilterModel; MediaMessageFilterModel *m_mediaMessageFilterModel; NeoChatConnection *m_connection; + + /** + * @brief Resolve a user URI. + * + * This overloads Quotient::UriResolverBase::visitUser(). + * + * Called by Quotient::UriResolverBase::visitResource() when the passed URI + * identifies a Matrix user. + * + * @note This is private as resolveResource() should always be called, which + * will in turn call Quotient::UriResolverBase::visitResource() and this + * function if appropriate for the URI. + * + * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource() + */ + UriResolveResult visitUser(User *user, const QString &action) override; + + /** + * @brief Visit a room. + * + * This overloads Quotient::UriResolverBase::visitRoom(). + * + * Called by Quotient::UriResolverBase::visitResource() when the passed URI + * identifies a room or an event in a room. + * + * @note This is private as resolveResource() should always be called, which + * will in turn call Quotient::UriResolverBase::visitResource() and this + * function if appropriate for the URI. + * + * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource() + */ + Q_INVOKABLE void visitRoom(Quotient::Room *room, const QString &eventId) override; + + /** + * @brief Join a room. + * + * This overloads Quotient::UriResolverBase::joinRoom(). + * + * Called by Quotient::UriResolverBase::visitResource() when the passed URI has + * `action() == "join"` and identifies a room that the user defined by the + * Connection argument is not a member of. + * + * @note This is private as resolveResource() should always be called, which + * will in turn call Quotient::UriResolverBase::visitResource() and this + * function if appropriate for the URI. + * + * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource() + */ + void joinRoom(Quotient::Connection *account, const QString &roomAliasOrId, const QStringList &viaServers) override; + + /** + * @brief Visit a non-matrix resource. + * + * This overloads Quotient::UriResolverBase::visitNonMatrix(). + * + * Called by Quotient::UriResolverBase::visitResource() when the passed URI + * has `type() == NonMatrix` + * + * @note This is private as resolveResource() should always be called, which + * will in turn call Quotient::UriResolverBase::visitResource() and this + * function if appropriate for the URI. + * + * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource() + */ + Q_INVOKABLE bool visitNonMatrix(const QUrl &url) override; };