summary refs log tree commit diff
path: root/resources/qml/TimelineRow.qml
diff options
context:
space:
mode:
Diffstat (limited to 'resources/qml/TimelineRow.qml')
-rw-r--r--resources/qml/TimelineRow.qml358
1 files changed, 179 insertions, 179 deletions
diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml
index 07cb5ce2..a064bd15 100644
--- a/resources/qml/TimelineRow.qml
+++ b/resources/qml/TimelineRow.qml
@@ -13,72 +13,45 @@ import im.nheko 1.0
 AbstractButton {
     id: r
 
-    required property double proportionalHeight
-    required property int type
-    required property string typeString
-    required property int originalWidth
     required property string blurhash
     required property string body
-    required property string formattedBody
+    required property string callType
+    required property int duration
+    required property int encryptionError
     required property string eventId
     required property string filename
     required property string filesize
-    required property string url
-    required property string thumbnailUrl
-    required property bool isOnlyEmoji
-    required property bool isSender
-    required property bool isEncrypted
+    required property string formattedBody
+    required property int index
     required property bool isEditable
     required property bool isEdited
+    required property bool isEncrypted
+    required property bool isOnlyEmoji
+    required property bool isSender
     required property bool isStateEvent
+    required property int notificationlevel
+    required property int originalWidth
+    required property double proportionalHeight
+    required property var reactions
+    required property int relatedEventCacheBuster
     required property string replyTo
+    required property string roomName
+    required property string roomTopic
+    required property int status
     required property string threadId
+    required property string thumbnailUrl
+    required property var timestamp
+    required property int trustlevel
+    required property int type
+    required property string typeString
+    required property string url
     required property string userId
     required property string userName
-    required property string roomTopic
-    required property string roomName
-    required property string callType
-    required property var reactions
-    required property int trustlevel
-    required property int notificationlevel
-    required property int encryptionError
-    required property int duration
-    required property var timestamp
-    required property int status
-    required property int index
-    required property int relatedEventCacheBuster
 
+    height: row.height + (reactionRow.height > 0 ? reactionRow.height - 2 : 0) + unreadRow.height
     hoverEnabled: true
-
     width: parent.width
-    height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 )+unreadRow.height
-
-    Rectangle {
-        color: (Settings.messageHoverHighlight && hovered) ? palette.alternateBase : "transparent"
-        anchors.fill: parent
-        // this looks better without margins
-        TapHandler {
-            acceptedButtons: Qt.RightButton
-            onSingleTapped: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
-            gesturePolicy: TapHandler.ReleaseWithinBounds
-            acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
-        }
-    }
 
-
-    onPressAndHold: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
-    onDoubleClicked: room.reply = eventId
-
-    DragHandler {
-        id: draghandler
-        yAxis.enabled: false
-        xAxis.maximum: 100
-        xAxis.minimum: -100
-        onActiveChanged: {
-            if(!active && (x < -70 || x > 70))
-                room.reply = eventId
-        }
-    }
     states: State {
         name: "dragging"
         when: draghandler.active
@@ -86,265 +59,292 @@ AbstractButton {
     transitions: Transition {
         from: "dragging"
         to: ""
+
         PropertyAnimation {
-            target: r
-            properties: "x"
+            duration: 100
             easing.type: Easing.InOutQuad
+            properties: "x"
+            target: r
             to: 0
-            duration: 100
         }
     }
 
     onClicked: {
-        let link = contentItem.child.linkAt != undefined && contentItem.child.linkAt(pressX-row.x-msg.x, pressY-row.y-msg.y-contentItem.y);
+        let link = contentItem.child.linkAt != undefined && contentItem.child.linkAt(pressX - row.x - msg.x, pressY - row.y - msg.y - contentItem.y);
         if (link) {
-            Nheko.openLink(link)
+            Nheko.openLink(link);
         }
     }
+    onDoubleClicked: room.reply = eventId
+    onPressAndHold: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
+
+    Rectangle {
+        anchors.fill: parent
+        color: (Settings.messageHoverHighlight && hovered) ? palette.alternateBase : "transparent"
+
+        // this looks better without margins
+        TapHandler {
+            acceptedButtons: Qt.RightButton
+            acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
+            gesturePolicy: TapHandler.ReleaseWithinBounds
+
+            onSingleTapped: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
+        }
+    }
+    DragHandler {
+        id: draghandler
+
+        xAxis.maximum: 100
+        xAxis.minimum: -100
+        yAxis.enabled: false
 
+        onActiveChanged: {
+            if (!active && (x < -70 || x > 70))
+                room.reply = eventId;
+        }
+    }
     AbstractButton {
-        anchors.leftMargin: Settings.smallAvatars? 0 : (Nheko.avatarSize + 8) // align bubble with section header
+        ToolTip.delay: Nheko.tooltipDelay
+        ToolTip.text: qsTr("Part of a thread")
+        ToolTip.visible: hovered
         anchors.left: parent.left
+        anchors.leftMargin: Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8) // align bubble with section header
+        height: parent.height
         visible: threadId
         width: 4
-        height: parent.height
+
+        onClicked: room.thread = threadId
 
         Rectangle {
             id: threadLine
 
-            color: TimelineManager.userColor(threadId, palette.base)
             anchors.fill: parent
+            color: TimelineManager.userColor(threadId, palette.base)
         }
-
-        ToolTip.visible: hovered
-        ToolTip.delay: Nheko.tooltipDelay
-        ToolTip.text: qsTr("Part of a thread")
-        onClicked: room.thread = threadId
     }
-
     Rectangle {
         id: row
-        property bool bubbleOnRight : isSender && Settings.bubbles
-        anchors.leftMargin: (isStateEvent || Settings.smallAvatars? 0 : (Nheko.avatarSize + 8)) + (threadId ? 6 : 0) // align bubble with section header
-        anchors.left: (isStateEvent || bubbleOnRight) ? undefined : parent.left
-        anchors.right: (isStateEvent || !bubbleOnRight) ? undefined : parent.right
-        anchors.horizontalCenter: isStateEvent? parent.horizontalCenter : undefined
-        property int maxWidth: (parent.width-(Settings.smallAvatars || isStateEvent? 0 : Nheko.avatarSize+8))*(Settings.bubbles && !isStateEvent? 0.9 : 1)
-        width: Settings.bubbles? Math.min(maxWidth,Math.max(reply.implicitWidth+8,contentItem.implicitWidth+metadata.width+20)) : maxWidth
-        height: msg.height+msg.anchors.margins*2
 
-        property color userColor: TimelineManager.userColor(userId, palette.base)
         property color bgColor: palette.base
+        property bool bubbleOnRight: isSender && Settings.bubbles
+        property int maxWidth: (parent.width - (Settings.smallAvatars || isStateEvent ? 0 : Nheko.avatarSize + 8)) * (Settings.bubbles && !isStateEvent ? 0.9 : 1)
+        property color userColor: TimelineManager.userColor(userId, palette.base)
+
+        anchors.horizontalCenter: isStateEvent ? parent.horizontalCenter : undefined
+        anchors.left: (isStateEvent || bubbleOnRight) ? undefined : parent.left
+        anchors.leftMargin: (isStateEvent || Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8)) + (threadId ? 6 : 0) // align bubble with section header
+        anchors.right: (isStateEvent || !bubbleOnRight) ? undefined : parent.right
+        border.color: Nheko.theme.red
+        border.width: r.notificationlevel == MtxEvent.Highlight ? 1 : 0
         color: (Settings.bubbles && !isStateEvent) ? Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.2)) : "#00000000"
+        height: msg.height + msg.anchors.margins * 2
         radius: 4
-        border.width: r.notificationlevel == MtxEvent.Highlight ? 1 : 0
-        border.color: Nheko.theme.red
+        width: Settings.bubbles ? Math.min(maxWidth, Math.max(reply.implicitWidth + 8, contentItem.implicitWidth + metadata.width + 20)) : maxWidth
 
         GridLayout {
+            id: msg
+
+            columnSpacing: 2
+            columns: Settings.bubbles ? 1 : 2
+            rowSpacing: 0
+            rows: Settings.bubbles ? 3 : 2
+
             anchors {
                 left: parent.left
-                top: parent.top
-                right: parent.right
-                margins: (Settings.bubbles && ! isStateEvent)? 4 : 2
                 leftMargin: 4
+                margins: (Settings.bubbles && !isStateEvent) ? 4 : 2
+                right: parent.right
                 rightMargin: 4
+                top: parent.top
             }
-            id: msg
-            rowSpacing: 0
-            columnSpacing: 2
-            columns: Settings.bubbles? 1 : 2
-            rows: Settings.bubbles? 3 : 2
 
             // fancy reply, if this is a reply
             Reply {
-                Layout.row: 0
-                Layout.column: 0
-                Layout.fillWidth: true
-                Layout.maximumWidth: Settings.bubbles? Number.MAX_VALUE : implicitWidth
-                Layout.bottomMargin: visible? 2 : 0
-                Layout.preferredHeight: height
                 id: reply
 
                 function fromModel(role) {
                     return replyTo != "" ? room.dataById(replyTo, role, r.eventId) : null;
                 }
-                visible: replyTo
-                userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, palette.base)
+
+                Layout.bottomMargin: visible ? 2 : 0
+                Layout.column: 0
+                Layout.fillWidth: true
+                Layout.maximumWidth: Settings.bubbles ? Number.MAX_VALUE : implicitWidth
+                Layout.preferredHeight: height
+                Layout.row: 0
                 blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? ""
                 body: r.relatedEventCacheBuster, fromModel(Room.Body) ?? ""
-                formattedBody: r.relatedEventCacheBuster, fromModel(Room.FormattedBody) ?? ""
+                callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? ""
+                duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0
+                encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0
                 eventId: fromModel(Room.EventId) ?? ""
                 filename: r.relatedEventCacheBuster, fromModel(Room.Filename) ?? ""
                 filesize: r.relatedEventCacheBuster, fromModel(Room.Filesize) ?? ""
+                formattedBody: r.relatedEventCacheBuster, fromModel(Room.FormattedBody) ?? ""
+                isOnlyEmoji: r.relatedEventCacheBuster, fromModel(Room.IsOnlyEmoji) ?? false
+                isStateEvent: r.relatedEventCacheBuster, fromModel(Room.IsStateEvent) ?? false
+                originalWidth: r.relatedEventCacheBuster, fromModel(Room.OriginalWidth) ?? 0
                 proportionalHeight: r.relatedEventCacheBuster, fromModel(Room.ProportionalHeight) ?? 1
+                relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0
+                roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? ""
+                roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? ""
+                thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? ""
                 type: r.relatedEventCacheBuster, fromModel(Room.Type) ?? MtxEvent.UnknownMessage
                 typeString: r.relatedEventCacheBuster, fromModel(Room.TypeString) ?? ""
                 url: r.relatedEventCacheBuster, fromModel(Room.Url) ?? ""
-                originalWidth: r.relatedEventCacheBuster, fromModel(Room.OriginalWidth) ?? 0
-                isOnlyEmoji: r.relatedEventCacheBuster, fromModel(Room.IsOnlyEmoji) ?? false
-                isStateEvent: r.relatedEventCacheBuster, fromModel(Room.IsStateEvent) ?? false
+                userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, palette.base)
                 userId: r.relatedEventCacheBuster, fromModel(Room.UserId) ?? ""
                 userName: r.relatedEventCacheBuster, fromModel(Room.UserName) ?? ""
-                thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? ""
-                duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0
-                roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? ""
-                roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? ""
-                callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? ""
-                encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0
-                relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0
+                visible: replyTo
             }
 
             // actual message content
             MessageDelegate {
-                Layout.row: 1
+                id: contentItem
+
                 Layout.column: 0
                 Layout.fillWidth: true
                 Layout.preferredHeight: height
-                id: contentItem
-
+                Layout.row: 1
                 blurhash: r.blurhash
                 body: r.body
-                formattedBody: r.formattedBody
+                callType: r.callType
+                duration: r.duration
+                encryptionError: r.encryptionError
                 eventId: r.eventId
                 filename: r.filename
                 filesize: r.filesize
+                formattedBody: r.formattedBody
+                isOnlyEmoji: r.isOnlyEmoji
+                isReply: false
+                isStateEvent: r.isStateEvent
+                metadataWidth: metadata.width
+                originalWidth: r.originalWidth
                 proportionalHeight: r.proportionalHeight
+                relatedEventCacheBuster: r.relatedEventCacheBuster
+                roomName: r.roomName
+                roomTopic: r.roomTopic
+                thumbnailUrl: r.thumbnailUrl
                 type: r.type
                 typeString: r.typeString ?? ""
                 url: r.url
-                thumbnailUrl: r.thumbnailUrl
-                duration: r.duration
-                originalWidth: r.originalWidth
-                isOnlyEmoji: r.isOnlyEmoji
-                isStateEvent: r.isStateEvent
                 userId: r.userId
                 userName: r.userName
-                roomTopic: r.roomTopic
-                roomName: r.roomName
-                callType: r.callType
-                encryptionError: r.encryptionError
-                relatedEventCacheBuster: r.relatedEventCacheBuster
-                isReply: false
-                metadataWidth: metadata.width
             }
-
             Row {
                 id: metadata
-                Layout.column: Settings.bubbles? 0 : 1
-                Layout.row: Settings.bubbles? 2 : 0
-                Layout.rowSpan: Settings.bubbles? 1 : 2
-                Layout.bottomMargin: -2
-                Layout.topMargin: (contentItem.fitsMetadata && Settings.bubbles)? -height-Layout.bottomMargin : 0
+
+                property int iconSize: Math.floor(fontMetrics.ascent * scaling)
+                property double scaling: Settings.bubbles ? 0.75 : 1
+
                 Layout.alignment: Qt.AlignTop | Qt.AlignRight
+                Layout.bottomMargin: -2
+                Layout.column: Settings.bubbles ? 0 : 1
                 Layout.preferredWidth: implicitWidth
-                visible: !isStateEvent
+                Layout.row: Settings.bubbles ? 2 : 0
+                Layout.rowSpan: Settings.bubbles ? 1 : 2
+                Layout.topMargin: (contentItem.fitsMetadata && Settings.bubbles) ? -height - Layout.bottomMargin : 0
                 spacing: 2
-
-                property double scaling: Settings.bubbles? 0.75 : 1
-
-                property int iconSize: Math.floor(fontMetrics.ascent*scaling)
+                visible: !isStateEvent
 
                 StatusIndicator {
                     Layout.alignment: Qt.AlignRight | Qt.AlignTop
+                    anchors.verticalCenter: ts.verticalCenter
+                    eventId: r.eventId
                     height: parent.iconSize
-                    width: parent.iconSize
                     status: r.status
-                    eventId: r.eventId
-                    anchors.verticalCenter: ts.verticalCenter
+                    width: parent.iconSize
                 }
-
                 Image {
-                    visible: isEdited || eventId == room.edit
                     Layout.alignment: Qt.AlignRight | Qt.AlignTop
-                    height: parent.iconSize
-                    width: parent.iconSize
-                    sourceSize.width: parent.iconSize * Screen.devicePixelRatio
-                    sourceSize.height: parent.iconSize * Screen.devicePixelRatio
-                    source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == room.edit) ? palette.highlight : palette.buttonText)
-                    ToolTip.visible: editHovered.hovered
                     ToolTip.delay: Nheko.tooltipDelay
                     ToolTip.text: qsTr("Edited")
+                    ToolTip.visible: editHovered.hovered
                     anchors.verticalCenter: ts.verticalCenter
+                    height: parent.iconSize
+                    source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == room.edit) ? palette.highlight : palette.buttonText)
+                    sourceSize.height: parent.iconSize * Screen.devicePixelRatio
+                    sourceSize.width: parent.iconSize * Screen.devicePixelRatio
+                    visible: isEdited || eventId == room.edit
+                    width: parent.iconSize
 
                     HoverHandler {
                         id: editHovered
-                    }
 
+                    }
                 }
-
                 ImageButton {
-                    visible: threadId
                     Layout.alignment: Qt.AlignRight | Qt.AlignTop
-                    height: parent.iconSize
-                    width: parent.iconSize
-                    image: ":/icons/icons/ui/thread.svg"
-                    buttonTextColor: TimelineManager.userColor(threadId, palette.base)
-                    ToolTip.visible: hovered
                     ToolTip.delay: Nheko.tooltipDelay
                     ToolTip.text: qsTr("Part of a thread")
+                    ToolTip.visible: hovered
                     anchors.verticalCenter: ts.verticalCenter
+                    buttonTextColor: TimelineManager.userColor(threadId, palette.base)
+                    height: parent.iconSize
+                    image: ":/icons/icons/ui/thread.svg"
+                    visible: threadId
+                    width: parent.iconSize
+
                     onClicked: room.thread = threadId
                 }
-
                 EncryptionIndicator {
-                    visible: room.isEncrypted
-                    encrypted: isEncrypted
-                    trust: trustlevel
                     Layout.alignment: Qt.AlignRight | Qt.AlignTop
+                    anchors.verticalCenter: ts.verticalCenter
+                    encrypted: isEncrypted
                     height: parent.iconSize
-                    width: parent.iconSize
-                    sourceSize.width: parent.iconSize * Screen.devicePixelRatio
                     sourceSize.height: parent.iconSize * Screen.devicePixelRatio
-                    anchors.verticalCenter: ts.verticalCenter
+                    sourceSize.width: parent.iconSize * Screen.devicePixelRatio
+                    trust: trustlevel
+                    visible: room.isEncrypted
+                    width: parent.iconSize
                 }
-
                 Label {
                     id: ts
+
                     Layout.alignment: Qt.AlignRight | Qt.AlignTop
                     Layout.preferredWidth: implicitWidth
-                    text: timestamp.toLocaleTimeString(Locale.ShortFormat)
-                    color: palette.inactive.text
-                    ToolTip.visible: ma.hovered
                     ToolTip.delay: Nheko.tooltipDelay
                     ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate)
-                    font.pointSize: fontMetrics.font.pointSize*parent.scaling
+                    ToolTip.visible: ma.hovered
+                    color: palette.inactive.text
+                    font.pointSize: fontMetrics.font.pointSize * parent.scaling
+                    text: timestamp.toLocaleTimeString(Locale.ShortFormat)
+
                     HoverHandler {
                         id: ma
-                    }
 
+                    }
                 }
             }
         }
     }
-
     Reactions {
+        id: reactionRow
+
+        eventId: r.eventId
+        layoutDirection: row.bubbleOnRight ? Qt.RightToLeft : Qt.LeftToRight
+        reactions: r.reactions
+        width: row.maxWidth
+
         anchors {
+            left: row.bubbleOnRight ? undefined : row.left
+            right: row.bubbleOnRight ? row.right : undefined
             top: row.bottom
             topMargin: -4
-            left: row.bubbleOnRight? undefined : row.left
-            right: row.bubbleOnRight? row.right : undefined
         }
-        width: row.maxWidth
-        layoutDirection: row.bubbleOnRight? Qt.RightToLeft : Qt.LeftToRight
-
-        id: reactionRow
-
-        reactions: r.reactions
-        eventId: r.eventId
     }
-
     Rectangle {
         id: unreadRow
+
+        color: palette.highlight
+        height: visible ? 3 : 0
+        visible: (r.index > 0 && (room.fullyReadEventId == r.eventId))
+
         anchors {
-            top: reactionRow.bottom
-            topMargin: 5
             left: parent.left
             right: parent.right
+            top: reactionRow.bottom
+            topMargin: 5
         }
-        color: palette.highlight
-        
-        visible: (r.index > 0 && (room.fullyReadEventId == r.eventId))
-        height: visible ? 3 : 0
-
     }
 }