diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts index d7cb6bfe..8a982f5e 100644 --- a/resources/langs/nheko_de.ts +++ b/resources/langs/nheko_de.ts @@ -277,6 +277,11 @@ removed topic Raumthema wurde entfernt. + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted -- verschlüsselter Event (keine Schlüssel zur Entschlüsselung gefunden) -- @@ -538,12 +543,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. %1 wurde eingeladen. - + %1 changed their display name and avatar. %1 hat den Anzeigenamen und Avatar geändert. @@ -563,7 +613,7 @@ %1 hat den Raum betreten. - + %1 rejected their invite. %1 hat die Einladung abgewiesen. @@ -600,16 +650,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets - %1 hat den Raum verlassen. + This is a leave event after the user already left and shouldn't happen apart from state resets + %1 hat den Raum verlassen. - - %1 was banned. - %1 wurde gebannt. + + %1 was banned + - + + Reason: %1 + + + + %1 knocked. %1 hat angeklopft. diff --git a/resources/langs/nheko_el.ts b/resources/langs/nheko_el.ts index 103312c5..0398f066 100644 --- a/resources/langs/nheko_el.ts +++ b/resources/langs/nheko_el.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted @@ -538,12 +543,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -563,7 +613,7 @@ - + %1 rejected their invite. @@ -600,16 +650,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/langs/nheko_en.ts b/resources/langs/nheko_en.ts index d8e4bf7e..638e0a89 100644 --- a/resources/langs/nheko_en.ts +++ b/resources/langs/nheko_en.ts @@ -277,6 +277,11 @@ removed topic removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted -- Encrypted Event (No keys found for decryption) -- @@ -538,12 +543,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. %1 was invited. - + %1 changed their display name and avatar. %1 changed their display name and avatar. @@ -563,7 +613,7 @@ %1 joined. - + %1 rejected their invite. %1 rejected their invite. @@ -600,16 +650,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets - %1 left after having already left! + This is a leave event after the user already left and shouldn't happen apart from state resets + %1 left after having already left! - - %1 was banned. - %1 was banned. + + %1 was banned + - + + Reason: %1 + + + + %1 knocked. %1 knocked. diff --git a/resources/langs/nheko_fi.ts b/resources/langs/nheko_fi.ts index 1f3c226c..bf7dd6f0 100644 --- a/resources/langs/nheko_fi.ts +++ b/resources/langs/nheko_fi.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted -- Salattu viesti (salauksen purkuavaimia ei löydetty) -- @@ -538,12 +543,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -563,7 +613,7 @@ - + %1 rejected their invite. @@ -600,16 +650,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index b5a8c99b..19236b11 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -475,7 +480,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted @@ -539,12 +544,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -564,7 +614,7 @@ - + %1 rejected their invite. @@ -601,16 +651,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/langs/nheko_ja.ts b/resources/langs/nheko_ja.ts index 618d8cb2..c0891f1f 100644 --- a/resources/langs/nheko_ja.ts +++ b/resources/langs/nheko_ja.ts @@ -277,6 +277,11 @@ removed topic 話題が削除されました + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted -- 暗号化イベント (復号鍵が見つかりません) -- @@ -537,12 +542,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. %1が招待されました。 - + %1 changed their display name and avatar. %1が表示名とアバターを変更しました。 @@ -562,7 +612,7 @@ %1が参加しました。 - + %1 rejected their invite. %1が招待を拒否しました。 @@ -599,16 +649,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets - 退出済みの%1が退出しました! + This is a leave event after the user already left and shouldn't happen apart from state resets + 退出済みの%1が退出しました! - - %1 was banned. - %1が永久追放されました。 + + %1 was banned + - + + Reason: %1 + + + + %1 knocked. %1がノックしました。 diff --git a/resources/langs/nheko_nl.ts b/resources/langs/nheko_nl.ts index aab1ed8d..3cb64e6c 100644 --- a/resources/langs/nheko_nl.ts +++ b/resources/langs/nheko_nl.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted @@ -538,12 +543,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -563,7 +613,7 @@ - + %1 rejected their invite. @@ -600,16 +650,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/langs/nheko_pl.ts b/resources/langs/nheko_pl.ts index 48d41117..f6764e82 100644 --- a/resources/langs/nheko_pl.ts +++ b/resources/langs/nheko_pl.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted @@ -539,12 +544,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -564,7 +614,7 @@ - + %1 rejected their invite. @@ -601,16 +651,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/langs/nheko_ru.ts b/resources/langs/nheko_ru.ts index 494dfb92..a2c8c951 100644 --- a/resources/langs/nheko_ru.ts +++ b/resources/langs/nheko_ru.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted @@ -539,12 +544,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -564,7 +614,7 @@ - + %1 rejected their invite. @@ -601,16 +651,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/langs/nheko_zh_CN.ts b/resources/langs/nheko_zh_CN.ts index fa963441..0ed3153e 100644 --- a/resources/langs/nheko_zh_CN.ts +++ b/resources/langs/nheko_zh_CN.ts @@ -277,6 +277,11 @@ removed topic + + + %1 created and configured room: %2 + + Placeholder @@ -474,7 +479,7 @@ TimelineModel - + -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted @@ -537,12 +542,57 @@ - + + %1 opened the room to the public + + + + + %1 made this room require and invitation to join + + + + + %1 made the room open to guests + + + + + %1 has closed the room to guest access + + + + + %1 made the room history world readable. Events may be now read by non-joined people + + + + + %1 set the room history visible to members from this point on + + + + + %1 set the room history visible to members since they were invited + + + + + %1 set the room history visible to members since they joined the room + + + + + %1 has changed the room's permissions. + + + + %1 was invited. - + %1 changed their display name and avatar. @@ -562,7 +612,7 @@ - + %1 rejected their invite. @@ -599,16 +649,21 @@ %1 left after having already left! - This is a leave event after the user already left and shouln't happen apart from state resets + This is a leave event after the user already left and shouldn't happen apart from state resets - - %1 was banned. + + %1 was banned - + + Reason: %1 + + + + %1 knocked. diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index ab633087..daeb61d6 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -81,6 +81,37 @@ Item { text: model.data.roomTopic ? qsTr("topic changed to: %1").arg(model.data.roomTopic) : qsTr("removed topic") } } + DelegateChoice { + roleValue: MtxEvent.RoomCreate + NoticeMessage { + text: qsTr("%1 created and configured room: %2").arg(model.data.userName).arg(model.data.roomId) + } + } + DelegateChoice { + // TODO: make a more complex formatter for the power levels. + roleValue: MtxEvent.PowerLevels + NoticeMessage { + text: timelineManager.timeline.formatPowerLevelEvent(model.data.id) + } + } + DelegateChoice { + roleValue: MtxEvent.RoomJoinRules + NoticeMessage { + text: timelineManager.timeline.formatJoinRuleEvent(model.data.id) + } + } + DelegateChoice { + roleValue: MtxEvent.RoomHistoryVisibility + NoticeMessage { + text: timelineManager.timeline.formatHistoryVisibilityEvent(model.data.id) + } + } + DelegateChoice { + roleValue: MtxEvent.RoomGuestAccess + NoticeMessage { + text: timelineManager.timeline.formatGuestAccessEvent(model.data.id) + } + } DelegateChoice { roleValue: MtxEvent.Member NoticeMessage { diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index cad39bc5..2c03937a 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -39,17 +39,17 @@ struct RoomEventType case EventType::RoomCanonicalAlias: return qml_mtx_events::EventType::CanonicalAlias; case EventType::RoomCreate: - return qml_mtx_events::EventType::Create; + return qml_mtx_events::EventType::RoomCreate; case EventType::RoomEncrypted: return qml_mtx_events::EventType::Encrypted; case EventType::RoomEncryption: return qml_mtx_events::EventType::Encryption; case EventType::RoomGuestAccess: - return qml_mtx_events::EventType::GuestAccess; + return qml_mtx_events::EventType::RoomGuestAccess; case EventType::RoomHistoryVisibility: - return qml_mtx_events::EventType::HistoryVisibility; + return qml_mtx_events::EventType::RoomHistoryVisibility; case EventType::RoomJoinRules: - return qml_mtx_events::EventType::JoinRules; + return qml_mtx_events::EventType::RoomJoinRules; case EventType::RoomMember: return qml_mtx_events::EventType::Member; case EventType::RoomMessage: @@ -222,6 +222,7 @@ TimelineModel::roleNames() const {State, "state"}, {IsEncrypted, "isEncrypted"}, {ReplyTo, "replyTo"}, + {RoomId, "roomId"}, {RoomName, "roomName"}, {RoomTopic, "roomTopic"}, {Dump, "dump"}, @@ -335,6 +336,8 @@ TimelineModel::data(const QString &id, int role) const } case ReplyTo: return QVariant(QString::fromStdString(in_reply_to_event(event))); + case RoomId: + return QVariant(QString::fromStdString(room_id(event))); case RoomName: return QVariant(QString::fromStdString(room_name(event))); case RoomTopic: @@ -1471,6 +1474,107 @@ TimelineModel::formatTypingUsers(const std::vector &users, QColor bg) return temp.arg(uidWithoutLast.join(", ")).arg(formatUser(users.back())); } +QString +TimelineModel::formatJoinRuleEvent(QString id) +{ + if (!events.contains(id)) + return ""; + + auto event = + std::get_if>(&events[id]); + if (!event) + return ""; + + QString user = QString::fromStdString(event->sender); + QString name = escapeEmoji(displayName(user)); + + switch (event->content.join_rule) { + case mtx::events::state::JoinRule::Public: + return tr("%1 opened the room to the public").arg(name); + case mtx::events::state::JoinRule::Invite: + return tr("%1 made this room require and invitation to join").arg(name); + default: + // Currently, knock and private are reserved keywords and not implemented in Matrix. + return ""; + } +} + +QString +TimelineModel::formatGuestAccessEvent(QString id) +{ + if (!events.contains(id)) + return ""; + + auto event = + std::get_if>(&events[id]); + if (!event) + return ""; + + QString user = QString::fromStdString(event->sender); + QString name = escapeEmoji(displayName(user)); + + switch (event->content.guest_access) { + case mtx::events::state::AccessState::CanJoin: + return tr("%1 made the room open to guests").arg(name); + case mtx::events::state::AccessState::Forbidden: + return tr("%1 has closed the room to guest access").arg(name); + default: + return ""; + } +} + +QString +TimelineModel::formatHistoryVisibilityEvent(QString id) +{ + if (!events.contains(id)) + return ""; + + auto event = + std::get_if>(&events[id]); + + if (!event) + return ""; + + QString user = QString::fromStdString(event->sender); + QString name = escapeEmoji(displayName(user)); + + switch (event->content.history_visibility) { + case mtx::events::state::Visibility::WorldReadable: + return tr("%1 made the room history world readable. Events may be now read by " + "non-joined people") + .arg(name); + case mtx::events::state::Visibility::Shared: + return tr("%1 set the room history visible to members from this point on") + .arg(name); + case mtx::events::state::Visibility::Invited: + return tr("%1 set the room history visible to members since they were invited") + .arg(name); + case mtx::events::state::Visibility::Joined: + return tr("%1 set the room history visible to members since they joined the room") + .arg(name); + default: + return ""; + } +} + +QString +TimelineModel::formatPowerLevelEvent(QString id) +{ + if (!events.contains(id)) + return ""; + + auto event = + std::get_if>(&events[id]); + if (!event) + return ""; + + QString user = QString::fromStdString(event->sender); + QString name = escapeEmoji(displayName(user)); + + // TODO: power levels rendering is actually a bit complex. work on this later. + return tr("%1 has changed the room's permissions.").arg(name); +} + QString TimelineModel::formatMemberEvent(QString id) { @@ -1510,12 +1614,14 @@ TimelineModel::formatMemberEvent(QString id) QString user = QString::fromStdString(event->state_key); QString name = escapeEmoji(displayName(user)); + QString rendered; // 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); + rendered = tr("%1 was invited.").arg(name); + break; case Membership::Join: if (prevEvent && prevEvent->content.membership == Membership::Join) { bool displayNameChanged = @@ -1524,47 +1630,57 @@ TimelineModel::formatMemberEvent(QString id) prevEvent->content.avatar_url != event->content.avatar_url; if (displayNameChanged && avatarChanged) - return tr("%1 changed their display name and avatar.").arg(name); + rendered = + tr("%1 changed their display name and avatar.").arg(name); else if (displayNameChanged) - return tr("%1 changed their display name.").arg(name); + rendered = tr("%1 changed their display name.").arg(name); else if (avatarChanged) - return tr("%1 changed their avatar.").arg(name); + rendered = 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 + } else { + rendered = tr("%1 joined.").arg(name); } - return tr("%1 joined.").arg(name); + break; 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); + rendered = tr("%1 rejected their invite.").arg(name); else - return tr("Revoked the invite to %1.").arg(name); + rendered = 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); + rendered = tr("%1 left the room.").arg(name); else - return tr("Kicked %1.").arg(name); + rendered = tr("Kicked %1.").arg(name); } else if (prevEvent->content.membership == Membership::Ban) { - return tr("Unbanned %1").arg(name); + rendered = 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); + rendered = tr("%1 redacted their knock.").arg(name); else - return tr("Rejected the knock from %1.").arg(name); + rendered = 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 " + "This is a leave event after the user already left and shouldn't " "happen apart from state resets") .arg(name); + break; case Membership::Ban: - return tr("%1 was banned.").arg(name); + rendered = tr("%1 was banned").arg(name); + break; case Membership::Knock: - return tr("%1 knocked.").arg(name); - default: - return ""; + rendered = tr("%1 knocked.").arg(name); + break; } + + if (event->content.reason != "") { + rendered += tr(" Reason: %1").arg(QString::fromStdString(event->content.reason)); + } + + return rendered; } diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index f06de5d9..15111f0a 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -35,17 +35,17 @@ enum EventType /// m.room.canonical_alias CanonicalAlias, /// m.room.create - Create, + RoomCreate, /// m.room.encrypted. Encrypted, /// m.room.encryption. Encryption, /// m.room.guest_access - GuestAccess, + RoomGuestAccess, /// m.room.history_visibility - HistoryVisibility, + RoomHistoryVisibility, /// m.room.join_rules - JoinRules, + RoomJoinRules, /// m.room.member Member, /// m.room.name @@ -152,6 +152,7 @@ public: State, IsEncrypted, ReplyTo, + RoomId, RoomName, RoomTopic, Dump, @@ -170,6 +171,10 @@ public: Q_INVOKABLE QString formatDateSeparator(QDate date) const; Q_INVOKABLE QString formatTypingUsers(const std::vector &users, QColor bg); Q_INVOKABLE QString formatMemberEvent(QString id); + Q_INVOKABLE QString formatJoinRuleEvent(QString id); + Q_INVOKABLE QString formatHistoryVisibilityEvent(QString id); + Q_INVOKABLE QString formatGuestAccessEvent(QString id); + Q_INVOKABLE QString formatPowerLevelEvent(QString id); Q_INVOKABLE QString escapeEmoji(QString str) const; Q_INVOKABLE void viewRawMessage(QString id) const;