Show redactions in qml timeline

This commit is contained in:
Nicolas Werner 2019-09-09 21:42:33 +02:00
parent 4efac5a247
commit a1c97fc8d6
5 changed files with 77 additions and 24 deletions

View file

@ -23,7 +23,7 @@ Rectangle {
ListView { ListView {
id: chat id: chat
cacheBuffer: 4*parent.height cacheBuffer: parent.height
visible: timelineManager.timeline != null visible: timelineManager.timeline != null
anchors.fill: parent anchors.fill: parent
@ -65,6 +65,7 @@ Rectangle {
case MtxEvent.TextMessage: return "delegates/TextMessage.qml" case MtxEvent.TextMessage: return "delegates/TextMessage.qml"
case MtxEvent.ImageMessage: return "delegates/ImageMessage.qml" case MtxEvent.ImageMessage: return "delegates/ImageMessage.qml"
case MtxEvent.VideoMessage: return "delegates/VideoMessage.qml" case MtxEvent.VideoMessage: return "delegates/VideoMessage.qml"
case MtxEvent.Redacted: return "delegates/Redacted.qml"
default: return "delegates/placeholder.qml" default: return "delegates/placeholder.qml"
} }
property variant eventData: model property variant eventData: model

View file

@ -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
}
}

View file

@ -120,5 +120,6 @@
<file>qml/delegates/TextMessage.qml</file> <file>qml/delegates/TextMessage.qml</file>
<file>qml/delegates/NoticeMessage.qml</file> <file>qml/delegates/NoticeMessage.qml</file>
<file>qml/delegates/ImageMessage.qml</file> <file>qml/delegates/ImageMessage.qml</file>
<file>qml/delegates/Redacted.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -1,5 +1,6 @@
#include "TimelineModel.h" #include "TimelineModel.h"
#include <algorithm>
#include <type_traits> #include <type_traits>
#include <QRegularExpression> #include <QRegularExpression>
@ -160,6 +161,12 @@ toRoomEventType(const mtx::events::Event<mtx::events::msg::Video> &)
{ {
return qml_mtx_events::EventType::VideoMessage; return qml_mtx_events::EventType::VideoMessage;
} }
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Redacted> &)
{
return qml_mtx_events::EventType::Redacted;
}
// ::EventType::Type toRoomEventType(const Event<mtx::events::msg::Location> &e) { return // ::EventType::Type toRoomEventType(const Event<mtx::events::msg::Location> &e) { return
// ::EventType::LocationMessage; } // ::EventType::LocationMessage; }
@ -319,19 +326,9 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
if (timeline.events.empty()) if (timeline.events.empty())
return; return;
std::vector<QString> ids; std::vector<QString> ids = internalAddEvents(timeline.events);
for (const auto &e : timeline.events) {
QString id =
boost::apply_visitor([](const auto &e) -> QString { return eventId(e); }, e);
if (this->events.contains(id)) if (ids.empty())
continue;
this->events.insert(id, e);
ids.push_back(id);
}
if (ids.empty)
return; return;
beginInsertRows(QModelIndex(), beginInsertRows(QModelIndex(),
@ -341,6 +338,52 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
endInsertRows(); endInsertRows();
} }
std::vector<QString>
TimelineModel::internalAddEvents(
const std::vector<mtx::events::collections::TimelineEvents> &timeline)
{
std::vector<QString> 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<mtx::events::RedactionEvent<mtx::events::msg::Redaction>>(&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::msg::Redacted> {
mtx::events::RoomEvent<mtx::events::msg::Redacted>
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 void
TimelineModel::fetchHistory() TimelineModel::fetchHistory()
{ {
@ -373,17 +416,7 @@ TimelineModel::fetchHistory()
void void
TimelineModel::addBackwardsEvents(const mtx::responses::Messages &msgs) TimelineModel::addBackwardsEvents(const mtx::responses::Messages &msgs)
{ {
std::vector<QString> ids; std::vector<QString> ids = internalAddEvents(msgs.chunk);
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);
}
if (!ids.empty()) { if (!ids.empty()) {
beginInsertRows(QModelIndex(), 0, static_cast<int>(ids.size() - 1)); beginInsertRows(QModelIndex(), 0, static_cast<int>(ids.size() - 1));

View file

@ -61,6 +61,7 @@ enum EventType
NoticeMessage, NoticeMessage,
TextMessage, TextMessage,
VideoMessage, VideoMessage,
Redacted,
UnknownMessage, UnknownMessage,
}; };
Q_ENUM_NS(EventType) Q_ENUM_NS(EventType)
@ -124,6 +125,8 @@ signals:
private: private:
DecryptionResult decryptEvent( DecryptionResult decryptEvent(
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e) const; const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e) const;
std::vector<QString> internalAddEvents(
const std::vector<mtx::events::collections::TimelineEvents> &timeline);
QHash<QString, mtx::events::collections::TimelineEvents> events; QHash<QString, mtx::events::collections::TimelineEvents> events;
std::vector<QString> eventOrder; std::vector<QString> eventOrder;