diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp index 91f7d555..0d47c64d 100644 --- a/src/timeline/CommunitiesModel.cpp +++ b/src/timeline/CommunitiesModel.cpp @@ -18,15 +18,7 @@ CommunitiesModel::CommunitiesModel(QObject *parent) : QAbstractListModel(parent) , hiddenTagIds_{UserSettings::instance()->hiddenTags()} , mutedTagIds_{UserSettings::instance()->mutedTags()} -{ - connect(ChatPage::instance(), &ChatPage::unreadMessages, this, [this](int) { - // Simply updating every space is easier than tracking which ones need updated. - if (!spaces_.empty()) - emit dataChanged(index(0, 0), - index(spaces_.size() + tags_.size() + 1, 0), - {Roles::UnreadMessages, Roles::HasLoudNotification}); - }); -} +{} QHash CommunitiesModel::roleNames() const @@ -92,17 +84,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const return 0; case CommunitiesModel::Roles::Id: return ""; - case CommunitiesModel::Roles::UnreadMessages: { - int total{0}; - for (const auto &[id, info] : cache::getRoomInfo(cache::joinedRooms())) - total += info.notification_count; - return total; - } + case CommunitiesModel::Roles::UnreadMessages: + return (int)globalUnreads.notification_count; case CommunitiesModel::Roles::HasLoudNotification: - for (const auto &[id, info] : cache::getRoomInfo(cache::joinedRooms())) - if (info.highlight_count > 0) - return true; - return false; + return globalUnreads.highlight_count > 0; } } else if (index.row() == 1) { switch (role) { @@ -124,17 +109,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const return 0; case CommunitiesModel::Roles::Id: return "dm"; - case CommunitiesModel::Roles::UnreadMessages: { - int total{0}; - for (const auto &[id, info] : cache::getRoomInfo(directMessages_)) - total += info.notification_count; - return total; - } + case CommunitiesModel::Roles::UnreadMessages: + return (int)dmUnreads.notification_count; case CommunitiesModel::Roles::HasLoudNotification: - for (const auto &[id, info] : cache::getRoomInfo(directMessages_)) - if (info.highlight_count > 0) - return true; - return false; + return dmUnreads.highlight_count > 0; } } else if (index.row() - 2 < spaceOrder_.size()) { auto id = spaceOrder_.tree.at(index.row() - 2).id; @@ -162,10 +140,20 @@ CommunitiesModel::data(const QModelIndex &index, int role) const return spaceOrder_.tree.at(index.row() - 2).depth; case CommunitiesModel::Roles::Id: return "space:" + id; - case CommunitiesModel::Roles::UnreadMessages: - return utils::getChildNotificationsForSpace(id).first; - case CommunitiesModel::Roles::HasLoudNotification: - return utils::getChildNotificationsForSpace(id).second > 0; + case CommunitiesModel::Roles::UnreadMessages: { + int count = 0; + auto end = spaceOrder_.lastChild(index.row() - 2); + for (int i = index.row() - 2; i <= end; i++) + count += spaceOrder_.tree[i].notificationCounts.notification_count; + return count; + } + case CommunitiesModel::Roles::HasLoudNotification: { + auto end = spaceOrder_.lastChild(index.row() - 2); + for (int i = index.row() - 2; i <= end; i++) + if (spaceOrder_.tree[i].notificationCounts.highlight_count > 0) + return true; + return false; + } } } else if (index.row() - 2 < tags_.size() + spaceOrder_.size()) { auto tag = tags_.at(index.row() - 2 - spaceOrder_.size()); @@ -219,24 +207,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const return 0; case CommunitiesModel::Roles::Id: return "tag:" + tag; - case CommunitiesModel::Roles::UnreadMessages: { - int total{0}; - auto rooms{cache::joinedRooms()}; - for (const auto &[roomid, info] : cache::getRoomInfo(rooms)) - if (std::find(std::begin(info.tags), std::end(info.tags), tag.toStdString()) != - std::end(info.tags)) - total += info.notification_count; - return total; - } - case CommunitiesModel::Roles::HasLoudNotification: { - auto rooms{cache::joinedRooms()}; - for (const auto &[roomid, info] : cache::getRoomInfo(rooms)) - if (std::find(std::begin(info.tags), std::end(info.tags), tag.toStdString()) != - std::end(info.tags)) - if (info.highlight_count > 0) - return true; - return false; - } + case CommunitiesModel::Roles::UnreadMessages: + return (int)tagNotificationCache.at(tag).notification_count; + case CommunitiesModel::Roles::HasLoudNotification: + return (int)tagNotificationCache.at(tag).highlight_count > 0; } } return QVariant(); @@ -438,6 +412,72 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_) e)) { tagsUpdated = true; } + + auto roomId = QString::fromStdString(roomid); + auto oldUnreads = roomNotificationCache[roomId]; + int notificationCDiff = -static_cast(oldUnreads.highlight_count) + + static_cast(room.unread_notifications.highlight_count); + int highlightCDiff = -static_cast(oldUnreads.highlight_count) + + static_cast(room.unread_notifications.highlight_count); + if (highlightCDiff || notificationCDiff) { + // bool hidden = hiddenTagIds_.contains(roomId); + globalUnreads.notification_count += notificationCDiff; + globalUnreads.highlight_count += highlightCDiff; + emit dataChanged(index(0), + index(0), + { + UnreadMessages, + HasLoudNotification, + }); + if (std::find(begin(directMessages_), end(directMessages_), roomid) != + end(directMessages_)) { + dmUnreads.notification_count += notificationCDiff; + dmUnreads.highlight_count += highlightCDiff; + emit dataChanged(index(1), + index(1), + { + UnreadMessages, + HasLoudNotification, + }); + } + + auto spaces = cache::client()->getParentRoomIds(roomid); + auto tags = cache::singleRoomInfo(roomid).tags; + + for (const auto &t : tags) { + auto tagId = QString::fromStdString(t); + auto &tNs = tagNotificationCache[tagId]; + tNs.notification_count += notificationCDiff; + tNs.highlight_count += highlightCDiff; + int idx = tags_.indexOf(tagId) + 2 + spaceOrder_.size(); + ; + emit dataChanged(index(idx), + index(idx), + { + UnreadMessages, + HasLoudNotification, + }); + } + + for (const auto &s : spaces) { + auto spaceId = QString::fromStdString(s); + + for (int i = 0; i < spaceOrder_.size(); i++) { + spaceOrder_.tree[i].notificationCounts.notification_count += notificationCDiff; + spaceOrder_.tree[i].notificationCounts.highlight_count += highlightCDiff; + + int idx = i; + do { + emit dataChanged(index(idx + 2), + index(idx + 2), + { + UnreadMessages, + HasLoudNotification, + }); + } while (idx != -1); + } + } + } } for (const auto &[roomid, room] : sync_.rooms.leave) { (void)room; diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h index 5a659751..08269e21 100644 --- a/src/timeline/CommunitiesModel.h +++ b/src/timeline/CommunitiesModel.h @@ -22,7 +22,7 @@ class FilteredCommunitiesModel : public QSortFilterProxyModel Q_OBJECT public: - FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr); + explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr); bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override; }; @@ -59,7 +59,10 @@ public: struct Elem { QString id; - int depth = 0; + int depth = 0; + + mtx::responses::UnreadNotifications notificationCounts = {0, 0}; + bool collapsed = false; }; @@ -160,5 +163,10 @@ private: std::map spaces_; std::vector directMessages_; + std::unordered_map roomNotificationCache; + std::unordered_map tagNotificationCache; + mtx::responses::UnreadNotifications globalUnreads{}; + mtx::responses::UnreadNotifications dmUnreads{}; + friend class FilteredCommunitiesModel; }; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index db56ac52..9b48a878 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -364,25 +364,11 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj { this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString()); - auto roomInfo = cache::singleRoomInfo(room_id_.toStdString()); - this->isSpace_ = roomInfo.is_space; - this->notification_count = - isSpace_ ? utils::getChildNotificationsForSpace(room_id_).first : roomInfo.notification_count; - this->highlight_count = - isSpace_ ? utils::getChildNotificationsForSpace(room_id_).second : roomInfo.highlight_count; - lastMessage_.timestamp = roomInfo.approximate_last_modification_ts; - - // this connection will simplify adding the plainRoomNameChanged() signal everywhere that it - // needs to be - connect(this, &TimelineModel::roomNameChanged, this, &TimelineModel::plainRoomNameChanged); - - if (isSpace_) - connect(ChatPage::instance(), &ChatPage::unreadMessages, this, [this](int) { - auto temp{utils::getChildNotificationsForSpace(room_id_)}; - notification_count = temp.first; - highlight_count = temp.second; - emit notificationsChanged(); - }); + auto roomInfo = cache::singleRoomInfo(room_id_.toStdString()); + this->isSpace_ = roomInfo.is_space; + this->notification_count = roomInfo.notification_count; + this->highlight_count = roomInfo.highlight_count; + lastMessage_.timestamp = roomInfo.approximate_last_modification_ts; connect( this, diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 6d424981..47fd27f1 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -182,7 +182,7 @@ class TimelineModel : public QAbstractListModel bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged) Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) - Q_PROPERTY(QString plainRoomName READ plainRoomName NOTIFY plainRoomNameChanged) + Q_PROPERTY(QString plainRoomName READ plainRoomName NOTIFY roomNameChanged) Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged) Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) Q_PROPERTY(QStringList pinnedMessages READ pinnedMessages NOTIFY pinnedMessagesChanged) @@ -429,7 +429,6 @@ signals: void encryptionChanged(); void trustlevelChanged(); void roomNameChanged(); - void plainRoomNameChanged(); void roomTopicChanged(); void pinnedMessagesChanged(); void widgetLinksChanged();