File indexing completed on 2024-05-05 09:14:02

0001 // SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0003 
0004 #pragma once
0005 
0006 #include <KConfigGroup>
0007 #include <KSharedConfig>
0008 #include <QObject>
0009 #include <QQmlEngine>
0010 #include <Quotient/room.h>
0011 #include <Quotient/uriresolver.h>
0012 
0013 #include "chatdocumenthandler.h"
0014 #include "enums/delegatetype.h"
0015 #include "models/mediamessagefiltermodel.h"
0016 #include "models/messagefiltermodel.h"
0017 #include "models/timelinemodel.h"
0018 
0019 class NeoChatRoom;
0020 class NeoChatConnection;
0021 
0022 namespace Quotient
0023 {
0024 class Room;
0025 class User;
0026 }
0027 
0028 using namespace Quotient;
0029 
0030 /**
0031  * @class RoomManager
0032  *
0033  * A singleton class to help manage which room is open in NeoChat.
0034  *
0035  * This class also inherits UriResolverBase and overrides the relevant functions to
0036  * resolve various URIs. The base functions visitUser(), visitRoom(), etc are held
0037  * private intentionally and instead resolveResource() should be called with either
0038  * an appropriate URI or a Matrix ID and action.
0039  */
0040 class RoomManager : public QObject, public UriResolverBase
0041 {
0042     Q_OBJECT
0043     QML_ELEMENT
0044     QML_SINGLETON
0045 
0046     Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
0047 
0048     /**
0049      * @brief The current open room in NeoChat, if any.
0050      *
0051      * @sa hasOpenRoom
0052      */
0053     Q_PROPERTY(NeoChatRoom *currentRoom READ currentRoom NOTIFY currentRoomChanged)
0054 
0055     /**
0056      * @brief The TimelineModel that should be used for room message visualisation.
0057      *
0058      * The room object the model uses to get the data will be updated by this class
0059      * so there is no need to do this manually or replace the model when a room
0060      * changes.
0061      *
0062      * @note Available here so that the room page and drawer both have access to the
0063      *       same model.
0064      */
0065     Q_PROPERTY(TimelineModel *timelineModel READ timelineModel CONSTANT)
0066 
0067     /**
0068      * @brief The MessageFilterModel that should be used for room message visualisation.
0069      *
0070      * @note Available here so that the room page and drawer both have access to the
0071      *       same model.
0072      */
0073     Q_PROPERTY(MessageFilterModel *messageFilterModel READ messageFilterModel CONSTANT)
0074 
0075     /**
0076      * @brief The MediaMessageFilterModel that should be used for room media message visualisation.
0077      *
0078      * @note Available here so that the room page and drawer both have access to the
0079      *       same model.
0080      */
0081     Q_PROPERTY(MediaMessageFilterModel *mediaMessageFilterModel READ mediaMessageFilterModel CONSTANT)
0082 
0083     /**
0084      * @brief Whether a room is currently open in NeoChat.
0085      *
0086      * @sa room
0087      */
0088     Q_PROPERTY(bool hasOpenRoom READ hasOpenRoom NOTIFY currentRoomChanged)
0089 
0090     /**
0091      * @brief The ChatDocumentHandler for the open room.
0092      *
0093      * @sa ChatDocumentHandler
0094      */
0095     Q_PROPERTY(ChatDocumentHandler *chatDocumentHandler READ chatDocumentHandler WRITE setChatDocumentHandler NOTIFY chatDocumentHandlerChanged)
0096 
0097 public:
0098     virtual ~RoomManager();
0099     static RoomManager &instance();
0100     static RoomManager *create(QQmlEngine *engine, QJSEngine *)
0101     {
0102         engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
0103         return &instance();
0104     }
0105 
0106     NeoChatRoom *currentRoom() const;
0107 
0108     TimelineModel *timelineModel() const;
0109     MessageFilterModel *messageFilterModel() const;
0110     MediaMessageFilterModel *mediaMessageFilterModel() const;
0111 
0112     /**
0113      * @brief Resolve the given URI resource.
0114      *
0115      * @note It's actually Quotient::UriResolverBase::visitResource() but with Q_INVOKABLE
0116      *       and the connection grabbed from RoomManager.
0117      *
0118      * @sa Quotient::UriResolverBase::visitResource()
0119      */
0120     Q_INVOKABLE UriResolveResult resolveResource(const Uri &uri);
0121 
0122     /**
0123      * @brief Resolve the given resource.
0124      *
0125      * @note It's actually Quotient::UriResolverBase::visitResource() but with Q_INVOKABLE
0126      *       and the connection grabbed from RoomManager.
0127      *
0128      * @sa Quotient::UriResolverBase::visitResource()
0129      */
0130     Q_INVOKABLE void resolveResource(const QString &idOrUri, const QString &action = {});
0131 
0132     bool hasOpenRoom() const;
0133 
0134     /**
0135      * @brief Load the last opened room or the welcome page.
0136      */
0137     Q_INVOKABLE void loadInitialRoom();
0138 
0139     /**
0140      * @brief Enter the given room.
0141      *
0142      * This method will tell NeoChat to open the message list with the given room.
0143      */
0144     Q_INVOKABLE void enterRoom(NeoChatRoom *room);
0145 
0146     /**
0147      * @brief Open a new window with the given room.
0148      *
0149      * The open window will have its own message list for the given room.
0150      */
0151     Q_INVOKABLE void openWindow(NeoChatRoom *room);
0152 
0153     /**
0154      * @brief Leave the room and close it if it is open.
0155      */
0156     Q_INVOKABLE void leaveRoom(NeoChatRoom *room);
0157 
0158     /**
0159      * @brief Enter the home page of the given space.
0160      *
0161      * This method will tell NeoChat to open the home page for the given space.
0162      */
0163     Q_INVOKABLE void enterSpaceHome(NeoChatRoom *spaceRoom);
0164 
0165     /**
0166      * @brief Knock a room.
0167      *
0168      * See https://spec.matrix.org/latest/client-server-api/#knocking-on-rooms for
0169      * knocking on rooms.
0170      */
0171     void knockRoom(Quotient::Connection *account, const QString &roomAliasOrId, const QString &reason, const QStringList &viaServers);
0172 
0173     /**
0174      * @brief Show a media item maximized.
0175      *
0176      * @param index the index to open the maximize delegate model at. This is the
0177      *        index in the MediaMessageFilterModel owned by this RoomManager. A value
0178      *        of -1 opens a the default item.
0179      */
0180     Q_INVOKABLE void maximizeMedia(int index);
0181 
0182     /**
0183      * @brief Request that any full screen overlay currently open closes.
0184      */
0185     Q_INVOKABLE void requestFullScreenClose();
0186 
0187     /**
0188      * @brief Show the JSON source for the given event Matrix ID
0189      */
0190     Q_INVOKABLE void viewEventSource(const QString &eventId);
0191 
0192     /**
0193      * @brief Show a conterxt menu for the given event.
0194      */
0195     Q_INVOKABLE void viewEventMenu(const QString &eventId,
0196                                    const QVariantMap &author,
0197                                    DelegateType::Type delegateType,
0198                                    const QString &plainText,
0199                                    const QString &htmlText = {},
0200                                    const QString &selectedText = {},
0201                                    const QString &mimeType = {},
0202                                    const FileTransferInfo &progressInfo = {});
0203 
0204     /**
0205      * @brief Call this when the current used connection is dropped.
0206      */
0207     Q_INVOKABLE void reset();
0208 
0209     ChatDocumentHandler *chatDocumentHandler() const;
0210     void setChatDocumentHandler(ChatDocumentHandler *handler);
0211 
0212     /**
0213      * @brief Set a URL to be loaded as the initial room.
0214      */
0215     void setUrlArgument(const QString &arg);
0216 
0217     NeoChatConnection *connection() const;
0218     void setConnection(NeoChatConnection *connection);
0219 
0220 Q_SIGNALS:
0221     void currentRoomChanged();
0222 
0223     /**
0224      * @brief Push a new room page.
0225      *
0226      * Signal triggered when the main window pageStack should push a new page with
0227      * the message list for the given room.
0228      *
0229      * @param room the room to be shown on the new page.
0230      * @param event the event to got to if available.
0231      */
0232     void pushRoom(NeoChatRoom *room, const QString &event);
0233 
0234     /**
0235      * @brief Replace the existing room.
0236      *
0237      * Signal triggered when the room displayed by the message list should be changed.
0238      *
0239      * @param room the room to be shown on the new page.
0240      * @param event the event to got to if available.
0241      */
0242     void replaceRoom(NeoChatRoom *room, const QString &event);
0243 
0244     /**
0245      * @brief Push a new space home page.
0246      *
0247      * Signal triggered when the main window pageStack should push a new page with
0248      * the space home for the given space room.
0249      *
0250      * @param spaceRoom the space room to be shown on the new page.
0251      */
0252     void pushSpaceHome(NeoChatRoom *spaceRoom);
0253 
0254     /**
0255      * @brief Replace the existing space home.
0256      *
0257      * Signal triggered when the currently displayed room page should be changed
0258      * to the space home for the given space room.
0259      *
0260      * @param spaceRoom the space room to be shown on the new page.
0261      */
0262     void replaceSpaceHome(NeoChatRoom *spaceRoom);
0263 
0264     /**
0265      * @brief Go to the specified event in the current room.
0266      */
0267     void goToEvent(const QString &event);
0268 
0269     /**
0270      * @brief Open room in a new window.
0271      *
0272      * Signal triggered when a room needs to be opened in a new window.
0273      */
0274     void openRoomInNewWindow(NeoChatRoom *room);
0275 
0276     /**
0277      * @brief Show details for the given user.
0278      *
0279      * Ask current room to open the user's details for the give user.
0280      * This assumes the user is loaded.
0281      */
0282     void showUserDetail(const Quotient::User *user);
0283 
0284     /**
0285      * @brief Request a media item is shown maximized.
0286      *
0287      * @param index the index to open the maximize delegate model at. This is the
0288      *        index in the MediaMessageFilterModel owned by this RoomManager. A value
0289      *        of -1 opens a the default item.
0290      */
0291     void showMaximizedMedia(int index);
0292 
0293     /**
0294      * @brief Request that any full screen overlay closes.
0295      */
0296     void closeFullScreen();
0297 
0298     /**
0299      * @brief Request the JSON source for the given event ID is shown.
0300      */
0301     void showEventSource(const QString &eventId);
0302 
0303     /**
0304      * @brief Request to show a menu for the given event.
0305      */
0306     void showMessageMenu(const QString &eventId,
0307                          const QVariantMap &author,
0308                          DelegateType::Type delegateType,
0309                          const QString &plainText,
0310                          const QString &htmlText,
0311                          const QString &selectedText);
0312 
0313     /**
0314      * @brief Request to show a menu for the given media event.
0315      */
0316     void showFileMenu(const QString &eventId,
0317                       const QVariantMap &author,
0318                       DelegateType::Type delegateType,
0319                       const QString &plainText,
0320                       const QString &mimeType,
0321                       const FileTransferInfo &progressInfo);
0322 
0323     /**
0324      * @brief Show the direct chat confirmation dialog.
0325      *
0326      * Ask current room to show confirmation dialog to open direct chat.
0327      * This assumes the user is loaded.
0328      */
0329     void askDirectChatConfirmation(const Quotient::User *user);
0330 
0331     /**
0332      * @brief Displays warning to the user.
0333      */
0334     void warning(const QString &title, const QString &message);
0335 
0336     void chatDocumentHandlerChanged();
0337 
0338     void connectionChanged();
0339 
0340 private:
0341     void openRoomForActiveConnection();
0342 
0343     NeoChatRoom *m_currentRoom;
0344     NeoChatRoom *m_lastCurrentRoom;
0345     QString m_arg;
0346     KSharedConfig::Ptr m_config;
0347     KConfigGroup m_lastRoomConfig;
0348     QPointer<ChatDocumentHandler> m_chatDocumentHandler;
0349 
0350     TimelineModel *m_timelineModel;
0351     MessageFilterModel *m_messageFilterModel;
0352     MediaMessageFilterModel *m_mediaMessageFilterModel;
0353     NeoChatConnection *m_connection;
0354 
0355     /**
0356      * @brief Resolve a user URI.
0357      *
0358      * This overloads Quotient::UriResolverBase::visitUser().
0359      *
0360      * Called by Quotient::UriResolverBase::visitResource() when the passed URI
0361      * identifies a Matrix user.
0362      *
0363      * @note This is private as resolveResource() should always be called, which
0364      *       will in turn call Quotient::UriResolverBase::visitResource() and this
0365      *       function if appropriate for the URI.
0366      *
0367      * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource()
0368      */
0369     UriResolveResult visitUser(User *user, const QString &action) override;
0370 
0371     /**
0372      * @brief Visit a room.
0373      *
0374      * This overloads Quotient::UriResolverBase::visitRoom().
0375      *
0376      * Called by Quotient::UriResolverBase::visitResource() when the passed URI
0377      * identifies a room or an event in a room.
0378      *
0379      * @note This is private as resolveResource() should always be called, which
0380      *       will in turn call Quotient::UriResolverBase::visitResource() and this
0381      *       function if appropriate for the URI.
0382      *
0383      * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource()
0384      */
0385     Q_INVOKABLE void visitRoom(Quotient::Room *room, const QString &eventId) override;
0386 
0387     /**
0388      * @brief Join a room.
0389      *
0390      * This overloads Quotient::UriResolverBase::joinRoom().
0391      *
0392      * Called by Quotient::UriResolverBase::visitResource() when the passed URI has
0393      * `action() == "join"` and identifies a room that the user defined by the
0394      * Connection argument is not a member of.
0395      *
0396      * @note This is private as resolveResource() should always be called, which
0397      *       will in turn call Quotient::UriResolverBase::visitResource() and this
0398      *       function if appropriate for the URI.
0399      *
0400      * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource()
0401      */
0402     void joinRoom(Quotient::Connection *account, const QString &roomAliasOrId, const QStringList &viaServers) override;
0403 
0404     /**
0405      * @brief Visit a non-matrix resource.
0406      *
0407      * This overloads Quotient::UriResolverBase::visitNonMatrix().
0408      *
0409      * Called by Quotient::UriResolverBase::visitResource() when the passed URI
0410      * has `type() == NonMatrix`
0411      *
0412      * @note This is private as resolveResource() should always be called, which
0413      *       will in turn call Quotient::UriResolverBase::visitResource() and this
0414      *       function if appropriate for the URI.
0415      *
0416      * @sa resolveResource(), Quotient::UriResolverBase::visitUser(), Quotient::UriResolverBase::visitResource()
0417      */
0418     Q_INVOKABLE bool visitNonMatrix(const QUrl &url) override;
0419 
0420 private:
0421     explicit RoomManager(QObject *parent = nullptr);
0422 };