mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 11:00:48 +03:00
Merge pull request #611 from balsoft/allow-edits-of-pending-messages
Allow editing unsent messages
This commit is contained in:
commit
57a9a1d0e1
4 changed files with 88 additions and 7 deletions
|
@ -1681,6 +1681,27 @@ Cache::storeEvent(const std::string &room_id,
|
||||||
txn.commit();
|
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>
|
std::vector<std::string>
|
||||||
Cache::relatedEvents(const std::string &room_id, const std::string &event_id)
|
Cache::relatedEvents(const std::string &room_id, const std::string &event_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,6 +184,9 @@ public:
|
||||||
void storeEvent(const std::string &room_id,
|
void storeEvent(const std::string &room_id,
|
||||||
const std::string &event_id,
|
const std::string &event_id,
|
||||||
const mtx::events::collections::TimelineEvent &event);
|
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,
|
std::vector<std::string> relatedEvents(const std::string &room_id,
|
||||||
const std::string &event_id);
|
const std::string &event_id);
|
||||||
|
|
||||||
|
|
|
@ -185,6 +185,48 @@ EventStore::EventStore(std::string room_id, QObject *)
|
||||||
[this](std::string txn_id, std::string event_id) {
|
[this](std::string txn_id, std::string event_id) {
|
||||||
nhlog::ui()->debug("sent {}", txn_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(
|
http::client()->read_event(
|
||||||
room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
|
room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
|
||||||
if (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);
|
cache::client()->removePendingStatus(room_id_, txn_id);
|
||||||
this->current_txn = "";
|
this->current_txn = "";
|
||||||
this->current_txn_error_count = 0;
|
this->current_txn_error_count = 0;
|
||||||
|
|
|
@ -375,6 +375,21 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
|
||||||
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
|
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
|
||||||
this->updateFlowEventId(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);
|
showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent);
|
||||||
}
|
}
|
||||||
|
@ -568,10 +583,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
|
||||||
case IsEdited:
|
case IsEdited:
|
||||||
return QVariant(relations(event).replaces().has_value());
|
return QVariant(relations(event).replaces().has_value());
|
||||||
case IsEditable:
|
case IsEditable:
|
||||||
return QVariant(!is_state_event(event) &&
|
return QVariant(!is_state_event(event) && mtx::accessors::sender(event) ==
|
||||||
mtx::accessors::sender(event) ==
|
http::client()->user_id().to_string());
|
||||||
http::client()->user_id().to_string() &&
|
|
||||||
!event_id(event).empty() && event_id(event).front() == '$');
|
|
||||||
case IsEncrypted: {
|
case IsEncrypted: {
|
||||||
auto id = event_id(event);
|
auto id = event_id(event);
|
||||||
auto encrypted_event = events.get(id, "", false);
|
auto encrypted_event = events.get(id, "", false);
|
||||||
|
@ -1796,9 +1809,6 @@ TimelineModel::formatMemberEvent(QString id)
|
||||||
void
|
void
|
||||||
TimelineModel::setEdit(QString newEdit)
|
TimelineModel::setEdit(QString newEdit)
|
||||||
{
|
{
|
||||||
if (edit_.startsWith('m'))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (newEdit.isEmpty()) {
|
if (newEdit.isEmpty()) {
|
||||||
resetEdit();
|
resetEdit();
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue