Allow the condition for when messages are automatically marked as read to be configurable.

Title this adds a number of options for when messages should be automatically marked as read for the user to choose from.

![image](/uploads/cef95f8c6c77bfdcabb7a8a309bc1fd2/image.png){width=480 height=262}
This commit is contained in:
James Graham
2025-07-04 14:36:36 +01:00
parent d5d291396d
commit 3d9d211d25
11 changed files with 160 additions and 42 deletions

View File

@@ -34,18 +34,15 @@ MessageModel::MessageModel(QObject *parent)
{
connect(this, &MessageModel::newEventAdded, this, &MessageModel::createEventObjects);
connect(this, &MessageModel::modelAboutToBeReset, this, [this]() {
resetting = true;
connect(this, &MessageModel::modelAboutToReset, this, [this]() {
m_resetting = true;
});
connect(this, &MessageModel::modelReset, this, [this]() {
resetting = false;
m_resetting = false;
});
connect(this, &MessageModel::threadsEnabledChanged, this, [this]() {
Q_EMIT modelAboutToBeReset();
beginResetModel();
endResetModel();
Q_EMIT modelResetComplete();
Q_EMIT dataChanged(index(0), index(rowCount() - 1), {IsThreadedRole});
});
}
@@ -60,17 +57,25 @@ void MessageModel::setRoom(NeoChatRoom *room)
return;
}
const auto oldRoom = m_room;
Q_EMIT roomAboutToChange(oldRoom, room);
clearModel();
Q_EMIT modelAboutToBeReset();
beginResetModel();
if (!m_resetting) {
m_resetting = true;
Q_EMIT modelAboutToReset();
beginResetModel();
}
m_room = room;
if (m_room != nullptr) {
m_room->setVisible(true);
}
Q_EMIT roomChanged();
endResetModel();
Q_EMIT modelResetComplete();
if (m_resetting) {
endResetModel();
Q_EMIT modelResetComplete();
m_resetting = false;
}
Q_EMIT roomChanged(oldRoom, m_room);
}
int MessageModel::timelineServerIndex() const
@@ -444,7 +449,7 @@ void MessageModel::createEventObjects(const Quotient::RoomEvent *event)
// If a model already exists but now has no reactions remove it
if (m_readMarkerModels[eventId]->rowCount() <= 0) {
m_readMarkerModels.remove(eventId);
if (!resetting) {
if (!m_resetting) {
refreshEventRoles(eventId, {ReadMarkersRole, ShowReadMarkersRole});
}
}
@@ -456,7 +461,7 @@ void MessageModel::createEventObjects(const Quotient::RoomEvent *event)
auto newModel = QSharedPointer<ReadMarkerModel>(new ReadMarkerModel(eventId, m_room));
if (newModel->rowCount() > 0) {
m_readMarkerModels[eventId] = newModel;
if (!resetting) {
if (!m_resetting) {
refreshEventRoles(eventId, {ReadMarkersRole, ShowReadMarkersRole});
}
}
@@ -512,12 +517,18 @@ void MessageModel::clearModel()
// HACK: Reset the model to a null room first to make sure QML dismantles
// last room's objects before the room is actually changed
Q_EMIT modelAboutToBeReset();
beginResetModel();
if (!m_resetting) {
m_resetting = true;
Q_EMIT modelAboutToReset();
beginResetModel();
}
m_room->disconnect(this);
m_room = nullptr;
endResetModel();
Q_EMIT modelResetComplete();
if (m_resetting) {
endResetModel();
Q_EMIT modelResetComplete();
m_resetting = false;
}
// Because we don't want any of the object deleted before the model is cleared.
oldRoom->setVisible(false);

View File

@@ -125,7 +125,12 @@ Q_SIGNALS:
/**
* @brief Emitted when the room is changed.
*/
void roomChanged();
void roomAboutToChange(NeoChatRoom *oldRoom, NeoChatRoom *newRoom);
/**
* @brief Emitted when the room is changed.
*/
void roomChanged(NeoChatRoom *oldRoom, NeoChatRoom *newRoom);
/**
* @brief Emitted when the reader marker is added.
@@ -140,7 +145,7 @@ Q_SIGNALS:
/**
* @brief Emitted when the model is about to reset.
*/
void modelAboutToBeReset();
void modelAboutToReset();
/**
* @brief Emitted when the model has been reset.
@@ -169,6 +174,9 @@ protected:
virtual int timelineServerIndex() const;
virtual std::optional<std::reference_wrapper<const Quotient::RoomEvent>> getEventForIndex(QModelIndex index) const;
bool m_resetting = false;
bool m_movingEvent = false;
void fullEventRefresh(int row);
int refreshEventRoles(const QString &eventId, const QList<int> &roles = {});
void refreshEventRoles(int row, const QList<int> &roles = {});
@@ -182,9 +190,6 @@ protected:
bool event(QEvent *event) override;
private:
bool resetting = false;
bool movingEvent = false;
QMap<QString, QSharedPointer<ReadMarkerModel>> m_readMarkerModels;
void createEventObjects(const Quotient::RoomEvent *event);

View File

@@ -28,12 +28,16 @@ void TimelineMessageModel::connectNewRoom()
}
connect(m_room, &Room::aboutToAddNewMessages, this, [this](RoomEventsRange events) {
m_initialized = true;
beginInsertRows({}, timelineServerIndex(), timelineServerIndex() + int(events.size()) - 1);
if (!m_resetting) {
m_initialized = true;
beginInsertRows({}, timelineServerIndex(), timelineServerIndex() + int(events.size()) - 1);
}
});
connect(m_room, &Room::aboutToAddHistoricalMessages, this, [this](RoomEventsRange events) {
m_initialized = true;
beginInsertRows({}, rowCount(), rowCount() + int(events.size()) - 1);
if (!m_resetting) {
m_initialized = true;
beginInsertRows({}, rowCount(), rowCount() + int(events.size()) - 1);
}
});
connect(m_room, &Room::addedMessages, this, [this](int lowest, int biggest) {
if (m_initialized) {
@@ -58,17 +62,21 @@ void TimelineMessageModel::connectNewRoom()
});
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 0)
connect(m_room, &Room::pendingEventAdded, this, [this](const Quotient::RoomEvent *event) {
m_initialized = true;
Q_EMIT newEventAdded(event);
Q_EMIT newLocalUserEventAdded();
beginInsertRows({}, 0, 0);
endInsertRows();
if (!m_resetting) {
beginInsertRows({}, 0, 0);
endInsertRows();
}
});
#else
connect(m_room, &Room::pendingEventAboutToAdd, this, [this](Quotient::RoomEvent *event) {
m_initialized = true;
Q_EMIT newEventAdded(event);
beginInsertRows({}, 0, 0);
if (!m_resetting) {
beginInsertRows({}, 0, 0);
endInsertRows();
}
});
connect(m_room, &Room::pendingEventAdded, this, &TimelineMessageModel::endInsertRows);
#endif
@@ -78,15 +86,15 @@ void TimelineMessageModel::connectNewRoom()
return; // No need to move anything, just refresh
}
movingEvent = true;
m_movingEvent = true;
// Reverse i because row 0 is bottommost in the model
const auto row = timelineServerIndex() - i - 1;
beginMoveRows({}, row, row, {}, timelineServerIndex());
});
connect(m_room, &Room::pendingEventMerged, this, [this] {
if (movingEvent) {
if (m_movingEvent) {
endMoveRows();
movingEvent = false;
m_movingEvent = false;
}
fullEventRefresh(timelineServerIndex());
refreshLastUserEvents(0);

View File

@@ -48,8 +48,6 @@ private:
std::optional<std::reference_wrapper<const Quotient::RoomEvent>> getEventForIndex(QModelIndex index) const override;
int rowBelowInserted = -1;
bool resetting = false;
bool movingEvent = false;
int timelineServerIndex() const override;