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({
0072                                     "text": i18n("Member (0)"),
0073                                     "powerLevel": 0
0074                                 });
0075                                 powerLevelModel.append({
0076                                     "text": i18n("Moderator (50)"),
0077                                     "powerLevel": 50
0078                                 });
0079                                 powerLevelModel.append({
0080                                     "text": i18n("Admin (100)"),
0081                                     "powerLevel": 100
0082                                 });
0083                             }
0084                             currentIndex = indexOfValue(powerLevel);
0085                         }
0086                         onActivated: {
0087                             room.setUserPowerLevel(userId, currentValue);
0088                         }
0089                     }
0090                 }
0091             }
0092         }
0093         FormCard.FormDelegateSeparator {
0094             below: userListSearchCard
0095         }
0096         FormCard.AbstractFormDelegate {
0097             id: userListSearchCard
0098             visible: room.canSendState("m.room.power_levels")
0099 
0100             contentItem: Kirigami.SearchField {
0101                 id: userListSearchField
0102 
0103                 autoAccept: false
0104 
0105                 Layout.fillWidth: true
0106 
0107                 Keys.onUpPressed: userListView.decrementCurrentIndex()
0108                 Keys.onDownPressed: userListView.incrementCurrentIndex()
0109 
0110                 onAccepted: {
0111                     let currentUser = userListView.itemAtIndex(userListView.currentIndex);
0112                     currentUser.action.trigger();
0113                 }
0114             }
0115             QQC2.Popup {
0116                 id: userListSearchPopup
0117 
0118                 x: userListSearchField.x
0119                 y: userListSearchField.y - height
0120                 width: userListSearchField.width
0121                 height: {
0122                     let maxHeight = userListSearchField.mapToGlobal(userListSearchField.x, userListSearchField.y).y - Kirigami.Units.largeSpacing * 3;
0123                     let minHeight = Kirigami.Units.gridUnit * 2 + userListSearchPopup.padding * 2;
0124                     let filterContentHeight = userListView.contentHeight + userListSearchPopup.padding * 2;
0125                     return Math.max(Math.min(filterContentHeight, maxHeight), minHeight);
0126                 }
0127                 padding: Kirigami.Units.smallSpacing
0128                 leftPadding: Kirigami.Units.smallSpacing / 2
0129                 rightPadding: Kirigami.Units.smallSpacing / 2
0130                 modal: false
0131                 onClosed: userListSearchField.text = ""
0132 
0133                 background: Kirigami.ShadowedRectangle {
0134                     property color borderColor: Kirigami.Theme.textColor
0135 
0136                     Kirigami.Theme.colorSet: Kirigami.Theme.View
0137                     Kirigami.Theme.inherit: false
0138 
0139                     radius: 4
0140                     color: Kirigami.Theme.backgroundColor
0141 
0142                     border {
0143                         color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
0144                         width: 1
0145                     }
0146 
0147                     shadow {
0148                         xOffset: 0
0149                         yOffset: 4
0150                         color: Qt.rgba(0, 0, 0, 0.3)
0151                         size: 8
0152                     }
0153                 }
0154 
0155                 contentItem: QQC2.ScrollView {
0156                     // HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
0157                     QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
0158 
0159                     ListView {
0160                         id: userListView
0161                         clip: true
0162 
0163                         model: UserFilterModel {
0164                             id: userListFilterModel
0165                             sourceModel: userListModel
0166                             filterText: userListSearchField.text
0167 
0168                             onFilterTextChanged: {
0169                                 if (filterText.length > 0 && !userListSearchPopup.visible) {
0170                                     userListSearchPopup.open();
0171                                 } else if (filterText.length <= 0 && userListSearchPopup.visible) {
0172                                     userListSearchPopup.close();
0173                                 }
0174                             }
0175                         }
0176 
0177                         delegate: Delegates.RoundedItemDelegate {
0178                             id: userListItem
0179 
0180                             required property string userId
0181                             required property string avatar
0182                             required property string name
0183                             required property int powerLevel
0184                             required property string powerLevelString
0185 
0186                             text: name
0187 
0188                             contentItem: RowLayout {
0189                                 KirigamiComponents.Avatar {
0190                                     Layout.preferredWidth: Kirigami.Units.iconSizes.medium
0191                                     Layout.preferredHeight: Kirigami.Units.iconSizes.medium
0192                                     source: userListItem.avatar ? ("image://" + userListItem.avatar) : ""
0193                                     name: userListItem.name
0194                                 }
0195 
0196                                 Delegates.SubtitleContentItem {
0197                                     itemDelegate: userListItem
0198                                     subtitle: userListItem.userId
0199                                     labelItem.textFormat: Text.PlainText
0200                                     subtitleItem.textFormat: Text.PlainText
0201                                     Layout.fillWidth: true
0202                                 }
0203 
0204                                 QQC2.Label {
0205                                     visible: userListItem.powerLevel > 0
0206 
0207                                     text: userListItem.powerLevelString
0208                                     color: Kirigami.Theme.disabledTextColor
0209                                     textFormat: Text.PlainText
0210                                     wrapMode: Text.NoWrap
0211                                 }
0212                             }
0213 
0214                             action: Kirigami.Action {
0215                                 id: editPowerLevelAction
0216                                 onTriggered: {
0217                                     userListSearchPopup.close();
0218                                     let dialog = powerLevelDialog.createObject(applicationWindow().overlay, {
0219                                         room: root.room,
0220                                         userId: userListItem.userId,
0221                                         powerLevel: userListItem.powerLevel
0222                                     });
0223                                     dialog.open();
0224                                 }
0225                             }
0226 
0227                             Component {
0228                                 id: powerLevelDialog
0229                                 PowerLevelDialog {
0230                                     id: powerLevelDialog
0231                                 }
0232                             }
0233                         }
0234                     }
0235                 }
0236             }
0237         }
0238     }
0239 
0240     FormCard.FormHeader {
0241         visible: room.canSendState("m.room.power_levels")
0242         title: i18n("Default permissions")
0243     }
0244     FormCard.FormCard {
0245         visible: room.canSendState("m.room.power_levels")
0246         FormCard.FormComboBoxDelegate {
0247             text: i18n("Default user power level")
0248             description: i18n("This is power level for all new users when joining the room")
0249             textRole: "text"
0250             valueRole: "powerLevel"
0251             model: powerLevelModel
0252             Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel)
0253             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0254                 room.defaultUserPowerLevel = currentValue;
0255             }
0256         }
0257         FormCard.FormComboBoxDelegate {
0258             text: i18n("Default power level to set the room state")
0259             description: i18n("This is used for all state events that do not have their own entry here")
0260             textRole: "text"
0261             valueRole: "powerLevel"
0262             model: powerLevelModel
0263             Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel)
0264             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0265                 room.statePowerLevel = currentValue;
0266             }
0267         }
0268         FormCard.FormComboBoxDelegate {
0269             text: i18n("Default power level to send messages")
0270             description: i18n("This is used for all message events that do not have their own entry here")
0271             textRole: "text"
0272             valueRole: "powerLevel"
0273             model: powerLevelModel
0274             Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel)
0275             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0276                 room.defaultEventPowerLevel = currentValue;
0277             }
0278         }
0279     }
0280 
0281     FormCard.FormHeader {
0282         visible: room.canSendState("m.room.power_levels")
0283         title: i18n("Basic permissions")
0284     }
0285     FormCard.FormCard {
0286         visible: room.canSendState("m.room.power_levels")
0287         FormCard.FormComboBoxDelegate {
0288             text: i18n("Invite users")
0289             textRole: "text"
0290             valueRole: "powerLevel"
0291             model: powerLevelModel
0292             Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel)
0293             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0294                 room.invitePowerLevel = currentValue;
0295             }
0296         }
0297         FormCard.FormComboBoxDelegate {
0298             text: i18n("Kick users")
0299             textRole: "text"
0300             valueRole: "powerLevel"
0301             model: powerLevelModel
0302             Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel)
0303             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0304                 room.kickPowerLevel = currentValue;
0305             }
0306         }
0307         FormCard.FormComboBoxDelegate {
0308             text: i18n("Ban users")
0309             textRole: "text"
0310             valueRole: "powerLevel"
0311             model: powerLevelModel
0312             Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel)
0313             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0314                 room.banPowerLevel = currentValue;
0315             }
0316         }
0317         FormCard.FormComboBoxDelegate {
0318             text: i18n("Remove message sent by other users")
0319             textRole: "text"
0320             valueRole: "powerLevel"
0321             model: powerLevelModel
0322             Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel)
0323             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0324                 room.redactPowerLevel = currentValue;
0325             }
0326         }
0327     }
0328 
0329     FormCard.FormHeader {
0330         visible: room.canSendState("m.room.power_levels")
0331         title: i18n("Event permissions")
0332     }
0333     FormCard.FormCard {
0334         visible: room.canSendState("m.room.power_levels")
0335         FormCard.FormComboBoxDelegate {
0336             text: i18n("Change user permissions")
0337             description: "m.room.power_levels"
0338             textRole: "text"
0339             valueRole: "powerLevel"
0340             model: powerLevelModel
0341             Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel)
0342             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0343                 room.powerLevelPowerLevel = currentValue;
0344             }
0345         }
0346         FormCard.FormComboBoxDelegate {
0347             text: i18n("Change the room name")
0348             description: "m.room.name"
0349             textRole: "text"
0350             valueRole: "powerLevel"
0351             model: powerLevelModel
0352             Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel)
0353             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0354                 room.namePowerLevel = currentValue;
0355             }
0356         }
0357         FormCard.FormComboBoxDelegate {
0358             text: i18n("Change the room avatar")
0359             description: "m.room.avatar"
0360             textRole: "text"
0361             valueRole: "powerLevel"
0362             model: powerLevelModel
0363             Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel)
0364             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0365                 room.avatarPowerLevel = currentValue;
0366             }
0367         }
0368         FormCard.FormComboBoxDelegate {
0369             text: i18n("Change the room canonical alias")
0370             description: "m.room.canonical_alias"
0371             textRole: "text"
0372             valueRole: "powerLevel"
0373             model: powerLevelModel
0374             Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel)
0375             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0376                 room.canonicalAliasPowerLevel = currentValue;
0377             }
0378         }
0379         FormCard.FormComboBoxDelegate {
0380             text: i18n("Change the room topic")
0381             description: "m.room.topic"
0382             textRole: "text"
0383             valueRole: "powerLevel"
0384             model: powerLevelModel
0385             Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel)
0386             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0387                 room.topicPowerLevel = currentValue;
0388             }
0389         }
0390         FormCard.FormComboBoxDelegate {
0391             text: i18n("Enable encryption for the room")
0392             description: "m.room.encryption"
0393             textRole: "text"
0394             valueRole: "powerLevel"
0395             model: powerLevelModel
0396             Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel)
0397             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0398                 room.encryptionPowerLevel = currentValue;
0399             }
0400         }
0401         FormCard.FormComboBoxDelegate {
0402             text: i18n("Change the room history visibility")
0403             description: "m.room.history_visibility"
0404             textRole: "text"
0405             valueRole: "powerLevel"
0406             model: powerLevelModel
0407             Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel)
0408             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0409                 room.historyVisibilityPowerLevel = currentValue;
0410             }
0411         }
0412         FormCard.FormComboBoxDelegate {
0413             text: i18n("Set pinned events")
0414             description: "m.room.pinned_events"
0415             textRole: "text"
0416             valueRole: "powerLevel"
0417             model: powerLevelModel
0418             Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel)
0419             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0420                 room.pinnedEventsPowerLevel = currentValue;
0421             }
0422         }
0423         FormCard.FormComboBoxDelegate {
0424             text: i18n("Upgrade the room")
0425             description: "m.room.tombstone"
0426             textRole: "text"
0427             valueRole: "powerLevel"
0428             model: powerLevelModel
0429             Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel)
0430             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0431                 room.tombstonePowerLevel = currentValue;
0432             }
0433         }
0434         FormCard.FormComboBoxDelegate {
0435             text: i18n("Set the room server access control list (ACL)")
0436             description: "m.room.server_acl"
0437             textRole: "text"
0438             valueRole: "powerLevel"
0439             model: powerLevelModel
0440             Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel)
0441             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0442                 room.serverAclPowerLevel = currentValue;
0443             }
0444         }
0445         FormCard.FormComboBoxDelegate {
0446             visible: room.isSpace
0447             text: i18n("Set the children of this space")
0448             description: "m.space.child"
0449             textRole: "text"
0450             valueRole: "powerLevel"
0451             model: powerLevelModel
0452             Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
0453             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0454                 room.spaceChildPowerLevel = currentValue;
0455             }
0456         }
0457         FormCard.FormComboBoxDelegate {
0458             text: i18n("Set the parent space of this room")
0459             description: "m.space.parent"
0460             textRole: "text"
0461             valueRole: "powerLevel"
0462             model: powerLevelModel
0463             Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
0464             onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
0465                 room.spaceParentPowerLevel = currentValue;
0466             }
0467         }
0468     }
0469 }