diff --git a/CMakeLists.txt b/CMakeLists.txt index 05436a37..86a4a656 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,6 +287,7 @@ qt5_wrap_cpp(MOC_HEADERS src/dialogs/LeaveRoom.h src/dialogs/Logout.h src/dialogs/UserProfile.h + src/dialogs/RawMessage.h src/dialogs/ReadReceipts.h src/dialogs/ReCaptcha.h src/dialogs/RoomSettings.h diff --git a/src/MatrixClient.cpp b/src/MatrixClient.cpp index 8d9361af..12d7ac91 100644 --- a/src/MatrixClient.cpp +++ b/src/MatrixClient.cpp @@ -31,6 +31,7 @@ init() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType>(); qRegisterMetaType>("std::map"); diff --git a/src/MatrixClient.h b/src/MatrixClient.h index f0aca5c4..981c6b1c 100644 --- a/src/MatrixClient.h +++ b/src/MatrixClient.h @@ -4,6 +4,7 @@ #include #include +#include "json.hpp" #include #include @@ -15,6 +16,7 @@ Q_DECLARE_METATYPE(mtx::responses::Sync) Q_DECLARE_METATYPE(mtx::responses::JoinedGroups) Q_DECLARE_METATYPE(mtx::responses::GroupProfile) Q_DECLARE_METATYPE(std::string) +Q_DECLARE_METATYPE(nlohmann::json) Q_DECLARE_METATYPE(std::vector) Q_DECLARE_METATYPE(std::vector) diff --git a/src/dialogs/RawMessage.h b/src/dialogs/RawMessage.h new file mode 100644 index 00000000..5a7335f4 --- /dev/null +++ b/src/dialogs/RawMessage.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "json.hpp" + +#include "Logging.h" +#include "MainWindow.h" +#include "ui/FlatButton.h" + +namespace dialogs { + +class RawMessage : public QWidget +{ + Q_OBJECT +public: + RawMessage(QString msg, QWidget *parent = nullptr) + : QWidget{parent} + { + QFont monospaceFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + + auto layout = new QVBoxLayout{this}; + auto viewer = new QTextBrowser{this}; + viewer->setFont(monospaceFont); + viewer->setText(msg); + + layout->setSpacing(0); + layout->setMargin(0); + layout->addWidget(viewer); + + setAutoFillBackground(true); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); + setAttribute(Qt::WA_DeleteOnClose, true); + + QSize winsize; + QPoint center; + + auto window = MainWindow::instance(); + if (window) { + winsize = window->frameGeometry().size(); + center = window->frameGeometry().center(); + + move(center.x() - (width() * 0.5), center.y() - (height() * 0.5)); + } else { + nhlog::ui()->warn("unable to retrieve MainWindow's size"); + } + + raise(); + show(); + } +}; +} // namespace dialogs diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp index a9739f3e..7409c5bd 100644 --- a/src/dialogs/RoomSettings.cpp +++ b/src/dialogs/RoomSettings.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -190,9 +191,7 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent) auto infoLabel = new QLabel(tr("Info").toUpper(), this); infoLabel->setFont(font); - QFont monospaceFont; - monospaceFont.setFamily("Courier New"); - monospaceFont.setStyleHint(QFont::Courier); + QFont monospaceFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); auto roomIdLabel = new QLabel(room_id, this); roomIdLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); diff --git a/src/timeline/TimelineItem.cpp b/src/timeline/TimelineItem.cpp index 8f44b7e8..5bec4458 100644 --- a/src/timeline/TimelineItem.cpp +++ b/src/timeline/TimelineItem.cpp @@ -34,6 +34,8 @@ #include "timeline/widgets/ImageItem.h" #include "timeline/widgets/VideoItem.h" +#include "dialogs/RawMessage.h" + constexpr int MSG_RIGHT_MARGIN = 7; constexpr int MSG_PADDING = 20; @@ -185,8 +187,10 @@ TimelineItem::init() contextMenu_ = new QMenu(this); showReadReceipts_ = new QAction("Read receipts", this); markAsRead_ = new QAction("Mark as read", this); + viewRawMessage_ = new QAction("View raw message", this); redactMsg_ = new QAction("Redact message", this); contextMenu_->addAction(showReadReceipts_); + contextMenu_->addAction(viewRawMessage_); contextMenu_->addAction(markAsRead_); contextMenu_->addAction(redactMsg_); @@ -218,7 +222,8 @@ TimelineItem::init() }); }); - connect(markAsRead_, &QAction::triggered, this, [this]() { sendReadReceipt(); }); + connect(markAsRead_, &QAction::triggered, this, &TimelineItem::sendReadReceipt); + connect(viewRawMessage_, &QAction::triggered, this, &TimelineItem::openRawMessageViewer); topLayout_ = new QHBoxLayout(this); mainLayout_ = new QVBoxLayout; @@ -816,3 +821,37 @@ TimelineItem::sendReadReceipt() const } }); } + +void +TimelineItem::openRawMessageViewer() const +{ + const auto event_id = event_id_.toStdString(); + const auto room_id = room_id_.toStdString(); + + auto proxy = std::make_shared(); + connect(proxy.get(), &EventProxy::eventRetrieved, this, [](const nlohmann::json &obj) { + auto dialog = new dialogs::RawMessage{QString::fromStdString(obj.dump(4))}; + Q_UNUSED(dialog); + }); + + http::client()->get_event( + room_id, + event_id, + [event_id, room_id, proxy = std::move(proxy)]( + const mtx::events::collections::TimelineEvents &res, mtx::http::RequestErr err) { + using namespace mtx::events; + + if (err) { + nhlog::net()->warn( + "failed to retrieve event {} from {}", event_id, room_id); + return; + } + + try { + emit proxy->eventRetrieved(utils::serialize_event(res)); + } catch (const nlohmann::json::exception &e) { + nhlog::net()->warn( + "failed to serialize event ({}, {})", room_id, event_id); + } + }); +} diff --git a/src/timeline/TimelineItem.h b/src/timeline/TimelineItem.h index 26bcfbae..fb961b6c 100644 --- a/src/timeline/TimelineItem.h +++ b/src/timeline/TimelineItem.h @@ -88,6 +88,14 @@ private: static constexpr int MaxWidth = 24; }; +class EventProxy : public QObject +{ + Q_OBJECT + +signals: + void eventRetrieved(const nlohmann::json &); +}; + class TextLabel : public QTextBrowser { Q_OBJECT @@ -220,6 +228,7 @@ public: bool isReceived() { return isReceived_; }; void setRoomId(QString room_id) { room_id_ = room_id; } void sendReadReceipt() const; + void openRawMessageViewer() const; //! Add a user avatar for this event. void addAvatar(); @@ -273,6 +282,7 @@ private: QAction *showReadReceipts_; QAction *markAsRead_; QAction *redactMsg_; + QAction *viewRawMessage_; QAction *replyMsg_; QHBoxLayout *topLayout_ = nullptr;