moment/src/gui/Pages/Chat/Composer/MessageArea.qml

210 lines
5.8 KiB
QML
Raw Normal View History

// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import "../../.."
import "../../../Base"
HTextArea {
id: textArea
property HListView eventList
property string indent: " "
property string toSend: ""
property bool textChangedSinceLostFocus: false
property string writingUserId: chat.userId
readonly property QtObject writingUserInfo:
ModelStore.get("accounts").find(writingUserId)
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).slice(-1)[0].length :
// 1
readonly property var usableAliases: {
const obj = {}
// Get accounts that are members of this room with permission to talk
for (const [id, alia] of Object.entries(window.settings.writeAliases)){
const room = ModelStore.get(id, "rooms").find(chat.roomId)
if (room &&
! room.inviter_id && ! room.left && room.can_send_messages)
obj[id] = alia
}
return obj
}
function setTyping(typing) {
py.callClientCoro(
writingUserId, "room_typing", [chat.roomId, typing, 5000],
)
}
function clearReplyTo() {
if (! chat.replyToEventId) return
chat.replyToEventId = ""
chat.replyToUserId = ""
chat.replyToDisplayName = ""
}
function addNewLine() {
let indents = 0
const parts = lineText.split(indent)
for (const [i, part] of parts.entries()) {
if (i === parts.length - 1 || part) { break }
indents += 1
}
const add = indent.repeat(indents)
textArea.insertAtCursor("\n" + add)
}
function sendText() {
if (! toSend) return
const args = [chat.roomId, toSend, chat.replyToEventId]
py.callClientCoro(writingUserId, "send_text", args)
textArea.clear()
clearReplyTo()
}
saveName: "composer"
saveId: [chat.roomId, writingUserId]
enabled: chat.roomInfo.can_send_messages
disabledText: qsTr("You do not have permission to post in this room")
placeholderText: qsTr("Type a message...")
backgroundColor: "transparent"
2020-06-06 21:54:13 -04:00
focusedBorderColor: "transparent"
tabStopDistance: 4 * 4 // 4 spaces
focus: true
// TODO: make this more declarative
onTextChanged: {
if (! text || utils.isEmptyObject(usableAliases)) {
writingUserId = Qt.binding(() => chat.userId)
toSend = text
setTyping(Boolean(text))
textChangedSinceLostFocus = true
return
}
let foundAlias = null
for (const [user, writing_alias] of Object.entries(usableAliases)) {
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(() => chat.userId)
toSend = text
const vals = Object.values(usableAliases)
const longestAlias =
vals.reduce((a, b) => a.length > b.length ? a: b)
const textNotStartsWithAnyAlias =
! vals.some(a => a.startsWith(text))
const 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
}
}
onEditingFinished: { // when focus is lost
if (text && textChangedSinceLostFocus) {
setTyping(false)
textChangedSinceLostFocus = false
}
}
Keys.onEscapePressed: clearReplyTo()
Keys.onReturnPressed: ev => {
ev.accepted = true
ev.modifiers & Qt.ShiftModifier ||
ev.modifiers & Qt.ControlModifier ||
ev.modifiers & Qt.AltModifier ?
addNewLine() :
sendText()
}
Keys.onEnterPressed: ev => Keys.returnPressed(ev)
Keys.onMenuPressed: ev => {
if (eventList && eventList.currentItem)
eventList.currentItem.openContextMenu()
}
Keys.onTabPressed: ev => {
ev.accepted = true
textArea.insertAtCursor(indent)
}
Keys.onPressed: ev => {
if (ev.matches(StandardKey.Copy) &&
! textArea.selectedText &&
eventList &&
(eventList.selectedCount || eventList.currentIndex !== -1))
{
ev.accepted = true
eventList.copySelectedDelegates()
return
}
// FIXME: buggy
// if (ev.modifiers === Qt.NoModifier &&
// ev.key === Qt.Key_Backspace &&
// ! textArea.selectedText)
// {
// ev.accepted = true
// textArea.remove(
// cursorPosition - deleteCharsOnBackspace,
// cursorPosition
// )
// }
}
}