Bug 883959: Part 1: Show circular download progress indicator. r=sfoster.

This commit is contained in:
Marina Samuel 2013-08-01 15:17:30 -04:00
parent 08d6011fa3
commit 1fde3a0ed2
11 changed files with 198 additions and 5 deletions

View File

@ -0,0 +1,78 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="circular-progress-indicator">
<content>
<xul:stack>
<xul:toolbarbutton anonid="progressButton" class="circularprogressindicator-progressButton appbar-secondary"/>
<html:canvas anonid="progressRing" class="circularprogressindicator-progressRing" width="46" height="46"></html:canvas>
</xul:stack>
</content>
<implementation>
<field name="_progressCanvas">
document.getAnonymousElementByAttribute(this, "anonid", "progressRing");
</field>
<field name="_progressCircleCtx">null</field>
<field name="_img">null</field>
<constructor>
<![CDATA[
this._progressCircleCtx = this._progressCanvas.getContext('2d');
this._img = new Image();
]]>
</constructor>
<method name="updateProgress">
<parameter name="percentComplete"/>
<body>
<![CDATA[
const PROGRESS_RING_IMG = "chrome://browser/skin/images/progresscircle.png";
let startAngle = 1.5 * Math.PI;
let endAngle = startAngle + (2 * Math.PI * (percentComplete / 100));
let ctx = this._progressCircleCtx;
ctx.clearRect(0, 0,
this._progressCanvas.width, this._progressCanvas.height);
// Save the state, so we can undo the clipping
ctx.save();
ctx.beginPath();
let center = this._progressCanvas.width / 2;
ctx.arc(center, center, center, startAngle, endAngle, false);
ctx.lineTo(center, center);
ctx.closePath();
ctx.clip();
// Draw circle image.
if (this._img && this._img.src) {
ctx.drawImage(this._img, 0, 0);
} else {
this._img.onload = function() {
ctx.drawImage(this._img, 0, 0);
}.bind(this);
this._img.src = PROGRESS_RING_IMG;
}
ctx.restore();
return [startAngle, endAngle];
]]>
</body>
</method>
<method name="reset">
<body>
<![CDATA[
this._progressCircleCtx.clearRect(0, 0,
this._progressCanvas.width, this._progressCanvas.height);
]]>
</body>
</method>
</implementation>
</binding>
</bindings>

View File

@ -42,6 +42,10 @@ autoscroller {
-moz-binding: url('chrome://browser/content/bindings/popup.xml#element-popup'); -moz-binding: url('chrome://browser/content/bindings/popup.xml#element-popup');
} }
circularprogressindicator {
-moz-binding: url('chrome://browser/content/bindings/circularprogress.xml#circular-progress-indicator');
}
setting[type="bool"] { setting[type="bool"] {
display: -moz-box; display: -moz-box;
-moz-binding: url("chrome://browser/content/bindings/toggleswitch.xml#setting-fulltoggle-bool"); -moz-binding: url("chrome://browser/content/bindings/toggleswitch.xml#setting-fulltoggle-bool");

View File

@ -296,8 +296,8 @@
command="cmd_stop"/> command="cmd_stop"/>
</hbox> </hbox>
<toolbarbutton id="download-button" class="appbar-secondary" <circularprogressindicator id="download-progress"
oncommand="Appbar.onDownloadButton()"/> oncommand="Appbar.onDownloadButton()"/>
<toolbarbutton id="star-button" class="appbar-primary" type="checkbox" <toolbarbutton id="star-button" class="appbar-primary" type="checkbox"
oncommand="Appbar.onStarButton()"/> oncommand="Appbar.onStarButton()"/>
<toolbarbutton id="pin-button" class="appbar-primary" type="checkbox" <toolbarbutton id="pin-button" class="appbar-primary" type="checkbox"

View File

@ -57,6 +57,8 @@ var Downloads = {
this._progress = new DownloadProgressListener(this); this._progress = new DownloadProgressListener(this);
this.manager.addListener(this._progress); this.manager.addListener(this._progress);
this._downloadProgressIndicator = document.getElementById("download-progress");
}, },
uninit: function dh_uninit() { uninit: function dh_uninit() {
@ -196,6 +198,7 @@ var Downloads = {
accessKey: "", accessKey: "",
callback: function() { callback: function() {
Downloads.manager.retryDownload(aDownload.id); Downloads.manager.retryDownload(aDownload.id);
Downloads._downloadProgressIndicator.reset();
} }
}, },
{ {
@ -203,6 +206,7 @@ var Downloads = {
accessKey: "", accessKey: "",
callback: function() { callback: function() {
Downloads.cancelDownload(aDownload); Downloads.cancelDownload(aDownload);
Downloads._downloadProgressIndicator.reset();
} }
} }
]; ];
@ -222,6 +226,7 @@ var Downloads = {
let fileURI = aDownload.target; let fileURI = aDownload.target;
let file = Downloads._getLocalFile(fileURI); let file = Downloads._getLocalFile(fileURI);
file.reveal(); file.reveal();
Downloads._downloadProgressIndicator.reset();
} }
} }
]; ];
@ -242,6 +247,7 @@ var Downloads = {
accessKey: "", accessKey: "",
callback: function() { callback: function() {
Downloads.openDownload(aDownload); Downloads.openDownload(aDownload);
Downloads._downloadProgressIndicator.reset();
} }
}); });
} }
@ -249,6 +255,22 @@ var Downloads = {
this._notificationBox.PRIORITY_WARNING_MEDIUM); this._notificationBox.PRIORITY_WARNING_MEDIUM);
}, },
_updateCircularProgressMeter: function dv_updateCircularProgressMeter() {
if (!this._progressNotificationInfo) {
return;
}
let totPercent = 0;
for (let info of this._progressNotificationInfo) {
// info[0] => download guid
// info[1].download => nsIDownload
totPercent += info[1].download.percentComplete;
}
let percentComplete = totPercent / this._progressNotificationInfo.size;
this._downloadProgressIndicator.updateProgress(percentComplete);
},
_computeDownloadProgressString: function dv_computeDownloadProgressString(aDownload) { _computeDownloadProgressString: function dv_computeDownloadProgressString(aDownload) {
let totTransferred = 0, totSize = 0, totSecondsLeft = 0; let totTransferred = 0, totSize = 0, totSecondsLeft = 0;
for (let info of this._progressNotificationInfo) { for (let info of this._progressNotificationInfo) {
@ -260,6 +282,7 @@ var Downloads = {
totSize += size; totSize += size;
totSecondsLeft += ((size - amountTransferred) / speed); totSecondsLeft += ((size - amountTransferred) / speed);
} }
// Compute progress in bytes. // Compute progress in bytes.
let amountTransferred = Util.getDownloadSize(totTransferred); let amountTransferred = Util.getDownloadSize(totTransferred);
let size = Util.getDownloadSize(totSize); let size = Util.getDownloadSize(totSize);
@ -296,6 +319,7 @@ var Downloads = {
updateInfobar: function dv_updateInfobar(aDownload) { updateInfobar: function dv_updateInfobar(aDownload) {
this._saveDownloadData(aDownload); this._saveDownloadData(aDownload);
let message = this._computeDownloadProgressString(aDownload); let message = this._computeDownloadProgressString(aDownload);
this._updateCircularProgressMeter();
if (this._progressNotification == null || if (this._progressNotification == null ||
!this._notificationBox.getNotificationWithValue("download-progress")) { !this._notificationBox.getNotificationWithValue("download-progress")) {
@ -310,6 +334,7 @@ var Downloads = {
accessKey: "", accessKey: "",
callback: function() { callback: function() {
Downloads.cancelDownloads(); Downloads.cancelDownloads();
Downloads._downloadProgressIndicator.reset();
} }
} }
]; ];
@ -327,6 +352,7 @@ var Downloads = {
this._saveDownloadData(aDownload); this._saveDownloadData(aDownload);
this._progressNotification.label = this._progressNotification.label =
this._computeDownloadProgressString(aDownload); this._computeDownloadProgressString(aDownload);
this._updateCircularProgressMeter();
} }
}, },

View File

@ -26,6 +26,7 @@ chrome.jar:
content/bindings/selectionoverlay.xml (content/bindings/selectionoverlay.xml) content/bindings/selectionoverlay.xml (content/bindings/selectionoverlay.xml)
content/bindings/cssthrobber.xml (content/bindings/cssthrobber.xml) content/bindings/cssthrobber.xml (content/bindings/cssthrobber.xml)
content/bindings/popup.xml (content/bindings/popup.xml) content/bindings/popup.xml (content/bindings/popup.xml)
content/bindings/circularprogress.xml (content/bindings/circularprogress.xml)
* content/flyoutpanels/FlyoutPanelsUI.js (content/flyoutpanels/FlyoutPanelsUI.js) * content/flyoutpanels/FlyoutPanelsUI.js (content/flyoutpanels/FlyoutPanelsUI.js)
* content/flyoutpanels/AboutFlyoutPanel.js (content/flyoutpanels/AboutFlyoutPanel.js) * content/flyoutpanels/AboutFlyoutPanel.js (content/flyoutpanels/AboutFlyoutPanel.js)

View File

@ -15,6 +15,7 @@ MOCHITEST_METRO_FILES = \
browser_urlbar.js \ browser_urlbar.js \
browser_bookmarks.js \ browser_bookmarks.js \
browser_canonizeURL.js \ browser_canonizeURL.js \
browser_circular_progress_indicator.js \
browser_context_menu_tests.js \ browser_context_menu_tests.js \
browser_context_menu_tests_01.html \ browser_context_menu_tests_01.html \
browser_context_menu_tests_02.html \ browser_context_menu_tests_02.html \
@ -27,6 +28,7 @@ MOCHITEST_METRO_FILES = \
browser_onscreen_keyboard.js \ browser_onscreen_keyboard.js \
browser_onscreen_keyboard.html \ browser_onscreen_keyboard.html \
browser_prefs_ui.js \ browser_prefs_ui.js \
browser_progress_indicator.xul \
browser_remotetabs.js \ browser_remotetabs.js \
browser_tabs.js \ browser_tabs.js \
browser_test.js \ browser_test.js \

View File

@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let doc;
function test() {
waitForExplicitFinish();
Task.spawn(function(){
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
info(chromeRoot + "browser_progress_indicator.xul");
yield addTab(chromeRoot + "browser_progress_indicator.xul");
doc = Browser.selectedTab.browser.contentWindow.document;
}).then(runTests);
}
gTests.push({
desc: "circular progress indicator binding is applied.",
run: function() {
ok(doc, "doc got defined");
let progressIndicator = doc.querySelector("#progress-indicator");
ok(progressIndicator, "progress-indicator is found");
is(typeof progressIndicator.reset, "function", "#progress-indicator has a reset() function");
is(typeof progressIndicator.updateProgress, "function", "#progress-indicator has a updateProgress() function");
}
});
gTests.push({
desc: "start and end angles are correct for various percents complete",
run: function() {
let progressIndicator = doc.querySelector("#progress-indicator");
ok(progressIndicator, "progress-indicator is found");
is(typeof progressIndicator.updateProgress, "function", "#progress-indicator has a updateProgress() function");
let expectedStartAngle = 1.5 * Math.PI;
let percentComplete = 0;
let [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
is(startAngle, expectedStartAngle, "start angle is correct");
is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
percentComplete = 0.05;
[startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
is(startAngle, expectedStartAngle, "start angle is correct");
is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
percentComplete = 0.5;
[startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
is(startAngle, expectedStartAngle, "start angle is correct");
is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
percentComplete = 1;
[startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
is(startAngle, expectedStartAngle, "start angle is correct");
is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
}
});

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
<!DOCTYPE window []>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<circularprogressindicator id="progress-indicator" oncommand=""/>
</window>

View File

@ -448,6 +448,12 @@ documenttab[selected] .documenttab-selection {
transform: none; transform: none;
} }
.circularprogressindicator-progressRing {
margin: 0 @toolbar_horizontal_spacing@;
pointer-events:none;
position: absolute;
}
/* Progress meter ---------------------------------------------------------- */ /* Progress meter ---------------------------------------------------------- */
#progress-container { #progress-container {
@ -675,13 +681,14 @@ documenttab[selected] .documenttab-selection {
/* Application-Specific */ /* Application-Specific */
#download-button { .circularprogressindicator-progressButton {
margin: 0 @toolbar_horizontal_spacing@;
-moz-image-region: rect(0px, 40px, 40px, 0px) !important; -moz-image-region: rect(0px, 40px, 40px, 0px) !important;
} }
#download-button:hover { .circularprogressindicator-progressButton:hover {
-moz-image-region: rect(40px, 40px, 80px, 0px) !important; -moz-image-region: rect(40px, 40px, 80px, 0px) !important;
} }
#download-button:active { .circularprogressindicator-progressButton:active {
-moz-image-region: rect(80px, 40px, 120px, 0px) !important; -moz-image-region: rect(80px, 40px, 120px, 0px) !important;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

View File

@ -99,6 +99,7 @@ chrome.jar:
skin/images/tile-selected-check-hdpi.png (images/tile-selected-check-hdpi.png) skin/images/tile-selected-check-hdpi.png (images/tile-selected-check-hdpi.png)
skin/images/plus-34.png (images/plus-34.png) skin/images/plus-34.png (images/plus-34.png)
skin/images/plus-24.png (images/plus-24.png) skin/images/plus-24.png (images/plus-24.png)
skin/images/progresscircle.png (images/progresscircle.png)
skin/images/overlay-back.png (images/overlay-back.png) skin/images/overlay-back.png (images/overlay-back.png)
skin/images/overlay-plus.png (images/overlay-plus.png) skin/images/overlay-plus.png (images/overlay-plus.png)