diff --git a/src/controller.cpp b/src/controller.cpp index e54d27052..09057312e 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -26,6 +26,7 @@ #include #include "neochatconfig.h" +#include "neochatconnection.h" #include "neochatroom.h" #include "notificationsmanager.h" #include "proxycontroller.h" @@ -37,6 +38,14 @@ #include "trayicon_sni.h" #endif +#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) +#ifndef Q_OS_ANDROID +#include +#include +#include +#endif +#endif + bool testMode = false; using namespace Quotient; @@ -149,6 +158,7 @@ void Controller::addConnection(NeoChatConnection *c) connect(c, &NeoChatConnection::loggedOut, this, [this, c] { dropConnection(c); }); + connect(c, &NeoChatConnection::badgeNotificationCountChanged, this, &Controller::updateBadgeNotificationCount); c->sync(); @@ -291,7 +301,14 @@ void Controller::setActiveConnection(NeoChatConnection *connection) if (connection == m_connection) { return; } + m_connection = connection; + + if (m_connection != nullptr) { + m_connection->refreshBadgeNotificationCount(); + updateBadgeNotificationCount(m_connection, m_connection->badgeNotificationCount()); + } + Q_EMIT activeConnectionChanged(); } @@ -316,6 +333,36 @@ void Controller::listenForNotifications() #endif } +void Controller::updateBadgeNotificationCount(NeoChatConnection *connection, int count) +{ + if (connection == m_connection) { +#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) +#ifndef Q_OS_ANDROID + // copied from Telegram desktop + const auto launcherUrl = "application://org.kde.neochat.desktop"_ls; + // Gnome requires that count is a 64bit integer + const qint64 counterSlice = std::min(count, 9999); + QVariantMap dbusUnityProperties; + + if (counterSlice > 0) { + dbusUnityProperties["count"_ls] = counterSlice; + dbusUnityProperties["count-visible"_ls] = true; + } else { + dbusUnityProperties["count-visible"_ls] = false; + } + + auto signal = QDBusMessage::createSignal("/com/canonical/unity/launcherentry/neochat"_ls, "com.canonical.Unity.LauncherEntry"_ls, "Update"_ls); + + signal.setArguments({launcherUrl, dbusUnityProperties}); + + QDBusConnection::sessionBus().send(signal); +#endif // Q_OS_ANDROID +#else + qGuiApp->setBadgeNumber(count); +#endif // QT_VERSION_CHECK(6, 6, 0) + } +} + bool Controller::isFlatpak() const { #ifdef NEOCHAT_FLATPAK diff --git a/src/controller.h b/src/controller.h index a2481e3a6..ba90d0dff 100644 --- a/src/controller.h +++ b/src/controller.h @@ -117,6 +117,7 @@ private: private Q_SLOTS: void invokeLogin(); void setQuitOnLastWindowClosed(); + void updateBadgeNotificationCount(NeoChatConnection *connection, int count); Q_SIGNALS: void errorOccured(const QString &error, const QString &detail); diff --git a/src/models/roomlistmodel.cpp b/src/models/roomlistmodel.cpp index c06d64aff..925539846 100644 --- a/src/models/roomlistmodel.cpp +++ b/src/models/roomlistmodel.cpp @@ -9,17 +9,7 @@ #include "roommanager.h" #include "spacehierarchycache.h" -#include -#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) -#ifndef Q_OS_ANDROID -#include -#include -#include -#endif -#endif - #include -#include using namespace Quotient; @@ -28,32 +18,6 @@ Q_DECLARE_METATYPE(Quotient::JoinState) RoomListModel::RoomListModel(QObject *parent) : QAbstractListModel(parent) { - connect(this, &RoomListModel::highlightCountChanged, this, [this]() { -#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) -#ifndef Q_OS_ANDROID - // copied from Telegram desktop - const auto launcherUrl = "application://org.kde.neochat.desktop"_ls; - // Gnome requires that count is a 64bit integer - const qint64 counterSlice = std::min(m_highlightCount, 9999); - QVariantMap dbusUnityProperties; - - if (counterSlice > 0) { - dbusUnityProperties["count"_ls] = counterSlice; - dbusUnityProperties["count-visible"_ls] = true; - } else { - dbusUnityProperties["count-visible"_ls] = false; - } - - auto signal = QDBusMessage::createSignal("/com/canonical/unity/launcherentry/neochat"_ls, "com.canonical.Unity.LauncherEntry"_ls, "Update"_ls); - - signal.setArguments({launcherUrl, dbusUnityProperties}); - - QDBusConnection::sessionBus().send(signal); -#endif // Q_OS_ANDROID -#else - qGuiApp->setBadgeNumber(m_highlightCount); -#endif // QT_VERSION_CHECK(6, 6, 0) - }); connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceHierarchyChanged, this, [this]() { Q_EMIT dataChanged(index(0, 0), index(rowCount(), 0), {IsChildSpaceRole}); }); @@ -122,7 +86,6 @@ void RoomListModel::doResetModel() doAddRoom(room); } endResetModel(); - refreshNotificationCount(); } NeoChatRoom *RoomListModel::roomAt(int row) const @@ -148,7 +111,7 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room) refresh(room, {DisplayNameRole}); }); connect(room, &Room::unreadStatsChanged, this, [this, room] { - refresh(room, {NotificationCountRole, HighlightCountRole}); + refresh(room, {ContextNotificationCountRole, HasHighlightNotificationsRole}); }); connect(room, &Room::notificationCountChanged, this, [this, room] { refresh(room); @@ -171,44 +134,6 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room) connect(room, &Room::pendingEventMerged, this, [this, room] { refresh(room, {SubtitleTextRole}); }); - connect(room, &Room::unreadStatsChanged, this, &RoomListModel::refreshNotificationCount); - connect(room, &Room::highlightCountChanged, this, &RoomListModel::refreshHighlightCount); -} - -int RoomListModel::notificationCount() const -{ - return m_notificationCount; -} - -int RoomListModel::highlightCount() const -{ - return m_highlightCount; -} - -void RoomListModel::refreshNotificationCount() -{ - int count = 0; - for (auto room : std::as_const(m_rooms)) { - count += room->notificationCount(); - } - if (m_notificationCount == count) { - return; - } - m_notificationCount = count; - Q_EMIT notificationCountChanged(); -} - -void RoomListModel::refreshHighlightCount() -{ - int count = 0; - for (auto room : std::as_const(m_rooms)) { - count += room->highlightCount(); - } - if (m_highlightCount == count) { - return; - } - m_highlightCount = count; - Q_EMIT highlightCountChanged(); } void RoomListModel::updateRoom(Room *room, Room *prev) @@ -295,11 +220,11 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const if (role == CategoryRole) { return NeoChatRoomType::typeForRoom(room); } - if (role == NotificationCountRole) { - return room->notificationCount(); + if (role == ContextNotificationCountRole) { + return room->contextAwareNotificationCount(); } - if (role == HighlightCountRole) { - return room->highlightCount(); + if (role == HasHighlightNotificationsRole) { + return room->highlightCount() > 0 && room->contextAwareNotificationCount() > 0; } if (role == LastActiveTimeRole) { return room->lastActiveTime(); @@ -361,8 +286,8 @@ QHash RoomListModel::roleNames() const roles[CanonicalAliasRole] = "canonicalAlias"; roles[TopicRole] = "topic"; roles[CategoryRole] = "category"; - roles[NotificationCountRole] = "notificationCount"; - roles[HighlightCountRole] = "highlightCount"; + roles[ContextNotificationCountRole] = "contextNotificationCount"; + roles[HasHighlightNotificationsRole] = "hasHighlightNotifications"; roles[LastActiveTimeRole] = "lastActiveTime"; roles[JoinStateRole] = "joinState"; roles[CurrentRoomRole] = "currentRoom"; diff --git a/src/models/roomlistmodel.h b/src/models/roomlistmodel.h index 46bcea09d..8cdc2da66 100644 --- a/src/models/roomlistmodel.h +++ b/src/models/roomlistmodel.h @@ -31,11 +31,6 @@ class RoomListModel : public QAbstractListModel */ Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged) - /** - * @brief The total number of notifications for all the rooms. - */ - Q_PROPERTY(int notificationCount READ notificationCount NOTIFY notificationCountChanged) - public: /** * @brief Defines the model roles. @@ -46,8 +41,8 @@ public: CanonicalAliasRole, /**< The room canonical alias. */ TopicRole, /**< The room topic. */ CategoryRole, /**< The room category, e.g favourite. */ - NotificationCountRole, /**< The number of notifications in the room. */ - HighlightCountRole, /**< The number of highlighted messages in the room. */ + ContextNotificationCountRole, /**< The context aware notification count for the room. */ + HasHighlightNotificationsRole, /**< Whether there are any highlight notifications. */ LastActiveTimeRole, /**< The timestamp of the last event sent in the room. */ JoinStateRole, /**< The local user's join state in the room. */ CurrentRoomRole, /**< The room object for the room. */ @@ -67,9 +62,6 @@ public: [[nodiscard]] Quotient::Connection *connection() const; void setConnection(Quotient::Connection *connection); - [[nodiscard]] int notificationCount() const; - [[nodiscard]] int highlightCount() const; - /** * @brief Get the given role value at the given index. * @@ -114,23 +106,16 @@ private Q_SLOTS: void updateRoom(Quotient::Room *room, Quotient::Room *prev); void deleteRoom(Quotient::Room *room); void refresh(NeoChatRoom *room, const QList &roles = {}); - void refreshNotificationCount(); - void refreshHighlightCount(); private: Quotient::Connection *m_connection = nullptr; QList m_rooms; - int m_notificationCount = 0; - int m_highlightCount = 0; QString m_activeSpaceId; void connectRoomSignals(NeoChatRoom *room); Q_SIGNALS: void connectionChanged(); - void notificationCountChanged(); - void highlightCountChanged(); - void roomAdded(NeoChatRoom *_t1); }; diff --git a/src/models/roomtreemodel.cpp b/src/models/roomtreemodel.cpp index d78e644de..65c539a00 100644 --- a/src/models/roomtreemodel.cpp +++ b/src/models/roomtreemodel.cpp @@ -127,7 +127,7 @@ void RoomTreeModel::connectRoomSignals(NeoChatRoom *room) refreshRoomRoles(room, {DisplayNameRole}); }); connect(room, &Room::unreadStatsChanged, this, [this, room] { - refreshRoomRoles(room, {NotificationCountRole, HighlightCountRole}); + refreshRoomRoles(room, {ContextNotificationCountRole, HasHighlightNotificationsRole}); }); connect(room, &Room::avatarChanged, this, [this, room] { refreshRoomRoles(room, {AvatarRole}); @@ -144,6 +144,9 @@ void RoomTreeModel::connectRoomSignals(NeoChatRoom *room) connect(room, &Room::pendingEventMerged, this, [this, room] { refreshRoomRoles(room, {SubtitleTextRole}); }); + connect(room, &NeoChatRoom::pushNotificationStateChanged, this, [this, room] { + refreshRoomRoles(room, {ContextNotificationCountRole, HasHighlightNotificationsRole}); + }); } void RoomTreeModel::refreshRoomRoles(NeoChatRoom *room, const QList &roles) @@ -208,8 +211,8 @@ QHash RoomTreeModel::roleNames() const roles[CanonicalAliasRole] = "canonicalAlias"; roles[TopicRole] = "topic"; roles[CategoryRole] = "category"; - roles[NotificationCountRole] = "notificationCount"; - roles[HighlightCountRole] = "highlightCount"; + roles[ContextNotificationCountRole] = "contextNotificationCount"; + roles[HasHighlightNotificationsRole] = "hasHighlightNotifications"; roles[LastActiveTimeRole] = "lastActiveTime"; roles[JoinStateRole] = "joinState"; roles[CurrentRoomRole] = "currentRoom"; @@ -271,11 +274,11 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const if (role == CategoryRole) { return NeoChatRoomType::typeForRoom(room); } - if (role == NotificationCountRole) { - return int(room->notificationCount()); + if (role == ContextNotificationCountRole) { + return int(room->contextAwareNotificationCount()); } - if (role == HighlightCountRole) { - return int(room->highlightCount()); + if (role == HasHighlightNotificationsRole) { + return room->highlightCount() > 0 && room->contextAwareNotificationCount() > 0; } if (role == LastActiveTimeRole) { return room->lastActiveTime(); diff --git a/src/models/roomtreemodel.h b/src/models/roomtreemodel.h index 2a28caa7a..4c3bae33a 100644 --- a/src/models/roomtreemodel.h +++ b/src/models/roomtreemodel.h @@ -33,8 +33,8 @@ public: CanonicalAliasRole, /**< The room canonical alias. */ TopicRole, /**< The room topic. */ CategoryRole, /**< The room category, e.g favourite. */ - NotificationCountRole, /**< The number of notifications in the room. */ - HighlightCountRole, /**< The number of highlighted messages in the room. */ + ContextNotificationCountRole, /**< The context aware notification count for the room. */ + HasHighlightNotificationsRole, /**< Whether there are any highlight notifications. */ LastActiveTimeRole, /**< The timestamp of the last event sent in the room. */ JoinStateRole, /**< The local user's join state in the room. */ CurrentRoomRole, /**< The room object for the room. */ diff --git a/src/models/sortfilterroomtreemodel.cpp b/src/models/sortfilterroomtreemodel.cpp index 539ebe3b5..5fb037e71 100644 --- a/src/models/sortfilterroomtreemodel.cpp +++ b/src/models/sortfilterroomtreemodel.cpp @@ -52,8 +52,8 @@ static const QVector activitySortPriorities{ // Anything useful at the top, quiet rooms at the bottom RoomTreeModel::AttentionRole, // Organize by highlights, notifications, unread favorites, all other unread, in that order - RoomTreeModel::HighlightCountRole, - RoomTreeModel::NotificationCountRole, + RoomTreeModel::HasHighlightNotificationsRole, + RoomTreeModel::ContextNotificationCountRole, RoomTreeModel::FavouriteRole, // Finally sort by last activity time RoomTreeModel::LastActiveTimeRole, diff --git a/src/neochatconnection.cpp b/src/neochatconnection.cpp index d9dddc396..1c1dce35c 100644 --- a/src/neochatconnection.cpp +++ b/src/neochatconnection.cpp @@ -77,7 +77,9 @@ void NeoChatConnection::connectSignals() for (const auto &chatId : additions) { if (const auto chat = room(chatId)) { connect(chat, &Room::unreadStatsChanged, this, [this]() { + refreshBadgeNotificationCount(); Q_EMIT directChatNotificationsChanged(); + Q_EMIT directChatsHaveHighlightNotificationsChanged(); }); } } @@ -91,29 +93,51 @@ void NeoChatConnection::connectSignals() if (room->isDirectChat()) { connect(room, &Room::unreadStatsChanged, this, [this]() { Q_EMIT directChatNotificationsChanged(); + Q_EMIT directChatsHaveHighlightNotificationsChanged(); }); } + connect(room, &Room::unreadStatsChanged, this, [this]() { + refreshBadgeNotificationCount(); + Q_EMIT homeNotificationsChanged(); + Q_EMIT homeHaveHighlightNotificationsChanged(); + }); }); connect(this, &NeoChatConnection::leftRoom, this, [this](Room *room, Room *prev) { Q_UNUSED(room) if (prev && prev->isDirectChat()) { Q_EMIT directChatInvitesChanged(); + Q_EMIT directChatNotificationsChanged(); + Q_EMIT directChatsHaveHighlightNotificationsChanged(); } + refreshBadgeNotificationCount(); + Q_EMIT homeNotificationsChanged(); + Q_EMIT homeHaveHighlightNotificationsChanged(); }); connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceHierarchyChanged, this, [this]() { + refreshBadgeNotificationCount(); Q_EMIT homeNotificationsChanged(); + Q_EMIT homeHaveHighlightNotificationsChanged(); }); - for (const auto room : allRooms()) { - connect(room, &NeoChatRoom::unreadStatsChanged, this, [this, room]() { - if (room != nullptr) { - auto category = NeoChatRoomType::typeForRoom(static_cast(room)); - if (!SpaceHierarchyCache::instance().isChild(room->id()) && (category == NeoChatRoomType::Normal || category == NeoChatRoomType::Favorite) - && room->successorId().isEmpty()) { - Q_EMIT homeNotificationsChanged(); - } - } - }); +} + +int NeoChatConnection::badgeNotificationCount() const +{ + return m_badgeNotificationCount; +} + +void NeoChatConnection::refreshBadgeNotificationCount() +{ + int count = 0; + for (const auto &r : allRooms()) { + if (const auto room = static_cast(r)) { + count += room->contextAwareNotificationCount(); + } + } + + if (count != m_badgeNotificationCount) { + m_badgeNotificationCount = count; + Q_EMIT badgeNotificationCountChanged(this, m_badgeNotificationCount); } } @@ -329,7 +353,7 @@ qsizetype NeoChatConnection::directChatNotifications() const for (const auto &chatId : directChats()) { if (!added.contains(chatId)) { if (const auto chat = room(chatId)) { - notifications += chat->notificationCount(); + notifications += dynamic_cast(chat)->contextAwareNotificationCount(); added += chatId; } } @@ -337,29 +361,47 @@ qsizetype NeoChatConnection::directChatNotifications() const return notifications; } +bool NeoChatConnection::directChatsHaveHighlightNotifications() const +{ + for (const auto &childId : directChats()) { + if (const auto child = static_cast(room(childId))) { + if (child->highlightCount() > 0) { + return true; + } + } + } + return false; +} + qsizetype NeoChatConnection::homeNotifications() const { qsizetype notifications = 0; QStringList added; const auto &spaceHierarchyCache = SpaceHierarchyCache::instance(); - for (const auto &room : allRooms()) { - auto category = NeoChatRoomType::typeForRoom(static_cast(room)); - if (!added.contains(room->id()) && room->joinState() == JoinState::Join && !room->isDirectChat() && !spaceHierarchyCache.isChild(room->id()) - && room->successorId().isEmpty()) { - switch (category) { - case NeoChatRoomType::Normal: - case NeoChatRoomType::Favorite: - notifications += room->notificationCount(); - break; - default: - notifications += room->highlightCount(); + for (const auto &r : allRooms()) { + if (const auto room = static_cast(r)) { + if (!added.contains(room->id()) && !room->isDirectChat() && !spaceHierarchyCache.isChild(room->id())) { + notifications += dynamic_cast(room)->contextAwareNotificationCount(); + added += room->id(); } - added += room->id(); } } return notifications; } +bool NeoChatConnection::homeHaveHighlightNotifications() const +{ + const auto &spaceHierarchyCache = SpaceHierarchyCache::instance(); + for (const auto &r : allRooms()) { + if (const auto room = static_cast(r)) { + if (!room->isDirectChat() && !spaceHierarchyCache.isChild(room->id()) && room->highlightCount() > 0) { + return true; + } + } + } + return false; +} + bool NeoChatConnection::directChatInvites() const { auto inviteRooms = rooms(JoinState::Invite); diff --git a/src/neochatconnection.h b/src/neochatconnection.h index d42eacd7e..af03f74e2 100644 --- a/src/neochatconnection.h +++ b/src/neochatconnection.h @@ -32,11 +32,21 @@ class NeoChatConnection : public Quotient::Connection */ Q_PROPERTY(qsizetype directChatNotifications READ directChatNotifications NOTIFY directChatNotificationsChanged) + /** + * @brief Whether any direct chats have highlight notifications. + */ + Q_PROPERTY(bool directChatsHaveHighlightNotifications READ directChatsHaveHighlightNotifications NOTIFY directChatsHaveHighlightNotificationsChanged) + /** * @brief The total number of notifications for all rooms in the home tab. */ Q_PROPERTY(qsizetype homeNotifications READ homeNotifications NOTIFY homeNotificationsChanged) + /** + * @brief Whether any of the rooms in the home tab have highlight notifications. + */ + Q_PROPERTY(bool homeHaveHighlightNotifications READ homeHaveHighlightNotifications NOTIFY homeHaveHighlightNotificationsChanged) + /** * @brief Whether there is at least one invite to a direct chat. */ @@ -119,7 +129,13 @@ public: Q_INVOKABLE QString accountDataJsonString(const QString &type) const; qsizetype directChatNotifications() const; + bool directChatsHaveHighlightNotifications() const; qsizetype homeNotifications() const; + bool homeHaveHighlightNotifications() const; + + int badgeNotificationCount() const; + void refreshBadgeNotificationCount(); + bool directChatInvites() const; // note: this is intentionally a copied QString because @@ -134,15 +150,20 @@ public: Q_SIGNALS: void labelChanged(); void directChatNotificationsChanged(); + void directChatsHaveHighlightNotificationsChanged(); void homeNotificationsChanged(); + void homeHaveHighlightNotificationsChanged(); void directChatInvitesChanged(); void isOnlineChanged(); void passwordStatus(NeoChatConnection::PasswordStatus status); void userConsentRequired(QUrl url); + void badgeNotificationCountChanged(NeoChatConnection *connection, int count); private: bool m_isOnline = true; void setIsOnline(bool isOnline); void connectSignals(); + + int m_badgeNotificationCount = 0; }; diff --git a/src/neochatroom.cpp b/src/neochatroom.cpp index 57b998d0e..446efb9bb 100644 --- a/src/neochatroom.cpp +++ b/src/neochatroom.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -129,15 +130,32 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceHierarchyChanged, this, [this]() { if (isSpace()) { Q_EMIT childrenNotificationCountChanged(); + Q_EMIT childrenHaveHighlightNotificationsChanged(); } }); connect(&SpaceHierarchyCache::instance(), &SpaceHierarchyCache::spaceNotifcationCountChanged, this, [this](const QStringList &spaces) { if (spaces.contains(id())) { Q_EMIT childrenNotificationCountChanged(); + Q_EMIT childrenHaveHighlightNotificationsChanged(); } }); } +int NeoChatRoom::contextAwareNotificationCount() const +{ + // DOn't include spaces, rooms that the user hasn't joined and rooms where the user has joined the successor. + if (isSpace() || joinState() != JoinState::Join || successor(JoinState::Join) != nullptr) { + return 0; + } + if (m_currentPushNotificationState == PushNotificationState::Mute) { + return 0; + } + if (m_currentPushNotificationState == PushNotificationState::MentionKeyword || isLowPriority()) { + return int(highlightCount()); + } + return int(notificationCount()); +} + bool NeoChatRoom::hasFileUploading() const { return m_hasFileUploading; @@ -1300,6 +1318,14 @@ qsizetype NeoChatRoom::childrenNotificationCount() return SpaceHierarchyCache::instance().notificationCountForSpace(id()); } +bool NeoChatRoom::childrenHaveHighlightNotifications() const +{ + if (!isSpace()) { + return false; + } + return SpaceHierarchyCache::instance().spaceHasHighlightNotifications(id()); +} + void NeoChatRoom::addChild(const QString &childId, bool setChildParent, bool canonical, bool suggested) { if (!isSpace()) { diff --git a/src/neochatroom.h b/src/neochatroom.h index 989c60ac4..1821e0bdb 100644 --- a/src/neochatroom.h +++ b/src/neochatroom.h @@ -133,6 +133,13 @@ class NeoChatRoom : public Quotient::Room */ Q_PROPERTY(qsizetype childrenNotificationCount READ childrenNotificationCount NOTIFY childrenNotificationCountChanged) + /** + * @brief Whether this room's children have any highlight notifications. + * + * Will always return false if this is not a space. + */ + Q_PROPERTY(bool childrenHaveHighlightNotifications READ childrenHaveHighlightNotifications NOTIFY childrenHaveHighlightNotificationsChanged) + /** * @brief Whether the local user has an invite to the room. * @@ -405,6 +412,16 @@ public: */ [[nodiscard]] bool lastEventIsSpoiler() const; + /** + * @brief Return the notification count for the room accounting for tags and notification state. + * + * The following rules are observed: + * - Rooms tagged as low priority or mentions and keywords notification state + * only return the number of highlights. + * - Muted rooms always return 0. + */ + int contextAwareNotificationCount() const; + [[nodiscard]] bool hasFileUploading() const; void setHasFileUploading(bool value); @@ -535,6 +552,8 @@ public: qsizetype childrenNotificationCount(); + bool childrenHaveHighlightNotifications() const; + /** * @brief Add the given room as a child. * @@ -825,6 +844,7 @@ Q_SIGNALS: void canonicalParentChanged(); void lastActiveTimeChanged(); void childrenNotificationCountChanged(); + void childrenHaveHighlightNotificationsChanged(); void isInviteChanged(); void readOnlyChanged(); void displayNameChanged(); diff --git a/src/qml/RoomDelegate.qml b/src/qml/RoomDelegate.qml index 1ddf0d1fe..f8ffebd6b 100644 --- a/src/qml/RoomDelegate.qml +++ b/src/qml/RoomDelegate.qml @@ -18,8 +18,8 @@ Delegates.RoundedItemDelegate { id: root required property int index - required property int notificationCount - required property int highlightCount + required property int contextNotificationCount + required property bool hasHighlightNotifications required property NeoChatRoom currentRoom required property NeoChatConnection connection required property string avatar @@ -28,7 +28,7 @@ Delegates.RoundedItemDelegate { property bool collapsed: false - readonly property bool hasNotifications: currentRoom.pushNotificationState === PushNotificationState.MentionKeyword || currentRoom.isLowPriority ? highlightCount > 0 : notificationCount > 0 + readonly property bool hasNotifications: contextNotificationCount > 0 Accessible.name: root.displayName Accessible.onPressAction: clicked() @@ -106,16 +106,16 @@ Delegates.RoundedItemDelegate { QQC2.Label { id: notificationCountLabel - text: currentRoom.pushNotificationState === PushNotificationState.MentionKeyword || currentRoom.isLowPriority ? root.highlightCount : root.notificationCount - visible: root.hasNotifications && currentRoom.pushNotificationState !== PushNotificationState.Mute && !root.collapsed + text: root.contextNotificationCount + visible: root.hasNotifications && !root.collapsed color: Kirigami.Theme.textColor horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter background: Rectangle { visible: root.hasNotifications Kirigami.Theme.colorSet: Kirigami.Theme.Button - color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.disabledTextColor - opacity: highlightCount > 0 ? 1 : 0.3 + Kirigami.Theme.inherit: false + color: root.hasHighlightNotifications > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.backgroundColor radius: height / 2 } @@ -141,7 +141,7 @@ Delegates.RoundedItemDelegate { } function createRoomListContextMenu() { - const component = Qt.createComponent(Qt.createComponent('org.kde.neochat', 'ContextMenu.qml')); + const component = Qt.createComponent('org.kde.neochat', 'ContextMenu.qml'); if (component.status === Component.Error) { console.error(component.errorString()); } diff --git a/src/qml/SpaceDrawer.qml b/src/qml/SpaceDrawer.qml index 12703f3a7..f1b8750ac 100644 --- a/src/qml/SpaceDrawer.qml +++ b/src/qml/SpaceDrawer.qml @@ -125,7 +125,8 @@ QQC2.Control { background: Rectangle { visible: true Kirigami.Theme.colorSet: Kirigami.Theme.Button - color: Kirigami.Theme.positiveTextColor + Kirigami.Theme.inherit: false + color: root.connection.homeHaveHighlightNotifications ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.backgroundColor radius: height / 2 } @@ -173,7 +174,8 @@ QQC2.Control { background: Rectangle { visible: true Kirigami.Theme.colorSet: Kirigami.Theme.Button - color: Kirigami.Theme.positiveTextColor + Kirigami.Theme.inherit: false + color: root.connection.directChatsHaveHighlightNotifications ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.backgroundColor radius: height / 2 } @@ -239,10 +241,12 @@ QQC2.Control { visible: spaceDelegate.currentRoom.childrenNotificationCount > 0 && root.selectedSpaceId != spaceDelegate.roomId color: Kirigami.Theme.textColor horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter background: Rectangle { visible: true Kirigami.Theme.colorSet: Kirigami.Theme.Button - color: Kirigami.Theme.positiveTextColor + Kirigami.Theme.inherit: false + color: spaceDelegate.currentRoom.childrenHaveHighlightNotifications ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.backgroundColor radius: height / 2 } diff --git a/src/spacehierarchycache.cpp b/src/spacehierarchycache.cpp index c24ab3a5b..4898ebad9 100644 --- a/src/spacehierarchycache.cpp +++ b/src/spacehierarchycache.cpp @@ -126,16 +126,8 @@ qsizetype SpaceHierarchyCache::notificationCountForSpace(const QString &spaceId) for (const auto &childId : children) { if (const auto child = static_cast(m_connection->room(childId))) { - auto category = NeoChatRoomType::typeForRoom(child); - if (!added.contains(child->id()) && child->successorId().isEmpty()) { - switch (category) { - case NeoChatRoomType::Normal: - case NeoChatRoomType::Favorite: - notifications += child->notificationCount(); - break; - default: - notifications += child->highlightCount(); - } + if (!added.contains(child->id())) { + notifications += child->contextAwareNotificationCount(); added += child->id(); } } @@ -143,6 +135,19 @@ qsizetype SpaceHierarchyCache::notificationCountForSpace(const QString &spaceId) return notifications; } +bool SpaceHierarchyCache::spaceHasHighlightNotifications(const QString &spaceId) +{ + auto children = m_spaceHierarchy[spaceId]; + for (const auto &childId : children) { + if (const auto child = static_cast(m_connection->room(childId))) { + if (child->highlightCount() > 0) { + return true; + } + } + } + return false; +} + bool SpaceHierarchyCache::isChild(const QString &roomId) const { const auto childrens = m_spaceHierarchy.values(); diff --git a/src/spacehierarchycache.h b/src/spacehierarchycache.h index 78ee31553..069e8f755 100644 --- a/src/spacehierarchycache.h +++ b/src/spacehierarchycache.h @@ -69,6 +69,11 @@ public: */ qsizetype notificationCountForSpace(const QString &spaceId); + /** + * @brief Whether any of the child rooms have highlight notifications. + */ + bool spaceHasHighlightNotifications(const QString &spaceId); + /** * @brief Returns whether the room is a child space of any space. *