diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml
index 51275f4e6ad7dc783931a92f6870d3cd1ac3d038..b40ce0687d022a7d5dd27ea3bba235e88d5154eb 100644
--- a/resources/qml/TimelineRow.qml
+++ b/resources/qml/TimelineRow.qml
@@ -102,7 +102,7 @@ Item {
                 left: parent.left
                 top: parent.top
             }
-            property bool narrowLayout: (r.width < 500) && Settings.bubbles
+            property bool narrowLayout: Settings.bubbles //&& (timelineView.width < 500) // timelineView causes fewew binding loops than r. But maybe it shouldn't depend on width anyway
             rowSpacing: 0
             columnSpacing: 2
             columns: narrowLayout? 1 : 2
@@ -142,6 +142,7 @@ Item {
                 callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? ""
                 encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? ""
                 relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0
+                maxWidth: row.maxWidth
             }
 
             // actual message content
@@ -173,6 +174,7 @@ Item {
                 encryptionError: r.encryptionError
                 relatedEventCacheBuster: r.relatedEventCacheBuster
                 isReply: false
+                maxWidth: row.maxWidth
             }
 
             RowLayout {
diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml
index f1fd07b909316b9081c20ac61496ae84586720c7..2ac2a80adda02cd6393d5716284003c962932219 100644
--- a/resources/qml/delegates/FileMessage.qml
+++ b/resources/qml/delegates/FileMessage.qml
@@ -11,9 +11,11 @@ Item {
     required property string eventId
     required property string filename
     required property string filesize
+    property int maxWidth
 
     height: row.height + 24
-    width: parent.width
+    width: maxWidth
+    implicitWidth: maxWidth
 
     RowLayout {
         id: row
diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml
index da15bdfea81d9dbf783e581c73b21b19031e5886..3bbcd077f30c1e653d9cb5298102098f28f615ca 100644
--- a/resources/qml/delegates/ImageMessage.qml
+++ b/resources/qml/delegates/ImageMessage.qml
@@ -17,13 +17,16 @@ Item {
     required property string filename
     required property bool isReply
     required property string eventId
-    property double tempWidth: Math.min(parent.width, originalWidth < 1 ? 200 : originalWidth)
+    property int maxWidth
+    property double tempWidth: Math.min(maxWidth, originalWidth < 1 ? 200 : originalWidth)
     property double tempHeight: tempWidth * proportionalHeight
     property double divisor: isReply ? 5 : 3
     property bool tooHigh: tempHeight > timelineView.height / divisor
 
     height: Math.round(tooHigh ? timelineView.height / divisor : tempHeight)
     width: Math.round(tooHigh ? (timelineView.height / divisor) / proportionalHeight : tempWidth)
+    implicitHeight: height
+    implicitWidth: width
 
     Image {
         id: blurhash_
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index 0cec51bc3f63ab70d7c08c6d42061cc03b482205..5d98784177b02845f211a677740116026ace2638 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -13,7 +13,7 @@ Item {
 
     required property bool isReply
     property alias child: chooser.child
-    implicitWidth: (chooser.child && chooser.child.implicitWidth) ? chooser.child.implicitWidth : width
+    implicitWidth: (chooser.child && chooser.child.implicitWidth) ? chooser.child.implicitWidth : 0
     required property double proportionalHeight
     required property int type
     required property string typeString
@@ -35,6 +35,7 @@ Item {
     required property string callType
     required property int encryptionError
     required property int relatedEventCacheBuster
+    property int maxWidth
 
     Layout.preferredHeight: chooser.child ? chooser.child.height : Nheko.paddingLarge
 
@@ -110,6 +111,7 @@ Item {
                 filename: d.filename
                 isReply: d.isReply
                 eventId: d.eventId
+                maxWidth: d.maxWidth
             }
 
         }
@@ -127,6 +129,7 @@ Item {
                 filename: d.filename
                 isReply: d.isReply
                 eventId: d.eventId
+                maxWidth: d.maxWidth
             }
 
         }
@@ -138,6 +141,7 @@ Item {
                 eventId: d.eventId
                 filename: d.filename
                 filesize: d.filesize
+                maxWidth: d.maxWidth
             }
 
         }
@@ -154,6 +158,7 @@ Item {
                 url: d.url
                 body: d.body
                 filesize: d.filesize
+                maxWidth: d.maxWidth
             }
 
         }
@@ -170,6 +175,7 @@ Item {
                 url: d.url
                 body: d.body
                 filesize: d.filesize
+                maxWidth: d.maxWidth
             }
 
         }
@@ -372,7 +378,7 @@ Item {
                 isOnlyEmoji: false
                 isReply: d.isReply
                 isStateEvent: d.isStateEvent
-                formatted: qsTr("% is negotiating the call...").arg(d.userName)
+                formatted: qsTr("%1 is negotiating the call...").arg(d.userName)
             }
 
         }
diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml
index 389d18145fc022e72f7d65d4ad6ae79e0d0b74a1..805eafbfcc71c728d94d99e1ff6075b00583df7b 100644
--- a/resources/qml/delegates/PlayableMediaMessage.qml
+++ b/resources/qml/delegates/PlayableMediaMessage.qml
@@ -22,13 +22,16 @@ Item {
     required property string url
     required property string body
     required property string filesize
-    property double tempWidth: Math.min(parent.width, originalWidth < 1 ? 400 : originalWidth)
+    property int maxWidth
+    property double tempWidth: Math.min(maxWidth, originalWidth < 1 ? 400 : originalWidth)
     property double tempHeight: tempWidth * proportionalHeight
     property double divisor: isReply ? 4 : 2
     property bool tooHigh: tempHeight > timelineRoot.height / divisor
 
     height: (type == MtxEvent.VideoMessage ? tooHigh ? timelineRoot.height / divisor : tempHeight : 80) + fileInfoLabel.height
     width: type == MtxEvent.VideoMessage ? tooHigh ? (timelineRoot.height / divisor) / proportionalHeight : tempWidth : 250
+    implicitHeight: height
+    implicitWidth: width
 
     MxcMedia {
         id: mxcmedia
diff --git a/resources/qml/delegates/Redacted.qml b/resources/qml/delegates/Redacted.qml
index 10b9217380f32860f9f789cc0fe4cb9c01d9ca56..b0c9abfef3607944e7a8538c2cbb7bb71db06b12 100644
--- a/resources/qml/delegates/Redacted.qml
+++ b/resources/qml/delegates/Redacted.qml
@@ -13,6 +13,7 @@ Rectangle{
     required property real delegateWidth
     height: redactedLayout.implicitHeight + Nheko.paddingSmall
     width: redactedLayout.implicitWidth + 2 * Nheko.paddingMedium
+    implicitWidth: width
     radius: fontMetrics.lineSpacing / 2 + 2 * Nheko.paddingSmall
     color: Nheko.colors.alternateBase
 
diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml
index 7c8bccce0aeb0aa6539422ba030546a9ca3d089f..28f0dd21973d9d023fcb0dae77b66b678923d036 100644
--- a/resources/qml/delegates/Reply.qml
+++ b/resources/qml/delegates/Reply.qml
@@ -35,6 +35,7 @@ Item {
     property string callType
     property int encryptionError
     property int relatedEventCacheBuster
+    property int maxWidth
 
     Layout.preferredHeight: replyContainer.height
     height: replyContainer.height
@@ -124,6 +125,7 @@ Item {
             enabled: false
             Layout.fillWidth: true
             isReply: true
+            maxWidth: r.maxWidth-4
         }
 
     }