Refine MessageContentModel further

Create some standard functions that should hopefully make it easier to manage the model contents. Used for file stuff for now.
This commit is contained in:
James Graham
2025-07-06 21:16:17 +01:00
parent 4f5e096e7e
commit 17fa2246da
2 changed files with 69 additions and 29 deletions

View File

@@ -57,7 +57,6 @@ void MessageContentModel::initializeModel()
connect(m_room, &NeoChatRoom::pendingEventAdded, this, [this]() { connect(m_room, &NeoChatRoom::pendingEventAdded, this, [this]() {
if (m_room != nullptr && m_currentState == Unknown) { if (m_room != nullptr && m_currentState == Unknown) {
initializeEvent(); initializeEvent();
updateReplyModel();
resetModel(); resetModel();
} }
}); });
@@ -71,7 +70,6 @@ void MessageContentModel::initializeModel()
connect(m_room, &NeoChatRoom::pendingEventMerged, this, [this]() { connect(m_room, &NeoChatRoom::pendingEventMerged, this, [this]() {
if (m_room != nullptr && m_currentState == Pending) { if (m_room != nullptr && m_currentState == Pending) {
initializeEvent(); initializeEvent();
updateReplyModel();
resetModel(); resetModel();
} }
}); });
@@ -80,7 +78,6 @@ void MessageContentModel::initializeModel()
for (int i = fromIndex; i <= toIndex; i++) { for (int i = fromIndex; i <= toIndex; i++) {
if (m_room->findInTimeline(i)->event()->id() == m_eventId) { if (m_room->findInTimeline(i)->event()->id() == m_eventId) {
initializeEvent(); initializeEvent();
updateReplyModel();
resetModel(); resetModel();
} }
} }
@@ -96,22 +93,26 @@ void MessageContentModel::initializeModel()
}); });
connect(m_room, &NeoChatRoom::newFileTransfer, this, [this](const QString &eventId) { connect(m_room, &NeoChatRoom::newFileTransfer, this, [this](const QString &eventId) {
if (eventId == m_eventId) { if (eventId == m_eventId) {
updateFileInfo(); forEachComponentOfType({MessageComponentType::File, MessageComponentType::Audio, MessageComponentType::Image, MessageComponentType::Video},
m_fileInfoFunction);
} }
}); });
connect(m_room, &NeoChatRoom::fileTransferProgress, this, [this](const QString &eventId) { connect(m_room, &NeoChatRoom::fileTransferProgress, this, [this](const QString &eventId) {
if (eventId == m_eventId) { if (eventId == m_eventId) {
updateFileInfo(); forEachComponentOfType({MessageComponentType::File, MessageComponentType::Audio, MessageComponentType::Image, MessageComponentType::Video},
m_fileInfoFunction);
} }
}); });
connect(m_room, &NeoChatRoom::fileTransferCompleted, this, [this](const QString &eventId) { connect(m_room, &NeoChatRoom::fileTransferCompleted, this, [this](const QString &eventId) {
if (m_room != nullptr && eventId == m_eventId) { if (m_room != nullptr && eventId == m_eventId) {
updateFileInfo(); forEachComponentOfType({MessageComponentType::File, MessageComponentType::Audio, MessageComponentType::Image, MessageComponentType::Video},
m_fileInfoFunction);
} }
}); });
connect(m_room, &NeoChatRoom::fileTransferFailed, this, [this](const QString &eventId, const QString &errorMessage) { connect(m_room, &NeoChatRoom::fileTransferFailed, this, [this](const QString &eventId, const QString &errorMessage) {
if (eventId == m_eventId) { if (eventId == m_eventId) {
updateFileInfo(); forEachComponentOfType({MessageComponentType::File, MessageComponentType::Audio, MessageComponentType::Image, MessageComponentType::Video},
m_fileInfoFunction);
if (errorMessage.isEmpty()) { if (errorMessage.isEmpty()) {
Q_EMIT m_room->showMessage(MessageType::Error, i18nc("@info", "Failed to download file.")); Q_EMIT m_room->showMessage(MessageType::Error, i18nc("@info", "Failed to download file."));
} else { } else {
@@ -149,7 +150,6 @@ void MessageContentModel::initializeModel()
}); });
connect(this, &MessageContentModel::threadsEnabledChanged, this, [this]() { connect(this, &MessageContentModel::threadsEnabledChanged, this, [this]() {
updateReplyModel();
resetModel(); resetModel();
}); });
connect(m_room, &Room::updatedEvent, this, [this](const QString &eventId) { connect(m_room, &Room::updatedEvent, this, [this](const QString &eventId) {
@@ -159,23 +159,9 @@ void MessageContentModel::initializeModel()
}); });
initializeEvent(); initializeEvent();
if (m_currentState == Available || m_currentState == Pending) {
updateReplyModel();
}
resetModel(); resetModel();
} }
void MessageContentModel::updateFileInfo()
{
for (auto it = m_components.cbegin(); it != m_components.cend(); it++) {
const auto currentIndex = it - m_components.cbegin();
if (m_components.at(currentIndex).type == MessageComponentType::File || m_components.at(currentIndex).type == MessageComponentType::Audio
|| m_components.at(currentIndex).type == MessageComponentType::Image || m_components.at(currentIndex).type == MessageComponentType::Video) {
Q_EMIT dataChanged(index(currentIndex), index(currentIndex), {FileTransferInfoRole});
}
}
}
void MessageContentModel::initializeEvent() void MessageContentModel::initializeEvent()
{ {
if (m_currentState == UnAvailable) { if (m_currentState == UnAvailable) {
@@ -203,7 +189,6 @@ void MessageContentModel::getEvent()
if (m_room != nullptr) { if (m_room != nullptr) {
if (eventId == m_eventId) { if (eventId == m_eventId) {
initializeEvent(); initializeEvent();
updateReplyModel();
resetModel(); resetModel();
return true; return true;
} }
@@ -427,6 +412,37 @@ QHash<int, QByteArray> MessageContentModel::roleNamesStatic()
return roles; return roles;
} }
bool MessageContentModel::hasComponentType(MessageComponentType::Type type)
{
return std::find_if(m_components.cbegin(),
m_components.cend(),
[type](const MessageComponent &component) {
return component.type == type;
})
!= m_components.cend();
}
void MessageContentModel::forEachComponentOfType(MessageComponentType::Type type, std::function<void(const QModelIndex &)> function)
{
auto it = m_components.begin();
while ((it = std::find_if(it,
m_components.end(),
[type](const MessageComponent &component) {
return component.type == type;
}))
!= m_components.end()) {
function(index(it - m_components.begin()));
++it;
}
}
void MessageContentModel::forEachComponentOfType(QList<MessageComponentType::Type> types, std::function<void(const QModelIndex &)> function)
{
for (const auto &type : types) {
forEachComponentOfType(type, function);
}
}
void MessageContentModel::resetModel() void MessageContentModel::resetModel()
{ {
beginResetModel(); beginResetModel();
@@ -450,6 +466,7 @@ void MessageContentModel::resetModel()
m_components += messageContentComponents(); m_components += messageContentComponents();
endResetModel(); endResetModel();
updateReplyModel();
updateReactionModel(); updateReactionModel();
} }
@@ -468,6 +485,7 @@ void MessageContentModel::resetContent(bool isEditing, bool isThreading)
m_components += newComponents; m_components += newComponents;
endInsertRows(); endInsertRows();
updateReplyModel();
updateReactionModel(); updateReactionModel();
} }
@@ -491,10 +509,6 @@ QList<MessageComponent> MessageContentModel::messageContentComponents(bool isEdi
return newComponents; return newComponents;
} }
if (m_replyModel != nullptr) {
newComponents += MessageComponent{MessageComponentType::Reply, QString(), {}};
}
if (isEditing) { if (isEditing) {
newComponents += MessageComponent{MessageComponentType::ChatBar, QString(), {}}; newComponents += MessageComponent{MessageComponentType::ChatBar, QString(), {}};
} else { } else {
@@ -540,7 +554,8 @@ void MessageContentModel::updateReplyModel()
} }
if (!roomMessageEvent->isReply(m_threadsEnabled) || (roomMessageEvent->isThreaded() && m_threadsEnabled)) { if (!roomMessageEvent->isReply(m_threadsEnabled) || (roomMessageEvent->isThreaded() && m_threadsEnabled)) {
if (m_replyModel) { if (m_replyModel) {
delete m_replyModel; m_replyModel->disconnect(this);
m_replyModel->deleteLater();
} }
return; return;
} }
@@ -554,6 +569,24 @@ void MessageContentModel::updateReplyModel()
connect(m_replyModel, &MessageContentModel::eventUpdated, this, [this]() { connect(m_replyModel, &MessageContentModel::eventUpdated, this, [this]() {
Q_EMIT dataChanged(index(0), index(0), {ReplyAuthorRole}); Q_EMIT dataChanged(index(0), index(0), {ReplyAuthorRole});
}); });
bool hasModel = hasComponentType(MessageComponentType::Reply);
if (m_replyModel && !hasModel) {
int insertRow = 0;
if (m_components.first().type == MessageComponentType::Author) {
insertRow = 1;
}
beginInsertRows({}, insertRow, insertRow);
m_components.insert(insertRow, MessageComponent{MessageComponentType::Reply, QString(), {}});
} else if (!m_replyModel && hasModel) {
int removeRow = 0;
if (m_components.first().type == MessageComponentType::Author) {
removeRow = 1;
}
beginRemoveRows({}, removeRow, removeRow);
m_components.removeAt(removeRow);
endRemoveRows();
}
} }
QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentType::Type type) QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentType::Type type)

View File

@@ -132,9 +132,16 @@ private:
void initializeModel(); void initializeModel();
void initializeEvent(); void initializeEvent();
void getEvent(); void getEvent();
void updateFileInfo();
QList<MessageComponent> m_components; QList<MessageComponent> m_components;
bool hasComponentType(MessageComponentType::Type type);
void forEachComponentOfType(MessageComponentType::Type type, std::function<void(const QModelIndex &)> function);
void forEachComponentOfType(QList<MessageComponentType::Type> types, std::function<void(const QModelIndex &)> function);
std::function<void(const QModelIndex &)> m_fileInfoFunction = [this](const QModelIndex &index) {
Q_EMIT dataChanged(index, index, {MessageContentModel::FileTransferInfoRole});
};
void resetModel(); void resetModel();
void resetContent(bool isEditing = false, bool isThreading = false); void resetContent(bool isEditing = false, bool isThreading = false);
QList<MessageComponent> messageContentComponents(bool isEditing = false, bool isThreading = false); QList<MessageComponent> messageContentComponents(bool isEditing = false, bool isThreading = false);