Create a content provider instance to get message content models from
This means that all content models will now come from the same source to remove duplication across multiple models and `chatbarcaches`. It also handily breaks the dependency on needing `MessageContentModel` for `NeochatRoom`
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
|
||||
#include "models/messagecontentmodel.h"
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -198,6 +198,8 @@ add_library(neochat STATIC
|
||||
models/commonroomsmodel.h
|
||||
models/pollanswermodel.cpp
|
||||
models/pollanswermodel.h
|
||||
contentprovider.cpp
|
||||
contentprovider.h
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/TextToSpeechWrapper.qml PROPERTIES
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <Quotient/roommember.h>
|
||||
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "contentprovider.h"
|
||||
#include "eventhandler.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "neochatroom.h"
|
||||
@@ -170,17 +171,13 @@ MessageContentModel *ChatBarCache::relationEventContentModel()
|
||||
if (m_relationId.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (m_relationContentModel != nullptr) {
|
||||
return m_relationContentModel;
|
||||
}
|
||||
|
||||
auto room = dynamic_cast<NeoChatRoom *>(parent());
|
||||
if (room == nullptr) {
|
||||
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
|
||||
return nullptr;
|
||||
}
|
||||
m_relationContentModel = new MessageContentModel(room, m_relationId, true);
|
||||
return m_relationContentModel;
|
||||
|
||||
return ContentProvider::self().contentModelForEvent(room, m_relationId);
|
||||
}
|
||||
|
||||
bool ChatBarCache::isThreaded() const
|
||||
|
||||
86
src/contentprovider.cpp
Normal file
86
src/contentprovider.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "contentprovider.h"
|
||||
|
||||
ContentProvider::ContentProvider()
|
||||
{
|
||||
}
|
||||
|
||||
ContentProvider &ContentProvider::self()
|
||||
{
|
||||
static ContentProvider instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
MessageContentModel *ContentProvider::contentModelForEvent(NeoChatRoom *room, const QString &evtOrTxnId, bool isReply)
|
||||
{
|
||||
if (!room || evtOrTxnId.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_eventContentModels.contains(evtOrTxnId)) {
|
||||
m_eventContentModels.insert(evtOrTxnId, new MessageContentModel(room, evtOrTxnId, isReply));
|
||||
}
|
||||
|
||||
return m_eventContentModels.object(evtOrTxnId);
|
||||
}
|
||||
|
||||
MessageContentModel *ContentProvider::contentModelForEvent(NeoChatRoom *room, const Quotient::RoomEvent *event, bool isReply)
|
||||
{
|
||||
if (!room) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||
if (roomMessageEvent == nullptr) {
|
||||
// If for some reason a model is there remove.
|
||||
if (m_eventContentModels.contains(event->id())) {
|
||||
m_eventContentModels.remove(event->id());
|
||||
}
|
||||
if (m_eventContentModels.contains(event->transactionId())) {
|
||||
m_eventContentModels.remove(event->transactionId());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (event->isStateEvent() || event->matrixType() == u"org.matrix.msc3672.beacon_info"_s) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto eventId = event->id();
|
||||
const auto txnId = event->transactionId();
|
||||
if (!m_eventContentModels.contains(eventId) && !m_eventContentModels.contains(txnId)) {
|
||||
m_eventContentModels.insert(eventId.isEmpty() ? txnId : eventId,
|
||||
new MessageContentModel(room, eventId.isEmpty() ? txnId : eventId, isReply, eventId.isEmpty()));
|
||||
}
|
||||
|
||||
if (!eventId.isEmpty() && m_eventContentModels.contains(eventId)) {
|
||||
return m_eventContentModels.object(eventId);
|
||||
}
|
||||
|
||||
if (!txnId.isEmpty() && m_eventContentModels.contains(txnId)) {
|
||||
if (eventId.isEmpty()) {
|
||||
return m_eventContentModels.object(txnId);
|
||||
}
|
||||
|
||||
// If we now have an event ID use that as the map key instead of transaction ID.
|
||||
auto txnModel = m_eventContentModels.take(txnId);
|
||||
m_eventContentModels.insert(eventId, txnModel);
|
||||
return m_eventContentModels.object(eventId);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ThreadModel *ContentProvider::modelForThread(NeoChatRoom *room, const QString &threadRootId)
|
||||
{
|
||||
if (!room || threadRootId.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_threadModels.contains(threadRootId)) {
|
||||
m_threadModels.insert(threadRootId, new ThreadModel(threadRootId, room));
|
||||
}
|
||||
|
||||
return m_threadModels.object(threadRootId);
|
||||
}
|
||||
67
src/contentprovider.h
Normal file
67
src/contentprovider.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCache>
|
||||
|
||||
#include "models/messagecontentmodel.h"
|
||||
#include "models/threadmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
/**
|
||||
* @class ContentProvider
|
||||
*
|
||||
* Store and retrieve models for message content.
|
||||
*/
|
||||
class ContentProvider
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get the global instance of ContentProvider.
|
||||
*/
|
||||
static ContentProvider &self();
|
||||
|
||||
/**
|
||||
* @brief Returns the content model for the given event ID.
|
||||
*
|
||||
* A model is created if one doesn't exist. Will return nullptr if evtOrTxnId
|
||||
* is empty.
|
||||
*
|
||||
* @warning If a non-empty ID is given it is assumed to be a valid Quotient::RoomMessageEvent
|
||||
* event ID. The caller must ensure that the ID is a real event. A model will be
|
||||
* returned unconditionally.
|
||||
*
|
||||
* @warning Do NOT use for pending events as this function has no way to differentiate.
|
||||
*/
|
||||
MessageContentModel *contentModelForEvent(NeoChatRoom *room, const QString &evtOrTxnId, bool isReply = false);
|
||||
|
||||
/**
|
||||
* @brief Returns the content model for the given event.
|
||||
*
|
||||
* A model is created if one doesn't exist. Will return nullptr if event is:
|
||||
* - nullptr
|
||||
* - not a Quotient::RoomMessageEvent (e.g a state event)
|
||||
*
|
||||
* @note This method is preferred to the version using just an event ID as it
|
||||
* can perform some basic checks. If a copy of the event is not available,
|
||||
* you may have to use the version that takes an event ID.
|
||||
*
|
||||
* @note This version must be used for pending events as it can differentiate.
|
||||
*/
|
||||
MessageContentModel *contentModelForEvent(NeoChatRoom *room, const Quotient::RoomEvent *event, bool isReply = false);
|
||||
|
||||
/**
|
||||
* @brief Returns the thread model for the given thread root event ID.
|
||||
*
|
||||
* A model is created if one doesn't exist. Will return nullptr if threadRootId
|
||||
* is empty.
|
||||
*/
|
||||
ThreadModel *modelForThread(NeoChatRoom *room, const QString &threadRootId);
|
||||
|
||||
private:
|
||||
ContentProvider();
|
||||
|
||||
QCache<QString, MessageContentModel> m_eventContentModels;
|
||||
QCache<QString, ThreadModel> m_threadModels;
|
||||
};
|
||||
@@ -50,6 +50,22 @@ void MessageAttached::setTimeline(QQuickItem *timeline)
|
||||
Q_EMIT timelineChanged();
|
||||
}
|
||||
|
||||
MessageContentModel *MessageAttached::contentModel() const
|
||||
{
|
||||
return m_contentModel;
|
||||
}
|
||||
|
||||
void MessageAttached::setContentModel(MessageContentModel *contentModel)
|
||||
{
|
||||
m_explicitContentModel = true;
|
||||
if (m_contentModel == contentModel) {
|
||||
return;
|
||||
}
|
||||
m_contentModel = contentModel;
|
||||
propagateMessage(this);
|
||||
Q_EMIT contentModelChanged();
|
||||
}
|
||||
|
||||
int MessageAttached::index() const
|
||||
{
|
||||
return m_index;
|
||||
@@ -126,6 +142,11 @@ void MessageAttached::propagateMessage(MessageAttached *message)
|
||||
Q_EMIT timelineChanged();
|
||||
}
|
||||
|
||||
if (!m_explicitContentModel && m_contentModel != message->contentModel()) {
|
||||
m_contentModel = message->contentModel();
|
||||
Q_EMIT contentModelChanged();
|
||||
}
|
||||
|
||||
if (m_explicitIndex || m_index != message->index()) {
|
||||
m_index = message->index();
|
||||
Q_EMIT indexChanged();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QQuickAttachedPropertyPropagator>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include "messagecontentmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
class MessageAttached : public QQuickAttachedPropertyPropagator
|
||||
@@ -26,6 +27,11 @@ class MessageAttached : public QQuickAttachedPropertyPropagator
|
||||
*/
|
||||
Q_PROPERTY(QQuickItem *timeline READ timeline WRITE setTimeline NOTIFY timelineChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief The content model for the current message.
|
||||
*/
|
||||
Q_PROPERTY(MessageContentModel *contentModel READ contentModel WRITE setContentModel NOTIFY contentModelChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief The index of the message in the timeline
|
||||
*/
|
||||
@@ -57,6 +63,9 @@ public:
|
||||
QQuickItem *timeline() const;
|
||||
void setTimeline(QQuickItem *timeline);
|
||||
|
||||
MessageContentModel *contentModel() const;
|
||||
void setContentModel(MessageContentModel *contentModel);
|
||||
|
||||
int index() const;
|
||||
void setIndex(int index);
|
||||
|
||||
@@ -72,6 +81,7 @@ public:
|
||||
Q_SIGNALS:
|
||||
void roomChanged();
|
||||
void timelineChanged();
|
||||
void contentModelChanged();
|
||||
void indexChanged();
|
||||
void maxContentWidthChanged();
|
||||
void selectedTextChanged();
|
||||
@@ -88,6 +98,9 @@ private:
|
||||
QPointer<QQuickItem> m_timeline;
|
||||
bool m_explicitTimeline = false;
|
||||
|
||||
QPointer<MessageContentModel> m_contentModel;
|
||||
bool m_explicitContentModel = false;
|
||||
|
||||
int m_index = -1;
|
||||
bool m_explicitIndex = false;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/room.h>
|
||||
|
||||
#include "messagecontentmodel.h"
|
||||
#include "messagefiltermodel.h"
|
||||
#include "timelinemessagemodel.h"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "messagecontentmodel.h"
|
||||
#include "contentprovider.h"
|
||||
#include "eventhandler.h"
|
||||
#include "messagecomponenttype.h"
|
||||
#include "neochatconfig.h"
|
||||
@@ -26,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "contentprovider.h"
|
||||
#include "filetype.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "models/reactionmodel.h"
|
||||
@@ -767,4 +769,9 @@ void MessageContentModel::updateReactionModel()
|
||||
resetContent();
|
||||
}
|
||||
|
||||
ThreadModel *MessageContentModel::modelForThread(const QString &threadRootId)
|
||||
{
|
||||
return ContentProvider::self().modelForThread(m_room, threadRootId);
|
||||
}
|
||||
|
||||
#include "moc_messagecontentmodel.cpp"
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "models/reactionmodel.h"
|
||||
#include "neochatroommember.h"
|
||||
|
||||
class ThreadModel;
|
||||
|
||||
/**
|
||||
* @class MessageContentModel
|
||||
*
|
||||
@@ -102,6 +104,14 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void closeLinkPreview(int row);
|
||||
|
||||
/**
|
||||
* @brief Returns the thread model for the given thread root event ID.
|
||||
*
|
||||
* A model is created is one doesn't exist. Will return nullptr if threadRootId
|
||||
* is empty.
|
||||
*/
|
||||
Q_INVOKABLE ThreadModel *modelForThread(const QString &threadRootId);
|
||||
|
||||
Q_SIGNALS:
|
||||
void showAuthorChanged();
|
||||
void eventUpdated();
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <QVariant>
|
||||
|
||||
#include "enums/delegatetype.h"
|
||||
#include "messagecontentmodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "timelinemessagemodel.h"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "messagemodel.h"
|
||||
|
||||
#include "neochatconfig.h"
|
||||
#include "threadmodel.h"
|
||||
|
||||
#include <Quotient/events/encryptedevent.h>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
#include <KFormat>
|
||||
|
||||
#include "contentprovider.h"
|
||||
#include "enums/delegatetype.h"
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "eventhandler.h"
|
||||
@@ -122,14 +124,14 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
||||
|
||||
if (role == ContentModelRole) {
|
||||
if (event->get().is<EncryptedEvent>() || event->get().is<PollStartEvent>()) {
|
||||
return QVariant::fromValue<MessageContentModel *>(m_room->contentModelForEvent(event->get().id()));
|
||||
return QVariant::fromValue<MessageContentModel *>(ContentProvider::self().contentModelForEvent(m_room, event->get().id()));
|
||||
}
|
||||
|
||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(&event.value().get());
|
||||
if (NeoChatConfig::self()->threads() && roomMessageEvent && roomMessageEvent->isThreaded()) {
|
||||
return QVariant::fromValue<MessageContentModel *>(m_room->contentModelForEvent(roomMessageEvent->threadRootEventId()));
|
||||
return QVariant::fromValue<MessageContentModel *>(ContentProvider::self().contentModelForEvent(m_room, roomMessageEvent->threadRootEventId()));
|
||||
}
|
||||
return QVariant::fromValue<MessageContentModel *>(m_room->contentModelForEvent(&event->get()));
|
||||
return QVariant::fromValue<MessageContentModel *>(ContentProvider::self().contentModelForEvent(m_room, &event->get()));
|
||||
}
|
||||
|
||||
if (role == GenericDisplayRole) {
|
||||
@@ -483,9 +485,4 @@ bool MessageModel::event(QEvent *event)
|
||||
return QObject::event(event);
|
||||
}
|
||||
|
||||
ThreadModel *MessageModel::threadModelForRootId(const QString &threadRootId) const
|
||||
{
|
||||
return m_room->modelForThread(threadRootId);
|
||||
}
|
||||
|
||||
#include "moc_messagemodel.cpp"
|
||||
|
||||
@@ -113,11 +113,6 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE [[nodiscard]] int eventIdToRow(const QString &eventID) const;
|
||||
|
||||
/**
|
||||
* @brief Get a ThreadModel for the give thread root Matrix ID.
|
||||
*/
|
||||
Q_INVOKABLE ThreadModel *threadModelForRootId(const QString &threadRootId) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief Emitted when the room is changed.
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "enums/delegatetype.h"
|
||||
#include "eventhandler.h"
|
||||
#include "models/messagecontentmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "models/messagecontentmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "contentprovider.h"
|
||||
#include "eventhandler.h"
|
||||
#include "messagecomponenttype.h"
|
||||
#include "messagecontentmodel.h"
|
||||
@@ -136,9 +137,9 @@ void ThreadModel::addModels()
|
||||
}
|
||||
addSourceModel(m_threadFetchModel);
|
||||
for (auto it = m_events.crbegin(); it != m_events.crend(); ++it) {
|
||||
const auto contentModel = room->contentModelForEvent(*it);
|
||||
const auto contentModel = ContentProvider::self().contentModelForEvent(room, *it);
|
||||
if (contentModel != nullptr) {
|
||||
addSourceModel(room->contentModelForEvent(*it));
|
||||
addSourceModel(ContentProvider::self().contentModelForEvent(room, *it));
|
||||
}
|
||||
}
|
||||
addSourceModel(m_threadChatBarModel);
|
||||
@@ -155,7 +156,7 @@ void ThreadModel::clearModels()
|
||||
}
|
||||
removeSourceModel(m_threadFetchModel);
|
||||
for (const auto &model : m_events) {
|
||||
const auto contentModel = room->contentModelForEvent(model);
|
||||
const auto contentModel = ContentProvider::self().contentModelForEvent(room, model);
|
||||
if (sourceModels().contains(contentModel)) {
|
||||
removeSourceModel(contentModel);
|
||||
}
|
||||
|
||||
@@ -173,8 +173,6 @@ void NeoChatRoom::setVisible(bool visible)
|
||||
|
||||
if (!visible) {
|
||||
m_memberObjects.clear();
|
||||
m_eventContentModels.clear();
|
||||
m_threadModels.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1706,77 +1704,6 @@ NeochatRoomMember *NeoChatRoom::qmlSafeMember(const QString &memberId)
|
||||
return m_memberObjects[memberId].get();
|
||||
}
|
||||
|
||||
MessageContentModel *NeoChatRoom::contentModelForEvent(const QString &eventId)
|
||||
{
|
||||
if (eventId.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_eventContentModels.contains(eventId)) {
|
||||
return m_eventContentModels.emplace(eventId, std::make_unique<MessageContentModel>(this, eventId)).first->second.get();
|
||||
}
|
||||
|
||||
return m_eventContentModels[eventId].get();
|
||||
}
|
||||
|
||||
MessageContentModel *NeoChatRoom::contentModelForEvent(const Quotient::RoomEvent *event)
|
||||
{
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||
if (roomMessageEvent == nullptr) {
|
||||
// If for some reason a model is there remove.
|
||||
if (m_eventContentModels.contains(event->id())) {
|
||||
m_eventContentModels.erase(event->id());
|
||||
}
|
||||
if (m_eventContentModels.contains(event->transactionId())) {
|
||||
m_eventContentModels.erase(event->transactionId());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (event->isStateEvent() || event->matrixType() == u"org.matrix.msc3672.beacon_info"_s) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto eventId = event->id();
|
||||
const auto txnId = event->transactionId();
|
||||
if (!m_eventContentModels.contains(eventId) && !m_eventContentModels.contains(txnId)) {
|
||||
return m_eventContentModels
|
||||
.emplace(eventId.isEmpty() ? txnId : eventId,
|
||||
std::make_unique<MessageContentModel>(this, eventId.isEmpty() ? txnId : eventId, false, eventId.isEmpty()))
|
||||
.first->second.get();
|
||||
}
|
||||
|
||||
if (!eventId.isEmpty() && m_eventContentModels.contains(eventId)) {
|
||||
return m_eventContentModels[eventId].get();
|
||||
}
|
||||
|
||||
if (!txnId.isEmpty() && m_eventContentModels.contains(txnId)) {
|
||||
if (eventId.isEmpty()) {
|
||||
return m_eventContentModels[txnId].get();
|
||||
}
|
||||
|
||||
// If we now have an event ID use that as the map key instead of transaction ID.
|
||||
auto txnModel = std::move(m_eventContentModels[txnId]);
|
||||
m_eventContentModels.erase(txnId);
|
||||
return m_eventContentModels.emplace(eventId, std::move(txnModel)).first->second.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ThreadModel *NeoChatRoom::modelForThread(const QString &threadRootId)
|
||||
{
|
||||
if (threadRootId.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_threadModels.contains(threadRootId)) {
|
||||
return m_threadModels.emplace(threadRootId, std::make_unique<ThreadModel>(threadRootId, this)).first->second.get();
|
||||
}
|
||||
|
||||
return m_threadModels[threadRootId].get();
|
||||
}
|
||||
|
||||
void NeoChatRoom::pinEvent(const QString &eventId)
|
||||
{
|
||||
auto eventIds = pinnedEventIds();
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "enums/messagetype.h"
|
||||
#include "enums/pushrule.h"
|
||||
#include "events/pollevent.h"
|
||||
#include "models/messagecontentmodel.h"
|
||||
#include "models/threadmodel.h"
|
||||
#include "neochatroommember.h"
|
||||
#include "pollhandler.h"
|
||||
|
||||
@@ -560,43 +558,6 @@ public:
|
||||
*/
|
||||
NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
||||
|
||||
/**
|
||||
* @brief Returns the content model for the given event ID.
|
||||
*
|
||||
* A model is created is one doesn't exist. Will return nullptr if evtOrTxnId
|
||||
* is empty.
|
||||
*
|
||||
* @warning If a non-empty ID is given it is assumed to be a valid Quotient::RoomMessageEvent
|
||||
* event ID. The caller must ensure that the ID is a real event. A model will be
|
||||
* returned unconditionally.
|
||||
*
|
||||
* @warning Do NOT use for pending events as this function has no way to differentiate.
|
||||
*/
|
||||
MessageContentModel *contentModelForEvent(const QString &evtOrTxnId);
|
||||
|
||||
/**
|
||||
* @brief Returns the content model for the given event.
|
||||
*
|
||||
* A model is created is one doesn't exist. Will return nullptr if event is:
|
||||
* - nullptr
|
||||
* - not a Quotient::RoomMessageEvent (e.g a state event)
|
||||
*
|
||||
* @note This method is preferred to the version using just an event ID as it
|
||||
* can perform some basic checks. If a copy of the event is not available,
|
||||
* you may have to use the version that takes an event ID.
|
||||
*
|
||||
* @note This version must be used for pending events as it can differentiate.
|
||||
*/
|
||||
MessageContentModel *contentModelForEvent(const Quotient::RoomEvent *event);
|
||||
|
||||
/**
|
||||
* @brief Returns the thread model for the given thread root event ID.
|
||||
*
|
||||
* A model is created is one doesn't exist. Will return nullptr if threadRootId
|
||||
* is empty.
|
||||
*/
|
||||
Q_INVOKABLE ThreadModel *modelForThread(const QString &threadRootId);
|
||||
|
||||
/**
|
||||
* @brief Pin a message in the room.
|
||||
* @param eventId The id of the event to pin.
|
||||
@@ -646,8 +607,6 @@ private:
|
||||
void cleanupExtraEvent(const QString &eventId);
|
||||
|
||||
std::unordered_map<QString, std::unique_ptr<NeochatRoomMember>> m_memberObjects;
|
||||
std::unordered_map<QString, std::unique_ptr<MessageContentModel>> m_eventContentModels;
|
||||
std::unordered_map<QString, std::unique_ptr<ThreadModel>> m_threadModels;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updatePushNotificationState(QString type);
|
||||
|
||||
@@ -190,6 +190,7 @@ TimelineDelegate {
|
||||
|
||||
Message.room: root.room
|
||||
Message.timeline: root.ListView.view
|
||||
Message.contentModel: root.contentModel
|
||||
Message.index: root.index
|
||||
Message.maxContentWidth: contentMaxWidth
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ ColumnLayout {
|
||||
|
||||
Repeater {
|
||||
id: threadRepeater
|
||||
model: root.Message.room.modelForThread(root.threadRoot);
|
||||
model: root.Message.contentModel.modelForThread(root.threadRoot);
|
||||
|
||||
delegate: BaseMessageComponentChooser {
|
||||
onSelectedTextChanged: selectedText => {
|
||||
|
||||
Reference in New Issue
Block a user