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

138 lines
3.7 KiB
QML
Raw Normal View History

2020-08-20 12:21:47 -04:00
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import QtQuick.Layouts 1.12
import "../../.."
import "../../../Base"
import "../../../Base/HTile"
2020-08-21 01:17:29 -04:00
// FIXME: a b -> a @p b → @p doesn't trigger completion
// FIXME: close autocomplete when cursor moves away
2020-08-20 12:21:47 -04:00
HListView {
2020-08-21 01:17:29 -04:00
id: root
2020-08-20 12:21:47 -04:00
property HTextArea textArea
property bool open: false
property string originalText: ""
property bool autoOpenCompleted: false
2020-08-21 01:17:29 -04:00
property var usersCompleted: ({}) // {displayName: userId}
2020-08-20 12:21:47 -04:00
readonly property bool autoOpen:
autoOpenCompleted || textArea.text.match(/.*(^|\W)@[^\s]+$/)
readonly property string wordToComplete:
open ?
(originalText || textArea.text).split(/\s/).slice(-1)[0].replace(
autoOpen ? /^@/ : "", "",
) :
""
function replaceLastWord(withText) {
2020-08-21 01:17:29 -04:00
let lastWordStart = /(?:^|\s)[^\s]+$/.exec(textArea.text).index
2020-08-20 12:21:47 -04:00
2020-08-21 01:17:29 -04:00
if (! (lastWordStart === 0 && ! textArea.text[0].match(/\s/)))
lastWordStart += 1
textArea.remove(lastWordStart, textArea.length)
2020-08-20 12:21:47 -04:00
textArea.insertAtCursor(withText)
}
function previous() {
if (open) {
decrementCurrentIndex()
return
}
open = true
const args = [model.modelId, wordToComplete]
py.callCoro("set_string_filter", args, decrementCurrentIndex)
}
function next() {
if (open) {
incrementCurrentIndex()
return
}
open = true
const args = [model.modelId, wordToComplete]
py.callCoro("set_string_filter", args, incrementCurrentIndex)
}
2020-08-21 01:17:29 -04:00
function accept() {
if (currentIndex !== -1) {
const member = model.get(currentIndex)
usersCompleted[member.display_name] = member.id
usersCompletedChanged()
}
open = false
}
2020-08-20 12:21:47 -04:00
function cancel() {
if (originalText)
replaceLastWord(originalText.split(/\s/).splice(-1)[0])
2020-08-21 01:17:29 -04:00
currentIndex = -1
open = false
2020-08-20 12:21:47 -04:00
}
visible: opacity > 0
opacity: open && count ? 1 : 0
implicitHeight: open && count ? Math.min(window.height, contentHeight) : 0
model: ModelStore.get(chat.userId, chat.roomId, "autocompleted_members")
delegate: HTile {
2020-08-21 01:17:29 -04:00
width: root.width
2020-08-20 12:21:47 -04:00
contentItem: HLabel { text: model.display_name + " (" + model.id + ")"}
onClicked: {
2020-08-21 01:17:29 -04:00
currentIndex = model.index
root.open = false
2020-08-20 12:21:47 -04:00
}
}
onCountChanged: if (! count && open) open = false
onAutoOpenChanged: open = autoOpen
onOpenChanged: if (! open) {
originalText = ""
currentIndex = -1
autoOpenCompleted = false
py.callCoro("set_string_filter", [model.modelId, ""])
}
onWordToCompleteChanged: {
if (! open) return
py.callCoro("set_string_filter", [model.modelId, wordToComplete])
}
onCurrentIndexChanged: {
if (currentIndex === -1) return
if (! originalText) originalText = textArea.text
if (autoOpen) autoOpenCompleted = true
replaceLastWord(model.get(currentIndex).display_name)
}
Behavior on opacity { HNumberAnimation {} }
Behavior on implicitHeight { HNumberAnimation {} }
2020-08-21 01:17:29 -04:00
Connections {
target: root.textArea
function onTextChanged() {
let changed = false
for (const displayName of Object.keys(root.usersCompleted)) {
if (! root.textArea.text.includes(displayName)) {
delete root.usersCompleted[displayName]
changed = true
}
}
if (changed) root.usersCompletedChanged()
}
}
2020-08-20 12:21:47 -04:00
}