import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls.Material 2.12 import QtGraphicalEffects 1.0 import Qt.labs.platform 1.0 as Platform import Spectral 0.1 import Spectral.Setting 0.1 import Spectral.Component 2.0 import Spectral.Dialog 2.0 import Spectral.Menu.Timeline 2.0 import Spectral.Font 0.1 import Spectral.Effect 2.0 RowLayout { readonly property bool avatarVisible: !sentByMe && showAuthor readonly property bool sentByMe: author === currentRoom.localUser property bool openOnFinished: false readonly property bool downloaded: progressInfo && progressInfo.completed id: root spacing: 4 onDownloadedChanged: if (downloaded && openOnFinished) openSavedFile() z: -5 Avatar { Layout.preferredWidth: 36 Layout.preferredHeight: 36 Layout.alignment: Qt.AlignBottom visible: avatarVisible hint: author.displayName source: author.avatarMediaId Component { id: userDetailDialog UserDetailDialog {} } RippleEffect { anchors.fill: parent circular: true onClicked: userDetailDialog.createObject(ApplicationWindow.overlay, {"room": currentRoom, "user": author}).open() } } Label { Layout.preferredWidth: 36 Layout.preferredHeight: 36 visible: !(sentByMe || avatarVisible) } Control { Layout.maximumWidth: messageListView.width - (!sentByMe ? 36 + root.spacing : 0) - 48 padding: 12 contentItem: RowLayout { ToolButton { contentItem: MaterialIcon { icon: progressInfo.completed ? "\ue5ca" : "\ue2c4" } onClicked: progressInfo.completed ? openSavedFile() : saveFileAs() } ColumnLayout { Label { Layout.fillWidth: true text: display wrapMode: Label.Wrap font.pixelSize: 18 font.weight: Font.Medium font.capitalization: Font.AllUppercase } Label { Layout.fillWidth: true text: progressInfo.active ? (humanSize(progressInfo.progress) + "/" + humanSize(progressInfo.total)) : humanSize(content.info ? content.info.size : 0) color: MPalette.lighter wrapMode: Label.Wrap } } } background: Rectangle { color: sentByMe ? MPalette.background : eventType === "notice" ? MPalette.primary : MPalette.accent radius: 2 AutoMouseArea { anchors.fill: parent id: messageMouseArea onSecondaryClicked: { var contextMenu = fileDelegateContextMenu.createObject(ApplicationWindow.overlay) contextMenu.viewSource.connect(function() { messageSourceDialog.createObject(ApplicationWindow.overlay, {"sourceText": toolTip}).open() }) contextMenu.downloadAndOpen.connect(downloadAndOpen) contextMenu.saveFileAs.connect(saveFileAs) contextMenu.reply.connect(function() { roomPanelInput.replyUser = author roomPanelInput.replyEventID = eventId roomPanelInput.replyContent = message roomPanelInput.isReply = true roomPanelInput.focus() }) contextMenu.redact.connect(function() { currentRoom.redactEvent(eventId) }) contextMenu.popup() } Component { id: messageSourceDialog MessageSourceDialog {} } Component { id: openFolderDialog OpenFolderDialog {} } Component { id: fileDelegateContextMenu FileDelegateContextMenu {} } } } } function saveFileAs() { var folderDialog = openFolderDialog.createObject(ApplicationWindow.overlay) folderDialog.chosen.connect(function(path) { if (!path) return currentRoom.downloadFile(eventId, path + "/" + currentRoom.fileNameToDownload(eventId)) }) folderDialog.open() } function downloadAndOpen() { if (downloaded) openSavedFile() else { openOnFinished = true currentRoom.downloadFile(eventId, Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(eventId)) } } function openSavedFile() { if (Qt.openUrlExternally(progressInfo.localPath)) return; if (Qt.openUrlExternally(progressInfo.localDir)) return; } function humanSize(bytes) { if (!bytes) return qsTr("Unknown", "Unknown attachment size") if (bytes < 4000) return qsTr("%1 bytes").arg(bytes) bytes = Math.round(bytes / 100) / 10 if (bytes < 2000) return qsTr("%1 KB").arg(bytes) bytes = Math.round(bytes / 100) / 10 if (bytes < 2000) return qsTr("%1 MB").arg(bytes) return qsTr("%1 GB").arg(Math.round(bytes / 100) / 10) } }