2020-12-30 21:03:07 +01:00
|
|
|
import "./voip"
|
2021-01-12 15:03:39 +01:00
|
|
|
import QtQuick 2.9
|
2020-10-26 14:57:54 +01:00
|
|
|
import QtQuick.Controls 2.3
|
2021-01-12 15:03:39 +01:00
|
|
|
import QtQuick.Layouts 1.2
|
|
|
|
import QtQuick.Window 2.2
|
2020-10-31 23:24:07 +01:00
|
|
|
import im.nheko 1.0
|
|
|
|
|
2020-10-26 14:57:54 +01:00
|
|
|
Rectangle {
|
|
|
|
color: colors.window
|
|
|
|
Layout.fillWidth: true
|
2021-01-17 04:05:02 +01:00
|
|
|
Layout.preferredHeight: textInput.height + 16
|
2020-10-26 14:57:54 +01:00
|
|
|
Layout.minimumHeight: 40
|
|
|
|
|
2020-12-18 18:49:24 +01:00
|
|
|
Component {
|
|
|
|
id: placeCallDialog
|
|
|
|
|
|
|
|
PlaceCall {
|
|
|
|
}
|
2021-01-11 23:51:39 +01:00
|
|
|
|
2020-12-18 18:49:24 +01:00
|
|
|
}
|
|
|
|
|
2020-10-26 14:57:54 +01:00
|
|
|
RowLayout {
|
|
|
|
id: inputBar
|
|
|
|
|
|
|
|
anchors.fill: parent
|
2021-01-17 04:05:02 +01:00
|
|
|
anchors.margins: 8
|
2020-10-26 14:57:54 +01:00
|
|
|
spacing: 16
|
|
|
|
|
|
|
|
ImageButton {
|
2020-12-10 02:49:48 +01:00
|
|
|
visible: CallManager.callsSupported
|
2021-01-11 23:51:39 +01:00
|
|
|
opacity: CallManager.haveCallInvite ? 0.3 : 1
|
2020-10-26 14:57:54 +01:00
|
|
|
Layout.alignment: Qt.AlignBottom
|
|
|
|
hoverEnabled: true
|
|
|
|
width: 22
|
|
|
|
height: 22
|
2020-12-10 02:49:48 +01:00
|
|
|
image: CallManager.isOnCall ? ":/icons/icons/ui/end-call.png" : ":/icons/icons/ui/place-call.png"
|
2020-11-15 23:14:47 +01:00
|
|
|
ToolTip.visible: hovered
|
2020-12-10 02:49:48 +01:00
|
|
|
ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : qsTr("Place a call")
|
2021-01-17 04:05:02 +01:00
|
|
|
Layout.leftMargin: 8
|
2020-12-18 18:49:24 +01:00
|
|
|
onClicked: {
|
|
|
|
if (TimelineManager.timeline) {
|
|
|
|
if (CallManager.haveCallInvite) {
|
2021-01-11 23:51:39 +01:00
|
|
|
return ;
|
|
|
|
} else if (CallManager.isOnCall) {
|
2020-12-18 18:49:24 +01:00
|
|
|
CallManager.hangUp();
|
2021-01-11 23:51:39 +01:00
|
|
|
} else {
|
2021-01-07 15:48:25 +01:00
|
|
|
CallManager.refreshDevices();
|
2020-12-18 18:49:24 +01:00
|
|
|
var dialog = placeCallDialog.createObject(timelineRoot);
|
2020-12-30 21:03:07 +01:00
|
|
|
dialog.open();
|
2020-12-18 18:49:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-26 14:57:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImageButton {
|
|
|
|
Layout.alignment: Qt.AlignBottom
|
|
|
|
hoverEnabled: true
|
|
|
|
width: 22
|
|
|
|
height: 22
|
|
|
|
image: ":/icons/icons/ui/paper-clip-outline.png"
|
2021-01-17 04:05:02 +01:00
|
|
|
Layout.leftMargin: CallManager.callsSupported ? 0 : 8
|
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
|
2021-01-19 03:25:56 +01:00
|
|
|
visible: TimelineManager.timeline && TimelineManager.timeline.input.uploading
|
2020-11-15 04:52:49 +01:00
|
|
|
|
|
|
|
NhekoBusyIndicator {
|
|
|
|
anchors.fill: parent
|
|
|
|
running: parent.visible
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-10-26 14:57:54 +01:00
|
|
|
}
|
|
|
|
|
2021-01-17 04:05:02 +01:00
|
|
|
Flickable {
|
2020-10-26 14:57:54 +01:00
|
|
|
id: textInput
|
|
|
|
|
2021-01-17 04:05:02 +01:00
|
|
|
function ensureVisible(r) {
|
|
|
|
if (contentX >= r.x)
|
|
|
|
contentX = r.x;
|
|
|
|
else if (contentX + width <= r.x + r.width)
|
|
|
|
contentX = r.x + r.width - width;
|
|
|
|
if (contentY >= r.y)
|
|
|
|
contentY = r.y;
|
|
|
|
else if (contentY + height <= r.y + r.height)
|
|
|
|
contentY = r.y + r.height - height;
|
|
|
|
}
|
|
|
|
|
2020-10-26 14:57:54 +01:00
|
|
|
Layout.alignment: Qt.AlignBottom
|
|
|
|
Layout.maximumHeight: Window.height / 4
|
2021-01-17 04:05:02 +01:00
|
|
|
Layout.minimumHeight: Settings.fontSize
|
2020-10-26 14:57:54 +01:00
|
|
|
Layout.fillWidth: true
|
2021-01-17 04:05:02 +01:00
|
|
|
clip: true
|
|
|
|
boundsBehavior: Flickable.StopAtBounds
|
2021-01-20 00:47:34 +01:00
|
|
|
flickableDirection: Flickable.VerticalFlick
|
2021-01-25 16:17:14 +01:00
|
|
|
implicitWidth: messageInput.width
|
|
|
|
implicitHeight: messageInput.height
|
|
|
|
contentWidth: messageInput.width
|
|
|
|
contentHeight: messageInput.height
|
2020-10-26 14:57:54 +01:00
|
|
|
|
|
|
|
TextArea {
|
2021-01-25 16:17:14 +01:00
|
|
|
id: messageInput
|
2020-10-31 23:24:07 +01:00
|
|
|
|
2020-11-20 01:22:36 +01:00
|
|
|
property int completerTriggeredAt: -1
|
|
|
|
|
2020-11-24 17:32:45 +01:00
|
|
|
function insertCompletion(completion) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.remove(completerTriggeredAt, cursorPosition);
|
|
|
|
messageInput.insert(cursorPosition, completion);
|
2020-11-24 17:32:45 +01:00
|
|
|
}
|
|
|
|
|
2020-11-25 19:03:22 +01:00
|
|
|
function openCompleter(pos, type) {
|
|
|
|
completerTriggeredAt = pos;
|
|
|
|
popup.completerName = type;
|
|
|
|
popup.open();
|
2021-01-25 16:17:14 +01:00
|
|
|
popup.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition));
|
2020-11-25 19:03:22 +01:00
|
|
|
}
|
|
|
|
|
2020-11-30 12:09:24 +01:00
|
|
|
selectByMouse: true
|
2020-10-26 14:57:54 +01:00
|
|
|
placeholderText: qsTr("Write a message...")
|
2021-01-18 13:44:26 +01:00
|
|
|
//placeholderTextColor: colors.buttonText
|
2021-01-19 03:25:56 +01:00
|
|
|
// only set the anchors on Qt 5.12 or higher
|
|
|
|
// see https://doc.qt.io/qt-5/qml-qtquick-controls2-popup.html#anchors.centerIn-prop
|
|
|
|
Component.onCompleted: {
|
|
|
|
if (placeholderTextColor !== undefined)
|
|
|
|
placeholderTextColor = colors.buttonText;
|
2021-01-18 13:44:26 +01:00
|
|
|
|
2021-01-19 03:25:56 +01:00
|
|
|
}
|
2020-10-26 14:57:54 +01:00
|
|
|
color: colors.text
|
2021-01-17 04:05:02 +01:00
|
|
|
width: textInput.width
|
2020-10-26 14:57:54 +01:00
|
|
|
wrapMode: TextEdit.Wrap
|
2021-01-17 04:05:02 +01:00
|
|
|
padding: 0
|
2020-11-25 17:38:06 +01:00
|
|
|
focus: true
|
2021-01-19 03:25:56 +01:00
|
|
|
onTextChanged: {
|
2021-01-19 23:58:25 +01:00
|
|
|
if (TimelineManager.timeline)
|
2021-01-19 03:25:56 +01:00
|
|
|
TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
2021-01-19 23:58:25 +01:00
|
|
|
|
2021-01-19 03:25:56 +01:00
|
|
|
}
|
2021-01-17 04:05:02 +01:00
|
|
|
onCursorRectangleChanged: textInput.ensureVisible(cursorRectangle)
|
2020-11-20 01:22:36 +01:00
|
|
|
onCursorPositionChanged: {
|
2021-01-19 03:25:56 +01:00
|
|
|
if (!TimelineManager.timeline)
|
|
|
|
return ;
|
|
|
|
|
2020-11-20 01:22:36 +01:00
|
|
|
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();
|
|
|
|
}
|
2020-11-24 03:06:24 +01:00
|
|
|
if (popup.opened)
|
2021-01-25 16:17:14 +01:00
|
|
|
popup.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition));
|
2020-11-24 03:06:24 +01:00
|
|
|
|
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;
|
2021-01-27 19:19:21 +01:00
|
|
|
} else if (event.key == Qt.Key_Space) {
|
2021-02-05 17:22:49 +01:00
|
|
|
// close popup if user enters space after colon
|
|
|
|
if(cursorPosition == completerTriggeredAt + 1)
|
|
|
|
popup.close();
|
|
|
|
|
2021-01-27 19:19:21 +01:00
|
|
|
if (popup.opened && popup.count <= 0)
|
2021-01-27 19:36:53 +01:00
|
|
|
popup.close();
|
|
|
|
|
2020-11-20 01:22:36 +01:00
|
|
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_U) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.clear();
|
2020-11-20 01:22:36 +01:00
|
|
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_P) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.text = TimelineManager.timeline.input.previousText();
|
2020-11-20 01:22:36 +01:00
|
|
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_N) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.text = TimelineManager.timeline.input.nextText();
|
2020-11-20 01:22:36 +01:00
|
|
|
} else if (event.key == Qt.Key_At) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.openCompleter(cursorPosition, "user");
|
2020-11-20 01:22:36 +01:00
|
|
|
popup.open();
|
2020-11-20 04:33:11 +01:00
|
|
|
} else if (event.key == Qt.Key_Colon) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.openCompleter(cursorPosition, "emoji");
|
2020-11-20 04:33:11 +01:00
|
|
|
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) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.insertCompletion(currentCompletion);
|
2020-11-25 02:20:42 +01:00
|
|
|
event.accepted = true;
|
|
|
|
return ;
|
|
|
|
}
|
2020-11-20 01:22:36 +01:00
|
|
|
}
|
2020-11-25 02:20:42 +01:00
|
|
|
TimelineManager.timeline.input.send();
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.clear();
|
2020-11-25 02:20:42 +01:00
|
|
|
event.accepted = true;
|
2020-11-25 19:03:22 +01:00
|
|
|
} else if (event.key == Qt.Key_Tab) {
|
2020-11-20 01:22:36 +01:00
|
|
|
event.accepted = true;
|
2020-11-25 19:03:22 +01:00
|
|
|
if (popup.opened) {
|
|
|
|
popup.up();
|
|
|
|
} else {
|
|
|
|
var pos = cursorPosition - 1;
|
|
|
|
while (pos > -1) {
|
2021-01-25 16:17:14 +01:00
|
|
|
var t = messageInput.getText(pos, pos + 1);
|
2020-11-25 19:03:22 +01:00
|
|
|
console.log('"' + t + '"');
|
2021-01-27 20:26:54 +01:00
|
|
|
if (t == '@') {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.openCompleter(pos, "user");
|
2020-11-25 19:03:22 +01:00
|
|
|
return ;
|
2021-01-27 20:26:54 +01:00
|
|
|
} else if (t == ' ' || t == '\t') {
|
|
|
|
messageInput.openCompleter(pos + 1, "user");
|
|
|
|
return ;
|
2020-11-25 19:03:22 +01:00
|
|
|
} else if (t == ':') {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.openCompleter(pos, "emoji");
|
2020-11-25 19:03:22 +01:00
|
|
|
return ;
|
|
|
|
}
|
|
|
|
pos = pos - 1;
|
|
|
|
}
|
|
|
|
// At start of input
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.openCompleter(0, "user");
|
2020-11-25 19:03:22 +01:00
|
|
|
}
|
2020-11-20 01:22:36 +01:00
|
|
|
} 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();
|
|
|
|
}
|
|
|
|
}
|
2021-01-17 04:05:02 +01:00
|
|
|
background: null
|
2020-11-20 01:22:36 +01:00
|
|
|
|
2020-11-20 02:38:08 +01:00
|
|
|
Connections {
|
2021-01-25 16:17:14 +01:00
|
|
|
onActiveTimelineChanged: {
|
|
|
|
messageInput.clear();
|
|
|
|
messageInput.append(TimelineManager.timeline.input.text());
|
|
|
|
messageInput.completerTriggeredAt = -1;
|
2020-11-20 02:38:08 +01:00
|
|
|
popup.completerName = "";
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.forceActiveFocus();
|
2020-11-20 02:38:08 +01:00
|
|
|
}
|
|
|
|
target: TimelineManager
|
|
|
|
}
|
2020-11-24 17:32:45 +01:00
|
|
|
|
|
|
|
Connections {
|
2021-01-25 16:17:14 +01:00
|
|
|
onCompletionClicked: messageInput.insertCompletion(completion)
|
2020-11-24 17:32:45 +01:00
|
|
|
target: popup
|
|
|
|
}
|
2020-11-20 02:38:08 +01:00
|
|
|
|
2020-11-20 01:22:36 +01:00
|
|
|
Completer {
|
|
|
|
id: popup
|
|
|
|
|
2021-01-25 16:17:14 +01:00
|
|
|
x: messageInput.completerTriggeredAt >= 0 ? messageInput.positionToRectangle(messageInput.completerTriggeredAt).x : 0
|
|
|
|
y: messageInput.completerTriggeredAt >= 0 ? messageInput.positionToRectangle(messageInput.completerTriggeredAt).y - height : 0
|
2020-11-15 04:52:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Connections {
|
2021-01-19 03:25:56 +01:00
|
|
|
ignoreUnknownSignals: true
|
2021-01-25 16:17:14 +01:00
|
|
|
onInsertText: messageInput.insert(messageInput.cursorPosition, text)
|
2021-01-19 03:25:56 +01:00
|
|
|
target: TimelineManager.timeline ? TimelineManager.timeline.input : null
|
2020-10-31 23:24:07 +01:00
|
|
|
}
|
|
|
|
|
2021-01-25 16:17:14 +01:00
|
|
|
Connections {
|
|
|
|
ignoreUnknownSignals: true
|
2021-01-27 19:36:53 +01:00
|
|
|
onReplyChanged: messageInput.forceActiveFocus()
|
2021-01-25 16:17:14 +01:00
|
|
|
target: TimelineManager.timeline
|
|
|
|
}
|
|
|
|
|
2020-10-26 14:57:54 +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
|
2020-10-26 14:57:54 +01:00
|
|
|
cursorShape: Qt.IBeamCursor
|
2020-11-09 03:12:37 +01:00
|
|
|
onClicked: TimelineManager.timeline.input.paste(true)
|
2020-10-26 14:57:54 +01:00
|
|
|
}
|
2021-02-03 03:12:08 +01:00
|
|
|
|
2021-01-17 04:05:02 +01:00
|
|
|
}
|
2020-10-26 14:57:54 +01:00
|
|
|
|
2021-01-17 04:05:02 +01:00
|
|
|
ScrollBar.vertical: ScrollBar {
|
2020-10-26 14:57:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageButton {
|
2020-11-16 18:41:29 +01:00
|
|
|
id: emojiButton
|
|
|
|
|
2020-10-26 14:57:54 +01:00
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
|
|
|
hoverEnabled: true
|
|
|
|
width: 22
|
|
|
|
height: 22
|
|
|
|
image: ":/icons/icons/ui/smile.png"
|
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) {
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.insert(messageInput.cursorPosition, emoji);
|
2020-11-16 18:41:29 +01:00
|
|
|
})
|
2020-10-26 14:57:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImageButton {
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
|
|
|
hoverEnabled: true
|
|
|
|
width: 22
|
|
|
|
height: 22
|
|
|
|
image: ":/icons/icons/ui/cursor.png"
|
2021-01-17 04:05:02 +01:00
|
|
|
Layout.rightMargin: 8
|
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();
|
2021-01-25 16:17:14 +01:00
|
|
|
messageInput.clear();
|
2020-11-15 04:52:49 +01:00
|
|
|
}
|
2020-10-26 14:57:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|