|
|
|
// SPDX-FileCopyrightText: Nheko Contributors
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
import ".."
|
|
|
|
import "../components"
|
|
|
|
import QtQuick 2.12
|
|
|
|
import QtQuick.Controls 2.12
|
|
|
|
import QtQuick.Layouts 1.12
|
|
|
|
import im.nheko 1.0
|
|
|
|
|
|
|
|
ApplicationWindow {
|
|
|
|
id: inviteDialogRoot
|
|
|
|
|
|
|
|
property InviteesModel invitees
|
|
|
|
property var friendsCompleter
|
|
|
|
property var profile
|
|
|
|
minimumWidth: 300
|
|
|
|
|
|
|
|
Component.onCompleted: {
|
|
|
|
friendsCompleter = TimelineManager.completerFor("user", "friends")
|
|
|
|
width = 600
|
|
|
|
}
|
|
|
|
|
|
|
|
function addInvite(mxid, displayName, avatarUrl) {
|
|
|
|
if (mxid.match("@.+?:.{3,}")) {
|
|
|
|
invitees.addUser(mxid, displayName, avatarUrl);
|
|
|
|
} else
|
|
|
|
console.log("invalid mxid: " + mxid)
|
|
|
|
}
|
|
|
|
|
|
|
|
function cleanUpAndClose() {
|
|
|
|
if (inviteeEntry.isValidMxid)
|
|
|
|
addInvite(inviteeEntry.text, "", "");
|
|
|
|
|
|
|
|
invitees.accept();
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
title: qsTr("Invite users to %1").arg(invitees.room.plainRoomName)
|
|
|
|
height: 380
|
|
|
|
width: 340
|
|
|
|
color: palette.window
|
|
|
|
flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
|
|
|
|
|
|
|
|
Shortcut {
|
|
|
|
sequence: "Ctrl+Enter"
|
|
|
|
onActivated: cleanUpAndClose()
|
|
|
|
}
|
|
|
|
|
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Cancel
|
|
|
|
onActivated: inviteDialogRoot.close()
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
anchors.fill: parent
|
|
|
|
anchors.margins: Nheko.paddingMedium
|
|
|
|
spacing: Nheko.paddingMedium
|
|
|
|
Flow {
|
|
|
|
layoutDirection: Qt.LeftToRight
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.preferredHeight: implicitHeight
|
|
|
|
spacing: 4
|
|
|
|
visible: !inviteesList.visible
|
|
|
|
Repeater {
|
|
|
|
id: inviteesRepeater
|
|
|
|
model: invitees
|
|
|
|
delegate: ItemDelegate {
|
|
|
|
onClicked: invitees.removeUser(model.mxid)
|
|
|
|
id: inviteeButton
|
|
|
|
contentItem: Label {
|
|
|
|
anchors.centerIn: parent
|
|
|
|
id: inviteeUserid
|
|
|
|
text: model.displayName != "" ? model.displayName : model.userid
|
|
|
|
color: inviteeButton.hovered ? palette.highlightedText: palette.text
|
|
|
|
maximumLineCount: 1
|
|
|
|
}
|
|
|
|
background: Rectangle {
|
|
|
|
border.color: palette.text
|
|
|
|
color: inviteeButton.hovered ? palette.highlight : palette.window
|
|
|
|
border.width: 1
|
|
|
|
radius: inviteeButton.height / 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Label {
|
|
|
|
text: qsTr("Search user")
|
|
|
|
Layout.fillWidth: true
|
|
|
|
color: palette.text
|
|
|
|
}
|
|
|
|
RowLayout {
|
|
|
|
spacing: Nheko.paddingMedium
|
|
|
|
|
|
|
|
MatrixTextField {
|
|
|
|
id: inviteeEntry
|
|
|
|
|
|
|
|
property bool isValidMxid: text.match("@.+?:.{3,}")
|
|
|
|
|
|
|
|
backgroundColor: palette.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(text, "", "");
|
|
|
|
clear()
|
|
|
|
}
|
|
|
|
else if (userSearch.count > 0) {
|
|
|
|
addInvite(userSearch.itemAtIndex(0).userid, userSearch.itemAtIndex(0).displayName, userSearch.itemAtIndex(0).avatarUrl)
|
|
|
|
clear()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
|
|
|
|
}
|
|
|
|
onTextChanged: {
|
|
|
|
searchTimer.restart()
|
|
|
|
if(isValidMxid) {
|
|
|
|
profile = TimelineManager.getGlobalUserProfile(text);
|
|
|
|
} else
|
|
|
|
profile = null;
|
|
|
|
}
|
|
|
|
Timer {
|
|
|
|
id: searchTimer
|
|
|
|
|
|
|
|
interval: 350
|
|
|
|
onTriggered: {
|
|
|
|
userSearch.model.setSearchString(parent.text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ToggleButton {
|
|
|
|
id: searchOnServer
|
|
|
|
checked: false
|
|
|
|
onClicked: userSearch.model.setSearchString(inviteeEntry.text)
|
|
|
|
}
|
|
|
|
MatrixText {
|
|
|
|
text: qsTr("Search on Server")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
RowLayout {
|
|
|
|
UserListRow {
|
|
|
|
visible: inviteeEntry.isValidMxid
|
|
|
|
id: del3
|
|
|
|
Layout.preferredWidth: inviteDialogRoot.width/2
|
|
|
|
Layout.alignment: Qt.AlignTop
|
|
|
|
Layout.preferredHeight: implicitHeight
|
|
|
|
displayName: profile? profile.displayName : ""
|
|
|
|
avatarUrl: profile? profile.avatarUrl : ""
|
|
|
|
userid: inviteeEntry.text
|
|
|
|
onClicked: addInvite(inviteeEntry.text, displayName, avatarUrl)
|
|
|
|
bgColor: del3.hovered ? palette.dark : inviteDialogRoot.color
|
|
|
|
}
|
|
|
|
ListView {
|
|
|
|
visible: !inviteeEntry.isValidMxid
|
|
|
|
id: userSearch
|
|
|
|
model: searchOnServer.checked? userDirectory : friendsCompleter
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
clip: true
|
|
|
|
delegate: UserListRow {
|
|
|
|
id: del2
|
|
|
|
width: ListView.view.width
|
|
|
|
height: implicitHeight
|
|
|
|
displayName: model.displayName
|
|
|
|
userid: model.userid
|
|
|
|
avatarUrl: model.avatarUrl
|
|
|
|
onClicked: addInvite(userid, displayName, avatarUrl)
|
|
|
|
bgColor: del2.hovered ? palette.dark : inviteDialogRoot.color
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
Layout.fillHeight: true
|
|
|
|
visible: inviteesList.visible
|
|
|
|
width: 1
|
|
|
|
color: Nheko.theme.separator
|
|
|
|
}
|
|
|
|
ListView {
|
|
|
|
id: inviteesList
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
model: invitees
|
|
|
|
clip: true
|
|
|
|
visible: inviteDialogRoot.width >= 500
|
|
|
|
|
|
|
|
delegate: UserListRow {
|
|
|
|
id: del
|
|
|
|
hoverEnabled: true
|
|
|
|
width: ListView.view.width
|
|
|
|
height: implicitHeight
|
|
|
|
onClicked: TimelineManager.openGlobalUserProfile(model.mxid)
|
|
|
|
userid: model.mxid
|
|
|
|
avatarUrl: model.avatarUrl
|
|
|
|
displayName: model.displayName
|
|
|
|
bgColor: del.hovered ? palette.dark : inviteDialogRoot.color
|
|
|
|
ImageButton {
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.rightMargin: Nheko.paddingSmall
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.topMargin: Nheko.paddingSmall
|
|
|
|
id: removeButton
|
|
|
|
image: ":/icons/icons/ui/dismiss.svg"
|
|
|
|
onClicked: invitees.removeUser(model.mxid)
|
|
|
|
}
|
|
|
|
|
|
|
|
CursorShape {
|
|
|
|
anchors.fill: parent
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|