Merge pull request #1062 from Nheko-Reborn/perSpaceNotifs

Per-space notification bubbles
This commit is contained in:
DeepBlueV7.X 2022-07-16 01:10:07 +00:00 committed by GitHub
commit f62cb77680
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 421 additions and 124 deletions

View file

@ -3,6 +3,7 @@
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import "./components"
import "./dialogs" import "./dialogs"
import Qt.labs.platform 1.1 as Platform import Qt.labs.platform 1.1 as Platform
import QtQml 2.12 import QtQml 2.12
@ -36,14 +37,27 @@ Page {
id: communityContextMenu id: communityContextMenu
property string tagId property string tagId
property bool hidden
property bool muted
function show(id_, tags_) { function show(id_, hidden_, muted_) {
tagId = id_; tagId = id_;
hidden = hidden_;
muted = muted_;
open(); open();
} }
Platform.MenuItem {
text: qsTr("Do not show notification counts for this space or tag.")
checkable: true
checked: communityContextMenu.muted
onTriggered: Communities.toggleTagMute(communityContextMenu.tagId)
}
Platform.MenuItem { Platform.MenuItem {
text: qsTr("Hide rooms with this tag or from this space by default.") text: qsTr("Hide rooms with this tag or from this space by default.")
checkable: true
checked: communityContextMenu.hidden
onTriggered: Communities.toggleTagId(communityContextMenu.tagId) onTriggered: Communities.toggleTagId(communityContextMenu.tagId)
} }
@ -57,6 +71,7 @@ Page {
property color unimportantText: Nheko.colors.buttonText property color unimportantText: Nheko.colors.buttonText
property color bubbleBackground: Nheko.colors.highlight property color bubbleBackground: Nheko.colors.highlight
property color bubbleText: Nheko.colors.highlightedText property color bubbleText: Nheko.colors.highlightedText
required property var model
height: avatarSize + 2 * Nheko.paddingMedium height: avatarSize + 2 * Nheko.paddingMedium
width: ListView.view.width width: ListView.view.width
@ -65,11 +80,11 @@ Page {
ToolTip.text: model.tooltip ToolTip.text: model.tooltip
ToolTip.delay: Nheko.tooltipDelay ToolTip.delay: Nheko.tooltipDelay
onClicked: Communities.setCurrentTagId(model.id) onClicked: Communities.setCurrentTagId(model.id)
onPressAndHold: communityContextMenu.show(model.id) onPressAndHold: communityContextMenu.show(model.id, model.hidden, model.muted)
states: [ states: [
State { State {
name: "highlight" name: "highlight"
when: (communityItem.hovered || model.hidden) && !(Communities.currentTagId == model.id) when: (communityItem.hovered || model.hidden) && !(Communities.currentTagId === model.id)
PropertyChanges { PropertyChanges {
target: communityItem target: communityItem
@ -102,7 +117,7 @@ Page {
TapHandler { TapHandler {
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onSingleTapped: communityContextMenu.show(model.id) onSingleTapped: communityContextMenu.show(model.id, model.hidden, model.muted)
gesturePolicy: TapHandler.ReleaseWithinBounds gesturePolicy: TapHandler.ReleaseWithinBounds
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
} }
@ -153,6 +168,19 @@ Page {
roomid: model.id roomid: model.id
displayName: model.displayName displayName: model.displayName
color: communityItem.backgroundColor color: communityItem.backgroundColor
NotificationBubble {
notificationCount: model.unreadMessages
hasLoudNotification: model.hasLoudNotification
bubbleBackgroundColor: communityItem.bubbleBackground
bubbleTextColor: communityItem.bubbleText
font.pixelSize: fontMetrics.font.pixelSize * 0.6
mayBeVisible: communitySidebar.collapsed && !model.muted && Settings.spaceNotifications
anchors.right: avatar.right
anchors.bottom: avatar.bottom
anchors.margins: -Nheko.paddingSmall
}
} }
ElidedLabel { ElidedLabel {
@ -169,10 +197,20 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
} }
NotificationBubble {
notificationCount: model.unreadMessages
hasLoudNotification: model.hasLoudNotification
bubbleBackgroundColor: communityItem.bubbleBackground
bubbleTextColor: communityItem.bubbleText
mayBeVisible: !communitySidebar.collapsed && !model.muted && Settings.spaceNotifications
Layout.alignment: Qt.AlignRight
Layout.leftMargin: Nheko.paddingSmall
}
} }
background: Rectangle { background: Rectangle {
color: backgroundColor color: communityItem.backgroundColor
} }
} }

View file

@ -3,6 +3,7 @@
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import "./components"
import "./dialogs" import "./dialogs"
import "./ui" import "./ui"
import Qt.labs.platform 1.1 as Platform import Qt.labs.platform 1.1 as Platform
@ -294,9 +295,6 @@ Page {
anchors.margins: Nheko.paddingMedium anchors.margins: Nheko.paddingMedium
Avatar { Avatar {
// In the future we could show an online indicator by setting the userid for the avatar
//userid: Nheko.currentUser.userid
id: avatar id: avatar
enabled: false enabled: false
@ -308,33 +306,17 @@ Page {
userid: isDirect ? directChatOtherUserId : "" userid: isDirect ? directChatOtherUserId : ""
roomid: roomId roomid: roomId
Rectangle { NotificationBubble {
id: collapsedNotificationBubble id: collapsedNotificationBubble
notificationCount: roomItem.notificationCount
hasLoudNotification: roomItem.hasLoudNotification
bubbleBackgroundColor: roomItem.bubbleBackground
bubbleTextColor: roomItem.bubbleText
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.margins: -Nheko.paddingSmall anchors.margins: -Nheko.paddingSmall
visible: collapsed && notificationCount > 0 mayBeVisible: collapsed && (isSpace ? Settings.spaceNotifications : true)
enabled: false
Layout.alignment: Qt.AlignRight
height: fontMetrics.averageCharacterWidth * 3
width: Math.max(collapsedBubbleText.width, height)
radius: height / 2
color: hasLoudNotification ? Nheko.theme.red : roomItem.bubbleBackground
Label {
id: collapsedBubbleText
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: Math.max(implicitWidth + Nheko.paddingMedium, parent.height)
font.bold: true
font.pixelSize: fontMetrics.font.pixelSize * 0.8
color: hasLoudNotification ? "white" : roomItem.bubbleText
text: notificationCount > 9999 ? "9999+" : notificationCount
}
} }
} }
@ -351,7 +333,24 @@ Page {
height: avatar.height height: avatar.height
spacing: Nheko.paddingSmall spacing: Nheko.paddingSmall
NotificationBubble {
id: notificationBubble
parent: isSpace ? titleRow : subtextRow
notificationCount: roomItem.notificationCount
hasLoudNotification: roomItem.hasLoudNotification
bubbleBackgroundColor: roomItem.bubbleBackground
bubbleTextColor: roomItem.bubbleText
Layout.alignment: Qt.AlignRight
Layout.leftMargin: Nheko.paddingSmall
Layout.preferredWidth: implicitWidth
Layout.preferredHeight: implicitHeight
mayBeVisible: !collapsed && (isSpace ? Settings.spaceNotifications : true)
}
RowLayout { RowLayout {
id: titleRow
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.fillWidth: true Layout.fillWidth: true
spacing: Nheko.paddingSmall spacing: Nheko.paddingSmall
@ -380,6 +379,8 @@ Page {
} }
RowLayout { RowLayout {
id: subtextRow
Layout.fillWidth: true Layout.fillWidth: true
spacing: 0 spacing: 0
visible: !isSpace visible: !isSpace
@ -395,40 +396,6 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
} }
Rectangle {
id: notificationBubble
visible: notificationCount > 0
Layout.alignment: Qt.AlignRight
Layout.leftMargin: Nheko.paddingSmall
height: notificationBubbleText.height + Nheko.paddingMedium
Layout.preferredWidth: Math.max(notificationBubbleText.width, height)
radius: height / 2
color: hasLoudNotification ? Nheko.theme.red : roomItem.bubbleBackground
ToolTip.text: notificationCount
ToolTip.delay: Nheko.tooltipDelay
ToolTip.visible: notificationBubbleHover.hovered && (notificationCount > 9999)
Label {
id: notificationBubbleText
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: Math.max(implicitWidth + Nheko.paddingMedium, parent.height)
font.bold: true
font.pixelSize: fontMetrics.font.pixelSize * 0.8
color: hasLoudNotification ? "white" : roomItem.bubbleText
text: notificationCount > 9999 ? "9999+" : notificationCount
HoverHandler {
id: notificationBubbleHover
}
}
}
} }
} }

View file

@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick 2.15
import QtQuick.Controls 2.15
import im.nheko 1.0
Rectangle {
id: bubbleRoot
required property int notificationCount
required property bool hasLoudNotification
required property color bubbleBackgroundColor
required property color bubbleTextColor
property bool mayBeVisible: true
property alias font: notificationBubbleText.font
visible: mayBeVisible && notificationCount > 0
implicitHeight: notificationBubbleText.height + Nheko.paddingMedium
implicitWidth: Math.max(notificationBubbleText.width, height)
radius: height / 2
color: hasLoudNotification ? Nheko.theme.red : bubbleBackgroundColor
ToolTip.text: notificationCount
ToolTip.delay: Nheko.tooltipDelay
ToolTip.visible: notificationBubbleHover.hovered && (notificationCount > 9999)
Label {
id: notificationBubbleText
anchors.centerIn: bubbleRoot
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: Math.max(implicitWidth + Nheko.paddingMedium, bubbleRoot.height)
font.bold: true
font.pixelSize: fontMetrics.font.pixelSize * 0.8
color: bubbleRoot.hasLoudNotification ? "white" : bubbleRoot.bubbleTextColor
text: bubbleRoot.notificationCount > 9999 ? "9999+" : bubbleRoot.notificationCount
HoverHandler {
id: notificationBubbleHover
}
}
}

View file

@ -185,6 +185,7 @@
<file>qml/voip/PlaceCall.qml</file> <file>qml/voip/PlaceCall.qml</file>
<file>qml/voip/ScreenShare.qml</file> <file>qml/voip/ScreenShare.qml</file>
<file>qml/voip/VideoCall.qml</file> <file>qml/voip/VideoCall.qml</file>
<file>qml/components/NotificationBubble.qml</file>
</qresource> </qresource>
<qresource prefix="/media"> <qresource prefix="/media">
<file>media/ring.ogg</file> <file>media/ring.ogg</file>

View file

@ -88,6 +88,7 @@ UserSettings::load(std::optional<QString> profile)
openImageExternal_ = settings.value(QStringLiteral("user/open_image_external"), false).toBool(); openImageExternal_ = settings.value(QStringLiteral("user/open_image_external"), false).toBool();
openVideoExternal_ = settings.value(QStringLiteral("user/open_video_external"), false).toBool(); openVideoExternal_ = settings.value(QStringLiteral("user/open_video_external"), false).toBool();
decryptSidebar_ = settings.value(QStringLiteral("user/decrypt_sidebar"), true).toBool(); decryptSidebar_ = settings.value(QStringLiteral("user/decrypt_sidebar"), true).toBool();
spaceNotifications_ = settings.value(QStringLiteral("user/space_notifications"), true).toBool();
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool(); privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
privacyScreenTimeout_ = privacyScreenTimeout_ =
settings.value(QStringLiteral("user/privacy_screen_timeout"), 0).toInt(); settings.value(QStringLiteral("user/privacy_screen_timeout"), 0).toInt();
@ -132,6 +133,7 @@ UserSettings::load(std::optional<QString> profile)
userId_ = settings.value(prefix + "auth/user_id", "").toString(); userId_ = settings.value(prefix + "auth/user_id", "").toString();
deviceId_ = settings.value(prefix + "auth/device_id", "").toString(); deviceId_ = settings.value(prefix + "auth/device_id", "").toString();
hiddenTags_ = settings.value(prefix + "user/hidden_tags", QStringList{}).toStringList(); hiddenTags_ = settings.value(prefix + "user/hidden_tags", QStringList{}).toStringList();
mutedTags_ = settings.value(prefix + "user/muted_tags", QStringList{"global"}).toStringList();
hiddenPins_ = settings.value(prefix + "user/hidden_pins", QStringList{}).toStringList(); hiddenPins_ = settings.value(prefix + "user/hidden_pins", QStringList{}).toStringList();
hiddenWidgets_ = settings.value(prefix + "user/hidden_widgets", QStringList{}).toStringList(); hiddenWidgets_ = settings.value(prefix + "user/hidden_widgets", QStringList{}).toStringList();
recentReactions_ = recentReactions_ =
@ -220,14 +222,21 @@ UserSettings::setGroupView(bool state)
} }
void void
UserSettings::setHiddenTags(QStringList hiddenTags) UserSettings::setHiddenTags(const QStringList &hiddenTags)
{ {
hiddenTags_ = hiddenTags; hiddenTags_ = hiddenTags;
save(); save();
} }
void void
UserSettings::setHiddenPins(QStringList hiddenTags) UserSettings::setMutedTags(const QStringList &mutedTags)
{
mutedTags_ = mutedTags;
save();
}
void
UserSettings::setHiddenPins(const QStringList &hiddenTags)
{ {
hiddenPins_ = hiddenTags; hiddenPins_ = hiddenTags;
save(); save();
@ -235,7 +244,7 @@ UserSettings::setHiddenPins(QStringList hiddenTags)
} }
void void
UserSettings::setHiddenWidgets(QStringList hiddenTags) UserSettings::setHiddenWidgets(const QStringList &hiddenTags)
{ {
hiddenWidgets_ = hiddenTags; hiddenWidgets_ = hiddenTags;
save(); save();
@ -416,6 +425,16 @@ UserSettings::setDecryptSidebar(bool state)
save(); save();
} }
void
UserSettings::setSpaceNotifications(bool state)
{
if (state == spaceNotifications_)
return;
spaceNotifications_ = state;
emit spaceNotificationsChanged(state);
save();
}
void void
UserSettings::setPrivacyScreen(bool state) UserSettings::setPrivacyScreen(bool state)
{ {
@ -777,6 +796,7 @@ UserSettings::save()
settings.setValue(QStringLiteral("avatar_circles"), avatarCircles_); settings.setValue(QStringLiteral("avatar_circles"), avatarCircles_);
settings.setValue(QStringLiteral("decrypt_sidebar"), decryptSidebar_); settings.setValue(QStringLiteral("decrypt_sidebar"), decryptSidebar_);
settings.setValue(QStringLiteral("space_notifications"), spaceNotifications_);
settings.setValue(QStringLiteral("privacy_screen"), privacyScreen_); settings.setValue(QStringLiteral("privacy_screen"), privacyScreen_);
settings.setValue(QStringLiteral("privacy_screen_timeout"), privacyScreenTimeout_); settings.setValue(QStringLiteral("privacy_screen_timeout"), privacyScreenTimeout_);
settings.setValue(QStringLiteral("mobile_mode"), mobileMode_); settings.setValue(QStringLiteral("mobile_mode"), mobileMode_);
@ -830,6 +850,7 @@ UserSettings::save()
onlyShareKeysWithVerifiedUsers_); onlyShareKeysWithVerifiedUsers_);
settings.setValue(prefix + "user/online_key_backup", useOnlineKeyBackup_); settings.setValue(prefix + "user/online_key_backup", useOnlineKeyBackup_);
settings.setValue(prefix + "user/hidden_tags", hiddenTags_); settings.setValue(prefix + "user/hidden_tags", hiddenTags_);
settings.setValue(prefix + "user/muted_tags", mutedTags_);
settings.setValue(prefix + "user/hidden_pins", hiddenPins_); settings.setValue(prefix + "user/hidden_pins", hiddenPins_);
settings.setValue(prefix + "user/hidden_widgets", hiddenWidgets_); settings.setValue(prefix + "user/hidden_widgets", hiddenWidgets_);
settings.setValue(prefix + "user/recent_reactions", recentReactions_); settings.setValue(prefix + "user/recent_reactions", recentReactions_);
@ -923,6 +944,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
return tr("Open videos with external program"); return tr("Open videos with external program");
case DecryptSidebar: case DecryptSidebar:
return tr("Decrypt messages in sidebar"); return tr("Decrypt messages in sidebar");
case SpaceNotifications:
return tr("Show message counts for spaces");
case PrivacyScreen: case PrivacyScreen:
return tr("Privacy Screen"); return tr("Privacy Screen");
case PrivacyScreenTimeout: case PrivacyScreenTimeout:
@ -1053,6 +1076,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
return i->openVideoExternal(); return i->openVideoExternal();
case DecryptSidebar: case DecryptSidebar:
return i->decryptSidebar(); return i->decryptSidebar();
case SpaceNotifications:
return i->spaceNotifications();
case PrivacyScreen: case PrivacyScreen:
return i->privacyScreen(); return i->privacyScreen();
case PrivacyScreenTimeout: case PrivacyScreenTimeout:
@ -1208,6 +1233,9 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
case DecryptSidebar: case DecryptSidebar:
return tr("Decrypt the messages shown in the sidebar.\nOnly affects messages in " return tr("Decrypt the messages shown in the sidebar.\nOnly affects messages in "
"encrypted chats."); "encrypted chats.");
case SpaceNotifications:
return tr(
"Choose where to show the total number of notifications contained within a space.");
case PrivacyScreen: case PrivacyScreen:
return tr("When the window loses focus, the timeline will\nbe blurred."); return tr("When the window loses focus, the timeline will\nbe blurred.");
case MobileMode: case MobileMode:
@ -1317,6 +1345,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
case ShareKeysWithTrustedUsers: case ShareKeysWithTrustedUsers:
case UseOnlineKeyBackup: case UseOnlineKeyBackup:
case ExposeDBusApi: case ExposeDBusApi:
case SpaceNotifications:
return Toggle; return Toggle;
case Profile: case Profile:
case UserId: case UserId:
@ -1409,7 +1438,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
return fontDb.families(); return fontDb.families();
case EmojiFont: case EmojiFont:
return fontDb.families(QFontDatabase::WritingSystem::Symbol); return fontDb.families(QFontDatabase::WritingSystem::Symbol);
case Ringtone: case Ringtone: {
QStringList l{ QStringList l{
QStringLiteral("Mute"), QStringLiteral("Mute"),
QStringLiteral("Default"), QStringLiteral("Default"),
@ -1419,6 +1448,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
l.push_back(i->ringtone()); l.push_back(i->ringtone());
return l; return l;
} }
}
} else if (role == Good) { } else if (role == Good) {
switch (index.row()) { switch (index.row()) {
case OnlineBackupKey: case OnlineBackupKey:
@ -1624,6 +1654,13 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int
return false; return false;
} }
return i->decryptSidebar(); return i->decryptSidebar();
case SpaceNotifications: {
if (value.userType() == QMetaType::Bool) {
i->setSpaceNotifications(value.toBool());
return true;
} else
return false;
}
case PrivacyScreen: { case PrivacyScreen: {
if (value.userType() == QMetaType::Bool) { if (value.userType() == QMetaType::Bool) {
i->setPrivacyScreen(value.toBool()); i->setPrivacyScreen(value.toBool());
@ -1936,7 +1973,9 @@ UserSettingsModel::UserSettingsModel(QObject *p)
connect(s.get(), &UserSettings::decryptSidebarChanged, this, [this]() { connect(s.get(), &UserSettings::decryptSidebarChanged, this, [this]() {
emit dataChanged(index(DecryptSidebar), index(DecryptSidebar), {Value}); emit dataChanged(index(DecryptSidebar), index(DecryptSidebar), {Value});
}); });
connect(s.get(), &UserSettings::spaceNotificationsChanged, this, [this] {
emit dataChanged(index(SpaceNotifications), index(SpaceNotifications), {Value});
});
connect(s.get(), &UserSettings::trayChanged, this, [this]() { connect(s.get(), &UserSettings::trayChanged, this, [this]() {
emit dataChanged(index(Tray), index(Tray), {Value}); emit dataChanged(index(Tray), index(Tray), {Value});
emit dataChanged(index(StartInTray), index(StartInTray), {Enabled}); emit dataChanged(index(StartInTray), index(StartInTray), {Enabled});

View file

@ -58,6 +58,8 @@ class UserSettings : public QObject
bool avatarCircles READ avatarCircles WRITE setAvatarCircles NOTIFY avatarCirclesChanged) bool avatarCircles READ avatarCircles WRITE setAvatarCircles NOTIFY avatarCirclesChanged)
Q_PROPERTY( Q_PROPERTY(
bool decryptSidebar READ decryptSidebar WRITE setDecryptSidebar NOTIFY decryptSidebarChanged) bool decryptSidebar READ decryptSidebar WRITE setDecryptSidebar NOTIFY decryptSidebarChanged)
Q_PROPERTY(bool spaceNotifications READ spaceNotifications WRITE setSpaceNotifications NOTIFY
spaceNotificationsChanged)
Q_PROPERTY( Q_PROPERTY(
bool privacyScreen READ privacyScreen WRITE setPrivacyScreen NOTIFY privacyScreenChanged) bool privacyScreen READ privacyScreen WRITE setPrivacyScreen NOTIFY privacyScreenChanged)
Q_PROPERTY(int privacyScreenTimeout READ privacyScreenTimeout WRITE setPrivacyScreenTimeout Q_PROPERTY(int privacyScreenTimeout READ privacyScreenTimeout WRITE setPrivacyScreenTimeout
@ -162,6 +164,7 @@ public:
void setAlertOnNotification(bool state); void setAlertOnNotification(bool state);
void setAvatarCircles(bool state); void setAvatarCircles(bool state);
void setDecryptSidebar(bool state); void setDecryptSidebar(bool state);
void setSpaceNotifications(bool state);
void setPrivacyScreen(bool state); void setPrivacyScreen(bool state);
void setPrivacyScreenTimeout(int state); void setPrivacyScreenTimeout(int state);
void setPresence(Presence state); void setPresence(Presence state);
@ -184,9 +187,10 @@ public:
void setDeviceId(QString deviceId); void setDeviceId(QString deviceId);
void setHomeserver(QString homeserver); void setHomeserver(QString homeserver);
void setDisableCertificateValidation(bool disabled); void setDisableCertificateValidation(bool disabled);
void setHiddenTags(QStringList hiddenTags); void setHiddenTags(const QStringList &hiddenTags);
void setHiddenPins(QStringList hiddenTags); void setMutedTags(const QStringList &mutedTags);
void setHiddenWidgets(QStringList hiddenTags); void setHiddenPins(const QStringList &hiddenTags);
void setHiddenWidgets(const QStringList &hiddenTags);
void setRecentReactions(QStringList recent); void setRecentReactions(QStringList recent);
void setUseIdenticon(bool state); void setUseIdenticon(bool state);
void setOpenImageExternal(bool state); void setOpenImageExternal(bool state);
@ -202,6 +206,7 @@ public:
bool groupView() const { return groupView_; } bool groupView() const { return groupView_; }
bool avatarCircles() const { return avatarCircles_; } bool avatarCircles() const { return avatarCircles_; }
bool decryptSidebar() const { return decryptSidebar_; } bool decryptSidebar() const { return decryptSidebar_; }
bool spaceNotifications() const { return spaceNotifications_; }
bool privacyScreen() const { return privacyScreen_; } bool privacyScreen() const { return privacyScreen_; }
int privacyScreenTimeout() const { return privacyScreenTimeout_; } int privacyScreenTimeout() const { return privacyScreenTimeout_; }
bool markdown() const { return markdown_; } bool markdown() const { return markdown_; }
@ -250,6 +255,7 @@ public:
QString homeserver() const { return homeserver_; } QString homeserver() const { return homeserver_; }
bool disableCertificateValidation() const { return disableCertificateValidation_; } bool disableCertificateValidation() const { return disableCertificateValidation_; }
QStringList hiddenTags() const { return hiddenTags_; } QStringList hiddenTags() const { return hiddenTags_; }
QStringList mutedTags() const { return mutedTags_; }
QStringList hiddenPins() const { return hiddenPins_; } QStringList hiddenPins() const { return hiddenPins_; }
QStringList hiddenWidgets() const { return hiddenWidgets_; } QStringList hiddenWidgets() const { return hiddenWidgets_; }
QStringList recentReactions() const { return recentReactions_; } QStringList recentReactions() const { return recentReactions_; }
@ -278,6 +284,7 @@ signals:
void alertOnNotificationChanged(bool state); void alertOnNotificationChanged(bool state);
void avatarCirclesChanged(bool state); void avatarCirclesChanged(bool state);
void decryptSidebarChanged(bool state); void decryptSidebarChanged(bool state);
void spaceNotificationsChanged(bool state);
void privacyScreenChanged(bool state); void privacyScreenChanged(bool state);
void privacyScreenTimeoutChanged(int state); void privacyScreenTimeoutChanged(int state);
void timelineMaxWidthChanged(int state); void timelineMaxWidthChanged(int state);
@ -340,6 +347,7 @@ private:
bool hasAlertOnNotification_; bool hasAlertOnNotification_;
bool avatarCircles_; bool avatarCircles_;
bool decryptSidebar_; bool decryptSidebar_;
bool spaceNotifications_;
bool privacyScreen_; bool privacyScreen_;
int privacyScreenTimeout_; int privacyScreenTimeout_;
bool shareKeysWithTrustedUsers_; bool shareKeysWithTrustedUsers_;
@ -370,6 +378,7 @@ private:
QString deviceId_; QString deviceId_;
QString homeserver_; QString homeserver_;
QStringList hiddenTags_; QStringList hiddenTags_;
QStringList mutedTags_;
QStringList hiddenPins_; QStringList hiddenPins_;
QStringList hiddenWidgets_; QStringList hiddenWidgets_;
QStringList recentReactions_; QStringList recentReactions_;
@ -424,6 +433,7 @@ class UserSettingsModel : public QAbstractListModel
GroupView, GroupView,
SortByImportance, SortByImportance,
DecryptSidebar, DecryptSidebar,
SpaceNotifications,
TraySection, TraySection,
Tray, Tray,

View file

@ -27,6 +27,7 @@
#include <cmark.h> #include <cmark.h>
#include "Cache.h" #include "Cache.h"
#include "Cache_p.h"
#include "Config.h" #include "Config.h"
#include "EventAccessors.h" #include "EventAccessors.h"
#include "Logging.h" #include "Logging.h"

View file

@ -9,11 +9,15 @@
#include "Cache.h" #include "Cache.h"
#include "Cache_p.h" #include "Cache_p.h"
#include "ChatPage.h"
#include "Logging.h" #include "Logging.h"
#include "UserSettingsPage.h" #include "UserSettingsPage.h"
#include "Utils.h"
CommunitiesModel::CommunitiesModel(QObject *parent) CommunitiesModel::CommunitiesModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, hiddenTagIds_{UserSettings::instance()->hiddenTags()}
, mutedTagIds_{UserSettings::instance()->mutedTags()}
{} {}
QHash<int, QByteArray> QHash<int, QByteArray>
@ -28,6 +32,9 @@ CommunitiesModel::roleNames() const
{Hidden, "hidden"}, {Hidden, "hidden"},
{Depth, "depth"}, {Depth, "depth"},
{Id, "id"}, {Id, "id"},
{UnreadMessages, "unreadMessages"},
{HasLoudNotification, "hasLoudNotification"},
{Muted, "muted"},
}; };
} }
@ -50,6 +57,13 @@ CommunitiesModel::setData(const QModelIndex &index, const QVariant &value, int r
QVariant QVariant
CommunitiesModel::data(const QModelIndex &index, int role) const CommunitiesModel::data(const QModelIndex &index, int role) const
{ {
if (role == CommunitiesModel::Roles::Muted) {
if (index.row() == 0)
return mutedTagIds_.contains(QStringLiteral("global"));
else
return mutedTagIds_.contains(data(index, CommunitiesModel::Roles::Id).toString());
}
if (index.row() == 0) { if (index.row() == 0) {
switch (role) { switch (role) {
case CommunitiesModel::Roles::AvatarUrl: case CommunitiesModel::Roles::AvatarUrl:
@ -70,6 +84,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
return 0; return 0;
case CommunitiesModel::Roles::Id: case CommunitiesModel::Roles::Id:
return ""; return "";
case CommunitiesModel::Roles::UnreadMessages:
return (int)globalUnreads.notification_count;
case CommunitiesModel::Roles::HasLoudNotification:
return globalUnreads.highlight_count > 0;
} }
} else if (index.row() == 1) { } else if (index.row() == 1) {
switch (role) { switch (role) {
@ -84,16 +102,20 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
case CommunitiesModel::Roles::Collapsible: case CommunitiesModel::Roles::Collapsible:
return false; return false;
case CommunitiesModel::Roles::Hidden: case CommunitiesModel::Roles::Hidden:
return hiddentTagIds_.contains(QStringLiteral("dm")); return hiddenTagIds_.contains(QStringLiteral("dm"));
case CommunitiesModel::Roles::Parent: case CommunitiesModel::Roles::Parent:
return ""; return "";
case CommunitiesModel::Roles::Depth: case CommunitiesModel::Roles::Depth:
return 0; return 0;
case CommunitiesModel::Roles::Id: case CommunitiesModel::Roles::Id:
return "dm"; return "dm";
case CommunitiesModel::Roles::UnreadMessages:
return (int)dmUnreads.notification_count;
case CommunitiesModel::Roles::HasLoudNotification:
return dmUnreads.highlight_count > 0;
} }
} else if (index.row() - 2 < spaceOrder_.size()) { } else if (index.row() - 2 < spaceOrder_.size()) {
auto id = spaceOrder_.tree.at(index.row() - 2).name; auto id = spaceOrder_.tree.at(index.row() - 2).id;
switch (role) { switch (role) {
case CommunitiesModel::Roles::AvatarUrl: case CommunitiesModel::Roles::AvatarUrl:
return QString::fromStdString(spaces_.at(id).avatar_url); return QString::fromStdString(spaces_.at(id).avatar_url);
@ -107,10 +129,10 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
return idx != spaceOrder_.lastChild(idx); return idx != spaceOrder_.lastChild(idx);
} }
case CommunitiesModel::Roles::Hidden: case CommunitiesModel::Roles::Hidden:
return hiddentTagIds_.contains("space:" + id); return hiddenTagIds_.contains("space:" + id);
case CommunitiesModel::Roles::Parent: { case CommunitiesModel::Roles::Parent: {
if (auto p = spaceOrder_.parent(index.row() - 2); p >= 0) if (auto p = spaceOrder_.parent(index.row() - 2); p >= 0)
return spaceOrder_.tree[p].name; return spaceOrder_.tree[p].id;
return ""; return "";
} }
@ -118,6 +140,20 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
return spaceOrder_.tree.at(index.row() - 2).depth; return spaceOrder_.tree.at(index.row() - 2).depth;
case CommunitiesModel::Roles::Id: case CommunitiesModel::Roles::Id:
return "space:" + id; return "space:" + id;
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()) { } else if (index.row() - 2 < tags_.size() + spaceOrder_.size()) {
auto tag = tags_.at(index.row() - 2 - spaceOrder_.size()); auto tag = tags_.at(index.row() - 2 - spaceOrder_.size());
@ -160,7 +196,7 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
switch (role) { switch (role) {
case CommunitiesModel::Roles::Hidden: case CommunitiesModel::Roles::Hidden:
return hiddentTagIds_.contains("tag:" + tag); return hiddenTagIds_.contains("tag:" + tag);
case CommunitiesModel::Roles::Collapsed: case CommunitiesModel::Roles::Collapsed:
return true; return true;
case CommunitiesModel::Roles::Collapsible: case CommunitiesModel::Roles::Collapsible:
@ -171,6 +207,16 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
return 0; return 0;
case CommunitiesModel::Roles::Id: case CommunitiesModel::Roles::Id:
return "tag:" + tag; return "tag:" + tag;
case CommunitiesModel::Roles::UnreadMessages:
if (auto it = tagNotificationCache.find(tag); it != tagNotificationCache.end())
return (int)it->second.notification_count;
else
return 0;
case CommunitiesModel::Roles::HasLoudNotification:
if (auto it = tagNotificationCache.find(tag); it != tagNotificationCache.end())
return it->second.highlight_count > 0;
else
return 0;
} }
} }
return QVariant(); return QVariant();
@ -225,6 +271,21 @@ CommunitiesModel::initializeSidebar()
tags_.clear(); tags_.clear();
spaceOrder_.tree.clear(); spaceOrder_.tree.clear();
spaces_.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; std::set<std::string> ts;
@ -244,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 // NOTE(Nico): We build a forrest from the Directed Cyclic(!) Graph of spaces. To do that we
@ -277,8 +351,16 @@ CommunitiesModel::initializeSidebar()
for (const auto &t : ts) for (const auto &t : ts)
tags_.push_back(QString::fromStdString(t)); tags_.push_back(QString::fromStdString(t));
hiddentTagIds_ = UserSettings::instance()->hiddenTags();
spaceOrder_.restoreCollapsed(); 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(); endResetModel();
emit tagsChanged(); emit tagsChanged();
@ -298,12 +380,12 @@ CommunitiesModel::FlatTree::storeCollapsed()
for (const auto &e : tree) { for (const auto &e : tree) {
if (e.depth > depth) { if (e.depth > depth) {
current.push_back(e.name); current.push_back(e.id);
} else if (e.depth == depth) { } else if (e.depth == depth) {
current.back() = e.name; current.back() = e.id;
} else { } else {
current.pop_back(); current.pop_back();
current.back() = e.name; current.back() = e.id;
} }
if (e.collapsed) if (e.collapsed)
@ -323,12 +405,12 @@ CommunitiesModel::FlatTree::restoreCollapsed()
for (auto &e : tree) { for (auto &e : tree) {
if (e.depth > depth) { if (e.depth > depth) {
current.push_back(e.name); current.push_back(e.id);
} else if (e.depth == depth) { } else if (e.depth == depth) {
current.back() = e.name; current.back() = e.id;
} else { } else {
current.pop_back(); current.pop_back();
current.back() = e.name; current.back() = e.id;
} }
if (elements.contains(current)) if (elements.contains(current))
@ -353,7 +435,6 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
bool tagsUpdated = false; bool tagsUpdated = false;
for (const auto &[roomid, room] : sync_.rooms.join) { for (const auto &[roomid, room] : sync_.rooms.join) {
(void)roomid;
for (const auto &e : room.account_data.events) for (const auto &e : room.account_data.events)
if (std::holds_alternative< if (std::holds_alternative<
mtx::events::AccountDataEvent<mtx::events::account_data::Tags>>(e)) { mtx::events::AccountDataEvent<mtx::events::account_data::Tags>>(e)) {
@ -373,6 +454,78 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
e)) { e)) {
tagsUpdated = true; tagsUpdated = true;
} }
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);
applyDiff(globalUnreads);
emit dataChanged(index(0),
index(0),
{
UnreadMessages,
HasLoudNotification,
});
if (std::find(begin(directMessages_), end(directMessages_), roomid) !=
end(directMessages_)) {
applyDiff(dmUnreads);
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);
applyDiff(tagNotificationCache[tagId]);
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++) {
if (spaceOrder_.tree[i].id != spaceId)
continue;
applyDiff(spaceOrder_.tree[i].notificationCounts);
int idx = i;
do {
emit dataChanged(index(idx + 2),
index(idx + 2),
{
UnreadMessages,
HasLoudNotification,
});
idx = spaceOrder_.parent(idx);
} while (idx != -1);
}
}
}
roomNotificationCache[roomId] = room.unread_notifications;
} }
for (const auto &[roomid, room] : sync_.rooms.leave) { for (const auto &[roomid, room] : sync_.rooms.leave) {
(void)room; (void)room;
@ -380,8 +533,12 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
tagsUpdated = true; tagsUpdated = true;
} }
for (const auto &e : sync_.account_data.events) { for (const auto &e : sync_.account_data.events) {
if (std::holds_alternative< if (auto event =
mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(e)) { std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(&e)) {
directMessages_.clear();
for (const auto &[userId, roomIds] : event->content.user_to_rooms)
for (const auto &roomId : roomIds)
directMessages_.push_back(roomId);
tagsUpdated = true; tagsUpdated = true;
break; break;
} }
@ -392,7 +549,7 @@ CommunitiesModel::sync(const mtx::responses::Sync &sync_)
} }
void void
CommunitiesModel::setCurrentTagId(QString tagId) CommunitiesModel::setCurrentTagId(const QString &tagId)
{ {
if (tagId.startsWith(QLatin1String("tag:"))) { if (tagId.startsWith(QLatin1String("tag:"))) {
auto tag = tagId.mid(4); auto tag = tagId.mid(4);
@ -406,7 +563,7 @@ CommunitiesModel::setCurrentTagId(QString tagId)
} else if (tagId.startsWith(QLatin1String("space:"))) { } else if (tagId.startsWith(QLatin1String("space:"))) {
auto tag = tagId.mid(6); auto tag = tagId.mid(6);
for (const auto &t : spaceOrder_.tree) { for (const auto &t : spaceOrder_.tree) {
if (t.name == tag) { if (t.id == tag) {
this->currentTagId_ = tagId; this->currentTagId_ = tagId;
emit currentTagIdChanged(currentTagId_); emit currentTagIdChanged(currentTagId_);
return; return;
@ -425,13 +582,11 @@ CommunitiesModel::setCurrentTagId(QString tagId)
void void
CommunitiesModel::toggleTagId(QString tagId) CommunitiesModel::toggleTagId(QString tagId)
{ {
if (hiddentTagIds_.contains(tagId)) { if (hiddenTagIds_.contains(tagId))
hiddentTagIds_.removeOne(tagId); hiddenTagIds_.removeOne(tagId);
UserSettings::instance()->setHiddenTags(hiddentTagIds_); else
} else { hiddenTagIds_.push_back(tagId);
hiddentTagIds_.push_back(tagId); UserSettings::instance()->setHiddenTags(hiddenTagIds_);
UserSettings::instance()->setHiddenTags(hiddentTagIds_);
}
if (tagId.startsWith(QLatin1String("tag:"))) { if (tagId.startsWith(QLatin1String("tag:"))) {
auto idx = tags_.indexOf(tagId.mid(4)); auto idx = tags_.indexOf(tagId.mid(4));
@ -449,6 +604,34 @@ CommunitiesModel::toggleTagId(QString tagId)
emit hiddenTagsChanged(); emit hiddenTagsChanged();
} }
void
CommunitiesModel::toggleTagMute(QString tagId)
{
if (tagId.isEmpty())
tagId = QStringLiteral("global");
if (mutedTagIds_.contains(tagId))
mutedTagIds_.removeOne(tagId);
else
mutedTagIds_.push_back(tagId);
UserSettings::instance()->setMutedTags(mutedTagIds_);
if (tagId.startsWith(QLatin1String("tag:"))) {
auto idx = tags_.indexOf(tagId.mid(4));
if (idx != -1)
emit dataChanged(index(idx + 1 + spaceOrder_.size()),
index(idx + 1 + spaceOrder_.size()));
} else if (tagId.startsWith(QLatin1String("space:"))) {
auto idx = spaceOrder_.indexOf(tagId.mid(6));
if (idx != -1)
emit dataChanged(index(idx + 1), index(idx + 1));
} else if (tagId == QLatin1String("dm")) {
emit dataChanged(index(1), index(1));
} else if (tagId == QLatin1String("global")) {
emit dataChanged(index(0), index(0));
}
}
FilteredCommunitiesModel::FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent) FilteredCommunitiesModel::FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent)
: QSortFilterProxyModel(parent) : QSortFilterProxyModel(parent)
{ {

View file

@ -22,7 +22,7 @@ class FilteredCommunitiesModel : public QSortFilterProxyModel
Q_OBJECT Q_OBJECT
public: 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 lessThan(const QModelIndex &left, const QModelIndex &right) const override;
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override; bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
}; };
@ -48,14 +48,21 @@ public:
Parent, Parent,
Depth, Depth,
Id, Id,
UnreadMessages,
HasLoudNotification,
Muted,
IsDirect,
}; };
struct FlatTree struct FlatTree
{ {
struct Elem struct Elem
{ {
QString name; QString id;
int depth = 0; int depth = 0;
mtx::responses::UnreadNotifications notificationCounts = {0, 0};
bool collapsed = false; bool collapsed = false;
}; };
@ -65,7 +72,7 @@ public:
int indexOf(const QString &s) const int indexOf(const QString &s) const
{ {
for (int i = 0; i < size(); i++) for (int i = 0; i < size(); i++)
if (tree[i].name == s) if (tree[i].id == s)
return i; return i;
return -1; return -1;
} }
@ -121,7 +128,7 @@ public slots:
void sync(const mtx::responses::Sync &sync_); void sync(const mtx::responses::Sync &sync_);
void clear(); void clear();
QString currentTagId() const { return currentTagId_; } QString currentTagId() const { return currentTagId_; }
void setCurrentTagId(QString tagId); void setCurrentTagId(const QString &tagId);
void resetCurrentTagId() void resetCurrentTagId()
{ {
currentTagId_.clear(); currentTagId_.clear();
@ -138,6 +145,7 @@ public slots:
return tagsWD; return tagsWD;
} }
void toggleTagId(QString tagId); void toggleTagId(QString tagId);
void toggleTagMute(QString tagId);
FilteredCommunitiesModel *filtered() { return new FilteredCommunitiesModel(this, this); } FilteredCommunitiesModel *filtered() { return new FilteredCommunitiesModel(this, this); }
signals: signals:
@ -149,9 +157,16 @@ signals:
private: private:
QStringList tags_; QStringList tags_;
QString currentTagId_; QString currentTagId_;
QStringList hiddentTagIds_; QStringList hiddenTagIds_;
QStringList mutedTagIds_;
FlatTree spaceOrder_; FlatTree spaceOrder_;
std::map<QString, RoomInfo> spaces_; std::map<QString, RoomInfo> spaces_;
std::vector<std::string> directMessages_;
std::unordered_map<QString, mtx::responses::UnreadNotifications> roomNotificationCache;
std::unordered_map<QString, mtx::responses::UnreadNotifications> tagNotificationCache;
mtx::responses::UnreadNotifications globalUnreads{};
mtx::responses::UnreadNotifications dmUnreads{};
friend class FilteredCommunitiesModel; friend class FilteredCommunitiesModel;
}; };

View file

@ -330,10 +330,13 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
Qt::DisplayRole, Qt::DisplayRole,
}); });
if (getRoomById(room_id)->isSpace())
return; // no need to update space notifications
int total_unread_msgs = 0; int total_unread_msgs = 0;
for (const auto &room : qAsConst(models)) { for (const auto &room : qAsConst(models)) {
if (!room.isNull()) if (!room.isNull() && !room->isSpace())
total_unread_msgs += room->notificationCount(); total_unread_msgs += room->notificationCount();
} }
@ -639,15 +642,18 @@ RoomlistModel::clear()
} }
void void
RoomlistModel::joinPreview(QString roomid, QString parentSpace) RoomlistModel::joinPreview(QString roomid)
{ {
if (previewedRooms.contains(roomid)) { if (previewedRooms.contains(roomid)) {
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>( auto child = cache::client()->getStateEvent<mtx::events::state::space::Child>(
parentSpace.toStdString(), roomid.toStdString()); p, roomid.toStdString());
ChatPage::instance()->joinRoomVia( if (child && child->content.via)
roomid.toStdString(), vias.insert(vias.end(), child->content.via->begin(), child->content.via->end());
(child && child->content.via) ? child->content.via.value() : std::vector<std::string>{}, }
false); ChatPage::instance()->joinRoomVia(roomid.toStdString(), vias, false);
} }
} }
void void

View file

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

View file

@ -370,10 +370,6 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
this->highlight_count = roomInfo.highlight_count; this->highlight_count = roomInfo.highlight_count;
lastMessage_.timestamp = roomInfo.approximate_last_modification_ts; 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);
connect( connect(
this, this,
&TimelineModel::redactionFailed, &TimelineModel::redactionFailed,

View file

@ -182,7 +182,7 @@ class TimelineModel : public QAbstractListModel
bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged) bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged)
Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomId READ roomId CONSTANT)
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) 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 roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged)
Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
Q_PROPERTY(QStringList pinnedMessages READ pinnedMessages NOTIFY pinnedMessagesChanged) Q_PROPERTY(QStringList pinnedMessages READ pinnedMessages NOTIFY pinnedMessagesChanged)
@ -429,7 +429,6 @@ signals:
void encryptionChanged(); void encryptionChanged();
void trustlevelChanged(); void trustlevelChanged();
void roomNameChanged(); void roomNameChanged();
void plainRoomNameChanged();
void roomTopicChanged(); void roomTopicChanged();
void pinnedMessagesChanged(); void pinnedMessagesChanged();
void widgetLinksChanged(); void widgetLinksChanged();