diff --git a/imports/Spectral/Component/Timeline/AudioDelegate.qml b/imports/Spectral/Component/Timeline/AudioDelegate.qml index 0b4d64a29..b7a5a7cbb 100644 --- a/imports/Spectral/Component/Timeline/AudioDelegate.qml +++ b/imports/Spectral/Component/Timeline/AudioDelegate.qml @@ -68,10 +68,45 @@ RowLayout { source: currentRoom.urlToMxcUrl(content.url) } - contentItem: Label { - text: content.info.duration || audio.duration || "Unknown audio" + contentItem: RowLayout { + ToolButton { + contentItem: MaterialIcon { + icon: audio.playbackState == Audio.PlayingState ? "\ue034" : "\ue405" + } - color: !sentByMe ? "white" : MPalette.foreground + onClicked: { + if (audio.playbackState == Audio.PlayingState) { + audio.stop() + } else { + audio.play() + } + } + } + + ColumnLayout { + Label { + Layout.fillWidth: true + + text: display + color: MPalette.foreground + wrapMode: Label.Wrap + font.pixelSize: 18 + font.weight: Font.Medium + font.capitalization: Font.AllUppercase + } + + Label { + readonly property int duration: content.info.duration || audio.duration || 0 + + Layout.fillWidth: true + + visible: duration + + text: humanSize(duration) + color: MPalette.lighter + wrapMode: Label.Wrap + } + } } background: AutoRectangle { @@ -79,7 +114,7 @@ RowLayout { id: bubbleBackground - color: sentByMe ? MPalette.background : author.color + color: MPalette.background radius: 18 topLeftVisible: !sentByMe && (bubbleShape == 3 || bubbleShape == 2) @@ -97,12 +132,40 @@ RowLayout { id: messageMouseArea - onPrimaryClicked: { - if (audio.playbackState === Audio.PlayingState) { - audio.stop() - } else { - audio.play() - } + 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.replyModel = Object.assign({}, model) + 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 {} } } } @@ -135,4 +198,19 @@ RowLayout { if (Qt.openUrlExternally(progressInfo.localPath)) return; if (Qt.openUrlExternally(progressInfo.localDir)) return; } + + function humanSize(duration) + { + if (!duration) + return qsTr("Unknown", "Unknown duration") + if (duration < 1000) + return qsTr("An instant") + duration = Math.round(duration / 100) / 10 + if (duration < 60) + return qsTr("%1 sec.").arg(duration) + duration = Math.round(duration / 6) / 10 + if (duration < 60) + return qsTr("%1 min.").arg(duration) + return qsTr("%1 hrs.").arg(Math.round(duration / 6) / 10) + } } diff --git a/imports/Spectral/Component/Timeline/DownloadableContent.qml b/imports/Spectral/Component/Timeline/DownloadableContent.qml deleted file mode 100644 index 60be43edf..000000000 --- a/imports/Spectral/Component/Timeline/DownloadableContent.qml +++ /dev/null @@ -1,38 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Controls.Material 2.12 -import Qt.labs.platform 1.0 - -Item { - property bool openOnFinished: false - readonly property bool downloaded: progressInfo && progressInfo.completed - - Rectangle { - z: -2 - height: parent.height - width: progressInfo.active && !progressInfo.completed ? progressInfo.progress / progressInfo.total * parent.width : 0 - - color: Material.accent - opacity: 0.4 - } - - onDownloadedChanged: if (downloaded && openOnFinished) openSavedFile() - - function saveFileAs() { currentRoom.saveFileAs(eventId) } - - function downloadAndOpen() - { - if (downloaded) openSavedFile() - else - { - openOnFinished = true - currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + (message || ".tmp")) - } - } - - function openSavedFile() - { - if (Qt.openUrlExternally(progressInfo.localPath)) return; - if (Qt.openUrlExternally(progressInfo.localDir)) return; - } -} diff --git a/imports/Spectral/Component/Timeline/FileDelegate.qml b/imports/Spectral/Component/Timeline/FileDelegate.qml index b37fe1f6f..616b4d85d 100644 --- a/imports/Spectral/Component/Timeline/FileDelegate.qml +++ b/imports/Spectral/Component/Timeline/FileDelegate.qml @@ -80,6 +80,7 @@ RowLayout { Layout.fillWidth: true text: display + color: MPalette.foreground wrapMode: Label.Wrap font.pixelSize: 18 font.weight: Font.Medium diff --git a/imports/Spectral/Component/Timeline/ImageDelegate.qml b/imports/Spectral/Component/Timeline/ImageDelegate.qml index ab2d92414..aa1d195f9 100644 --- a/imports/Spectral/Component/Timeline/ImageDelegate.qml +++ b/imports/Spectral/Component/Timeline/ImageDelegate.qml @@ -35,7 +35,7 @@ RowLayout { } } - Avatar { + Avatar { Layout.preferredWidth: 36 Layout.preferredHeight: 36 Layout.alignment: Qt.AlignBottom @@ -67,28 +67,24 @@ RowLayout { visible: !(sentByMe || avatarVisible) } - BusyIndicator { - Layout.preferredWidth: 64 - Layout.preferredHeight: 64 - - visible: img.status == Image.Loading - } - Image { - property int maxWidth: messageListView.width - (!sentByMe ? 36 + root.spacing : 0) - 48 + readonly property bool isThumbnail: !(content.info.thumbnail_info == null || content.thumbnailMediaId == null) + readonly property var info: isThumbnail ? content.info.thumbnail_info : content.info + readonly property string mediaId: isThumbnail ? content.thumbnailMediaId : content.mediaId + readonly property int maxWidth: messageListView.width - (!sentByMe ? 36 + root.spacing : 0) - 48 Layout.minimumWidth: 256 Layout.minimumHeight: 64 - Layout.preferredWidth: content.info.w > maxWidth ? maxWidth : content.info.w - Layout.preferredHeight: content.info.w > maxWidth ? (content.info.h / content.info.w * maxWidth) : content.info.h + Layout.preferredWidth: info.w > maxWidth ? maxWidth : info.w + Layout.preferredHeight: info.w > maxWidth ? (info.h / info.w * maxWidth) : info.h id: img - source: "image://mxc/" + content.mediaId + source: "image://mxc/" + mediaId - sourceSize.width: 720 - sourceSize.height: 720 + sourceSize.width: info.w + sourceSize.height: info.h fillMode: Image.PreserveAspectCrop diff --git a/imports/Spectral/Component/Timeline/VideoDelegate.qml b/imports/Spectral/Component/Timeline/VideoDelegate.qml index aa24acccf..a9ed79116 100644 --- a/imports/Spectral/Component/Timeline/VideoDelegate.qml +++ b/imports/Spectral/Component/Timeline/VideoDelegate.qml @@ -73,7 +73,7 @@ RowLayout { } Video { - property int maxWidth: messageListView.width - (!sentByMe ? 36 + root.spacing : 0) - 48 + readonly property int maxWidth: messageListView.width - (!sentByMe ? 36 + root.spacing : 0) - 48 Layout.preferredWidth: content.info.w > maxWidth ? maxWidth : content.info.w Layout.preferredHeight: content.info.w > maxWidth ? (content.info.h / content.info.w * maxWidth) : content.info.h @@ -99,19 +99,19 @@ RowLayout { } Image { + readonly property bool isThumbnail: !(content.info.thumbnail_info == null || content.thumbnailMediaId == null) + readonly property var info: isThumbnail ? content.info.thumbnail_info : content.info + anchors.fill: parent - visible: content.info && content.info.thumbnail_info && vid.playbackState != MediaPlayer.PlayingState + visible: isThumbnail && vid.playbackState != MediaPlayer.PlayingState - source: "image://mxc/" + (content.info && content.info.thumbnail_info ? - content.thumbnailMediaId : "") + source: "image://mxc/" + (isThumbnail ? content.thumbnailMediaId : "") - sourceSize.width: 720 - sourceSize.height: 720 + sourceSize.width: info.w + sourceSize.height: info.h fillMode: Image.PreserveAspectCrop - - Component.onCompleted: console.log(source) } Label { diff --git a/res.qrc b/res.qrc index f51bcd27b..b4c8ae782 100644 --- a/res.qrc +++ b/res.qrc @@ -4,7 +4,6 @@ qml/main.qml imports/Spectral/Component/Emoji/EmojiPicker.qml imports/Spectral/Component/Emoji/qmldir - imports/Spectral/Component/Timeline/DownloadableContent.qml imports/Spectral/Component/Timeline/MessageDelegate.qml imports/Spectral/Component/Timeline/qmldir imports/Spectral/Component/Timeline/StateDelegate.qml