From a1c97fc8d6e6f835aab79e2f8e37ce8488bcb5b6 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Mon, 9 Sep 2019 21:42:33 +0200 Subject: [PATCH] Show redactions in qml timeline --- resources/qml/TimelineView.qml | 3 +- resources/qml/delegates/Redacted.qml | 15 ++++++ resources/res.qrc | 1 + src/timeline2/TimelineModel.cpp | 79 ++++++++++++++++++++-------- src/timeline2/TimelineModel.h | 3 ++ 5 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 resources/qml/delegates/Redacted.qml diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 36701c72..5c96ff18 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -23,7 +23,7 @@ Rectangle { ListView { id: chat - cacheBuffer: 4*parent.height + cacheBuffer: parent.height visible: timelineManager.timeline != null anchors.fill: parent @@ -65,6 +65,7 @@ Rectangle { case MtxEvent.TextMessage: return "delegates/TextMessage.qml" case MtxEvent.ImageMessage: return "delegates/ImageMessage.qml" case MtxEvent.VideoMessage: return "delegates/VideoMessage.qml" + case MtxEvent.Redacted: return "delegates/Redacted.qml" default: return "delegates/placeholder.qml" } property variant eventData: model diff --git a/resources/qml/delegates/Redacted.qml b/resources/qml/delegates/Redacted.qml new file mode 100644 index 00000000..53e95a83 --- /dev/null +++ b/resources/qml/delegates/Redacted.qml @@ -0,0 +1,15 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.5 + +Label { + text: qsTr("redacted") + color: inactiveColors.text + horizontalAlignment: Text.AlignHCenter + + height: contentHeight * 1.2 + width: contentWidth * 1.2 + background: Rectangle { + radius: parent.height / 2 + color: colors.dark + } +} diff --git a/resources/res.qrc b/resources/res.qrc index 62ed53e5..0d55e70d 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -120,5 +120,6 @@ qml/delegates/TextMessage.qml qml/delegates/NoticeMessage.qml qml/delegates/ImageMessage.qml + qml/delegates/Redacted.qml diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp index 54f03b56..f544c83c 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp @@ -1,5 +1,6 @@ #include "TimelineModel.h" +#include #include #include @@ -160,6 +161,12 @@ toRoomEventType(const mtx::events::Event &) { return qml_mtx_events::EventType::VideoMessage; } + +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::Redacted; +} // ::EventType::Type toRoomEventType(const Event &e) { return // ::EventType::LocationMessage; } @@ -319,19 +326,9 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) if (timeline.events.empty()) return; - std::vector ids; - for (const auto &e : timeline.events) { - QString id = - boost::apply_visitor([](const auto &e) -> QString { return eventId(e); }, e); + std::vector ids = internalAddEvents(timeline.events); - if (this->events.contains(id)) - continue; - - this->events.insert(id, e); - ids.push_back(id); - } - - if (ids.empty) + if (ids.empty()) return; beginInsertRows(QModelIndex(), @@ -341,6 +338,52 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) endInsertRows(); } +std::vector +TimelineModel::internalAddEvents( + const std::vector &timeline) +{ + std::vector ids; + for (const auto &e : timeline) { + QString id = + boost::apply_visitor([](const auto &e) -> QString { return eventId(e); }, e); + + if (this->events.contains(id)) + continue; + + if (auto redaction = + boost::get>(&e)) { + QString redacts = QString::fromStdString(redaction->redacts); + auto redacted = std::find(eventOrder.begin(), eventOrder.end(), redacts); + + if (redacted != eventOrder.end()) { + auto redactedEvent = boost::apply_visitor( + [](const auto &ev) + -> mtx::events::RoomEvent { + mtx::events::RoomEvent + replacement = {}; + replacement.event_id = ev.event_id; + replacement.room_id = ev.room_id; + replacement.sender = ev.sender; + replacement.origin_server_ts = ev.origin_server_ts; + replacement.type = ev.type; + return replacement; + }, + e); + events.insert(redacts, redactedEvent); + + int row = (int)std::distance(eventOrder.begin(), redacted); + emit dataChanged(index(row, 0), index(row, 0)); + } + + continue; // don't insert redaction into timeline + } + + this->events.insert(id, e); + ids.push_back(id); + } + return ids; +} + void TimelineModel::fetchHistory() { @@ -373,17 +416,7 @@ TimelineModel::fetchHistory() void TimelineModel::addBackwardsEvents(const mtx::responses::Messages &msgs) { - std::vector ids; - for (const auto &e : msgs.chunk) { - QString id = - boost::apply_visitor([](const auto &e) -> QString { return eventId(e); }, e); - - if (this->events.contains(id)) - continue; - - this->events.insert(id, e); - ids.push_back(id); - } + std::vector ids = internalAddEvents(msgs.chunk); if (!ids.empty()) { beginInsertRows(QModelIndex(), 0, static_cast(ids.size() - 1)); diff --git a/src/timeline2/TimelineModel.h b/src/timeline2/TimelineModel.h index d63ed818..ca8d4ad6 100644 --- a/src/timeline2/TimelineModel.h +++ b/src/timeline2/TimelineModel.h @@ -61,6 +61,7 @@ enum EventType NoticeMessage, TextMessage, VideoMessage, + Redacted, UnknownMessage, }; Q_ENUM_NS(EventType) @@ -124,6 +125,8 @@ signals: private: DecryptionResult decryptEvent( const mtx::events::EncryptedEvent &e) const; + std::vector internalAddEvents( + const std::vector &timeline); QHash events; std::vector eventOrder;