diff --git a/src/qml/RoomSettings/General.qml b/src/qml/RoomSettings/General.qml index a125fc1c5..0a8ebdecf 100644 --- a/src/qml/RoomSettings/General.qml +++ b/src/qml/RoomSettings/General.qml @@ -8,358 +8,333 @@ import QtQuick.Layouts 1.15 import QtQuick.Window 2.15 import org.kde.kirigami 2.15 as Kirigami -import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm +import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents import org.kde.neochat 1.0 -Kirigami.ScrollablePage { +FormCard.FormCardPage { id: root property NeoChatRoom room title: i18n("General") - topPadding: 0 - leftPadding: 0 - rightPadding: 0 - ColumnLayout { - spacing: 0 - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18n("Room Information") + + FormCard.FormHeader { + title: i18n("Room Information") + } + FormCard.FormCard { + FormCard.AbstractFormDelegate { + background: null + contentItem: RowLayout { + Item { + Layout.fillWidth: true + } + KirigamiComponents.Avatar { + id: avatar + Layout.alignment: Qt.AlignRight + name: room.name + source: room.avatarMediaId ? ("image://mxc/" + room.avatarMediaId) : "" + implicitWidth: Kirigami.Units.iconSizes.medium + implicitHeight: Kirigami.Units.iconSizes.medium + } + QQC2.Button { + Layout.alignment: Qt.AlignLeft + enabled: room.canSendState("m.room.avatar") + visible: enabled + icon.name: "cloud-upload" + text: i18n("Update avatar") + display: QQC2.AbstractButton.IconOnly + + onClicked: { + const fileDialog = openFileDialog.createObject(QQC2.ApplicationWindow.overlay) + + fileDialog.chosen.connect(function(path) { + if (!path) return + + room.changeAvatar(path) + }) + + fileDialog.open() + } + + QQC2.ToolTip.text: text + QQC2.ToolTip.visible: hovered + } + Item { + Layout.fillWidth: true + } + } } - MobileForm.FormCard { - Layout.fillWidth: true + FormCard.FormTextFieldDelegate { + id: roomNameField + label: i18n("Room name:") + text: room.name + enabled: room.canSendState("m.room.name") + } + FormCard.AbstractFormDelegate { + id: roomTopicField + enabled: room.canSendState("m.room.topic") + background: Item {} contentItem: ColumnLayout { - spacing: 0 - MobileForm.AbstractFormDelegate { + QQC2.Label { + id: roomTopicLabel + text: i18n("Room topic:") Layout.fillWidth: true - background: Item {} - contentItem: RowLayout { - Item { - Layout.fillWidth: true + } + QQC2.TextArea { + Accessible.description: roomTopicLabel.text + Layout.fillWidth: true + text: room.topic + onTextChanged: roomTopicField.text = text + } + } + } + FormCard.AbstractFormDelegate { + background: Item {} + contentItem: RowLayout { + Item { + Layout.fillWidth: true + } + QQC2.Button { + Layout.bottomMargin: Kirigami.Units.smallSpacing + Layout.topMargin: Kirigami.Units.smallSpacing + enabled: room.name !== roomNameField.text || room.topic !== roomTopicField.text + text: i18n("Save") + onClicked: { + if (room.name != roomNameField.text) { + room.setName(roomNameField.text) } - KirigamiComponents.Avatar { - id: avatar - Layout.alignment: Qt.AlignRight - name: room.name - source: room.avatarMediaId ? ("image://mxc/" + room.avatarMediaId) : "" - implicitWidth: Kirigami.Units.iconSizes.medium - implicitHeight: Kirigami.Units.iconSizes.medium - } - QQC2.Button { - Layout.alignment: Qt.AlignLeft - enabled: room.canSendState("m.room.avatar") - visible: enabled - icon.name: "cloud-upload" - text: i18n("Update avatar") - display: QQC2.AbstractButton.IconOnly - onClicked: { - const fileDialog = openFileDialog.createObject(QQC2.ApplicationWindow.overlay) - - fileDialog.chosen.connect(function(path) { - if (!path) return - - room.changeAvatar(path) - }) - - fileDialog.open() - } - - QQC2.ToolTip.text: text - QQC2.ToolTip.visible: hovered - } - Item { - Layout.fillWidth: true + if (room.topic != roomTopicField.text) { + room.setTopic(roomTopicField.text) } } } - MobileForm.FormTextFieldDelegate { - id: roomNameField - label: i18n("Room name:") - text: room.name - enabled: room.canSendState("m.room.name") + } + } + FormCard.FormTextDelegate { + id: roomIdDelegate + text: i18n("Room ID") + description: room.id + + contentItem.children: QQC2.Button { + visible: roomIdDelegate.hovered + text: i18n("Copy room ID to clipboard") + icon.name: "edit-copy" + display: QQC2.AbstractButton.IconOnly + + onClicked: { + Clipboard.saveText(room.id) } - MobileForm.AbstractFormDelegate { - id: roomTopicField - Layout.fillWidth: true - enabled: room.canSendState("m.room.topic") - background: Item {} - contentItem: ColumnLayout { - QQC2.Label { - id: roomTopicLabel - text: i18n("Room topic:") - Layout.fillWidth: true - } - QQC2.TextArea { - Accessible.description: roomTopicLabel.text - Layout.fillWidth: true - text: room.topic - onTextChanged: roomTopicField.text = text - } + + QQC2.ToolTip.text: text + QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay + QQC2.ToolTip.visible: hovered + } + } + FormCard.FormTextDelegate { + text: i18n("Room version") + description: room.version + + contentItem.children: QQC2.Button { + visible: room.canSwitchVersions() + enabled: room.version < room.maxRoomVersion + text: i18n("Upgrade Room") + icon.name: "arrow-up-double" + + onClicked: { + if (room.canSwitchVersions()) { + roomUpgradeSheet.currentRoomVersion = room.version + roomUpgradeSheet.open() } } - MobileForm.AbstractFormDelegate { - Layout.fillWidth: true - background: Item {} - contentItem: RowLayout { - Item { - Layout.fillWidth: true - } - QQC2.Button { - Layout.bottomMargin: Kirigami.Units.smallSpacing - Layout.topMargin: Kirigami.Units.smallSpacing - enabled: room.name !== roomNameField.text || room.topic !== roomTopicField.text - text: i18n("Save") - onClicked: { - if (room.name != roomNameField.text) { - room.setName(roomNameField.text) - } - if (room.topic != roomTopicField.text) { - room.setTopic(roomTopicField.text) - } - } - } - } + QQC2.ToolTip { + text: text + delay: Kirigami.Units.toolTipDelay } - MobileForm.FormTextDelegate { - id: roomIdDelegate - text: i18n("Room ID") - description: room.id + } + } + } - contentItem.children: QQC2.Button { - visible: roomIdDelegate.hovered - text: i18n("Copy room ID to clipboard") - icon.name: "edit-copy" + FormCard.FormHeader { + title: i18n("Aliases") + } + FormCard.FormCard { + FormCard.FormTextDelegate { + visible: room.aliases.length <= 0 + text: i18n("No canonical alias set") + } + Repeater { + id: altAliasRepeater + model: room.aliases.slice().reverse() + + delegate: FormCard.FormTextDelegate { + text: modelData + description: room.canonicalAlias.length > 0 && modelData === room.canonicalAlias ? "Canonical alias" : "" + contentItem.children: [ + QQC2.ToolButton { + id: setCanonicalAliasButton + visible: modelData !== room.canonicalAlias && room.canSendState("m.room.canonical_alias") + text: i18n("Make this alias the room's canonical alias") + icon.name: "checkmark" display: QQC2.AbstractButton.IconOnly onClicked: { - Clipboard.saveText(room.id) + room.setCanonicalAlias(modelData) } - - QQC2.ToolTip.text: text - QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay - QQC2.ToolTip.visible: hovered - } - } - MobileForm.FormTextDelegate { - text: i18n("Room version") - description: room.version - - contentItem.children: QQC2.Button { - visible: room.canSwitchVersions() - enabled: room.version < room.maxRoomVersion - text: i18n("Upgrade Room") - icon.name: "arrow-up-double" + QQC2.ToolTip { + text: setCanonicalAliasButton.text + delay: Kirigami.Units.toolTipDelay + } + }, + QQC2.ToolButton { + id: deleteButton + visible: room.canSendState("m.room.canonical_alias") + text: i18n("Delete alias") + icon.name: "edit-delete-remove" + display: QQC2.AbstractButton.IconOnly onClicked: { - if (room.canSwitchVersions()) { - roomUpgradeSheet.currentRoomVersion = room.version - roomUpgradeSheet.open() - } + room.unmapAlias(modelData) } - QQC2.ToolTip { - text: text + text: deleteButton.text delay: Kirigami.Units.toolTipDelay } } - } + ] + } } + FormCard.AbstractFormDelegate { + visible: room.canSendState("m.room.canonical_alias") - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18n("Aliases") - } - MobileForm.FormCard { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormTextDelegate { - visible: room.aliases.length <= 0 - text: i18n("No canonical alias set") - } - Repeater { - id: altAliasRepeater - model: room.aliases.slice().reverse() + contentItem : RowLayout { + Kirigami.ActionTextField { + id: aliasAddField - delegate: MobileForm.FormTextDelegate { - text: modelData - description: room.canonicalAlias.length > 0 && modelData === room.canonicalAlias ? "Canonical alias" : "" - contentItem.children: [ - QQC2.ToolButton { - id: setCanonicalAliasButton - visible: modelData !== room.canonicalAlias && room.canSendState("m.room.canonical_alias") - text: i18n("Make this alias the room's canonical alias") - icon.name: "checkmark" - display: QQC2.AbstractButton.IconOnly - - onClicked: { - room.setCanonicalAlias(modelData) - } - QQC2.ToolTip { - text: setCanonicalAliasButton.text - delay: Kirigami.Units.toolTipDelay - } - }, - QQC2.ToolButton { - id: deleteButton - visible: room.canSendState("m.room.canonical_alias") - text: i18n("Delete alias") - icon.name: "edit-delete-remove" - display: QQC2.AbstractButton.IconOnly - - onClicked: { - room.unmapAlias(modelData) - } - QQC2.ToolTip { - text: deleteButton.text - delay: Kirigami.Units.toolTipDelay - } - } - ] - - } - } - MobileForm.AbstractFormDelegate { Layout.fillWidth: true - visible: room.canSendState("m.room.canonical_alias") - contentItem : RowLayout { - Kirigami.ActionTextField { - id: aliasAddField + placeholderText: i18n("#new_alias:server.org") - Layout.fillWidth: true - - placeholderText: i18n("#new_alias:server.org") - - rightActions: Kirigami.Action { - icon.name: "edit-clear" - visible: aliasAddField.text.length > 0 - onTriggered: { - aliasAddField.text = "" - } - } - - onAccepted: { - room.mapAlias(aliasAddField.text) - } - } - QQC2.Button { - id: addButton - - text: i18n("Add new alias") - Accessible.name: text - icon.name: "list-add" - display: QQC2.AbstractButton.IconOnly - - onClicked: { - room.mapAlias(aliasAddField.text) - } - - QQC2.ToolTip { - text: addButton.text - delay: Kirigami.Units.toolTipDelay - } + rightActions: Kirigami.Action { + icon.name: "edit-clear" + visible: aliasAddField.text.length > 0 + onTriggered: { + aliasAddField.text = "" } } - } - } - } - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18n("URL Previews") - } - MobileForm.FormCard { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormCheckDelegate { - text: i18n("Enable URL previews by default for room members") - checked: room.defaultUrlPreviewState - visible: room.canSendState("org.matrix.room.preview_urls") - onToggled: { - room.defaultUrlPreviewState = checked + onAccepted: { + room.mapAlias(aliasAddField.text) } } - MobileForm.FormCheckDelegate { - text: i18n("Enable URL previews") - // Most users won't see the above setting so tell them the default. - description: room.defaultUrlPreviewState ? i18n("URL previews are enabled by default in this room") : i18n("URL previews are disabled by default in this room") - checked: room.urlPreviewEnabled - onToggled: { - room.urlPreviewEnabled = checked - } - } - } - } - - Kirigami.InlineMessage { - Layout.fillWidth: true - Layout.maximumWidth: Kirigami.Units.gridUnit * 30 - Layout.alignment: Qt.AlignHCenter - text: i18n("This room continues another conversation.") - type: Kirigami.MessageType.Information - visible: room.predecessorId && room.connection.room(room.predecessorId) - actions: Kirigami.Action { - text: i18n("See older messages…") - onTriggered: { - RoomManager.enterRoom(Controller.activeConnection.room(room.predecessorId)); - root.close(); - } - } - } - Kirigami.InlineMessage { - Layout.fillWidth: true - Layout.maximumWidth: Kirigami.Units.gridUnit * 30 - Layout.alignment: Qt.AlignHCenter - text: i18n("This room has been replaced.") - type: Kirigami.MessageType.Information - visible: room.successorId && room.connection.room(room.successorId) - actions: Kirigami.Action { - text: i18n("See new room…") - onTriggered: { - RoomManager.enterRoom(Controller.activeConnection.room(room.successorId)); - root.close(); - } - } - } - - Component { - id: openFileDialog - - OpenFileDialog { - parentWindow: root.Window.window - } - } - - Kirigami.OverlaySheet { - id: roomUpgradeSheet - - property var currentRoomVersion - - title: i18n("Upgrade the Room") - Kirigami.FormLayout { - QQC2.SpinBox { - id: spinBox - Kirigami.FormData.label: i18n("Select new version") - from: room.version - to: room.maxRoomVersion - value: room.version - } QQC2.Button { - text: i18n("Confirm") + id: addButton + + text: i18n("Add new alias") + Accessible.name: text + icon.name: "list-add" + display: QQC2.AbstractButton.IconOnly + onClicked: { - room.switchVersion(spinBox.value) - roomUpgradeSheet.close() + room.mapAlias(aliasAddField.text) + } + + QQC2.ToolTip { + text: addButton.text + delay: Kirigami.Units.toolTipDelay } } } } } + + FormCard.FormHeader { + title: i18n("URL Previews") + } + FormCard.FormCard { + FormCard.FormCheckDelegate { + text: i18n("Enable URL previews by default for room members") + checked: room.defaultUrlPreviewState + visible: room.canSendState("org.matrix.room.preview_urls") + onToggled: { + room.defaultUrlPreviewState = checked + } + } + FormCard.FormCheckDelegate { + text: i18n("Enable URL previews") + // Most users won't see the above setting so tell them the default. + description: room.defaultUrlPreviewState ? i18n("URL previews are enabled by default in this room") : i18n("URL previews are disabled by default in this room") + checked: room.urlPreviewEnabled + onToggled: { + room.urlPreviewEnabled = checked + } + } + } + + Kirigami.InlineMessage { + Layout.maximumWidth: Kirigami.Units.gridUnit * 30 + Layout.alignment: Qt.AlignHCenter + text: i18n("This room continues another conversation.") + type: Kirigami.MessageType.Information + visible: room.predecessorId && room.connection.room(room.predecessorId) + actions: Kirigami.Action { + text: i18n("See older messages…") + onTriggered: { + RoomManager.enterRoom(Controller.activeConnection.room(room.predecessorId)); + root.close(); + } + } + } + Kirigami.InlineMessage { + Layout.maximumWidth: Kirigami.Units.gridUnit * 30 + Layout.alignment: Qt.AlignHCenter + text: i18n("This room has been replaced.") + type: Kirigami.MessageType.Information + visible: room.successorId && room.connection.room(room.successorId) + actions: Kirigami.Action { + text: i18n("See new room…") + onTriggered: { + RoomManager.enterRoom(Controller.activeConnection.room(room.successorId)); + root.close(); + } + } + } + + property Component openFileDialog: Component { + id: openFileDialog + + OpenFileDialog { + parentWindow: root.Window.window + } + } + + property Kirigami.OverlaySheet roomUpgradeSheet: Kirigami.OverlaySheet { + id: roomUpgradeSheet + + property var currentRoomVersion + + title: i18n("Upgrade the Room") + Kirigami.FormLayout { + QQC2.SpinBox { + id: spinBox + Kirigami.FormData.label: i18n("Select new version") + from: room.version + to: room.maxRoomVersion + value: room.version + } + QQC2.Button { + text: i18n("Confirm") + onClicked: { + room.switchVersion(spinBox.value) + roomUpgradeSheet.close() + } + } + } + } + } diff --git a/src/qml/RoomSettings/Permissions.qml b/src/qml/RoomSettings/Permissions.qml index 07b8a942c..1df589acf 100644 --- a/src/qml/RoomSettings/Permissions.qml +++ b/src/qml/RoomSettings/Permissions.qml @@ -6,441 +6,414 @@ import QtQuick.Controls 2.15 as QQC2 import QtQuick.Layouts 1.15 import org.kde.kirigami 2.15 as Kirigami -import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm +import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.kirigamiaddons.delegates 1.0 as Delegates import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents import org.kde.kitemmodels 1.0 import org.kde.neochat 1.0 -Kirigami.ScrollablePage { +FormCard.FormCardPage { id: root property NeoChatRoom room title: i18nc('@title:window', 'Permissions') - topPadding: 0 - leftPadding: 0 - rightPadding: 0 - UserListModel { + property UserListModel userListModel: UserListModel { id: userListModel room: root.room } - ListModel { + property ListModel powerLevelModel: ListModel { id: powerLevelModel } - ColumnLayout { - spacing: 0 - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18n("Privileged Users") - } - MobileForm.FormCard { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - Repeater { - model: KSortFilterProxyModel { - sourceModel: userListModel - sortRole: "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: MobileForm.FormTextDelegate { - text: name - description: userId - contentItem.children: RowLayout { - spacing: Kirigami.Units.largeSpacing - QQC2.Label { - visible: !room.canSendState("m.room.power_levels") - text: powerLevelString - color: Kirigami.Theme.disabledTextColor - } - QQC2.ComboBox { - focusPolicy: Qt.NoFocus // provided by parent - model: powerLevelModel - textRole: "text" - valueRole: "powerLevel" - visible: room.canSendState("m.room.power_levels") - Component.onCompleted: { - /** - * This is very silly but the only way to populate the model with - * translated strings. Done here because the model needs to be filled - * before the first delegate sets it's current index. - */ - if (powerLevelModel.count == 0) { - powerLevelModel.append({"text": i18n("Member (0)"), "powerLevel": 0}); - powerLevelModel.append({"text": i18n("Moderator (50)"), "powerLevel": 50}); - powerLevelModel.append({"text": i18n("Admin (100)"), "powerLevel": 100}); - } - currentIndex = indexOfValue(powerLevel) - } - onActivated: { - room.setUserPowerLevel(userId, currentValue) - } - } - } - } + FormCard.FormHeader { + title: i18n("Privileged Users") + } + FormCard.FormCard { + Repeater { + model: KSortFilterProxyModel { + sourceModel: 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; } - MobileForm.FormDelegateSeparator { below: userListSearchCard } - MobileForm.AbstractFormDelegate { - id: userListSearchCard - Layout.fillWidth: true - visible: 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: { - let currentUser = userListView.itemAtIndex(userListView.currentIndex); - currentUser.action.trigger(); - } + } + delegate: FormCard.FormTextDelegate { + text: name + description: userId + contentItem.children: RowLayout { + spacing: Kirigami.Units.largeSpacing + QQC2.Label { + visible: !room.canSendState("m.room.power_levels") + text: powerLevelString + color: Kirigami.Theme.disabledTextColor } - 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); + QQC2.ComboBox { + focusPolicy: Qt.NoFocus // provided by parent + model: powerLevelModel + textRole: "text" + valueRole: "powerLevel" + visible: room.canSendState("m.room.power_levels") + Component.onCompleted: { + /** + * This is very silly but the only way to populate the model with + * translated strings. Done here because the model needs to be filled + * before the first delegate sets it's current index. + */ + if (powerLevelModel.count == 0) { + powerLevelModel.append({"text": i18n("Member (0)"), "powerLevel": 0}); + powerLevelModel.append({"text": i18n("Moderator (50)"), "powerLevel": 50}); + powerLevelModel.append({"text": i18n("Admin (100)"), "powerLevel": 100}); + } + currentIndex = indexOfValue(powerLevel) } - 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: 4 - 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: 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 string 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 ? ("image://" + 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 - } - } - - action: Kirigami.Action { - id: editPowerLevelAction - onTriggered: { - userListSearchPopup.close() - let dialog = powerLevelDialog.createObject(applicationWindow().overlay, { - room: root.room, - userId: userListItem.userId, - powerLevel: userListItem.powerLevel - }); - dialog.open(); - } - } - - Component { - id: powerLevelDialog - PowerLevelDialog { - id: powerLevelDialog - } - } - } - } + onActivated: { + room.setUserPowerLevel(userId, currentValue) } } } } } + FormCard.FormDelegateSeparator { below: userListSearchCard } + FormCard.AbstractFormDelegate { + id: userListSearchCard + visible: room.canSendState("m.room.power_levels") - MobileForm.FormHeader { - Layout.fillWidth: true - visible: room.canSendState("m.room.power_levels") - title: i18n("Default permissions") - } - MobileForm.FormCard { - Layout.fillWidth: true - visible: room.canSendState("m.room.power_levels") - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormComboBoxDelegate { - text: i18n("Default user power level") - description: i18n("This is power level for all new users when joining the room") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultUserPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Default power level to set the room state") - description: i18n("This is used for all state events that do not have their own entry here") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.statePowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Default power level to send messages") - description: i18n("This is used for all message events that do not have their own entry here") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultEventPowerLevel = currentValue + contentItem: Kirigami.SearchField { + id: userListSearchField + + autoAccept: false + + Layout.fillWidth: true + + Keys.onUpPressed: userListView.decrementCurrentIndex() + Keys.onDownPressed: userListView.incrementCurrentIndex() + + onAccepted: { + let currentUser = userListView.itemAtIndex(userListView.currentIndex); + currentUser.action.trigger(); } } - } + QQC2.Popup { + id: userListSearchPopup - MobileForm.FormHeader { - Layout.fillWidth: true - visible: room.canSendState("m.room.power_levels") - title: i18n("Basic permissions") - } - MobileForm.FormCard { - Layout.fillWidth: true - visible: room.canSendState("m.room.power_levels") - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormComboBoxDelegate { - text: i18n("Invite users") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.invitePowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Kick users") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.kickPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Ban users") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.banPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Remove message sent by other users") - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.redactPowerLevel = currentValue - } - } - } + 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; - MobileForm.FormHeader { - Layout.fillWidth: true - visible: room.canSendState("m.room.power_levels") - title: i18n("Event permissions") - } - MobileForm.FormCard { - Layout.fillWidth: true - visible: room.canSendState("m.room.power_levels") - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormComboBoxDelegate { - text: i18n("Change user permissions") - description: "m.room.power_levels" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.powerLevelPowerLevel = currentValue + return Math.max(Math.min(filterContentHeight, maxHeight), minHeight); } - MobileForm.FormComboBoxDelegate { - text: i18n("Change the room name") - description: "m.room.name" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.namePowerLevel = currentValue + 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: 4 + 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 + } } - MobileForm.FormComboBoxDelegate { - text: i18n("Change the room avatar") - description: "m.room.avatar" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.avatarPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Change the room canonical alias") - description: "m.room.canonical_alias" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.canonicalAliasPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Change the room topic") - description: "m.room.topic" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.topicPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Enable encryption for the room") - description: "m.room.encryption" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.encryptionPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Change the room history visibility") - description: "m.room.history_visibility" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.historyVisibilityPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Set pinned events") - description: "m.room.pinned_events" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.pinnedEventsPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Upgrade the room") - description: "m.room.tombstone" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.tombstonePowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Set the room server access control list (ACL)") - description: "m.room.server_acl" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.serverAclPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - visible: room.isSpace - text: i18n("Set the children of this space") - description: "m.space.child" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceChildPowerLevel = currentValue - } - MobileForm.FormComboBoxDelegate { - text: i18n("Set the parent space of this room") - description: "m.space.parent" - textRole: "text" - valueRole: "powerLevel" - model: powerLevelModel - Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel) - onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceParentPowerLevel = currentValue + + 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: 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 string 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 ? ("image://" + 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 + } + } + + action: Kirigami.Action { + id: editPowerLevelAction + onTriggered: { + userListSearchPopup.close() + let dialog = powerLevelDialog.createObject(applicationWindow().overlay, { + room: root.room, + userId: userListItem.userId, + powerLevel: userListItem.powerLevel + }); + dialog.open(); + } + } + + Component { + id: powerLevelDialog + PowerLevelDialog { + id: powerLevelDialog + } + } + } + } } } } } + + FormCard.FormHeader { + visible: room.canSendState("m.room.power_levels") + title: i18n("Default permissions") + } + FormCard.FormCard { + visible: room.canSendState("m.room.power_levels") + FormCard.FormComboBoxDelegate { + text: i18n("Default user power level") + description: i18n("This is power level for all new users when joining the room") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultUserPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Default power level to set the room state") + description: i18n("This is used for all state events that do not have their own entry here") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.statePowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Default power level to send messages") + description: i18n("This is used for all message events that do not have their own entry here") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.defaultEventPowerLevel = currentValue + } + } + + FormCard.FormHeader { + visible: room.canSendState("m.room.power_levels") + title: i18n("Basic permissions") + } + FormCard.FormCard { + visible: room.canSendState("m.room.power_levels") + FormCard.FormComboBoxDelegate { + text: i18n("Invite users") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.invitePowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Kick users") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.kickPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Ban users") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.banPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Remove message sent by other users") + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.redactPowerLevel = currentValue + } + } + + FormCard.FormHeader { + visible: room.canSendState("m.room.power_levels") + title: i18n("Event permissions") + } + FormCard.FormCard { + visible: room.canSendState("m.room.power_levels") + FormCard.FormComboBoxDelegate { + text: i18n("Change user permissions") + description: "m.room.power_levels" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.powerLevelPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Change the room name") + description: "m.room.name" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.namePowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Change the room avatar") + description: "m.room.avatar" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.avatarPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Change the room canonical alias") + description: "m.room.canonical_alias" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.canonicalAliasPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Change the room topic") + description: "m.room.topic" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.topicPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Enable encryption for the room") + description: "m.room.encryption" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.encryptionPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Change the room history visibility") + description: "m.room.history_visibility" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.historyVisibilityPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Set pinned events") + description: "m.room.pinned_events" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.pinnedEventsPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Upgrade the room") + description: "m.room.tombstone" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.tombstonePowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Set the room server access control list (ACL)") + description: "m.room.server_acl" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.serverAclPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + visible: room.isSpace + text: i18n("Set the children of this space") + description: "m.space.child" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceChildPowerLevel = currentValue + } + FormCard.FormComboBoxDelegate { + text: i18n("Set the parent space of this room") + description: "m.space.parent" + textRole: "text" + valueRole: "powerLevel" + model: powerLevelModel + Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel) + onCurrentValueChanged: if(room.canSendState("m.room.power_levels")) room.spaceParentPowerLevel = currentValue + } + } } diff --git a/src/qml/RoomSettings/Security.qml b/src/qml/RoomSettings/Security.qml index d65b6d106..a5c31ef92 100644 --- a/src/qml/RoomSettings/Security.qml +++ b/src/qml/RoomSettings/Security.qml @@ -6,138 +6,118 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 as QQC2 import QtQuick.Layouts 1.15 import org.kde.kirigami 2.15 as Kirigami -import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm +import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.neochat 1.0 -Kirigami.ScrollablePage { +FormCard.FormCardPage { id: root property NeoChatRoom room property string needUpgradeRoom: i18n("You need to upgrade this room to a newer version to enable this setting.") title: i18n("Security") - topPadding: 0 - leftPadding: 0 - rightPadding: 0 - ColumnLayout { - spacing: 0 - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18nc("@option:check", "Encryption") - } - MobileForm.FormCard { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormSwitchDelegate { - id: enableEncryptionSwitch - text: i18n("Enable encryption") - description: i18nc("option:check", "Once enabled, encryption cannot be disabled.") - enabled: room.canEncryptRoom - checked: room.usesEncryption - onToggled: if (checked) { - let dialog = confirmEncryptionDialog.createObject(applicationWindow(), {room: room}); - dialog.open(); - } - } + + FormCard.FormHeader { + title: i18nc("@option:check", "Encryption") + } + FormCard.FormCard { + FormCard.FormSwitchDelegate { + id: enableEncryptionSwitch + text: i18n("Enable encryption") + description: i18nc("option:check", "Once enabled, encryption cannot be disabled.") + enabled: room.canEncryptRoom + checked: room.usesEncryption + onToggled: if (checked) { + let dialog = confirmEncryptionDialog.createObject(applicationWindow(), {room: room}); + dialog.open(); } } + } - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18nc("@option:check", "Access") - } - MobileForm.FormCard { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Private (invite only)") - description: i18n("Only invited people can join.") - checked: room.joinRule === "invite" - enabled: room.canSendState("m.room.join_rules") - onCheckedChanged: if (checked) { - room.joinRule = "invite"; - } - } - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Space members") - description: i18n("Anyone in a space can find and join.") + - (!["8", "9", "10"].includes(room.version) ? `\n${needUpgradeRoom}` : "") - checked: room.joinRule === "restricted" - enabled: room.canSendState("m.room.join_rules") && ["8", "9", "10"].includes(room.version) && false - onCheckedChanged: if (checked) { - room.joinRule = "restricted"; - } - } - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Knock") - description: i18n("People not in the room need to request an invite to join the room.") + - (!["7", "8", "9", "10"].includes(room.version) ? `\n${needUpgradeRoom}` : "") - checked: room.joinRule === "knock" - // https://spec.matrix.org/v1.4/rooms/#feature-matrix - enabled: room.canSendState("m.room.join_rules") && ["7", "8", "9", "10"].includes(room.version) - onCheckedChanged: if (checked) { - room.joinRule = "knock"; - } - } - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Public") - description: i18nc("@option:check", "Anyone can find and join.") - checked: room.joinRule === "public" - enabled: room.canSendState("m.room.join_rules") - onCheckedChanged: if (checked) { - room.joinRule = "public"; - } - } + FormCard.FormHeader { + title: i18nc("@option:check", "Access") + } + FormCard.FormCard { + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Private (invite only)") + description: i18n("Only invited people can join.") + checked: room.joinRule === "invite" + enabled: room.canSendState("m.room.join_rules") + onCheckedChanged: if (checked) { + room.joinRule = "invite"; } } - - MobileForm.FormHeader { - Layout.fillWidth: true - title: i18nc("@option:check", "Message history visibility") + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Space members") + description: i18n("Anyone in a space can find and join.") + + (!["8", "9", "10"].includes(room.version) ? `\n${needUpgradeRoom}` : "") + checked: room.joinRule === "restricted" + enabled: room.canSendState("m.room.join_rules") && ["8", "9", "10"].includes(room.version) && false + onCheckedChanged: if (checked) { + room.joinRule = "restricted"; + } } - MobileForm.FormCard { - Layout.fillWidth: true - contentItem: ColumnLayout { - spacing: 0 - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Anyone") - description: i18nc("@option:check", "Anyone, regardless of whether they have joined, can view history.") - checked: room.historyVisibility === "world_readable" - enabled: room.canSendState("m.room.history_visibility") - onCheckedChanged: if (checked) { - room.historyVisibility = "world_readable" - } - } - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Members only") - description: i18nc("@option:check", "All members can view the entire message history, even before they joined.") - checked: room.historyVisibility === "shared" - enabled: room.canSendState("m.room.history_visibility") - onCheckedChanged: if (checked) { - room.historyVisibility = "shared" - } - } - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Members only (since invite)") - description: i18nc("@option:check", "New members can view the message history from the point they were invited to the room.") - checked: room.historyVisibility === "invited" - enabled: room.canSendState("m.room.history_visibility") - onCheckedChanged: if (checked) { - room.historyVisibility = "invited" - } - } - MobileForm.FormRadioDelegate { - text: i18nc("@option:check", "Members only (since joining)") - description: i18nc("@option:check", "New members can view the message history from the point they joined the room.") - checked: room.historyVisibility === "joined" - enabled: room.canSendState("m.room.history_visibility") - onCheckedChanged: if (checked) { - room.historyVisibility = "joined" - } - } + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Knock") + description: i18n("People not in the room need to request an invite to join the room.") + + (!["7", "8", "9", "10"].includes(room.version) ? `\n${needUpgradeRoom}` : "") + checked: room.joinRule === "knock" + // https://spec.matrix.org/v1.4/rooms/#feature-matrix + enabled: room.canSendState("m.room.join_rules") && ["7", "8", "9", "10"].includes(room.version) + onCheckedChanged: if (checked) { + room.joinRule = "knock"; + } + } + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Public") + description: i18nc("@option:check", "Anyone can find and join.") + checked: room.joinRule === "public" + enabled: room.canSendState("m.room.join_rules") + onCheckedChanged: if (checked) { + room.joinRule = "public"; + } + } + } + + FormCard.FormHeader { + title: i18nc("@option:check", "Message history visibility") + } + FormCard.FormCard { + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Anyone") + description: i18nc("@option:check", "Anyone, regardless of whether they have joined, can view history.") + checked: room.historyVisibility === "world_readable" + enabled: room.canSendState("m.room.history_visibility") + onCheckedChanged: if (checked) { + room.historyVisibility = "world_readable" + } + } + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Members only") + description: i18nc("@option:check", "All members can view the entire message history, even before they joined.") + checked: room.historyVisibility === "shared" + enabled: room.canSendState("m.room.history_visibility") + onCheckedChanged: if (checked) { + room.historyVisibility = "shared" + } + } + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Members only (since invite)") + description: i18nc("@option:check", "New members can view the message history from the point they were invited to the room.") + checked: room.historyVisibility === "invited" + enabled: room.canSendState("m.room.history_visibility") + onCheckedChanged: if (checked) { + room.historyVisibility = "invited" + } + } + FormCard.FormRadioDelegate { + text: i18nc("@option:check", "Members only (since joining)") + description: i18nc("@option:check", "New members can view the message history from the point they joined the room.") + checked: room.historyVisibility === "joined" + enabled: room.canSendState("m.room.history_visibility") + onCheckedChanged: if (checked) { + room.historyVisibility = "joined" } } } @@ -155,7 +135,7 @@ Kirigami.ScrollablePage { } } - Component { + property Component confirmEncryptionDialog: Component { id: confirmEncryptionDialog ConfirmEncryptionDialog { @@ -168,7 +148,7 @@ Kirigami.ScrollablePage { } } - Connections { + property Connections connections: Connections { target: room onEncryption: { enableEncryptionSwitch.checked = room.usesEncryption