From dcddea6fb89246d63be91a1f1151ce2dbd255a12 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Mon, 13 Apr 2020 16:22:30 +0200 Subject: [PATCH] Fix reply not closing fixes #124 --- CMakeLists.txt | 2 - resources/qml/TimelineView.qml | 6 +- src/ChatPage.cpp | 37 ++++------ src/ChatPage.h | 6 +- src/TextInputWidget.cpp | 69 +++--------------- src/TextInputWidget.h | 27 ++----- src/notifications/ManagerLinux.cpp | 32 ++++----- src/notifications/ManagerWin.cpp | 1 - src/popups/ReplyPopup.cpp | 103 --------------------------- src/popups/ReplyPopup.h | 44 ------------ src/timeline/TimelineModel.cpp | 13 +++- src/timeline/TimelineModel.h | 21 ++++++ src/timeline/TimelineViewManager.cpp | 76 ++++++++++++-------- src/timeline/TimelineViewManager.h | 30 ++------ 14 files changed, 133 insertions(+), 334 deletions(-) delete mode 100644 src/popups/ReplyPopup.cpp delete mode 100644 src/popups/ReplyPopup.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9742c48e..6f769a26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,7 +303,6 @@ set(SRC_FILES src/Utils.cpp src/WelcomePage.cpp src/popups/PopupItem.cpp - src/popups/ReplyPopup.cpp src/popups/SuggestionsPopup.cpp src/popups/UserMentions.cpp src/main.cpp @@ -501,7 +500,6 @@ qt5_wrap_cpp(MOC_HEADERS src/UserSettingsPage.h src/WelcomePage.h src/popups/PopupItem.h - src/popups/ReplyPopup.h src/popups/SuggestionsPopup.h src/popups/UserMentions.h ) diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 5b051235..86b511b2 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -285,7 +285,7 @@ Page { id: replyPopup - visible: timelineManager.replyingEvent && chat.model + visible: chat.model && chat.model.reply // Height of child, plus margins, plus border height: replyPreview.height + 10 color: colors.base @@ -300,7 +300,7 @@ Page { anchors.rightMargin: 20 anchors.bottom: parent.bottom - modelData: chat.model ? chat.model.getDump(timelineManager.replyingEvent) : {} + modelData: chat.model ? chat.model.getDump(chat.model.reply) : {} userColor: timelineManager.userColor(modelData.userId, colors.window) } @@ -318,7 +318,7 @@ Page { ToolTip.visible: closeReplyButton.hovered ToolTip.text: qsTr("Close") - onClicked: timelineManager.closeReply() + onClicked: chat.model.reply = undefined } } } diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index d7d11a12..c9afeb75 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -303,10 +303,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) text_input_, &TextInputWidget::uploadMedia, this, - [this](QSharedPointer dev, - QString mimeClass, - const QString &fn, - const std::optional &related) { + [this](QSharedPointer dev, QString mimeClass, const QString &fn) { if (!dev->open(QIODevice::ReadOnly)) { emit uploadFailed( QString("Error while reading media: %1").arg(dev->errorString())); @@ -358,8 +355,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) mime = mime.name(), size = payload.size(), dimensions, - blurhash, - related](const mtx::responses::ContentURI &res, mtx::http::RequestErr err) { + blurhash](const mtx::responses::ContentURI &res, mtx::http::RequestErr err) { if (err) { emit uploadFailed( tr("Failed to upload media. Please try again.")); @@ -378,8 +374,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) mime, size, dimensions, - blurhash, - related); + blurhash); }); }); @@ -398,8 +393,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) QString mime, qint64 dsize, QSize dimensions, - QString blurhash, - const std::optional &related) { + QString blurhash) { text_input_->hideUploadSpinner(); if (encryptedFile) @@ -413,17 +407,16 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) mime, dsize, dimensions, - blurhash, - related); + blurhash); else if (mimeClass == "audio") view_manager_->queueAudioMessage( - roomid, filename, encryptedFile, url, mime, dsize, related); + roomid, filename, encryptedFile, url, mime, dsize); else if (mimeClass == "video") view_manager_->queueVideoMessage( - roomid, filename, encryptedFile, url, mime, dsize, related); + roomid, filename, encryptedFile, url, mime, dsize); else view_manager_->queueFileMessage( - roomid, filename, encryptedFile, url, mime, dsize, related); + roomid, filename, encryptedFile, url, mime, dsize); }); connect(room_list_, &RoomList::roomAvatarChanged, this, &ChatPage::updateTopBarAvatar); @@ -548,14 +541,6 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) }); connect(this, &ChatPage::dropToLoginPageCb, this, &ChatPage::dropToLoginPage); - connect(this, &ChatPage::messageReply, text_input_, &TextInputWidget::addReply); - connect(this, &ChatPage::messageReply, this, [this](const RelatedInfo &related) { - view_manager_->updateReplyingEvent(QString::fromStdString(related.related_event)); - }); - connect(view_manager_, - &TimelineViewManager::replyClosed, - text_input_, - &TextInputWidget::closeReplyPopup); instance_ = this; } @@ -596,6 +581,12 @@ ChatPage::resetUI() showUnreadMessageNotification(0); } +void +ChatPage::focusMessageInput() +{ + this->text_input_->focusLineEdit(); +} + void ChatPage::deleteConfigs() { diff --git a/src/ChatPage.h b/src/ChatPage.h index 02c19ba7..5182ab99 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -85,6 +85,7 @@ public: //! Show the room/group list (if it was visible). void showSideBars(); void initiateLogout(); + void focusMessageInput(); public slots: void leaveRoom(const QString &room_id); @@ -99,8 +100,6 @@ signals: void connectionLost(); void connectionRestored(); - void messageReply(const RelatedInfo &related); - void notificationsRetrieved(const mtx::responses::Notifications &); void highlightedNotifsRetrieved(const mtx::responses::Notifications &, const QPoint widgetPos); @@ -114,8 +113,7 @@ signals: const QString &mime, qint64 dsize, const QSize &dimensions, - const QString &blurhash, - const std::optional &related); + const QString &blurhash); void contentLoaded(); void closing(); diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp index 11f7ddda..af5c278e 100644 --- a/src/TextInputWidget.cpp +++ b/src/TextInputWidget.cpp @@ -46,7 +46,6 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent) : QTextEdit{parent} , history_index_{0} , suggestionsPopup_{parent} - , replyPopup_{parent} , previewDialog_{parent} { setFrameStyle(QFrame::NoFrame); @@ -73,10 +72,6 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent) &FilteredTextEdit::uploadData); connect(this, &FilteredTextEdit::resultsRetrieved, this, &FilteredTextEdit::showResults); - connect(&replyPopup_, &ReplyPopup::userSelected, this, [](const QString &text) { - // TODO: Show user avatar window. - nhlog::ui()->info("User selected: " + text.toStdString()); - }); connect( &suggestionsPopup_, &SuggestionsPopup::itemSelected, this, [this](const QString &text) { suggestionsPopup_.hide(); @@ -90,8 +85,6 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent) cursor.insertText(text); }); - connect(&replyPopup_, &ReplyPopup::cancel, this, [this]() { closeReply(); }); - // For cycling through the suggestions by hitting tab. connect(this, &FilteredTextEdit::selectNextSuggestion, @@ -174,17 +167,6 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event) } } - if (replyPopup_.isVisible()) { - switch (event->key()) { - case Qt::Key_Escape: - closeReply(); - return; - - default: - break; - } - } - switch (event->key()) { case Qt::Key_At: atTriggerPosition_ = textCursor().position(); @@ -218,7 +200,6 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event) if (!(event->modifiers() & Qt::ShiftModifier)) { stopTyping(); submit(); - closeReply(); } else { QTextEdit::keyPressEvent(event); } @@ -416,30 +397,17 @@ FilteredTextEdit::submit() auto name = text.mid(1, command_end - 1); auto args = text.mid(command_end + 1); if (name.isEmpty() || name == "/") { - message(args, related); + message(args); } else { command(name, args); } } else { - message(std::move(text), std::move(related)); + message(std::move(text)); } - related = {}; - clear(); } -void -FilteredTextEdit::showReplyPopup(const RelatedInfo &related_) -{ - QPoint pos = viewport()->mapToGlobal(this->pos()); - - replyPopup_.setReplyContent(related_); - replyPopup_.move(pos.x(), pos.y() - replyPopup_.height() - 10); - replyPopup_.setFixedWidth(this->parentWidget()->width()); - replyPopup_.show(); -} - void FilteredTextEdit::textChanged() { @@ -456,9 +424,7 @@ FilteredTextEdit::uploadData(const QByteArray data, emit startedUpload(); - emit media(buffer, mediaType, filename, related); - related = {}; - closeReply(); + emit media(buffer, mediaType, filename); } void @@ -599,7 +565,7 @@ void TextInputWidget::command(QString command, QString args) { if (command == "me") { - sendEmoteMessage(args, input_->related); + sendEmoteMessage(args); } else if (command == "join") { sendJoinRoomRequest(args); } else if (command == "invite") { @@ -611,16 +577,14 @@ TextInputWidget::command(QString command, QString args) } else if (command == "unban") { sendUnbanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1)); } else if (command == "shrug") { - sendTextMessage("¯\\_(ツ)_/¯", input_->related); + sendTextMessage("¯\\_(ツ)_/¯"); } else if (command == "fliptable") { - sendTextMessage("(╯°□°)╯︵ ┻━┻", input_->related); + sendTextMessage("(╯°□°)╯︵ ┻━┻"); } else if (command == "unfliptable") { - sendTextMessage(" ┯━┯╭( º _ º╭)", input_->related); + sendTextMessage(" ┯━┯╭( º _ º╭)"); } else if (command == "sovietflip") { - sendTextMessage("ノ┬─┬ノ ︵ ( \\o°o)\\", input_->related); + sendTextMessage("ノ┬─┬ノ ︵ ( \\o°o)\\"); } - - input_->related = std::nullopt; } void @@ -640,9 +604,7 @@ TextInputWidget::openFileSelection() QSharedPointer file{new QFile{fileName, this}}; - emit uploadMedia(file, format, QFileInfo(fileName).fileName(), input_->related); - input_->related = {}; - input_->closeReply(); + emit uploadMedia(file, format, QFileInfo(fileName).fileName()); showUploadSpinner(); } @@ -687,16 +649,3 @@ TextInputWidget::paintEvent(QPaintEvent *) style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } - -void -TextInputWidget::addReply(const RelatedInfo &related) -{ - // input_->setText(QString("> %1: %2\n\n").arg(username).arg(msg)); - input_->setFocus(); - - // input_->showReplyPopup(related); - auto cursor = input_->textCursor(); - cursor.movePosition(QTextCursor::End); - input_->setTextCursor(cursor); - input_->related = related; -} diff --git a/src/TextInputWidget.h b/src/TextInputWidget.h index 77d77e44..addb61ec 100644 --- a/src/TextInputWidget.h +++ b/src/TextInputWidget.h @@ -28,7 +28,6 @@ #include "dialogs/PreviewUploadOverlay.h" #include "emoji/PickButton.h" -#include "popups/ReplyPopup.h" #include "popups/SuggestionsPopup.h" struct SearchResult; @@ -49,27 +48,15 @@ public: QSize minimumSizeHint() const override; void submit(); - void showReplyPopup(const RelatedInfo &related_); - void closeReply() - { - replyPopup_.hide(); - related = {}; - } - - // Used for replies - std::optional related; signals: void heightChanged(int height); void startedTyping(); void stoppedTyping(); void startedUpload(); - void message(QString, const std::optional &); + void message(QString msg); void command(QString name, QString args); - void media(QSharedPointer data, - QString mimeClass, - const QString &filename, - const std::optional &related); + void media(QSharedPointer data, QString mimeClass, const QString &filename); //! Trigger the suggestion popup. void showSuggestions(const QString &query); @@ -97,7 +84,6 @@ private: QTimer *typingTimer_; SuggestionsPopup suggestionsPopup_; - ReplyPopup replyPopup_; enum class AnchorType { @@ -163,21 +149,18 @@ public slots: void openFileSelection(); void hideUploadSpinner(); void focusLineEdit() { input_->setFocus(); } - void addReply(const RelatedInfo &related); - void closeReplyPopup() { input_->closeReply(); } private slots: void addSelectedEmoji(const QString &emoji); signals: - void sendTextMessage(const QString &msg, const std::optional &related); - void sendEmoteMessage(QString msg, const std::optional &related); + void sendTextMessage(const QString &msg); + void sendEmoteMessage(QString msg); void heightChanged(int height); void uploadMedia(const QSharedPointer data, QString mimeClass, - const QString &filename, - const std::optional &related); + const QString &filename); void sendJoinRoomRequest(const QString &room); void sendInviteRoomRequest(const QString &userid, const QString &reason); diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp index 8b7b41bb..b9eca1a8 100644 --- a/src/notifications/ManagerLinux.cpp +++ b/src/notifications/ManagerLinux.cpp @@ -97,24 +97,24 @@ NotificationsManager::closeNotification(uint id) void NotificationsManager::removeNotification(const QString &roomId, const QString &eventId) +{ + roomEventId reId = {roomId, eventId}; + for (auto elem = notificationIds.begin(); elem != notificationIds.end(); ++elem) { + if (elem.value().roomId != roomId) + continue; - roomEventId reId = {roomId, eventId}; -for (auto elem = notificationIds.begin(); elem != notificationIds.end(); ++elem) { - if (elem.value().roomId != roomId) - continue; + // close all notifications matching the eventId or having a lower + // notificationId + // This relies on the notificationId not wrapping around. This allows for + // approximately 2,147,483,647 notifications, so it is a bit unlikely. + // Otherwise we would need to store a 64bit counter instead. + closeNotification(elem.key()); - // close all notifications matching the eventId or having a lower - // notificationId - // This relies on the notificationId not wrapping around. This allows for - // approximately 2,147,483,647 notifications, so it is a bit unlikely. - // Otherwise we would need to store a 64bit counter instead. - closeNotification(elem.key()); - - // FIXME: compare index of event id of the read receipt and the notification instead of just - // the id to prevent read receipts of events without notification clearing all notifications - // in that room! - if (elem.value() == reId) - break; + // FIXME: compare index of event id of the read receipt and the notification instead + // of just the id to prevent read receipts of events without notification clearing + // all notifications in that room! + if (elem.value() == reId) + break; } } diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp index b00bac2e..5e209ee6 100644 --- a/src/notifications/ManagerWin.cpp +++ b/src/notifications/ManagerWin.cpp @@ -67,4 +67,3 @@ void NotificationsManager::notificationClosed(uint, uint) {} void NotificationsManager::removeNotification(const QString &roomId, const QString &eventId) {} - diff --git a/src/popups/ReplyPopup.cpp b/src/popups/ReplyPopup.cpp deleted file mode 100644 index 5058c039..00000000 --- a/src/popups/ReplyPopup.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include -#include - -#include "../Config.h" -#include "../Utils.h" -#include "../ui/Avatar.h" -#include "../ui/DropShadow.h" -#include "../ui/TextLabel.h" -#include "PopupItem.h" -#include "ReplyPopup.h" - -ReplyPopup::ReplyPopup(QWidget *parent) - : QWidget(parent) - , userItem_{nullptr} - , msgLabel_{nullptr} - , eventLabel_{nullptr} -{ - setAttribute(Qt::WA_ShowWithoutActivating, true); - setWindowFlags(Qt::ToolTip | Qt::NoDropShadowWindowHint); - - mainLayout_ = new QVBoxLayout(this); - mainLayout_->setMargin(0); - mainLayout_->setSpacing(0); - - topLayout_ = new QHBoxLayout(); - topLayout_->setSpacing(0); - topLayout_->setContentsMargins(13, 1, 13, 0); - - userItem_ = new UserItem(this); - connect(userItem_, &UserItem::clicked, this, &ReplyPopup::userSelected); - topLayout_->addWidget(userItem_); - - buttonLayout_ = new QHBoxLayout(); - buttonLayout_->setSpacing(0); - buttonLayout_->setMargin(0); - - topLayout_->addLayout(buttonLayout_); - QFont f; - f.setPointSizeF(f.pointSizeF()); - const int fontHeight = QFontMetrics(f).height(); - buttonSize_ = std::min(fontHeight, 20); - - closeBtn_ = new FlatButton(this); - closeBtn_->setToolTip(tr("Logout")); - closeBtn_->setCornerRadius(buttonSize_ / 4); - closeBtn_->setText("X"); - - QIcon icon; - icon.addFile(":/icons/icons/ui/remove-symbol.png"); - - closeBtn_->setIcon(icon); - closeBtn_->setIconSize(QSize(buttonSize_, buttonSize_)); - connect(closeBtn_, &FlatButton::clicked, this, [this]() { emit cancel(); }); - - buttonLayout_->addWidget(closeBtn_); - - topLayout_->addLayout(buttonLayout_); - - mainLayout_->addLayout(topLayout_); - msgLabel_ = new TextLabel(this); - msgLabel_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); - mainLayout_->addWidget(msgLabel_); - eventLabel_ = new QLabel(this); - mainLayout_->addWidget(eventLabel_); - - setLayout(mainLayout_); -} - -void -ReplyPopup::setReplyContent(const RelatedInfo &related) -{ - // Update the current widget with the new data. - userItem_->updateItem(related.quoted_user); - - msgLabel_->setText(utils::getFormattedQuoteBody(related, "") - .replace("", "") - .replace("", "")); - - // eventLabel_->setText(srcEvent); - - adjustSize(); -} - -void -ReplyPopup::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - -void -ReplyPopup::mousePressEvent(QMouseEvent *event) -{ - if (event->buttons() != Qt::RightButton) { - emit clicked(eventLabel_->text()); - } - - QWidget::mousePressEvent(event); -} diff --git a/src/popups/ReplyPopup.h b/src/popups/ReplyPopup.h deleted file mode 100644 index 1fa3bb83..00000000 --- a/src/popups/ReplyPopup.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "../ui/FlatButton.h" -#include "../ui/TextLabel.h" - -struct RelatedInfo; -class UserItem; - -class ReplyPopup : public QWidget -{ - Q_OBJECT - -public: - explicit ReplyPopup(QWidget *parent = nullptr); - -public slots: - void setReplyContent(const RelatedInfo &related); - -protected: - void paintEvent(QPaintEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - -signals: - void userSelected(const QString &user); - void clicked(const QString &text); - void cancel(); - -private: - QHBoxLayout *topLayout_; - QVBoxLayout *mainLayout_; - QHBoxLayout *buttonLayout_; - - UserItem *userItem_; - FlatButton *closeBtn_; - TextLabel *msgLabel_; - QLabel *eventLabel_; - - int buttonSize_; -}; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 84dd9885..d54677f7 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -800,6 +800,16 @@ TimelineModel::decryptEvent(const mtx::events::EncryptedEventfocusMessageInput(); +} + +RelatedInfo +TimelineModel::relatedInfo(QString id) +{ + if (!events.contains(id)) + return {}; + auto event = events.value(id); if (auto e = std::get_if>(&event)) { @@ -815,10 +825,9 @@ TimelineModel::replyAction(QString id) related.quoted_formatted_body = mtx::accessors::formattedBodyWithFallback(event); related.quoted_formatted_body.remove(QRegularExpression( ".*", QRegularExpression::DotMatchesEverythingOption)); - nhlog::ui()->debug("after replacement: {}", related.quoted_body.toStdString()); related.room = room_id_; - ChatPage::instance()->messageReply(related); + return related; } void diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 02f5527a..0b181583 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -18,6 +18,7 @@ struct Timeline; struct Messages; struct ClaimKeys; } +struct RelatedInfo; namespace qml_mtx_events { Q_NAMESPACE @@ -124,6 +125,7 @@ class TimelineModel : public QAbstractListModel int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(std::vector typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY typingUsersChanged) + Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply) public: explicit TimelineModel(TimelineViewManager *manager, @@ -191,6 +193,7 @@ public: void addEvents(const mtx::responses::Timeline &events); template void sendMessage(const T &msg); + RelatedInfo relatedInfo(QString id); public slots: void setCurrentIndex(int index); @@ -206,6 +209,22 @@ public slots: } std::vector typingUsers() const { return typingUsers_; } + QString reply() const { return reply_; } + void setReply(QString newReply) + { + if (reply_ != newReply) { + reply_ = newReply; + emit replyChanged(reply_); + } + } + void resetReply() + { + if (!reply_.isEmpty()) { + reply_ = ""; + emit replyChanged(reply_); + } + } + private slots: // Add old events at the top of the timeline. void addBackwardsEvents(const mtx::responses::Messages &msgs); @@ -225,6 +244,7 @@ signals: void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo); void eventFetched(QString requestingEvent, mtx::events::collections::TimelineEvents event); void typingUsersChanged(std::vector users); + void replyChanged(QString reply); private: DecryptionResult decryptEvent( @@ -254,6 +274,7 @@ private: bool isProcessingPending = false; QString currentId; + QString reply_; std::vector typingUsers_; TimelineViewManager *manager_; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 794c13aa..0a339825 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -188,8 +188,11 @@ TimelineViewManager::initWithMessages(const std::map &related) +TimelineViewManager::queueTextMessage(const QString &msg) { + if (!timeline_) + return; + mtx::events::msg::Text text = {}; text.body = msg.trimmed().toStdString(); @@ -203,13 +206,15 @@ TimelineViewManager::queueTextMessage(const QString &msg, const std::optionalreply().isEmpty()) { + auto related = timeline_->relatedInfo(timeline_->reply()); + QString body; bool firstLine = true; - for (const auto &line : related->quoted_body.split("\n")) { + for (const auto &line : related.quoted_body.split("\n")) { if (firstLine) { firstLine = false; - body = QString("> <%1> %2\n").arg(related->quoted_user).arg(line); + body = QString("> <%1> %2\n").arg(related.quoted_user).arg(line); } else { body = QString("%1\n> %2\n").arg(body).arg(line); } @@ -221,17 +226,17 @@ TimelineViewManager::queueTextMessage(const QString &msg, const std::optionalisMarkdownEnabled()) text.formatted_body = - utils::getFormattedQuoteBody(*related, utils::markdownToHtml(msg)) + utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg)) .toStdString(); else text.formatted_body = - utils::getFormattedQuoteBody(*related, msg.toHtmlEscaped()).toStdString(); + utils::getFormattedQuoteBody(related, msg.toHtmlEscaped()).toStdString(); - text.relates_to.in_reply_to.event_id = related->related_event; + text.relates_to.in_reply_to.event_id = related.related_event; + timeline_->resetReply(); } - if (timeline_) - timeline_->sendMessage(text); + timeline_->sendMessage(text); } void @@ -247,6 +252,11 @@ TimelineViewManager::queueEmoteMessage(const QString &msg) emote.format = "org.matrix.custom.html"; } + if (!timeline_->reply().isEmpty()) { + emote.relates_to.in_reply_to.event_id = timeline_->reply().toStdString(); + timeline_->resetReply(); + } + if (timeline_) timeline_->sendMessage(emote); } @@ -259,8 +269,7 @@ TimelineViewManager::queueImageMessage(const QString &roomid, const QString &mime, uint64_t dsize, const QSize &dimensions, - const QString &blurhash, - const std::optional &related) + const QString &blurhash) { mtx::events::msg::Image image; image.info.mimetype = mime.toStdString(); @@ -272,10 +281,13 @@ TimelineViewManager::queueImageMessage(const QString &roomid, image.info.w = dimensions.width(); image.file = file; - if (related) - image.relates_to.in_reply_to.event_id = related->related_event; + auto model = models.value(roomid); + if (!model->reply().isEmpty()) { + image.relates_to.in_reply_to.event_id = model->reply().toStdString(); + model->resetReply(); + } - models.value(roomid)->sendMessage(image); + model->sendMessage(image); } void @@ -285,8 +297,7 @@ TimelineViewManager::queueFileMessage( const std::optional &encryptedFile, const QString &url, const QString &mime, - uint64_t dsize, - const std::optional &related) + uint64_t dsize) { mtx::events::msg::File file; file.info.mimetype = mime.toStdString(); @@ -295,10 +306,13 @@ TimelineViewManager::queueFileMessage( file.url = url.toStdString(); file.file = encryptedFile; - if (related) - file.relates_to.in_reply_to.event_id = related->related_event; + auto model = models.value(roomid); + if (!model->reply().isEmpty()) { + file.relates_to.in_reply_to.event_id = model->reply().toStdString(); + model->resetReply(); + } - models.value(roomid)->sendMessage(file); + model->sendMessage(file); } void @@ -307,8 +321,7 @@ TimelineViewManager::queueAudioMessage(const QString &roomid, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize, - const std::optional &related) + uint64_t dsize) { mtx::events::msg::Audio audio; audio.info.mimetype = mime.toStdString(); @@ -317,10 +330,13 @@ TimelineViewManager::queueAudioMessage(const QString &roomid, audio.url = url.toStdString(); audio.file = file; - if (related) - audio.relates_to.in_reply_to.event_id = related->related_event; + auto model = models.value(roomid); + if (!model->reply().isEmpty()) { + audio.relates_to.in_reply_to.event_id = model->reply().toStdString(); + model->resetReply(); + } - models.value(roomid)->sendMessage(audio); + model->sendMessage(audio); } void @@ -329,8 +345,7 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize, - const std::optional &related) + uint64_t dsize) { mtx::events::msg::Video video; video.info.mimetype = mime.toStdString(); @@ -339,8 +354,11 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, video.url = url.toStdString(); video.file = file; - if (related) - video.relates_to.in_reply_to.event_id = related->related_event; + auto model = models.value(roomid); + if (!model->reply().isEmpty()) { + video.relates_to.in_reply_to.event_id = model->reply().toStdString(); + model->resetReply(); + } - models.value(roomid)->sendMessage(video); + model->sendMessage(video); } diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 0c516e7f..122e4aec 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -26,8 +26,6 @@ class TimelineViewManager : public QObject TimelineModel *timeline MEMBER timeline_ READ activeTimeline NOTIFY activeTimelineChanged) Q_PROPERTY( bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged) - Q_PROPERTY(QString replyingEvent READ getReplyingEvent WRITE updateReplyingEvent NOTIFY - replyingEventChanged) public: TimelineViewManager(QSharedPointer userSettings, QWidget *parent = nullptr); @@ -52,26 +50,13 @@ signals: void replyClosed(); public slots: - void updateReplyingEvent(const QString &replyingEvent) - { - if (this->replyingEvent_ != replyingEvent) { - this->replyingEvent_ = replyingEvent; - emit replyingEventChanged(replyingEvent_); - } - } - void closeReply() - { - this->updateReplyingEvent(nullptr); - emit replyClosed(); - } - QString getReplyingEvent() const { return replyingEvent_; } void updateReadReceipts(const QString &room_id, const std::vector &event_ids); void initWithMessages(const std::map &msgs); void setHistoryView(const QString &room_id); void updateColorPalette(); - void queueTextMessage(const QString &msg, const std::optional &related); + void queueTextMessage(const QString &msg); void queueEmoteMessage(const QString &msg); void queueImageMessage(const QString &roomid, const QString &filename, @@ -80,29 +65,25 @@ public slots: const QString &mime, uint64_t dsize, const QSize &dimensions, - const QString &blurhash, - const std::optional &related); + const QString &blurhash); void queueFileMessage(const QString &roomid, const QString &filename, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize, - const std::optional &related); + uint64_t dsize); void queueAudioMessage(const QString &roomid, const QString &filename, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize, - const std::optional &related); + uint64_t dsize); void queueVideoMessage(const QString &roomid, const QString &filename, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize, - const std::optional &related); + uint64_t dsize); private: #ifdef USE_QUICK_VIEW @@ -119,7 +100,6 @@ private: QHash> models; TimelineModel *timeline_ = nullptr; bool isInitialSync_ = true; - QString replyingEvent_; QSharedPointer settings; QHash userColors;