Refactor threads
The focus here is to make threads use the standard message content system rather than having a special implementation. To achieve this the threadroot content model will now get a thread body component which will visualise the thread model with all the other messages. The latest message in the thread will then just ask for the thread root content model and show that. Note: in order to stop a cyclical dependency with MessageComponentChooser and new base version has been added which is just missing ThreadBodyComponent and and the main version is now inherited from that with ThreadBodyComponent added.
This commit is contained in:
@@ -340,6 +340,17 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
if (role == ReplyContentModelRole) {
|
||||
return QVariant::fromValue<MessageContentModel *>(m_replyModel);
|
||||
}
|
||||
if (role == ThreadRootRole) {
|
||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event.first);
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 1)
|
||||
if (roomMessageEvent && (roomMessageEvent->isThreaded() || m_room->threads().contains(roomMessageEvent->id()))) {
|
||||
#else
|
||||
if (roomMessageEvent && roomMessageEvent->isThreaded()) {
|
||||
#endif
|
||||
return roomMessageEvent->threadRootEventId();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
if (role == LinkPreviewerRole) {
|
||||
if (component.type == MessageComponentType::LinkPreview) {
|
||||
return QVariant::fromValue<LinkPreviewer *>(
|
||||
@@ -366,27 +377,32 @@ int MessageContentModel::rowCount(const QModelIndex &parent) const
|
||||
|
||||
QHash<int, QByteArray> MessageContentModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[DisplayRole] = "display";
|
||||
roles[ComponentTypeRole] = "componentType";
|
||||
roles[ComponentAttributesRole] = "componentAttributes";
|
||||
roles[EventIdRole] = "eventId";
|
||||
roles[TimeRole] = "time";
|
||||
roles[TimeStringRole] = "timeString";
|
||||
roles[AuthorRole] = "author";
|
||||
roles[MediaInfoRole] = "mediaInfo";
|
||||
roles[FileTransferInfoRole] = "fileTransferInfo";
|
||||
roles[ItineraryModelRole] = "itineraryModel";
|
||||
roles[LatitudeRole] = "latitude";
|
||||
roles[LongitudeRole] = "longitude";
|
||||
roles[AssetRole] = "asset";
|
||||
roles[PollHandlerRole] = "pollHandler";
|
||||
roles[ReplyEventIdRole] = "replyEventId";
|
||||
roles[ReplyAuthorRole] = "replyAuthor";
|
||||
roles[ReplyContentModelRole] = "replyContentModel";
|
||||
roles[ThreadRootRole] = "threadRoot";
|
||||
roles[LinkPreviewerRole] = "linkPreviewer";
|
||||
roles[ChatBarCacheRole] = "chatBarCache";
|
||||
return roleNamesStatic();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> MessageContentModel::roleNamesStatic()
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[MessageContentModel::DisplayRole] = "display";
|
||||
roles[MessageContentModel::ComponentTypeRole] = "componentType";
|
||||
roles[MessageContentModel::ComponentAttributesRole] = "componentAttributes";
|
||||
roles[MessageContentModel::EventIdRole] = "eventId";
|
||||
roles[MessageContentModel::TimeRole] = "time";
|
||||
roles[MessageContentModel::TimeStringRole] = "timeString";
|
||||
roles[MessageContentModel::AuthorRole] = "author";
|
||||
roles[MessageContentModel::MediaInfoRole] = "mediaInfo";
|
||||
roles[MessageContentModel::FileTransferInfoRole] = "fileTransferInfo";
|
||||
roles[MessageContentModel::ItineraryModelRole] = "itineraryModel";
|
||||
roles[MessageContentModel::LatitudeRole] = "latitude";
|
||||
roles[MessageContentModel::LongitudeRole] = "longitude";
|
||||
roles[MessageContentModel::AssetRole] = "asset";
|
||||
roles[MessageContentModel::PollHandlerRole] = "pollHandler";
|
||||
roles[MessageContentModel::ReplyEventIdRole] = "replyEventId";
|
||||
roles[MessageContentModel::ReplyAuthorRole] = "replyAuthor";
|
||||
roles[MessageContentModel::ReplyContentModelRole] = "replyContentModel";
|
||||
roles[MessageContentModel::ThreadRootRole] = "threadRoot";
|
||||
roles[MessageContentModel::LinkPreviewerRole] = "linkPreviewer";
|
||||
roles[MessageContentModel::ChatBarCacheRole] = "chatBarCache";
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -464,6 +480,15 @@ QList<MessageComponent> MessageContentModel::messageContentComponents(bool isEdi
|
||||
newComponents = addLinkPreviews(newComponents);
|
||||
}
|
||||
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 1)
|
||||
if (roomMessageEvent && (roomMessageEvent->isThreaded() || m_room->threads().contains(roomMessageEvent->id()))
|
||||
&& roomMessageEvent->id() == roomMessageEvent->threadRootEventId()) {
|
||||
#else
|
||||
if (isThreading && roomMessageEvent && roomMessageEvent->isThreaded() && roomMessageEvent->id() == roomMessageEvent->threadRootEventId()) {
|
||||
#endif
|
||||
newComponents += MessageComponent{MessageComponentType::ThreadBody, u"Thread Body"_s, {}};
|
||||
}
|
||||
|
||||
// If the event is already threaded the ThreadModel will handle displaying a chat bar.
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 1)
|
||||
if (isThreading && roomMessageEvent && !(roomMessageEvent->isThreaded() || m_room->threads().contains(roomMessageEvent->id()))) {
|
||||
|
||||
@@ -91,6 +91,8 @@ public:
|
||||
*/
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
static QHash<int, QByteArray> roleNamesStatic();
|
||||
|
||||
/**
|
||||
* @brief Close the link preview at the given index.
|
||||
*
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
#if Quotient_VERSION_MINOR > 9
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 1)
|
||||
#include <Quotient/thread.h>
|
||||
#endif
|
||||
|
||||
@@ -120,6 +120,10 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
||||
}
|
||||
|
||||
if (role == ContentModelRole) {
|
||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(&event.value().get());
|
||||
if (roomMessageEvent && roomMessageEvent->isThreaded()) {
|
||||
return QVariant::fromValue<MessageContentModel *>(m_room->contentModelForEvent(roomMessageEvent->threadRootEventId()));
|
||||
}
|
||||
return QVariant::fromValue<MessageContentModel *>(m_room->contentModelForEvent(&event->get()));
|
||||
}
|
||||
|
||||
@@ -169,7 +173,7 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
||||
}
|
||||
|
||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(&event.value().get());
|
||||
#if Quotient_VERSION_MINOR > 9
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 1)
|
||||
if (roomMessageEvent && (roomMessageEvent->isThreaded() || m_room->threads().contains(event.value().get().id()))) {
|
||||
const auto &thread = m_room->threads().value(roomMessageEvent->isThreaded() ? roomMessageEvent->threadRootEventId() : event.value().get().id());
|
||||
if (thread.latestEventId != event.value().get().id()) {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "chatbarcache.h"
|
||||
#include "eventhandler.h"
|
||||
#include "messagecomponenttype.h"
|
||||
#include "messagecontentmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
ThreadModel::ThreadModel(const QString &threadRootId, NeoChatRoom *room)
|
||||
@@ -21,8 +22,6 @@ ThreadModel::ThreadModel(const QString &threadRootId, NeoChatRoom *room)
|
||||
Q_ASSERT(!m_threadRootId.isEmpty());
|
||||
Q_ASSERT(room);
|
||||
|
||||
m_threadRootContentModel = std::unique_ptr<MessageContentModel>(new MessageContentModel(room, threadRootId));
|
||||
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 0)
|
||||
connect(room, &Quotient::Room::pendingEventAdded, this, [this](const Quotient::RoomEvent *event) {
|
||||
#else
|
||||
@@ -73,14 +72,9 @@ QString ThreadModel::threadRootId() const
|
||||
return m_threadRootId;
|
||||
}
|
||||
|
||||
MessageContentModel *ThreadModel::threadRootContentModel() const
|
||||
{
|
||||
return m_threadRootContentModel.get();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ThreadModel::roleNames() const
|
||||
{
|
||||
return m_threadRootContentModel->roleNames();
|
||||
return MessageContentModel::roleNamesStatic();
|
||||
}
|
||||
|
||||
bool ThreadModel::canFetchMore(const QModelIndex &parent) const
|
||||
@@ -134,7 +128,6 @@ void ThreadModel::addModels()
|
||||
clearModels();
|
||||
}
|
||||
|
||||
addSourceModel(m_threadRootContentModel.get());
|
||||
const auto room = dynamic_cast<NeoChatRoom *>(QObject::parent());
|
||||
if (room == nullptr) {
|
||||
return;
|
||||
@@ -153,8 +146,6 @@ void ThreadModel::addModels()
|
||||
|
||||
void ThreadModel::clearModels()
|
||||
{
|
||||
removeSourceModel(m_threadRootContentModel.get());
|
||||
|
||||
const auto room = dynamic_cast<NeoChatRoom *>(QObject::parent());
|
||||
if (room == nullptr) {
|
||||
return;
|
||||
@@ -168,6 +159,35 @@ void ThreadModel::clearModels()
|
||||
removeSourceModel(m_threadChatBarModel);
|
||||
}
|
||||
|
||||
void ThreadModel::closeLinkPreview(int row)
|
||||
{
|
||||
if (row < 0 || row >= rowCount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto index = this->index(row, 0);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sourceIndex = mapToSource(index);
|
||||
const auto sourceModel = sourceIndex.model();
|
||||
if (sourceModel == nullptr) {
|
||||
return;
|
||||
}
|
||||
// This is a bit silly but we can only get a const reference to the model from the
|
||||
// index so we need to search the source models.
|
||||
for (const auto &model : sourceModels()) {
|
||||
if (model == sourceModel) {
|
||||
const auto sourceContentModel = dynamic_cast<MessageContentModel *>(model);
|
||||
if (sourceContentModel == nullptr) {
|
||||
return;
|
||||
}
|
||||
sourceContentModel->closeLinkPreview(sourceIndex.row());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadChatBarModel::ThreadChatBarModel(QObject *parent, NeoChatRoom *room)
|
||||
: QAbstractListModel(parent)
|
||||
, m_room(room)
|
||||
|
||||
@@ -91,11 +91,6 @@ public:
|
||||
|
||||
QString threadRootId() const;
|
||||
|
||||
/**
|
||||
* @brief The content model for the thread root event.
|
||||
*/
|
||||
MessageContentModel *threadRootContentModel() const;
|
||||
|
||||
/**
|
||||
* @brief Returns a mapping from Role enum values to role names.
|
||||
*
|
||||
@@ -117,10 +112,16 @@ public:
|
||||
*/
|
||||
void fetchMore(const QModelIndex &parent) override;
|
||||
|
||||
/**
|
||||
* @brief Close the link preview at the given index.
|
||||
*
|
||||
* If the given index is not a link preview component, nothing happens.
|
||||
*/
|
||||
Q_INVOKABLE void closeLinkPreview(int row);
|
||||
|
||||
private:
|
||||
QString m_threadRootId;
|
||||
|
||||
std::unique_ptr<MessageContentModel> m_threadRootContentModel;
|
||||
QPointer<MessageContentModel> m_threadRootContentModel;
|
||||
|
||||
std::deque<QString> m_events;
|
||||
ThreadChatBarModel *m_threadChatBarModel;
|
||||
|
||||
Reference in New Issue
Block a user