mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 12:38:48 +03:00
Merge remote-tracking branch 'origin/perSpaceNotifs' into perSpaceNotifs
This commit is contained in:
commit
aa63e50cea
12 changed files with 374 additions and 124 deletions
|
@ -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,19 +71,30 @@ 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 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
|
||||||
|
|
||||||
height: avatarSize + 2 * Nheko.paddingMedium
|
height: avatarSize + 2 * Nheko.paddingMedium
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
state: "normal"
|
state: "normal"
|
||||||
ToolTip.visible: hovered && collapsed
|
ToolTip.visible: hovered && collapsed
|
||||||
ToolTip.text: model.tooltip
|
ToolTip.text: communityItem.tooltip
|
||||||
ToolTip.delay: Nheko.tooltipDelay
|
ToolTip.delay: Nheko.tooltipDelay
|
||||||
onClicked: Communities.setCurrentTagId(model.id)
|
onClicked: Communities.setCurrentTagId(communityItem.id)
|
||||||
onPressAndHold: communityContextMenu.show(model.id)
|
onPressAndHold: communityContextMenu.show(communityItem.id, communityItem.hidden, communityItem.muted)
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "highlight"
|
name: "highlight"
|
||||||
when: (communityItem.hovered || model.hidden) && !(Communities.currentTagId == model.id)
|
when: (communityItem.hovered || communityItem.hidden) && !(Communities.currentTagId === communityItem.id)
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: communityItem
|
target: communityItem
|
||||||
|
@ -83,7 +108,7 @@ Page {
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: "selected"
|
name: "selected"
|
||||||
when: Communities.currentTagId == model.id
|
when: Communities.currentTagId == communityItem.id
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: communityItem
|
target: communityItem
|
||||||
|
@ -102,7 +127,7 @@ Page {
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onSingleTapped: communityContextMenu.show(model.id)
|
onSingleTapped: communityContextMenu.show(communityItem.id, communityItem.hidden, communityItem.muted)
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
|
||||||
}
|
}
|
||||||
|
@ -114,27 +139,27 @@ Page {
|
||||||
spacing: Nheko.paddingMedium
|
spacing: Nheko.paddingMedium
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Nheko.paddingMedium
|
anchors.margins: Nheko.paddingMedium
|
||||||
anchors.leftMargin: Nheko.paddingMedium + (communitySidebar.collapsed ? 0 : (fontMetrics.lineSpacing * model.depth))
|
anchors.leftMargin: Nheko.paddingMedium + (communitySidebar.collapsed ? 0 : (fontMetrics.lineSpacing * communityItem.depth))
|
||||||
|
|
||||||
ImageButton {
|
ImageButton {
|
||||||
visible: !communitySidebar.collapsed && model.collapsible
|
visible: !communitySidebar.collapsed && communityItem.collapsible
|
||||||
Layout.preferredHeight: fontMetrics.lineSpacing
|
Layout.preferredHeight: fontMetrics.lineSpacing
|
||||||
Layout.preferredWidth: fontMetrics.lineSpacing
|
Layout.preferredWidth: fontMetrics.lineSpacing
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
height: fontMetrics.lineSpacing
|
height: fontMetrics.lineSpacing
|
||||||
width: fontMetrics.lineSpacing
|
width: fontMetrics.lineSpacing
|
||||||
image: model.collapsed ? ":/icons/icons/ui/collapsed.svg" : ":/icons/icons/ui/expanded.svg"
|
image: communityItem.collapsed ? ":/icons/icons/ui/collapsed.svg" : ":/icons/icons/ui/expanded.svg"
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.delay: Nheko.tooltipDelay
|
ToolTip.delay: Nheko.tooltipDelay
|
||||||
ToolTip.text: model.collapsed ? qsTr("Expand") : qsTr("Collapse")
|
ToolTip.text: communityItem.collapsed ? qsTr("Expand") : qsTr("Collapse")
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: model.collapsed = !model.collapsed
|
onClicked: communityItem.collapsed = !communityItem.collapsed
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
Layout.preferredWidth: fontMetrics.lineSpacing
|
Layout.preferredWidth: fontMetrics.lineSpacing
|
||||||
visible: !communitySidebar.collapsed && !model.collapsible && Communities.containsSubspaces
|
visible: !communitySidebar.collapsed && !communityItem.collapsible && Communities.containsSubspaces
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
|
@ -145,14 +170,27 @@ Page {
|
||||||
height: avatarSize
|
height: avatarSize
|
||||||
width: avatarSize
|
width: avatarSize
|
||||||
url: {
|
url: {
|
||||||
if (model.avatarUrl.startsWith("mxc://"))
|
if (communityItem.avatarUrl.startsWith("mxc://"))
|
||||||
return model.avatarUrl.replace("mxc://", "image://MxcImage/");
|
return communityItem.avatarUrl.replace("mxc://", "image://MxcImage/");
|
||||||
else
|
else
|
||||||
return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText;
|
return "image://colorimage/" + communityItem.avatarUrl + "?" + communityItem.unimportantText;
|
||||||
}
|
}
|
||||||
roomid: model.id
|
roomid: communityItem.id
|
||||||
displayName: model.displayName
|
displayName: communityItem.displayName
|
||||||
color: communityItem.backgroundColor
|
color: communityItem.backgroundColor
|
||||||
|
|
||||||
|
NotificationBubble {
|
||||||
|
notificationCount: communityItem.unreadMessages
|
||||||
|
hasLoudNotification: communityItem.hasLoudNotification
|
||||||
|
bubbleBackgroundColor: communityItem.bubbleBackground
|
||||||
|
bubbleTextColor: communityItem.bubbleText
|
||||||
|
font.pixelSize: fontMetrics.font.pixelSize * 0.6
|
||||||
|
mayBeVisible: communitySidebar.collapsed && !communityItem.muted && Settings.spaceNotifications
|
||||||
|
anchors.right: avatar.right
|
||||||
|
anchors.bottom: avatar.bottom
|
||||||
|
anchors.margins: -Nheko.paddingSmall
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ElidedLabel {
|
ElidedLabel {
|
||||||
|
@ -161,7 +199,7 @@ Page {
|
||||||
color: communityItem.importantText
|
color: communityItem.importantText
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
elideWidth: width
|
elideWidth: width
|
||||||
fullText: model.displayName
|
fullText: communityItem.displayName
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,10 +207,20 @@ Page {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationBubble {
|
||||||
|
notificationCount: communityItem.unreadMessages
|
||||||
|
hasLoudNotification: communityItem.hasLoudNotification
|
||||||
|
bubbleBackgroundColor: communityItem.bubbleBackground
|
||||||
|
bubbleTextColor: communityItem.bubbleText
|
||||||
|
mayBeVisible: !communitySidebar.collapsed && !communityItem.muted && Settings.spaceNotifications
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.leftMargin: Nheko.paddingSmall
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: backgroundColor
|
color: communityItem.backgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
46
resources/qml/components/NotificationBubble.qml
Normal file
46
resources/qml/components/NotificationBubble.qml
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -88,7 +88,8 @@ 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();
|
||||||
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
|
spaceNotifications_ = settings.value(QStringLiteral("user/space_notifications"), true).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();
|
||||||
exposeDBusApi_ = settings.value(QStringLiteral("user/expose_dbus_api"), false).toBool();
|
exposeDBusApi_ = settings.value(QStringLiteral("user/expose_dbus_api"), false).toBool();
|
||||||
|
@ -132,7 +133,8 @@ 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();
|
||||||
hiddenPins_ = settings.value(prefix + "user/hidden_pins", QStringList{}).toStringList();
|
mutedTags_ = settings.value(prefix + "user/muted_tags", QStringList{"global"}).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_ =
|
||||||
settings.value(prefix + "user/recent_reactions", QStringList{}).toStringList();
|
settings.value(prefix + "user/recent_reactions", QStringList{}).toStringList();
|
||||||
|
@ -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});
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -880,3 +881,21 @@ 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;
|
||||||
|
}
|
||||||
|
|
|
@ -311,4 +311,9 @@ removeDirectFromRoom(QString roomid);
|
||||||
|
|
||||||
void
|
void
|
||||||
markRoomAsDirect(QString roomid, std::vector<RoomMember> members);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,24 @@
|
||||||
|
|
||||||
#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()}
|
||||||
|
{
|
||||||
|
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<int, QByteArray>
|
QHash<int, QByteArray>
|
||||||
CommunitiesModel::roleNames() const
|
CommunitiesModel::roleNames() const
|
||||||
|
@ -28,6 +40,9 @@ CommunitiesModel::roleNames() const
|
||||||
{Hidden, "hidden"},
|
{Hidden, "hidden"},
|
||||||
{Depth, "depth"},
|
{Depth, "depth"},
|
||||||
{Id, "id"},
|
{Id, "id"},
|
||||||
|
{UnreadMessages, "unreadMessages"},
|
||||||
|
{HasLoudNotification, "hasLoudNotification"},
|
||||||
|
{Muted, "muted"},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +65,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 +92,17 @@ 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: {
|
||||||
|
int total{0};
|
||||||
|
for (const auto &[id, info] : cache::getRoomInfo(cache::joinedRooms()))
|
||||||
|
total += info.notification_count;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
case CommunitiesModel::Roles::HasLoudNotification:
|
||||||
|
for (const auto &[id, info] : cache::getRoomInfo(cache::joinedRooms()))
|
||||||
|
if (info.highlight_count > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else if (index.row() == 1) {
|
} else if (index.row() == 1) {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
@ -84,16 +117,27 @@ 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: {
|
||||||
|
int total{0};
|
||||||
|
for (const auto &[id, info] : cache::getRoomInfo(directMessages_))
|
||||||
|
total += info.notification_count;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
case CommunitiesModel::Roles::HasLoudNotification:
|
||||||
|
for (const auto &[id, info] : cache::getRoomInfo(directMessages_))
|
||||||
|
if (info.highlight_count > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} 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 +151,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 +162,10 @@ 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:
|
||||||
|
return utils::getChildNotificationsForSpace(id).first;
|
||||||
|
case CommunitiesModel::Roles::HasLoudNotification:
|
||||||
|
return utils::getChildNotificationsForSpace(id).second > 0;
|
||||||
}
|
}
|
||||||
} 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 +208,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 +219,24 @@ 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: {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
@ -277,8 +343,8 @@ 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();
|
||||||
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
||||||
emit tagsChanged();
|
emit tagsChanged();
|
||||||
|
@ -298,12 +364,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 +389,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 +419,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)) {
|
||||||
|
@ -380,8 +445,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 +461,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 +475,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 +494,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 +516,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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,13 +48,17 @@ 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;
|
||||||
bool collapsed = false;
|
bool collapsed = false;
|
||||||
};
|
};
|
||||||
|
@ -65,7 +69,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 +125,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 +142,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 +154,11 @@ 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_;
|
||||||
|
|
||||||
friend class FilteredCommunitiesModel;
|
friend class FilteredCommunitiesModel;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -364,16 +364,26 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
|
||||||
{
|
{
|
||||||
this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString());
|
this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString());
|
||||||
|
|
||||||
auto roomInfo = cache::singleRoomInfo(room_id_.toStdString());
|
auto roomInfo = cache::singleRoomInfo(room_id_.toStdString());
|
||||||
this->isSpace_ = roomInfo.is_space;
|
this->isSpace_ = roomInfo.is_space;
|
||||||
this->notification_count = roomInfo.notification_count;
|
this->notification_count =
|
||||||
this->highlight_count = roomInfo.highlight_count;
|
isSpace_ ? utils::getChildNotificationsForSpace(room_id_).first : roomInfo.notification_count;
|
||||||
lastMessage_.timestamp = roomInfo.approximate_last_modification_ts;
|
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
|
// this connection will simplify adding the plainRoomNameChanged() signal everywhere that it
|
||||||
// needs to be
|
// needs to be
|
||||||
connect(this, &TimelineModel::roomNameChanged, this, &TimelineModel::plainRoomNameChanged);
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
this,
|
this,
|
||||||
&TimelineModel::redactionFailed,
|
&TimelineModel::redactionFailed,
|
||||||
|
|
Loading…
Reference in a new issue