File indexing completed on 2024-10-06 07:36:10
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 };