Add ChatBarMessageContentModel and hook up
This commit is contained in:
@@ -35,7 +35,7 @@ QQC2.Control {
|
||||
|
||||
required property NeoChatConnection connection
|
||||
|
||||
onActiveFocusChanged: textField.forceActiveFocus()
|
||||
onActiveFocusChanged: chatContentView.itemAt(contentModel.index(contentModel.focusRow, 0)).forceActiveFocus()
|
||||
|
||||
onCurrentRoomChanged: {
|
||||
_private.chatBarCache = currentRoom.mainCache
|
||||
@@ -75,6 +75,9 @@ QQC2.Control {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
Message.room: root.currentRoom
|
||||
Message.contentModel: contentModel
|
||||
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
Kirigami.Separator {
|
||||
@@ -84,233 +87,39 @@ QQC2.Control {
|
||||
}
|
||||
}
|
||||
|
||||
height: Math.max(Math.min(chatScrollView.contentHeight + bottomPadding + topPadding, Kirigami.Units.gridUnit * 10), Kirigami.Units.gridUnit * 5)
|
||||
leftPadding: rightPadding
|
||||
rightPadding: (root.width - chatBarSizeHelper.availableWidth) / 2
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
topPadding: Kirigami.Units.smallSpacing
|
||||
bottomPadding: Kirigami.Units.smallSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
Item {
|
||||
// Required to adjust for the top separator
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Loader {
|
||||
id: replyLoader
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
Layout.preferredHeight: active ? (item as Item).implicitHeight : 0
|
||||
|
||||
active: visible
|
||||
visible: root.currentRoom.mainCache.replyId.length > 0
|
||||
sourceComponent: replyPane
|
||||
}
|
||||
RowLayout {
|
||||
visible: replyLoader.visible && !root.currentRoom.mainCache.relationAuthorIsPresent
|
||||
contentItem: QQC2.ScrollView {
|
||||
id: chatScrollView
|
||||
ColumnLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Kirigami.Icon {
|
||||
source: "help-hint-symbolic"
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
}
|
||||
QQC2.Label {
|
||||
text: i18nc("@info", "The user you're replying to has left the room, and can't be notified.")
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: attachLoader
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
Layout.preferredHeight: active ? (item as Item).implicitHeight : 0
|
||||
|
||||
active: visible
|
||||
visible: root.currentRoom.mainCache.attachmentPath.length > 0
|
||||
sourceComponent: attachmentPane
|
||||
}
|
||||
RowLayout {
|
||||
QQC2.ScrollView {
|
||||
id: chatBarScrollView
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: Kirigami.Units.gridUnit * 8
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 3
|
||||
|
||||
// HACK: This is to stop the ScrollBar flickering on and off as the height is increased
|
||||
QQC2.ScrollBar.vertical.policy: chatBarHeightAnimation.running && implicitHeight <= height ? QQC2.ScrollBar.AlwaysOff : QQC2.ScrollBar.AsNeeded
|
||||
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation {
|
||||
id: chatBarHeightAnimation
|
||||
duration: Kirigami.Units.shortDuration
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
Repeater {
|
||||
id: chatContentView
|
||||
model: ChatBarMessageContentModel {
|
||||
id: contentModel
|
||||
type: ChatBarType.Room
|
||||
room: root.currentRoom
|
||||
}
|
||||
|
||||
QQC2.TextArea {
|
||||
id: textField
|
||||
|
||||
placeholderText: root.currentRoom.usesEncryption ? i18nc("@placeholder", "Send an encrypted message…") : root.currentRoom.mainCache.attachmentPath.length > 0 ? i18nc("@placeholder", "Set an attachment caption…") : i18nc("@placeholder", "Send a message…")
|
||||
verticalAlignment: TextEdit.AlignVCenter
|
||||
wrapMode: TextEdit.Wrap
|
||||
persistentSelection: true
|
||||
|
||||
Accessible.description: placeholderText
|
||||
|
||||
Kirigami.SpellCheck.enabled: false
|
||||
|
||||
Timer {
|
||||
id: repeatTimer
|
||||
interval: 5000
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
if (!repeatTimer.running && NeoChatConfig.typingNotifications) {
|
||||
var textExists = text.length > 0;
|
||||
root.currentRoom.sendTypingNotification(textExists);
|
||||
textExists ? repeatTimer.start() : repeatTimer.stop();
|
||||
}
|
||||
}
|
||||
onSelectedTextChanged: {
|
||||
if (selectedText.length > 0) {
|
||||
quickFormatBar.selectionStart = selectionStart;
|
||||
quickFormatBar.selectionEnd = selectionEnd;
|
||||
quickFormatBar.open();
|
||||
} else if (quickFormatBar.visible) {
|
||||
quickFormatBar.close();
|
||||
}
|
||||
}
|
||||
|
||||
QuickFormatBar {
|
||||
id: quickFormatBar
|
||||
|
||||
x: textField.cursorRectangle.x
|
||||
y: textField.cursorRectangle.y - height
|
||||
|
||||
onFormattingSelected: (format, selectionStart, selectionEnd) => _private.formatText(format, selectionStart, selectionEnd)
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: event => {
|
||||
const controlIsPressed = event.modifiers & Qt.ControlModifier;
|
||||
if (completionMenu.visible) {
|
||||
completionMenu.complete();
|
||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) {
|
||||
textField.insert(cursorPosition, "\n");
|
||||
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) {
|
||||
_private.postMessage();
|
||||
}
|
||||
}
|
||||
Keys.onReturnPressed: event => {
|
||||
const controlIsPressed = event.modifiers & Qt.ControlModifier;
|
||||
if (completionMenu.visible) {
|
||||
completionMenu.complete();
|
||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) {
|
||||
textField.insert(cursorPosition, "\n");
|
||||
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) {
|
||||
_private.postMessage();
|
||||
}
|
||||
}
|
||||
Keys.onTabPressed: {
|
||||
if (completionMenu.visible) {
|
||||
completionMenu.complete();
|
||||
} else {
|
||||
contextDrawer.handle.children[0].forceActiveFocus()
|
||||
}
|
||||
}
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
|
||||
event.accepted = _private.pasteImage();
|
||||
} else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) {
|
||||
root.currentRoom.replyLastMessage();
|
||||
} else if (event.key === Qt.Key_Up && textField.text.length === 0) {
|
||||
root.currentRoom.editLastMessage();
|
||||
} else if (event.key === Qt.Key_Up && completionMenu.visible) {
|
||||
completionMenu.decrementIndex();
|
||||
} else if (event.key === Qt.Key_Down && completionMenu.visible) {
|
||||
completionMenu.incrementIndex();
|
||||
} else if (event.key === Qt.Key_Backspace || event.key === Qt.Key_Delete) {
|
||||
if (textField.text == selectedText || textField.text.length <= 1) {
|
||||
root.currentRoom.sendTypingNotification(false);
|
||||
repeatTimer.stop();
|
||||
}
|
||||
if (quickFormatBar.visible && selectedText.length > 0) {
|
||||
quickFormatBar.close();
|
||||
}
|
||||
} else if (event.key === Qt.Key_Escape && completionMenu.visible) {
|
||||
completionMenu.close();
|
||||
}
|
||||
}
|
||||
Keys.onShortcutOverride: event => {
|
||||
if ((_private.chatBarCache.isReplying || _private.chatBarCache.attachmentPath.length > 0) && event.key === Qt.Key_Escape) {
|
||||
_private.chatBarCache.attachmentPath = "";
|
||||
_private.chatBarCache.replyId = "";
|
||||
_private.chatBarCache.threadId = "";
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
background: MouseArea {
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
delegate: MessageComponentChooser {}
|
||||
}
|
||||
RowLayout {
|
||||
id: actionsRow
|
||||
spacing: 0
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing * 4
|
||||
RichEditBar {
|
||||
id: richEditBar
|
||||
maxAvailableWidth: chatBarSizeHelper.availableWidth - Kirigami.Units.largeSpacing * 2
|
||||
|
||||
Repeater {
|
||||
model: root.actions
|
||||
delegate: QQC2.ToolButton {
|
||||
id: actionDelegate
|
||||
required property BusyAction modelData
|
||||
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
||||
onClicked: if (!pieProgress.visible) {
|
||||
modelData.trigger()
|
||||
}
|
||||
room: root.currentRoom
|
||||
contentModel: chatContentView.model
|
||||
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: modelData.tooltip
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
PieProgressBar {
|
||||
id: pieProgress
|
||||
anchors.fill: parent
|
||||
visible: actionDelegate.modelData.isBusy
|
||||
progress: root.currentRoom.fileUploadingProgress
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: contentModel.refocusCurrentComponent()
|
||||
}
|
||||
}
|
||||
RichEditBar {
|
||||
id: richEditBar
|
||||
Layout.maximumWidth: chatBarSizeHelper.availableWidth - Kirigami.Units.largeSpacing * 2
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
Layout.alignment:Qt.AlignHCenter
|
||||
maxAvailableWidth: chatBarSizeHelper.availableWidth - Kirigami.Units.largeSpacing * 2
|
||||
|
||||
room: root.currentRoom
|
||||
documentHandler: documentHandler
|
||||
|
||||
onRequestPostMessage: _private.postMessage()
|
||||
}
|
||||
}
|
||||
|
||||
LibNeoChat.DelegateSizeHelper {
|
||||
id: chatBarSizeHelper
|
||||
parentItem: root
|
||||
@@ -321,49 +130,6 @@ QQC2.Control {
|
||||
maxWidth: NeoChatConfig.compactLayout ? root.width - Kirigami.Units.largeSpacing * 2 : Kirigami.Units.gridUnit * 60
|
||||
}
|
||||
|
||||
Component {
|
||||
id: replyPane
|
||||
Item {
|
||||
implicitHeight: replyComponent.implicitHeight
|
||||
ReplyComponent {
|
||||
id: replyComponent
|
||||
replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true)
|
||||
Message.maxContentWidth: (replyLoader.item as Item).width
|
||||
|
||||
// When the user replies to a message and the preview is loaded, make sure the text field is focused again
|
||||
Component.onCompleted: textField.forceActiveFocus(Qt.OtherFocusReason)
|
||||
}
|
||||
QQC2.Button {
|
||||
id: cancelButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("@action:button", "Cancel reply")
|
||||
icon.name: "dialog-close"
|
||||
onClicked: {
|
||||
_private.chatBarCache.replyId = "";
|
||||
_private.chatBarCache.attachmentPath = "";
|
||||
}
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: attachmentPane
|
||||
AttachmentPane {
|
||||
attachmentPath: _private.chatBarCache.attachmentPath
|
||||
|
||||
onAttachmentCancelled: {
|
||||
_private.chatBarCache.attachmentPath = "";
|
||||
root.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: _private
|
||||
property ChatBarCache chatBarCache
|
||||
@@ -371,53 +137,6 @@ QQC2.Control {
|
||||
richEditBar.chatBarCache = chatBarCache
|
||||
}
|
||||
|
||||
function postMessage() {
|
||||
_private.chatBarCache.postMessage();
|
||||
repeatTimer.stop();
|
||||
textField.clear();
|
||||
}
|
||||
|
||||
function formatText(format, selectionStart, selectionEnd) {
|
||||
let index = textField.cursorPosition;
|
||||
|
||||
/*
|
||||
* There cannot be white space at the beginning or end of the string for the
|
||||
* formatting to work so move the sectionStart and sectionEnd markers past any whitespace.
|
||||
*/
|
||||
let innerText = textField.text.substr(selectionStart, selectionEnd - selectionStart);
|
||||
if (innerText.charAt(innerText.length - 1) === " ") {
|
||||
let trimmedRightString = innerText.replace(/\s*$/, "");
|
||||
let trimDifference = innerText.length - trimmedRightString.length;
|
||||
selectionEnd -= trimDifference;
|
||||
}
|
||||
if (innerText.charAt(0) === " ") {
|
||||
let trimmedLeftString = innerText.replace(/^\s*/, "");
|
||||
let trimDifference = innerText.length - trimmedLeftString.length;
|
||||
selectionStart = selectionStart + trimDifference;
|
||||
}
|
||||
let startText = textField.text.substr(0, selectionStart);
|
||||
// Needs updating with the new selectionStart and selectionEnd with white space trimmed.
|
||||
innerText = textField.text.substr(selectionStart, selectionEnd - selectionStart);
|
||||
let endText = textField.text.substr(selectionEnd);
|
||||
textField.text = "";
|
||||
textField.text = startText + format.start + innerText + format.end + format.extra + endText;
|
||||
|
||||
/*
|
||||
* Put the cursor where it was when the popup was opened accounting for the
|
||||
* new markup.
|
||||
*
|
||||
* The exception is for a hyperlink where it is placed ready to start typing
|
||||
* the url.
|
||||
*/
|
||||
if (format.extra !== "") {
|
||||
textField.cursorPosition = selectionEnd + format.start.length + format.end.length;
|
||||
} else if (index == selectionStart) {
|
||||
textField.cursorPosition = index;
|
||||
} else {
|
||||
textField.cursorPosition = index + format.start.length + format.end.length;
|
||||
}
|
||||
}
|
||||
|
||||
function pasteImage() {
|
||||
let localPath = Clipboard.saveImage();
|
||||
if (localPath.length === 0) {
|
||||
@@ -428,16 +147,9 @@ QQC2.Control {
|
||||
}
|
||||
}
|
||||
|
||||
ChatDocumentHandler {
|
||||
id: documentHandler
|
||||
type: ChatBarType.Room
|
||||
textItem: textField
|
||||
room: root.currentRoom
|
||||
}
|
||||
|
||||
CompletionMenu {
|
||||
id: completionMenu
|
||||
chatDocumentHandler: documentHandler
|
||||
chatDocumentHandler: contentModel.focusedDocumentHandler
|
||||
connection: root.connection
|
||||
|
||||
x: 1
|
||||
|
||||
@@ -18,6 +18,10 @@ QQC2.Popup {
|
||||
|
||||
required property NeoChatConnection connection
|
||||
required property var chatDocumentHandler
|
||||
onChatDocumentHandlerChanged: if (chatDocumentHandler) {
|
||||
chatDocumentHandler.completionModel.roomListModel = RoomManager.roomListModel;
|
||||
chatDocumentHandler.completionModel.userListModel = RoomManager.userListModel;
|
||||
}
|
||||
|
||||
visible: completions.count > 0
|
||||
|
||||
@@ -25,11 +29,6 @@ QQC2.Popup {
|
||||
root.open();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
chatDocumentHandler.completionModel.roomListModel = RoomManager.roomListModel;
|
||||
chatDocumentHandler.completionModel.userListModel = RoomManager.userListModel;
|
||||
}
|
||||
|
||||
function incrementIndex() {
|
||||
completions.incrementCurrentIndex();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2025 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 QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
@@ -8,6 +9,7 @@ import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.neochat.libneochat as LibNeoChat
|
||||
import org.kde.neochat.messagecontent as MessageContent
|
||||
|
||||
QQC2.ToolBar {
|
||||
id: root
|
||||
@@ -19,13 +21,23 @@ QQC2.ToolBar {
|
||||
|
||||
property LibNeoChat.ChatBarCache chatBarCache
|
||||
|
||||
required property LibNeoChat.ChatDocumentHandler documentHandler
|
||||
required property MessageContent.ChatBarMessageContentModel contentModel
|
||||
readonly property LibNeoChat.ChatDocumentHandler focusedDocumentHandler: contentModel.focusedDocumentHandler
|
||||
|
||||
Connections {
|
||||
target: contentModel
|
||||
|
||||
function onFocusRowChanged() {
|
||||
console.warn("focus changed", contentModel.focusRow, contentModel.focusType)
|
||||
}
|
||||
}
|
||||
|
||||
required property real maxAvailableWidth
|
||||
|
||||
readonly property real uncompressedImplicitWidth: textFormatRow.implicitWidth +
|
||||
listRow.implicitWidth +
|
||||
styleButton.implicitWidth +
|
||||
codeButton.implicitWidth +
|
||||
emojiButton.implicitWidth +
|
||||
linkButton.implicitWidth +
|
||||
sendRow.implicitWidth +
|
||||
@@ -36,6 +48,7 @@ QQC2.ToolBar {
|
||||
readonly property real listCompressedImplicitWidth: textFormatRow.implicitWidth +
|
||||
compressedListButton.implicitWidth +
|
||||
styleButton.implicitWidth +
|
||||
codeButton.implicitWidth +
|
||||
emojiButton.implicitWidth +
|
||||
linkButton.implicitWidth +
|
||||
sendRow.implicitWidth +
|
||||
@@ -46,6 +59,7 @@ QQC2.ToolBar {
|
||||
readonly property real textFormatCompressedImplicitWidth: compressedTextFormatButton.implicitWidth +
|
||||
compressedListButton.implicitWidth +
|
||||
styleButton.implicitWidth +
|
||||
codeButton.implicitWidth +
|
||||
emojiButton.implicitWidth +
|
||||
linkButton.implicitWidth +
|
||||
sendRow.implicitWidth +
|
||||
@@ -53,7 +67,7 @@ QQC2.ToolBar {
|
||||
buttonRow.spacing * 9 +
|
||||
3
|
||||
|
||||
signal requestPostMessage
|
||||
signal clicked
|
||||
|
||||
RowLayout {
|
||||
id: buttonRow
|
||||
@@ -67,11 +81,15 @@ QQC2.ToolBar {
|
||||
onActivated: boldButton.clicked()
|
||||
}
|
||||
icon.name: "format-text-bold"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Bold")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: root.documentHandler.bold
|
||||
onClicked: root.documentHandler.bold = checked;
|
||||
checked: root.focusedDocumentHandler.bold
|
||||
onClicked: {
|
||||
root.focusedDocumentHandler.bold = checked;
|
||||
root.clicked()
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -84,11 +102,15 @@ QQC2.ToolBar {
|
||||
onActivated: italicButton.clicked()
|
||||
}
|
||||
icon.name: "format-text-italic"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Italic")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: root.documentHandler.italic
|
||||
onClicked: root.documentHandler.italic = checked;
|
||||
checked: root.focusedDocumentHandler.italic
|
||||
onClicked: {
|
||||
root.focusedDocumentHandler.italic = checked;
|
||||
root.clicked()
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -101,11 +123,15 @@ QQC2.ToolBar {
|
||||
onActivated: underlineButton.clicked()
|
||||
}
|
||||
icon.name: "format-text-underline"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Underline")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: root.documentHandler.underline
|
||||
onClicked: root.documentHandler.underline = checked;
|
||||
checked: root.focusedDocumentHandler.underline
|
||||
onClicked: {
|
||||
root.focusedDocumentHandler.underline = checked;
|
||||
root.clicked();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -113,11 +139,15 @@ QQC2.ToolBar {
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
icon.name: "format-text-strikethrough"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Strikethrough")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: root.documentHandler.strikethrough
|
||||
onClicked: root.documentHandler.strikethrough = checked;
|
||||
checked: root.focusedDocumentHandler.strikethrough
|
||||
onClicked: {
|
||||
root.focusedDocumentHandler.strikethrough = checked;
|
||||
root.clicked()
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -128,6 +158,7 @@ QQC2.ToolBar {
|
||||
id: compressedTextFormatButton
|
||||
visible: root.maxAvailableWidth < root.listCompressedImplicitWidth
|
||||
icon.name: "dialog-text-and-font"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Format Text")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
@@ -144,29 +175,41 @@ QQC2.ToolBar {
|
||||
icon.name: "format-text-bold"
|
||||
text: i18nc("@action:button", "Bold")
|
||||
checkable: true
|
||||
checked: root.documentHandler.bold
|
||||
onTriggered: root.documentHandler.bold = checked;
|
||||
checked: root.focusedDocumentHandler.bold
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.bold = checked;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-text-italic"
|
||||
text: i18nc("@action:button", "Italic")
|
||||
checkable: true
|
||||
checked: root.documentHandler.italic
|
||||
onTriggered: root.documentHandler.italic = checked;
|
||||
checked: root.focusedDocumentHandler.italic
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.italic = checked;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-text-underline"
|
||||
text: i18nc("@action:button", "Underline")
|
||||
checkable: true
|
||||
checked: root.documentHandler.underline
|
||||
onTriggered: root.documentHandler.underline = checked;
|
||||
checked: root.focusedDocumentHandler.underline
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.underline = checked;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-text-strikethrough"
|
||||
text: i18nc("@action:button", "Strikethrough")
|
||||
checkable: true
|
||||
checked: root.documentHandler.strikethrough
|
||||
onTriggered: root.documentHandler.strikethrough = checked;
|
||||
checked: root.focusedDocumentHandler.strikethrough
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.strikethrough = checked;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,12 +226,14 @@ QQC2.ToolBar {
|
||||
visible: root.maxAvailableWidth > root.uncompressedImplicitWidth
|
||||
QQC2.ToolButton {
|
||||
icon.name: "format-list-unordered"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Unordered List")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: root.documentHandler.currentListStyle === 1
|
||||
checked: root.focusedDocumentHandler.currentListStyle === 1
|
||||
onClicked: {
|
||||
root.documentHandler.setListStyle(root.documentHandler.currentListStyle === 1 ? 0 : 1)
|
||||
root.focusedDocumentHandler.setListStyle(root.focusedDocumentHandler.currentListStyle === 1 ? 0 : 1);
|
||||
root.clicked();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
@@ -197,11 +242,15 @@ QQC2.ToolBar {
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
icon.name: "format-list-ordered"
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
text: i18nc("@action:button", "Ordered List")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: root.documentHandler.currentListStyle === 4
|
||||
onClicked: root.documentHandler.setListStyle(root.documentHandler.currentListStyle === 4 ? 0 : 4)
|
||||
checked: root.focusedDocumentHandler.currentListStyle === 4
|
||||
onClicked: {
|
||||
root.focusedDocumentHandler.setListStyle(root.focusedDocumentHandler.currentListStyle === 4 ? 0 : 4);
|
||||
root.clicked();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -213,7 +262,8 @@ QQC2.ToolBar {
|
||||
text: i18nc("@action:button", "Increase List Level")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
onClicked: {
|
||||
root.documentHandler.indentListMore();
|
||||
root.focusedDocumentHandler.indentListMore();
|
||||
root.clicked();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
@@ -226,7 +276,8 @@ QQC2.ToolBar {
|
||||
text: i18nc("@action:button", "Decrease List Level")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
onClicked: {
|
||||
root.documentHandler.indentListLess();
|
||||
root.focusedDocumentHandler.indentListLess();
|
||||
root.clicked();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
@@ -236,6 +287,7 @@ QQC2.ToolBar {
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: compressedListButton
|
||||
enabled: root.contentModel.focusType !== LibNeoChat.MessageComponentType.Code
|
||||
visible: root.maxAvailableWidth < root.uncompressedImplicitWidth
|
||||
icon.name: "format-list-unordered"
|
||||
text: i18nc("@action:button", "List Style")
|
||||
@@ -253,22 +305,34 @@ QQC2.ToolBar {
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-list-unordered"
|
||||
text: i18nc("@action:button", "Unordered List")
|
||||
onTriggered: root.documentHandler.setListStyle(root.documentHandler.currentListStyle === 1 ? 0 : 1);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.setListStyle(root.focusedDocumentHandler.currentListStyle === 1 ? 0 : 1);
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-list-ordered"
|
||||
text: i18nc("@action:button", "Ordered List")
|
||||
onTriggered: root.documentHandler.setListStyle(root.documentHandler.currentListStyle === 4 ? 0 : 4);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.setListStyle(root.focusedDocumentHandler.currentListStyle === 4 ? 0 : 4);
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-indent-more"
|
||||
text: i18nc("@action:button", "Increase List Level")
|
||||
onTriggered: root.documentHandler.indentListMore();
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.indentListMore();
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
icon.name: "format-indent-less"
|
||||
text: i18nc("@action:button", "Decrease List Level")
|
||||
onTriggered: root.documentHandler.indentListLess();
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.indentListLess();
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,31 +357,56 @@ QQC2.ToolBar {
|
||||
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu no heading", "Paragraph")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(0);
|
||||
onTriggered: root.contentModel.insertComponentAtCursor(LibNeoChat.MessageComponentType.Text);
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu heading level 1 (largest)", "Heading 1")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(1);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.style = LibNeoChat.ChatDocumentHandler.Heading1;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu heading level 2", "Heading 2")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(2);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.style = LibNeoChat.ChatDocumentHandler.Heading2;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu heading level 3", "Heading 3")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(3);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.style = LibNeoChat.ChatDocumentHandler.Heading3;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu heading level 4", "Heading 4")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(4);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.style = LibNeoChat.ChatDocumentHandler.Heading4;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu heading level 5", "Heading 5")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(5);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.style = LibNeoChat.ChatDocumentHandler.Heading5;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu heading level 6 (smallest)", "Heading 6")
|
||||
onTriggered: root.documentHandler.setHeadingLevel(6);
|
||||
onTriggered: {
|
||||
root.focusedDocumentHandler.style = LibNeoChat.ChatDocumentHandler.Heading6;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@item:inmenu", "Quote")
|
||||
onTriggered: {
|
||||
root.contentModel.insertComponentAtCursor(LibNeoChat.MessageComponentType.Quote);
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,6 +414,20 @@ QQC2.ToolBar {
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: codeButton
|
||||
icon.name: "format-text-code"
|
||||
text: i18n("Code")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
onClicked: {
|
||||
root.contentModel.insertComponentAtCursor(LibNeoChat.MessageComponentType.Code);
|
||||
root.clicked();
|
||||
}
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
}
|
||||
Kirigami.Separator {
|
||||
Layout.fillHeight: true
|
||||
Layout.margins: 0
|
||||
@@ -354,10 +457,13 @@ QQC2.ToolBar {
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
onClicked: {
|
||||
let dialog = linkDialog.createObject(QQC2.Overlay.overlay, {
|
||||
linkText: root.documentHandler.currentLinkText(),
|
||||
linkUrl: root.documentHandler.currentLinkUrl()
|
||||
linkText: root.focusedDocumentHandler.currentLinkText(),
|
||||
linkUrl: root.focusedDocumentHandler.currentLinkUrl()
|
||||
})
|
||||
dialog.onAccepted.connect(() => { documentHandler.updateLink(dialog.linkUrl, dialog.linkText) });
|
||||
dialog.onAccepted.connect(() => {
|
||||
root.focusedDocumentHandler.updateLink(dialog.linkUrl, dialog.linkText)
|
||||
root.clicked();
|
||||
});
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
@@ -384,7 +490,7 @@ QQC2.ToolBar {
|
||||
|
||||
onClicked: {
|
||||
let dialog = (LibNeoChat.Clipboard.hasImage ? attachDialog : openFileDialog).createObject(QQC2.Overlay.overlay);
|
||||
dialog.chosen.connect(path => root.chatBarCache.attachmentPath = path);
|
||||
dialog.chosen.connect(path => root.contentModel.addAttachment(path));
|
||||
dialog.open();
|
||||
}
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -482,9 +588,8 @@ QQC2.ToolBar {
|
||||
icon.name: "document-send"
|
||||
text: i18n("Send message")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
|
||||
onClicked: root.requestPostMessage()
|
||||
onClicked: root.contentModel.postMessage();
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
@@ -543,7 +648,7 @@ QQC2.ToolBar {
|
||||
currentRoom: root.room
|
||||
|
||||
onChosen: emoji => {
|
||||
root.documentHandler.insertText(emoji);
|
||||
root.focusedDocumentHandler.insertText(emoji);
|
||||
close();
|
||||
}
|
||||
onClosed: if (emojiButton.checked) {
|
||||
|
||||
Reference in New Issue
Block a user