import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.2 import Spectral 0.1 import Spectral.Setting 0.1 import Spectral.Component 2.0 import Spectral.Font 0.1 RowLayout { 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() z: -5 id: messageRow Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft spacing: 4 ImageItem { Layout.preferredWidth: 32 Layout.preferredHeight: 32 Layout.alignment: Qt.AlignTop visible: avatarVisible hint: author.displayName source: author.paintable } Rectangle { Layout.preferredWidth: 32 Layout.preferredHeight: 32 Layout.alignment: Qt.AlignTop color: "transparent" visible: !(sentByMe || avatarVisible) } Control { Layout.maximumWidth: messageListView.width - (!sentByMe ? 40 + messageRow.spacing : 0) - 48 topPadding: 8 bottomPadding: 8 leftPadding: 16 rightPadding: 16 background: Rectangle { color: sentByMe ? "#009DC2" : (highlighted || eventType) === "notice" ? "#4285F4" : "#673AB7" radius: 18 AutoMouseArea { anchors.fill: parent onSecondaryClicked: { messageContextMenu.row = messageRow messageContextMenu.model = model messageContextMenu.selectedText = contentLabel.selectedText messageContextMenu.popup() } } } contentItem: ColumnLayout { id: messageColumn spacing: 0 // TimelineLabel { // Layout.fillWidth: true // id: authorLabel // visible: messageRow.avatarVisible // text: author.displayName // Material.foreground: Material.accent // coloredBackground: highlighted // font.bold: true // MouseArea { // anchors.fill: parent // cursorShape: Qt.PointingHandCursor // onClicked: roomPanelInput.insert(author.displayName) // } // } TextEdit { Layout.fillWidth: true id: contentLabel text: "" + display visible: isText color: "white" font.family: CommonFont.font.family font.pointSize: 10.5 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" } // Row { // Layout.alignment: Qt.AlignRight // spacing: 4 // TimelineLabel { // visible: userMarker.length > 5 // text: userMarker.length - 5 + "+" // coloredBackground: highlighted // Material.foreground: "grey" // font.pointSize: 8 // } // Repeater { // model: userMarker.length > 5 ? userMarker.slice(0, 5) : userMarker // ImageItem { // width: parent.height // height: parent.height // hint: modelData.displayName // source: modelData.paintable // MouseArea { // anchors.fill: parent // cursorShape: Qt.PointingHandCursor // onClicked: { // readMarkerDialog.listModel = userMarker // readMarkerDialog.open() // } // } // } // } // TimelineLabel { // id: timeLabel // visible: Math.abs(time - aboveTime) > 600000 || index == 0 // text: Qt.formatTime(time, "hh:mm") // coloredBackground: highlighted // Material.foreground: "grey" // font.pointSize: 8 // } // } } 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: { messageRow.saveFileAs.connect(saveFileAs) messageRow.openExternally.connect(downloadAndOpen) } } } Component { id: fileComponent TimelineLabel { Layout.fillWidth: true id: downloadDelegate text: "File: " + content.body coloredBackground: highlighted background: DownloadableContent { id: downloadable Component.onCompleted: { messageRow.saveFileAs.connect(saveFileAs) messageRow.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: { messageRow.saveFileAs.connect(saveFileAs) messageRow.openExternally.connect(downloadAndOpen) } } } } } }