File indexing completed on 2024-11-03 10:41:29
0001 // SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org> 0002 // SPDX-License-Identifier: GPL-3.0-only 0003 0004 #pragma once 0005 0006 #include <KFormat> 0007 #include <QAbstractListModel> 0008 0009 #include "linkpreviewer.h" 0010 #include "neochatroom.h" 0011 0012 class ReactionModel; 0013 0014 /** 0015 * @class MessageEventModel 0016 * 0017 * This class defines the model for visualising the room timeline. 0018 * 0019 * This model covers all event types in the timeline with many of the roles being 0020 * specific to a subset of events. This means the user needs to understand which 0021 * roles will return useful information for a given event type. 0022 * 0023 * @sa NeoChatRoom 0024 */ 0025 class MessageEventModel : public QAbstractListModel 0026 { 0027 Q_OBJECT 0028 0029 /** 0030 * @brief The current room that the model is getting its messages from. 0031 */ 0032 Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged) 0033 0034 public: 0035 /** 0036 * @brief The type of delegate that is needed for the event. 0037 * 0038 * @note While similar this is not the matrix event or message type. This is 0039 * to tell a QML ListView what delegate to show for each event. So while 0040 * similar to the spec it is not the same. 0041 */ 0042 enum DelegateType { 0043 Emote, /**< A message that begins with /me. */ 0044 Notice, /**< A notice event. */ 0045 Image, /**< A message that is an image. */ 0046 Audio, /**< A message that is an audio recording. */ 0047 Video, /**< A message that is a video. */ 0048 File, /**< A message that is a file. */ 0049 Message, /**< A text message. */ 0050 Sticker, /**< A message that is a sticker. */ 0051 State, /**< A state event in the room. */ 0052 Encrypted, /**< An encrypted message that cannot be decrypted. */ 0053 ReadMarker, /**< The local user read marker. */ 0054 Poll, /**< The initial event for a poll. */ 0055 Location, /**< A location event. */ 0056 LiveLocation, /**< The initial event of a shared live location (i.e., the place where this is supposed to be shown in the timeline). */ 0057 Other, /**< Anything that cannot be classified as another type. */ 0058 }; 0059 Q_ENUM(DelegateType) 0060 0061 /** 0062 * @brief Defines the model roles. 0063 */ 0064 enum EventRoles { 0065 DelegateTypeRole = Qt::UserRole + 1, /**< The delegate type of the message. */ 0066 PlainText, /**< Plain text representation of the message. */ 0067 EventIdRole, /**< The matrix event ID of the event. */ 0068 TimeRole, /**< The timestamp for when the event was sent. */ 0069 SectionRole, /**< The date of the event as a string. */ 0070 AuthorRole, /**< The author of the event. */ 0071 ContentRole, /**< The full message content. */ 0072 HighlightRole, /**< Whether the event should be highlighted. */ 0073 SpecialMarksRole, /**< Whether the event is hidden or not. */ 0074 ProgressInfoRole, /**< Progress info when downloading files. */ 0075 GenericDisplayRole, /**< A generic string based upon the message type. */ 0076 0077 ShowLinkPreviewRole, /**< Whether a link preview should be shown. */ 0078 LinkPreviewRole, /**< The link preview details. */ 0079 0080 MediaInfoRole, /**< The media info for the event. */ 0081 MimeTypeRole, /**< The mime type of the message's file or media. */ 0082 0083 IsReplyRole, /**< Is the message a reply to another event. */ 0084 ReplyAuthor, /**< The author of the event that was replied to. */ 0085 ReplyIdRole, /**< The matrix ID of the message that was replied to. */ 0086 ReplyMediaInfoRole, /**< The media info of the message that was replied to. */ 0087 ReplyRole, /**< The content data of the message that was replied to. */ 0088 0089 ShowAuthorRole, /**< Whether the author's name should be shown. */ 0090 ShowSectionRole, /**< Whether the section header should be shown. */ 0091 0092 ReadMarkersRole, /**< The first 5 other users at the event for read marker tracking. */ 0093 ExcessReadMarkersRole, /**< The number of other users at the event after the first 5. */ 0094 ReadMarkersStringRole, /**< String with the display name and mxID of the users at the event. */ 0095 ShowReadMarkersRole, /**< Whether there are any other user read markers to be shown. */ 0096 ReactionRole, /**< List model for this event. */ 0097 ShowReactionsRole, /**< Whether there are any reactions to be shown. */ 0098 SourceRole, /**< The full message source JSON. */ 0099 0100 AuthorIdRole, /**< Matrix ID of the message author. */ 0101 0102 VerifiedRole, /**< Whether an encrypted message is sent in a verified session. */ 0103 DisplayNameForInitialsRole, /**< Sender's displayname, always without the matrix id. */ 0104 AuthorDisplayNameRole, /**< The displayname for the event's sender; for name change events, the old displayname. */ 0105 IsRedactedRole, /**< Whether an event has been deleted. */ 0106 IsPendingRole, /**< Whether an event is waiting to be accepted by the server. */ 0107 LatitudeRole, /**< Latitude for a location event. */ 0108 LongitudeRole, /**< Longitude for a location event. */ 0109 AssetRole, /**< Type of location event, e.g. self pin of the user location. */ 0110 LastRole, // Keep this last 0111 }; 0112 Q_ENUM(EventRoles) 0113 0114 explicit MessageEventModel(QObject *parent = nullptr); 0115 0116 [[nodiscard]] NeoChatRoom *room() const; 0117 void setRoom(NeoChatRoom *room); 0118 0119 /** 0120 * @brief Get the given role value at the given index. 0121 * 0122 * @sa QAbstractItemModel::data 0123 */ 0124 [[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override; 0125 0126 /** 0127 * @brief Number of rows in the model. 0128 * 0129 * @sa QAbstractItemModel::rowCount 0130 */ 0131 [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0132 0133 /** 0134 * @brief Returns a mapping from Role enum values to role names. 0135 * 0136 * @sa EventRoles, QAbstractItemModel::roleNames() 0137 */ 0138 [[nodiscard]] QHash<int, QByteArray> roleNames() const override; 0139 0140 /** 0141 * @brief Get the row number of the given event ID in the model. 0142 */ 0143 Q_INVOKABLE [[nodiscard]] int eventIdToRow(const QString &eventID) const; 0144 0145 private Q_SLOTS: 0146 int refreshEvent(const QString &eventId); 0147 void refreshRow(int row); 0148 0149 private: 0150 NeoChatRoom *m_currentRoom = nullptr; 0151 QString lastReadEventId; 0152 QPersistentModelIndex m_lastReadEventIndex; 0153 int rowBelowInserted = -1; 0154 bool movingEvent = false; 0155 KFormat m_format; 0156 0157 QMap<QString, LinkPreviewer *> m_linkPreviewers; 0158 QMap<QString, ReactionModel *> m_reactionModels; 0159 0160 [[nodiscard]] int timelineBaseIndex() const; 0161 [[nodiscard]] QDateTime makeMessageTimestamp(const Quotient::Room::rev_iter_t &baseIt) const; 0162 0163 bool canFetchMore(const QModelIndex &parent) const override; 0164 void fetchMore(const QModelIndex &parent) override; 0165 0166 void refreshLastUserEvents(int baseTimelineRow); 0167 void refreshEventRoles(int row, const QVector<int> &roles = {}); 0168 int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {}); 0169 void moveReadMarker(const QString &toEventId); 0170 0171 QVariantMap getMediaInfoForEvent(const Quotient::RoomEvent &event) const; 0172 QVariantMap getMediaInfoFromFileInfo(const Quotient::EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail = false) const; 0173 void createLinkPreviewerForEvent(const Quotient::RoomMessageEvent *event); 0174 void createReactionModelForEvent(const Quotient::RoomMessageEvent *event); 0175 // Hack to ensure that we don't call endInsertRows when we haven't called beginInsertRows 0176 bool m_initialized = false; 0177 0178 Q_SIGNALS: 0179 void roomChanged(); 0180 void fancyEffectsReasonFound(const QString &fancyEffect); 0181 };