Files
neochat/src/timeline/ChatBarComponent.qml
James Graham 4bd4bd6f22 Rework ActionsHandler
Rework ActionsHandler as static helper functions.

The functions are now invoked from ChatBarCache so there is no need to pass an actions handler object around qml simplifying the code.
2024-10-05 13:44:53 +00:00

178 lines
5.4 KiB
QML

// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.neochat.chatbar
/**
* @brief A component to show a chat bar in a message bubble.
*/
QQC2.TextArea {
id: root
/**
* @brief The NeoChatRoom the delegate is being displayed in.
*/
required property NeoChatRoom room
/**
* @brief The ChatBarCache to use.
*/
required property ChatBarCache chatBarCache
onChatBarCacheChanged: documentHandler.chatBarCache = chatBarCache
/**
* @brief The maximum width that the bubble's content can be.
*/
property real maxContentWidth: -1
Layout.fillWidth: true
Layout.preferredWidth: textMetrics.advanceWidth + rightPadding + Kirigami.Units.smallSpacing + Kirigami.Units.gridUnit
Layout.maximumWidth: root.maxContentWidth
Layout.minimumHeight: chatButtons.height + topPadding + bottomPadding
Component.onCompleted: _private.updateText()
topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
rightPadding: chatButtons.width + chatButtons.anchors.rightMargin * 2
color: Kirigami.Theme.textColor
verticalAlignment: TextEdit.AlignVCenter
wrapMode: TextEdit.Wrap
onTextChanged: {
root.chatBarCache.text = text;
}
Keys.onEnterPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else if (event.modifiers & Qt.ShiftModifier) {
root.insert(cursorPosition, "\n");
} else {
_private.post();
}
}
Keys.onReturnPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else if (event.modifiers & Qt.ShiftModifier) {
root.insert(cursorPosition, "\n");
} else {
_private.post();
}
}
Keys.onTabPressed: {
if (completionMenu.visible) {
completionMenu.complete();
}
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Up && completionMenu.visible) {
completionMenu.decrementIndex();
} else if (event.key === Qt.Key_Down && completionMenu.visible) {
completionMenu.incrementIndex();
}
}
/**
* This is anchored like this so that control expands properly as the
* text grows in length.
*/
RowLayout {
id: chatButtons
anchors.verticalCenter: root.verticalCenter
anchors.right: root.right
anchors.rightMargin: Kirigami.Units.smallSpacing
spacing: 0
QQC2.ToolButton {
display: QQC2.AbstractButton.IconOnly
action: Kirigami.Action {
text: root.chatBarCache.isEditing ? i18nc("@action:button", "Confirm edit") : i18nc("@action:button", "Post message in thread")
icon.name: "document-send"
onTriggered: {
_private.post();
}
}
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton {
display: QQC2.AbstractButton.IconOnly
action: Kirigami.Action {
text: i18nc("@action:button", "Cancel")
icon.name: "dialog-close"
onTriggered: {
root.chatBarCache.clearRelations();
}
shortcut: "Escape"
}
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
}
}
CompletionMenu {
id: completionMenu
height: implicitHeight
y: -height - 5
z: 10
connection: root.room.connection
chatDocumentHandler: documentHandler
Behavior on height {
NumberAnimation {
property: "height"
duration: Kirigami.Units.shortDuration
easing.type: Easing.OutCubic
}
}
}
// opt-out of whatever spell checker a styled TextArea might come with
Kirigami.SpellCheck.enabled: false
ChatDocumentHandler {
id: documentHandler
document: root.textDocument
cursorPosition: root.cursorPosition
selectionStart: root.selectionStart
selectionEnd: root.selectionEnd
room: root.room // We don't care about saving for edits so this is OK.
mentionColor: Kirigami.Theme.linkColor
errorColor: Kirigami.Theme.negativeTextColor
}
TextMetrics {
id: textMetrics
text: root.text
}
QtObject {
id: _private
function updateText() {
// This could possibly be undefined due to some esoteric QtQuick issue. Referencing it somewhere in JS is enough.
documentHandler.document;
if (chatBarCache?.isEditing && chatBarCache.relationMessage.length > 0) {
root.text = chatBarCache.relationMessage;
root.chatBarCache.updateMentions(root.textDocument, documentHandler);
root.forceActiveFocus();
root.cursorPosition = root.text.length;
}
}
function post() {
root.chatBarCache.postMessage();
root.clear();
root.chatBarCache.clearRelations();
}
}
}