File indexing completed on 2024-11-03 07:45:10
0001 // SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com> 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 <QObject> 0007 0008 #include <KFormat> 0009 0010 #include <Quotient/eventitem.h> 0011 #include <Quotient/events/roomevent.h> 0012 #include <Quotient/events/roommessageevent.h> 0013 0014 #include "enums/delegatetype.h" 0015 0016 class LinkPreviewer; 0017 class NeoChatRoom; 0018 class ReactionModel; 0019 0020 /** 0021 * @class EventHandler 0022 * 0023 * This class is designed to handle a Quotient::RoomEvent allowing data to be extracted 0024 * in a form ready for the NeoChat UI. 0025 * 0026 * To use this properly both the room and the event should be set (and the event should 0027 * be from the given room). 0028 * 0029 * @note EventHandler will always try to return something even when not properly 0030 * initialised, this is usually the best empty value it can create with available 0031 * information. This is to minimize warnings from QML especially during startup 0032 * and room changes. 0033 */ 0034 class EventHandler : public QObject 0035 { 0036 Q_OBJECT 0037 0038 public: 0039 /** 0040 * @brief Return the current room the EventHandler is using. 0041 */ 0042 const NeoChatRoom *getRoom() const; 0043 0044 /** 0045 * @brief Set the current room the EventHandler to using. 0046 */ 0047 void setRoom(const NeoChatRoom *room); 0048 0049 /** 0050 * @brief Return the current event the EventHandler is using. 0051 */ 0052 const Quotient::Event *getEvent() const; 0053 0054 /** 0055 * @brief Set the current event the EventHandler to using. 0056 */ 0057 void setEvent(const Quotient::RoomEvent *event); 0058 0059 /** 0060 * @brief Return the Matrix ID of the event. 0061 */ 0062 QString getId() const; 0063 0064 /** 0065 * @brief Return the DelegateType of the event. 0066 * 0067 * @note While similar this is not the matrix event or message type. This is 0068 * to tell a QML ListView what delegate to show for each event. So while 0069 * similar to the spec it is not the same. 0070 */ 0071 DelegateType::Type getDelegateType() const; 0072 0073 /** 0074 * @brief Get the author of the event in context of the room. 0075 * 0076 * This is different to getting a Quotient::User object 0077 * as neither of those can provide details like the displayName or avatarMediaId 0078 * without the room context as these can vary from room to room. This function 0079 * uses the room context and outputs the result as QVariantMap. 0080 * 0081 * An empty QVariantMap will be returned if the EventHandler hasn't had the room 0082 * intialised. An empty user (i.e. a QVariantMap with all the correct keys 0083 * but empty values) will be returned if the room has been set but not an event. 0084 * 0085 * @param isPending if the event is pending, i.e. has not been confirmed by 0086 * the server. 0087 * 0088 * @return a QVariantMap for the user with the following properties: 0089 * - isLocalUser - Whether the user is the local user. 0090 * - id - The matrix ID of the user. 0091 * - displayName - Display name in the context of this room. 0092 * - avatarSource - The mxc URL for the user's avatar in the current room. 0093 * - avatarMediaId - Avatar id in the context of this room. 0094 * - color - Color for the user. 0095 * - object - The Quotient::User object for the user. 0096 * 0097 * @sa Quotient::User 0098 */ 0099 QVariantMap getAuthor(bool isPending = false) const; 0100 0101 /** 0102 * @brief Get the display name of the event author. 0103 * 0104 * This method is separate from getAuthor() and special in that it will return 0105 * the old display name of the author if the current event is one that caused it 0106 * to change. This allows for scenarios where the UI wishes to notify that a 0107 * user's display name has changed and what it changed from. 0108 * 0109 * @param isPending whether the event is pending as this cannot be derived from 0110 * just the event object. 0111 */ 0112 QString getAuthorDisplayName(bool isPending = false) const; 0113 0114 /** 0115 * @brief Get the display name of the event author but with any newlines removed. 0116 * 0117 * Turns out you can put newlines in your display name so we need to handle that 0118 * primarily for the room list subtitle. 0119 * 0120 * @param isPending whether the event is pending as this cannot be derived from 0121 * just the event object. 0122 */ 0123 QString singleLineAuthorDisplayname(bool isPending = false) const; 0124 0125 /** 0126 * @brief Return a QDateTime object for the event timestamp. 0127 */ 0128 QDateTime getTime(bool isPending = false, QDateTime lastUpdated = {}) const; 0129 0130 /** 0131 * @brief Return a QString for the event timestamp. 0132 * 0133 * This is intended to return a string that is read for display in the UI without 0134 * any further manipulation required. 0135 * 0136 * @param relative whether the string is realtive to the current date, i.e. 0137 * Yesterday or Wednesday, etc. 0138 * @param format the QLocale::FormatType to use. 0139 * @param isPending whether the event is pending as this cannot be derived from 0140 * just the event object. 0141 * @param lastUpdated the time the event was last updated locally as this cannot be 0142 * obtained from the event. 0143 */ 0144 QString getTimeString(bool relative, QLocale::FormatType format = QLocale::ShortFormat, bool isPending = false, QDateTime lastUpdated = {}) const; 0145 0146 /** 0147 * @brief Whether the event should be highlighted in the timeline. 0148 * 0149 * @note Messages in direct chats are never highlighted. 0150 */ 0151 bool isHighlighted(); 0152 0153 /** 0154 * @brief Whether the event should be hidden in the timeline. 0155 * 0156 * This could be for numerous reasons, e.g. if it's a replacement event, if the 0157 * user has hidden all state events or if the sender has been ignored by the local 0158 * user. 0159 */ 0160 bool isHidden(); 0161 0162 /** 0163 * @brief Output a string for the message content ready for display in a rich text field. 0164 * 0165 * The output string is dependant upon the event type and the desired output format. 0166 * 0167 * For most messages this is the body content of the message. For media messages 0168 * this will be the caption and for state events it will be a string specific 0169 * to that event with some dynamic details about the event added. 0170 * 0171 * E.g. For a room topic state event the text will be: 0172 * "set the topic to: <new topic text>" 0173 * 0174 * @param stripNewlines whether the output should have new lines in it. 0175 */ 0176 QString getRichBody(bool stripNewlines = false) const; 0177 0178 /** 0179 * @brief Output a string for the message content ready for display in a plain text field. 0180 * 0181 * The output string is dependant upon the event type and the desired output format. 0182 * 0183 * For most messages this is the body content of the message. For media messages 0184 * this will be the caption and for state events it will be a string specific 0185 * to that event with some dynamic details about the event added. 0186 * 0187 * E.g. For a room topic state event the text will be: 0188 * "set the topic to: <new topic text>" 0189 * 0190 * @param stripNewlines whether the output should have new lines in it. 0191 */ 0192 QString getPlainBody(bool stripNewlines = false) const; 0193 0194 /** 0195 * @brief Output a generic string for the message content ready for display. 0196 * 0197 * The output string is dependant upon the event type. 0198 * 0199 * Unlike EventHandler::getRichBody or EventHandler::getPlainBody the string 0200 * is the same for all events of the same type. 0201 * 0202 * E.g. For a message the text will be: 0203 * "sent a message" 0204 * 0205 * @sa getRichBody(), getPlainBody() 0206 */ 0207 QString getGenericBody() const; 0208 0209 /** 0210 * @brief Output a string for the event to be used as a RoomList subtitle. 0211 * 0212 * The output includes the username followed by the plain message, all with no 0213 * line breaks. 0214 */ 0215 QString subtitleText() const; 0216 0217 /** 0218 * @brief Return the media info for the event. 0219 * 0220 * An empty QVariantMap will be returned for any event that doesn't have any 0221 * media info. 0222 * 0223 * @return This should consist of the following: 0224 * - source - The mxc URL for the media. 0225 * - mimeType - The MIME type of the media (should be image/xxx for this delegate). 0226 * - mimeIcon - The MIME icon name (should be image-xxx). 0227 * - size - The file size in bytes. 0228 * - width - The width in pixels of the audio media. 0229 * - height - The height in pixels of the audio media. 0230 * - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads. 0231 */ 0232 QVariantMap getMediaInfo() const; 0233 0234 /** 0235 * @brief Whether the event is a reply to another in the timeline. 0236 */ 0237 bool hasReply() const; 0238 0239 /** 0240 * @brief Return the Matrix ID of the event replied to. 0241 */ 0242 QString getReplyId() const; 0243 0244 /** 0245 * @brief Return the DelegateType of the event replied to. 0246 * 0247 * @note While similar this is not the matrix event or message type. This is 0248 * to tell a QML ListView what delegate to show for each event. So while 0249 * similar to the spec it is not the same. 0250 */ 0251 DelegateType::Type getReplyDelegateType() const; 0252 0253 /** 0254 * @brief Get the author of the event replied to in context of the room. 0255 * 0256 * This is different to getting a Quotient::User object 0257 * as neither of those can provide details like the displayName or avatarMediaId 0258 * without the room context as these can vary from room to room. This function 0259 * uses the room context and outputs the result as QVariantMap. 0260 * 0261 * An empty QVariantMap will be returned if the EventHandler hasn't had the room 0262 * intialised. An empty user (i.e. a QVariantMap with all the correct keys 0263 * but empty values) will be returned if the room has been set but not an event. 0264 * 0265 * @return a QVariantMap for the user with the following properties: 0266 * - isLocalUser - Whether the user is the local user. 0267 * - id - The matrix ID of the user. 0268 * - displayName - Display name in the context of this room. 0269 * - avatarSource - The mxc URL for the user's avatar in the current room. 0270 * - avatarMediaId - Avatar id in the context of this room. 0271 * - color - Color for the user. 0272 * - object - The Quotient::User object for the user. 0273 * 0274 * @sa Quotient::User 0275 */ 0276 QVariantMap getReplyAuthor() const; 0277 0278 /** 0279 * @brief Output a string for the message content of the event replied to ready 0280 * for display in a rich text field. 0281 * 0282 * The output string is dependant upon the event type and the desired output format. 0283 * 0284 * For most messages this is the body content of the message. For media messages 0285 * this will be the caption and for state events it will be a string specific 0286 * to that event with some dynamic details about the event added. 0287 * 0288 * E.g. For a room topic state event the text will be: 0289 * "set the topic to: <new topic text>" 0290 * 0291 * @param stripNewlines whether the output should have new lines in it. 0292 */ 0293 QString getReplyRichBody(bool stripNewlines = false) const; 0294 0295 /** 0296 * @brief Output a string for the message content of the event replied to ready 0297 * for display in a plain text field. 0298 * 0299 * The output string is dependant upon the event type and the desired output format. 0300 * 0301 * For most messages this is the body content of the message. For media messages 0302 * this will be the caption and for state events it will be a string specific 0303 * to that event with some dynamic details about the event added. 0304 * 0305 * E.g. For a room topic state event the text will be: 0306 * "set the topic to: <new topic text>" 0307 * 0308 * @param stripNewlines whether the output should have new lines in it. 0309 */ 0310 QString getReplyPlainBody(bool stripNewlines = false) const; 0311 0312 /** 0313 * @brief Return the media info for the event replied to. 0314 * 0315 * An empty QVariantMap will be returned for any event that doesn't have any 0316 * media info. 0317 * 0318 * @return This should consist of the following: 0319 * - source - The mxc URL for the media. 0320 * - mimeType - The MIME type of the media (should be image/xxx for this delegate). 0321 * - mimeIcon - The MIME icon name (should be image-xxx). 0322 * - size - The file size in bytes. 0323 * - width - The width in pixels of the audio media. 0324 * - height - The height in pixels of the audio media. 0325 * - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads. 0326 */ 0327 QVariantMap getReplyMediaInfo() const; 0328 0329 /** 0330 * @brief Whether the message is part of a thread. 0331 * 0332 * i.e. There is a rel_type of m.thread. 0333 */ 0334 bool isThreaded() const; 0335 0336 /** 0337 * @brief Return the Matrix ID of the thread's root message. 0338 * 0339 * Empty if this not part of a thread. 0340 */ 0341 QString threadRoot() const; 0342 0343 /** 0344 * @brief Return the latitude for the event. 0345 * 0346 * Returns -100.0 if the event doesn't have a location (latitudes are in the 0347 * range -90deg to +90deg so -100 is out of range). 0348 */ 0349 float getLatitude() const; 0350 0351 /** 0352 * @brief Return the longitude for the event. 0353 * 0354 * Returns -200.0 if the event doesn't have a location (latitudes are in the 0355 * range -180deg to +180deg so -200 is out of range). 0356 */ 0357 float getLongitude() const; 0358 0359 /** 0360 * @brief Return the type of location marker for the event. 0361 */ 0362 QString getLocationAssetType() const; 0363 0364 /** 0365 * @brief Whether the event has any read marker for other users. 0366 */ 0367 bool hasReadMarkers() const; 0368 0369 /** 0370 * @brief Returns a list of user read marker for the event. 0371 * 0372 * @param maxMarkers the maximum number of users to return. Usually the number 0373 * of user read makers shown is limited to not clutter the UI. 0374 * This needs to be the same as used in getNumberExcessReadMarkers 0375 * so that the markers line up with the number displayed, i.e. 0376 * the number of users shown plus the excess number will be 0377 * the total number of other user read markers at an event. 0378 */ 0379 QVariantList getReadMarkers(int maxMarkers = 5) const; 0380 0381 /** 0382 * @brief Returns the number of excess user read markers for the event. 0383 * 0384 * This returns a string in the form "+ x" ready for use in the UI. 0385 * 0386 * @param maxMarkers the maximum number of markers shown in the UI. This needs to 0387 * be the same as used in getReadMarkers so that the value lines 0388 * up with the number displayed, i.e. the number of users shown 0389 * plus the excess number will be the total number of other user 0390 * read markers at an event. 0391 */ 0392 QString getNumberExcessReadMarkers(int maxMarkers = 5) const; 0393 0394 /** 0395 * @brief Returns a string with the names of the read markers at the event. 0396 * 0397 * This is in the form "x users: name 1, name 2, ...". 0398 */ 0399 QString getReadMarkersString() const; 0400 0401 private: 0402 const NeoChatRoom *m_room = nullptr; 0403 const Quotient::RoomEvent *m_event = nullptr; 0404 0405 KFormat m_format; 0406 0407 DelegateType::Type getDelegateTypeForEvent(const Quotient::RoomEvent *event) const; 0408 0409 QString getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const; 0410 QString getMessageBody(const Quotient::RoomMessageEvent &event, Qt::TextFormat format, bool stripNewlines) const; 0411 0412 QVariantMap getMediaInfoForEvent(const Quotient::RoomEvent *event) const; 0413 QVariantMap getMediaInfoFromFileInfo(const Quotient::EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail = false) const; 0414 };