Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Downloads UX Changes (#415)
Browse files Browse the repository at this point in the history
Originally from #336 

- Fixes #193 
- Implemented recent downloads dialog in bot the browser and webapp. This is displayed when a new download started instead of the downloads page.
- A downloads button is added in the navigation bar which wiggles and turns blue when a download completes. In webapps without the title bar, the recent downloads dialog is displayed instead
- Only display the file names in the Downloads page instead of full path.
- Added info such as file size and download speed in the Downloads page
- Added actions such as copy download link and remove from history
  • Loading branch information
kugiigi authored Feb 3, 2021
1 parent ee7fdcf commit f6f636e
Show file tree
Hide file tree
Showing 10 changed files with 830 additions and 87 deletions.
204 changes: 134 additions & 70 deletions src/app/DownloadDelegate.qml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

import QtQuick 2.4
import Ubuntu.Components 1.3
import QtQuick.Layouts 1.3
import ".."
import "FileUtils.js" as FileUtils

ListItem {
id: downloadDelegate
Expand All @@ -31,6 +33,7 @@ ListItem {
property string downloadId
property var download
readonly property int progress: download ? 100 * (download.receivedBytes / download.totalBytes) : -1
property real speed: 0
property bool paused: download.isPaused
property alias incognito: incognitoIcon.visible

Expand All @@ -40,31 +43,67 @@ ListItem {
signal cancelled()

height: visible ? layout.height : 0

Timer {
id: speedTimer

property real prevBytes: 0

interval: 1000
running: download && !paused? true : false
repeat: true
onTriggered: {
if (download) {
speed = download.receivedBytes - prevBytes
prevBytes = download.receivedBytes
}
}
}

MimeData {
id: linkMimeData

text: model ? model.url : ""
}

SlotsLayout {
id: layout

Item {
ColumnLayout {
SlotsLayout.position: SlotsLayout.Leading
width: units.gu(3)
height: units.gu(3)

Image {
id: thumbimage
asynchronous: true
anchors.fill: parent
fillMode: Image.PreserveAspectFit
sourceSize.width: width
sourceSize.height: height
spacing: units.gu(1)

Item {
Layout.alignment: Qt.AlignHCenter
implicitWidth: units.gu(3)
implicitHeight: units.gu(3)

Image {
id: thumbimage
asynchronous: true
anchors.fill: parent
fillMode: Image.PreserveAspectFit
sourceSize.width: width
sourceSize.height: height
}

Image {
asynchronous: true
anchors.fill: parent
anchors.margins: units.gu(0.2)
source: "image://theme/%1".arg(downloadDelegate.icon || "save")
visible: thumbimage.status !== Image.Ready
cache: true
}
}

Image {
asynchronous: true
anchors.fill: parent
anchors.margins: units.gu(0.2)
source: "image://theme/%1".arg(downloadDelegate.icon || "save")
visible: thumbimage.status !== Image.Ready
cache: true
Label {
Layout.alignment: Qt.AlignHCenter
visible: !progressBar.indeterminateProgress && incomplete
horizontalAlignment: Text.AlignHCenter
// TRANSLATORS: %1 is the percentage of the download completed so far
text: i18n.tr("%1%").arg(progressBar.progress)
opacity: paused ? 0.5 : 1
}
}

Expand Down Expand Up @@ -133,70 +172,55 @@ ListItem {
}
}

IndeterminateProgressBar {
id: progressBar
ColumnLayout {
visible: incomplete && !error.visible
anchors {
left: parent.left
right: parent.right
}
height: units.gu(0.5)
visible: incomplete && !error.visible
progress: downloadDelegate.progress
// Work around UDM bug #1450144
indeterminateProgress: progress < 0 || progress > 100
opacity: paused ? 0.5 : 1
}
}

Column {
SlotsLayout.position: SlotsLayout.Trailing
spacing: units.gu(1)
width: (incomplete && !error.visible) ? cancelButton.width : 0

Button {
id: cancelButton
visible: incomplete && !error.visible
text: i18n.tr("Cancel")
onClicked: {
if (download) {
download.cancel()
cancelled()
}
IndeterminateProgressBar {
id: progressBar
Layout.fillWidth: true
implicitHeight: units.gu(0.5)
progress: downloadDelegate.progress
// Work around UDM bug #1450144
indeterminateProgress: progress < 0 || progress > 100
opacity: paused ? 0.5 : 1
}
}

Label {
visible: !progressBar.indeterminateProgress && incomplete && !error.visible
width: cancelButton.width
horizontalAlignment: Text.AlignHCenter
textSize: Label.Small
// TRANSLATORS: %1 is the percentage of the download completed so far
text: i18n.tr("%1%").arg(progressBar.progress)
opacity: paused ? 0.5 : 1
}
RowLayout {
Layout.fillWidth: true
implicitHeight: units.gu(4)

Button {
visible: incomplete && ! paused && ! error.visible
text: i18n.tr("Pause")
width: cancelButton.width
onClicked: {
if (download) {
download.pause()
Label {
horizontalAlignment: Text.AlignHCenter
textSize: Label.Small
text: download ? FileUtils.formatBytes(download.receivedBytes) + " / " + FileUtils.formatBytes(download.totalBytes) : i18n.tr("Unknown")
opacity: paused ? 0.5 : 1
}
}
}

Button {
visible: incomplete && paused && ! error.visible
text: i18n.tr("Resume")
width: cancelButton.width
onClicked: {
if (download) {
download.resume()
Label {
horizontalAlignment: Text.AlignHCenter
textSize: Label.Small
// TRANSLATORS: %1 is the number of bytes i.e. 2bytes, 5KB, 1MB
text: "(" + i18n.tr("%1/s").arg(FileUtils.formatBytes(downloadDelegate.speed)) + ")"
opacity: paused ? 0.5 : 1
}
}
}
}
Icon {
id: iconPauseResume

implicitWidth: units.gu(4)
implicitHeight: implicitWidth
SlotsLayout.position: SlotsLayout.Trailing
asynchronous: true
name: paused ? "media-preview-start" : "media-preview-pause"
visible: incomplete && !error.visible
color: theme.palette.normal.overlayText
}
}

Icon {
Expand All @@ -213,7 +237,8 @@ ListItem {
name: "private-browsing"
}

leadingActions: error.visible || !incomplete ? deleteActionList : null
leadingActions: deleteActionList
trailingActions: trailingActionList

ListItemActions {
id: deleteActionList
Expand All @@ -222,10 +247,49 @@ ListItem {
objectName: "leadingAction.delete"
iconName: "delete"
enabled: error.visible || !incomplete
visible: enabled
text: i18n.tr("Delete File")
onTriggered: {
removed()
}
},
Action {
objectName: "leadingAction.remove"
iconName: "list-remove"
enabled: !incomplete && !error.visible
visible: enabled
text: i18n.tr("Remove from History")
onTriggered: {

removed()
}
},
Action {
objectName: "leadingAction.cancel"
iconName: "cancel"
enabled: incomplete && !error.visible
visible: enabled
text: i18n.tr("Cancel")
onTriggered: {
if (download) {
download.cancel()
cancelled()
}
}
}
]
}

ListItemActions {
id: trailingActionList
actions: [
Action {
objectName: "trailingAction.CopyLink"
iconName: "edit-copy"
enabled: model.url != "" ? true : false
visible: enabled
text: i18n.tr("Copy Download Link")
onTriggered: {
Clipboard.push(linkMimeData)
}
}
]
Expand Down
Loading

0 comments on commit f6f636e

Please sign in to comment.