From 1a500a087b1dc913a4438692d4d928f93aede891 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Fri, 9 Jan 2026 17:54:03 -0500 Subject: [PATCH] Separate priviled members list, and more useful permissions Having both the member list and permission controls is troublesome, and scales the larger your moderation team is. We eventually may want to manage banned/muted users too so I think it warrants having a new page. I also moved the search field to the top so it's more accessible. As for permissions, I tried to improve the UX generally while not changing it too heavily. First the easy change is to the text, hopefully the sections should be clearer (especially for "state" events.) The bigger change here is the new sections, I tried to make it more useful and organized. Additionally, I added more permissions like sharing live locations and polls so they're more easily configurable. One other change is that permissions are visible regardless of whether you can set them or not, matching Element's behavior. --- src/settings/CMakeLists.txt | 1 + src/settings/Members.qml | 247 ++++++++++++++++++ src/settings/Permissions.qml | 306 ++++++++--------------- src/settings/RoomSettingsView.qml | 11 + src/settings/models/permissionsmodel.cpp | 59 ++++- src/settings/models/permissionsmodel.h | 2 + 6 files changed, 411 insertions(+), 215 deletions(-) create mode 100644 src/settings/Members.qml diff --git a/src/settings/CMakeLists.txt b/src/settings/CMakeLists.txt index 21010a692..5ce8b9bab 100644 --- a/src/settings/CMakeLists.txt +++ b/src/settings/CMakeLists.txt @@ -51,6 +51,7 @@ ecm_add_qml_module(Settings GENERATE_PLUGIN_SOURCE RoomProfile.qml RoomAdvancedPage.qml KeyboardShortcutsPage.qml + Members.qml SOURCES colorschemer.cpp threepidaddhelper.cpp diff --git a/src/settings/Members.qml b/src/settings/Members.qml new file mode 100644 index 000000000..0198b83e0 --- /dev/null +++ b/src/settings/Members.qml @@ -0,0 +1,247 @@ +// SPDX-FileCopyrightText: 2022 James Graham +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls as QQC2 +import QtQuick.Layouts + +import org.kde.kirigami as Kirigami +import org.kde.kirigamiaddons.formcard as FormCard +import org.kde.kirigamiaddons.delegates as Delegates +import org.kde.kirigamiaddons.labs.components as KirigamiComponents +import org.kde.kitemmodels + +import org.kde.neochat + +FormCard.FormCardPage { + id: root + + property NeoChatRoom room + + title: i18nc("@title:window", "Members") + + readonly property bool loading: permissions.count === 0 && !root.room.roomCreatorHasUltimatePowerLevel() + + readonly property PowerLevelModel powerLevelModel: PowerLevelModel { + showMute: false + } + + FormCard.FormHeader { + title: i18nc("@title", "Privileged Members") + visible: !root.loading + } + FormCard.FormCard { + visible: !root.loading + + FormCard.AbstractFormDelegate { + id: userListSearchCard + visible: root.room.canSendState("m.room.power_levels") + + contentItem: Kirigami.SearchField { + id: userListSearchField + + autoAccept: false + + Layout.fillWidth: true + + Keys.onUpPressed: userListView.decrementCurrentIndex() + Keys.onDownPressed: userListView.incrementCurrentIndex() + + onAccepted: (userListView.itemAtIndex(userListView.currentIndex) as Delegates.RoundedItemDelegate).action.trigger() + } + QQC2.Popup { + id: userListSearchPopup + + x: userListSearchField.x + y: userListSearchField.y - height + width: userListSearchField.width + height: { + let maxHeight = userListSearchField.mapToGlobal(userListSearchField.x, userListSearchField.y).y - Kirigami.Units.largeSpacing * 3; + let minHeight = Kirigami.Units.gridUnit * 2 + userListSearchPopup.padding * 2; + let filterContentHeight = userListView.contentHeight + userListSearchPopup.padding * 2; + return Math.max(Math.min(filterContentHeight, maxHeight), minHeight); + } + padding: Kirigami.Units.smallSpacing + leftPadding: Kirigami.Units.smallSpacing / 2 + rightPadding: Kirigami.Units.smallSpacing / 2 + modal: false + onClosed: userListSearchField.text = "" + + background: Kirigami.ShadowedRectangle { + property color borderColor: Kirigami.Theme.textColor + + Kirigami.Theme.colorSet: Kirigami.Theme.View + Kirigami.Theme.inherit: false + + radius: Kirigami.Units.cornerRadius + color: Kirigami.Theme.backgroundColor + + border { + color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) + width: 1 + } + + shadow { + xOffset: 0 + yOffset: 4 + color: Qt.rgba(0, 0, 0, 0.3) + size: 8 + } + } + + contentItem: QQC2.ScrollView { + // HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890) + QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff + + ListView { + id: userListView + clip: true + + model: UserFilterModel { + id: userListFilterModel + sourceModel: RoomManager.userListModel + filterText: userListSearchField.text + + onFilterTextChanged: { + if (filterText.length > 0 && !userListSearchPopup.visible) { + userListSearchPopup.open(); + } else if (filterText.length <= 0 && userListSearchPopup.visible) { + userListSearchPopup.close(); + } + } + } + + delegate: Delegates.RoundedItemDelegate { + id: userListItem + + required property string userId + required property url avatar + required property string name + required property int powerLevel + required property string powerLevelString + + text: name + + contentItem: RowLayout { + KirigamiComponents.Avatar { + Layout.preferredWidth: Kirigami.Units.iconSizes.medium + Layout.preferredHeight: Kirigami.Units.iconSizes.medium + source: userListItem.avatar + name: userListItem.name + } + + Delegates.SubtitleContentItem { + itemDelegate: userListItem + subtitle: userListItem.userId + labelItem.textFormat: Text.PlainText + subtitleItem.textFormat: Text.PlainText + Layout.fillWidth: true + } + + QQC2.Label { + visible: userListItem.powerLevel > 0 + + text: userListItem.powerLevelString + color: Kirigami.Theme.disabledTextColor + textFormat: Text.PlainText + wrapMode: Text.NoWrap + } + } + + onClicked: { + userListSearchPopup.close(); + (powerLevelDialog.createObject(root.QQC2.Overlay.overlay, { + room: root.room, + userId: userListItem.userId, + powerLevel: userListItem.powerLevel + }) as PowerLevelDialog).open(); + } + + Component { + id: powerLevelDialog + PowerLevelDialog {} + } + } + + QQC2.Label { + text: i18nc("@info", "No users found.") + visible: userListView.count === 0 + + anchors { + left: parent.left + leftMargin: Kirigami.Units.mediumSpacing + verticalCenter: parent.verticalCenter + } + } + } + } + } + } + FormCard.FormDelegateSeparator { + above: userListSearchCard + } + Repeater { + id: permissions + model: KSortFilterProxyModel { + sourceModel: RoomManager.userListModel + sortRoleName: "powerLevel" + sortOrder: Qt.DescendingOrder + filterRowCallback: function (source_row, source_parent) { + let powerLevelRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), UserListModel.PowerLevelRole); + return powerLevelRole != 0; + } + } + delegate: FormCard.FormTextDelegate { + id: privilegedUserDelegate + required property string userId + required property string name + required property int powerLevel + required property string powerLevelString + required property bool isCreator + + text: name + textItem.textFormat: Text.PlainText + description: userId + contentItem.children: RowLayout { + spacing: Kirigami.Units.largeSpacing + QQC2.Label { + id: powerLevelLabel + text: privilegedUserDelegate.powerLevelString + visible: (!root.room.canSendState("m.room.power_levels") || (root.room.memberEffectivePowerLevel(root.room.localMember.id) <= privilegedUserDelegate.powerLevel && privilegedUserDelegate.userId != root.room.localMember.id)) || privilegedUserDelegate.isCreator + color: Kirigami.Theme.disabledTextColor + } + QQC2.ComboBox { + focusPolicy: Qt.NoFocus // provided by parent + model: PowerLevelModel {} + textRole: "name" + valueRole: "value" + visible: !powerLevelLabel.visible + Component.onCompleted: { + let index = indexOfValue(privilegedUserDelegate.powerLevel) + if (index === -1) { + displayText = privilegedUserDelegate.powerLevelString; + } else { + currentIndex = index; + } + } + onActivated: { + root.room.setUserPowerLevel(privilegedUserDelegate.userId, currentValue); + } + } + } + } + } + } + + Item { + visible: root.loading + Layout.fillWidth: true + implicitHeight: root.height * 0.9 + Kirigami.LoadingPlaceholder { + anchors.centerIn: parent + text: i18nc("@placeholder", "Loading…") + } + } +} diff --git a/src/settings/Permissions.qml b/src/settings/Permissions.qml index 515679891..b3fdf3f1d 100644 --- a/src/settings/Permissions.qml +++ b/src/settings/Permissions.qml @@ -33,207 +33,10 @@ FormCard.FormCardPage { } FormCard.FormHeader { - title: i18nc("@title", "Privileged Users") - visible: !root.loading + title: i18nc("@title", "Power Levels") } FormCard.FormCard { - visible: !root.loading - - Repeater { - id: permissions - model: KSortFilterProxyModel { - sourceModel: RoomManager.userListModel - sortRoleName: "powerLevel" - sortOrder: Qt.DescendingOrder - filterRowCallback: function (source_row, source_parent) { - let powerLevelRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), UserListModel.PowerLevelRole); - return powerLevelRole != 0; - } - } - delegate: FormCard.FormTextDelegate { - id: privilegedUserDelegate - required property string userId - required property string name - required property int powerLevel - required property string powerLevelString - required property bool isCreator - - text: name - textItem.textFormat: Text.PlainText - description: userId - contentItem.children: RowLayout { - spacing: Kirigami.Units.largeSpacing - QQC2.Label { - id: powerLevelLabel - text: privilegedUserDelegate.powerLevelString - visible: (!root.room.canSendState("m.room.power_levels") || (root.room.memberEffectivePowerLevel(root.room.localMember.id) <= privilegedUserDelegate.powerLevel && privilegedUserDelegate.userId != root.room.localMember.id)) || privilegedUserDelegate.isCreator - color: Kirigami.Theme.disabledTextColor - } - QQC2.ComboBox { - focusPolicy: Qt.NoFocus // provided by parent - model: PowerLevelModel {} - textRole: "name" - valueRole: "value" - visible: !powerLevelLabel.visible - Component.onCompleted: { - let index = indexOfValue(privilegedUserDelegate.powerLevel) - if (index === -1) { - displayText = privilegedUserDelegate.powerLevelString; - } else { - currentIndex = index; - } - } - onActivated: { - root.room.setUserPowerLevel(privilegedUserDelegate.userId, currentValue); - } - } - } - } - } - FormCard.FormDelegateSeparator { - below: userListSearchCard - } - FormCard.AbstractFormDelegate { - id: userListSearchCard - visible: root.room.canSendState("m.room.power_levels") - - contentItem: Kirigami.SearchField { - id: userListSearchField - - autoAccept: false - - Layout.fillWidth: true - - Keys.onUpPressed: userListView.decrementCurrentIndex() - Keys.onDownPressed: userListView.incrementCurrentIndex() - - onAccepted: (userListView.itemAtIndex(userListView.currentIndex) as Delegates.RoundedItemDelegate).action.trigger() - } - QQC2.Popup { - id: userListSearchPopup - - x: userListSearchField.x - y: userListSearchField.y - height - width: userListSearchField.width - height: { - let maxHeight = userListSearchField.mapToGlobal(userListSearchField.x, userListSearchField.y).y - Kirigami.Units.largeSpacing * 3; - let minHeight = Kirigami.Units.gridUnit * 2 + userListSearchPopup.padding * 2; - let filterContentHeight = userListView.contentHeight + userListSearchPopup.padding * 2; - return Math.max(Math.min(filterContentHeight, maxHeight), minHeight); - } - padding: Kirigami.Units.smallSpacing - leftPadding: Kirigami.Units.smallSpacing / 2 - rightPadding: Kirigami.Units.smallSpacing / 2 - modal: false - onClosed: userListSearchField.text = "" - - background: Kirigami.ShadowedRectangle { - property color borderColor: Kirigami.Theme.textColor - - Kirigami.Theme.colorSet: Kirigami.Theme.View - Kirigami.Theme.inherit: false - - radius: Kirigami.Units.cornerRadius - color: Kirigami.Theme.backgroundColor - - border { - color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) - width: 1 - } - - shadow { - xOffset: 0 - yOffset: 4 - color: Qt.rgba(0, 0, 0, 0.3) - size: 8 - } - } - - contentItem: QQC2.ScrollView { - // HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890) - QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff - - ListView { - id: userListView - clip: true - - model: UserFilterModel { - id: userListFilterModel - sourceModel: RoomManager.userListModel - filterText: userListSearchField.text - - onFilterTextChanged: { - if (filterText.length > 0 && !userListSearchPopup.visible) { - userListSearchPopup.open(); - } else if (filterText.length <= 0 && userListSearchPopup.visible) { - userListSearchPopup.close(); - } - } - } - - delegate: Delegates.RoundedItemDelegate { - id: userListItem - - required property string userId - required property url avatar - required property string name - required property int powerLevel - required property string powerLevelString - - text: name - - contentItem: RowLayout { - KirigamiComponents.Avatar { - Layout.preferredWidth: Kirigami.Units.iconSizes.medium - Layout.preferredHeight: Kirigami.Units.iconSizes.medium - source: userListItem.avatar - name: userListItem.name - } - - Delegates.SubtitleContentItem { - itemDelegate: userListItem - subtitle: userListItem.userId - labelItem.textFormat: Text.PlainText - subtitleItem.textFormat: Text.PlainText - Layout.fillWidth: true - } - - QQC2.Label { - visible: userListItem.powerLevel > 0 - - text: userListItem.powerLevelString - color: Kirigami.Theme.disabledTextColor - textFormat: Text.PlainText - wrapMode: Text.NoWrap - } - } - - onClicked: { - userListSearchPopup.close(); - (powerLevelDialog.createObject(root.QQC2.Overlay.overlay, { - room: root.room, - userId: userListItem.userId, - powerLevel: userListItem.powerLevel - }) as PowerLevelDialog).open(); - } - - Component { - id: powerLevelDialog - PowerLevelDialog {} - } - } - } - } - } - } - } - - FormCard.FormHeader { - visible: root.room.canSendState("m.room.power_levels") - title: i18nc("@title", "Default permissions") - } - FormCard.FormCard { - visible: root.room.canSendState("m.room.power_levels") + enabled: root.room.canSendState("m.room.power_levels") Repeater { model: KSortFilterProxyModel { sourceModel: root.permissionsModel @@ -269,11 +72,49 @@ FormCard.FormCardPage { } FormCard.FormHeader { - visible: root.room.canSendState("m.room.power_levels") - title: i18nc("@title", "Basic permissions") + title: i18nc("@title", "Messages") } FormCard.FormCard { - visible: root.room.canSendState("m.room.power_levels") + enabled: root.room.canSendState("m.room.power_levels") + Repeater { + model: KSortFilterProxyModel { + sourceModel: root.permissionsModel + filterRowCallback: function (source_row, source_parent) { + return sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsMessagePermissionRole); + } + } + delegate: FormCard.FormComboBoxDelegate { + required property string name + required property string subtitle + required property string type + required property int level + required property string levelName + + text: name + description: subtitle + textRole: "name" + valueRole: "value" + model: root.powerLevelModel + Component.onCompleted: { + let index = indexOfValue(level) + if (index === -1) { + displayText = levelName; + } else { + currentIndex = index; + } + } + onCurrentValueChanged: if (root.room.canSendState("m.room.power_levels")) { + root.permissionsModel.setPowerLevel(type, currentValue); + } + } + } + } + + FormCard.FormHeader { + title: i18nc("@title", "Moderation") + } + FormCard.FormCard { + enabled: root.room.canSendState("m.room.power_levels") Repeater { model: KSortFilterProxyModel { sourceModel: root.permissionsModel @@ -309,18 +150,15 @@ FormCard.FormCardPage { } FormCard.FormHeader { - visible: root.room.canSendState("m.room.power_levels") - title: i18nc("@title", "Event permissions") + title: i18nc("@title", "General") } FormCard.FormCard { - visible: root.room.canSendState("m.room.power_levels") + enabled: root.room.canSendState("m.room.power_levels") Repeater { model: KSortFilterProxyModel { sourceModel: root.permissionsModel filterRowCallback: function (source_row, source_parent) { - let isBasicPermissionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsBasicPermissionRole); - let isDefaultValueRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsDefaultValueRole); - return !isBasicPermissionRole && !isDefaultValueRole; + return sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsGeneralPermissionRole); } } delegate: FormCard.FormComboBoxDelegate { @@ -348,7 +186,59 @@ FormCard.FormCardPage { } } } + } + + FormCard.FormHeader { + title: i18nc("@title", "Other Events") + } + FormCard.FormCard { + enabled: root.room.canSendState("m.room.power_levels") + + Repeater { + id: otherEventsRepeater + + model: KSortFilterProxyModel { + sourceModel: root.permissionsModel + filterRowCallback: function (source_row, source_parent) { + let isBasicPermissionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsBasicPermissionRole); + let isDefaultValueRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsDefaultValueRole); + let isMessagePermissionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsMessagePermissionRole); + let isGeneralPermissionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsGeneralPermissionRole); + return !isBasicPermissionRole && !isDefaultValueRole && !isMessagePermissionRole && !isGeneralPermissionRole; + } + } + delegate: FormCard.FormComboBoxDelegate { + required property string name + required property string subtitle + required property string type + required property int level + required property string levelName + + text: name + description: subtitle + textRole: "name" + valueRole: "value" + model: root.powerLevelModel + Component.onCompleted: { + let index = indexOfValue(level) + if (index === -1) { + displayText = levelName; + } else { + currentIndex = index; + } + } + onCurrentValueChanged: if (root.room.canSendState("m.room.power_levels")) { + root.permissionsModel.setPowerLevel(type, currentValue); + } + } + } + FormCard.FormDelegateSeparator { + below: addNewEventDelegate + visible: otherEventsRepeater.count > 0 + } FormCard.AbstractFormDelegate { + id: addNewEventDelegate + Layout.fillWidth: true contentItem: RowLayout { diff --git a/src/settings/RoomSettingsView.qml b/src/settings/RoomSettingsView.qml index b012a2b48..3d394f644 100644 --- a/src/settings/RoomSettingsView.qml +++ b/src/settings/RoomSettingsView.qml @@ -55,6 +55,17 @@ KirigamiSettings.ConfigurationView { }; } }, + KirigamiSettings.ConfigurationModule { + moduleId: "members" + text: i18nc("@title", "Members") + icon.name: "system-users-symbolic" + page: () => Qt.createComponent("org.kde.neochat.settings", "Members") + initialProperties: () => { + return { + room: root._room + }; + } + }, KirigamiSettings.ConfigurationModule { moduleId: "permissions" text: i18nc("@title", "Permissions") diff --git a/src/settings/models/permissionsmodel.cpp b/src/settings/models/permissionsmodel.cpp index 76ebf9231..e0944a9a8 100644 --- a/src/settings/models/permissionsmodel.cpp +++ b/src/settings/models/permissionsmodel.cpp @@ -50,12 +50,16 @@ static const QStringList knownPermissions = { u"m.room.server_acl"_s, u"m.space.child"_s, u"m.space.parent"_s, + u"org.matrix.msc3672.beacon_info"_s, + u"org.matrix.msc3381.poll.start"_s, + u"org.matrix.msc3381.poll.response"_s, + u"org.matrix.msc3381.poll.end"_s, }; // Alternate name text for default permissions. static const QHash permissionNames = { - {UsersDefaultKey, kli18nc("Room permission type", "Default user power level")}, - {StateDefaultKey, kli18nc("Room permission type", "Default power level to set the room state")}, + {UsersDefaultKey, kli18nc("Room permission type", "Default power level")}, + {StateDefaultKey, kli18nc("Room permission type", "Default power level to change room state")}, {EventsDefaultKey, kli18nc("Room permission type", "Default power level to send messages")}, {InviteKey, kli18nc("Room permission type", "Invite users")}, {KickKey, kli18nc("Room permission type", "Kick users")}, @@ -70,25 +74,58 @@ static const QHash permissionNames = { {u"m.room.topic"_s, kli18nc("Room permission type", "Change the room topic")}, {u"m.room.encryption"_s, kli18nc("Room permission type", "Enable encryption for the room")}, {u"m.room.history_visibility"_s, kli18nc("Room permission type", "Change the room history visibility")}, - {u"m.room.pinned_events"_s, kli18nc("Room permission type", "Set pinned events")}, + {u"m.room.pinned_events"_s, kli18nc("Room permission type", "Pin and unpin messages")}, {u"m.room.tombstone"_s, kli18nc("Room permission type", "Upgrade the room")}, {u"m.room.server_acl"_s, kli18nc("Room permission type", "Set the room server access control list (ACL)")}, {u"m.space.child"_s, kli18nc("Room permission type", "Set the children of this space")}, {u"m.space.parent"_s, kli18nc("Room permission type", "Set the parent space of this room")}, + {u"org.matrix.msc3672.beacon_info"_s, kli18nc("Room permission type", "Send live location updates")}, + {u"org.matrix.msc3381.poll.start"_s, kli18nc("Room permission type", "Start polls")}, + {u"org.matrix.msc3381.poll.response"_s, kli18nc("Room permission type", "Vote in polls")}, + {u"org.matrix.msc3381.poll.end"_s, kli18nc("Room permission type", "Close polls")}, }; // Subtitles for the default values. static const QHash permissionSubtitles = { - {UsersDefaultKey, kli18nc("Room permission type", "This is the power level for all new users when joining the room")}, - {StateDefaultKey, kli18nc("Room permission type", "This is used for all state events that do not have their own entry here")}, - {EventsDefaultKey, kli18nc("Room permission type", "This is used for all message events that do not have their own entry here")}, + {UsersDefaultKey, kli18nc("Room permission type", "This is the power level for all new users when joining the room.")}, + {StateDefaultKey, kli18nc("Room permission type", "This is used for all state-type events that do not have their own entry.")}, + {EventsDefaultKey, kli18nc("Room permission type", "This is used for all message-type events that do not have their own entry.")}, }; -// Permissions that should use the event default. +// Permissions that should use the message event default. static const QStringList eventPermissions = { u"m.room.message"_s, u"m.reaction"_s, u"m.room.redaction"_s, + u"org.matrix.msc3381.poll.start"_s, + u"org.matrix.msc3381.poll.response"_s, + u"org.matrix.msc3381.poll.end"_s, +}; + +// Permissions related to messaging. +static const QStringList messagingPermissions = { + u"m.reaction"_s, + u"m.room.redaction"_s, + u"org.matrix.msc3672.beacon_info"_s, + u"org.matrix.msc3381.poll.start"_s, + u"org.matrix.msc3381.poll.response"_s, + u"org.matrix.msc3381.poll.end"_s, +}; + +// Permissions related to general room management. +static const QStringList generalPermissions = { + u"m.room.power_levels"_s, + u"m.room.name"_s, + u"m.room.avatar"_s, + u"m.room.canonical_alias"_s, + u"m.room.topic"_s, + u"m.room.encryption"_s, + u"m.room.history_visibility"_s, + u"m.room.pinned_events"_s, + u"m.room.tombstone"_s, + u"m.room.server_acl"_s, + u"m.space.child"_s, + u"m.space.parent"_s, }; }; @@ -194,6 +231,12 @@ QVariant PermissionsModel::data(const QModelIndex &index, int role) const if (role == IsBasicPermissionRole) { return basicPermissions.contains(permission); } + if (role == IsMessagePermissionRole) { + return messagingPermissions.contains(permission); + } + if (role == IsGeneralPermissionRole) { + return generalPermissions.contains(permission); + } return {}; } @@ -213,6 +256,8 @@ QHash PermissionsModel::roleNames() const roles[LevelNameRole] = "levelName"; roles[IsDefaultValueRole] = "isDefaultValue"; roles[IsBasicPermissionRole] = "isBasicPermission"; + roles[IsMessagePermissionRole] = "isMessagePermission"; + roles[IsGeneralPermissionRole] = "isGeneralPermission"; return roles; } diff --git a/src/settings/models/permissionsmodel.h b/src/settings/models/permissionsmodel.h index 26a6592b7..82738cf58 100644 --- a/src/settings/models/permissionsmodel.h +++ b/src/settings/models/permissionsmodel.h @@ -36,6 +36,8 @@ public: LevelNameRole, /**< The current power level for the permission as a string. */ IsDefaultValueRole, /**< Whether the permission is a default value, e.g. for users. */ IsBasicPermissionRole, /**< Whether the permission is one of the basic ones, e.g. kick, ban, etc. */ + IsMessagePermissionRole, /** Permissions related to messaging. */ + IsGeneralPermissionRole, /** Permissions related to general room management. */ }; Q_ENUM(Roles)