Load replied-to message when it isn't in the timeline already

This commit is contained in:
Tobias Fella
2022-02-18 16:11:51 +01:00
parent 290b2249c4
commit dd91cb91d0
3 changed files with 49 additions and 9 deletions

View File

@@ -27,6 +27,12 @@ QQC2.ItemDelegate {
signal openExternally() signal openExternally()
signal replyClicked(string eventID) signal replyClicked(string eventID)
Component.onCompleted: {
if (model.isReply && model.reply === undefined) {
messageEventModel.loadReply(sortedMessageEventModel.mapToSource(sortedMessageEventModel.index(model.index, 0)))
}
}
topPadding: 0 topPadding: 0
bottomPadding: 0 bottomPadding: 0
background: null background: null

View File

@@ -5,6 +5,7 @@
#include "neochatconfig.h" #include "neochatconfig.h"
#include <connection.h> #include <connection.h>
#include <csapi/rooms.h>
#include <events/reactionevent.h> #include <events/reactionevent.h>
#include <events/redactionevent.h> #include <events/redactionevent.h>
#include <events/roomavatarevent.h> #include <events/roomavatarevent.h>
@@ -41,7 +42,9 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
roles[FileMimetypeIcon] = "fileMimetypeIcon"; roles[FileMimetypeIcon] = "fileMimetypeIcon";
roles[AnnotationRole] = "annotation"; roles[AnnotationRole] = "annotation";
roles[EventResolvedTypeRole] = "eventResolvedType"; roles[EventResolvedTypeRole] = "eventResolvedType";
roles[IsReplyRole] = "isReply";
roles[ReplyRole] = "reply"; roles[ReplyRole] = "reply";
roles[ReplyIdRole] = "replyId";
roles[UserMarkerRole] = "userMarker"; roles[UserMarkerRole] = "userMarker";
roles[ShowAuthorRole] = "showAuthor"; roles[ShowAuthorRole] = "showAuthor";
roles[ShowSectionRole] = "showSection"; roles[ShowSectionRole] = "showSection";
@@ -642,19 +645,35 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
return variantList; return variantList;
} }
if (role == IsReplyRole) {
return !evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString().isEmpty();
}
if (role == ReplyIdRole) {
return evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString();
}
if (role == ReplyRole) { if (role == ReplyRole) {
const QString &replyEventId = evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString(); const QString &replyEventId = evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString();
if (replyEventId.isEmpty()) { if (replyEventId.isEmpty()) {
return {}; return {};
}; };
const auto replyIt = m_currentRoom->findInTimeline(replyEventId); const auto replyIt = m_currentRoom->findInTimeline(replyEventId);
if (replyIt == m_currentRoom->historyEdge()) { const RoomEvent *replyPtr = replyIt != m_currentRoom->historyEdge() ? &**replyIt : nullptr;
if (!replyPtr) {
for (const auto &e : m_extraEvents) {
if (e->id() == replyEventId) {
replyPtr = e.get();
break;
}
}
}
if (!replyPtr) {
return {}; return {};
}; }
const auto &replyEvt = **replyIt;
QString type; QString type;
if (auto e = eventCast<const RoomMessageEvent>(&replyEvt)) { if (auto e = eventCast<const RoomMessageEvent>(replyPtr)) {
switch (e->msgtype()) { switch (e->msgtype()) {
case MessageEventType::Emote: case MessageEventType::Emote:
type = "emote"; type = "emote";
@@ -679,29 +698,29 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
type = "message"; type = "message";
} }
} else if (is<const StickerEvent>(replyEvt)) { } else if (is<const StickerEvent>(*replyPtr)) {
type = "sticker"; type = "sticker";
} else { } else {
type = "other"; type = "other";
} }
QVariant content; QVariant content;
if (auto e = eventCast<const RoomMessageEvent>(&replyEvt)) { if (auto e = eventCast<const RoomMessageEvent>(replyPtr)) {
// Cannot use e.contentJson() here because some // Cannot use e.contentJson() here because some
// EventContent classes inject values into the copy of the // EventContent classes inject values into the copy of the
// content JSON stored in EventContent::Base // content JSON stored in EventContent::Base
content = e->hasFileContent() ? QVariant::fromValue(e->content()->originalJson) : QVariant(); content = e->hasFileContent() ? QVariant::fromValue(e->content()->originalJson) : QVariant();
}; };
if (auto e = eventCast<const StickerEvent>(&replyEvt)) { if (auto e = eventCast<const StickerEvent>(replyPtr)) {
content = QVariant::fromValue(e->image().originalJson); content = QVariant::fromValue(e->image().originalJson);
} }
return QVariantMap{{"eventId", replyEventId}, return QVariantMap{{"eventId", replyEventId},
{"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)}, {"display", m_currentRoom->eventToString(*replyPtr, Qt::RichText)},
{"content", content}, {"content", content},
{"type", type}, {"type", type},
{"author", userAtEvent(static_cast<NeoChatUser *>(m_currentRoom->user(replyEvt.senderId())), m_currentRoom, evt)}}; {"author", userAtEvent(static_cast<NeoChatUser *>(m_currentRoom->user(replyPtr->senderId())), m_currentRoom, evt)}};
} }
if (role == ShowAuthorRole) { if (role == ShowAuthorRole) {
@@ -851,3 +870,13 @@ QVariant MessageEventModel::getLatestMessageFromIndex(const int baseline)
} }
return replyResponse; return replyResponse;
} }
void MessageEventModel::loadReply(const QModelIndex &index)
{
auto job = m_currentRoom->connection()->callApi<GetOneRoomEventJob>(m_currentRoom->id(), data(index, ReplyIdRole).toString());
QPersistentModelIndex persistentIndex(index);
connect(job, &BaseJob::success, this, [this, job, persistentIndex] {
m_extraEvents.push_back(fromJson<event_ptr_tt<RoomEvent>>(job->jsonData()));
Q_EMIT dataChanged(persistentIndex, persistentIndex, {ReplyRole});
});
}

View File

@@ -33,7 +33,9 @@ public:
MimeTypeRole, MimeTypeRole,
FileMimetypeIcon, FileMimetypeIcon,
IsReplyRole,
ReplyRole, ReplyRole,
ReplyIdRole,
ShowAuthorRole, ShowAuthorRole,
ShowSectionRole, ShowSectionRole,
@@ -64,6 +66,7 @@ public:
Q_INVOKABLE [[nodiscard]] int eventIDToIndex(const QString &eventID) const; Q_INVOKABLE [[nodiscard]] int eventIDToIndex(const QString &eventID) const;
Q_INVOKABLE [[nodiscard]] QVariant getLastLocalUserMessageEventId(); Q_INVOKABLE [[nodiscard]] QVariant getLastLocalUserMessageEventId();
Q_INVOKABLE [[nodiscard]] QVariant getLatestMessageFromIndex(const int baseline); Q_INVOKABLE [[nodiscard]] QVariant getLatestMessageFromIndex(const int baseline);
Q_INVOKABLE void loadReply(const QModelIndex &row);
private Q_SLOTS: private Q_SLOTS:
int refreshEvent(const QString &eventId); int refreshEvent(const QString &eventId);
@@ -88,6 +91,8 @@ private:
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {}); int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});
void moveReadMarker(const QString &toEventId); void moveReadMarker(const QString &toEventId);
std::vector<event_ptr_tt<RoomEvent>> m_extraEvents;
Q_SIGNALS: Q_SIGNALS:
void roomChanged(); void roomChanged();
void fancyEffectsReasonFound(const QString &fancyEffect); void fancyEffectsReasonFound(const QString &fancyEffect);