diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml
index 03ed1a8d34dd747b1a3ad35f926d3b1bd43bac7b..aef05a639c5b4b2d16f20b544ba29106c7200b3b 100644
--- a/resources/qml/MessageView.qml
+++ b/resources/qml/MessageView.qml
@@ -252,7 +252,7 @@ ScrollView {
                 topPadding: 4
                 bottomPadding: 4
                 spacing: 8
-                visible: (previousMessageUserId !== userId || previousMessageDay !== day || previousMessageIsStateEvent) && !isStateEvent
+                visible: (previousMessageUserId !== userId || previousMessageDay !== day || isStateEvent !== previousMessageIsStateEvent)
                 width: parentWidth
                 height: ((previousMessageDay !== day) ? dateBubble.height : 0) + (isStateEvent? 0 : userName.height +8 )
 
@@ -278,6 +278,7 @@ ScrollView {
                 Row {
                     height: userName_.height
                     spacing: 8
+                    visible: !isStateEvent
 
                     Avatar {
                         id: messageUserAvatar
@@ -289,7 +290,7 @@ ScrollView {
                         userid: userId
                         onClicked: room.openUserProfile(userId)
                         ToolTip.visible: avatarHover.hovered
-                    ToolTip.delay: Nheko.tooltipDelay
+                        ToolTip.delay: Nheko.tooltipDelay
                         ToolTip.text: userid
 
                         HoverHandler {
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index aef69ba445f786b35044aa633f7b149a660e3dde..58f12c9150b671816601c0d3594d2596ca4a71bd 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -186,7 +186,7 @@ Item {
             roleValue: MtxEvent.Redaction
 
             Pill {
-                text: qsTr("removed")
+                text: qsTr("%1 removed a message").arg(d.userName)
                 isStateEvent: d.isStateEvent
             }
 
@@ -196,7 +196,7 @@ Item {
             roleValue: MtxEvent.Encryption
 
             Pill {
-                text: qsTr("Encryption enabled")
+                text: qsTr("%1 enabled encryption").arg(d.userName)
                 isStateEvent: d.isStateEvent
             }
 
@@ -220,7 +220,7 @@ Item {
                 isOnlyEmoji: false
                 isReply: d.isReply
                 isStateEvent: d.isStateEvent
-                formatted: d.roomName ? qsTr("room name changed to: %1").arg(d.roomName) : qsTr("removed room name")
+                formatted: d.roomName ? qsTr("%2 changed the room name to: %1").arg(d.roomName).arg(d.userName) : qsTr("%1 removed the room name").arg(d.userName)
             }
 
         }
@@ -233,7 +233,7 @@ Item {
                 isOnlyEmoji: false
                 isReply: d.isReply
                 isStateEvent: d.isStateEvent
-                formatted: d.roomTopic ? qsTr("topic changed to: %1").arg(d.roomTopic) : qsTr("removed topic")
+                formatted: d.roomTopic ? qsTr("%2 changed the topic to: %1").arg(d.roomTopic).arg(d.userName): qsTr("%1 removed the topic").arg(d.userName)
             }
 
         }
@@ -372,7 +372,7 @@ Item {
                 isOnlyEmoji: false
                 isReply: d.isReply
                 isStateEvent: d.isStateEvent
-                formatted: qsTr("Negotiating call...")
+                formatted: qsTr("% is negotiating the call...").arg(d.userName)
             }
 
         }
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 6b380f79ad7c17044200f43be8ad61f34c6ecc8f..dfd06f0bad308bee39079d2ed6e88cf906bf0817 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -453,6 +453,7 @@ TimelineModel::roleNames() const
       {UserId, "userId"},
       {UserName, "userName"},
       {PreviousMessageDay, "previousMessageDay"},
+      {PreviousMessageIsStateEvent, "previousMessageIsStateEvent"},
       {Day, "day"},
       {Timestamp, "timestamp"},
       {Url, "url"},
@@ -469,6 +470,7 @@ TimelineModel::roleNames() const
       {IsEdited, "isEdited"},
       {IsEditable, "isEditable"},
       {IsEncrypted, "isEncrypted"},
+      {IsStateEvent, "isStateEvent"},
       {Trustlevel, "trustlevel"},
       {EncryptionError, "encryptionError"},
       {ReplyTo, "replyTo"},
@@ -666,6 +668,9 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
                std::holds_alternative<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
                  *encrypted_event);
     }
+    case IsStateEvent: {
+        return is_state_event(event);
+    }
 
     case Trustlevel: {
         auto encrypted_event = events.get(event_id(event), "", false);
@@ -730,6 +735,7 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
         m.insert(names[IsEdited], data(event, static_cast<int>(IsEdited)));
         m.insert(names[IsEditable], data(event, static_cast<int>(IsEditable)));
         m.insert(names[IsEncrypted], data(event, static_cast<int>(IsEncrypted)));
+        m.insert(names[IsStateEvent], data(event, static_cast<int>(IsStateEvent)));
         m.insert(names[ReplyTo], data(event, static_cast<int>(ReplyTo)));
         m.insert(names[RoomName], data(event, static_cast<int>(RoomName)));
         m.insert(names[RoomTopic], data(event, static_cast<int>(RoomTopic)));
@@ -762,7 +768,8 @@ TimelineModel::data(const QModelIndex &index, int role) const
     if (!event)
         return "";
 
-    if (role == PreviousMessageDay || role == PreviousMessageUserId) {
+    if (role == PreviousMessageDay || role == PreviousMessageUserId ||
+        role == PreviousMessageIsStateEvent) {
         int prevIdx = rowCount() - index.row() - 2;
         if (prevIdx < 0)
             return {};
@@ -771,8 +778,10 @@ TimelineModel::data(const QModelIndex &index, int role) const
             return {};
         if (role == PreviousMessageUserId)
             return data(*tempEv, UserId);
-        else
+        else if (role == PreviousMessageDay)
             return data(*tempEv, Day);
+        else
+            return data(*tempEv, IsStateEvent);
     }
 
     return data(*event, role);
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 556f9f54cccc58889f7c4548f6bf335795143b4c..c50a2c06b5e211b8093108811fa559ef7a3c6fee 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -205,6 +205,7 @@ public:
         UserId,
         UserName,
         PreviousMessageDay,
+        PreviousMessageIsStateEvent,
         Day,
         Timestamp,
         Url,
@@ -221,6 +222,7 @@ public:
         IsEdited,
         IsEditable,
         IsEncrypted,
+        IsStateEvent,
         Trustlevel,
         EncryptionError,
         ReplyTo,