Make notification count calculation more efficient

This commit is contained in:
Nicolas Werner 2022-07-16 03:07:00 +02:00
parent f76fd4ca83
commit 7b33d14277
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
6 changed files with 103 additions and 89 deletions

View File

@ -71,30 +71,20 @@ Page {
property color unimportantText: Nheko.colors.buttonText
property color bubbleBackground: Nheko.colors.highlight
property color bubbleText: Nheko.colors.highlightedText
required property string avatarUrl
required property string displayName
required property string tooltip
required property bool collapsed
required property bool collapsible
required property bool hidden
required property int depth
required property string id
required property int unreadMessages
required property bool hasLoudNotification
required property bool muted
required property var model
height: avatarSize + 2 * Nheko.paddingMedium
width: ListView.view.width
state: "normal"
ToolTip.visible: hovered && collapsed
ToolTip.text: communityItem.tooltip
ToolTip.text: model.tooltip
ToolTip.delay: Nheko.tooltipDelay
onClicked: Communities.setCurrentTagId(communityItem.id)
onPressAndHold: communityContextMenu.show(communityItem.id, communityItem.hidden, communityItem.muted)
onClicked: Communities.setCurrentTagId(model.id)
onPressAndHold: communityContextMenu.show(model.id, model.hidden, model.muted)
states: [
State {
name: "highlight"
when: (communityItem.hovered || communityItem.hidden) && !(Communities.currentTagId === communityItem.id)
when: (communityItem.hovered || model.hidden) && !(Communities.currentTagId === model.id)
PropertyChanges {
target: communityItem
@ -108,7 +98,7 @@ Page {
},
State {
name: "selected"
when: Communities.currentTagId == communityItem.id
when: Communities.currentTagId == model.id
PropertyChanges {
target: communityItem
@ -127,7 +117,7 @@ Page {
TapHandler {
acceptedButtons: Qt.RightButton
onSingleTapped: communityContextMenu.show(communityItem.id, communityItem.hidden, communityItem.muted)
onSingleTapped: communityContextMenu.show(model.id, model.hidden, model.muted)
gesturePolicy: TapHandler.ReleaseWithinBounds
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
}
@ -139,27 +129,27 @@ Page {
spacing: Nheko.paddingMedium
anchors.fill: parent
anchors.margins: Nheko.paddingMedium
anchors.leftMargin: Nheko.paddingMedium + (communitySidebar.collapsed ? 0 : (fontMetrics.lineSpacing * communityItem.depth))
anchors.leftMargin: Nheko.paddingMedium + (communitySidebar.collapsed ? 0 : (fontMetrics.lineSpacing * model.depth))
ImageButton {
visible: !communitySidebar.collapsed && communityItem.collapsible
visible: !communitySidebar.collapsed && model.collapsible
Layout.preferredHeight: fontMetrics.lineSpacing
Layout.preferredWidth: fontMetrics.lineSpacing
Layout.alignment: Qt.AlignVCenter
height: fontMetrics.lineSpacing
width: fontMetrics.lineSpacing
image: communityItem.collapsed ? ":/icons/icons/ui/collapsed.svg" : ":/icons/icons/ui/expanded.svg"
image: model.collapsed ? ":/icons/icons/ui/collapsed.svg" : ":/icons/icons/ui/expanded.svg"
ToolTip.visible: hovered
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: communityItem.collapsed ? qsTr("Expand") : qsTr("Collapse")
ToolTip.text: model.collapsed ? qsTr("Expand") : qsTr("Collapse")
hoverEnabled: true
onClicked: communityItem.collapsed = !communityItem.collapsed
onClicked: model.collapsed = !model.collapsed
}
Item {
Layout.preferredWidth: fontMetrics.lineSpacing
visible: !communitySidebar.collapsed && !communityItem.collapsible && Communities.containsSubspaces
visible: !communitySidebar.collapsed && !model.collapsible && Communities.containsSubspaces
}
Avatar {
@ -170,22 +160,22 @@ Page {
height: avatarSize
width: avatarSize
url: {
if (communityItem.avatarUrl.startsWith("mxc://"))
return communityItem.avatarUrl.replace("mxc://", "image://MxcImage/");
if (model.avatarUrl.startsWith("mxc://"))
return model.avatarUrl.replace("mxc://", "image://MxcImage/");
else
return "image://colorimage/" + communityItem.avatarUrl + "?" + communityItem.unimportantText;
return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText;
}
roomid: communityItem.id
displayName: communityItem.displayName
roomid: model.id
displayName: model.displayName
color: communityItem.backgroundColor
NotificationBubble {
notificationCount: communityItem.unreadMessages
hasLoudNotification: communityItem.hasLoudNotification
notificationCount: model.unreadMessages
hasLoudNotification: model.hasLoudNotification
bubbleBackgroundColor: communityItem.bubbleBackground
bubbleTextColor: communityItem.bubbleText
font.pixelSize: fontMetrics.font.pixelSize * 0.6
mayBeVisible: communitySidebar.collapsed && !communityItem.muted && Settings.spaceNotifications
mayBeVisible: communitySidebar.collapsed && !model.muted && Settings.spaceNotifications
anchors.right: avatar.right
anchors.bottom: avatar.bottom
anchors.margins: -Nheko.paddingSmall
@ -199,7 +189,7 @@ Page {
color: communityItem.importantText
Layout.fillWidth: true
elideWidth: width
fullText: communityItem.displayName
fullText: model.displayName
textFormat: Text.PlainText
}
@ -208,11 +198,11 @@ Page {
}
NotificationBubble {
notificationCount: communityItem.unreadMessages
hasLoudNotification: communityItem.hasLoudNotification
notificationCount: model.unreadMessages
hasLoudNotification: model.hasLoudNotification
bubbleBackgroundColor: communityItem.bubbleBackground
bubbleTextColor: communityItem.bubbleText
mayBeVisible: !communitySidebar.collapsed && !communityItem.muted && Settings.spaceNotifications
mayBeVisible: !communitySidebar.collapsed && !model.muted && Settings.spaceNotifications
Layout.alignment: Qt.AlignRight
Layout.leftMargin: Nheko.paddingSmall
}

View File

@ -881,21 +881,3 @@ utils::markRoomAsDirect(QString roomid, std::vector<RoomMember> members)
});
});
}
QPair<int, int>
utils::getChildNotificationsForSpace(const QString &spaceId)
{
auto children = cache::getRoomInfo(cache::client()->getChildRoomIds(spaceId.toStdString()));
QPair<int, int> retVal;
for (const auto &[childId, child] : children) {
if (child.is_space) {
auto temp{utils::getChildNotificationsForSpace(childId)};
retVal.first += temp.first;
retVal.second += temp.second;
} else {
retVal.first += child.notification_count;
retVal.second += child.highlight_count;
}
}
return retVal;
}

View File

@ -311,9 +311,4 @@ removeDirectFromRoom(QString roomid);
void
markRoomAsDirect(QString roomid, std::vector<RoomMember> members);
//! Returns a pair of integers representing the unread notifications in a space and how many of them
//! are loud notifications, respectively.
QPair<int, int>
getChildNotificationsForSpace(const QString &spaceId);
}

View File

@ -208,9 +208,15 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
case CommunitiesModel::Roles::Id:
return "tag:" + tag;
case CommunitiesModel::Roles::UnreadMessages:
return (int)tagNotificationCache.at(tag).notification_count;
if (auto it = tagNotificationCache.find(tag); it != tagNotificationCache.end())
return (int)it->second.notification_count;
else
return 0;
case CommunitiesModel::Roles::HasLoudNotification:
return (int)tagNotificationCache.at(tag).highlight_count > 0;
if (auto it = tagNotificationCache.find(tag); it != tagNotificationCache.end())
return it->second.highlight_count > 0;
else
return 0;
}
}
return QVariant();
@ -265,6 +271,21 @@ CommunitiesModel::initializeSidebar()
tags_.clear();
spaceOrder_.tree.clear();
spaces_.clear();
tagNotificationCache.clear();
globalUnreads.notification_count = {};
dmUnreads.notification_count = {};
auto e = cache::client()->getAccountData(mtx::events::EventType::Direct);
if (e) {
if (auto event =
std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(
&e.value())) {
directMessages_.clear();
for (const auto &[userId, roomIds] : event->content.user_to_rooms)
for (const auto &roomId : roomIds)
directMessages_.push_back(roomId);
}
}
std::set<std::string> ts;
@ -284,6 +305,19 @@ CommunitiesModel::initializeSidebar()
}
}
}
for (const auto &t : it->tags) {
auto tagId = QString::fromStdString(t);
auto &tNs = tagNotificationCache[tagId];
tNs.notification_count += it->notification_count;
tNs.highlight_count += it->highlight_count;
}
auto &e = roomNotificationCache[it.key()];
e.highlight_count = it->highlight_count;
e.notification_count = it->notification_count;
globalUnreads.notification_count += it->notification_count;
globalUnreads.highlight_count += it->highlight_count;
}
// NOTE(Nico): We build a forrest from the Directed Cyclic(!) Graph of spaces. To do that we
@ -319,6 +353,14 @@ CommunitiesModel::initializeSidebar()
spaceOrder_.restoreCollapsed();
for (auto &space : spaceOrder_.tree) {
for (const auto &c : cache::client()->getChildRoomIds(space.id.toStdString())) {
const auto &counts = roomNotificationCache[QString::fromStdString(c)];
space.notificationCounts.highlight_count += counts.highlight_count;
space.notificationCounts.notification_count += counts.notification_count;
}
}
endResetModel();
emit tagsChanged();
@ -413,16 +455,21 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
tagsUpdated = true;
}
auto roomId = QString::fromStdString(roomid);
auto oldUnreads = roomNotificationCache[roomId];
int notificationCDiff = -static_cast<int64_t>(oldUnreads.highlight_count) +
static_cast<int64_t>(room.unread_notifications.highlight_count);
int highlightCDiff = -static_cast<int64_t>(oldUnreads.highlight_count) +
static_cast<int64_t>(room.unread_notifications.highlight_count);
auto roomId = QString::fromStdString(roomid);
auto &oldUnreads = roomNotificationCache[roomId];
auto notificationCDiff = -static_cast<int64_t>(oldUnreads.notification_count) +
static_cast<int64_t>(room.unread_notifications.notification_count);
auto highlightCDiff = -static_cast<int64_t>(oldUnreads.highlight_count) +
static_cast<int64_t>(room.unread_notifications.highlight_count);
auto applyDiff = [notificationCDiff,
highlightCDiff](mtx::responses::UnreadNotifications &n) {
n.highlight_count = static_cast<int64_t>(n.highlight_count) + highlightCDiff;
n.notification_count = static_cast<int64_t>(n.notification_count) + notificationCDiff;
};
if (highlightCDiff || notificationCDiff) {
// bool hidden = hiddenTagIds_.contains(roomId);
globalUnreads.notification_count += notificationCDiff;
globalUnreads.highlight_count += highlightCDiff;
applyDiff(globalUnreads);
emit dataChanged(index(0),
index(0),
{
@ -431,8 +478,7 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
});
if (std::find(begin(directMessages_), end(directMessages_), roomid) !=
end(directMessages_)) {
dmUnreads.notification_count += notificationCDiff;
dmUnreads.highlight_count += highlightCDiff;
applyDiff(dmUnreads);
emit dataChanged(index(1),
index(1),
{
@ -446,11 +492,8 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
for (const auto &t : tags) {
auto tagId = QString::fromStdString(t);
auto &tNs = tagNotificationCache[tagId];
tNs.notification_count += notificationCDiff;
tNs.highlight_count += highlightCDiff;
applyDiff(tagNotificationCache[tagId]);
int idx = tags_.indexOf(tagId) + 2 + spaceOrder_.size();
;
emit dataChanged(index(idx),
index(idx),
{
@ -463,8 +506,10 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
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;
if (spaceOrder_.tree[i].id != spaceId)
continue;
applyDiff(spaceOrder_.tree[i].notificationCounts);
int idx = i;
do {
@ -474,10 +519,13 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
UnreadMessages,
HasLoudNotification,
});
idx = spaceOrder_.parent(idx);
} while (idx != -1);
}
}
}
roomNotificationCache[roomId] = room.unread_notifications;
}
for (const auto &[roomid, room] : sync_.rooms.leave) {
(void)room;

View File

@ -642,15 +642,18 @@ RoomlistModel::clear()
}
void
RoomlistModel::joinPreview(QString roomid, QString parentSpace)
RoomlistModel::joinPreview(QString roomid)
{
if (previewedRooms.contains(roomid)) {
auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>(
parentSpace.toStdString(), roomid.toStdString());
ChatPage::instance()->joinRoomVia(
roomid.toStdString(),
(child && child->content.via) ? child->content.via.value() : std::vector<std::string>{},
false);
std::vector<std::string> vias;
auto parents = cache::client()->getParentRoomIds(roomid.toStdString());
for (const auto &p : parents) {
auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>(
p, roomid.toStdString());
if (child && child->content.via)
vias.insert(vias.end(), child->content.via->begin(), child->content.via->end());
}
ChatPage::instance()->joinRoomVia(roomid.toStdString(), vias, false);
}
}
void

View File

@ -105,7 +105,7 @@ public slots:
return -1;
}
void joinPreview(QString roomid, QString parentSpace);
void joinPreview(QString roomid);
void acceptInvite(QString roomid);
void declineInvite(QString roomid);
void leave(QString roomid, QString reason = "");
@ -169,11 +169,7 @@ public slots:
{
return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid))).row();
}
void joinPreview(QString roomid)
{
roomlistmodel->joinPreview(roomid,
filterType == FilterBy::Space ? filterStr : QLatin1String(""));
}
void joinPreview(QString roomid) { roomlistmodel->joinPreview(roomid); }
void acceptInvite(QString roomid) { roomlistmodel->acceptInvite(roomid); }
void declineInvite(QString roomid) { roomlistmodel->declineInvite(roomid); }
void leave(QString roomid, QString reason = "") { roomlistmodel->leave(roomid, reason); }