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