Add a button to mark spaces as read

[BUG: 508122](https://bugs.kde.org/show_bug.cgi?id=508122)
This commit is contained in:
Azhar Momin
2026-01-24 01:59:51 +05:30
committed by Joshua Goins
parent fb8ee02e3b
commit ade5750550
5 changed files with 109 additions and 0 deletions

View File

@@ -157,12 +157,14 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
if (isSpace()) { if (isSpace()) {
Q_EMIT childrenNotificationCountChanged(); Q_EMIT childrenNotificationCountChanged();
Q_EMIT childrenHaveHighlightNotificationsChanged(); Q_EMIT childrenHaveHighlightNotificationsChanged();
Q_EMIT spaceHasUnreadMessagesChanged();
} }
}); });
connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceNotificationCountChanged, this, [this](const QStringList &spaces) { connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceNotificationCountChanged, this, [this](const QStringList &spaces) {
if (spaces.contains(id())) { if (spaces.contains(id())) {
Q_EMIT childrenNotificationCountChanged(); Q_EMIT childrenNotificationCountChanged();
Q_EMIT childrenHaveHighlightNotificationsChanged(); Q_EMIT childrenHaveHighlightNotificationsChanged();
Q_EMIT spaceHasUnreadMessagesChanged();
} }
}); });
@@ -1906,4 +1908,20 @@ void NeoChatRoom::invalidateLastUnreadHighlightId(const QString &fromEventId, co
} }
} }
bool NeoChatRoom::spaceHasUnreadMessages() const
{
if (!isSpace()) {
return false;
}
return SpaceHierarchyCache::instance().spaceHasUnreadMessages(id());
}
void NeoChatRoom::markAllChildrenMessagesAsRead()
{
if (isSpace()) {
SpaceHierarchyCache::instance().markAllChildrenMessagesAsRead(id());
}
};
#include "moc_neochatroom.cpp" #include "moc_neochatroom.cpp"

View File

@@ -213,6 +213,13 @@ class NeoChatRoom : public Quotient::Room
*/ */
Q_PROPERTY(bool highlightCycleStarted READ highlightCycleStarted NOTIFY highlightCycleStartedChanged) Q_PROPERTY(bool highlightCycleStarted READ highlightCycleStarted NOTIFY highlightCycleStartedChanged)
/**
* @brief Whether the space has unread messages.
*
* Will always return false if this is not a space.
*/
Q_PROPERTY(bool spaceHasUnreadMessages READ spaceHasUnreadMessages NOTIFY spaceHasUnreadMessagesChanged)
public: public:
explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {}); explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {});
@@ -652,6 +659,18 @@ public:
*/ */
bool highlightCycleStarted() const; bool highlightCycleStarted() const;
/**
* @brief Whether the space has unread messages.
*
* Will always return false if this is not a space.
*/
bool spaceHasUnreadMessages() const;
/**
* @brief Mark the space and all its children messages as read.
*/
Q_INVOKABLE void markAllChildrenMessagesAsRead();
private: private:
bool m_visible = false; bool m_visible = false;
@@ -722,6 +741,7 @@ Q_SIGNALS:
void inviteTimestampChanged(); void inviteTimestampChanged();
void pinnedMessageChanged(); void pinnedMessageChanged();
void highlightCycleStartedChanged(); void highlightCycleStartedChanged();
void spaceHasUnreadMessagesChanged();
/** /**
* @brief Request a message be shown to the user of the given type. * @brief Request a message be shown to the user of the given type.

View File

@@ -187,6 +187,21 @@ bool SpaceHierarchyCache::isChild(const QString &roomId) const
return false; return false;
} }
bool SpaceHierarchyCache::spaceHasUnreadMessages(const QString &spaceId)
{
auto children = m_spaceHierarchy[spaceId];
for (const auto &childId : children) {
if (const auto child = static_cast<NeoChatRoom *>(m_connection->room(childId))) {
if (child->notificationCount() > 0) {
return true;
}
}
}
return false;
}
NeoChatConnection *SpaceHierarchyCache::connection() const NeoChatConnection *SpaceHierarchyCache::connection() const
{ {
return m_connection; return m_connection;
@@ -239,4 +254,40 @@ void SpaceHierarchyCache::setRecommendedSpaceHidden(bool hidden)
Q_EMIT recommendedSpaceHiddenChanged(); Q_EMIT recommendedSpaceHiddenChanged();
} }
void SpaceHierarchyCache::markAllChildrenMessagesAsRead(const QString &spaceId)
{
const auto children = m_spaceHierarchy[spaceId];
for (const auto &childId : children) {
if (const auto child = static_cast<NeoChatRoom *>(m_connection->room(childId))) {
if (child->notificationCount() <= 0) {
continue;
}
if (child->messageEvents().crbegin() == child->historyEdge()) {
if (!child->eventsHistoryJob()) {
if (child->allHistoryLoaded()) {
continue;
}
child->getPreviousContent();
}
connect(
child,
&NeoChatRoom::addedMessages,
child,
[child] {
if (child->messageEvents().crbegin() != child->historyEdge()) {
child->markAllMessagesAsRead();
}
},
Qt::SingleShotConnection);
} else {
child->markAllMessagesAsRead();
}
}
}
}
#include "moc_spacehierarchycache.cpp" #include "moc_spacehierarchycache.cpp"

View File

@@ -84,6 +84,11 @@ public:
*/ */
[[nodiscard]] bool isChild(const QString &roomId) const; [[nodiscard]] bool isChild(const QString &roomId) const;
/**
* @brief Return whether the given space has unread messages.
*/
bool spaceHasUnreadMessages(const QString &spaceId);
NeoChatConnection *connection() const; NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection); void setConnection(NeoChatConnection *connection);
@@ -95,6 +100,8 @@ public:
bool recommendedSpaceHidden() const; bool recommendedSpaceHidden() const;
void setRecommendedSpaceHidden(bool hidden); void setRecommendedSpaceHidden(bool hidden);
void markAllChildrenMessagesAsRead(const QString &spaceId);
Q_SIGNALS: Q_SIGNALS:
void spaceHierarchyChanged(); void spaceHierarchyChanged();
void connectionChanged(); void connectionChanged();

View File

@@ -40,6 +40,19 @@ KirigamiComponents.ConvergentContextMenu {
} }
} }
QQC2.Action {
text: i18nc("@action:inmenu", "Mark Space as Read")
icon.name: "checkmark"
enabled: root.room.spaceHasUnreadMessages
onTriggered: {
root.room.markAllChildrenMessagesAsRead();
}
}
Kirigami.Action {
separator: true
}
QQC2.Action { QQC2.Action {
text: i18nc("'Space' is a matrix space", "View Space") text: i18nc("'Space' is a matrix space", "View Space")
icon.name: "view-list-details" icon.name: "view-list-details"