diff options
author | Loren Burkholder <computersemiexpert@outlook.com> | 2021-09-24 23:27:57 -0400 |
---|---|---|
committer | Loren Burkholder <computersemiexpert@outlook.com> | 2021-09-29 20:16:46 -0400 |
commit | 4e020645f118055b94eda5704573854e4b81cf80 (patch) | |
tree | 29f194dc60f38c97ba036b7e49180dbd0be6e3eb /resources/qml/dialogs | |
parent | Translated using Weblate (Dutch) (diff) | |
download | nheko-4e020645f118055b94eda5704573854e4b81cf80.tar.xz |
Reorganize all the dialogs into the dialogs folder
Diffstat (limited to 'resources/qml/dialogs')
-rw-r--r-- | resources/qml/dialogs/InviteDialog.qml | 160 | ||||
-rw-r--r-- | resources/qml/dialogs/RawMessageDialog.qml | 52 | ||||
-rw-r--r-- | resources/qml/dialogs/ReadReceipts.qml | 131 | ||||
-rw-r--r-- | resources/qml/dialogs/RoomDirectory.qml | 216 | ||||
-rw-r--r-- | resources/qml/dialogs/RoomMembers.qml | 180 | ||||
-rw-r--r-- | resources/qml/dialogs/RoomSettings.qml | 305 | ||||
-rw-r--r-- | resources/qml/dialogs/UserProfile.qml | 327 |
7 files changed, 1371 insertions, 0 deletions
diff --git a/resources/qml/dialogs/InviteDialog.qml b/resources/qml/dialogs/InviteDialog.qml new file mode 100644 index 00000000..86c176be --- /dev/null +++ b/resources/qml/dialogs/InviteDialog.qml @@ -0,0 +1,160 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import im.nheko 1.0 + +ApplicationWindow { + id: inviteDialogRoot + + property string roomId + property string plainRoomName + property InviteesModel invitees + + function addInvite() { + if (inviteeEntry.isValidMxid) { + invitees.addUser(inviteeEntry.text); + inviteeEntry.clear(); + } + } + + function cleanUpAndClose() { + if (inviteeEntry.isValidMxid) + addInvite(); + + invitees.accept(); + close(); + } + + title: qsTr("Invite users to %1").arg(plainRoomName) + height: 380 + width: 340 + palette: Nheko.colors + color: Nheko.colors.window + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(inviteDialogRoot) + + Shortcut { + sequence: "Ctrl+Enter" + onActivated: cleanUpAndClose() + } + + Shortcut { + sequence: StandardKey.Cancel + onActivated: inviteDialogRoot.close() + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Nheko.paddingMedium + spacing: Nheko.paddingMedium + + Label { + text: qsTr("User ID to invite") + Layout.fillWidth: true + color: Nheko.colors.text + } + + RowLayout { + spacing: Nheko.paddingMedium + + MatrixTextField { + id: inviteeEntry + + property bool isValidMxid: text.match("@.+?:.{3,}") + + backgroundColor: Nheko.colors.window + placeholderText: qsTr("@joe:matrix.org", "Example user id. The name 'joe' can be localized however you want.") + Layout.fillWidth: true + onAccepted: { + if (isValidMxid) + addInvite(); + + } + Component.onCompleted: forceActiveFocus() + Keys.onShortcutOverride: event.accepted = ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (event.modifiers & Qt.ControlModifier)) + Keys.onPressed: { + if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (event.modifiers === Qt.ControlModifier)) + cleanUpAndClose(); + + } + } + + Button { + text: qsTr("Add") + enabled: inviteeEntry.isValidMxid + onClicked: addInvite() + } + + } + + ListView { + id: inviteesList + + Layout.fillWidth: true + Layout.fillHeight: true + model: invitees + + delegate: RowLayout { + spacing: Nheko.paddingMedium + + Avatar { + width: Nheko.avatarSize + height: Nheko.avatarSize + userid: model.mxid + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + displayName: model.displayName + onClicked: TimelineManager.openGlobalUserProfile(model.mxid) + } + + ColumnLayout { + spacing: Nheko.paddingSmall + + Label { + text: model.displayName + color: TimelineManager.userColor(model ? model.mxid : "", Nheko.colors.window) + font.pointSize: fontMetrics.font.pointSize + } + + Label { + text: model.mxid + color: Nheko.colors.buttonText + font.pointSize: fontMetrics.font.pointSize * 0.9 + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + + } + + } + + } + + } + + footer: DialogButtonBox { + id: buttons + + Button { + text: qsTr("Invite") + DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole + enabled: invitees.count > 0 + onClicked: cleanUpAndClose() + } + + Button { + text: qsTr("Cancel") + DialogButtonBox.buttonRole: DialogButtonBox.DestructiveRole + onClicked: inviteDialogRoot.close() + } + + } + +} diff --git a/resources/qml/dialogs/RawMessageDialog.qml b/resources/qml/dialogs/RawMessageDialog.qml new file mode 100644 index 00000000..c171de7e --- /dev/null +++ b/resources/qml/dialogs/RawMessageDialog.qml @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import im.nheko 1.0 + +ApplicationWindow { + id: rawMessageRoot + + property alias rawMessage: rawMessageView.text + + height: 420 + width: 420 + palette: Nheko.colors + color: Nheko.colors.window + flags: Qt.Tool | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(rawMessageRoot) + + Shortcut { + sequence: StandardKey.Cancel + onActivated: rawMessageRoot.close() + } + + ScrollView { + anchors.margins: Nheko.paddingMedium + anchors.fill: parent + palette: Nheko.colors + padding: Nheko.paddingMedium + + TextArea { + id: rawMessageView + + font: Nheko.monospaceFont() + color: Nheko.colors.text + readOnly: true + + background: Rectangle { + color: Nheko.colors.base + } + + } + + } + + footer: DialogButtonBox { + standardButtons: DialogButtonBox.Ok + onAccepted: rawMessageRoot.close() + } + +} diff --git a/resources/qml/dialogs/ReadReceipts.qml b/resources/qml/dialogs/ReadReceipts.qml new file mode 100644 index 00000000..e825dd81 --- /dev/null +++ b/resources/qml/dialogs/ReadReceipts.qml @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import im.nheko 1.0 + +ApplicationWindow { + id: readReceiptsRoot + + property ReadReceiptsProxy readReceipts + property Room room + + height: 380 + width: 340 + minimumHeight: 380 + minimumWidth: headerTitle.width + 2 * Nheko.paddingMedium + palette: Nheko.colors + color: Nheko.colors.window + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(readReceiptsRoot) + + Shortcut { + sequence: StandardKey.Cancel + onActivated: readReceiptsRoot.close() + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Nheko.paddingMedium + spacing: Nheko.paddingMedium + + Label { + id: headerTitle + + color: Nheko.colors.text + Layout.alignment: Qt.AlignCenter + text: qsTr("Read receipts") + font.pointSize: fontMetrics.font.pointSize * 1.5 + } + + ScrollView { + palette: Nheko.colors + padding: Nheko.paddingMedium + ScrollBar.horizontal.visible: false + Layout.fillHeight: true + Layout.minimumHeight: 200 + Layout.fillWidth: true + + ListView { + id: readReceiptsList + + clip: true + spacing: Nheko.paddingMedium + boundsBehavior: Flickable.StopAtBounds + model: readReceipts + + delegate: RowLayout { + spacing: Nheko.paddingMedium + + Avatar { + width: Nheko.avatarSize + height: Nheko.avatarSize + userid: model.mxid + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + displayName: model.displayName + onClicked: room.openUserProfile(model.mxid) + ToolTip.visible: avatarHover.hovered + ToolTip.text: model.mxid + + HoverHandler { + id: avatarHover + } + + } + + ColumnLayout { + spacing: Nheko.paddingSmall + + Label { + text: model.displayName + color: TimelineManager.userColor(model ? model.mxid : "", Nheko.colors.window) + font.pointSize: fontMetrics.font.pointSize + ToolTip.visible: displayNameHover.hovered + ToolTip.text: model.mxid + + TapHandler { + onSingleTapped: room.openUserProfile(userId) + } + + CursorShape { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + } + + HoverHandler { + id: displayNameHover + } + + } + + Label { + text: model.timestamp + color: Nheko.colors.buttonText + font.pointSize: fontMetrics.font.pointSize * 0.9 + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + + } + + } + + } + + } + + } + + footer: DialogButtonBox { + standardButtons: DialogButtonBox.Ok + onAccepted: readReceiptsRoot.close() + } + +} diff --git a/resources/qml/dialogs/RoomDirectory.qml b/resources/qml/dialogs/RoomDirectory.qml new file mode 100644 index 00000000..5c27fc26 --- /dev/null +++ b/resources/qml/dialogs/RoomDirectory.qml @@ -0,0 +1,216 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import "../ui" +import QtQuick 2.9 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import im.nheko 1.0 + +ApplicationWindow { + id: roomDirectoryWindow + + property RoomDirectoryModel publicRooms + + visible: true + minimumWidth: 650 + minimumHeight: 420 + palette: Nheko.colors + color: Nheko.colors.window + modality: Qt.WindowModal + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(roomDirectoryWindow) + title: qsTr("Explore Public Rooms") + + Shortcut { + sequence: StandardKey.Cancel + onActivated: roomDirectoryWindow.close() + } + + ListView { + id: roomDirView + + anchors.fill: parent + model: publicRooms + + ScrollHelper { + flickable: parent + anchors.fill: parent + enabled: !Settings.mobileMode + } + + delegate: Rectangle { + id: roomDirDelegate + + property color background: Nheko.colors.window + property color importantText: Nheko.colors.text + property color unimportantText: Nheko.colors.buttonText + property int avatarSize: fontMetrics.lineSpacing * 4 + + color: background + height: avatarSize + Nheko.paddingLarge + width: ListView.view.width + + RowLayout { + spacing: Nheko.paddingMedium + anchors.fill: parent + anchors.margins: Nheko.paddingLarge + implicitHeight: textContent.height + + Avatar { + id: roomAvatar + + Layout.alignment: Qt.AlignVCenter + width: avatarSize + height: avatarSize + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + roomid: model.roomid + displayName: model.name + } + + ColumnLayout { + id: textContent + + Layout.alignment: Qt.AlignLeft + width: parent.width - avatar.width + Layout.preferredWidth: parent.width - avatar.width + spacing: Nheko.paddingSmall + + ElidedLabel { + Layout.alignment: Qt.AlignBottom + color: roomDirDelegate.importantText + elideWidth: textContent.width - numMembersRectangle.width - buttonRectangle.width + font.pixelSize: fontMetrics.font.pixelSize * 1.1 + fullText: model.name + } + + RowLayout { + id: roomDescriptionRow + + Layout.preferredWidth: parent.width + spacing: Nheko.paddingSmall + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + Layout.preferredHeight: fontMetrics.lineSpacing * 4 + + Label { + id: roomTopic + + color: roomDirDelegate.unimportantText + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + font.pixelSize: fontMetrics.font.pixelSize + elide: Text.ElideRight + maximumLineCount: 2 + Layout.fillWidth: true + text: model.topic + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + } + + Item { + id: numMembersRectangle + + Layout.margins: Nheko.paddingSmall + width: roomCount.width + + Label { + id: roomCount + + color: roomDirDelegate.unimportantText + anchors.centerIn: parent + font.pixelSize: fontMetrics.font.pixelSize + text: model.numMembers.toString() + } + + } + + Item { + id: buttonRectangle + + Layout.margins: Nheko.paddingSmall + width: joinRoomButton.width + + Button { + id: joinRoomButton + + visible: model.canJoin + anchors.centerIn: parent + text: "Join" + onClicked: publicRooms.joinRoom(model.index) + } + + } + + } + + } + + } + + } + + footer: Item { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + visible: !publicRooms.reachedEndOfPagination && publicRooms.loadingMoreRooms + // hacky but works + height: loadingSpinner.height + 2 * Nheko.paddingLarge + anchors.margins: Nheko.paddingLarge + + Spinner { + id: loadingSpinner + + anchors.centerIn: parent + anchors.margins: Nheko.paddingLarge + running: visible + foreground: Nheko.colors.mid + } + + } + + } + + publicRooms: RoomDirectoryModel { + } + + header: RowLayout { + id: searchBarLayout + + spacing: Nheko.paddingMedium + width: parent.width + implicitHeight: roomSearch.height + + MatrixTextField { + id: roomSearch + + Layout.fillWidth: true + selectByMouse: true + font.pixelSize: fontMetrics.font.pixelSize + padding: Nheko.paddingMedium + color: Nheko.colors.text + placeholderText: qsTr("Search for public rooms") + onTextChanged: searchTimer.restart() + } + + MatrixTextField { + id: chooseServer + Layout.minimumWidth: 0.3 * header.width + Layout.maximumWidth: 0.3 * header.width + + padding: Nheko.paddingMedium + color: Nheko.colors.text + placeholderText: qsTr("Choose custom homeserver") + onTextChanged: publicRooms.setMatrixServer(text) + } + + Timer { + id: searchTimer + + interval: 350 + onTriggered: roomDirView.model.setSearchTerm(roomSearch.text) + } + + } + +} diff --git a/resources/qml/dialogs/RoomMembers.qml b/resources/qml/dialogs/RoomMembers.qml new file mode 100644 index 00000000..b2806292 --- /dev/null +++ b/resources/qml/dialogs/RoomMembers.qml @@ -0,0 +1,180 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import "../ui" +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Window 2.13 +import im.nheko 1.0 + +ApplicationWindow { + id: roomMembersRoot + + property MemberList members + property Room room + + title: qsTr("Members of %1").arg(members.roomName) + height: 650 + width: 420 + minimumHeight: 420 + palette: Nheko.colors + color: Nheko.colors.window + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(roomMembersRoot) + + Shortcut { + sequence: StandardKey.Cancel + onActivated: roomMembersRoot.close() + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Nheko.paddingMedium + spacing: Nheko.paddingMedium + + Avatar { + id: roomAvatar + + width: 130 + height: width + roomid: members.roomId + displayName: members.roomName + Layout.alignment: Qt.AlignHCenter + url: members.avatarUrl.replace("mxc://", "image://MxcImage/") + onClicked: TimelineManager.openRoomSettings(members.roomId) + } + + ElidedLabel { + font.pixelSize: fontMetrics.font.pixelSize * 2 + fullText: qsTr("%n people in %1", "Summary above list of members", members.memberCount).arg(members.roomName) + Layout.alignment: Qt.AlignHCenter + elideWidth: parent.width - Nheko.paddingMedium + } + + ImageButton { + Layout.alignment: Qt.AlignHCenter + image: ":/icons/icons/ui/add-square-button.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Invite more people") + onClicked: TimelineManager.openInviteUsers(members.roomId) + } + + ScrollView { + palette: Nheko.colors + padding: Nheko.paddingMedium + ScrollBar.horizontal.visible: false + Layout.fillHeight: true + Layout.minimumHeight: 200 + Layout.fillWidth: true + + ListView { + id: memberList + + clip: true + spacing: Nheko.paddingMedium + boundsBehavior: Flickable.StopAtBounds + model: members + + ScrollHelper { + flickable: parent + anchors.fill: parent + enabled: !Settings.mobileMode + } + + delegate: RowLayout { + id: del + + width: ListView.view.width + spacing: Nheko.paddingMedium + + Avatar { + id: avatar + + width: Nheko.avatarSize + height: Nheko.avatarSize + userid: model.mxid + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + displayName: model.displayName + onClicked: Rooms.currentRoom.openUserProfile(model.mxid) + } + + ColumnLayout { + spacing: Nheko.paddingSmall + + ElidedLabel { + fullText: model.displayName + color: TimelineManager.userColor(model ? model.mxid : "", Nheko.colors.window) + font.pixelSize: fontMetrics.font.pixelSize + elideWidth: del.width - Nheko.paddingMedium * 2 - avatar.width - encryptInd.width + } + + ElidedLabel { + fullText: model.mxid + color: Nheko.colors.buttonText + font.pixelSize: Math.ceil(fontMetrics.font.pixelSize * 0.9) + elideWidth: del.width - Nheko.paddingMedium * 2 - avatar.width - encryptInd.width + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + + } + + EncryptionIndicator { + id: encryptInd + + Layout.alignment: Qt.AlignRight + visible: room.isEncrypted + encrypted: room.isEncrypted + trust: encrypted ? model.trustlevel : Crypto.Unverified + ToolTip.text: { + if (!encrypted) + return qsTr("This room is not encrypted!"); + + switch (trust) { + case Crypto.Verified: + return qsTr("This user is verified."); + case Crypto.TOFU: + return qsTr("This user isn't verified, but is still using the same master key from the first time you met."); + default: + return qsTr("This user has unverified devices!"); + } + } + } + + } + + footer: Item { + width: parent.width + visible: (members.numUsersLoaded < members.memberCount) && members.loadingMoreMembers + // use the default height if it's visible, otherwise no height at all + height: membersLoadingSpinner.height + anchors.margins: Nheko.paddingMedium + + Spinner { + id: membersLoadingSpinner + + anchors.centerIn: parent + height: visible ? 35 : 0 + } + + } + + } + + } + + } + + footer: DialogButtonBox { + standardButtons: DialogButtonBox.Ok + onAccepted: roomMembersRoot.close() + } + +} diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml new file mode 100644 index 00000000..0e7749ce --- /dev/null +++ b/resources/qml/dialogs/RoomSettings.qml @@ -0,0 +1,305 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import "../ui" +import Qt.labs.platform 1.1 as Platform +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.13 +import im.nheko 1.0 + +ApplicationWindow { + id: roomSettingsDialog + + property var roomSettings + + minimumWidth: 450 + minimumHeight: 680 + palette: Nheko.colors + color: Nheko.colors.window + modality: Qt.NonModal + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(roomSettingsDialog) + title: qsTr("Room Settings") + + Shortcut { + sequence: StandardKey.Cancel + onActivated: roomSettingsDialog.close() + } + + ColumnLayout { + id: contentLayout1 + + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + Avatar { + url: roomSettings.roomAvatarUrl.replace("mxc://", "image://MxcImage/") + roomid: roomSettings.roomId + displayName: roomSettings.roomName + height: 130 + width: 130 + Layout.alignment: Qt.AlignHCenter + onClicked: { + if (roomSettings.canChangeAvatar) + roomSettings.updateAvatar(); + + } + } + + Spinner { + Layout.alignment: Qt.AlignHCenter + visible: roomSettings.isLoading + foreground: Nheko.colors.mid + running: roomSettings.isLoading + } + + Text { + id: errorText + + color: "red" + visible: opacity > 0 + opacity: 0 + Layout.alignment: Qt.AlignHCenter + } + + SequentialAnimation { + id: hideErrorAnimation + + running: false + + PauseAnimation { + duration: 4000 + } + + NumberAnimation { + target: errorText + property: 'opacity' + to: 0 + duration: 1000 + } + + } + + Connections { + target: roomSettings + onDisplayError: { + errorText.text = errorMessage; + errorText.opacity = 1; + hideErrorAnimation.restart(); + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignHCenter + + MatrixText { + text: roomSettings.roomName + font.pixelSize: fontMetrics.font.pixelSize * 2 + Layout.alignment: Qt.AlignHCenter + } + + MatrixText { + text: qsTr("%1 member(s)").arg(roomSettings.memberCount) + Layout.alignment: Qt.AlignHCenter + + TapHandler { + onTapped: TimelineManager.openRoomMembers(roomSettings.roomId) + } + + CursorShape { + cursorShape: Qt.PointingHandCursor + anchors.fill: parent + } + + } + + } + + ImageButton { + Layout.alignment: Qt.AlignHCenter + image: ":/icons/icons/ui/edit.png" + visible: roomSettings.canChangeNameAndTopic + onClicked: roomSettings.openEditModal() + } + + ScrollView { + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.leftMargin: Nheko.paddingLarge + Layout.rightMargin: Nheko.paddingLarge + + TextArea { + text: TimelineManager.escapeEmoji(roomSettings.roomTopic) + wrapMode: TextEdit.WordWrap + textFormat: TextEdit.RichText + readOnly: true + background: null + selectByMouse: true + color: Nheko.colors.text + horizontalAlignment: TextEdit.AlignHCenter + onLinkActivated: Nheko.openLink(link) + + CursorShape { + anchors.fill: parent + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + + } + + } + + GridLayout { + columns: 2 + rowSpacing: Nheko.paddingLarge + + MatrixText { + text: qsTr("SETTINGS") + font.bold: true + } + + Item { + Layout.fillWidth: true + } + + MatrixText { + text: qsTr("Notifications") + Layout.fillWidth: true + } + + ComboBox { + model: [qsTr("Muted"), qsTr("Mentions only"), qsTr("All messages")] + currentIndex: roomSettings.notifications + onActivated: { + roomSettings.changeNotifications(index); + } + Layout.fillWidth: true + } + + MatrixText { + text: qsTr("Room access") + Layout.fillWidth: true + } + + ComboBox { + enabled: roomSettings.canChangeJoinRules + model: { + let opts = [qsTr("Anyone and guests"), qsTr("Anyone"), qsTr("Invited users")]; + if (roomSettings.supportsKnocking) + opts.push(qsTr("By knocking")); + + if (roomSettings.supportsRestricted) + opts.push(qsTr("Restricted by membership in other rooms")); + + return opts; + } + currentIndex: roomSettings.accessJoinRules + onActivated: { + roomSettings.changeAccessRules(index); + } + Layout.fillWidth: true + } + + MatrixText { + text: qsTr("Encryption") + } + + ToggleButton { + id: encryptionToggle + + checked: roomSettings.isEncryptionEnabled + onClicked: { + if (roomSettings.isEncryptionEnabled) { + checked = true; + return ; + } + confirmEncryptionDialog.open(); + } + Layout.alignment: Qt.AlignRight + } + + Platform.MessageDialog { + id: confirmEncryptionDialog + + title: qsTr("End-to-End Encryption") + text: qsTr("Encryption is currently experimental and things might break unexpectedly. <br> + Please take note that it can't be disabled afterwards.") + modality: Qt.Modal + onAccepted: { + if (roomSettings.isEncryptionEnabled) + return ; + + roomSettings.enableEncryption(); + } + onRejected: { + encryptionToggle.checked = false; + } + buttons: Dialog.Ok | Dialog.Cancel + } + + MatrixText { + text: qsTr("Sticker & Emote Settings") + } + + Button { + text: qsTr("Change") + ToolTip.text: qsTr("Change what packs are enabled, remove packs or create new ones") + onClicked: TimelineManager.openImagePackSettings(roomSettings.roomId) + Layout.alignment: Qt.AlignRight + } + + Item { + // for adding extra space between sections + Layout.fillWidth: true + } + + Item { + // for adding extra space between sections + Layout.fillWidth: true + } + + MatrixText { + text: qsTr("INFO") + font.bold: true + } + + Item { + Layout.fillWidth: true + } + + MatrixText { + text: qsTr("Internal ID") + } + + MatrixText { + text: roomSettings.roomId + font.pixelSize: fontMetrics.font.pixelSize * 1.2 + Layout.alignment: Qt.AlignRight + } + + MatrixText { + text: qsTr("Room Version") + } + + MatrixText { + text: roomSettings.roomVersion + font.pixelSize: fontMetrics.font.pixelSize * 1.2 + Layout.alignment: Qt.AlignRight + } + + } + + DialogButtonBox { + Layout.fillWidth: true + standardButtons: DialogButtonBox.Ok + onAccepted: close() + } + + } + +} diff --git a/resources/qml/dialogs/UserProfile.qml b/resources/qml/dialogs/UserProfile.qml new file mode 100644 index 00000000..9bf548e3 --- /dev/null +++ b/resources/qml/dialogs/UserProfile.qml @@ -0,0 +1,327 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import ".." +import "../device-verification" +import "../ui" +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.13 +import im.nheko 1.0 + +ApplicationWindow { + // this does not work in ApplicationWindow, just in Window + //transientParent: Nheko.mainwindow() + + id: userProfileDialog + + property var profile + + height: 650 + width: 420 + minimumWidth: 150 + minimumHeight: 150 + palette: Nheko.colors + color: Nheko.colors.window + title: profile.isGlobalUserProfile ? qsTr("Global User Profile") : qsTr("Room User Profile") + modality: Qt.NonModal + flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Component.onCompleted: Nheko.reparent(userProfileDialog) + + Shortcut { + sequence: StandardKey.Cancel + onActivated: userProfileDialog.close() + } + + + ListView { + + ScrollHelper { + flickable: parent + anchors.fill: parent + enabled: !Settings.mobileMode + } + + header: ColumnLayout { + id: contentL + width: devicelist.width + + spacing: 10 + + Avatar { + url: profile.avatarUrl.replace("mxc://", "image://MxcImage/") + height: 130 + width: 130 + displayName: profile.displayName + id: displayAvatar + userid: profile.userid + Layout.alignment: Qt.AlignHCenter + onClicked: TimelineManager.openImageOverlay(profile.avatarUrl, "") + + ImageButton { + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: profile.isGlobalUserProfile ? qsTr("Change avatar globally.") : qsTr("Change avatar. Will only apply to this room.") + anchors.left: displayAvatar.left + anchors.top: displayAvatar.top + anchors.leftMargin: Nheko.paddingMedium + anchors.topMargin: Nheko.paddingMedium + visible: profile.isSelf + image: ":/icons/icons/ui/edit.png" + onClicked: profile.changeAvatar() + } + } + + Spinner { + Layout.alignment: Qt.AlignHCenter + running: profile.isLoading + visible: profile.isLoading + foreground: Nheko.colors.mid + } + + Text { + id: errorText + + color: "red" + visible: opacity > 0 + opacity: 0 + Layout.alignment: Qt.AlignHCenter + } + + SequentialAnimation { + id: hideErrorAnimation + + running: false + + PauseAnimation { + duration: 4000 + } + + NumberAnimation { + target: errorText + property: 'opacity' + to: 0 + duration: 1000 + } + + } + + Connections { + function onDisplayError(errorMessage) { + errorText.text = errorMessage; + errorText.opacity = 1; + hideErrorAnimation.restart(); + } + + target: profile + } + + TextInput { + id: displayUsername + + property bool isUsernameEditingAllowed + + readOnly: !isUsernameEditingAllowed + text: profile.displayName + font.pixelSize: 20 + color: TimelineManager.userColor(profile.userid, Nheko.colors.window) + font.bold: true + Layout.alignment: Qt.AlignHCenter + selectByMouse: true + onAccepted: { + profile.changeUsername(displayUsername.text); + displayUsername.isUsernameEditingAllowed = false; + } + + ImageButton { + visible: profile.isSelf + anchors.leftMargin: Nheko.paddingSmall + anchors.left: displayUsername.right + anchors.verticalCenter: displayUsername.verticalCenter + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: profile.isGlobalUserProfile ? qsTr("Change display name globally.") : qsTr("Change display name. Will only apply to this room.") + image: displayUsername.isUsernameEditingAllowed ? ":/icons/icons/ui/checkmark.png" : ":/icons/icons/ui/edit.png" + onClicked: { + if (displayUsername.isUsernameEditingAllowed) { + profile.changeUsername(displayUsername.text); + displayUsername.isUsernameEditingAllowed = false; + } else { + displayUsername.isUsernameEditingAllowed = true; + displayUsername.focus = true; + displayUsername.selectAll(); + } + } + } + + } + + MatrixText { + text: profile.userid + Layout.alignment: Qt.AlignHCenter + } + + + RowLayout { + visible: !profile.isGlobalUserProfile + Layout.alignment: Qt.AlignHCenter + spacing: Nheko.paddingSmall + MatrixText { + id: displayRoomname + text: qsTr("Room: %1").arg(profile.room?profile.room.roomName:"") + ToolTip.text: qsTr("This is a room-specific profile. The user's name and avatar may be different from their global versions.") + ToolTip.visible: ma.hovered + HoverHandler { + id: ma + } + } + + ImageButton { + image: ":/icons/icons/ui/world.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Open the global profile for this user.") + onClicked: profile.openGlobalProfile() + } + } + + Button { + id: verifyUserButton + + text: qsTr("Verify") + Layout.alignment: Qt.AlignHCenter + enabled: profile.userVerified != Crypto.Verified + visible: profile.userVerified != Crypto.Verified && !profile.isSelf && profile.userVerificationEnabled + onClicked: profile.verify() + } + + Image { + Layout.preferredHeight: 16 + Layout.preferredWidth: 16 + source: "image://colorimage/:/icons/icons/ui/lock.png?" + ((profile.userVerified == Crypto.Verified) ? "green" : Nheko.colors.buttonText) + visible: profile.userVerified != Crypto.Unverified + Layout.alignment: Qt.AlignHCenter + } + + RowLayout { + // ImageButton{ + // image:":/icons/icons/ui/volume-off-indicator.png" + // Layout.margins: { + // left: 5 + // right: 5 + // } + // ToolTip.visible: hovered + // ToolTip.text: qsTr("Ignore messages from this user.") + // onClicked : { + // profile.ignoreUser() + // } + // } + + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: 10 + spacing: Nheko.paddingSmall + + ImageButton { + image: ":/icons/icons/ui/black-bubble-speech.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Start a private chat.") + onClicked: profile.startChat() + } + + ImageButton { + image: ":/icons/icons/ui/round-remove-button.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Kick the user.") + onClicked: profile.kickUser() + visible: !profile.isGlobalUserProfile && profile.room.permissions.canKick() + } + + ImageButton { + image: ":/icons/icons/ui/do-not-disturb-rounded-sign.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Ban the user.") + onClicked: profile.banUser() + visible: !profile.isGlobalUserProfile && profile.room.permissions.canBan() + } + + } + } + + id: devicelist + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + spacing: 8 + boundsBehavior: Flickable.StopAtBounds + model: profile.deviceList + anchors.fill: parent + anchors.margins: 10 + + + delegate: RowLayout { + width: devicelist.width + spacing: 4 + + ColumnLayout { + spacing: 0 + + Text { + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + elide: Text.ElideRight + font.bold: true + color: Nheko.colors.text + text: model.deviceId + } + + Text { + Layout.fillWidth: true + Layout.alignment: Qt.AlignRight + elide: Text.ElideRight + color: Nheko.colors.text + text: model.deviceName + } + + } + + Image { + Layout.preferredHeight: 16 + Layout.preferredWidth: 16 + source: ((model.verificationStatus == VerificationStatus.VERIFIED) ? "image://colorimage/:/icons/icons/ui/lock.png?green" : ((model.verificationStatus == VerificationStatus.UNVERIFIED) ? "image://colorimage/:/icons/icons/ui/unlock.png?yellow" : "image://colorimage/:/icons/icons/ui/unlock.png?red")) + } + + Button { + id: verifyButton + + visible: (!profile.userVerificationEnabled && !profile.isSelf) || (profile.isSelf && (model.verificationStatus != VerificationStatus.VERIFIED || !profile.userVerificationEnabled)) + text: (model.verificationStatus != VerificationStatus.VERIFIED) ? qsTr("Verify") : qsTr("Unverify") + onClicked: { + if (model.verificationStatus == VerificationStatus.VERIFIED) + profile.unverify(model.deviceId); + else + profile.verify(model.deviceId); + } + } + + } + footerPositioning: ListView.OverlayFooter + footer: DialogButtonBox { + z: 2 + width: devicelist.width + alignment: Qt.AlignRight + standardButtons: DialogButtonBox.Ok + onAccepted: userProfileDialog.close() + background: Rectangle { + anchors.fill: parent + color: Nheko.colors.window + } + } + + } + +} |