diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2022-05-27 16:31:54 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2022-05-27 17:01:58 +0200 |
commit | 6c6d43691d98aa02513350b52fe736fff6d6071d (patch) | |
tree | 6155225e4005f22c2a613a77912227b05fb48ff7 /resources | |
parent | Translated using Weblate (Russian) (diff) | |
download | nheko-6c6d43691d98aa02513350b52fe736fff6d6071d.tar.xz |
Add basic powerlevel editor
Diffstat (limited to 'resources')
-rw-r--r-- | resources/qml/Completer.qml | 28 | ||||
-rw-r--r-- | resources/qml/Root.qml | 16 | ||||
-rw-r--r-- | resources/qml/components/ReorderableListview.qml | 126 | ||||
-rw-r--r-- | resources/qml/dialogs/PowerLevelEditor.qml | 347 | ||||
-rw-r--r-- | resources/qml/dialogs/RoomSettings.qml | 12 | ||||
-rw-r--r-- | resources/res.qrc | 6 |
6 files changed, 523 insertions, 12 deletions
diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index a16ffa65..7e14e734 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -13,6 +13,7 @@ Control { id: popup property alias currentIndex: listView.currentIndex + property string roomId property string completerName property var completer property bool bottomToTop: true @@ -24,6 +25,10 @@ Control { property int rowSpacing: 5 property alias count: listView.count + Component.onCompleted: { + console.log("RRRRRRRRRR: " + roomId); + } + signal completionClicked(string completion) signal completionSelected(string id) @@ -65,18 +70,22 @@ Control { function finishCompletion() { if (popup.completerName == "room") popup.completionSelected(listView.itemAtIndex(currentIndex).modelData.roomid); + else if (popup.completerName == "user") + popup.completionSelected(listView.itemAtIndex(currentIndex).modelData.userid); } - onCompleterNameChanged: { + function changeCompleter() { if (completerName) { - completer = TimelineManager.completerFor(completerName, completerName == "room" ? "" : room.roomId); + completer = TimelineManager.completerFor(completerName, completerName == "room" ? "" : (popup.roomId != "" ? popup.roomId : room.roomId)); completer.setSearchString(""); } else { completer = undefined; } currentIndex = -1 } + onCompleterNameChanged: changeCompleter() + onRoomIdChanged: changeCompleter() bottomPadding: 1 leftPadding: 1 @@ -131,6 +140,8 @@ Control { popup.completionClicked(completer.completionAt(model.index)); if (popup.completerName == "room") popup.completionSelected(model.roomid); + else if (popup.completerName == "user") + popup.completionSelected(model.userid); } } Ripple { @@ -151,7 +162,7 @@ Control { RowLayout { id: del - anchors.centerIn: parent + anchors.centerIn: centerRowContent ? parent : undefined spacing: rowSpacing Avatar { @@ -160,7 +171,7 @@ Control { displayName: model.displayName userid: model.userid url: model.avatarUrl.replace("mxc://", "image://MxcImage/") - onClicked: popup.completionClicked(completer.completionAt(model.index)) + enabled: false } Label { @@ -216,7 +227,7 @@ Control { displayName: model.shortcode //userid: model.shortcode url: model.url.replace("mxc://", "image://MxcImage/") - onClicked: popup.completionClicked(completer.completionAt(model.index)) + enabled: false crop: false } @@ -249,10 +260,7 @@ Control { displayName: model.roomName roomid: model.roomid url: model.avatarUrl.replace("mxc://", "image://MxcImage/") - onClicked: { - popup.completionClicked(completer.completionAt(model.index)); - popup.completionSelected(model.roomid); - } + enabled: false } Label { @@ -281,7 +289,7 @@ Control { displayName: model.roomName roomid: model.roomid url: model.avatarUrl.replace("mxc://", "image://MxcImage/") - onClicked: popup.completionClicked(completer.completionAt(model.index)) + enabled: false } Label { diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index 00600508..86ddc649 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -51,6 +51,22 @@ Pane { } + function showPLEditor(settings) { + var dialog = plEditor.createObject(timelineRoot, { + "roomSettings": settings + }); + dialog.show(); + destroyOnClose(dialog); + } + + Component { + id: plEditor + + PowerLevelEditor { + } + } + + Component { id: roomSettingsComponent diff --git a/resources/qml/components/ReorderableListview.qml b/resources/qml/components/ReorderableListview.qml new file mode 100644 index 00000000..7e9ae05d --- /dev/null +++ b/resources/qml/components/ReorderableListview.qml @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: 2022 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQml.Models 2.1 +import im.nheko 1.0 +import ".." + +Item { + id: root + + property alias model: visualModel.model + property Component delegate + + Component { + id: dragDelegate + + MouseArea { + id: dragArea + + required property var model + required property int index + + enabled: model.moveable == undefined || model.moveable + + property bool held: false + + anchors { left: parent.left; right: parent.right } + height: content.height + + drag.target: held ? content : undefined + drag.axis: Drag.YAxis + + onPressAndHold: held = true + onPressed: if (mouse.source !== Qt.MouseEventNotSynthesized) { held = true } + onReleased: held = false + onHeldChanged: if (held) ListView.view.currentIndex = dragArea.index; else ListView.view.currentIndex = -1 + + Rectangle { + id: content + + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + width: dragArea.width; height: actualDelegate.implicitHeight + 4 + + border.width: dragArea.enabled ? 1 : 0 + border.color: Nheko.colors.highlight + + color: dragArea.held ? Nheko.colors.highlight : Nheko.colors.base + Behavior on color { ColorAnimation { duration: 100 } } + + radius: 2 + + Drag.active: dragArea.held + Drag.source: dragArea + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + + states: State { + when: dragArea.held + + ParentChange { target: content; parent: root } + AnchorChanges { + target: content + anchors { horizontalCenter: undefined; verticalCenter: undefined } + } + } + + Loader { + id: actualDelegate + sourceComponent: root.delegate + property var model: dragArea.model + property int index: dragArea.index + property int offset: -view.contentY + dragArea.y + anchors { fill: parent; margins: 2 } + } + + } + + DropArea { + enabled: index != 0 || model.moveable == undefined || model.moveable + anchors { fill: parent; margins: 8 } + + onEntered: (drag)=> { + visualModel.model.move(drag.source.index, dragArea.index) + } + } + + } + } + + + DelegateModel { + id: visualModel + + delegate: dragDelegate + } + + ListView { + id: view + + clip: true + + anchors { fill: parent; margins: 2 } + ScrollHelper { + flickable: parent + anchors.fill: parent + } + + model: visualModel + + highlightRangeMode: ListView.ApplyRange + preferredHighlightBegin: 0.2 * height + preferredHighlightEnd: 0.8 * height + + spacing: 4 + cacheBuffer: 50 + } + + + } + + diff --git a/resources/qml/dialogs/PowerLevelEditor.qml b/resources/qml/dialogs/PowerLevelEditor.qml new file mode 100644 index 00000000..241585f9 --- /dev/null +++ b/resources/qml/dialogs/PowerLevelEditor.qml @@ -0,0 +1,347 @@ +// SPDX-FileCopyrightText: 2022 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import "../components" +import QtQuick 2.12 +import QtQuick.Controls 2.5 +import QtQuick.Layouts 1.3 +import im.nheko 1.0 + + +ApplicationWindow { + id: plEditorW + + property var roomSettings + property var editingModel: Nheko.editPowerlevels(roomSettings.roomId) + + modality: Qt.NonModal + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + minimumWidth: 300 + minimumHeight: 400 + + title: qsTr("Permissions in %1").arg(roomSettings.roomName); + +// Shortcut { +// sequence: StandardKey.Cancel +// onActivated: dbb.rejected() +// } + + ColumnLayout { + anchors.margins: Nheko.paddingMedium + anchors.fill: parent + spacing: 0 + + + MatrixText { + text: qsTr("Be careful when editing permissions. You can't lower the permissions of people with a same or higher level than you. Be careful when promoting others.") + font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) + Layout.fillWidth: true + Layout.fillHeight: false + color: Nheko.colors.text + Layout.bottomMargin: Nheko.paddingMedium + } + + TabBar { + id: bar + width: parent.width + palette: Nheko.colors + + component TabB : TabButton { + id: control + + contentItem: Text { + text: control.text + font: control.font + opacity: enabled ? 1.0 : 0.3 + color: control.down ? Nheko.colors.highlightedText : Nheko.colors.text + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle { + border.color: control.down ? Nheko.colors.highlight : Nheko.theme.separator + color: control.checked ? Nheko.colors.highlight : Nheko.colors.base + border.width: 1 + radius: 2 + } + } + TabB { + text: qsTr("Roles") + } + TabB { + text: qsTr("Users") + } + } + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + color: Nheko.colors.alternateBase + border.width: 1 + border.color: Nheko.theme.separator + + StackLayout { + anchors.fill: parent + anchors.margins: Nheko.paddingMedium + currentIndex: bar.currentIndex + + + ColumnLayout { + spacing: Nheko.paddingMedium + + MatrixText { + text: qsTr("Move permissions between roles to change them") + font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) + Layout.fillWidth: true + Layout.fillHeight: false + color: Nheko.colors.text + } + + ReorderableListview { + Layout.fillWidth: true + Layout.fillHeight: true + + model: editingModel.types + + delegate: RowLayout { + Column { + Layout.fillWidth: true + + Text { visible: model.isType; text: model.displayName; color: Nheko.colors.text} + Text { + visible: !model.isType; + text: { + if (editingModel.adminLevel == model.powerlevel) + return qsTr("Administrator (%1)").arg(model.powerlevel) + else if (editingModel.moderatorLevel == model.powerlevel) + return qsTr("Moderator (%1)").arg(model.powerlevel) + else + return qsTr("Custom (%1)").arg(model.powerlevel) + } + color: Nheko.colors.text + } + } + + ImageButton { + Layout.alignment: Qt.AlignRight + Layout.rightMargin: 2 + image: model.isType ? ":/icons/icons/ui/dismiss.svg" : ":/icons/icons/ui/add-square-button.svg" + visible: !model.isType || model.removeable + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: model.isType ? qsTr("Remove event type") : qsTr("Add event type") + onClicked: { + if (model.isType) { + editingModel.types.remove(index); + } else { + typeEntry.y = offset + typeEntry.visible = true + typeEntry.index = index; + typeEntry.forceActiveFocus() + } + } + } + } + MatrixTextField { + id: typeEntry + + property int index + + width: parent.width + z: 5 + visible: false + + color: Nheko.colors.text + + Keys.onPressed: { + if (typeEntry.text.includes('.') && event.matches(StandardKey.InsertParagraphSeparator)) { + editingModel.types.add(typeEntry.index, typeEntry.text) + typeEntry.visible = false; + typeEntry.clear(); + event.accepted = true; + } + else if (event.matches(StandardKey.Cancel)) { + typeEntry.visible = false; + typeEntry.clear(); + event.accepted = true; + } + } + } + } + + } + ColumnLayout { + spacing: Nheko.paddingMedium + + MatrixText { + text: qsTr("Move users up or down to change their permissions") + font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) + Layout.fillWidth: true + Layout.fillHeight: false + } + + ReorderableListview { + Layout.fillWidth: true + Layout.fillHeight: true + + model: editingModel.users + + Column{ + id: userEntryCompleter + + property int index: 0 + + visible: false + + width: parent.width + spacing: 1 + z: 5 + MatrixTextField { + id: userEntry + + width: parent.width + //font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) + color: Nheko.colors.text + onTextEdited: { + userCompleter.completer.searchString = text; + } + Keys.onPressed: { + if (event.key == Qt.Key_Up || event.key == Qt.Key_Backtab) { + event.accepted = true; + userCompleter.up(); + } else if (event.key == Qt.Key_Down || event.key == Qt.Key_Tab) { + event.accepted = true; + if (event.key == Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier)) + userCompleter.up(); + else + userCompleter.down(); + } else if (event.matches(StandardKey.InsertParagraphSeparator)) { + userCompleter.finishCompletion(); + event.accepted = true; + } else if (event.matches(StandardKey.Cancel)) { + typeEntry.visible = false; + typeEntry.clear(); + event.accepted = true; + } + } + } + + + Completer { + id: userCompleter + + visible: userEntry.text.length > 0 + width: parent.width + roomId: plEditorW.roomSettings.roomId + completerName: "user" + bottomToTop: false + fullWidth: true + avatarHeight: Nheko.avatarSize / 2 + avatarWidth: Nheko.avatarSize / 2 + centerRowContent: false + rowMargin: 2 + rowSpacing: 2 + } + } + + Connections { + function onCompletionSelected(id) { + console.log("selected: " + id); + editingModel.users.add(userEntryCompleter.index, id); + userEntry.clear(); + userEntryCompleter.visible = false; + } + + function onCountChanged() { + if (userCompleter.count > 0 && (userCompleter.currentIndex < 0 || userCompleter.currentIndex >= userCompleter.count)) + userCompleter.currentIndex = 0; + + } + + target: userCompleter + } + + delegate: RowLayout { + //anchors { fill: parent; margins: 2 } + id: row + + Avatar { + id: avatar + + Layout.preferredHeight: Nheko.avatarSize / 2 + Layout.preferredWidth: Nheko.avatarSize / 2 + Layout.leftMargin: 2 + userid: model.mxid + url: { + if (model.isUser) + return model.avatarUrl.replace("mxc://", "image://MxcImage/") + else if (editingModel.adminLevel >= model.powerlevel) + return "image://colorimage/:/icons/icons/ui/ribbon_star.svg?" + Nheko.colors.buttonText; + else if (editingModel.moderatorLevel >= model.powerlevel) + return "image://colorimage/:/icons/icons/ui/ribbon.svg?" + Nheko.colors.buttonText; + else + return "image://colorimage/:/icons/icons/ui/person.svg?" + Nheko.colors.buttonText; + } + displayName: model.displayName + enabled: false + } + Column { + Layout.fillWidth: true + + Text { visible: model.isUser; text: model.displayName; color: Nheko.colors.text} + Text { visible: model.isUser; text: model.mxid; color: Nheko.colors.text} + Text { + visible: !model.isUser; + text: { + if (editingModel.adminLevel == model.powerlevel) + return qsTr("Administrator (%1)").arg(model.powerlevel) + else if (editingModel.moderatorLevel == model.powerlevel) + return qsTr("Moderator (%1)").arg(model.powerlevel) + else + return qsTr("Custom (%1)").arg(model.powerlevel) + } + color: Nheko.colors.text + } + } + + ImageButton { + Layout.alignment: Qt.AlignRight + Layout.rightMargin: 2 + image: model.isUser ? ":/icons/icons/ui/dismiss.svg" : ":/icons/icons/ui/add-square-button.svg" + visible: !model.isUser || model.removeable + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: model.isUser ? qsTr("Remove user") : qsTr("Add user") + onClicked: { + if (model.isUser) { + editingModel.users.remove(index); + } else { + userEntryCompleter.y = offset + userEntryCompleter.visible = true + userEntryCompleter.index = index; + userEntry.forceActiveFocus() + } + } + } + } + } + + } + } + } + } + + footer: DialogButtonBox { + id: dbb + + standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel + onAccepted: { + editingModel.commit(); + plEditorW.close(); + } + onRejected: plEditorW.close(); + } + + } diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml index 4a7b24fe..332a7b09 100644 --- a/resources/qml/dialogs/RoomSettings.qml +++ b/resources/qml/dialogs/RoomSettings.qml @@ -336,6 +336,18 @@ ApplicationWindow { } Label { + text: qsTr("Permission") + color: Nheko.colors.text + } + + Button { + text: qsTr("Configure") + ToolTip.text: qsTr("View and change the permissions in this room") + onClicked: timelineRoot.showPLEditor(roomSettings) + Layout.alignment: Qt.AlignRight + } + + Label { text: qsTr("Sticker & Emote Settings") color: Nheko.colors.text } diff --git a/resources/res.qrc b/resources/res.qrc index 35b06704..6e3023ea 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -127,6 +127,7 @@ <file>qml/components/AvatarListTile.qml</file> <file>qml/components/FlatButton.qml</file> <file>qml/components/MainWindowDialog.qml</file> + <file>qml/components/ReorderableListview.qml</file> <file>qml/components/TextButton.qml</file> <file>qml/delegates/Encrypted.qml</file> <file>qml/delegates/FileMessage.qml</file> @@ -148,22 +149,23 @@ <file>qml/device-verification/Waiting.qml</file> <file>qml/dialogs/CreateDirect.qml</file> <file>qml/dialogs/CreateRoom.qml</file> + <file>qml/dialogs/HiddenEventsDialog.qml</file> <file>qml/dialogs/ImageOverlay.qml</file> <file>qml/dialogs/ImagePackEditorDialog.qml</file> <file>qml/dialogs/ImagePackSettingsDialog.qml</file> - <file>qml/dialogs/PhoneNumberInputDialog.qml</file> <file>qml/dialogs/InputDialog.qml</file> <file>qml/dialogs/InviteDialog.qml</file> <file>qml/dialogs/JoinRoomDialog.qml</file> <file>qml/dialogs/LeaveRoomDialog.qml</file> <file>qml/dialogs/LogoutDialog.qml</file> + <file>qml/dialogs/PhoneNumberInputDialog.qml</file> + <file>qml/dialogs/PowerLevelEditor.qml</file> <file>qml/dialogs/RawMessageDialog.qml</file> <file>qml/dialogs/ReadReceipts.qml</file> <file>qml/dialogs/RoomDirectory.qml</file> <file>qml/dialogs/RoomMembers.qml</file> <file>qml/dialogs/RoomSettings.qml</file> <file>qml/dialogs/UserProfile.qml</file> - <file>qml/dialogs/HiddenEventsDialog.qml</file> <file>qml/emoji/EmojiPicker.qml</file> <file>qml/emoji/StickerPicker.qml</file> <file>qml/ui/NhekoSlider.qml</file> |