diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 23a9ed25..f4d454a0 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -46,10 +46,10 @@ set(BOOST_SHA256 set( MTXCLIENT_URL - https://github.com/Nheko-Reborn/mtxclient/archive/9fda08b222dc4f9f59da18ed8370698643131cdd.zip + https://github.com/Nheko-Reborn/mtxclient/archive/6d2a02b6079c9d888c28cd24504618aaadb7fa97.zip ) set(MTXCLIENT_HASH - 9a9da7a9e0ede51d36238b54be03782892d47233a1ba2ce7d36614ad2ed6a6c1) + 30811e076ee1fee22ba5d5d92c94a5425ff714a7ccb245ff4ac64fecb04dc539) set( TWEENY_URL https://github.com/mobius3/tweeny/archive/b94ce07cfb02a0eb8ac8aaf66137dabdaea857cf.tar.gz diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index ad07efdd..777709be 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -56,6 +56,7 @@ constexpr int RETRY_TIMEOUT = 5'000; constexpr size_t MAX_ONETIME_KEYS = 50; Q_DECLARE_METATYPE(std::optional) +Q_DECLARE_METATYPE(std::optional) ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) : QWidget(parent) @@ -65,8 +66,8 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) { setObjectName("chatPage"); - qRegisterMetaType>( - "std::optional"); + qRegisterMetaType>(); + qRegisterMetaType>(); topLayout_ = new QHBoxLayout(this); topLayout_->setSpacing(0); @@ -287,19 +288,14 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) SLOT(showUnreadMessageNotification(int))); connect(text_input_, - SIGNAL(sendTextMessage(const QString &)), + &TextInputWidget::sendTextMessage, view_manager_, - SLOT(queueTextMessage(const QString &))); + &TimelineViewManager::queueTextMessage); connect(text_input_, - SIGNAL(sendReplyMessage(const QString &, const RelatedInfo &)), + &TextInputWidget::sendEmoteMessage, view_manager_, - SLOT(queueReplyMessage(const QString &, const RelatedInfo &))); - - connect(text_input_, - SIGNAL(sendEmoteMessage(const QString &)), - view_manager_, - SLOT(queueEmoteMessage(const QString &))); + &TimelineViewManager::queueEmoteMessage); connect(text_input_, &TextInputWidget::sendJoinRoomRequest, this, &ChatPage::joinRoom); @@ -307,7 +303,10 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) text_input_, &TextInputWidget::uploadMedia, this, - [this](QSharedPointer dev, QString mimeClass, const QString &fn) { + [this](QSharedPointer dev, + QString mimeClass, + const QString &fn, + const std::optional &related) { QMimeDatabase db; QMimeType mime = db.mimeTypeForData(dev.data()); @@ -341,7 +340,8 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) mimeClass, mime = mime.name(), size = payload.size(), - dimensions](const mtx::responses::ContentURI &res, mtx::http::RequestErr err) { + dimensions, + related](const mtx::responses::ContentURI &res, mtx::http::RequestErr err) { if (err) { emit uploadFailed( tr("Failed to upload media. Please try again.")); @@ -359,7 +359,8 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) mimeClass, mime, size, - dimensions); + dimensions, + related); }); }); @@ -367,35 +368,37 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) text_input_->hideUploadSpinner(); emit showNotification(msg); }); - connect(this, - &ChatPage::mediaUploaded, - this, - [this](QString roomid, - QString filename, - std::optional encryptedFile, - QString url, - QString mimeClass, - QString mime, - qint64 dsize, - QSize dimensions) { - text_input_->hideUploadSpinner(); + connect( + this, + &ChatPage::mediaUploaded, + this, + [this](QString roomid, + QString filename, + std::optional encryptedFile, + QString url, + QString mimeClass, + QString mime, + qint64 dsize, + QSize dimensions, + const std::optional &related) { + text_input_->hideUploadSpinner(); - if (encryptedFile) - encryptedFile->url = url.toStdString(); + if (encryptedFile) + encryptedFile->url = url.toStdString(); - if (mimeClass == "image") - view_manager_->queueImageMessage( - roomid, filename, encryptedFile, url, mime, dsize, dimensions); - else if (mimeClass == "audio") - view_manager_->queueAudioMessage( - roomid, filename, encryptedFile, url, mime, dsize); - else if (mimeClass == "video") - view_manager_->queueVideoMessage( - roomid, filename, encryptedFile, url, mime, dsize); - else - view_manager_->queueFileMessage( - roomid, filename, encryptedFile, url, mime, dsize); - }); + if (mimeClass == "image") + view_manager_->queueImageMessage( + roomid, filename, encryptedFile, url, mime, dsize, dimensions, related); + else if (mimeClass == "audio") + view_manager_->queueAudioMessage( + roomid, filename, encryptedFile, url, mime, dsize, related); + else if (mimeClass == "video") + view_manager_->queueVideoMessage( + roomid, filename, encryptedFile, url, mime, dsize, related); + else + view_manager_->queueFileMessage( + roomid, filename, encryptedFile, url, mime, dsize, related); + }); connect(room_list_, &RoomList::roomAvatarChanged, this, &ChatPage::updateTopBarAvatar); diff --git a/src/ChatPage.h b/src/ChatPage.h index 9e88dcc6..e4c0ef16 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -109,7 +109,8 @@ signals: const QString &mimeClass, const QString &mime, qint64 dsize, - const QSize &dimensions); + const QSize &dimensions, + const std::optional &related); void contentLoaded(); void closing(); diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp index b481a57c..b6b51980 100644 --- a/src/TextInputWidget.cpp +++ b/src/TextInputWidget.cpp @@ -419,33 +419,25 @@ FilteredTextEdit::submit() auto name = text.mid(1, command_end - 1); auto args = text.mid(command_end + 1); if (name.isEmpty() || name == "/") { - if (!related_.related_event.empty()) { - reply(args, related_); - } else { - message(args); - } + message(args, related); } else { command(name, args); } } else { - if (!related_.related_event.empty()) { - reply(std::move(text), std::move(related_)); - } else { - message(std::move(text)); - } + message(std::move(text), std::move(related)); } - related_ = {}; + related = {}; clear(); } void -FilteredTextEdit::showReplyPopup(const RelatedInfo &related) +FilteredTextEdit::showReplyPopup(const RelatedInfo &related_) { QPoint pos = viewport()->mapToGlobal(this->pos()); - replyPopup_.setReplyContent(related); + replyPopup_.setReplyContent(related_); replyPopup_.move(pos.x(), pos.y() - replyPopup_.height() - 10); replyPopup_.setFixedWidth(this->parentWidget()->width()); replyPopup_.show(); @@ -467,7 +459,9 @@ FilteredTextEdit::uploadData(const QByteArray data, emit startedUpload(); - emit media(buffer, mediaType, filename); + emit media(buffer, mediaType, filename, related); + related = {}; + closeReply(); } void @@ -573,7 +567,6 @@ TextInputWidget::TextInputWidget(QWidget *parent) connect(sendMessageBtn_, &FlatButton::clicked, input_, &FilteredTextEdit::submit); connect(sendFileBtn_, SIGNAL(clicked()), this, SLOT(openFileSelection())); connect(input_, &FilteredTextEdit::message, this, &TextInputWidget::sendTextMessage); - connect(input_, &FilteredTextEdit::reply, this, &TextInputWidget::sendReplyMessage); connect(input_, &FilteredTextEdit::command, this, &TextInputWidget::command); connect(input_, &FilteredTextEdit::media, this, &TextInputWidget::uploadMedia); connect(emojiBtn_, @@ -609,14 +602,16 @@ void TextInputWidget::command(QString command, QString args) { if (command == "me") { - sendEmoteMessage(args); + sendEmoteMessage(args, input_->related); } else if (command == "join") { sendJoinRoomRequest(args); } else if (command == "shrug") { - sendTextMessage("¯\\_(ツ)_/¯"); + sendTextMessage("¯\\_(ツ)_/¯", input_->related); } else if (command == "fliptable") { - sendTextMessage("(╯°□°)╯︵ ┻━┻"); + sendTextMessage("(╯°□°)╯︵ ┻━┻", input_->related); } + + input_->related = std::nullopt; } void @@ -635,7 +630,9 @@ TextInputWidget::openFileSelection() QSharedPointer file{new QFile{fileName, this}}; - emit uploadMedia(file, format, fileName); + emit uploadMedia(file, format, fileName, input_->related); + input_->related = {}; + input_->closeReply(); showUploadSpinner(); } @@ -691,5 +688,5 @@ TextInputWidget::addReply(const RelatedInfo &related) auto cursor = input_->textCursor(); cursor.movePosition(QTextCursor::End); input_->setTextCursor(cursor); - input_->setRelated(related); + input_->related = related; } diff --git a/src/TextInputWidget.h b/src/TextInputWidget.h index d498be72..6641d97c 100644 --- a/src/TextInputWidget.h +++ b/src/TextInputWidget.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -52,18 +53,27 @@ public: QSize minimumSizeHint() const override; void submit(); - void setRelated(const RelatedInfo &related) { related_ = related; } - void showReplyPopup(const RelatedInfo &related); + 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); - void reply(QString, const RelatedInfo &); + void message(QString, const std::optional &); void command(QString name, QString args); - void media(QSharedPointer data, QString mimeClass, const QString &filename); + void media(QSharedPointer data, + QString mimeClass, + const QString &filename, + const std::optional &related); //! Trigger the suggestion popup. void showSuggestions(const QString &query); @@ -93,9 +103,6 @@ private: SuggestionsPopup suggestionsPopup_; ReplyPopup replyPopup_; - // Used for replies - RelatedInfo related_; - enum class AnchorType { Tab = 0, @@ -107,11 +114,6 @@ private: int anchorWidth(AnchorType anchor) { return static_cast(anchor); } void closeSuggestions() { suggestionsPopup_.hide(); } - void closeReply() - { - replyPopup_.hide(); - related_ = {}; - } void resetAnchor() { atTriggerPosition_ = -1; } bool isAnchorValid() { return atTriggerPosition_ != -1; } bool hasAnchor(int pos, AnchorType anchor) @@ -171,14 +173,14 @@ private slots: void addSelectedEmoji(const QString &emoji); signals: - void sendTextMessage(QString msg); - void sendReplyMessage(QString msg, const RelatedInfo &related); - void sendEmoteMessage(QString msg); + void sendTextMessage(const QString &msg, const std::optional &related); + void sendEmoteMessage(QString msg, const std::optional &related); void heightChanged(int height); void uploadMedia(const QSharedPointer data, QString mimeClass, - const QString &filename); + const QString &filename, + const std::optional &related); void sendJoinRoomRequest(const QString &room); @@ -196,9 +198,6 @@ private: QHBoxLayout *topLayout_; FilteredTextEdit *input_; - // Used for replies - QString related_event_; - LoadingIndicator *spinner_; FlatButton *sendFileBtn_; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 8cb204a6..cd2b4a7b 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -170,38 +170,30 @@ TimelineViewManager::initWithMessages(const std::map &related) { mtx::events::msg::Text text = {}; text.body = msg.trimmed().toStdString(); text.format = "org.matrix.custom.html"; text.formatted_body = utils::markdownToHtml(msg).toStdString(); - if (timeline_) - timeline_->sendMessage(text); -} - -void -TimelineViewManager::queueReplyMessage(const QString &reply, const RelatedInfo &related) -{ - mtx::events::msg::Text text = {}; - - QString body; - bool firstLine = true; - for (const auto &line : related.quoted_body.split("\n")) { - if (firstLine) { - firstLine = false; - body = QString("> <%1> %2\n").arg(related.quoted_user).arg(line); - } else { - body = QString("%1\n> %2\n").arg(body).arg(line); + if (related) { + QString body; + bool firstLine = true; + for (const auto &line : related->quoted_body.split("\n")) { + if (firstLine) { + firstLine = false; + body = QString("> <%1> %2\n").arg(related->quoted_user).arg(line); + } else { + body = QString("%1\n> %2\n").arg(body).arg(line); + } } - } - text.body = QString("%1\n%2").arg(body).arg(reply).toStdString(); - text.format = "org.matrix.custom.html"; - text.formatted_body = - utils::getFormattedQuoteBody(related, utils::markdownToHtml(reply)).toStdString(); - text.relates_to.in_reply_to.event_id = related.related_event; + text.body = QString("%1\n%2").arg(body).arg(msg).toStdString(); + text.formatted_body = + utils::getFormattedQuoteBody(*related, utils::markdownToHtml(msg)).toStdString(); + text.relates_to.in_reply_to.event_id = related->related_event; + } if (timeline_) timeline_->sendMessage(text); @@ -229,7 +221,8 @@ TimelineViewManager::queueImageMessage(const QString &roomid, const QString &url, const QString &mime, uint64_t dsize, - const QSize &dimensions) + const QSize &dimensions, + const std::optional &related) { mtx::events::msg::Image image; image.info.mimetype = mime.toStdString(); @@ -239,6 +232,10 @@ TimelineViewManager::queueImageMessage(const QString &roomid, image.info.h = dimensions.height(); image.info.w = dimensions.width(); image.file = file; + + if (related) + image.relates_to.in_reply_to.event_id = related->related_event; + models.value(roomid)->sendMessage(image); } @@ -249,7 +246,8 @@ TimelineViewManager::queueFileMessage( const std::optional &encryptedFile, const QString &url, const QString &mime, - uint64_t dsize) + uint64_t dsize, + const std::optional &related) { mtx::events::msg::File file; file.info.mimetype = mime.toStdString(); @@ -257,6 +255,10 @@ TimelineViewManager::queueFileMessage( file.body = filename.toStdString(); file.url = url.toStdString(); file.file = encryptedFile; + + if (related) + file.relates_to.in_reply_to.event_id = related->related_event; + models.value(roomid)->sendMessage(file); } @@ -266,7 +268,8 @@ TimelineViewManager::queueAudioMessage(const QString &roomid, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize) + uint64_t dsize, + const std::optional &related) { mtx::events::msg::Audio audio; audio.info.mimetype = mime.toStdString(); @@ -274,6 +277,10 @@ TimelineViewManager::queueAudioMessage(const QString &roomid, audio.body = filename.toStdString(); audio.url = url.toStdString(); audio.file = file; + + if (related) + audio.relates_to.in_reply_to.event_id = related->related_event; + models.value(roomid)->sendMessage(audio); } @@ -283,7 +290,8 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize) + uint64_t dsize, + const std::optional &related) { mtx::events::msg::Video video; video.info.mimetype = mime.toStdString(); @@ -291,5 +299,9 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, video.body = filename.toStdString(); video.url = url.toStdString(); video.file = file; + + if (related) + video.relates_to.in_reply_to.event_id = related->related_event; + models.value(roomid)->sendMessage(video); } diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 587aa14e..63075649 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -51,8 +51,7 @@ public slots: void setHistoryView(const QString &room_id); void updateColorPalette(); - void queueTextMessage(const QString &msg); - void queueReplyMessage(const QString &reply, const RelatedInfo &related); + void queueTextMessage(const QString &msg, const std::optional &related); void queueEmoteMessage(const QString &msg); void queueImageMessage(const QString &roomid, const QString &filename, @@ -60,25 +59,29 @@ public slots: const QString &url, const QString &mime, uint64_t dsize, - const QSize &dimensions); + const QSize &dimensions, + const std::optional &related); void queueFileMessage(const QString &roomid, const QString &filename, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize); + uint64_t dsize, + const std::optional &related); void queueAudioMessage(const QString &roomid, const QString &filename, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize); + uint64_t dsize, + const std::optional &related); void queueVideoMessage(const QString &roomid, const QString &filename, const std::optional &file, const QString &url, const QString &mime, - uint64_t dsize); + uint64_t dsize, + const std::optional &related); private: #ifdef USE_QUICK_VIEW