Document messageeventmodel

Document the API and cleanup some unused roles.
This commit is contained in:
James Graham
2023-04-09 14:02:30 +00:00
parent b4090d9671
commit 7bb7dd7bbb
8 changed files with 160 additions and 107 deletions

View File

@@ -9,9 +9,9 @@
bool CollapseStateProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const bool CollapseStateProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{ {
Q_UNUSED(source_parent); Q_UNUSED(source_parent);
return sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::EventTypeRole) return sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::DelegateTypeRole)
!= MessageEventModel::DelegateType::State // If this is not a state, show it != MessageEventModel::DelegateType::State // If this is not a state, show it
|| sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::EventTypeRole) || sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::DelegateTypeRole)
!= MessageEventModel::DelegateType::State // If this is the first state in a block, show it. TODO hidden events? != MessageEventModel::DelegateType::State // If this is the first state in a block, show it. TODO hidden events?
|| sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::ShowSectionRole).toBool(); // If it's a new day, show it || sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::ShowSectionRole).toBool(); // If it's a new day, show it
} }
@@ -47,7 +47,7 @@ QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
if (!uniqueAuthors.contains(nextAuthor)) { if (!uniqueAuthors.contains(nextAuthor)) {
uniqueAuthors.append(nextAuthor); uniqueAuthors.append(nextAuthor);
} }
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventTypeRole) if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
!= MessageEventModel::DelegateType::State // If it's not a state event != MessageEventModel::DelegateType::State // If it's not a state event
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible || sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
) { ) {
@@ -105,7 +105,7 @@ QVariantList CollapseStateProxyModel::stateEventsList(int sourceRow) const
{"text", sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()}, {"text", sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()},
}; };
stateEvents.append(nextState); stateEvents.append(nextState);
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventTypeRole) if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
!= MessageEventModel::DelegateType::State // If it's not a state event != MessageEventModel::DelegateType::State // If it's not a state event
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible || sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
) { ) {
@@ -123,7 +123,7 @@ QVariantList CollapseStateProxyModel::authorList(int sourceRow) const
if (!uniqueAuthors.contains(nextAvatar)) { if (!uniqueAuthors.contains(nextAvatar)) {
uniqueAuthors.append(nextAvatar); uniqueAuthors.append(nextAvatar);
} }
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventTypeRole) if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
!= MessageEventModel::DelegateType::State // If it's not a state event != MessageEventModel::DelegateType::State // If it's not a state event
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible || sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
) { ) {

View File

@@ -33,7 +33,7 @@ using namespace Quotient;
QHash<int, QByteArray> MessageEventModel::roleNames() const QHash<int, QByteArray> MessageEventModel::roleNames() const
{ {
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
roles[EventTypeRole] = "eventType"; roles[DelegateTypeRole] = "delegateType";
roles[MessageRole] = "message"; roles[MessageRole] = "message";
roles[EventIdRole] = "eventId"; roles[EventIdRole] = "eventId";
roles[TimeRole] = "time"; roles[TimeRole] = "time";
@@ -45,12 +45,10 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
roles[SpecialMarksRole] = "marks"; roles[SpecialMarksRole] = "marks";
roles[LongOperationRole] = "progressInfo"; roles[LongOperationRole] = "progressInfo";
roles[FileMimetypeIcon] = "fileMimetypeIcon"; roles[FileMimetypeIcon] = "fileMimetypeIcon";
roles[AnnotationRole] = "annotation";
roles[EventResolvedTypeRole] = "eventResolvedType"; roles[EventResolvedTypeRole] = "eventResolvedType";
roles[IsReplyRole] = "isReply"; roles[IsReplyRole] = "isReply";
roles[ReplyRole] = "reply"; roles[ReplyRole] = "reply";
roles[ReplyIdRole] = "replyId"; roles[ReplyIdRole] = "replyId";
roles[UserMarkerRole] = "userMarker";
roles[ShowAuthorRole] = "showAuthor"; roles[ShowAuthorRole] = "showAuthor";
roles[ShowSectionRole] = "showSection"; roles[ShowSectionRole] = "showSection";
roles[ReadMarkersRole] = "readMarkers"; roles[ReadMarkersRole] = "readMarkers";
@@ -76,7 +74,6 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
MessageEventModel::MessageEventModel(QObject *parent) MessageEventModel::MessageEventModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_currentRoom(nullptr)
{ {
using namespace Quotient; using namespace Quotient;
qmlRegisterAnonymousType<FileTransferInfo>("org.kde.neochat", 1); qmlRegisterAnonymousType<FileTransferInfo>("org.kde.neochat", 1);
@@ -89,6 +86,11 @@ MessageEventModel::MessageEventModel(QObject *parent)
MessageEventModel::~MessageEventModel() = default; MessageEventModel::~MessageEventModel() = default;
NeoChatRoom *MessageEventModel::room() const
{
return m_currentRoom;
}
void MessageEventModel::setRoom(NeoChatRoom *room) void MessageEventModel::setRoom(NeoChatRoom *room)
{ {
if (room == m_currentRoom) { if (room == m_currentRoom) {
@@ -316,7 +318,7 @@ int MessageEventModel::refreshEventRoles(const QString &id, const QVector<int> &
return -1; return -1;
} }
row = int(timelineIt - m_currentRoom->messageEvents().rbegin()) + timelineBaseIndex(); row = int(timelineIt - m_currentRoom->messageEvents().rbegin()) + timelineBaseIndex();
if (data(index(row, 0), EventTypeRole).toInt() == ReadMarker || data(index(row, 0), EventTypeRole).toInt() == Other) { if (data(index(row, 0), DelegateTypeRole).toInt() == ReadMarker || data(index(row, 0), DelegateTypeRole).toInt() == Other) {
row++; row++;
} }
} }
@@ -447,7 +449,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (m_lastReadEventIndex.row() == row) { if (m_lastReadEventIndex.row() == row) {
switch (role) { switch (role) {
case EventTypeRole: case DelegateTypeRole:
return DelegateType::ReadMarker; return DelegateType::ReadMarker;
case TimeRole: { case TimeRole: {
const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime().toLocalTime(); const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime().toLocalTime();
@@ -499,7 +501,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
return evt.originalJson(); return evt.originalJson();
} }
if (role == EventTypeRole) { if (role == DelegateTypeRole) {
if (auto e = eventCast<const RoomMessageEvent>(&evt)) { if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
switch (e->msgtype()) { switch (e->msgtype()) {
case MessageEventType::Emote: case MessageEventType::Emote:
@@ -676,29 +678,11 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
} }
} }
if (role == AnnotationRole) {
if (isPending) {
return pendingIt->annotation();
}
}
if (role == TimeRole || role == SectionRole) { if (role == TimeRole || role == SectionRole) {
auto ts = isPending ? pendingIt->lastUpdated() : makeMessageTimestamp(timelineIt); auto ts = isPending ? pendingIt->lastUpdated() : makeMessageTimestamp(timelineIt);
return role == TimeRole ? QVariant(ts) : renderDate(ts); return role == TimeRole ? QVariant(ts) : renderDate(ts);
} }
if (role == UserMarkerRole) {
QVariantList variantList;
const auto users = m_currentRoom->usersAtEventId(evt.id());
for (User *user : users) {
if (user == m_currentRoom->localUser()) {
continue;
}
variantList.append(QVariant::fromValue(user));
}
return variantList;
}
if (role == IsReplyRole) { if (role == IsReplyRole) {
return !evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString().isEmpty(); return !evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString().isEmpty();
} }
@@ -784,7 +768,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
// While the row is removed the subsequent row indexes are not changed so we need to skip over the removed index. // While the row is removed the subsequent row indexes are not changed so we need to skip over the removed index.
// See - https://doc.qt.io/qt-5/qabstractitemmodel.html#beginRemoveRows // See - https://doc.qt.io/qt-5/qabstractitemmodel.html#beginRemoveRows
if (data(i, SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) { if (data(i, SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) {
return data(i, AuthorRole) != data(idx, AuthorRole) || data(i, EventTypeRole) == MessageEventModel::State return data(i, AuthorRole) != data(idx, AuthorRole) || data(i, DelegateTypeRole) == MessageEventModel::State
|| data(i, TimeRole).toDateTime().msecsTo(data(idx, TimeRole).toDateTime()) > 600000 || data(i, TimeRole).toDateTime().msecsTo(data(idx, TimeRole).toDateTime()) > 600000
|| data(i, TimeRole).toDateTime().toLocalTime().date().day() != data(idx, TimeRole).toDateTime().toLocalTime().date().day(); || data(i, TimeRole).toDateTime().toLocalTime().date().day() != data(idx, TimeRole).toDateTime().toLocalTime().date().day();
} }
@@ -1005,7 +989,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
return {}; return {};
} }
int MessageEventModel::eventIDToIndex(const QString &eventID) const int MessageEventModel::eventIdToRow(const QString &eventID) const
{ {
const auto it = m_currentRoom->findInTimeline(eventID); const auto it = m_currentRoom->findInTimeline(eventID);
if (it == m_currentRoom->historyEdge()) { if (it == m_currentRoom->historyEdge()) {
@@ -1047,7 +1031,7 @@ QVariant MessageEventModel::getLastLocalUserMessageEventId()
targetMessage.insert("event_id", eventId); targetMessage.insert("event_id", eventId);
targetMessage.insert("formattedBody", content["formatted_body"].toString()); targetMessage.insert("formattedBody", content["formatted_body"].toString());
// Need to get the message from the original eventId or body will have * on the front // Need to get the message from the original eventId or body will have * on the front
QModelIndex idx = index(eventIDToIndex(eventId), 0); QModelIndex idx = index(eventIdToRow(eventId), 0);
targetMessage.insert("message", idx.data(Qt::UserRole + 2)); targetMessage.insert("message", idx.data(Qt::UserRole + 2));
return targetMessage; return targetMessage;
@@ -1057,14 +1041,14 @@ QVariant MessageEventModel::getLastLocalUserMessageEventId()
return targetMessage; return targetMessage;
} }
QVariant MessageEventModel::getLatestMessageFromIndex(const int baseline) QVariant MessageEventModel::getLatestMessageFromRow(const int startRow)
{ {
QVariantMap replyResponse; QVariantMap replyResponse;
const auto &timelineBottom = m_currentRoom->messageEvents().rbegin() + baseline; const auto &timelineBottom = m_currentRoom->messageEvents().rbegin() + startRow;
// set a cap limit of baseline + 35 messages, to prevent loading a lot of messages // set a cap limit of startRow + 35 messages, to prevent loading a lot of messages
// in rooms where the user has not sent many messages // in rooms where the user has not sent many messages
const auto limit = timelineBottom + std::min(baseline + 35, m_currentRoom->timelineSize()); const auto limit = timelineBottom + std::min(startRow + 35, m_currentRoom->timelineSize());
for (auto it = timelineBottom; it != limit; ++it) { for (auto it = timelineBottom; it != limit; ++it) {
auto evt = it->event(); auto evt = it->event();
@@ -1086,7 +1070,7 @@ QVariant MessageEventModel::getLatestMessageFromIndex(const int baseline)
} }
replyResponse.insert("event_id", eventId); replyResponse.insert("event_id", eventId);
// Need to get the message from the original eventId or body will have * on the front // Need to get the message from the original eventId or body will have * on the front
QModelIndex idx = index(eventIDToIndex(eventId), 0); QModelIndex idx = index(eventIdToRow(eventId), 0);
replyResponse.insert("message", idx.data(Qt::UserRole + 2)); replyResponse.insert("message", idx.data(Qt::UserRole + 2));
replyResponse.insert("sender_id", QVariant::fromValue(m_currentRoom->getUser((*it)->senderId()))); replyResponse.insert("sender_id", QVariant::fromValue(m_currentRoom->getUser((*it)->senderId())));
replyResponse.insert("at", -it->index()); replyResponse.insert("at", -it->index());

View File

@@ -7,77 +7,99 @@
#include "neochatroom.h" #include "neochatroom.h"
/**
* @class MessageEventModel
*
* This class defines the model for visualising the room timeline.
*
* This model covers all event types in the timeline with many of the roles being
* specific to a subset of events. This means the user needs to understand which
* roles will return useful information for a given event type.
*
* @sa NeoChatRoom
*/
class MessageEventModel : public QAbstractListModel class MessageEventModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
/**
* @brief The current room that the model is getting its messages from.
*/
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged) Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
public: public:
/**
* @brief The type of delegate that is needed for the event.
*
* @note While similar this is not the matrix event or message type. This is
* to tell a QML ListView what delegate to show for each event. So while
* similar to the spec it is not the same.
*/
enum DelegateType { enum DelegateType {
Emote, Emote, /**< A message that begins with /me. */
Notice, Notice, /**< A notice event. */
Image, Image, /**< A message that is an image. */
Audio, Audio, /**< A message that is an audio recording. */
Video, Video, /**< A message that is a video. */
File, File, /**< A message that is a file. */
Message, Message, /**< A text message. */
Sticker, Sticker, /**< A message that is a sticker. */
State, State, /**< A state event in the room. */
Encrypted, Encrypted, /**< An encrypted message that cannot be decrypted. */
ReadMarker, ReadMarker, /**< The local user read marker. */
Poll, Poll, /**< The initial event for a poll. */
Location, Location, /**< A location event. */
Other, Other, /**< Anything that cannot be classified as another type. */
}; };
Q_ENUM(DelegateType); Q_ENUM(DelegateType);
/**
* @brief Defines the model roles.
*/
enum EventRoles { enum EventRoles {
EventTypeRole = Qt::UserRole + 1, DelegateTypeRole = Qt::UserRole + 1, /**< The delegate type of the message. */
MessageRole, MessageRole, /**< Plain text representation of the message. */
EventIdRole, EventIdRole, /**< The matrix event ID of the event. */
TimeRole, TimeRole, /**< The timestamp for when the event was sent. */
SectionRole, SectionRole, /**< The date of the event as a string. */
AuthorRole, AuthorRole, /**< The author of the event. */
ContentRole, ContentRole, /**< The full message content. */
ContentTypeRole, ContentTypeRole, /**< The content mime type. */
HighlightRole, HighlightRole, /**< Whether the event should be highlighted. */
SpecialMarksRole, SpecialMarksRole, /**< Whether the event is hidden or not. */
LongOperationRole, LongOperationRole, /**< Progress info when downloading files. */
AnnotationRole, FormattedBodyRole, /**< The formatted body of a rich message. */
UserMarkerRole, GenericDisplayRole, /**< A generic string based upon the message type. */
FormattedBodyRole,
GenericDisplayRole,
MimeTypeRole, MimeTypeRole, /**< The mime type of the message's file or media. */
FileMimetypeIcon, FileMimetypeIcon, /**< The icon name for the mime type of a file. */
IsReplyRole, IsReplyRole, /**< Is the message a reply to another event. */
ReplyRole, ReplyRole, /**< The content data of the message that was replied to. */
ReplyIdRole, ReplyIdRole, /**< The matrix ID of the message that was replied to. */
ShowAuthorRole, ShowAuthorRole, /**< Whether the author's name should be shown. */
ShowSectionRole, ShowSectionRole, /**< Whether the section header should be shown. */
ReadMarkersRole, /**< QVariantList of users at the event for read marker tracking. */ ReadMarkersRole, /**< Other users at the event for read marker tracking. */
ReadMarkersStringRole, /**< QString with the display name and mxID of the users at the event. */ ReadMarkersStringRole, /**< String with the display name and mxID of the users at the event. */
ShowReadMarkersRole, /**< bool with whether there are any other user read markers to be shown. */ ShowReadMarkersRole, /**< Whether there are any other user read markers to be shown. */
ReactionRole, ReactionRole, /**< List of reactions to this event. */
SourceRole, /**< The full message source JSON. */
MediaUrlRole, /**< The source URL for any media in the message. */
SourceRole,
MediaUrlRole,
// For debugging // For debugging
EventResolvedTypeRole, EventResolvedTypeRole, /**< The event type the message. */
AuthorIdRole, AuthorIdRole, /**< Matrix ID of the message author. */
VerifiedRole,
// Sender's displayname, always without the matrix id VerifiedRole, /**< Whether an encrypted message is sent in a verified session. */
DisplayNameForInitialsRole, DisplayNameForInitialsRole, /**< Sender's displayname, always without the matrix id. */
// The displayname for the event's sender; for name change events, the old displayname AuthorDisplayNameRole, /**< The displayname for the event's sender; for name change events, the old displayname. */
AuthorDisplayNameRole, IsRedactedRole, /**< Whether an event has been deleted. */
IsRedactedRole, IsPendingRole, /**< Whether an event is waiting to be accepted by the server. */
IsPendingRole, LatitudeRole, /**< Latitude for a location event. */
LatitudeRole, LongitudeRole, /**< Longitude for a location event. */
LongitudeRole, AssetRole, /**< Type of location event, e.g. self pin of the user location. */
AssetRole,
LastRole, // Keep this last LastRole, // Keep this last
}; };
Q_ENUM(EventRoles) Q_ENUM(EventRoles)
@@ -85,20 +107,67 @@ public:
explicit MessageEventModel(QObject *parent = nullptr); explicit MessageEventModel(QObject *parent = nullptr);
~MessageEventModel() override; ~MessageEventModel() override;
[[nodiscard]] NeoChatRoom *room() const [[nodiscard]] NeoChatRoom *room() const;
{
return m_currentRoom;
}
void setRoom(NeoChatRoom *room); void setRoom(NeoChatRoom *room);
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; /**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa EventRoles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE [[nodiscard]] int eventIDToIndex(const QString &eventID) const; /**
* @brief Get the row number of the given event ID in the model.
*/
Q_INVOKABLE [[nodiscard]] int eventIdToRow(const QString &eventID) const;
/**
* @brief Get the last message sent by the local user.
*
* @note This checks a maximum of the previous 35 message for performance reasons.
*
* @return a QVariantMap for the event with the following parameters:
* - eventId - The event ID.
* - formattedBody - The message text formatted as Qt::RichText.
* - message - The message text formatted as Qt::PlainText.
*/
Q_INVOKABLE [[nodiscard]] QVariant getLastLocalUserMessageEventId(); Q_INVOKABLE [[nodiscard]] QVariant getLastLocalUserMessageEventId();
Q_INVOKABLE [[nodiscard]] QVariant getLatestMessageFromIndex(const int baseline);
Q_INVOKABLE void loadReply(const QModelIndex &row); /**
* @brief Get the last message sent earlier than the given row.
*
* @note This checks a maximum of the previous 35 message for performance reasons.
*
* @return a QVariantMap for the event with the following parameters:
* - eventId - The event ID.
* - message - The message text formatted as Qt::PlainText.
* - sender_id - The matrix ID of the sender.
* - at - The QModelIndex of the message.
*/
Q_INVOKABLE [[nodiscard]] QVariant getLatestMessageFromRow(const int startRow);
/**
* @brief Load the event that the item at the given index replied to.
*
* This is used to ensure that the reply data is available when the message that
* was replied to is outside the currently loaded timeline.
*/
Q_INVOKABLE void loadReply(const QModelIndex &index);
private Q_SLOTS: private Q_SLOTS:
int refreshEvent(const QString &eventId); int refreshEvent(const QString &eventId);

View File

@@ -41,7 +41,7 @@ bool MessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
return false; return false;
} }
const auto eventType = index.data(MessageEventModel::EventTypeRole).toInt(); const auto eventType = index.data(MessageEventModel::DelegateTypeRole).toInt();
if (eventType == MessageEventModel::Other) { if (eventType == MessageEventModel::Other) {
return false; return false;

View File

@@ -206,7 +206,7 @@ QQC2.Control {
if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) { if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
chatBar.pasteImage(); chatBar.pasteImage();
} else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) { } else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) {
let replyEvent = messageEventModel.getLatestMessageFromIndex(0) let replyEvent = messageEventModel.getLatestMessageFromRow(0)
if (replyEvent && replyEvent["event_id"]) { if (replyEvent && replyEvent["event_id"]) {
currentRoom.chatBoxReplyId = replyEvent["event_id"] currentRoom.chatBoxReplyId = replyEvent["event_id"]
} }

View File

@@ -11,7 +11,7 @@ import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0 import org.kde.neochat 1.0
DelegateChooser { DelegateChooser {
role: "eventType" role: "delegateType"
DelegateChoice { DelegateChoice {
roleValue: MessageEventModel.State roleValue: MessageEventModel.State

View File

@@ -336,7 +336,7 @@ ColumnLayout {
Layout.leftMargin: showUserMessageOnRight ? 0 : bubble.x + bubble.anchors.leftMargin Layout.leftMargin: showUserMessageOnRight ? 0 : bubble.x + bubble.anchors.leftMargin
Layout.rightMargin: showUserMessageOnRight ? Kirigami.Units.largeSpacing : 0 Layout.rightMargin: showUserMessageOnRight ? Kirigami.Units.largeSpacing : 0
visible: eventType !== MessageEventModel.State && eventType !== MessageEventModel.Notice && reaction != undefined && reaction.length > 0 visible: delegateType !== MessageEventModel.State && delegateType !== MessageEventModel.Notice && reaction != undefined && reaction.length > 0
} }
AvatarFlow { AvatarFlow {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight

View File

@@ -476,7 +476,7 @@ Kirigami.ScrollablePage {
id: hoverActions id: hoverActions
property var event: null property var event: null
property bool userMsg: event && event.author.id === Controller.activeConnection.localUserId property bool userMsg: event && event.author.id === Controller.activeConnection.localUserId
property bool showEdit: event && (userMsg && (event.eventType === MessageEventModel.Emote || event.eventType === MessageEventModel.Message)) property bool showEdit: event && (userMsg && (event.delegateType === MessageEventModel.Emote || event.delegateType === MessageEventModel.Message))
property var delegate: null property var delegate: null
property var bubble: null property var bubble: null
property var hovered: bubble && bubble.hovered property var hovered: bubble && bubble.hovered
@@ -642,7 +642,7 @@ Kirigami.ScrollablePage {
} }
function eventToIndex(eventID) { function eventToIndex(eventID) {
const index = messageEventModel.eventIDToIndex(eventID) const index = messageEventModel.eventIdToRow(eventID)
if (index === -1) if (index === -1)
return -1 return -1
return sortedMessageEventModel.mapFromSource(messageEventModel.index(index, 0)).row return sortedMessageEventModel.mapFromSource(messageEventModel.index(index, 0)).row
@@ -702,7 +702,7 @@ Kirigami.ScrollablePage {
eventId: event.eventId, eventId: event.eventId,
formattedBody: event.formattedBody, formattedBody: event.formattedBody,
source: event.source, source: event.source,
eventType: event.eventType, eventType: event.delegateType,
plainMessage: plainMessage, plainMessage: plainMessage,
}); });
contextMenu.open(); contextMenu.open();