2019-07-08 13:52:41 +10:00
|
|
|
// Copyright 2019 miruka
|
|
|
|
// This file is part of harmonyqml, licensed under LGPLv3.
|
|
|
|
|
2019-07-13 19:39:01 +10:00
|
|
|
import QtQuick 2.12
|
|
|
|
import QtQuick.Layouts 1.12
|
2019-04-29 05:18:36 +10:00
|
|
|
import "../Base"
|
2019-03-22 14:28:14 +11:00
|
|
|
|
2019-05-12 07:51:00 +10:00
|
|
|
HRectangle {
|
2019-07-21 04:37:21 +10:00
|
|
|
function setFocus() { areaScrollView.forceActiveFocus() }
|
2019-03-22 14:28:14 +11:00
|
|
|
|
2019-07-22 09:12:32 +10:00
|
|
|
property string indent: " "
|
|
|
|
|
2019-07-21 22:57:17 +10:00
|
|
|
property var aliases: window.settings.writeAliases
|
2019-07-19 13:50:23 +10:00
|
|
|
property string writingUserId: chatPage.userId
|
|
|
|
property string toSend: ""
|
|
|
|
|
|
|
|
property bool textChangedSinceLostFocus: false
|
|
|
|
|
2019-07-21 04:37:21 +10:00
|
|
|
property alias textArea: areaScrollView.area
|
|
|
|
|
2019-07-22 10:24:21 +10:00
|
|
|
readonly property int cursorPosition:
|
|
|
|
textArea.cursorPosition
|
|
|
|
|
|
|
|
readonly property int cursorY:
|
|
|
|
textArea.text.substring(0, cursorPosition).split("\n").length - 1
|
|
|
|
|
|
|
|
readonly property int cursorX:
|
|
|
|
cursorPosition - lines.slice(0, cursorY).join("").length - cursorY
|
|
|
|
|
|
|
|
readonly property var lines: textArea.text.split("\n")
|
|
|
|
readonly property string lineText: lines[cursorY] || ""
|
|
|
|
|
|
|
|
readonly property string lineTextUntilCursor:
|
|
|
|
lineText.substring(0, cursorX)
|
|
|
|
|
|
|
|
readonly property int deleteCharsOnBackspace:
|
|
|
|
lineTextUntilCursor.match(/^ +$/) ?
|
|
|
|
lineTextUntilCursor.match(/ {1,4}/g).splice(-1)[0].length :
|
|
|
|
1
|
|
|
|
|
|
|
|
// property var pr: lineTextUntilCursor
|
|
|
|
// onPrChanged: print(
|
|
|
|
// "y", cursorY, "x", cursorX,
|
|
|
|
// "ltuc <" + lineTextUntilCursor + ">", "dob",
|
|
|
|
// deleteCharsOnBackspace, "m", lineTextUntilCursor.match(/^ +$/))
|
|
|
|
|
2019-07-07 07:56:04 +10:00
|
|
|
id: sendBox
|
2019-03-22 14:28:14 +11:00
|
|
|
Layout.fillWidth: true
|
2019-07-16 19:13:19 +10:00
|
|
|
Layout.minimumHeight: theme.baseElementsHeight
|
2019-07-21 04:37:21 +10:00
|
|
|
Layout.preferredHeight: areaScrollView.implicitHeight
|
2019-03-22 14:28:14 +11:00
|
|
|
Layout.maximumHeight: pageStack.height / 2
|
2019-07-07 07:50:55 +10:00
|
|
|
color: theme.chat.sendBox.background
|
2019-03-22 14:28:14 +11:00
|
|
|
|
2019-04-29 05:18:36 +10:00
|
|
|
HRowLayout {
|
2019-03-22 14:28:14 +11:00
|
|
|
anchors.fill: parent
|
|
|
|
|
2019-07-07 14:24:23 +10:00
|
|
|
HUserAvatar {
|
2019-04-21 07:45:51 +10:00
|
|
|
id: avatar
|
2019-07-19 13:50:23 +10:00
|
|
|
userId: writingUserId
|
2019-03-22 14:28:14 +11:00
|
|
|
}
|
|
|
|
|
2019-04-29 05:18:36 +10:00
|
|
|
HScrollableTextArea {
|
2019-03-22 14:28:14 +11:00
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
2019-07-07 07:56:04 +10:00
|
|
|
Layout.topMargin: Math.max(0, sendBox.Layout.minimumHeight - 34)
|
2019-03-22 14:28:14 +11:00
|
|
|
|
2019-07-21 04:37:21 +10:00
|
|
|
id: areaScrollView
|
2019-04-29 01:50:46 +10:00
|
|
|
placeholderText: qsTr("Type a message...")
|
2019-04-29 05:13:18 +10:00
|
|
|
backgroundColor: "transparent"
|
2019-07-22 09:12:32 +10:00
|
|
|
area.tabStopDistance: 4 * 4 // 4 spaces
|
2019-04-29 01:50:46 +10:00
|
|
|
area.focus: true
|
2019-04-19 17:11:56 +10:00
|
|
|
|
2019-04-29 01:50:46 +10:00
|
|
|
function setTyping(typing) {
|
2019-07-08 13:28:10 +10:00
|
|
|
py.callClientCoro(
|
2019-07-19 13:50:23 +10:00
|
|
|
writingUserId,
|
2019-07-08 13:28:10 +10:00
|
|
|
"room_typing",
|
|
|
|
[chatPage.roomId, typing, 5000]
|
|
|
|
)
|
2019-04-29 01:50:46 +10:00
|
|
|
}
|
2019-04-19 17:11:56 +10:00
|
|
|
|
2019-05-18 06:01:42 +10:00
|
|
|
onTextChanged: {
|
2019-07-19 13:50:23 +10:00
|
|
|
let foundAlias = null
|
|
|
|
|
|
|
|
for (let [user, writing_alias] of Object.entries(aliases)) {
|
|
|
|
if (text.startsWith(writing_alias + " ")) {
|
|
|
|
writingUserId = user
|
|
|
|
foundAlias = new RegExp("^" + writing_alias + " ")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundAlias) {
|
|
|
|
toSend = text.replace(foundAlias, "")
|
|
|
|
setTyping(Boolean(text))
|
|
|
|
textChangedSinceLostFocus = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
writingUserId = Qt.binding(() => chatPage.userId)
|
|
|
|
toSend = text
|
|
|
|
|
|
|
|
let vals = Object.values(aliases)
|
|
|
|
|
|
|
|
let longestAlias =
|
|
|
|
vals.reduce((a, b) => a.length > b.length ? a: b)
|
|
|
|
|
|
|
|
let textNotStartsWithAnyAlias =
|
2019-07-23 17:14:02 +10:00
|
|
|
! vals.some(a => a.startsWith(text))
|
2019-07-19 13:50:23 +10:00
|
|
|
|
|
|
|
let textContainsCharNotInAnyAlias =
|
|
|
|
vals.every(a => text.split("").some(c => ! a.includes(c)))
|
|
|
|
|
|
|
|
// Only set typing when it's sure that the user will not use
|
|
|
|
// an alias and has written something
|
|
|
|
if (toSend &&
|
|
|
|
(text.length > longestAlias.length ||
|
|
|
|
textNotStartsWithAnyAlias ||
|
|
|
|
textContainsCharNotInAnyAlias))
|
|
|
|
{
|
|
|
|
setTyping(Boolean(text))
|
|
|
|
textChangedSinceLostFocus = true
|
|
|
|
}
|
2019-05-18 06:01:42 +10:00
|
|
|
}
|
2019-07-19 13:50:23 +10:00
|
|
|
|
2019-05-18 06:01:42 +10:00
|
|
|
area.onEditingFinished: { // when lost focus
|
|
|
|
if (text && textChangedSinceLostFocus) {
|
|
|
|
setTyping(false)
|
|
|
|
textChangedSinceLostFocus = false
|
|
|
|
}
|
|
|
|
}
|
2019-03-22 14:28:14 +11:00
|
|
|
|
2019-07-05 17:16:52 +10:00
|
|
|
Component.onCompleted: {
|
2019-07-18 17:35:30 +10:00
|
|
|
area.Keys.onReturnPressed.connect(event => {
|
2019-07-05 17:16:52 +10:00
|
|
|
event.accepted = true
|
2019-03-22 14:28:14 +11:00
|
|
|
|
2019-07-05 17:16:52 +10:00
|
|
|
if (event.modifiers & Qt.ShiftModifier ||
|
|
|
|
event.modifiers & Qt.ControlModifier ||
|
2019-07-21 04:37:21 +10:00
|
|
|
event.modifiers & Qt.AltModifier)
|
|
|
|
{
|
2019-07-22 10:24:21 +10:00
|
|
|
let indents = 0
|
|
|
|
let parts = lineText.split(indent)
|
2019-07-22 09:12:32 +10:00
|
|
|
|
2019-07-22 10:24:21 +10:00
|
|
|
for (const [i, part] of parts.entries()) {
|
|
|
|
if (i == parts.length - 1 || part) { break }
|
2019-07-22 09:12:32 +10:00
|
|
|
indents += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
let add = indent.repeat(indents)
|
2019-07-22 10:24:21 +10:00
|
|
|
textArea.insert(cursorPosition, "\n" + add)
|
2019-07-05 17:16:52 +10:00
|
|
|
return
|
|
|
|
}
|
2019-04-19 17:11:56 +10:00
|
|
|
|
2019-07-05 17:16:52 +10:00
|
|
|
if (textArea.text === "") { return }
|
2019-07-04 11:20:49 +10:00
|
|
|
|
2019-07-19 13:50:23 +10:00
|
|
|
let args = [chatPage.roomId, toSend]
|
|
|
|
py.callClientCoro(writingUserId, "send_markdown", args)
|
|
|
|
|
2019-07-05 17:16:52 +10:00
|
|
|
area.clear()
|
|
|
|
})
|
2019-04-29 01:50:46 +10:00
|
|
|
|
2019-07-05 17:16:52 +10:00
|
|
|
area.Keys.onEnterPressed.connect(area.Keys.onReturnPressed)
|
2019-07-22 08:20:36 +10:00
|
|
|
|
|
|
|
area.Keys.onTabPressed.connect(event => {
|
2019-07-22 10:24:21 +10:00
|
|
|
event.accepted = true
|
|
|
|
textArea.insert(cursorPosition, indent)
|
|
|
|
})
|
|
|
|
|
|
|
|
area.Keys.onPressed.connect(event => {
|
|
|
|
if (event.modifiers == Qt.NoModifier &&
|
|
|
|
event.key == Qt.Key_Backspace &&
|
|
|
|
! textArea.selectedText)
|
|
|
|
{
|
|
|
|
event.accepted = true
|
|
|
|
textArea.remove(
|
|
|
|
cursorPosition - deleteCharsOnBackspace,
|
|
|
|
cursorPosition
|
|
|
|
)
|
|
|
|
}
|
2019-07-22 08:20:36 +10:00
|
|
|
})
|
2019-07-05 17:16:52 +10:00
|
|
|
}
|
2019-03-22 14:28:14 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|