Restore missing functionality

This commit is contained in:
James Graham
2026-01-04 19:19:22 +00:00
parent d10fe4a684
commit d0abfe60f9
15 changed files with 330 additions and 219 deletions

View File

@@ -39,7 +39,7 @@ public:
return; return;
} }
m_textItem = textItem; m_textItem = textItem;
m_keyHelper->setTextItem(textItem); m_keyHelper->textItem = textItem;
Q_EMIT textItemChanged(); Q_EMIT textItemChanged();
} }

View File

@@ -68,7 +68,7 @@ KirigamiComponents.ConvergentContextMenu {
text: i18nc("@action:button", "Mention") text: i18nc("@action:button", "Mention")
icon.name: "username-copy-symbolic" icon.name: "username-copy-symbolic"
onTriggered: { onTriggered: {
RoomManager.currentRoom.mainCache.mentionAdded(root.author.id); RoomManager.currentRoom.mainCache.mentionAdded(root.author.disambiguatedName, "https://matrix.to/#/" + root.author.id);
} }
} }
} }

View File

@@ -40,12 +40,45 @@ QQC2.Control {
onCurrentRoomChanged: { onCurrentRoomChanged: {
_private.chatBarCache = currentRoom.mainCache _private.chatBarCache = currentRoom.mainCache
if (ShareHandler.text.length > 0 && ShareHandler.room === root.currentRoom.id) { if (ShareHandler.text.length > 0 && ShareHandler.room === root.currentRoom.id) {
contentModel.focusedTextItem.
textField.text = ShareHandler.text; textField.text = ShareHandler.text;
ShareHandler.text = ""; ShareHandler.text = "";
ShareHandler.room = ""; ShareHandler.room = "";
} }
} }
Connections {
target: contentModel.keyHelper
function onUnhandledUp(isCompleting: bool): void {
if (!isCompleting) {
return;
}
completionMenu.decrementIndex();
}
function onUnhandledDown(isCompleting: bool): void {
if (!isCompleting) {
return;
}
completionMenu.incrementIndex();
}
function onUnhandledTab(isCompleting: bool): void {
if (!isCompleting) {
return;
}
completionMenu.completeCurrent();
}
function onUnhandledReturn(isCompleting: bool): void {
if (!isCompleting) {
return;
}
completionMenu.completeCurrent();
}
}
Connections { Connections {
target: ShareHandler target: ShareHandler
function onRoomChanged(): void { function onRoomChanged(): void {
@@ -60,13 +93,10 @@ QQC2.Control {
Connections { Connections {
target: root.currentRoom.mainCache target: root.currentRoom.mainCache
function onMentionAdded(mention: string): void { function onMentionAdded(text: string, hRef: string): void {
// add mention text completionMenu.complete(text, hRef);
textField.append(mention + " ");
// move cursor to the end
textField.cursorPosition = textField.text.length;
// move the focus back to the chat bar // move the focus back to the chat bar
textField.forceActiveFocus(Qt.OtherFocusReason); contentModel.refocusCurrentComponent();
} }
} }
@@ -93,30 +123,39 @@ QQC2.Control {
topPadding: Kirigami.Units.smallSpacing topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing bottomPadding: Kirigami.Units.smallSpacing
contentItem: QQC2.ScrollView { contentItem: ColumnLayout {
id: chatScrollView QQC2.ScrollView {
ColumnLayout { id: chatScrollView
spacing: Kirigami.Units.smallSpacing Layout.fillWidth: true
Layout.maximumHeight: Kirigami.Units.gridUnit * 8
Repeater { clip: true
id: chatContentView
model: ChatBarMessageContentModel { ColumnLayout {
id: contentModel width: chatScrollView.width
type: ChatBarType.Room spacing: Kirigami.Units.smallSpacing
room: root.currentRoom
Repeater {
id: chatContentView
model: ChatBarMessageContentModel {
id: contentModel
type: ChatBarType.Room
room: root.currentRoom
}
delegate: MessageComponentChooser {}
} }
delegate: MessageComponentChooser {}
} }
RichEditBar { }
id: richEditBar RichEditBar {
maxAvailableWidth: chatBarSizeHelper.availableWidth - Kirigami.Units.largeSpacing * 2 id: richEditBar
Layout.alignment: Qt.AlignCenter
maxAvailableWidth: chatBarSizeHelper.availableWidth - Kirigami.Units.largeSpacing * 2
room: root.currentRoom room: root.currentRoom
contentModel: chatContentView.model contentModel: chatContentView.model
onClicked: contentModel.refocusCurrentComponent() onClicked: contentModel.refocusCurrentComponent()
}
} }
} }
@@ -151,7 +190,7 @@ QQC2.Control {
id: completionMenu id: completionMenu
room: root.currentRoom room: root.currentRoom
type: LibNeoChat.ChatBarType.Room type: LibNeoChat.ChatBarType.Room
textItem: chatContentView.model.focusedTextItem textItem: contentModel.focusedTextItem
x: 1 x: 1
y: -height y: -height

View File

@@ -46,8 +46,12 @@ QQC2.Popup {
completions.decrementCurrentIndex(); completions.decrementCurrentIndex();
} }
function complete() { function complete(text: string, hRef: string) {
completionModel.insertCompletion(completions.currentItem.replacedText, completions.currentItem.hRef) completionModel.insertCompletion(text, hRef);
}
function completeCurrent() {
completionModel.insertCompletion(completions.currentItem.replacedText, completions.currentItem.hRef);
} }
leftPadding: 0 leftPadding: 0

View File

@@ -205,7 +205,7 @@ Q_SIGNALS:
void relationIdChanged(const QString &oldEventId, const QString &newEventId); void relationIdChanged(const QString &oldEventId, const QString &newEventId);
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId); void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
void attachmentPathChanged(); void attachmentPathChanged();
void mentionAdded(const QString &mention); void mentionAdded(const QString &text, const QString &hRef);
void relationAuthorIsPresentChanged(); void relationAuthorIsPresentChanged();
private: private:

View File

@@ -3,120 +3,191 @@
#include "chatkeyhelper.h" #include "chatkeyhelper.h"
#include "chattextitemhelper.h"
#include "clipboard.h"
#include "neochatroom.h"
ChatKeyHelper::ChatKeyHelper(QObject *parent) ChatKeyHelper::ChatKeyHelper(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
} }
ChatTextItemHelper *ChatKeyHelper::textItem() const bool ChatKeyHelper::handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers)
{ {
return m_textItem; switch (key) {
case Qt::Key_V:
return vKey(modifiers);
case Qt::Key_Up:
return up(modifiers);
case Qt::Key_Down:
return down();
case Qt::Key_Tab:
return tab();
case Qt::Key_Delete:
return deleteChar();
case Qt::Key_Backspace:
return backspace();
case Qt::Key_Enter:
case Qt::Key_Return:
return insertReturn();
default:
return false;
}
} }
void ChatKeyHelper::setTextItem(ChatTextItemHelper *textItem) bool ChatKeyHelper::vKey(Qt::KeyboardModifiers modifiers)
{ {
if (textItem == m_textItem) { if (!textItem) {
return; return false;
} }
if (m_textItem) { if (modifiers.testFlag(Qt::ControlModifier)) {
m_textItem->disconnect(this); return pasteImage();
} }
return false;
m_textItem = textItem;
if (m_textItem) {
connect(m_textItem, &ChatTextItemHelper::textItemChanged, this, &ChatKeyHelper::textItemChanged);
}
Q_EMIT textItemChanged();
} }
void ChatKeyHelper::up() bool ChatKeyHelper::up(Qt::KeyboardModifiers modifiers)
{ {
if (!m_textItem) { if (!textItem) {
return; return false;
} }
QTextCursor cursor = m_textItem->textCursor();
if (modifiers.testFlag(Qt::ControlModifier)) {
room->replyLastMessage();
return true;
}
if (textItem->isEmpty()) {
room->editLastMessage();
return true;
}
if (textItem->isCompleting) {
Q_EMIT unhandledUp(true);
return true;
}
QTextCursor cursor = textItem->textCursor();
if (cursor.isNull()) { if (cursor.isNull()) {
return; return false;
} }
if (cursor.blockNumber() == 0 && cursor.block().layout()->lineForTextPosition(cursor.positionInBlock()).lineNumber() == 0) { if (cursor.blockNumber() == 0 && cursor.block().layout()->lineForTextPosition(cursor.positionInBlock()).lineNumber() == 0) {
Q_EMIT unhandledUp(); Q_EMIT unhandledUp(false);
return; return true;
} }
cursor.movePosition(QTextCursor::Up); return false;
m_textItem->setCursorPosition(cursor.position());
} }
void ChatKeyHelper::down() bool ChatKeyHelper::down()
{ {
if (!m_textItem) { if (!textItem) {
return; return false;
} }
QTextCursor cursor = m_textItem->textCursor(); if (textItem->isCompleting) {
Q_EMIT unhandledDown(true);
return true;
}
QTextCursor cursor = textItem->textCursor();
if (cursor.isNull()) { if (cursor.isNull()) {
return; return false;
} }
if (cursor.blockNumber() == cursor.document()->blockCount() - 1 if (cursor.blockNumber() == cursor.document()->blockCount() - 1
&& cursor.block().layout()->lineForTextPosition(cursor.positionInBlock()).lineNumber() == (cursor.block().layout()->lineCount() - 1)) { && cursor.block().layout()->lineForTextPosition(cursor.positionInBlock()).lineNumber() == (cursor.block().layout()->lineCount() - 1)) {
Q_EMIT unhandledDown(); Q_EMIT unhandledDown(false);
return; return true;
} }
cursor.movePosition(QTextCursor::Down); return false;
m_textItem->setCursorPosition(cursor.position());
} }
void ChatKeyHelper::tab() bool ChatKeyHelper::tab()
{ {
QTextCursor cursor = m_textItem->textCursor(); if (!textItem) {
return false;
}
if (textItem->isCompleting) {
Q_EMIT unhandledTab(true);
return true;
}
QTextCursor cursor = textItem->textCursor();
if (cursor.isNull()) { if (cursor.isNull()) {
return; return false;
} }
if (cursor.currentList() && m_textItem->canIndentListMoreAtCursor()) { if (cursor.currentList() && textItem->canIndentListMoreAtCursor()) {
m_textItem->indentListMoreAtCursor(); textItem->indentListMoreAtCursor();
return; return true;
} }
cursor.insertText(u" "_s); return false;
} }
void ChatKeyHelper::deleteChar() bool ChatKeyHelper::deleteChar()
{ {
QTextCursor cursor = m_textItem->textCursor(); if (!textItem) {
if (cursor.isNull()) { return false;
return;
} }
if (cursor.position() >= m_textItem->document()->characterCount() - m_textItem->fixedEndChars().length() - 1) {
QTextCursor cursor = textItem->textCursor();
if (cursor.isNull()) {
return false;
}
if (cursor.position() >= textItem->document()->characterCount() - textItem->fixedEndChars().length() - 1) {
Q_EMIT unhandledDelete(); Q_EMIT unhandledDelete();
return; return true;
} }
cursor.deleteChar(); return false;
} }
void ChatKeyHelper::backspace() bool ChatKeyHelper::backspace()
{ {
QTextCursor cursor = m_textItem->textCursor(); if (!textItem) {
if (cursor.isNull()) { return false;
return;
} }
if (cursor.position() <= m_textItem->fixedStartChars().length()) {
if (cursor.currentList() && m_textItem->canIndentListLessAtCursor()) { QTextCursor cursor = textItem->textCursor();
m_textItem->indentListLessAtCursor(); if (cursor.isNull()) {
return; return false;
}
if (cursor.position() <= textItem->fixedStartChars().length()) {
if (cursor.currentList() && textItem->canIndentListLessAtCursor()) {
textItem->indentListLessAtCursor();
return true;
} }
Q_EMIT unhandledBackspace(); Q_EMIT unhandledBackspace();
return; return true;
} }
cursor.deletePreviousChar(); return false;
} }
void ChatKeyHelper::insertReturn() bool ChatKeyHelper::insertReturn()
{ {
QTextCursor cursor = m_textItem->textCursor(); if (!textItem) {
return false;
}
if (textItem->isCompleting) {
Q_EMIT unhandledReturn(true);
return true;
}
QTextCursor cursor = textItem->textCursor();
if (cursor.isNull()) { if (cursor.isNull()) {
return; return false;
} }
cursor.insertBlock(); cursor.insertBlock();
return true;
}
bool ChatKeyHelper::pasteImage()
{
if (!textItem) {
return false;
}
const auto savePath = Clipboard().saveImage();
if (!savePath.isEmpty()) {
Q_EMIT imagePasted(savePath);
}
return false;
} }
#include "moc_chatkeyhelper.cpp" #include "moc_chatkeyhelper.cpp"

View File

@@ -6,8 +6,18 @@
#include <QObject> #include <QObject>
#include <QQmlEngine> #include <QQmlEngine>
#include "chattextitemhelper.h" class NeoChatRoom;
class ChatTextItemHelper;
/**
* @class ChatKeyHelper
*
* A class to handle some key presses on behalf of a ChatTextItemHelper.
*
* This is used to manage complex rich text interactions.
*
* @sa ChatTextItemHelper
*/
class ChatKeyHelper : public QObject class ChatKeyHelper : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -16,72 +26,94 @@ class ChatKeyHelper : public QObject
public: public:
explicit ChatKeyHelper(QObject *parent = nullptr); explicit ChatKeyHelper(QObject *parent = nullptr);
ChatTextItemHelper *textItem() const; /**
void setTextItem(ChatTextItemHelper *textItem); * @brief The ChatTextItemHelper that ChatKeyHelper is handling key presses for.
*
* @sa ChatTextItemHelper
*/
QPointer<NeoChatRoom> room;
/** /**
* @brief Handle up key at current cursor location. * @brief The ChatTextItemHelper that ChatKeyHelper is handling key presses for.
*
* @sa ChatTextItemHelper
*/ */
Q_INVOKABLE void up(); QPointer<ChatTextItemHelper> textItem;
/** Q_INVOKABLE bool handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers);
* @brief Handle down key at current cursor location.
*/
Q_INVOKABLE void down();
/**
* @brief Handle tab key at current cursor location.
*/
Q_INVOKABLE void tab();
/**
* @brief Handle delete key at current cursor location.
*/
Q_INVOKABLE void deleteChar();
/**
* @brief Handle backspace key at current cursor location.
*/
Q_INVOKABLE void backspace();
/**
* @brief Handle return key at current cursor location.
*/
Q_INVOKABLE void insertReturn();
Q_SIGNALS: Q_SIGNALS:
void textItemChanged();
/** /**
* @brief There is an unhandled up key press. * @brief There is an unhandled up key press.
* *
* i.e. up is pressed on the first line of the first block of the text item. * Current trigger conditions:
* - Up is pressed on the first line of the first block of the text item.
* - Return clicked when a completion has been started.
*/ */
void unhandledUp(); void unhandledUp(bool isCompleting);
/** /**
* @brief There is an unhandled down key press. * @brief There is an unhandled down key press.
* *
* i.e. down is pressed on the last line of the last block of the text item. * Current trigger conditions:
* - Down is pressed on the last line of the last block of the text item.
* - Return clicked when a completion has been started.
*/ */
void unhandledDown(); void unhandledDown(bool isCompleting);
/**
* @brief There is an unhandled tab key press.
*
* Current trigger conditions:
* - Tab clicked when a completion has been started.
*/
void unhandledTab(bool isCompleting);
/** /**
* @brief There is an unhandled delete key press. * @brief There is an unhandled delete key press.
* *
* i.e. delete is pressed at the end of the last line of the last block of the * Current trigger conditions:
* text item. * - Delete is pressed at the end of the last line of the last block of the
* text item.
*/ */
void unhandledDelete(); void unhandledDelete();
/** /**
* @brief There is an unhandled backspace key press. * @brief There is an unhandled backspace key press.
* *
* i.e. backspace is pressed at the beginning of the first line of the first * Current trigger conditions:
* block of the text item. * - Backspace is pressed at the beginning of the first line of the first
* block of the text item.
*/ */
void unhandledBackspace(); void unhandledBackspace();
/**
* @brief There is an unhandled return key press.
*
* Current trigger conditions:
* - Return clicked when a completion has been started.
*/
void unhandledReturn(bool isCompleting);
/**
* @brief An image has been pasted.
*/
void imagePasted(const QString &filePath);
private: private:
QPointer<ChatTextItemHelper> m_textItem; bool vKey(Qt::KeyboardModifiers modifiers);
bool up(Qt::KeyboardModifiers modifiers);
bool down();
bool tab();
bool deleteChar();
bool backspace();
bool insertReturn();
bool pasteImage();
}; };

View File

@@ -64,6 +64,11 @@ public:
QQuickItem *textItem() const; QQuickItem *textItem() const;
void setTextItem(QQuickItem *textItem); void setTextItem(QQuickItem *textItem);
/**
* @brief Whether a completion has started based on recent text entry.
*/
bool isCompleting = false;
/** /**
* @brief The fixed characters that will always be at the beginning of the text item. * @brief The fixed characters that will always be at the beginning of the text item.
*/ */
@@ -98,6 +103,13 @@ public:
*/ */
QTextDocument *document() const; QTextDocument *document() const;
/**
* @brief Whetehr the underlying QTextDocument is empty.
*
* @sa QTextDocument
*/
bool isEmpty() const;
/** /**
* @brief The line count of the text item. * @brief The line count of the text item.
*/ */
@@ -238,7 +250,6 @@ private:
void initializeChars(); void initializeChars();
bool m_initializingChars = false; bool m_initializingChars = false;
bool isEmpty() const;
std::optional<int> lineLength(int lineNumber) const; std::optional<int> lineLength(int lineNumber) const;
int selectionStart() const; int selectionStart() const;

View File

@@ -240,6 +240,8 @@ void CompletionModel::updateCompletion()
} }
beginResetModel(); beginResetModel();
endResetModel(); endResetModel();
m_textItem->isCompleting = rowCount() > 0;
} }
CompletionModel::AutoCompletionType CompletionModel::autoCompletionType() const CompletionModel::AutoCompletionType CompletionModel::autoCompletionType() const

View File

@@ -55,6 +55,10 @@ QString QmlUtils::nameForPowerLevelValue(const int value)
bool Utils::isEmoji(const QString &text) bool Utils::isEmoji(const QString &text)
{ {
if (text.isEmpty()) {
return false;
}
#ifdef HAVE_ICU #ifdef HAVE_ICU
QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme, text); QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme, text);
int from = 0; int from = 0;

View File

@@ -75,7 +75,7 @@ QQC2.Control {
Keys.onEnterPressed: event => { Keys.onEnterPressed: event => {
if (completionMenu.visible) { if (completionMenu.visible) {
completionMenu.complete(); completionMenu.completeCurrent();
} else if (event.modifiers & Qt.ShiftModifier) { } else if (event.modifiers & Qt.ShiftModifier) {
textArea.insert(cursorPosition, "\n"); textArea.insert(cursorPosition, "\n");
} else { } else {
@@ -84,7 +84,7 @@ QQC2.Control {
} }
Keys.onReturnPressed: event => { Keys.onReturnPressed: event => {
if (completionMenu.visible) { if (completionMenu.visible) {
completionMenu.complete(); completionMenu.completeCurrent();
} else if (event.modifiers & Qt.ShiftModifier) { } else if (event.modifiers & Qt.ShiftModifier) {
textArea.insert(cursorPosition, "\n"); textArea.insert(cursorPosition, "\n");
} else { } else {
@@ -93,7 +93,7 @@ QQC2.Control {
} }
Keys.onTabPressed: { Keys.onTabPressed: {
if (completionMenu.visible) { if (completionMenu.visible) {
completionMenu.complete(); completionMenu.completeCurrent();
} }
} }
Keys.onPressed: event => { Keys.onPressed: event => {

View File

@@ -91,27 +91,8 @@ QQC2.Control {
QQC2.TextArea { QQC2.TextArea {
id: codeText id: codeText
Keys.onUpPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.up();
}
Keys.onDownPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.down();
}
Keys.onDeletePressed: (event) => {
event.accepted = true;
root.Message.contentModel.keyHelper.deleteChar();
}
Keys.onPressed: (event) => { Keys.onPressed: (event) => {
if (event.key == Qt.Key_Backspace && cursorPosition == 0) { event.accepted = Message.contentModel.keyHelper.handleKey(event.key, event.modifiers);
event.accepted = true;
root.Message.contentModel.keyHelper.backspace();
return;
}
event.accepted = false;
} }
onFocusChanged: if (focus && !root.currentFocus) { onFocusChanged: if (focus && !root.currentFocus) {

View File

@@ -63,26 +63,8 @@ QQC2.TextArea {
*/ */
signal selectedTextChanged(string selectedText) signal selectedTextChanged(string selectedText)
Keys.onUpPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.up();
}
Keys.onDownPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.down();
}
Keys.onDeletePressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.deleteChar();
}
Keys.onPressed: (event) => { Keys.onPressed: (event) => {
if (event.key == Qt.Key_Backspace) { event.accepted = Message.contentModel.keyHelper.handleKey(event.key, event.modifiers);
event.accepted = true;
Message.contentModel.keyHelper.backspace();
return;
}
event.accepted = false;
} }
Layout.fillWidth: true Layout.fillWidth: true

View File

@@ -75,41 +75,8 @@ TextEdit {
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumWidth: Message.maxContentWidth Layout.maximumWidth: Message.maxContentWidth
Keys.onUpPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.up();
}
Keys.onDownPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.down();
}
Keys.onTabPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.tab();
}
Keys.onDeletePressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.deleteChar();
}
Keys.onPressed: (event) => { Keys.onPressed: (event) => {
if (event.key == Qt.Key_Backspace && cursorPosition == 0) { event.accepted = Message.contentModel.keyHelper.handleKey(event.key, event.modifiers);
event.accepted = true;
Message.contentModel.keyHelper.backspace();
return;
}
event.accepted = false;
}
Keys.onEnterPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.insertReturn();
}
Keys.onReturnPressed: (event) => {
event.accepted = true;
Message.contentModel.keyHelper.insertReturn();
} }
onFocusChanged: if (focus && !root.currentFocus) { onFocusChanged: if (focus && !root.currentFocus) {

View File

@@ -25,8 +25,6 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
, m_keyHelper(new ChatKeyHelper(this)) , m_keyHelper(new ChatKeyHelper(this))
{ {
m_editableActive = true; m_editableActive = true;
connectKeyHelper();
initializeModel();
connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() { connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() {
if (m_type == ChatBarType::None || !m_room) { if (m_type == ChatBarType::None || !m_room) {
@@ -34,15 +32,23 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
} }
connect(m_room->cacheForType(m_type), &ChatBarCache::relationIdChanged, this, &ChatBarMessageContentModel::updateReplyModel); connect(m_room->cacheForType(m_type), &ChatBarCache::relationIdChanged, this, &ChatBarMessageContentModel::updateReplyModel);
clearModel(); connect(m_room->cacheForType(m_type), &ChatBarCache::attachmentPathChanged, this, [this]() {
if (m_room->cacheForType(m_type)->attachmentPath().length() > 0) {
beginResetModel(); addAttachment(QUrl(m_room->cacheForType(m_type)->attachmentPath()));
}
});
if (m_room->cacheForType(m_type)->attachmentPath().length() > 0) { if (m_room->cacheForType(m_type)->attachmentPath().length() > 0) {
addAttachment(QUrl(m_room->cacheForType(m_type)->attachmentPath())); addAttachment(QUrl(m_room->cacheForType(m_type)->attachmentPath()));
} }
const auto textSections = m_room->cacheForType(m_type)->text().split(u"\n\n"_s); const auto textSections = m_room->cacheForType(m_type)->text().split(u"\n\n"_s);
if (textSections.length() == 1 && textSections[0].isEmpty()) {
return;
}
clearModel();
beginResetModel();
for (const auto &section : textSections) { for (const auto &section : textSections) {
const auto type = MessageComponentType::typeForString(section); const auto type = MessageComponentType::typeForString(section);
auto cleanText = section; auto cleanText = section;
@@ -54,14 +60,14 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
} }
insertComponent(rowCount(), type, {}, cleanText); insertComponent(rowCount(), type, {}, cleanText);
} }
m_currentFocusComponent = QPersistentModelIndex(index(rowCount() - 1));
endResetModel(); endResetModel();
m_currentFocusComponent = QPersistentModelIndex(index(rowCount() - 1));
Q_EMIT focusRowChanged(); Q_EMIT focusRowChanged();
}); });
connect(this, &ChatBarMessageContentModel::focusRowChanged, this, [this]() { connect(this, &ChatBarMessageContentModel::focusRowChanged, this, [this]() {
m_markdownHelper->setTextItem(focusedTextItem()); m_markdownHelper->setTextItem(focusedTextItem());
m_keyHelper->setTextItem(focusedTextItem()); m_keyHelper->textItem = focusedTextItem();
}); });
connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() { connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() {
for (const auto &component : m_components) { for (const auto &component : m_components) {
@@ -69,6 +75,7 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
textItem->setRoom(m_room); textItem->setRoom(m_room);
} }
} }
m_keyHelper->room = m_room;
}); });
connect(this, &ChatBarMessageContentModel::typeChanged, this, [this]() { connect(this, &ChatBarMessageContentModel::typeChanged, this, [this]() {
for (const auto &component : m_components) { for (const auto &component : m_components) {
@@ -78,6 +85,9 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
} }
}); });
connect(m_markdownHelper, &ChatMarkdownHelper::unhandledBlockFormat, this, &ChatBarMessageContentModel::insertStyleAtCursor); connect(m_markdownHelper, &ChatMarkdownHelper::unhandledBlockFormat, this, &ChatBarMessageContentModel::insertStyleAtCursor);
connectKeyHelper();
initializeModel();
} }
void ChatBarMessageContentModel::initializeModel() void ChatBarMessageContentModel::initializeModel()
@@ -92,9 +102,9 @@ void ChatBarMessageContentModel::initializeModel()
.display = {}, .display = {},
.attributes = {{TextItemKey, QVariant::fromValue<ChatTextItemHelper *>(textItem)}}, .attributes = {{TextItemKey, QVariant::fromValue<ChatTextItemHelper *>(textItem)}},
}; };
m_currentFocusComponent = QPersistentModelIndex(index(0));
endInsertRows(); endInsertRows();
m_currentFocusComponent = QPersistentModelIndex(index(0));
Q_EMIT focusRowChanged(); Q_EMIT focusRowChanged();
} }
@@ -119,10 +129,16 @@ ChatKeyHelper *ChatBarMessageContentModel::keyHelper() const
void ChatBarMessageContentModel::connectKeyHelper() void ChatBarMessageContentModel::connectKeyHelper()
{ {
connect(m_keyHelper, &ChatKeyHelper::unhandledUp, this, [this]() { connect(m_keyHelper, &ChatKeyHelper::unhandledUp, this, [this](bool isCompleting) {
if (isCompleting) {
return;
}
setFocusRow(m_currentFocusComponent.row() - 1); setFocusRow(m_currentFocusComponent.row() - 1);
}); });
connect(m_keyHelper, &ChatKeyHelper::unhandledDown, this, [this]() { connect(m_keyHelper, &ChatKeyHelper::unhandledDown, this, [this](bool isCompleting) {
if (isCompleting) {
return;
}
setFocusRow(m_currentFocusComponent.row() + 1); setFocusRow(m_currentFocusComponent.row() + 1);
}); });
connect(m_keyHelper, &ChatKeyHelper::unhandledDelete, this, [this]() { connect(m_keyHelper, &ChatKeyHelper::unhandledDelete, this, [this]() {
@@ -150,6 +166,9 @@ void ChatBarMessageContentModel::connectKeyHelper()
insertComponentAtCursor(MessageComponentType::Text); insertComponentAtCursor(MessageComponentType::Text);
} }
}); });
connect(m_keyHelper, &ChatKeyHelper::imagePasted, this, [this](const QString &filePath) {
m_room->cacheForType(m_type)->setAttachmentPath(filePath);
});
} }
int ChatBarMessageContentModel::focusRow() const int ChatBarMessageContentModel::focusRow() const
@@ -508,7 +527,6 @@ void ChatBarMessageContentModel::postMessage()
return; return;
} }
qWarning() << m_room->cacheForType(m_type)->text();
m_room->cacheForType(m_type)->postMessage(); m_room->cacheForType(m_type)->postMessage();
clearModel(); clearModel();
initializeModel(); initializeModel();