summary refs log tree commit diff
path: root/resources/qml/MessageView.qml
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2020-10-26 14:57:54 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2020-10-26 21:34:34 +0100
commit3d64df41dac45693d1e2626909f0e55d4b7a6f47 (patch)
treed592ee2279235b9d7dc58f52c3cfed06ea61d707 /resources/qml/MessageView.qml
parentQml message input mockup (diff)
downloadnheko-3d64df41dac45693d1e2626909f0e55d4b7a6f47.tar.xz
Split up TimelineView into separate components
Diffstat (limited to 'resources/qml/MessageView.qml')
-rw-r--r--resources/qml/MessageView.qml202
1 files changed, 202 insertions, 0 deletions
diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml
new file mode 100644
index 00000000..09220a71
--- /dev/null
+++ b/resources/qml/MessageView.qml
@@ -0,0 +1,202 @@
+import "./delegates"
+import QtGraphicalEffects 1.0
+import QtQuick 2.9
+import QtQuick.Controls 2.3
+import QtQuick.Layouts 1.2
+import QtQuick.Window 2.2
+import im.nheko 1.0
+
+ListView {
+    id: chat
+
+    property int delegateMaxWidth: (Settings.timelineMaxWidth > 100 && (parent.width - Settings.timelineMaxWidth) > scrollbar.width * 2) ? Settings.timelineMaxWidth : (parent.width - scrollbar.width * 2)
+
+    Layout.fillWidth: true
+    Layout.fillHeight: true
+    cacheBuffer: 400
+    model: TimelineManager.timeline
+    boundsBehavior: Flickable.StopAtBounds
+    pixelAligned: true
+    spacing: 4
+    verticalLayoutDirection: ListView.BottomToTop
+    onCountChanged: {
+        if (atYEnd)
+            model.currentIndex = 0;
+
+    } // Mark last event as read, since we are at the bottom
+
+    ScrollHelper {
+        flickable: parent
+        anchors.fill: parent
+    }
+
+    Shortcut {
+        sequence: StandardKey.MoveToPreviousPage
+        onActivated: {
+            chat.contentY = chat.contentY - chat.height / 2;
+            chat.returnToBounds();
+        }
+    }
+
+    Shortcut {
+        sequence: StandardKey.MoveToNextPage
+        onActivated: {
+            chat.contentY = chat.contentY + chat.height / 2;
+            chat.returnToBounds();
+        }
+    }
+
+    Shortcut {
+        sequence: StandardKey.Cancel
+        onActivated: chat.model.reply = undefined
+    }
+
+    Shortcut {
+        sequence: "Alt+Up"
+        onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0)
+    }
+
+    Shortcut {
+        sequence: "Alt+Down"
+        onActivated: {
+            var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1;
+            chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : undefined;
+        }
+    }
+
+    section {
+        property: "section"
+    }
+
+    Component {
+        id: sectionHeader
+
+        Column {
+            property var modelData
+            property string section
+            property string nextSection
+
+            topPadding: 4
+            bottomPadding: 4
+            spacing: 8
+            visible: !!modelData
+            width: parent.width
+            height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8
+
+            Label {
+                id: dateBubble
+
+                anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
+                visible: section.includes(" ")
+                text: chat.model.formatDateSeparator(modelData.timestamp)
+                color: colors.text
+                height: fontMetrics.height * 1.4
+                width: contentWidth * 1.2
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+
+                background: Rectangle {
+                    radius: parent.height / 2
+                    color: colors.window
+                }
+
+            }
+
+            Row {
+                height: userName.height
+                spacing: 8
+
+                Avatar {
+                    width: avatarSize
+                    height: avatarSize
+                    url: chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/")
+                    displayName: modelData.userName
+                    userid: modelData.userId
+
+                    MouseArea {
+                        anchors.fill: parent
+                        onClicked: chat.model.openUserProfile(modelData.userId)
+                        cursorShape: Qt.PointingHandCursor
+                        propagateComposedEvents: true
+                    }
+
+                }
+
+                Label {
+                    id: userName
+
+                    text: TimelineManager.escapeEmoji(modelData.userName)
+                    color: TimelineManager.userColor(modelData.userId, colors.window)
+                    textFormat: Text.RichText
+
+                    MouseArea {
+                        anchors.fill: parent
+                        Layout.alignment: Qt.AlignHCenter
+                        onClicked: chat.model.openUserProfile(modelData.userId)
+                        cursorShape: Qt.PointingHandCursor
+                        propagateComposedEvents: true
+                    }
+
+                }
+
+            }
+
+        }
+
+    }
+
+    ScrollBar.vertical: ScrollBar {
+        id: scrollbar
+    }
+
+    delegate: Item {
+        id: wrapper
+
+        // This would normally be previousSection, but our model's order is inverted.
+        property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1
+        property Item section
+
+        anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
+        width: chat.delegateMaxWidth
+        height: section ? section.height + timelinerow.height : timelinerow.height
+        onSectionBoundaryChanged: {
+            if (sectionBoundary) {
+                var properties = {
+                    "modelData": model.dump,
+                    "section": ListView.section,
+                    "nextSection": ListView.nextSection
+                };
+                section = sectionHeader.createObject(wrapper, properties);
+            } else {
+                section.destroy();
+                section = null;
+            }
+        }
+
+        TimelineRow {
+            id: timelinerow
+
+            y: section ? section.y + section.height : 0
+        }
+
+        Connections {
+            function onMovementEnded() {
+                if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height)
+                    chat.model.currentIndex = index;
+
+            }
+
+            target: chat
+        }
+
+    }
+
+    footer: BusyIndicator {
+        anchors.horizontalCenter: parent.horizontalCenter
+        running: chat.model && chat.model.paginationInProgress
+        height: 50
+        width: 50
+        z: 3
+    }
+
+}