diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 6e653f10..371e9f58 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -154,13 +154,25 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
connect(this, &TimelineModel::messageSent, this, [this](QString txn_id, QString event_id) {
pending.removeOne(txn_id);
+ auto ev = events.value(txn_id);
+
+ if (auto reaction =
+ std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(&ev)) {
+ QString reactedTo =
+ QString::fromStdString(reaction->content.relates_to.event_id);
+ auto &rModel = reactions[reactedTo];
+ rModel.removeReaction(*reaction);
+ auto rCopy = *reaction;
+ rCopy.event_id = event_id.toStdString();
+ rModel.addReaction(room_id_.toStdString(), rCopy);
+ }
+
int idx = idToIndex(txn_id);
if (idx < 0) {
// transaction already received via sync
return;
}
eventOrder[idx] = event_id;
- auto ev = events.value(txn_id);
ev = std::visit(
[event_id](const auto &e) -> mtx::events::collections::TimelineEvents {
auto eventCopy = e;
@@ -362,7 +374,7 @@ TimelineModel::data(const QString &id, int role) const
else
return {};
case RoomId:
- return QVariant(QString::fromStdString(room_id(event)));
+ return QVariant(room_id_);
case RoomName:
return QVariant(QString::fromStdString(room_name(event)));
case RoomTopic:
@@ -665,6 +677,14 @@ TimelineModel::internalAddEvents(
QString reactedTo =
QString::fromStdString(reaction->content.relates_to.event_id);
events.insert(id, e);
+
+ // remove local echo
+ if (!txid.isEmpty()) {
+ auto rCopy = *reaction;
+ rCopy.event_id = txid.toStdString();
+ reactions[reactedTo].removeReaction(rCopy);
+ }
+
reactions[reactedTo].addReaction(room_id_.toStdString(), *reaction);
int idx = idToIndex(reactedTo);
if (idx >= 0)
@@ -924,6 +944,13 @@ TimelineModel::decryptEvent(const mtx::events::EncryptedEvent<mtx::events::msg::
}
void
+TimelineModel::reactAction(QString id)
+{
+ setReaction(id);
+ ChatPage::instance()->reactMessage(id);
+}
+
+void
TimelineModel::replyAction(QString id)
{
setReply(id);
@@ -1337,10 +1364,11 @@ struct SendMessageVisitor
, model_(model)
{}
+ // Do-nothing operator for all unhandled events
template<typename T>
void operator()(const mtx::events::Event<T> &)
{}
-
+ // Operator for m.room.message events that contain a msgtype in their content
template<typename T,
std::enable_if_t<std::is_same<decltype(T::msgtype), std::string>::value, int> = 0>
void operator()(const mtx::events::RoomEvent<T> &msg)
@@ -1377,6 +1405,36 @@ struct SendMessageVisitor
}
}
+ // Special operator for reactions, which are a type of m.room.message, but need to be
+ // handled distinctly for their differences from normal room messages. Specifically,
+ // reactions need to have the relation outside of ciphertext, or synapse / the homeserver
+ // cannot handle it correctly. See the MSC for more details:
+ // https://github.com/matrix-org/matrix-doc/blob/matthew/msc1849/proposals/1849-aggregations.md#end-to-end-encryption
+ void operator()(const mtx::events::RoomEvent<mtx::events::msg::Reaction> &msg)
+
+ {
+ QString txn_id_qstr = txn_id_qstr_;
+ TimelineModel *model = model_;
+ http::client()
+ ->send_room_message<mtx::events::msg::Reaction, mtx::events::EventType::Reaction>(
+ model->room_id_.toStdString(),
+ txn_id_qstr.toStdString(),
+ msg.content,
+ [txn_id_qstr, model](const mtx::responses::EventId &res,
+ mtx::http::RequestErr err) {
+ if (err) {
+ const int status_code = static_cast<int>(err->status_code);
+ nhlog::net()->warn("[{}] failed to send message: {} {}",
+ txn_id_qstr.toStdString(),
+ err->matrix_error.error,
+ status_code);
+ emit model->messageFailed(txn_id_qstr);
+ }
+ emit model->messageSent(
+ txn_id_qstr, QString::fromStdString(res.event_id.to_string()));
+ });
+ }
+
QString txn_id_qstr_;
TimelineModel *model_;
};
@@ -1408,10 +1466,12 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event)
internalAddEvents({event});
QString txn_id_qstr = QString::fromStdString(mtx::accessors::event_id(event));
- beginInsertRows(QModelIndex(), 0, 0);
pending.push_back(txn_id_qstr);
- this->eventOrder.insert(this->eventOrder.begin(), txn_id_qstr);
- endInsertRows();
+ if (!std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(&event)) {
+ beginInsertRows(QModelIndex(), 0, 0);
+ this->eventOrder.insert(this->eventOrder.begin(), txn_id_qstr);
+ endInsertRows();
+ }
updateLastMessage();
emit nextPendingMessage();
|