Bug 972069 - show progressbar when installing app. r=jryans
authorPaul Rouget <paul@mozilla.com>
Mon, 30 Jun 2014 14:46:25 +0200
changeset 191552 1384e5d7b1f36cb19dd8e808be881e1ca422c9d1
parent 191551 2a523e4ae0046211d52248560255a225164db783
child 191553 34762d090431fa7082f69b3a42f3984c7780e9e8
push id45618
push userkwierso@gmail.com
push dateTue, 01 Jul 2014 01:47:43 +0000
treeherdermozilla-inbound@d0787b1eebc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs972069
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 972069 - show progressbar when installing app. r=jryans
browser/devtools/webide/content/webide.js
browser/devtools/webide/content/webide.xul
browser/devtools/webide/modules/app-manager.js
browser/devtools/webide/themes/webide.css
--- a/browser/devtools/webide/content/webide.js
+++ b/browser/devtools/webide/content/webide.js
@@ -133,16 +133,18 @@ let UI = {
         this.updateRuntimeButton();
         break;
       case "project-validated":
         this.updateTitle();
         this.updateCommands();
         this.updateProjectButton();
         this.updateProjectEditorHeader();
         break;
+      case "install-progress":
+        this.updateProgress(Math.round(100 * details.bytesSent / details.totalBytes));
     };
   },
 
   openInBrowser: function(url) {
     // Open a URL in a Firefox window
     let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
     if (browserWin) {
       let gBrowser = browserWin.gBrowser;
@@ -164,44 +166,81 @@ let UI = {
 
   hidePanels: function() {
     let panels = document.querySelectorAll("panel");
     for (let p of panels) {
       p.hidePopup();
     }
   },
 
+  /********** BUSY UI **********/
+
+  _busyTimeout: null,
+  _busyOperationDescription: null,
+  _busyPromise: null,
+
+  updateProgress: function(percent) {
+    let progress = document.querySelector("#action-busy-determined");
+    progress.mode = "determined";
+    progress.value = percent;
+    this.setupBusyTimeout();
+  },
+
   busy: function() {
     this.hidePanels();
-    document.querySelector("window").classList.add("busy")
+    let win = document.querySelector("window");
+    win.classList.add("busy")
+    win.classList.add("busy-undetermined");
     this.updateCommands();
   },
 
   unbusy: function() {
-    document.querySelector("window").classList.remove("busy")
+    let win = document.querySelector("window");
+    win.classList.remove("busy")
+    win.classList.remove("busy-determined");
+    win.classList.remove("busy-undetermined");
     this.updateCommands();
     this._busyPromise = null;
   },
 
+  setupBusyTimeout: function() {
+    this.cancelBusyTimeout();
+    this._busyTimeout = setTimeout(() => {
+      this.unbusy();
+      UI.reportError("error_operationTimeout", this._busyOperationDescription);
+      this._busyPromise.reject("promise timeout: " + this._busyOperationDescription);
+    }, 30000);
+  },
+
+  cancelBusyTimeout: function() {
+    clearTimeout(this._busyTimeout);
+  },
+
+  busyWithProgressUntil: function(promise, operationDescription) {
+    this.busyUntil(promise, operationDescription);
+    let win = document.querySelector("window");
+    let progress = document.querySelector("#action-busy-determined");
+    progress.mode = "undetermined";
+    win.classList.add("busy-determined");
+    win.classList.remove("busy-undetermined");
+  },
+
   busyUntil: function(promise, operationDescription) {
     // Freeze the UI until the promise is resolved. A 30s timeout
     // will unfreeze the UI, just in case the promise never gets
     // resolved.
     this._busyPromise = promise;
-    let timeout = setTimeout(() => {
-      this.unbusy();
-      UI.reportError("error_operationTimeout", operationDescription);
-      promise.reject("promise timeout: " + operationDescription);
-    }, 30000);
+    this._busyOperationDescription = operationDescription;
+    this.setupBusyTimeout();
     this.busy();
     promise.then(() => {
-      clearTimeout(timeout);
+      this.cancelBusyTimeout();
       this.unbusy();
     }, (e) => {
-      clearTimeout(timeout);
+      this.cancelBusyTimeout();
       UI.reportError("error_operationFail", operationDescription);
       console.error(e);
       this.unbusy();
     });
     return promise;
   },
 
   reportError: function(l10nProperty, ...l10nArgs) {
@@ -391,16 +430,22 @@ let UI = {
 
     // Nothing to show
 
     if (!project) {
       this.resetDeck();
       return;
     }
 
+    // Save last project location
+
+    if (project.location) {
+      Services.prefs.setCharPref("devtools.webide.lastprojectlocation", project.location);
+    }
+
     // Make sure the directory exist before we show Project Editor
 
     let forceDetailsOnly = false;
     if (project.type == "packaged") {
       let directory = new FileUtils.File(project.location);
       forceDetailsOnly = !directory.exists();
     }
 
@@ -415,20 +460,16 @@ let UI = {
 
     // Show ProjectEditor
 
     this.selectDeckPanel("projecteditor");
 
     this.getProjectEditor().then(() => {
       this.updateProjectEditorHeader();
     }, console.error);
-
-    if (project.location) {
-      Services.prefs.setCharPref("devtools.webide.lastprojectlocation", project.location);
-    }
   },
 
   /********** DECK **********/
 
   resetFocus: function() {
     document.commandDispatcher.focusedElement = document.documentElement;
   },
 
@@ -818,22 +859,21 @@ let Cmds = {
 
   showRuntimeDetails: function() {
     UI.selectDeckPanel("runtimedetails");
   },
 
   play: function() {
     switch(AppManager.selectedProject.type) {
       case "packaged":
+        return UI.busyWithProgressUntil(AppManager.installAndRunProject(), "installing and running app");
       case "hosted":
         return UI.busyUntil(AppManager.installAndRunProject(), "installing and running app");
-        break;
       case "runtimeApp":
         return UI.busyUntil(AppManager.runRuntimeApp(), "running app");
-        break;
     }
     return promise.reject();
   },
 
   stop: function() {
     return UI.busyUntil(AppManager.stopRunningApp(), "stopping app");
   },
 
--- a/browser/devtools/webide/content/webide.xul
+++ b/browser/devtools/webide/content/webide.xul
@@ -97,17 +97,20 @@
 
   <toolbar id="main-toolbar">
 
     <vbox flex="1">
       <hbox id="action-buttons-container" class="busy">
         <toolbarbutton id="action-button-play"  class="action-button" command="cmd_play" tooltiptext="&projectMenu_play_label;"/>
         <toolbarbutton id="action-button-stop"  class="action-button" command="cmd_stop" tooltiptext="&projectMenu_stop_label;"/>
         <toolbarbutton id="action-button-debug" class="action-button" command="cmd_toggleToolbox" tooltiptext="&projectMenu_debug_label;"/>
-        <html:img id="action-busy" src="chrome://webide/skin/throbber.svg"/>
+        <hbox id="action-busy" align="center">
+          <html:img id="action-busy-undetermined" src="chrome://webide/skin/throbber.svg"/>
+          <progressmeter id="action-busy-determined"/>
+        </hbox>
       </hbox>
 
       <hbox id="panel-buttons-container">
         <toolbarbutton id="project-panel-button" class="panel-button no-project" command="cmd_showProjectPanel">
           <image class="panel-button-image"/>
           <label class="panel-button-label" value="&projectButton_label;"/>
           <image class="panel-button-anchor"/>
         </toolbarbutton>
--- a/browser/devtools/webide/modules/app-manager.js
+++ b/browser/devtools/webide/modules/app-manager.js
@@ -54,21 +54,25 @@ exports.AppManager = AppManager = {
     };
     if (Services.prefs.getBoolPref("devtools.webide.enableLocalRuntime")) {
       this.runtimeList.custom.push(gLocalRuntime);
     }
     this.trackUSBRuntimes();
     this.trackWiFiRuntimes();
     this.trackSimulatorRuntimes();
 
+    this.onInstallProgress = this.onInstallProgress.bind(this);
+    AppActorFront.on("install-progress", this.onInstallProgress);
+
     this.observe = this.observe.bind(this);
     Services.prefs.addObserver(WIFI_SCANNING_PREF, this, false);
   },
 
   uninit: function() {
+    AppActorFront.off("install-progress", this.onInstallProgress);
     this._unlistenToApps();
     this.selectedProject = null;
     this.selectedRuntime = null;
     this.untrackUSBRuntimes();
     this.untrackWiFiRuntimes();
     this.untrackSimulatorRuntimes();
     this._runningApps.clear();
     this.runtimeList = null;
@@ -129,16 +133,20 @@ exports.AppManager = AppManager = {
         this._getRunningApps();
         this.update("list-tabs-response");
       });
     }
 
     this.update("connection");
   },
 
+  onInstallProgress: function(event, details) {
+    this.update("install-progress", details);
+  },
+
   onWebAppsStoreready: function() {
     this.update("runtime-apps-found");
   },
 
   _runningApps: new Set(),
   _getRunningApps: function() {
     let client = this.connection.client;
     if (!this._listTabsResponse.webappsActor) {
--- a/browser/devtools/webide/themes/webide.css
+++ b/browser/devtools/webide/themes/webide.css
@@ -16,23 +16,25 @@
   margin-top: -50px;
   pointer-events: none;
 }
 
 #panel-buttons-container > .panel-button {
   pointer-events: auto;
 }
 
-#action-busy {
+#action-busy-undetermined {
   height: 24px;
   width: 24px;
 }
 
 window.busy .action-button,
-window:not(.busy) #action-busy {
+window:not(.busy) #action-busy,
+window.busy-undetermined #action-busy-determined,
+window.busy-determined #action-busy-undetermined {
   display: none;
 }
 
 /* Panel buttons */
 
 .panel-button {
   -moz-appearance: none;
   -moz-box-align: center;