Bläddra i källkod

Merge pull request #10 from thingsSDK/progress-ui

Progress ui
Andrew Chalkley 9 år sedan
förälder
incheckning
c935a7950c
5 ändrade filer med 199 tillägg och 65 borttagningar
  1. 12 1
      back-end/prepare_binaries.js
  2. 131 37
      front-end/css/style.css
  3. 24 18
      front-end/index.html
  4. 27 4
      front-end/js/app.js
  5. 5 5
      index.js

+ 12 - 1
back-end/prepare_binaries.js

@@ -2,6 +2,7 @@
 const http = require("http");
 const unzip = require("unzip");
 const fs = require("fs");
+const EventEmitter = require("events");
 
 function isBinaryFileRequired(flashSpecification, fileName) {
     return flashSpecification.map(binary => binary.path).indexOf(fileName) !== -1;
@@ -16,11 +17,17 @@ function addBufferToBinary(flashSpecification, fileName, buffer) {
 }
 
 function prepareBinaries(manifest, callback) {
+    const eventEmitter = new EventEmitter();
     const flashContents = manifest.flash;
     const downloadRequest = http.get(manifest.download, (response) => {
         response.pipe(unzip.Parse()).on('entry', (entry) => {
             const fileName = entry.path;
             if (isBinaryFileRequired(flashContents, fileName)) {
+                eventEmitter.emit("entry", {
+                    display: `Extracting ${fileName}`,
+                    stage: "start"
+                });
+
                 let body;
                 entry.on("data", function(data){
                     if(body) {
@@ -29,6 +36,10 @@ function prepareBinaries(manifest, callback) {
                         body = data;
                     }
                 }).on("end", () => {
+                    eventEmitter.emit("entry", {
+                        display: `Extracted ${fileName}`,
+                        stage: "end"
+                    });
                     addBufferToBinary(flashContents, fileName, body);
                 }).on("error", callback);
 
@@ -36,11 +47,11 @@ function prepareBinaries(manifest, callback) {
                 entry.autodrain();
             }
         }).on("close", () => {
-            console.log("close");
             callback(null, flashContents);
         });
         response.on("error", callback);
     });
+    return eventEmitter;
 }
 
 module.exports = prepareBinaries;

+ 131 - 37
front-end/css/style.css

@@ -1,58 +1,152 @@
-body {
-  padding: 50px;
-  font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
+* {
+	margin: 0;
+	padding: 0;
 }
 
-#progress {
-    display: block;
-    border: 1px solid black;
-    background: #00B7FF;
-    width: 0%;
-    height: 10px;
-    float:left;
+body {
+	padding: 50px;
+	font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
+	background: #333;
+	color: white;
 }
 
 button {
-  clear:both;
-  background: #3498db;
-  border-radius: 28px;
-  color: #fff;
-  font-size: 20px;
-  padding: 10px 20px 10px 20px;
-  text-decoration: none;
-  border:0;
-    float: left;
+	clear:both;
+	background: #3498db;
+	border-radius: 5px;
+	color: #fff;
+	padding: 10px 20px 10px 20px;
+	text-decoration: none;
+	border:0;
+    width: 100%;
 }
 
+button:disabled {
+	background: #eee;
+	color: #aaa
+}
+
+
 button:hover {
-  background: #3cb0fd;
-  text-decoration: none;
+	background: #3cb0fd;
+	text-decoration: none;
 }
 
+button:hover:disabled {
+    background: #bbb;
+    color: #aaa
+}
 
 label {
-    width: 215px;
-    float: left;
-    clear: both;
+	width: 180px;
+	display: inline-block;
 }
 
 select {
-    float: left;
-    width: 200px;
-    font-size: 15px;
+	width: 200px;
+	font-size: 15px;
 }
 footer {
-   position:fixed;
-   left:0px;
-   bottom:0px;
-   height:30px;
-   width:100%;
-   background: #3cb0fd;
-   color: white;
+	position:fixed;
+	left:0;
+	bottom:0;
+	height:30px;
+	width:100%;
+	background: #0568c6;
+	color: white;
 }
 
 footer span {
-    top: 5px;
-    left: 10px;
-    position: relative;
+	top: 5px;
+	left: 10px;
+	position: relative;
+}
+
+#progressBar {
+    display:none;
+}
+
+#progress {
+	width: 0;
+}
+
+#form div {
+	margin-bottom: 30px;
+	text-align: center;
+}
+#form label {
+	text-align: right;
+}
+/*
+* https://css-tricks.com/examples/ProgressBars/
+*/
+.meter {
+	height: 40px;  /* Can be anything */
+	position: relative;
+	margin: 40px 0 20px 0; /* Just for demo spacing */
+	background: #555;
+	border-radius: 25px;
+	padding: 10px;
+	box-shadow: inset 0 -1px 1px rgba(255,255,255,0.3);
+}
+.meter > span {
+	display: block;
+	height: 100%;
+	border-top-right-radius: 8px;
+	border-bottom-right-radius: 8px;
+	border-top-left-radius: 20px;
+	border-bottom-left-radius: 20px;
+	background-color: rgb(5, 138, 255);
+	background-image: -webkit-gradient(
+			linear,
+			left bottom,
+			left top,
+			color-stop(0,  rgb(5, 138, 255)),
+			color-stop(1, rgb(71, 190, 240))
+	);
+
+	box-shadow:
+			inset 0 2px 9px  rgba(255,255,255,0.3),
+			inset 0 -2px 6px rgba(0,0,0,0.4);
+	position: relative;
+	overflow: hidden;
+}
+.meter > span:after, .animate > span > span {
+	content: "";
+	position: absolute;
+	top: 0; left: 0; bottom: 0; right: 0;
+	background-image:
+			-webkit-gradient(linear, 0 0, 100% 100%,
+			color-stop(.25, rgba(255, 255, 255, .2)),
+			color-stop(.25, transparent), color-stop(.5, transparent),
+			color-stop(.5, rgba(255, 255, 255, .2)),
+			color-stop(.75, rgba(255, 255, 255, .2)),
+			color-stop(.75, transparent), to(transparent)
+			);
+	z-index: 1;
+	background-size: 50px 50px;
+	-webkit-animation: move 2s linear infinite;
+	border-top-right-radius: 8px;
+	border-bottom-right-radius: 8px;
+	border-top-left-radius: 20px;
+	border-bottom-left-radius: 20px;
+	overflow: hidden;
+}
+
+.animate > span:after {
+	display: none;
+}
+
+@-webkit-keyframes move {
+	0% {
+		background-position: 0 0;
+	}
+	100% {
+		background-position: 50px 50px;
+	}
+}
+
+.nostripes > span > span, .nostripes > span:after {
+	-webkit-animation: none;
+	background-image: none;
 }

+ 24 - 18
front-end/index.html

@@ -6,24 +6,30 @@
     <link rel="stylesheet" href="css/style.css">
 </head>
 <body>
-    <label for="ports">Select Port:</label>
-    <select title="Select a Serial/COM Port" id="ports" name="ports" disabled>
-
-    </select>
-
-    <label for="manifests">Select Binaries to Flash:</label>
-    <select title="Select Binaries to Flash" id="manifests" name="manifests" disabled>
-
-    </select>
-
-
-    <button id="flash-button" disabled>
-        Flash!
-    </button>
-
-    <div id="progress"></div>
-
-    <footer><span id="status"></span></footer>
+<div id="form">
+    <div>
+        <label for="ports">Select Port:</label>
+        <select title="Select a Serial/COM Port" id="ports" name="ports" disabled>
+
+        </select>
+    </div>
+    <div>
+        <label for="manifests">Select Binaries to Flash:</label>
+        <select title="Select Binaries to Flash" id="manifests" name="manifests" disabled>
+
+        </select>
+    </div>
+    <div>
+        <button id="flash-button" disabled>
+            Flash!
+        </button>
+    </div>
+</div>
+<div id="progressBar" class="meter animate">
+    <span id="progress"><span></span></span>
+</div>
+
+<footer><span id="status"></span></footer>
 
 <!-- Javascript -->
 <script src="js/app.js" charset="utf-8"></script>

+ 27 - 4
front-end/js/app.js

@@ -36,7 +36,9 @@ const flashButton = $("flash-button");
 const appStatus = $("status");
 const portsSelect = new PortSelect($("ports"));
 const manifestsSelect = $("manifests");
+const progressHolder = $("progressBar");
 const progressBar =  $("progress");
+const form = $("form");
 
 /************************
  * Utility Functions
@@ -98,6 +100,8 @@ serialScanner.on("error", onError);
  * Updates UI to say it's ready
  */
 function readyToFlash() {
+    progressHolder.style.display = "none";
+    form.style.display = "block";
     appStatus.textContent = "Ready";
     enableInputs();
 }
@@ -151,22 +155,30 @@ function getManifests() {
 }
 
 function flashWithManifest(manifest) {
+    form.style.display = "none";
+    progressHolder.style.display = "block";
     appStatus.textContent = `Flashing ${portsSelect.value}`;
+    const numberOfSteps = manifest.flash.length * 2;
+    let currectStepNumber = 1;
     prepareBinaries(manifest, (err, flashSpec) => {
         if(err) throw err;
 
         const esp = new RomComm({
             portName: portsSelect.value,
-            baudRate: 115200,
+            baudRate: 115200
         });
 
         esp.on('progress', (progress) => {
-            applicationCache.textContent = progress.display;
-            progressBar.style.width = `${Math.round((progress.details.flashedBytes/progress.details.totalBytes) * 100)}%`;
+            const flashPercent = Math.round((progress.details.flashedBytes/progress.details.totalBytes) * 100);
+            const processSoFar = 50; //From download and extracting.
+            const flashProcess = flashPercent / 2; //To add to the overall progress
+            updateProgressBar(processSoFar + flashProcess);
+            appStatus.textContent = `${progress.display} - ${flashPercent}%`;
+
         });
 
         esp.open().then((result) => {
-            appStatus.textContent = `Flashing ${portsSelect.value}...Opened Port.`;
+            appStatus.textContent = `Flashing device connected to ${portsSelect.value}`;
             let promise = Promise.resolve();
             return esp.flashSpecifications(flashSpec)
                 .then(() => esp.close())
@@ -176,11 +188,22 @@ function flashWithManifest(manifest) {
                     log.info("Flashed to latest Espruino build!", result);
                 });
         }).catch((error) => {
+            new Notification("An error occured during flashing.");
+            readyToFlash();
             log.error("Oh noes!", error);
         });
+    }).on("entry", (progress) => {
+        //For the download/extract progress. The other half is flashing.
+        const extractPercent = Math.round((currectStepNumber++/numberOfSteps) * 50);
+        updateProgressBar(extractPercent);
+        appStatus.textContent = progress.display;
     });
 }
 
+function updateProgressBar(percent) {
+    progressBar.style.width = `${percent}%`;
+}
+
 /**
  * Get's manifest list for possibilities for flashing,
  * scans serial ports and sets up timer for checking for changes.

+ 5 - 5
index.js

@@ -23,10 +23,10 @@ app.on('window-all-closed', function() {
 app.on('ready', function() {
   // Create the browser window.
   mainWindow = new BrowserWindow({
-    width: 450,
-    height: 160,
-    'min-width': 450,
-    'min-height': 160,
+    width: 520,
+    height: 300,
+    'min-width': 520,
+    'min-height': 300,
     'accept-first-mouse': true
   });
 
@@ -34,7 +34,7 @@ app.on('ready', function() {
   mainWindow.loadURL('file://' + __dirname + '/front-end/index.html');
 
   // Open the DevTools.
-  mainWindow.webContents.openDevTools();
+  //mainWindow.webContents.openDevTools();
 
   // Emitted when the window is closed.
   mainWindow.on('closed', function() {