diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 65a6e470..774e30da 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -189,7 +189,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
connect(this, &TimelineModel::newMessageToSend, this, &TimelineModel::addPendingMessage);
connect(this,
- &TimelineModel::replyFetched,
+ &TimelineModel::eventFetched,
this,
[this](QString requestingEvent, mtx::events::collections::TimelineEvents event) {
events.insert(QString::fromStdString(mtx::accessors::event_id(event)),
@@ -566,7 +566,7 @@ TimelineModel::internalAddEvents(
id.toStdString());
return;
}
- emit replyFetched(id, timeline);
+ emit eventFetched(id, timeline);
});
}
}
@@ -1442,3 +1442,101 @@ TimelineModel::formatTypingUsers(const std::vector<QString> &users, QColor bg)
return temp.arg(uidWithoutLast.join(", ")).arg(formatUser(users.back()));
}
+
+QString
+TimelineModel::formatMemberEvent(QString id)
+{
+ if (!events.contains(id))
+ return "";
+
+ auto event = std::get_if<mtx::events::StateEvent<mtx::events::state::Member>>(&events[id]);
+ if (!event)
+ return "";
+
+ mtx::events::StateEvent<mtx::events::state::Member> *prevEvent = nullptr;
+ QString prevEventId = QString::fromStdString(event->unsigned_data.replaces_state);
+ if (!prevEventId.isEmpty()) {
+ if (!events.contains(prevEventId)) {
+ http::client()->get_event(
+ this->room_id_.toStdString(),
+ event->unsigned_data.replaces_state,
+ [this, id, prevEventId](
+ const mtx::events::collections::TimelineEvents &timeline,
+ mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->error(
+ "Failed to retrieve event with id {}, which was "
+ "requested to show the membership for event {}",
+ prevEventId.toStdString(),
+ id.toStdString());
+ return;
+ }
+ emit eventFetched(id, timeline);
+ });
+ } else {
+ prevEvent =
+ std::get_if<mtx::events::StateEvent<mtx::events::state::Member>>(
+ &events[prevEventId]);
+ }
+ }
+
+ QString user = QString::fromStdString(event->state_key);
+ QString name = escapeEmoji(displayName(user));
+
+ // see table https://matrix.org/docs/spec/client_server/latest#m-room-member
+ using namespace mtx::events::state;
+ switch (event->content.membership) {
+ case Membership::Invite:
+ return tr("%1 was invited.").arg(name);
+ case Membership::Join:
+ if (prevEvent && prevEvent->content.membership == Membership::Join) {
+ bool displayNameChanged =
+ prevEvent->content.display_name != event->content.display_name;
+ bool avatarChanged =
+ prevEvent->content.avatar_url != event->content.avatar_url;
+
+ if (displayNameChanged && avatarChanged)
+ return tr("%1 changed their display name and avatar.").arg(name);
+ else if (displayNameChanged)
+ return tr("%1 changed their display name.").arg(name);
+ else if (avatarChanged)
+ return tr("%1 changed their avatar.").arg(name);
+ // the case of nothing changed but join follows join shouldn't happen, so
+ // just show it as join
+ }
+ return tr("%1 joined.").arg(name);
+ case Membership::Leave:
+ if (!prevEvent) // Should only ever happen temporarily
+ return "";
+
+ if (prevEvent->content.membership == Membership::Invite) {
+ if (event->state_key == event->sender)
+ return tr("%1 rejected their invite.").arg(name);
+ else
+ return tr("Revoked the invite to %1.").arg(name);
+ } else if (prevEvent->content.membership == Membership::Join) {
+ if (event->state_key == event->sender)
+ return tr("%1 left the room.").arg(name);
+ else
+ return tr("Kicked %1.").arg(name);
+ } else if (prevEvent->content.membership == Membership::Ban) {
+ return tr("Unbanned %1").arg(name);
+ } else if (prevEvent->content.membership == Membership::Knock) {
+ if (event->state_key == event->sender)
+ return tr("%1 redacted their knock.").arg(name);
+ else
+ return tr("Rejected the knock from %1.").arg(name);
+ } else
+ return tr("%1 left after having already left!",
+ "This is a leave event after the user already left and shouln't "
+ "happen apart from state resets")
+ .arg(name);
+
+ case Membership::Ban:
+ return tr("%1 was banned.").arg(name);
+ case Membership::Knock:
+ return tr("%1 knocked.").arg(name);
+ default:
+ return "";
+ }
+}
|