diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index 212c2970..e6bc61b0 100644
--- a/src/EventAccessors.cpp
+++ b/src/EventAccessors.cpp
@@ -34,6 +34,20 @@ struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
template<template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
+struct IsStateEvent
+{
+ template<class T>
+ bool operator()(const mtx::events::StateEvent<T> &)
+ {
+ return true;
+ }
+ template<class T>
+ bool operator()(const mtx::events::Event<T> &)
+ {
+ return false;
+ }
+};
+
struct EventMsgType
{
template<class E>
@@ -476,3 +490,9 @@ mtx::accessors::serialize_event(const mtx::events::collections::TimelineEvents &
{
return std::visit([](const auto &e) { return nlohmann::json(e); }, event);
}
+
+bool
+mtx::accessors::is_state_event(const mtx::events::collections::TimelineEvents &event)
+{
+ return std::visit(IsStateEvent{}, event);
+}
diff --git a/src/EventAccessors.h b/src/EventAccessors.h
index 95e5df24..7bf695fc 100644
--- a/src/EventAccessors.h
+++ b/src/EventAccessors.h
@@ -17,6 +17,9 @@ room_id(const mtx::events::collections::TimelineEvents &event);
std::string
sender(const mtx::events::collections::TimelineEvents &event);
+bool
+is_state_event(const mtx::events::collections::TimelineEvents &event);
+
QDateTime
origin_server_ts(const mtx::events::collections::TimelineEvents &event);
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index e5a66e19..94d43a83 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -774,15 +774,17 @@ EventStore::get(std::string_view id, std::string_view related_to, bool decrypt,
if (id.empty())
return nullptr;
- std::string id_ = std::string(id);
+ IdIndex index{room_id_, std::string(id)};
if (resolve_edits) {
- auto edits_ = edits(id_);
- if (!edits_.empty())
- id_ = mtx::accessors::event_id(edits_.back());
+ auto edits_ = edits(index.id);
+ if (!edits_.empty()) {
+ index.id = mtx::accessors::event_id(edits_.back());
+ auto event_ptr =
+ new mtx::events::collections::TimelineEvents(std::move(edits_.back()));
+ events_by_id_.insert(index, event_ptr);
+ }
}
- IdIndex index{room_id_, id_};
-
auto event_ptr = events_by_id_.object(index);
if (!event_ptr) {
auto event = cache::client()->getEvent(room_id_, index.id);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index c47194f5..dd4f8696 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -288,6 +288,8 @@ TimelineModel::roleNames() const
{ProportionalHeight, "proportionalHeight"},
{Id, "id"},
{State, "state"},
+ {IsEdited, "isEdited"},
+ {IsEditable, "isEditable"},
{IsEncrypted, "isEncrypted"},
{IsRoomEncrypted, "isRoomEncrypted"},
{ReplyTo, "replyTo"},
@@ -409,8 +411,12 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
return QVariant(prop > 0 ? prop : 1.);
}
- case Id:
- return QVariant(QString::fromStdString(event_id(event)));
+ case Id: {
+ if (auto replaces = relations(event).replaces())
+ return QVariant(QString::fromStdString(replaces.value()));
+ else
+ return QVariant(QString::fromStdString(event_id(event)));
+ }
case State: {
auto id = QString::fromStdString(event_id(event));
auto containsOthers = [](const auto &vec) {
@@ -430,6 +436,11 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
else
return qml_mtx_events::Received;
}
+ case IsEdited:
+ return QVariant(relations(event).replaces().has_value());
+ case IsEditable:
+ return QVariant(!is_state_event(event) && mtx::accessors::sender(event) ==
+ http::client()->user_id().to_string());
case IsEncrypted: {
auto id = event_id(event);
auto encrypted_event = events.get(id, id, false);
@@ -444,7 +455,7 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
case ReplyTo:
return QVariant(QString::fromStdString(relations(event).reply_to().value_or("")));
case Reactions: {
- auto id = event_id(event);
+ auto id = relations(event).replaces().value_or(event_id(event));
return QVariant::fromValue(events.reactions(id));
}
case RoomId:
@@ -813,6 +824,12 @@ TimelineModel::replyAction(QString id)
setReply(id);
}
+void
+TimelineModel::editAction(QString id)
+{
+ setEdit(id);
+}
+
RelatedInfo
TimelineModel::relatedInfo(QString id)
{
@@ -1501,6 +1518,22 @@ TimelineModel::formatMemberEvent(QString id)
return rendered;
}
+void
+TimelineModel::setEdit(QString newEdit)
+{
+ if (edit_ != newEdit) {
+ edit_ = newEdit;
+ emit editChanged(edit_);
+
+ auto ev = events.get(newEdit.toStdString(), "");
+ if (ev) {
+ setReply(QString::fromStdString(
+ mtx::accessors::relations(*ev).reply_to().value_or("")));
+ // input()->setText(mtx::accessors::body(*ev));
+ }
+ }
+}
+
QString
TimelineModel::roomName() const
{
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 51b8049e..463d8705 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -145,6 +145,7 @@ class TimelineModel : public QAbstractListModel
Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
typingUsersChanged)
Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply)
+ Q_PROPERTY(QString edit READ edit WRITE setEdit NOTIFY editChanged RESET resetEdit)
Q_PROPERTY(
bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged)
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
@@ -181,6 +182,8 @@ public:
ProportionalHeight,
Id,
State,
+ IsEdited,
+ IsEditable,
IsEncrypted,
IsRoomEncrypted,
ReplyTo,
@@ -213,6 +216,7 @@ public:
Q_INVOKABLE void viewRawMessage(QString id) const;
Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
Q_INVOKABLE void openUserProfile(QString userid, bool global = false);
+ Q_INVOKABLE void editAction(QString id);
Q_INVOKABLE void replyAction(QString id);
Q_INVOKABLE void readReceiptsAction(QString id) const;
Q_INVOKABLE void redactEvent(QString id);
@@ -268,6 +272,16 @@ public slots:
emit replyChanged(reply_);
}
}
+ QString edit() const { return edit_; }
+ void setEdit(QString newEdit);
+ void resetEdit()
+ {
+ if (!edit_.isEmpty()) {
+ edit_ = "";
+ emit editChanged(edit_);
+ resetReply();
+ }
+ }
void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
void clearTimeline() { events.clearTimeline(); }
void receivedSessionKey(const std::string &session_key)
@@ -292,6 +306,7 @@ signals:
void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo);
void typingUsersChanged(std::vector<QString> users);
void replyChanged(QString reply);
+ void editChanged(QString reply);
void paginationInProgressChanged(const bool);
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
@@ -322,7 +337,7 @@ private:
bool m_paginationInProgress = false;
QString currentId;
- QString reply_;
+ QString reply_, edit_;
std::vector<QString> typingUsers_;
TimelineViewManager *manager_;
|