Move the storage of MessageContentModels to the room
Move the storage of MessageContentModels to the room in the same manner as memeber objects to prevent duplication but mainly to make the system easier to maintain going forward with things like threads for example. This requires the creation of a MessageContentFilterModel as the same model may be used in multiple places, sometimes with the author showning sometimes not.
This commit is contained in:
@@ -192,6 +192,8 @@ add_library(neochat STATIC
|
|||||||
models/roomsortparametermodel.h
|
models/roomsortparametermodel.h
|
||||||
models/messagemodel.cpp
|
models/messagemodel.cpp
|
||||||
models/messagemodel.h
|
models/messagemodel.h
|
||||||
|
models/messagecontentfiltermodel.cpp
|
||||||
|
models/messagecontentfiltermodel.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
|
|||||||
@@ -39,14 +39,6 @@ QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
|
|||||||
const auto previousEventDay = mapToSource(this->index(index.row() + 1, 0)).data(TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date();
|
const auto previousEventDay = mapToSource(this->index(index.row() + 1, 0)).data(TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date();
|
||||||
return day != previousEventDay;
|
return day != previousEventDay;
|
||||||
}
|
}
|
||||||
// Catch and force the author to be shown for all rows
|
|
||||||
if (role == TimelineMessageModel::ContentModelRole) {
|
|
||||||
const auto model = qvariant_cast<MessageContentModel *>(mapToSource(index).data(TimelineMessageModel::ContentModelRole));
|
|
||||||
if (model != nullptr) {
|
|
||||||
model->setShowAuthor(true);
|
|
||||||
}
|
|
||||||
return QVariant::fromValue<MessageContentModel *>(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap mediaInfo = mapToSource(index).data(TimelineMessageModel::MediaInfoRole).toMap();
|
QVariantMap mediaInfo = mapToSource(index).data(TimelineMessageModel::MediaInfoRole).toMap();
|
||||||
|
|
||||||
|
|||||||
37
src/models/messagecontentfiltermodel.cpp
Normal file
37
src/models/messagecontentfiltermodel.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 "messagecontentfiltermodel.h"
|
||||||
|
#include "enums/messagecomponenttype.h"
|
||||||
|
#include "models/messagecontentmodel.h"
|
||||||
|
|
||||||
|
MessageContentFilterModel::MessageContentFilterModel(QObject *parent)
|
||||||
|
: QSortFilterProxyModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageContentFilterModel::showAuthor() const
|
||||||
|
{
|
||||||
|
return m_showAuthor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageContentFilterModel::setShowAuthor(bool showAuthor)
|
||||||
|
{
|
||||||
|
if (showAuthor == m_showAuthor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_showAuthor = showAuthor;
|
||||||
|
Q_EMIT showAuthorChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageContentFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||||
|
{
|
||||||
|
if (m_showAuthor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = sourceModel()->index(source_row, 0, source_parent);
|
||||||
|
auto contentType = static_cast<MessageComponentType::Type>(index.data(MessageContentModel::ComponentTypeRole).toInt());
|
||||||
|
return contentType != MessageComponentType::Author;
|
||||||
|
}
|
||||||
43
src/models/messagecontentfiltermodel.h
Normal file
43
src/models/messagecontentfiltermodel.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// 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 <QQmlEngine>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class MessageContentFilterModel
|
||||||
|
*
|
||||||
|
* This model filters a message's contents.
|
||||||
|
*/
|
||||||
|
class MessageContentFilterModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the author component should be shown.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(bool showAuthor READ showAuthor WRITE setShowAuthor NOTIFY showAuthorChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MessageContentFilterModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
bool showAuthor() const;
|
||||||
|
void setShowAuthor(bool showAuthor);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void showAuthorChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Whether a row should be shown out or not.
|
||||||
|
*
|
||||||
|
* @sa QSortFilterProxyModel::filterAcceptsRow
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_showAuthor = true;
|
||||||
|
};
|
||||||
@@ -233,32 +233,6 @@ NeochatRoomMember *MessageContentModel::senderObject() const
|
|||||||
return m_room->qmlSafeMember(eventResult.first->senderId());
|
return m_room->qmlSafeMember(eventResult.first->senderId());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageContentModel::showAuthor() const
|
|
||||||
{
|
|
||||||
return m_showAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageContentModel::setShowAuthor(bool showAuthor)
|
|
||||||
{
|
|
||||||
if (showAuthor == m_showAuthor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_showAuthor = showAuthor;
|
|
||||||
|
|
||||||
if (m_room->connection()->isIgnored(senderId())) {
|
|
||||||
if (showAuthor) {
|
|
||||||
beginInsertRows({}, 0, 0);
|
|
||||||
m_components.prepend(MessageComponent{MessageComponentType::Author, QString(), {}});
|
|
||||||
endInsertRows();
|
|
||||||
} else {
|
|
||||||
beginRemoveRows({}, 0, 0);
|
|
||||||
m_components.remove(0, 1);
|
|
||||||
endRemoveRows();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Q_EMIT showAuthorChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
static LinkPreviewer *emptyLinkPreview = new LinkPreviewer;
|
static LinkPreviewer *emptyLinkPreview = new LinkPreviewer;
|
||||||
|
|
||||||
QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||||
@@ -434,9 +408,7 @@ void MessageContentModel::resetModel()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_showAuthor) {
|
m_components += MessageComponent{MessageComponentType::Author, QString(), {}};
|
||||||
m_components += MessageComponent{MessageComponentType::Author, QString(), {}};
|
|
||||||
}
|
|
||||||
|
|
||||||
m_components += messageContentComponents();
|
m_components += messageContentComponents();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|||||||
@@ -25,11 +25,6 @@ class MessageContentModel : public QAbstractListModel
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_UNCREATABLE("")
|
QML_UNCREATABLE("")
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Whether the author component is being shown.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool showAuthor READ showAuthor WRITE setShowAuthor NOTIFY showAuthorChanged)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum MessageState {
|
enum MessageState {
|
||||||
Unknown, /**< The message state is unknown. */
|
Unknown, /**< The message state is unknown. */
|
||||||
@@ -75,9 +70,6 @@ public:
|
|||||||
bool isPending = false,
|
bool isPending = false,
|
||||||
MessageContentModel *parent = nullptr);
|
MessageContentModel *parent = nullptr);
|
||||||
|
|
||||||
bool showAuthor() const;
|
|
||||||
void setShowAuthor(bool showAuthor);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the given role value at the given index.
|
* @brief Get the given role value at the given index.
|
||||||
*
|
*
|
||||||
@@ -117,7 +109,6 @@ private:
|
|||||||
NeochatRoomMember *senderObject() const;
|
NeochatRoomMember *senderObject() const;
|
||||||
|
|
||||||
MessageState m_currentState = Unknown;
|
MessageState m_currentState = Unknown;
|
||||||
bool m_showAuthor = true;
|
|
||||||
bool m_isReply;
|
bool m_isReply;
|
||||||
|
|
||||||
void initializeModel();
|
void initializeModel();
|
||||||
|
|||||||
@@ -92,12 +92,8 @@ QVariant MessageFilterModel::data(const QModelIndex &index, int role) const
|
|||||||
return authorList(mapToSource(index).row());
|
return authorList(mapToSource(index).row());
|
||||||
} else if (role == ExcessAuthorsRole) {
|
} else if (role == ExcessAuthorsRole) {
|
||||||
return excessAuthors(mapToSource(index).row());
|
return excessAuthors(mapToSource(index).row());
|
||||||
} else if (role == TimelineMessageModel::ContentModelRole) {
|
} else if (role == ShowAuthorRole) {
|
||||||
const auto model = qvariant_cast<MessageContentModel *>(mapToSource(index).data(TimelineMessageModel::ContentModelRole));
|
return showAuthor(index);
|
||||||
if (model != nullptr && !showAuthor(index)) {
|
|
||||||
model->setShowAuthor(false);
|
|
||||||
}
|
|
||||||
return QVariant::fromValue<MessageContentModel *>(model);
|
|
||||||
}
|
}
|
||||||
return QSortFilterProxyModel::data(index, role);
|
return QSortFilterProxyModel::data(index, role);
|
||||||
}
|
}
|
||||||
@@ -109,6 +105,7 @@ QHash<int, QByteArray> MessageFilterModel::roleNames() const
|
|||||||
roles[StateEventsRole] = "stateEvents";
|
roles[StateEventsRole] = "stateEvents";
|
||||||
roles[AuthorListRole] = "authorList";
|
roles[AuthorListRole] = "authorList";
|
||||||
roles[ExcessAuthorsRole] = "excessAuthors";
|
roles[ExcessAuthorsRole] = "excessAuthors";
|
||||||
|
roles[ShowAuthorRole] = "showAuthor";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public:
|
|||||||
StateEventsRole, /**< List of state events in the aggregated state. */
|
StateEventsRole, /**< List of state events in the aggregated state. */
|
||||||
AuthorListRole, /**< List of the first 5 unique authors of the aggregated state event. */
|
AuthorListRole, /**< List of the first 5 unique authors of the aggregated state event. */
|
||||||
ExcessAuthorsRole, /**< The number of unique authors beyond the first 5. */
|
ExcessAuthorsRole, /**< The number of unique authors beyond the first 5. */
|
||||||
|
ShowAuthorRole, /**< Whether the author of a message should be shown. */
|
||||||
LastRole, // Keep this last
|
LastRole, // Keep this last
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -120,16 +120,11 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (role == ContentModelRole) {
|
if (role == ContentModelRole) {
|
||||||
QString modelId;
|
auto evtOrTxnId = event->get().id();
|
||||||
if (!event->get().id().isEmpty() && m_contentModels.contains(event->get().id())) {
|
if (evtOrTxnId.isEmpty()) {
|
||||||
modelId = event.value().get().id();
|
evtOrTxnId = event->get().transactionId();
|
||||||
} else if (!event.value().get().transactionId().isEmpty() && m_contentModels.contains(event.value().get().transactionId())) {
|
|
||||||
modelId = event.value().get().transactionId();
|
|
||||||
}
|
}
|
||||||
if (!modelId.isEmpty()) {
|
return QVariant::fromValue<MessageContentModel *>(m_room->contentModelForEvent(evtOrTxnId));
|
||||||
return QVariant::fromValue<MessageContentModel *>(m_contentModels.at(modelId).get());
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == GenericDisplayRole) {
|
if (role == GenericDisplayRole) {
|
||||||
@@ -430,12 +425,6 @@ void MessageModel::createEventObjects(const Quotient::RoomEvent *event, bool isP
|
|||||||
senderId = m_room->localMember().id();
|
senderId = m_room->localMember().id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_contentModels.contains(eventId) && !m_contentModels.contains(event->transactionId())) {
|
|
||||||
if (!event->isStateEvent() || event->matrixType() == u"org.matrix.msc3672.beacon_info"_s) {
|
|
||||||
m_contentModels[eventId] = std::unique_ptr<MessageContentModel>(new MessageContentModel(m_room, eventId, false, isPending));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||||
if (roomMessageEvent && roomMessageEvent->isThreaded() && !m_threadModels.contains(roomMessageEvent->threadRootEventId())) {
|
if (roomMessageEvent && roomMessageEvent->isThreaded() && !m_threadModels.contains(roomMessageEvent->threadRootEventId())) {
|
||||||
m_threadModels[roomMessageEvent->threadRootEventId()] = QSharedPointer<ThreadModel>(new ThreadModel(roomMessageEvent->threadRootEventId(), m_room));
|
m_threadModels[roomMessageEvent->threadRootEventId()] = QSharedPointer<ThreadModel>(new ThreadModel(roomMessageEvent->threadRootEventId(), m_room));
|
||||||
@@ -515,7 +504,6 @@ void MessageModel::clearModel()
|
|||||||
|
|
||||||
void MessageModel::clearEventObjects()
|
void MessageModel::clearEventObjects()
|
||||||
{
|
{
|
||||||
m_contentModels.clear();
|
|
||||||
m_reactionModels.clear();
|
m_reactionModels.clear();
|
||||||
m_readMarkerModels.clear();
|
m_readMarkerModels.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "messagecontentmodel.h"
|
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "pollhandler.h"
|
#include "pollhandler.h"
|
||||||
#include "readmarkermodel.h"
|
#include "readmarkermodel.h"
|
||||||
@@ -153,7 +152,6 @@ private:
|
|||||||
bool resetting = false;
|
bool resetting = false;
|
||||||
bool movingEvent = false;
|
bool movingEvent = false;
|
||||||
|
|
||||||
std::map<QString, std::unique_ptr<MessageContentModel>> m_contentModels;
|
|
||||||
QMap<QString, QSharedPointer<ReadMarkerModel>> m_readMarkerModels;
|
QMap<QString, QSharedPointer<ReadMarkerModel>> m_readMarkerModels;
|
||||||
QMap<QString, QSharedPointer<ThreadModel>> m_threadModels;
|
QMap<QString, QSharedPointer<ThreadModel>> m_threadModels;
|
||||||
QMap<QString, QSharedPointer<ReactionModel>> m_reactionModels;
|
QMap<QString, QSharedPointer<ReactionModel>> m_reactionModels;
|
||||||
|
|||||||
@@ -97,10 +97,9 @@ void ThreadModel::fetchMore(const QModelIndex &parent)
|
|||||||
const auto connection = room->connection();
|
const auto connection = room->connection();
|
||||||
m_currentJob = connection->callApi<Quotient::GetRelatingEventsWithRelTypeJob>(room->id(), m_threadRootId, u"m.thread"_s, *m_nextBatch, QString(), 5);
|
m_currentJob = connection->callApi<Quotient::GetRelatingEventsWithRelTypeJob>(room->id(), m_threadRootId, u"m.thread"_s, *m_nextBatch, QString(), 5);
|
||||||
connect(m_currentJob, &Quotient::BaseJob::success, this, [this]() {
|
connect(m_currentJob, &Quotient::BaseJob::success, this, [this]() {
|
||||||
const auto room = dynamic_cast<NeoChatRoom *>(QObject::parent());
|
|
||||||
auto newEvents = m_currentJob->chunk();
|
auto newEvents = m_currentJob->chunk();
|
||||||
for (auto &event : newEvents) {
|
for (auto &event : newEvents) {
|
||||||
m_contentModels.push_back(new MessageContentModel(room, event->id()));
|
m_events.push_back(event->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
addModels();
|
addModels();
|
||||||
@@ -122,12 +121,11 @@ void ThreadModel::fetchMore(const QModelIndex &parent)
|
|||||||
|
|
||||||
void ThreadModel::addNewEvent(const Quotient::RoomEvent *event)
|
void ThreadModel::addNewEvent(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
const auto room = dynamic_cast<NeoChatRoom *>(QObject::parent());
|
|
||||||
auto eventId = event->id();
|
auto eventId = event->id();
|
||||||
if (eventId.isEmpty()) {
|
if (eventId.isEmpty()) {
|
||||||
eventId = event->transactionId();
|
eventId = event->transactionId();
|
||||||
}
|
}
|
||||||
m_contentModels.push_front(new MessageContentModel(room, eventId));
|
m_events.push_front(eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadModel::addModels()
|
void ThreadModel::addModels()
|
||||||
@@ -137,8 +135,15 @@ void ThreadModel::addModels()
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSourceModel(m_threadRootContentModel.get());
|
addSourceModel(m_threadRootContentModel.get());
|
||||||
for (auto it = m_contentModels.crbegin(); it != m_contentModels.crend(); ++it) {
|
const auto room = dynamic_cast<NeoChatRoom *>(QObject::parent());
|
||||||
addSourceModel(*it);
|
if (room == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto it = m_events.crbegin(); it != m_events.crend(); ++it) {
|
||||||
|
const auto contentModel = room->contentModelForEvent(*it);
|
||||||
|
if (contentModel != nullptr) {
|
||||||
|
addSourceModel(room->contentModelForEvent(*it));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addSourceModel(m_threadChatBarModel);
|
addSourceModel(m_threadChatBarModel);
|
||||||
|
|
||||||
@@ -149,9 +154,15 @@ void ThreadModel::addModels()
|
|||||||
void ThreadModel::clearModels()
|
void ThreadModel::clearModels()
|
||||||
{
|
{
|
||||||
removeSourceModel(m_threadRootContentModel.get());
|
removeSourceModel(m_threadRootContentModel.get());
|
||||||
for (const auto &model : m_contentModels) {
|
|
||||||
if (sourceModels().contains(model)) {
|
const auto room = dynamic_cast<NeoChatRoom *>(QObject::parent());
|
||||||
removeSourceModel(model);
|
if (room == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto &model : m_events) {
|
||||||
|
const auto contentModel = room->contentModelForEvent(model);
|
||||||
|
if (sourceModels().contains(contentModel)) {
|
||||||
|
removeSourceModel(contentModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeSourceModel(m_threadChatBarModel);
|
removeSourceModel(m_threadChatBarModel);
|
||||||
|
|||||||
@@ -122,14 +122,9 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<MessageContentModel> m_threadRootContentModel;
|
std::unique_ptr<MessageContentModel> m_threadRootContentModel;
|
||||||
|
|
||||||
std::deque<MessageContentModel *> m_contentModels;
|
std::deque<QString> m_events;
|
||||||
ThreadChatBarModel *m_threadChatBarModel;
|
ThreadChatBarModel *m_threadChatBarModel;
|
||||||
|
|
||||||
QList<QString> m_events;
|
|
||||||
QList<QString> m_pendingEvents;
|
|
||||||
|
|
||||||
std::unordered_map<QString, std::unique_ptr<Quotient::RoomEvent>> m_unloadedEvents;
|
|
||||||
|
|
||||||
QMap<QString, QSharedPointer<ReactionModel>> m_reactionModels;
|
QMap<QString, QSharedPointer<ReactionModel>> m_reactionModels;
|
||||||
|
|
||||||
QPointer<Quotient::GetRelatingEventsWithRelTypeJob> m_currentJob = nullptr;
|
QPointer<Quotient::GetRelatingEventsWithRelTypeJob> m_currentJob = nullptr;
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ void NeoChatRoom::setVisible(bool visible)
|
|||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
m_memberObjects.clear();
|
m_memberObjects.clear();
|
||||||
|
m_eventContentModels.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1754,4 +1755,46 @@ NeochatRoomMember *NeoChatRoom::qmlSafeMember(const QString &memberId)
|
|||||||
return m_memberObjects[memberId].get();
|
return m_memberObjects[memberId].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageContentModel *NeoChatRoom::contentModelForEvent(const QString &evtOrTxnId)
|
||||||
|
{
|
||||||
|
const auto event = getEvent(evtOrTxnId);
|
||||||
|
if (event.first == nullptr) {
|
||||||
|
// If for some reason a model is there remove.
|
||||||
|
if (m_eventContentModels.contains(evtOrTxnId)) {
|
||||||
|
m_eventContentModels.erase(evtOrTxnId);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.first->isStateEvent() || event.first->matrixType() == u"org.matrix.msc3672.beacon_info"_s) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eventId = event.first->id();
|
||||||
|
const auto txnId = event.first->transactionId();
|
||||||
|
if (!m_eventContentModels.contains(eventId) && !m_eventContentModels.contains(txnId)) {
|
||||||
|
if (eventId.isEmpty()) {
|
||||||
|
eventId = txnId;
|
||||||
|
}
|
||||||
|
return m_eventContentModels.emplace(eventId, std::make_unique<MessageContentModel>(this, eventId, false, event.second)).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;
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_neochatroom.cpp"
|
#include "moc_neochatroom.cpp"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "enums/messagetype.h"
|
#include "enums/messagetype.h"
|
||||||
#include "enums/pushrule.h"
|
#include "enums/pushrule.h"
|
||||||
|
#include "models/messagecontentmodel.h"
|
||||||
#include "neochatroommember.h"
|
#include "neochatroommember.h"
|
||||||
#include "pollhandler.h"
|
#include "pollhandler.h"
|
||||||
|
|
||||||
@@ -595,6 +596,8 @@ public:
|
|||||||
|
|
||||||
NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
||||||
|
|
||||||
|
MessageContentModel *contentModelForEvent(const QString &evtOrTxnId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_visible = false;
|
bool m_visible = false;
|
||||||
|
|
||||||
@@ -627,6 +630,7 @@ private:
|
|||||||
void cleanupExtraEvent(const QString &eventId);
|
void cleanupExtraEvent(const QString &eventId);
|
||||||
|
|
||||||
std::unordered_map<QString, std::unique_ptr<NeochatRoomMember>> m_memberObjects;
|
std::unordered_map<QString, std::unique_ptr<NeochatRoomMember>> m_memberObjects;
|
||||||
|
std::unordered_map<QString, std::unique_ptr<MessageContentModel>> m_eventContentModels;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void updatePushNotificationState(QString type);
|
void updatePushNotificationState(QString type);
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ QQC2.Control {
|
|||||||
*/
|
*/
|
||||||
property var author
|
property var author
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the message author should be shown.
|
||||||
|
*/
|
||||||
|
required property bool showAuthor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the message should be highlighted.
|
* @brief Whether the message should be highlighted.
|
||||||
*/
|
*/
|
||||||
@@ -105,7 +110,10 @@ QQC2.Control {
|
|||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
Repeater {
|
Repeater {
|
||||||
id: contentRepeater
|
id: contentRepeater
|
||||||
model: root.contentModel
|
model: MessageContentFilterModel {
|
||||||
|
showAuthor: root.showAuthor
|
||||||
|
sourceModel: root.contentModel
|
||||||
|
}
|
||||||
delegate: MessageComponentChooser {
|
delegate: MessageComponentChooser {
|
||||||
room: root.room
|
room: root.room
|
||||||
index: root.index
|
index: root.index
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ TimelineDelegate {
|
|||||||
*/
|
*/
|
||||||
required property NeochatRoomMember author
|
required property NeochatRoomMember author
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the message author should be shown.
|
||||||
|
*/
|
||||||
|
required property bool showAuthor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The model to visualise the content of the message.
|
* @brief The model to visualise the content of the message.
|
||||||
*/
|
*/
|
||||||
@@ -222,11 +227,11 @@ TimelineDelegate {
|
|||||||
id: mainContainer
|
id: mainContainer
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: root.contentModel?.showAuthor ? Kirigami.Units.largeSpacing : (NeoChatConfig.compactLayout ? 1 : Kirigami.Units.smallSpacing)
|
Layout.topMargin: root.showAuthor ? Kirigami.Units.largeSpacing : (NeoChatConfig.compactLayout ? 1 : Kirigami.Units.smallSpacing)
|
||||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
implicitHeight: Math.max(root.contentModel?.showAuthor ? avatar.implicitHeight : 0, bubble.height)
|
implicitHeight: Math.max(root.showAuthor ? avatar.implicitHeight : 0, bubble.height)
|
||||||
|
|
||||||
// show hover actions
|
// show hover actions
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
@@ -246,7 +251,7 @@ TimelineDelegate {
|
|||||||
topMargin: Kirigami.Units.smallSpacing
|
topMargin: Kirigami.Units.smallSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: ((root.contentModel?.showAuthor ?? false) || root.isThreaded) && NeoChatConfig.showAvatarInTimeline && (NeoChatConfig.compactLayout || !_private.showUserMessageOnRight)
|
visible: ((root.showAuthor ?? false) || root.isThreaded) && NeoChatConfig.showAvatarInTimeline && (NeoChatConfig.compactLayout || !_private.showUserMessageOnRight)
|
||||||
name: root.author.displayName
|
name: root.author.displayName
|
||||||
source: root.author.avatarUrl
|
source: root.author.avatarUrl
|
||||||
color: root.author.color
|
color: root.author.color
|
||||||
@@ -292,6 +297,7 @@ TimelineDelegate {
|
|||||||
room: root.room
|
room: root.room
|
||||||
index: root.index
|
index: root.index
|
||||||
author: root.author
|
author: root.author
|
||||||
|
showAuthor: root.showAuthor
|
||||||
isThreaded: root.isThreaded
|
isThreaded: root.isThreaded
|
||||||
|
|
||||||
// HACK: This is stupid but seemingly QConcatenateTablesProxyModel
|
// HACK: This is stupid but seemingly QConcatenateTablesProxyModel
|
||||||
|
|||||||
Reference in New Issue
Block a user