File indexing completed on 2024-05-05 16:58:39

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 };