diff --git a/imports/Spectral/Component/Timeline/ImageDelegate.qml b/imports/Spectral/Component/Timeline/ImageDelegate.qml new file mode 100644 index 0000000..465ff30 --- /dev/null +++ b/imports/Spectral/Component/Timeline/ImageDelegate.qml @@ -0,0 +1,103 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import QtGraphicalEffects 1.0 + +import Spectral 0.1 +import Spectral.Setting 0.1 + +import Spectral.Component 2.0 +import Spectral.Font 0.1 + +ColumnLayout { + readonly property int alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft + + readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other") + readonly property bool sentByMe: author === currentRoom.localUser + + signal saveFileAs() + signal openExternally() + + id: root + + spacing: 0 + + Label { + Layout.leftMargin: 48 + + text: author.displayName + + visible: avatarVisible + + font.pixelSize: 13 + verticalAlignment: Text.AlignVCenter + } + + RowLayout { + Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft + + z: -5 + + id: messageRow + + spacing: 4 + + ImageItem { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop + + visible: avatarVisible + hint: author.displayName + source: author.paintable + } + + Label { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop + + visible: !(sentByMe || avatarVisible) + + text: Qt.formatDateTime(time, "hh:mm") + color: "#5B7480" + + font.pixelSize: 10 + horizontalAlignment: Label.AlignHCenter + verticalAlignment: Label.AlignVCenter + } + + Image { + Layout.maximumWidth: messageListView.width - (!sentByMe ? 32 + messageRow.spacing : 0) - 48 + + id: img + + source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url) + sourceSize.width: Math.min(256, messageListView.width) + sourceSize.height: 256 + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: img.width + height: img.height + radius: 24 + } + } + + AutoMouseArea { + anchors.fill: parent + + id: messageMouseArea + + onSecondaryClicked: { + messageContextMenu.root = root + messageContextMenu.model = model + messageContextMenu.selectedText = "" + messageContextMenu.popup() + } + } + } + } +} diff --git a/imports/Spectral/Component/Timeline/MessageDelegate.qml b/imports/Spectral/Component/Timeline/MessageDelegate.qml index d45cec8..e73c589 100644 --- a/imports/Spectral/Component/Timeline/MessageDelegate.qml +++ b/imports/Spectral/Component/Timeline/MessageDelegate.qml @@ -10,16 +10,14 @@ import Spectral.Component 2.0 import Spectral.Font 0.1 ColumnLayout { + readonly property int alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft + readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other") - readonly property bool highlighted: !(sentByMe || eventType === "notice" ) readonly property bool sentByMe: author === currentRoom.localUser - readonly property bool isText: eventType === "notice" || eventType === "message" signal saveFileAs() signal openExternally() - Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft - id: root spacing: 0 @@ -95,139 +93,30 @@ ColumnLayout { } } - contentItem: ColumnLayout { - id: messageColumn + contentItem: TextEdit { + Layout.fillWidth: true - spacing: 0 + id: contentLabel - TextEdit { - Layout.fillWidth: true + text: "" + display - id: contentLabel + color: "white" - text: "" + display + font.family: CommonFont.font.family + font.pixelSize: 14 + selectByMouse: true + readOnly: true + wrapMode: Label.Wrap + selectedTextColor: "white" + selectionColor: Material.accent + textFormat: Text.RichText - visible: isText - color: "white" + onLinkActivated: Qt.openUrlExternally(link) - font.family: CommonFont.font.family - font.pixelSize: 14 - selectByMouse: true - readOnly: true - wrapMode: Label.Wrap - selectedTextColor: highlighted ? Material.accent : "white" - selectionColor: highlighted ? "white" : Material.accent - textFormat: Text.RichText - - onLinkActivated: Qt.openUrlExternally(link) - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - - Loader { - sourceComponent: { - switch (eventType) { - case "image": - return imageComponent - case "file": - return fileComponent - case "audio": - return audioComponent - } - } - - active: eventType === "image" || eventType === "file" || eventType === "audio" - } - } - - Component { - id: imageComponent - - DownloadableContent { - width: messageImage.width - height: messageImage.height - - id: downloadable - - TimelineImage { - z: -4 - - id: messageImage - - sourceSize: 128 - source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url) - - onClicked: downloadAndOpen() - } - - Component.onCompleted: { - root.saveFileAs.connect(saveFileAs) - root.openExternally.connect(downloadAndOpen) - } - } - } - - Component { - id: fileComponent - - TimelineLabel { - Layout.fillWidth: true - - id: downloadDelegate - - text: "File: " + content.body - coloredBackground: highlighted - - background: DownloadableContent { - id: downloadable - - Component.onCompleted: { - root.saveFileAs.connect(saveFileAs) - root.openExternally.connect(downloadAndOpen) - } - } - } - } - - Component { - id: audioComponent - - TimelineLabel { - id: downloadDelegate - - text: content.info.duration / 1000 + '"' - coloredBackground: highlighted - - MouseArea { - anchors.fill: parent - - propagateComposedEvents: true - - onClicked: { - if (downloadable.downloaded) - spectralController.playAudio(progressInfo.localPath) - else - { - playOnFinished = true - currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + ".tmp") - } - } - } - - background: DownloadableContent { - id: downloadable - - onDownloadedChanged: downloaded && playOnFinished ? spectralController.playAudio(progressInfo.localPath) : {} - - Component.onCompleted: { - root.saveFileAs.connect(saveFileAs) - root.openExternally.connect(downloadAndOpen) - } - } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } } } diff --git a/imports/Spectral/Component/Timeline/StateDelegate.qml b/imports/Spectral/Component/Timeline/StateDelegate.qml index 91bc2e7..2c3a262 100644 --- a/imports/Spectral/Component/Timeline/StateDelegate.qml +++ b/imports/Spectral/Component/Timeline/StateDelegate.qml @@ -6,6 +6,8 @@ import QtQuick.Controls.Material 2.2 import Spectral.Setting 0.1 Label { + readonly property int alignment: Qt.AlignHCenter + text: "" + author.displayName + " " + display color: Material.accent diff --git a/imports/Spectral/Panel/RoomPanel.qml b/imports/Spectral/Panel/RoomPanel.qml index 73326ca..643c235 100644 --- a/imports/Spectral/Panel/RoomPanel.qml +++ b/imports/Spectral/Panel/RoomPanel.qml @@ -103,7 +103,7 @@ Item { var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex()) messageListView.currentIndex = lastScrollPosition if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20) - currentRoom.getPreviousContent(100) + currentRoom.getPreviousContent(50) } } } @@ -112,7 +112,7 @@ Item { onContentYChanged: { if(currentRoom && contentY - 5000 < originY) - currentRoom.getPreviousContent(50); + currentRoom.getPreviousContent(20); } onMovementEnded: currentRoom.saveViewport(sortedMessageEventModel.mapToSource(indexAt(contentX, contentY)), sortedMessageEventModel.mapToSource(largestVisibleIndex)) @@ -138,29 +138,27 @@ Item { visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 } - MessageDelegate { - visible: eventType === "notice" || eventType === "message" - || eventType === "image" || eventType === "video" - || eventType === "audio" || eventType === "file" - } - - StateDelegate { - Layout.maximumWidth: parent.width - Layout.alignment: Qt.AlignHCenter - - visible: eventType === "emote" || eventType === "state" - } - - Label { - Layout.alignment: Qt.AlignHCenter - - visible: eventType === "other" - - text: display - color: "grey" - font.italic: true + Loader { + Layout.maximumWidth: delegateColumn.width + Layout.alignment: item ? item.alignment : 0 + + source: { + switch (eventType) { + case "message": + case "notice": + return "qrc:/imports/Spectral/Component/Timeline/MessageDelegate.qml" + case "emote": + case "state": + return "qrc:/imports/Spectral/Component/Timeline/StateDelegate.qml" + case "image": + return "qrc:/imports/Spectral/Component/Timeline/ImageDelegate.qml" + default: + return "" + } + } } + // Read marker RowLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter diff --git a/res.qrc b/res.qrc index 7b3a6aa..a1be77d 100644 --- a/res.qrc +++ b/res.qrc @@ -46,5 +46,6 @@ imports/Spectral/Effect/RippleEffect.qml imports/Spectral/Effect/CircleMask.qml assets/img/roompanel-dark.svg + imports/Spectral/Component/Timeline/ImageDelegate.qml