Hook sending messages back up

This commit is contained in:
James Graham
2026-02-21 12:12:11 +00:00
parent d2d48110cb
commit c6313d2951
10 changed files with 94 additions and 98 deletions

View File

@@ -7,7 +7,9 @@
#include <QVariantList>
#include "accountmanager.h"
#include "blockcache.h"
#include "chatbarcache.h"
#include "enums/messagecomponenttype.h"
#include "models/actionsmodel.h"
#include "server.h"
@@ -89,8 +91,9 @@ void ActionsTest::testActions()
QFETCH(std::optional<Quotient::RoomMessageEvent::MsgType>, type);
auto cache = new ChatBarCache(this);
cache->setText(command);
cache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(command)};
auto result = ActionsModel::handleAction(room, cache);
qWarning() << result << resultText;
QCOMPARE(resultText, std::get<std::optional<QString>>(result));
QCOMPARE(type, std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result));
}

View File

@@ -14,6 +14,7 @@
#include <KLocalizedString>
#include "accountmanager.h"
#include "blockcache.h"
#include "chatbarcache.h"
#include "neochatroom.h"
@@ -77,7 +78,7 @@ void ChatBarCacheTest::empty()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
QCOMPARE(chatBarCache->text(), QString());
QCOMPARE(chatBarCache->cache().toString(), QString());
QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false);
@@ -123,11 +124,11 @@ void ChatBarCacheTest::badParent()
void ChatBarCacheTest::reply()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
chatBarCache->setAttachmentPath(u"some/path"_s);
chatBarCache->setReplyId(eventId);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), eventId);
QCOMPARE(chatBarCache->isEditing(), false);
@@ -141,11 +142,11 @@ void ChatBarCacheTest::reply()
void ChatBarCacheTest::replyMissingUser()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
chatBarCache->setAttachmentPath(u"some/path"_s);
chatBarCache->setReplyId(eventId);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), eventId);
QCOMPARE(chatBarCache->isEditing(), false);
@@ -172,7 +173,7 @@ void ChatBarCacheTest::edit()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
chatBarCache->setAttachmentPath(u"some/path"_s);
connect(chatBarCache.get(), &ChatBarCache::relationIdChanged, this, [this](const QString &oldEventId, const QString &newEventId) {
QCOMPARE(oldEventId, QString());
@@ -180,7 +181,7 @@ void ChatBarCacheTest::edit()
});
chatBarCache->setEditId(eventId);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), true);
@@ -193,11 +194,11 @@ void ChatBarCacheTest::edit()
void ChatBarCacheTest::attachment()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
chatBarCache->setEditId(eventId);
chatBarCache->setAttachmentPath(u"some/path"_s);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false);

View File

@@ -3,10 +3,65 @@
#include "blockcache.h"
#include <QRegularExpression>
#include "chattextitemhelper.h"
using namespace Block;
inline QString formatQuote(const QString &input)
{
QString stringOut;
auto splitString = input.split(u"\n\n"_s, Qt::SkipEmptyParts);
for (auto &string : splitString) {
if (string.startsWith(u'*')) {
string.removeFirst();
}
if (string.startsWith(u'\"')) {
string.removeFirst();
}
if (string.endsWith(u'*')) {
string.removeLast();
}
if (string.endsWith(u'\"')) {
string.removeLast();
}
if (!stringOut.isEmpty()) {
stringOut += u"\n"_s;
}
stringOut += u"> "_s + string;
}
return stringOut;
}
inline QString formatCode(const QString &input)
{
return u"```\n%1\n```"_s.arg(input).replace(u"\n\n"_s, u"\n"_s);
}
inline QString trim(QString string)
{
while (string.startsWith(u"\n"_s)) {
string.removeFirst();
}
while (string.endsWith(u"\n"_s)) {
string.removeLast();
}
return string;
}
QString CacheItem::toString() const
{
auto newText = trim(content.toMarkdown(QTextDocument::MarkdownDialectGitHub));
newText.replace(QRegularExpression(u"(?<!\n)\n(?!\n)"_s), u" "_s);
if (type == MessageComponentType::Quote) {
newText = formatQuote(newText);
} else if (type == MessageComponentType::Code) {
newText = formatCode(newText);
}
return newText;
}
void Cache::fill(QList<MessageComponent> components)
{
std::ranges::for_each(components, [this](const MessageComponent &component) {
@@ -23,3 +78,15 @@ void Cache::fill(QList<MessageComponent> components)
});
});
}
QString Cache::toString() const
{
QString text;
std::ranges::for_each(constBegin(), constEnd(), [&text](const CacheItem &item) {
if (!text.isEmpty()) {
text += u"\n\n"_s;
}
text += item.toString();
});
return text;
}

View File

@@ -14,6 +14,8 @@ namespace Block
struct CacheItem {
MessageComponentType::Type type = MessageComponentType::Other;
QTextDocumentFragment content;
QString toString() const;
};
class Cache : private QList<CacheItem>
@@ -22,7 +24,10 @@ public:
using QList<CacheItem>::constBegin, QList<CacheItem>::constEnd;
using QList<CacheItem>::isEmpty;
using QList<CacheItem>::clear;
using QList<CacheItem>::append, QList<CacheItem>::operator+=, QList<CacheItem>::operator<<;
void fill(QList<MessageComponent> components);
QString toString() const;
};
}

View File

@@ -38,29 +38,16 @@ Block::Cache &ChatBarCache::cache()
return m_cache;
}
QString ChatBarCache::text() const
{
return m_text;
}
void ChatBarCache::setText(const QString &text)
{
if (text == m_text) {
return;
}
m_text = text;
Q_EMIT textChanged();
}
QString ChatBarCache::sendText() const
{
const auto cacheText = m_cache.toString();
if (!attachmentPath().isEmpty()) {
QUrl url(attachmentPath());
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
return text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : text();
return cacheText.isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : cacheText;
}
return text();
return cacheText;
}
bool ChatBarCache::isReplying() const
@@ -267,13 +254,16 @@ void ChatBarCache::postMessage()
auto content = std::make_unique<Quotient::EventContent::TextContent>(sendText, u"text/html"_s);
room->post<Quotient::RoomMessageEvent>(text(), *std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result), std::move(content), relatesTo);
room->post<Quotient::RoomMessageEvent>(m_cache.toString(),
*std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result),
std::move(content),
relatesTo);
clearCache();
}
void ChatBarCache::clearCache()
{
setText({});
m_cache.clear();
m_savedText = QString();
clearRelations();
}

View File

@@ -39,14 +39,6 @@ class ChatBarCache : public QObject
QML_ELEMENT
QML_UNCREATABLE("")
/**
* @brief The text in the chat bar.
*
* Due to problems with QTextDocument, unlike the other properties here,
* text is *not* used to store the text when switching rooms.
*/
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
/**
* @brief Whether the chat bar is currently replying to a message.
*/
@@ -139,10 +131,7 @@ public:
explicit ChatBarCache(QObject *parent = nullptr);
Block::Cache &cache();
QString text() const;
QString sendText() const;
void setText(const QString &text);
bool isReplying() const;
QString replyId() const;
@@ -189,7 +178,6 @@ public:
Q_INVOKABLE void drop(QList<QUrl> urls, const QString &transferPortal);
Q_SIGNALS:
void textChanged();
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
void attachmentPathChanged();
@@ -199,8 +187,6 @@ Q_SIGNALS:
private:
Block::Cache m_cache;
QString m_text = QString();
QString m_relationId = QString();
RelationType m_relationType = RelationType::None;
QString m_threadId = QString();

View File

@@ -7,7 +7,6 @@
#include <QQuickTextDocument>
#include <QTextCursor>
#include <QTextDocumentFragment>
#include <Kirigami/Platform/PlatformTheme>
#include <qtextdocument.h>

View File

@@ -6,7 +6,6 @@
#include <QObject>
#include <QQuickItem>
#include <QTextDocumentFragment>
#include <qtextdocumentfragment.h>
#include "enums/chatbartype.h"
#include "enums/richformat.h"

View File

@@ -596,59 +596,6 @@ void ChatBarMessageContentModel::updateCache() const
m_room->cacheForType(m_type)->cache().fill(m_components);
}
inline QString formatQuote(const QString &input)
{
QString stringOut;
auto splitString = input.split(u"\n\n"_s, Qt::SkipEmptyParts);
for (auto &string : splitString) {
if (string.startsWith(u'*')) {
string.removeFirst();
}
if (string.startsWith(u'\"')) {
string.removeFirst();
}
if (string.endsWith(u'*')) {
string.removeLast();
}
if (string.endsWith(u'\"')) {
string.removeLast();
}
if (!stringOut.isEmpty()) {
stringOut += u"\n"_s;
}
stringOut += u"> "_s + string;
}
return stringOut;
}
inline QString formatCode(const QString &input)
{
return u"```\n%1\n```"_s.arg(input).replace(u"\n\n"_s, u"\n"_s);
}
QString ChatBarMessageContentModel::messageText() const
{
QString text;
for (const auto &component : m_components) {
if (MessageComponentType::isTextType(component.type)) {
if (const auto textItem = textItemForComponent(component)) {
auto newText = textItem->markdownText();
newText.replace(QRegularExpression(u"(?<!\n)\n(?!\n)"_s), u" "_s);
if (component.type == MessageComponentType::Quote) {
newText = formatQuote(newText);
} else if (component.type == MessageComponentType::Code) {
newText = formatCode(newText);
}
if (!text.isEmpty()) {
text += u"\n\n"_s;
}
text += newText;
}
}
}
return text;
}
void ChatBarMessageContentModel::postMessage()
{
if (m_type == ChatBarType::None || !m_room) {

View File

@@ -150,7 +150,6 @@ private:
void handleBlockTransition(bool up);
void updateCache() const;
QString messageText() const;
bool m_sendMessageWithEnter = true;