diff --git a/ui/app/AppLayouts/Browser/BrowserLayout.qml b/ui/app/AppLayouts/Browser/BrowserLayout.qml index 7770038458..d2176925b0 100644 --- a/ui/app/AppLayouts/Browser/BrowserLayout.qml +++ b/ui/app/AppLayouts/Browser/BrowserLayout.qml @@ -32,6 +32,13 @@ Rectangle { property var downloads: [] } + function removeDownloadFromModel(index) { + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== downloadModel.downloads[index].id; + }); + downloadModel.remove(index); + } + Layout.fillHeight: true Layout.fillWidth: true @@ -631,7 +638,7 @@ Rectangle { } function onDownloadRequested(download) { - downloadBar.visible = true + downloadBar.isVisible = true downloadView.append(download); download.accept(); } diff --git a/ui/app/AppLayouts/Browser/DownloadBar.qml b/ui/app/AppLayouts/Browser/DownloadBar.qml index 1073fd1d21..f66ba9f00f 100644 --- a/ui/app/AppLayouts/Browser/DownloadBar.qml +++ b/ui/app/AppLayouts/Browser/DownloadBar.qml @@ -4,11 +4,11 @@ import "../../../shared" import "../../../shared/status" import "../../../imports" -//downloadModel.downloads[index].receivedBytes - Rectangle { + property bool isVisible: false + id: root - visible: false + visible: isVisible && !!listView.count color: Style.current.background width: parent.width height: 56 @@ -61,7 +61,7 @@ Rectangle { icon.name: "browser/close" iconColor: Style.current.textColor onClicked: { - root.visible = false + root.isVisible = false } } } diff --git a/ui/app/AppLayouts/Browser/DownloadElement.qml b/ui/app/AppLayouts/Browser/DownloadElement.qml index 37ecf642d7..2a0d5e5add 100644 --- a/ui/app/AppLayouts/Browser/DownloadElement.qml +++ b/ui/app/AppLayouts/Browser/DownloadElement.qml @@ -1,14 +1,44 @@ import QtQuick 2.1 +import QtQuick.Controls 2.13 import QtGraphicalEffects 1.13 import "../../../shared" import "../../../shared/status" import "../../../imports" -Item { - id: downloadElement +Rectangle { + property bool downloadComplete: { + return !!downloadModel.downloads && !!downloadModel.downloads[index] && downloadModel.downloads[index].receivedBytes >= downloadModel.downloads[index].totalBytes + } + property bool isCanceled: false + property bool hovered: false + + id: root width: 272 height: 40 + border.width: 0 + color: hovered ? Style.current.backgroundHover : Style.current.transparent + radius: Style.current.radius + + function openFile() { + Qt.openUrlExternally(`file://${downloadDirectory}/${downloadFileName}`) + removeDownloadFromModel(index) + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onEntered: { + root.hovered = true + } + onExited: { + root.hovered = false + } + onClicked: { + openFile() + } + } Loader { id: iconLoader @@ -17,10 +47,10 @@ Item { anchors.leftMargin: Style.current.smallPadding active: root.visible sourceComponent: { - if (!downloadModel.downloads || !downloadModel.downloads[index] || downloadModel.downloads[index].receivedBytes < downloadModel.downloads[index].totalBytes) { - return loadingImageComponent + if (downloadComplete || !downloadModel.downloads[index] || downloadModel.downloads[index].isPaused || isCanceled) { + return fileImageComponent } - return fileImageComponent + return loadingImageComponent } Component { @@ -34,10 +64,9 @@ Item { width: 24 height: 24 ColorOverlay { - enabled: false anchors.fill: parent source: parent - color: Style.current.darkGrey + color: downloadComplete ? Style.current.transparent : Style.current.darkGrey } } } @@ -49,7 +78,8 @@ Item { elide: Text.ElideRight anchors.left: iconLoader.right anchors.right: optionsBtn.left - anchors.top: parent.top + anchors.top: downloadComplete ? undefined : parent.top + anchors.verticalCenter: downloadComplete ? parent.verticalCenter : undefined minimumPixelSize: 13 anchors.leftMargin: Style.current.smallPadding anchors.topMargin: 2 @@ -57,8 +87,17 @@ Item { StyledText { id: progressText + visible: !downloadComplete color: Style.current.secondaryText - text: `${downloadModel.downloads[index] ? downloadModel.downloads[index].receivedBytes / 1000000 : 0}/${downloadModel.downloads[index] ? downloadModel.downloads[index].totalBytes / 1000000 : 0} MB` //"14.4/109 MB, 26 sec left" + text: { + if (isCanceled) { + return qsTr("Cancelled") + } + if (downloadModel.downloads[index] && downloadModel.downloads[index].isPaused) { + return qsTr("Paused") + } + return `${downloadModel.downloads[index] ? (downloadModel.downloads[index].receivedBytes / 1000000).toFixed(2) : 0}/${downloadModel.downloads[index] ? (downloadModel.downloads[index].totalBytes / 1000000).toFixed(2) : 0} MB` //"14.4/109 MB, 26 sec left" + } elide: Text.ElideRight anchors.left: iconLoader.right anchors.right: optionsBtn.left @@ -74,6 +113,70 @@ Item { anchors.right: parent.right anchors.rightMargin: Style.current.smallPadding icon.name: "dots-icon" + onClicked: { + downloadMenu.x = optionsBtn.x + downloadMenu.open() + } + } + + // TODO Move this outside? + PopupMenu { + id: downloadMenu + y: -height - Style.current.smallPadding + + Action { + enabled: downloadComplete + icon.source: "../../img/browser/file.svg" + icon.width: 16 + icon.height: 16 + text: qsTr("Open") + onTriggered: openFile() + } + Action { + icon.source: "../../img/add_watch_only.svg" + icon.width: 13 + icon.height: 9 + text: qsTr("Show in folder") + // TODO check if this works in Windows and Mac + onTriggered: Qt.openUrlExternally("file://" + downloadDirectory) + } + Action { + enabled: !downloadComplete && !!downloadModel.downloads[index] && !downloadModel.downloads[index].isPaused + icon.source: "../../img/browser/pause.svg" + icon.width: 16 + icon.height: 16 + text: qsTr("Pause") + onTriggered: { + downloadModel.downloads[index].pause() + } + } + Action { + enabled: !downloadComplete && !!downloadModel.downloads[index] && downloadModel.downloads[index].isPaused + icon.source: "../../img/browser/play.svg" + icon.width: 16 + icon.height: 16 + text: qsTr("Resume") + onTriggered: { + downloadModel.downloads[index].resume() + } + } + + Separator { + visible: !downloadComplete + } + + Action { + enabled: !downloadComplete + icon.source: "../../img/block-icon.svg" + icon.width: 13 + icon.height: 13 + text: qsTr("Cancel") + onTriggered: { + downloadModel.downloads[index].cancel() + isCanceled = true + } + icon.color: Style.current.red + } } } diff --git a/ui/app/AppLayouts/Browser/DownloadView.qml b/ui/app/AppLayouts/Browser/DownloadView.qml index b1dee6dd27..efc4e56e9b 100644 --- a/ui/app/AppLayouts/Browser/DownloadView.qml +++ b/ui/app/AppLayouts/Browser/DownloadView.qml @@ -96,7 +96,7 @@ Rectangle { } Label { id: label - text: downloadModel.downloads[index].downloadDirectory + "/" + downloadModel.downloads[index].downloadFileName + text: downloadDirectory + "/" + downloadFileName anchors { verticalCenter: cancelButton.verticalCenter left: parent.left @@ -112,10 +112,7 @@ Rectangle { download.cancel(); - downloadModel.downloads = downloadModel.downloads.filter(function (el) { - return el.id !== download.id; - }); - downloadModel.remove(index); + removeDownloadFromModel(index) } } } diff --git a/ui/app/img/browser/pause.svg b/ui/app/img/browser/pause.svg new file mode 100644 index 0000000000..63df28447d --- /dev/null +++ b/ui/app/img/browser/pause.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ui/app/img/browser/play.svg b/ui/app/img/browser/play.svg new file mode 100644 index 0000000000..6718a9ba71 --- /dev/null +++ b/ui/app/img/browser/play.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/shared/Separator.qml b/ui/shared/Separator.qml index 463239b14c..5f538da593 100644 --- a/ui/shared/Separator.qml +++ b/ui/shared/Separator.qml @@ -4,7 +4,7 @@ import "../imports" Rectangle { id: separator width: parent.width - height: 1 + height: visible ? 1 : 0 color: Style.current.border anchors.topMargin: Style.current.padding }