diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts
index d7cb6bf..8a982f5 100644
--- a/resources/langs/nheko_de.ts
+++ b/resources/langs/nheko_de.ts
@@ -277,6 +277,11 @@
Raumthema wurde entfernt.
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
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 wurde eingeladen.
-
+
%1 hat den Anzeigenamen und Avatar geändert.
@@ -563,7 +613,7 @@
%1 hat den Raum betreten.
-
+
%1 hat die Einladung abgewiesen.
@@ -600,16 +650,21 @@
- 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 wurde gebannt.
+
+
+
-
+
+
+
+
+
+
%1 hat angeklopft.
diff --git a/resources/langs/nheko_el.ts b/resources/langs/nheko_el.ts
index 103312c..0398f06 100644
--- a/resources/langs/nheko_el.ts
+++ b/resources/langs/nheko_el.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
@@ -538,12 +543,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -563,7 +613,7 @@
-
+
@@ -600,16 +650,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/langs/nheko_en.ts b/resources/langs/nheko_en.ts
index d8e4bf7..638e0a8 100644
--- a/resources/langs/nheko_en.ts
+++ b/resources/langs/nheko_en.ts
@@ -277,6 +277,11 @@
removed topic
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
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 was invited.
-
+
%1 changed their display name and avatar.
@@ -563,7 +613,7 @@
%1 joined.
-
+
%1 rejected their invite.
@@ -600,16 +650,21 @@
- 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 knocked.
diff --git a/resources/langs/nheko_fi.ts b/resources/langs/nheko_fi.ts
index 1f3c226..bf7dd6f 100644
--- a/resources/langs/nheko_fi.ts
+++ b/resources/langs/nheko_fi.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
-- Salattu viesti (salauksen purkuavaimia ei löydetty) --
@@ -538,12 +543,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -563,7 +613,7 @@
-
+
@@ -600,16 +650,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts
index b5a8c99..19236b1 100644
--- a/resources/langs/nheko_fr.ts
+++ b/resources/langs/nheko_fr.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -475,7 +480,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
@@ -539,12 +544,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -564,7 +614,7 @@
-
+
@@ -601,16 +651,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/langs/nheko_ja.ts b/resources/langs/nheko_ja.ts
index 618d8cb..c0891f1 100644
--- a/resources/langs/nheko_ja.ts
+++ b/resources/langs/nheko_ja.ts
@@ -277,6 +277,11 @@
話題が削除されました
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
-- 暗号化イベント (復号鍵が見つかりません) --
@@ -537,12 +542,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
%1が招待されました。
-
+
%1が表示名とアバターを変更しました。
@@ -562,7 +612,7 @@
%1が参加しました。
-
+
%1が招待を拒否しました。
@@ -599,16 +649,21 @@
- 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が永久追放されました。
+
+
+
-
+
+
+
+
+
+
%1がノックしました。
diff --git a/resources/langs/nheko_nl.ts b/resources/langs/nheko_nl.ts
index aab1ed8..3cb64e6 100644
--- a/resources/langs/nheko_nl.ts
+++ b/resources/langs/nheko_nl.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
@@ -538,12 +543,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -563,7 +613,7 @@
-
+
@@ -600,16 +650,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/langs/nheko_pl.ts b/resources/langs/nheko_pl.ts
index 48d4111..f6764e8 100644
--- a/resources/langs/nheko_pl.ts
+++ b/resources/langs/nheko_pl.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
@@ -539,12 +544,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -564,7 +614,7 @@
-
+
@@ -601,16 +651,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/langs/nheko_ru.ts b/resources/langs/nheko_ru.ts
index 494dfb9..a2c8c95 100644
--- a/resources/langs/nheko_ru.ts
+++ b/resources/langs/nheko_ru.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
@@ -539,12 +544,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -564,7 +614,7 @@
-
+
@@ -601,16 +651,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/langs/nheko_zh_CN.ts b/resources/langs/nheko_zh_CN.ts
index fa96344..0ed3153 100644
--- a/resources/langs/nheko_zh_CN.ts
+++ b/resources/langs/nheko_zh_CN.ts
@@ -277,6 +277,11 @@
+
+
+
+
+
Placeholder
@@ -474,7 +479,7 @@
TimelineModel
-
+
Placeholder, when the message was not decrypted yet or can't be decrypted
@@ -537,12 +542,57 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -562,7 +612,7 @@
-
+
@@ -599,16 +649,21 @@
- 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
-
-
+
+
-
+
+
+
+
+
+
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index ab63308..daeb61d 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 cad39bc..2c03937 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 f06de5d..15111f0 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;