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