Merge pull request #611 from balsoft/allow-edits-of-pending-messages

Allow editing unsent messages
This commit is contained in:
DeepBlueV7.X 2021-06-19 20:27:53 +00:00 committed by GitHub
commit 57a9a1d0e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 7 deletions

View file

@ -1681,6 +1681,27 @@ Cache::storeEvent(const std::string &room_id,
txn.commit();
}
void
Cache::replaceEvent(const std::string &room_id,
const std::string &event_id,
const mtx::events::collections::TimelineEvent &event)
{
auto txn = lmdb::txn::begin(env_);
auto eventsDb = getEventsDb(txn, room_id);
auto relationsDb = getRelationsDb(txn, room_id);
auto event_json = mtx::accessors::serialize_event(event.data).dump();
{
eventsDb.del(txn, event_id);
eventsDb.put(txn, event_id, event_json);
for (auto relation : mtx::accessors::relations(event.data).relations) {
relationsDb.put(txn, relation.event_id, event_id);
}
}
txn.commit();
}
std::vector<std::string>
Cache::relatedEvents(const std::string &room_id, const std::string &event_id)
{

View file

@ -184,6 +184,9 @@ public:
void storeEvent(const std::string &room_id,
const std::string &event_id,
const mtx::events::collections::TimelineEvent &event);
void replaceEvent(const std::string &room_id,
const std::string &event_id,
const mtx::events::collections::TimelineEvent &event);
std::vector<std::string> relatedEvents(const std::string &room_id,
const std::string &event_id);

View file

@ -185,6 +185,48 @@ EventStore::EventStore(std::string room_id, QObject *)
[this](std::string txn_id, std::string event_id) {
nhlog::ui()->debug("sent {}", txn_id);
// Replace the event_id in pending edits/replies/redactions with the actual
// event_id of this event. This allows one to edit and reply to events that are
// currently pending.
// FIXME (introduced by balsoft): this doesn't work for encrypted events, but
// allegedly it's hard to fix so I'll leave my first contribution at that
for (auto related_event_id : cache::client()->relatedEvents(room_id_, txn_id)) {
if (cache::client()->getEvent(room_id_, related_event_id)) {
auto related_event =
cache::client()->getEvent(room_id_, related_event_id).value();
auto relations = mtx::accessors::relations(related_event.data);
// Replace the blockquote in fallback reply
auto related_text =
std::get_if<mtx::events::RoomEvent<mtx::events::msg::Text>>(
&related_event.data);
if (related_text && relations.reply_to() == txn_id) {
size_t index =
related_text->content.formatted_body.find(txn_id);
if (index != std::string::npos) {
related_text->content.formatted_body.replace(
index, event_id.length(), event_id);
}
}
for (mtx::common::Relation &rel : relations.relations) {
if (rel.event_id == txn_id)
rel.event_id = event_id;
}
mtx::accessors::set_relations(related_event.data, relations);
cache::client()->replaceEvent(
room_id_, related_event_id, related_event);
auto idx = idToIndex(related_event_id);
events_by_id_.remove({room_id_, related_event_id});
events_.remove({room_id_, toInternalIdx(*idx)});
}
}
http::client()->read_event(
room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
if (err) {
@ -193,6 +235,11 @@ EventStore::EventStore(std::string room_id, QObject *)
}
});
auto idx = idToIndex(event_id);
if (idx)
emit dataChanged(*idx, *idx);
cache::client()->removePendingStatus(room_id_, txn_id);
this->current_txn = "";
this->current_txn_error_count = 0;

View file

@ -375,6 +375,21 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
this->updateFlowEventId(event_id);
});
// When a message is sent, check if the current edit/reply relates to that message,
// and update the event_id so that it points to the sent message and not the pending one.
connect(&events,
&EventStore::messageSent,
this,
[this](std::string txn_id, std::string event_id) {
if (edit_.toStdString() == txn_id) {
edit_ = QString::fromStdString(event_id);
emit editChanged(edit_);
}
if (reply_.toStdString() == txn_id) {
reply_ = QString::fromStdString(event_id);
emit replyChanged(reply_);
}
});
showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent);
}
@ -568,10 +583,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
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() &&
!event_id(event).empty() && event_id(event).front() == '$');
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, "", false);
@ -1796,9 +1809,6 @@ TimelineModel::formatMemberEvent(QString id)
void
TimelineModel::setEdit(QString newEdit)
{
if (edit_.startsWith('m'))
return;
if (newEdit.isEmpty()) {
resetEdit();
return;