diff --git a/imports/NeoChat/Component/ChatBox/AttachmentPane.qml b/imports/NeoChat/Component/ChatBox/AttachmentPane.qml
index f07aba717..372cd598a 100644
--- a/imports/NeoChat/Component/ChatBox/AttachmentPane.qml
+++ b/imports/NeoChat/Component/ChatBox/AttachmentPane.qml
@@ -14,17 +14,14 @@ import org.kde.neochat 1.0
Loader {
id: root
- property string attachmentPath: ""
- property var attachmentMimetype: FileType.mimeTypeForUrl(attachmentPath)
+ property var attachmentMimetype: FileType.mimeTypeForUrl(ChatBoxHelper.attachmentPath)
readonly property bool hasImage: attachmentMimetype.valid && FileType.supportedImageFormats.includes(attachmentMimetype.preferredSuffix)
- signal clearAttachmentTriggered()
-
active: visible
sourceComponent: Component {
Pane {
id: attachmentPane
- property string baseFileName: attachmentPath.toString().substring(attachmentPath.toString().lastIndexOf('/') + 1, attachmentPath.length)
+ property string baseFileName: ChatBoxHelper.attachmentPath.toString().substring(ChatBoxHelper.attachmentPath.toString().lastIndexOf('/') + 1, ChatBoxHelper.attachmentPath.length)
Kirigami.Theme.colorSet: Kirigami.Theme.View
contentItem: Item {
@@ -49,7 +46,7 @@ Loader {
asynchronous: true
cache: false // Cache is not needed. Images will rarely be shown repeatedly.
smooth: height == preferredHeight && parent.height == parent.implicitHeight // Don't smooth until height animation stops
- source: hasImage ? attachmentPath : ""
+ source: hasImage ? ChatBoxHelper.attachmentPath : ""
visible: hasImage
fillMode: Image.PreserveAspectFit
@@ -165,14 +162,14 @@ Loader {
Component {
id: imageEditorPage
ImageEditorPage {
- imagePath: attachmentPath
+ imagePath: ChatBoxHelper.attachmentPath
}
}
onClicked: {
let imageEditor = applicationWindow().pageStack.layers.push(imageEditorPage);
imageEditor.newPathChanged.connect(function(newPath) {
applicationWindow().pageStack.layers.pop();
- attachmentPath = newPath;
+ ChatBoxHelper.attachmentPath = newPath;
});
}
ToolTip.text: text
@@ -183,9 +180,7 @@ Loader {
icon.name: "dialog-cancel"
text: i18n("Cancel")
display: AbstractButton.IconOnly
- onClicked: {
- clearAttachmentTriggered();
- }
+ onClicked: ChatBoxHelper.clearAttachment();
ToolTip.text: text
ToolTip.visible: hovered
}
diff --git a/imports/NeoChat/Component/ChatBox/ChatBar.qml b/imports/NeoChat/Component/ChatBox/ChatBar.qml
index 01068eb4b..916fc4317 100644
--- a/imports/NeoChat/Component/ChatBox/ChatBar.qml
+++ b/imports/NeoChat/Component/ChatBox/ChatBar.qml
@@ -15,7 +15,7 @@ ToolBar {
id: chatBar
property string replyEventId: ""
property string editEventId: ""
- property string inputFieldText: currentRoom ? currentRoom.cachedInput : ""
+ property alias inputFieldText: inputField.text
property alias textField: inputField
property alias emojiPaneOpened: emojiButton.checked
@@ -24,7 +24,6 @@ ToolBar {
// This use an hack to define: https://doc.qt.io/qt-5/qml-var.html#property-value-initialization-semantics
property var userAutocompleted: ({})
- signal attachTriggered(string localPath)
signal closeAllTriggered()
signal inputFieldForceActiveFocusTriggered()
signal messageSent()
@@ -220,14 +219,14 @@ ToolBar {
}
Item {
- visible: !isReply && (!hasAttachment || uploadingBusySpinner.running)
+ visible: !ChatBoxHelper.isReplying && (!ChatBoxHelper.hasAttachment || uploadingBusySpinner.running)
implicitWidth: uploadButton.implicitWidth
implicitHeight: uploadButton.implicitHeight
ToolButton {
id: uploadButton
anchors.fill: parent
// Matrix does not allow sending attachments in replies
- visible: !isReply && !hasAttachment && !uploadingBusySpinner.running
+ visible: !ChatBoxHelper.isReplying && !ChatBoxHelper.hasAttachment && !uploadingBusySpinner.running
icon.name: "mail-attachment"
text: i18n("Attach an image or file")
display: AbstractButton.IconOnly
@@ -239,7 +238,7 @@ ToolBar {
var fileDialog = openFileDialog.createObject(ApplicationWindow.overlay)
fileDialog.chosen.connect((path) => {
if (!path) { return }
- attachTriggered(path)
+ ChatBoxHelper.attachmentPath = path;
})
fileDialog.open()
}
@@ -318,13 +317,21 @@ ToolBar {
if (!Clipboard.saveImage(localPath)) {
return;
}
- attachTriggered(localPath)
+ ChatBoxHelper.attachmentPath = localPath;
}
function postMessage() {
checkForFancyEffectsReason();
- roomManager.actionsHandler.postMessage(inputField.text.trim(), attachmentPath,
- replyEventId, editEventId, userAutocompleted);
+ if (ChatBoxHelper.hasAttachment) {
+ // send attachment but don't reset the text
+ roomManager.actionsHandler.postMessage("", ChatBoxHelper.attachmentPath,
+ ChatBoxHelper.replyEventId, ChatBoxHelper.editEventId, {});
+ currentRoom.markAllMessagesAsRead();
+ messageSent();
+ return;
+ }
+ roomManager.actionsHandler.postMessage(inputField.text.trim(), ChatBoxHelper.attachmentPath,
+ ChatBoxHelper.replyEventId, ChatBoxHelper.editEventId, userAutocompleted);
currentRoom.markAllMessagesAsRead();
inputField.clear();
inputField.text = Qt.binding(function() {
diff --git a/imports/NeoChat/Component/ChatBox/ChatBox.qml b/imports/NeoChat/Component/ChatBox/ChatBox.qml
index aa408d467..0d42036c4 100644
--- a/imports/NeoChat/Component/ChatBox/ChatBox.qml
+++ b/imports/NeoChat/Component/ChatBox/ChatBox.qml
@@ -13,19 +13,8 @@ import org.kde.neochat 1.0
Item {
id: root
- readonly property bool isReply: replyEventId.length > 0
- property var replyUser
- property alias replyEventId: chatBar.replyEventId
- property string replyContent: ""
-
- readonly property bool hasAttachment: attachmentPath.length > 0
- property string attachmentPath: ""
-
property alias inputFieldText: chatBar.inputFieldText
- readonly property bool isEdit: editEventId.length > 0
- property alias editEventId: chatBar.editEventId
-
signal fancyEffectsReasonFound(string fancyEffect)
Kirigami.Theme.colorSet: Kirigami.Theme.View
@@ -76,6 +65,7 @@ Item {
sourceComponent: EmojiPicker{
textArea: chatBar.textField
emojiModel: EmojiModel { id: emojiModel }
+ onChosen: addText(emoji)
}
Behavior on height {
NumberAnimation {
@@ -97,10 +87,8 @@ Item {
ReplyPane {
id: replyPane
- visible: isReply || isEdit
- isEdit: root.isEdit
- user: root.replyUser
- content: root.replyContent
+ visible: ChatBoxHelper.isReplying || ChatBoxHelper.isEditing
+ user: ChatBoxHelper.replyUser
width: parent.width
height: visible ? implicitHeight : 0
anchors.bottom: attachmentSeparator.top
@@ -123,8 +111,7 @@ Item {
AttachmentPane {
id: attachmentPane
- attachmentPath: root.attachmentPath
- visible: hasAttachment
+ visible: ChatBoxHelper.hasAttachment
width: parent.width
height: visible ? implicitHeight : 0
anchors.bottom: chatBarSeparator.top
@@ -159,36 +146,9 @@ Item {
easing.type: Easing.OutCubic
}
}
- }
- Connections {
- target: replyPane
- function onClearEditReplyTriggered() {
- if (isEdit) {
- clearEdit()
- }
- if (isReply) {
- clearReply()
- }
- }
- }
-
- Connections {
- target: attachmentPane
- function onClearAttachmentTriggered() {
- clearAttachment()
- }
- }
-
- Connections {
- target: chatBar
- function onAttachTriggered(localPath) {
- attach(localPath)
- }
- function onCloseAllTriggered() {
- closeAll()
- }
- function onMessageSent() {
+ onCloseAllTriggered: closeAll()
+ onMessageSent: {
closeAll()
checkForFancyEffectsReason()
}
@@ -225,70 +185,41 @@ Item {
root.inputFieldText = inputFieldText.substr(0, inputField.cursorPosition) + str + inputFieldText.substr(inputField.cursorPosition)
}
- function clearText() {
- // ChatBar's TextArea syncs currentRoom.cachedInput with the TextArea's text property
- root.inputFieldText = ""
- }
-
function focusInputField() {
chatBar.inputFieldForceActiveFocusTriggered()
}
- function edit(editContent, editFormatedContent, editEventId) {
- // Set the input field in edit mode
- root.inputFieldText = editContent;
- root.editEventId = editEventId;
- root.replyContent = editContent;
+ Connections {
+ target: ChatBoxHelper
- // clean autocompletion list
- chatBar.userAutocompleted = {};
-
- // Fill autocompletion list with values extracted from message.
- // We can't just iterate on every user in the list and try to
- // find matching display name since some users have display name
- // matching frequent words and this will marks too many words as
- // mentions.
- const regex = /([^<]*)<\/a>/g;
-
- let match;
- while ((match = regex.exec(editFormatedContent.toString())) !== null) {
- chatBar.userAutocompleted[match[2]] = match[1];
+ function onShouldClearText() {
+ root.inputFieldText = "";
}
- }
- function clearEdit() {
- // Clear input when edits are cancelled.
- // Cached input will be
- clearText()
- clearReply()
- root.editEventId = "";
- }
+ function onEditing(editContent, editFormatedContent) {
+ // Set the input field in edit mode
+ root.inputFieldText = editContent;
+ //root.replyContent = editContent;
- function attach(localPath) {
- root.attachmentPath = localPath
- }
+ // clean autocompletion list
+ chatBar.userAutocompleted = {};
- function clearAttachment() {
- root.attachmentPath = ""
- }
+ // Fill autocompletion list with values extracted from message.
+ // We can't just iterate on every user in the list and try to
+ // find matching display name since some users have display name
+ // matching frequent words and this will marks too many words as
+ // mentions.
+ const regex = /([^<]*)<\/a>/g;
- function clearReply() {
- replyUser = null;
- root.replyContent = "";
- root.replyEventId = "";
- // Don't clear input when replies are cancelled
+ let match;
+ while ((match = regex.exec(editFormatedContent.toString())) !== null) {
+ chatBar.userAutocompleted[match[2]] = match[1];
+ }
+ }
}
function closeAll() {
- if (hasAttachment) {
- clearAttachment();
- }
- if (isEdit) {
- clearEdit();
- }
- if (isReply) {
- clearReply();
- }
+ ChatBoxHelper.clear();
chatBar.emojiPaneOpened = false;
}
}
diff --git a/imports/NeoChat/Component/ChatBox/ReplyPane.qml b/imports/NeoChat/Component/ChatBox/ReplyPane.qml
index 21074dd60..b86a49a93 100644
--- a/imports/NeoChat/Component/ChatBox/ReplyPane.qml
+++ b/imports/NeoChat/Component/ChatBox/ReplyPane.qml
@@ -7,15 +7,13 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.14 as Kirigami
+import org.kde.neochat 1.0
Loader {
id: root
- property bool isEdit: false
+ readonly property bool isEdit: ChatBoxHelper.isEditing
property var user: null
- property string content: ""
- property string avatarMediaUrl: user ? "image://mxc/" + replyUser.avatarMediaId : ""
-
- signal clearEditReplyTriggered()
+ property string avatarMediaUrl: user ? "image://mxc/" + user.avatarMediaId : ""
active: visible
sourceComponent: Pane {
@@ -78,9 +76,9 @@ Loader {
topPadding: 0
bottomPadding: 0
text: {
- let stylesheet = ""
- let userName = user ? "" + user.displayName + "" : ""
- return stylesheet + content
+ const stylesheet = "";
+ const content = ChatBoxHelper.isReplying ? ChatBoxHelper.replyEventContent : ChatBoxHelper.editContent;
+ return stylesheet + content;
}
selectByMouse: true
selectByKeyboard: true
@@ -101,9 +99,7 @@ Loader {
icon.name: "dialog-cancel"
text: i18n("Cancel")
display: AbstractButton.IconOnly
- onClicked: {
- clearEditReplyTriggered()
- }
+ onClicked: ChatBoxHelper.clearEditReply()
ToolTip.text: text
ToolTip.visible: hovered
}
diff --git a/imports/NeoChat/Component/Timeline/TextDelegate.qml b/imports/NeoChat/Component/Timeline/TextDelegate.qml
index d6445966e..9c79348b0 100644
--- a/imports/NeoChat/Component/Timeline/TextDelegate.qml
+++ b/imports/NeoChat/Component/Timeline/TextDelegate.qml
@@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: GPL-3.0-only
*/
-import QtQuick 2.12
+import QtQuick 2.15
import QtQuick.Controls 2.12 as QQC2
import QtQuick.Layouts 1.12
diff --git a/imports/NeoChat/Component/Timeline/TimelineContainer.qml b/imports/NeoChat/Component/Timeline/TimelineContainer.qml
index 36c6a4dae..a77bf59b4 100644
--- a/imports/NeoChat/Component/Timeline/TimelineContainer.qml
+++ b/imports/NeoChat/Component/Timeline/TimelineContainer.qml
@@ -33,8 +33,6 @@ Item {
signal saveFileAs()
signal openExternally()
signal replyClicked(string eventID)
- signal replyToMessageClicked(var replyUser, string replyContent, string eventID)
- signal edit(string message, string formattedBody, string eventId)
property alias hovered: controlContainer.hovered
@@ -49,7 +47,7 @@ Item {
updateHoverComponent();
}
}
-
+
// updates the global hover component to point to this delegate, and update its position
function updateHoverComponent() {
hoverComponent.x = column.mapToItem(page, hoverComponentX, hoverComponentY).x;
@@ -57,14 +55,14 @@ Item {
hoverComponent.hovered = Qt.binding(() => controlContainer.hovered);
hoverComponent.showEdit = author.id === Controller.activeConnection.localUserId && (model.eventType === "emote" || model.eventType === "message");
hoverComponent.updateFunction = updateHoverComponent;
-
+
hoverComponent.editClicked = () => {
if (hoverComponent.showEdit) {
- edit(message, model.formattedBody, eventId);
- }
+ ChatBoxHelper.edit(message, formattedBody, eventId)
+ }
};
hoverComponent.replyClicked = () => {
- replyToMessage(author, message, eventId);
+ ChatBoxHelper.replyToMessage(eventId, message, author);
};
hoverComponent.reacted = emoji => {
currentRoom.toggleReaction(eventId, emoji);
@@ -85,6 +83,7 @@ Item {
parent.x = 0;
}
}
+
onXChanged: if (x !== 0) {
applicationWindow().pageStack.interactive = false;
} else {
@@ -146,7 +145,7 @@ Item {
}
// bubble
- QQC2.Control {
+ QQC2.ItemDelegate {
id: controlContainer
Layout.maximumWidth: mainColumn.width - Kirigami.Units.gridUnit * 2 - Kirigami.Units.largeSpacing * 2
implicitHeight: contentItem.implicitHeight
diff --git a/imports/NeoChat/Page/RoomPage.qml b/imports/NeoChat/Page/RoomPage.qml
index ab5df0cbf..2e69284b7 100644
--- a/imports/NeoChat/Page/RoomPage.qml
+++ b/imports/NeoChat/Page/RoomPage.qml
@@ -255,7 +255,7 @@ Kirigami.ScrollablePage {
fileDialog.chosen.connect(function(path) {
if (!path) return
- chatBox.attach(path)
+ ChatBoxHelper.attachmentPath = path;
})
fileDialog.open()
@@ -273,10 +273,12 @@ Kirigami.ScrollablePage {
icon.name: 'insert-image'
text: i18n("Clipboard image")
onClicked: {
- var localPath = Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/screenshots/" + (new Date()).getTime() + ".png"
- if (!Clipboard.saveImage(localPath)) return
- chatBox.attach(localPath)
- attachDialog.close()
+ const localPath = Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/screenshots/" + (new Date()).getTime() + ".png"
+ if (!Clipboard.saveImage(localPath)) {
+ return;
+ }
+ ChatBoxHelper.attachmentPath = localPath;
+ attachDialog.close();
}
}
}
@@ -356,8 +358,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
isEmote: true
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
- onEdit: chatBox.edit(message, formattedBody, eventId)
hoverComponent: hoverActions
@@ -386,8 +386,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
- onEdit: chatBox.edit(message, formattedBody, eventId)
hoverComponent: hoverActions
@@ -413,8 +411,6 @@ Kirigami.ScrollablePage {
width: messageListView.width - Kirigami.Units.largeSpacing
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
- onEdit: chatBox.edit(message, formattedBody, eventId)
hoverComponent: hoverActions
innerObject: TextDelegate {
@@ -432,7 +428,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
hoverComponent: hoverActions
@@ -453,7 +448,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
hoverComponent: hoverActions
cardBackground: false
@@ -476,7 +470,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
innerObject: AudioDelegate {
Layout.fillWidth: true
@@ -501,7 +494,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
innerObject: VideoDelegate {
Layout.fillWidth: true
@@ -532,7 +524,6 @@ Kirigami.ScrollablePage {
isLoaded: timelineDelegateChooser.delegateLoaded
onReplyClicked: goToEvent(eventID)
- onReplyToMessageClicked: replyToMessage(replyUser, replyContent, eventId);
innerObject: FileDelegate {
Layout.fillWidth: true
@@ -613,7 +604,7 @@ Kirigami.ScrollablePage {
DropArea {
id: dropAreaFile
anchors.fill: parent
- onDropped: chatBox.attach(drop.urls[0])
+ onDropped: ChatBoxHelper.attachmentPath = drop.urls[0]
}
QQC2.Pane {
@@ -767,7 +758,7 @@ Kirigami.ScrollablePage {
}).open();
});
contextMenu.reply.connect(function(replyUser, replyContent) {
- replyToMessage(replyUser, replyContent, eventId);
+ ChatBoxHelper.replyToMessage(eventId, replyContent, replyUser);
})
contextMenu.remove.connect(function() {
currentRoom.redactEvent(eventId);
@@ -788,19 +779,11 @@ Kirigami.ScrollablePage {
}).open();
});
contextMenu.reply.connect(function(replyUser, replyContent) {
- replyToMessage(replyUser, replyContent, eventId);
+ ChatBoxHelper.replyToMessage(eventId, replyContent, replyUser);
})
contextMenu.remove.connect(function() {
currentRoom.redactEvent(eventId);
})
contextMenu.open();
}
-
- function replyToMessage(replyUser, replyContent, eventId) {
- chatBox.editEventId = "";
- chatBox.replyUser = replyUser;
- chatBox.replyEventId = eventId;
- chatBox.replyContent = replyContent;
- chatBox.focusInputField();
- }
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 15ade8edc..3ca23148b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ add_executable(neochat
filetypesingleton.cpp
login.cpp
stickerevent.cpp
+ chatboxhelper.cpp
../res.qrc
)
diff --git a/src/chatboxhelper.cpp b/src/chatboxhelper.cpp
new file mode 100644
index 000000000..2452ae0d7
--- /dev/null
+++ b/src/chatboxhelper.cpp
@@ -0,0 +1,162 @@
+// SPDX-FileCopyrightText: 2020 Carl Schwan
+// SPDX-License-Identifier: GPl-3.0-or-later
+
+#include "chatboxhelper.h"
+#include
+
+ChatBoxHelper::ChatBoxHelper(QObject *parent)
+ : QObject(parent)
+{
+}
+
+bool ChatBoxHelper::isEditing() const
+{
+ return !m_editEventId.isEmpty();
+}
+
+QString ChatBoxHelper::editEventId() const
+{
+ return m_editEventId;
+}
+
+void ChatBoxHelper::setEditEventId(const QString& editEventId)
+{
+ if (m_editEventId == editEventId) {
+ return;
+ }
+
+ m_editEventId = editEventId;
+ Q_EMIT editEventIdChanged(m_editEventId);
+ Q_EMIT isEditingChanged(!m_editEventId.isEmpty());
+}
+
+QString ChatBoxHelper::editContent() const
+{
+ return m_editContent;
+}
+
+void ChatBoxHelper::setEditContent(const QString& editContent)
+{
+ if (m_editContent == editContent) {
+ return;
+ }
+
+ m_editContent = editContent;
+ Q_EMIT editContentChanged();
+}
+
+QString ChatBoxHelper::replyEventId() const
+{
+ return m_replyEventId;
+}
+
+void ChatBoxHelper::setReplyEventId(const QString& replyEventId)
+{
+ if (m_replyEventId == replyEventId) {
+ return;
+ }
+
+ m_replyEventId = replyEventId;
+ Q_EMIT replyEventIdChanged(m_replyEventId);
+}
+
+QString ChatBoxHelper::replyEventContent() const
+{
+ return m_replyEventContent;
+}
+
+void ChatBoxHelper::setReplyEventContent(const QString& replyEventContent)
+{
+ if (m_replyEventContent == replyEventContent) {
+ return;
+ }
+
+ m_replyEventContent = replyEventContent;
+ Q_EMIT replyEventContentChanged(m_replyEventContent);
+ Q_EMIT isReplyingChanged(!m_replyEventContent.isEmpty());
+}
+
+bool ChatBoxHelper::isReplying() const
+{
+ return !m_replyEventId.isEmpty();
+}
+
+QString ChatBoxHelper::attachmentPath() const
+{
+ return m_attachmentPath;
+}
+
+void ChatBoxHelper::setAttachmentPath(const QString& attachmentPath)
+{
+ if (m_attachmentPath == attachmentPath) {
+ return;
+ }
+
+ m_attachmentPath = attachmentPath;
+ Q_EMIT attachmentPathChanged(m_attachmentPath);
+ Q_EMIT hasAttachmentChanged(!m_attachmentPath.isEmpty());
+}
+
+bool ChatBoxHelper::hasAttachment() const
+{
+ return !m_attachmentPath.isEmpty();
+}
+
+void ChatBoxHelper::replyToMessage(const QString &replyEventId, const QString &replyEvent, const QVariant &replyUser)
+{
+ setEditEventId(QString());
+ setEditContent(QString());
+ setReplyEventId(replyEventId);
+ setReplyEventContent(replyEvent);
+ setReplyUser(replyUser);
+}
+
+QVariant ChatBoxHelper::replyUser() const
+{
+ return m_replyUser;
+}
+
+void ChatBoxHelper::setReplyUser(const QVariant &replyUser)
+{
+ if (m_replyUser == replyUser) {
+ return;
+ }
+ m_replyUser = replyUser;
+ Q_EMIT replyUserChanged();
+}
+
+void ChatBoxHelper::clear()
+{
+ setEditEventId(QString());
+ setEditContent(QString());
+ setReplyEventId(QString());
+ setReplyEventContent(QString());
+ setAttachmentPath(QString());
+ setReplyUser(QVariant());
+}
+
+void ChatBoxHelper::edit(const QString& message, const QString& formattedBody, const QString& eventId)
+{
+ setEditEventId(eventId);
+ setEditContent(message);
+ Q_EMIT editing(message, formattedBody);
+}
+
+void ChatBoxHelper::clearEditReply()
+{
+ setEditEventId(QString());
+ setEditContent(QString());
+ setReplyEventId(QString());
+ setReplyEventContent(QString());
+ setReplyUser(QVariant());
+ Q_EMIT shouldClearText();
+}
+
+void ChatBoxHelper::clearAttachment()
+{
+ setAttachmentPath(QString());
+}
+
+
+
+
diff --git a/src/chatboxhelper.h b/src/chatboxhelper.h
new file mode 100644
index 000000000..55fc44600
--- /dev/null
+++ b/src/chatboxhelper.h
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: 2020 Carl Schwan
+// SPDX-License-Identifier: GPl-3.0-or-later
+
+#pragma once
+
+#include
+#include
+
+/// Helper singleton for keeping the chatbar state in sync in the application.
+class ChatBoxHelper : public QObject
+{
+ Q_OBJECT
+ /// True, iff the user is currently editing one of their previous message.
+ Q_PROPERTY(bool isEditing READ isEditing NOTIFY isEditingChanged)
+ Q_PROPERTY(QString editEventId READ editEventId WRITE setEditEventId NOTIFY editEventIdChanged)
+ Q_PROPERTY(QString editContent READ editContent WRITE setEditContent NOTIFY editContentChanged)
+
+ Q_PROPERTY(bool isReplying READ isReplying NOTIFY isReplyingChanged)
+ Q_PROPERTY(QString replyEventId READ replyEventId WRITE setReplyEventId NOTIFY replyEventIdChanged)
+ Q_PROPERTY(QString replyEventContent READ replyEventContent WRITE setReplyEventContent NOTIFY replyEventContentChanged)
+ Q_PROPERTY(QVariant replyUser READ replyUser WRITE setReplyUser NOTIFY replyUserChanged)
+
+ Q_PROPERTY(QString attachmentPath READ attachmentPath WRITE setAttachmentPath NOTIFY attachmentPathChanged)
+ Q_PROPERTY(bool hasAttachment READ hasAttachment NOTIFY hasAttachmentChanged)
+
+public:
+ ChatBoxHelper(QObject *parent = nullptr);
+ ~ChatBoxHelper() = default;
+
+ bool isEditing() const;
+ QString editEventId() const;
+ QString editContent() const;
+
+ QString replyEventId() const;
+ QString replyEventContent() const;
+ QVariant replyUser() const;
+ bool isReplying() const;
+
+ QString attachmentPath() const;
+ bool hasAttachment() const;
+
+ void setEditEventId(const QString& editEventId);
+ void setEditContent(const QString& editContent);
+ void setReplyEventId(const QString& replyEventId);
+ void setReplyEventContent(const QString& replyEventContent);
+ void setAttachmentPath(const QString& attachmentPath);
+ void setReplyUser(const QVariant &replyUser);
+
+ Q_INVOKABLE void replyToMessage(const QString &replyEventid, const QString &replyEvent, const QVariant &replyUser);
+ Q_INVOKABLE void edit(const QString &message, const QString &formattedBody, const QString &eventId);
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void clearEditReply();
+ Q_INVOKABLE void clearAttachment();
+
+Q_SIGNALS:
+ void isEditingChanged(bool isEditing);
+ void editEventIdChanged(const QString& editEventId);
+ void editContentChanged();
+ void replyEventIdChanged(const QString& replyEventId);
+ void replyEventContentChanged(const QString& replyEventContent);
+ void replyUserChanged();
+ void isReplyingChanged(bool isReplying);
+ void attachmentPathChanged(const QString& attachmentPath);
+ void hasAttachmentChanged(bool hasAttachment);
+ void editing(const QString &message, const QString &formattedBody);
+ void shouldClearText();
+
+private:
+ QString m_editEventId;
+ QString m_editContent;
+ QString m_replyEventId;
+ QString m_replyEventContent;
+ QVariant m_replyUser;
+ QString m_attachmentPath;
+};
diff --git a/src/main.cpp b/src/main.cpp
index e84c0a89c..bf8fb9a96 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -47,6 +47,7 @@
#include "userdirectorylistmodel.h"
#include "userlistmodel.h"
#include "actionshandler.h"
+#include "chatboxhelper.h"
using namespace Quotient;
@@ -108,12 +109,14 @@ int main(int argc, char *argv[])
FileTypeSingleton fileTypeSingleton;
Login *login = new Login();
+ ChatBoxHelper chatBoxHelper;
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Controller", &Controller::instance());
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Clipboard", &clipboard);
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Config", config);
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton);
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "LoginHelper", login);
+ qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "ChatBoxHelper", &chatBoxHelper);
qmlRegisterType("org.kde.neochat", 1, 0, "AccountListModel");
qmlRegisterType("org.kde.neochat", 1, 0, "ActionsHandler");
qmlRegisterType("org.kde.neochat", 1, 0, "ChatDocumentHandler");