Warning, /network/neochat/src/qml/Permissions.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0003 
0004 import QtQuick
0005 import QtQuick.Controls as QQC2
0006 import QtQuick.Layouts
0007 
0008 import org.kde.kirigami as Kirigami
0009 import org.kde.kirigamiaddons.formcard as FormCard
0010 import org.kde.kirigamiaddons.delegates as Delegates
0011 import org.kde.kirigamiaddons.labs.components as KirigamiComponents
0012 import org.kde.kitemmodels
0013 
0014 import org.kde.neochat
0015 
0016 FormCard.FormCardPage {
0017     id: root
0018 
0019     property NeoChatRoom room
0020 
0021     title: i18nc('@title:window', 'Permissions')
0022 
0023     property UserListModel userListModel: UserListModel {
0024         id: userListModel
0025         room: root.room
0026     }
0027 
0028     property ListModel powerLevelModel: ListModel {
0029         id: powerLevelModel
0030     }
0031 
0032     FormCard.FormHeader {
0033         title: i18n("Privileged Users")
0034     }
0035     FormCard.FormCard {
0036         Repeater {
0037             model: KSortFilterProxyModel {
0038                 sourceModel: userListModel
0039                 sortRoleName: "powerLevel"
0040                 sortOrder: Qt.DescendingOrder
0041                 filterRowCallback: function(source_row, source_parent) {
0042                     let powerLevelRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), UserListModel.PowerLevelRole)
0043                     return powerLevelRole > 0;
0044                 }
0045             }
0046             delegate: FormCard.FormTextDelegate {
0047                 text: name
0048                 textItem.textFormat: Text.PlainText
0049                 description: userId
0050                 contentItem.children: RowLayout {
0051                     spacing: Kirigami.Units.largeSpacing
0052                     QQC2.Label {
0053                         id: powerLevelLabel
0054                         visible: !room.canSendState("m.room.power_levels") || (room.getUserPowerLevel(room.localUser.id) <= model.powerLevel && model.userId != room.localUser.id)
0055                         text: powerLevelString
0056                         color: Kirigami.Theme.disabledTextColor
0057                     }
0058                     QQC2.ComboBox {
0059                         focusPolicy: Qt.NoFocus // provided by parent
0060                         model: powerLevelModel
0061                         textRole: "text"
0062                         valueRole: "powerLevel"
0063                         visible: !powerLevelLabel.visible
0064                         Component.onCompleted: {
0065                             /**
0066                                 * This is very silly but the only way to populate the model with
0067                                 * translated strings. Done here because the model needs to be filled
0068                                 * before the first delegate sets it's current index.
0069                                 */
0070                             if (powerLevelModel.count == 0) {
0071                                 powerLevelModel.append({"text":  i18n("Member (0)"), "powerLevel": 0});
0072                                 powerLevelModel.append({"text":  i18n("Moderator (50)"), "powerLevel": 50});
0073                                 powerLevelModel.append({"text":  i18n("Admin (100)"), "powerLevel": 100});
0074                             }
0075                             currentIndex = indexOfValue(powerLevel)
0076                         }
0077                         onActivated: {
0078                             room.setUserPowerLevel(userId, currentValue)
0079                         }
0080                     }
0081                 }
0082             }
0083         }
0084         FormCard.FormDelegateSeparator { below: userListSearchCard }
0085         FormCard.AbstractFormDelegate {
0086             id: userListSearchCard
0087             visible: room.canSendState("m.room.power_levels")
0088 
0089             contentItem: Kirigami.SearchField {
0090                 id: userListSearchField
0091 
0092                 autoAccept: false
0093 
0094                 Layout.fillWidth: true
0095 
0096                 Keys.onUpPressed: userListView.decrementCurrentIndex()
0097                 Keys.onDownPressed: userListView.incrementCurrentIndex()
0098 
0099                 onAccepted: {
0100                     let currentUser = userListView.itemAtIndex(userListView.currentIndex);
0101                     currentUser.action.trigger();
0102                 }
0103             }
0104             QQC2.Popup {
0105                 id: userListSearchPopup
0106 
0107                 x: userListSearchField.x
0108                 y: userListSearchField.y - height
0109                 width: userListSearchField.width
0110                 height: {
0111                     let maxHeight = userListSearchField.mapToGlobal(userListSearchField.x, userListSearchField.y).y - Kirigami.Units.largeSpacing * 3;
0112                     let minHeight = Kirigami.Units.gridUnit * 2 + userListSearchPopup.padding * 2;
0113                     let filterContentHeight = userListView.contentHeight + userListSearchPopup.padding * 2;
0114 
0115                     return Math.max(Math.min(filterContentHeight, maxHeight), minHeight);
0116                 }
0117                 padding: Kirigami.Units.smallSpacing
0118                 leftPadding: Kirigami.Units.smallSpacing / 2
0119                 rightPadding: Kirigami.Units.smallSpacing / 2
0120                 modal: false
0121                 onClosed: userListSearchField.text = ""
0122 
0123                 background: Kirigami.ShadowedRectangle {
0124                     property color borderColor: Kirigami.Theme.textColor
0125 
0126                     Kirigami.Theme.colorSet: Kirigami.Theme.View
0127                     Kirigami.Theme.inherit: false
0128 
0129                     radius: 4
0130                     color: Kirigami.Theme.backgroundColor
0131 
0132                     border {
0133                         color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
0134                         width: 1
0135                     }
0136 
0137                     shadow {
0138                         xOffset: 0
0139                         yOffset: 4
0140                         color: Qt.rgba(0, 0, 0, 0.3)
0141                         size: 8
0142                     }
0143                 }
0144 
0145                 contentItem: QQC2.ScrollView {
0146                     // HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
0147                     QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
0148 
0149                     ListView {
0150                         id: userListView
0151                         clip: true
0152 
0153                         model: UserFilterModel {
0154                             id: userListFilterModel
0155                             sourceModel: userListModel
0156                             filterText: userListSearchField.text
0157 
0158                             onFilterTextChanged: {
0159                                 if (filterText.length > 0 && !userListSearchPopup.visible) {
0160                                     userListSearchPopup.open()
0161                                 } else if (filterText.length <= 0 && userListSearchPopup.visible) {
0162                                     userListSearchPopup.close()
0163                                 }
0164                             }
0165                         }
0166 
0167                         delegate: Delegates.RoundedItemDelegate {
0168                             id: userListItem
0169 
0170                             required property string userId
0171                             required property string avatar
0172                             required property string name
0173                             required property int powerLevel
0174                             required property string powerLevelString
0175 
0176                             text: name
0177 
0178                             contentItem: RowLayout {
0179                                 KirigamiComponents.Avatar {
0180                                     Layout.preferredWidth: Kirigami.Units.iconSizes.medium
0181                                     Layout.preferredHeight: Kirigami.Units.iconSizes.medium
0182                                     source: userListItem.avatar ? ("image://" + userListItem.avatar) : ""
0183                                     name: userListItem.name
0184                                 }
0185 
0186                                 Delegates.SubtitleContentItem {
0187                                     itemDelegate: userListItem
0188                                     subtitle: userListItem.userId
0189                                     labelItem.textFormat: Text.PlainText
0190                                     subtitleItem.textFormat: Text.PlainText
0191                                     Layout.fillWidth: true
0192                                 }
0193 
0194                                 QQC2.Label {
0195                                     visible: userListItem.powerLevel > 0
0196 
0197                                     text: userListItem.powerLevelString
0198                                     color: Kirigami.Theme.disabledTextColor
0199                                     textFormat: Text.PlainText
0200                                     wrapMode: Text.NoWrap
0201                                 }
0202                             }
0203 
0204                             action: Kirigami.Action {
0205                                 id: editPowerLevelAction
0206                                 onTriggered: {
0207                                     userListSearchPopup.close()
0208                                     let dialog = powerLevelDialog.createObject(applicationWindow().overlay, {
0209                                         room: root.room,
0210                                         userId: userListItem.userId,
0211                                         powerLevel: userListItem.powerLevel
0212                                     });
0213                                     dialog.open();
0214                                 }
0215                             }
0216 
0217                             Component {
0218                                 id: powerLevelDialog
0219                                 PowerLevelDialog {
0220                                     id: powerLevelDialog
0221                                 }
0222                             }
0223                         }
0224                     }
0225                 }
0226             }
0227         }
0228     }
0229 
0230     FormCard.FormHeader {
0231         visible: room.canSendState("m.room.power_levels")
0232         title: i18n("Default permissions")
0233     }
0234     FormCard.FormCard {
0235         visible: room.canSendState("m.room.power_levels")
0236         FormCard.FormComboBoxDelegate {
0237             text: i18n("Default user power level")
0238             description: i18n("This is power level for all new users when joining the room")
0239             textRole: "text"
0240             valueRole: "powerLevel"
0241             model: powerLevelModel
0242             Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel)
0243             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultUserPowerLevel = currentValue
0244         }
0245         FormCard.FormComboBoxDelegate {
0246             text: i18n("Default power level to set the room state")
0247             description: i18n("This is used for all state events that do not have their own entry here")
0248             textRole: "text"
0249             valueRole: "powerLevel"
0250             model: powerLevelModel
0251             Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel)
0252             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.statePowerLevel = currentValue
0253         }
0254         FormCard.FormComboBoxDelegate {
0255             text: i18n("Default power level to send messages")
0256             description: i18n("This is used for all message events that do not have their own entry here")
0257             textRole: "text"
0258             valueRole: "powerLevel"
0259             model: powerLevelModel
0260             Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel)
0261             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultEventPowerLevel = currentValue
0262         }
0263     }
0264 
0265     FormCard.FormHeader {
0266         visible: room.canSendState("m.room.power_levels")
0267         title: i18n("Basic permissions")
0268     }
0269     FormCard.FormCard {
0270         visible: room.canSendState("m.room.power_levels")
0271         FormCard.FormComboBoxDelegate {
0272             text: i18n("Invite users")
0273             textRole: "text"
0274             valueRole: "powerLevel"
0275             model: powerLevelModel
0276             Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel)
0277             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.invitePowerLevel = currentValue
0278         }
0279         FormCard.FormComboBoxDelegate {
0280             text: i18n("Kick users")
0281             textRole: "text"
0282             valueRole: "powerLevel"
0283             model: powerLevelModel
0284             Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel)
0285             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.kickPowerLevel = currentValue
0286         }
0287         FormCard.FormComboBoxDelegate {
0288             text: i18n("Ban users")
0289             textRole: "text"
0290             valueRole: "powerLevel"
0291             model: powerLevelModel
0292             Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel)
0293             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.banPowerLevel = currentValue
0294         }
0295         FormCard.FormComboBoxDelegate {
0296             text: i18n("Remove message sent by other users")
0297             textRole: "text"
0298             valueRole: "powerLevel"
0299             model: powerLevelModel
0300             Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel)
0301             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.redactPowerLevel = currentValue
0302         }
0303     }
0304 
0305     FormCard.FormHeader {
0306         visible: room.canSendState("m.room.power_levels")
0307         title: i18n("Event permissions")
0308     }
0309     FormCard.FormCard {
0310         visible: room.canSendState("m.room.power_levels")
0311         FormCard.FormComboBoxDelegate {
0312             text: i18n("Change user permissions")
0313             description: "m.room.power_levels"
0314             textRole: "text"
0315             valueRole: "powerLevel"
0316             model: powerLevelModel
0317             Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel)
0318             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.powerLevelPowerLevel = currentValue
0319         }
0320         FormCard.FormComboBoxDelegate {
0321             text: i18n("Change the room name")
0322             description: "m.room.name"
0323             textRole: "text"
0324             valueRole: "powerLevel"
0325             model: powerLevelModel
0326             Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel)
0327             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.namePowerLevel = currentValue
0328         }
0329         FormCard.FormComboBoxDelegate {
0330             text: i18n("Change the room avatar")
0331             description: "m.room.avatar"
0332             textRole: "text"
0333             valueRole: "powerLevel"
0334             model: powerLevelModel
0335             Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel)
0336             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.avatarPowerLevel = currentValue
0337         }
0338         FormCard.FormComboBoxDelegate {
0339             text: i18n("Change the room canonical alias")
0340             description: "m.room.canonical_alias"
0341             textRole: "text"
0342             valueRole: "powerLevel"
0343             model: powerLevelModel
0344             Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel)
0345             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.canonicalAliasPowerLevel = currentValue
0346         }
0347         FormCard.FormComboBoxDelegate {
0348             text: i18n("Change the room topic")
0349             description: "m.room.topic"
0350             textRole: "text"
0351             valueRole: "powerLevel"
0352             model: powerLevelModel
0353             Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel)
0354             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.topicPowerLevel = currentValue
0355         }
0356         FormCard.FormComboBoxDelegate {
0357             text: i18n("Enable encryption for the room")
0358             description: "m.room.encryption"
0359             textRole: "text"
0360             valueRole: "powerLevel"
0361             model: powerLevelModel
0362             Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel)
0363             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.encryptionPowerLevel = currentValue
0364         }
0365         FormCard.FormComboBoxDelegate {
0366             text: i18n("Change the room history visibility")
0367             description: "m.room.history_visibility"
0368             textRole: "text"
0369             valueRole: "powerLevel"
0370             model: powerLevelModel
0371             Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel)
0372             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.historyVisibilityPowerLevel = currentValue
0373         }
0374         FormCard.FormComboBoxDelegate {
0375             text: i18n("Set pinned events")
0376             description: "m.room.pinned_events"
0377             textRole: "text"
0378             valueRole: "powerLevel"
0379             model: powerLevelModel
0380             Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel)
0381             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.pinnedEventsPowerLevel = currentValue
0382         }
0383         FormCard.FormComboBoxDelegate {
0384             text: i18n("Upgrade the room")
0385             description: "m.room.tombstone"
0386             textRole: "text"
0387             valueRole: "powerLevel"
0388             model: powerLevelModel
0389             Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel)
0390             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.tombstonePowerLevel = currentValue
0391         }
0392         FormCard.FormComboBoxDelegate {
0393             text: i18n("Set the room server access control list (ACL)")
0394             description: "m.room.server_acl"
0395             textRole: "text"
0396             valueRole: "powerLevel"
0397             model: powerLevelModel
0398             Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel)
0399             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.serverAclPowerLevel = currentValue
0400         }
0401         FormCard.FormComboBoxDelegate {
0402             visible: room.isSpace
0403             text: i18n("Set the children of this space")
0404             description: "m.space.child"
0405             textRole: "text"
0406             valueRole: "powerLevel"
0407             model: powerLevelModel
0408             Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
0409             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceChildPowerLevel = currentValue
0410         }
0411         FormCard.FormComboBoxDelegate {
0412             text: i18n("Set the parent space of this room")
0413             description: "m.space.parent"
0414             textRole: "text"
0415             valueRole: "powerLevel"
0416             model: powerLevelModel
0417             Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
0418             onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceParentPowerLevel = currentValue
0419         }
0420     }
0421 }