nheko/resources/qml/MessageInput.qml

231 lines
8.8 KiB
QML
Raw Normal View History

import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.2
import QtQuick.Window 2.2
2020-10-31 23:24:07 +01:00
import im.nheko 1.0
Rectangle {
color: colors.window
Layout.fillWidth: true
Layout.preferredHeight: textInput.height
Layout.minimumHeight: 40
RowLayout {
id: inputBar
anchors.fill: parent
spacing: 16
ImageButton {
2020-11-15 23:14:47 +01:00
visible: TimelineManager.callsSupported
Layout.alignment: Qt.AlignBottom
hoverEnabled: true
width: 22
height: 22
2020-11-15 23:14:47 +01:00
image: TimelineManager.isOnCall ? ":/icons/icons/ui/end-call.png" : ":/icons/icons/ui/place-call.png"
ToolTip.visible: hovered
ToolTip.text: TimelineManager.isOnCall ? qsTr("Hang up") : qsTr("Place a call")
Layout.topMargin: 8
Layout.bottomMargin: 8
Layout.leftMargin: 16
2020-11-15 23:14:47 +01:00
onClicked: TimelineManager.timeline.input.callButton()
}
ImageButton {
Layout.alignment: Qt.AlignBottom
hoverEnabled: true
width: 22
height: 22
image: ":/icons/icons/ui/paper-clip-outline.png"
Layout.topMargin: 8
Layout.bottomMargin: 8
2020-11-15 23:14:47 +01:00
Layout.leftMargin: TimelineManager.callsSupported ? 0 : 16
2020-11-15 04:52:49 +01:00
onClicked: TimelineManager.timeline.input.openFileSelection()
2020-11-15 23:14:47 +01:00
ToolTip.visible: hovered
ToolTip.text: qsTr("Send a file")
2020-11-15 04:52:49 +01:00
Rectangle {
anchors.fill: parent
color: colors.window
visible: TimelineManager.timeline.input.uploading
NhekoBusyIndicator {
anchors.fill: parent
running: parent.visible
}
}
}
ScrollView {
id: textInput
Layout.alignment: Qt.AlignBottom
Layout.maximumHeight: Window.height / 4
Layout.fillWidth: true
TextArea {
2020-10-31 23:24:07 +01:00
id: textArea
2020-11-20 01:22:36 +01:00
property int completerTriggeredAt: -1
2020-11-24 17:32:45 +01:00
function insertCompletion(completion) {
textArea.remove(completerTriggeredAt, cursorPosition);
textArea.insert(cursorPosition, completion);
}
placeholderText: qsTr("Write a message...")
placeholderTextColor: colors.buttonText
color: colors.text
wrapMode: TextEdit.Wrap
2020-10-31 23:24:07 +01:00
onTextChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
2020-11-20 01:22:36 +01:00
onCursorPositionChanged: {
TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
2020-11-20 02:38:08 +01:00
if (cursorPosition <= completerTriggeredAt) {
2020-11-20 01:22:36 +01:00
completerTriggeredAt = -1;
popup.close();
}
if (popup.opened)
popup.completer.setSearchString(textArea.getText(completerTriggeredAt, cursorPosition));
2020-11-20 01:22:36 +01:00
}
2020-10-31 23:24:07 +01:00
onSelectionStartChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
onSelectionEndChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
2020-11-24 17:32:45 +01:00
// Ensure that we get escape key press events first.
2020-11-20 01:22:36 +01:00
Keys.onShortcutOverride: event.accepted = (completerTriggeredAt != -1 && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter))
2020-10-31 23:24:07 +01:00
Keys.onPressed: {
if (event.matches(StandardKey.Paste)) {
2020-11-15 04:52:49 +01:00
TimelineManager.timeline.input.paste(false);
event.accepted = true;
2020-11-20 01:22:36 +01:00
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_U) {
textArea.clear();
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_P) {
textArea.text = TimelineManager.timeline.input.previousText();
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_N) {
textArea.text = TimelineManager.timeline.input.nextText();
} else if (event.key == Qt.Key_At) {
2020-11-20 02:38:08 +01:00
completerTriggeredAt = cursorPosition;
2020-11-20 01:22:36 +01:00
popup.completerName = "user";
popup.open();
2020-11-20 04:33:11 +01:00
} else if (event.key == Qt.Key_Colon) {
completerTriggeredAt = cursorPosition;
popup.completerName = "emoji";
popup.open();
2020-11-20 01:22:36 +01:00
} else if (event.key == Qt.Key_Escape && popup.opened) {
completerTriggeredAt = -1;
2020-11-20 02:38:08 +01:00
popup.completerName = "";
2020-11-20 01:22:36 +01:00
event.accepted = true;
popup.close();
2020-11-25 02:20:42 +01:00
} else if (event.matches(StandardKey.InsertParagraphSeparator)) {
if (popup.opened) {
var currentCompletion = popup.currentCompletion();
popup.completerName = "";
popup.close();
if (currentCompletion) {
textArea.insertCompletion(currentCompletion);
event.accepted = true;
return ;
}
2020-11-20 01:22:36 +01:00
}
2020-11-25 02:20:42 +01:00
TimelineManager.timeline.input.send();
textArea.clear();
event.accepted = true;
2020-11-20 01:22:36 +01:00
} else if (event.key == Qt.Key_Tab && popup.opened) {
event.accepted = true;
popup.down();
} else if (event.key == Qt.Key_Up && popup.opened) {
event.accepted = true;
popup.up();
} else if (event.key == Qt.Key_Down && popup.opened) {
event.accepted = true;
popup.down();
}
}
2020-11-20 02:38:08 +01:00
Connections {
onTimelineChanged: {
textArea.clear();
textArea.append(TimelineManager.timeline.input.text());
textArea.completerTriggeredAt = -1;
popup.completerName = "";
}
target: TimelineManager
}
2020-11-24 17:32:45 +01:00
Connections {
onCompletionClicked: textArea.insertCompletion(completion)
target: popup
}
2020-11-20 02:38:08 +01:00
2020-11-20 01:22:36 +01:00
Completer {
id: popup
x: textArea.positionToRectangle(textArea.completerTriggeredAt).x
y: textArea.positionToRectangle(textArea.completerTriggeredAt).y - height
2020-11-15 04:52:49 +01:00
}
Connections {
2020-11-16 18:41:29 +01:00
onInsertText: textArea.insert(textArea.cursorPosition, text)
2020-11-15 04:52:49 +01:00
target: TimelineManager.timeline.input
2020-10-31 23:24:07 +01:00
}
MouseArea {
// workaround for wrong cursor shape on some platforms
anchors.fill: parent
2020-10-31 23:24:07 +01:00
acceptedButtons: Qt.MiddleButton
cursorShape: Qt.IBeamCursor
2020-11-09 03:12:37 +01:00
onClicked: TimelineManager.timeline.input.paste(true)
}
2020-11-25 17:02:23 +01:00
NhekoDropArea {
anchors.fill: parent
roomid: TimelineManager.timeline.roomId()
}
background: Rectangle {
color: colors.window
}
}
}
ImageButton {
2020-11-16 18:41:29 +01:00
id: emojiButton
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
hoverEnabled: true
width: 22
height: 22
image: ":/icons/icons/ui/smile.png"
Layout.topMargin: 8
Layout.bottomMargin: 8
2020-11-15 23:14:47 +01:00
ToolTip.visible: hovered
ToolTip.text: qsTr("Emoji")
2020-11-16 18:41:29 +01:00
onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(emojiButton, function(emoji) {
textArea.insert(textArea.cursorPosition, emoji);
})
}
ImageButton {
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
hoverEnabled: true
width: 22
height: 22
image: ":/icons/icons/ui/cursor.png"
Layout.topMargin: 8
Layout.bottomMargin: 8
Layout.rightMargin: 16
2020-11-15 23:14:47 +01:00
ToolTip.visible: hovered
ToolTip.text: qsTr("Send")
2020-11-15 04:52:49 +01:00
onClicked: {
TimelineManager.timeline.input.send();
textArea.clear();
}
}
}
}