Fix issues caused by Storage.eraseAll taking too long (fix #64)

Add progress bar and description to erase, uploads, and getting file info
master
Gordon Williams 2020-02-27 15:52:20 +00:00
parent d1fe3c5c97
commit 5c3d1a48fa
2 changed files with 106 additions and 36 deletions

View File

@ -2,7 +2,15 @@ Puck.debug=3;
// FIXME: use UART lib so that we handle errors properly
var Comms = {
uploadApp : app => {
reset : () => {
return new Promise((resolve,reject) => {
Puck.write("\x03reset();\n", (result) => {
if (result===null) return reject("");
setTimeout(resolve,500);
});
});
},
uploadApp : (app,skipReset) => {
return AppInfo.getFiles(app, httpGet).then(fileContents => {
return new Promise((resolve,reject) => {
var appJSONFile = fileContents.find(f=>f.name=="+"+app.id);
@ -16,16 +24,18 @@ uploadApp : app => {
}
fileContents = fileContents.map(storageFile=>storageFile.cmd).join("\n")+"\n";
console.log("uploadApp",fileContents);
// reset to ensure we have enough memory to upload what we need to
Puck.write("\x03reset();\n", (result) => {
if (result===null) return reject("");
setTimeout(() => { // wait for reset
Puck.write("\x10E.showMessage('Uploading...')\n"+fileContents+"\x10E.showMessage('Hold BTN3\\nto reload')\n",(result) => {
if (result===null) return reject("");
resolve(appJSON);
});
},500);
});
function doUpload() {
Puck.write(`\x10E.showMessage('Uploading\\n${app.id}...')\n${fileContents}\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => {
if (result===null) return reject("");
resolve(appJSON);
});
}
if (skipReset) {
doUpload();
} else {
// reset to ensure we have enough memory to upload what we need to
Comms.reset().then(doUpload)
}
});
});
},
@ -46,24 +56,21 @@ removeApp : app => { // expects an app structure
return `\x10require("Storage").erase(${toJS(file.name)});\n`;
}).join("");
console.log("removeApp", cmds);
return new Promise((resolve,reject) => {
Puck.write("\x03"+cmds+"\x10E.showMessage('Hold BTN3\\nto reload')\n",(result) => {
return Comms.reset().then(new Promise((resolve,reject) => {
Puck.write(`\x03\x10E.showMessage('Erasing\\n${app.id}...')${cmds}\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => {
if (result===null) return reject("");
resolve();
});
});
}));
},
removeAllApps : () => {
return new Promise((resolve,reject) => {
// Use eval here so we wait for it to finish
Puck.eval('require("Storage").eraseAll()||true', (result,err) => {
return Comms.reset().then(new Promise((resolve,reject) => {
// Use write with newline here so we wait for it to finish
Puck.write('\x10E.showMessage("Erasing...");require("Storage").eraseAll();Bluetooth.println("OK")\n', (result,err) => {
if (result===null) return reject(err || "");
Puck.write('\x03\x10reset()\n',(result) => {
if (result===null) return reject("");
resolve();
});
});
});
resolve();
}, true /* wait for newline */);
}));
},
setTime : () => {
return new Promise((resolve,reject) => {

View File

@ -29,17 +29,31 @@ function showToast(message, type) {
msgDiv.remove();
}, 5000);
}
var progressToast;
Puck.writeProgress = function(charsSent, charsTotal) {
if (charsSent===undefined) {
if (progressToast) progressToast.remove();
progressToast = undefined;
return;
}
var percent = Math.round(charsSent*100/charsTotal);
var progressToast; // the DOM element
var progressSticky; // showProgress(,,"sticky") don't remove until hideProgress("sticky")
var progressInterval; // the interval used if showProgress(..., "animate")
var progressPercent; // the current progress percentage
function showProgress(text, percent, sticky) {
if (sticky=="sticky")
progressSticky = true;
if (!progressToast) {
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = undefined;
}
if (percent == "animate") {
progressInterval = setInterval(function() {
progressPercent += 2;
if (progressPercent>100) progressPercent=0;
showProgress(undefined, progressPercent);
}, 100);
percent = 0;
}
progressPercent = percent;
var toastcontainer = document.getElementById("toastcontainer");
progressToast = htmlElement(`<div class="toast">
${text ? `<div>${text}</div>`:``}
<div class="bar bar-sm">
<div class="bar-item" id="progressToast" role="progressbar" style="width:${percent}%;" aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
@ -51,6 +65,26 @@ Puck.writeProgress = function(charsSent, charsTotal) {
pt.style.width = percent+"%";
}
}
function hideProgress(sticky) {
if (progressSticky && sticky!="sticky")
return;
progressSticky = false;
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = undefined;
}
if (progressToast) progressToast.remove();
progressToast = undefined;
}
Puck.writeProgress = function(charsSent, charsTotal) {
if (charsSent===undefined) {
hideProgress();
return;
}
var percent = Math.round(charsSent*100/charsTotal);
showProgress(undefined, percent);
}
function showPrompt(title, text, buttons) {
if (!buttons) buttons={yes:1,no:1};
return new Promise((resolve,reject) => {
@ -78,7 +112,7 @@ function showPrompt(title, text, buttons) {
document.body.append(modal);
modal.querySelector("a[href='#close']").addEventListener("click",event => {
event.preventDefault();
reject();
reject("User cancelled");
modal.remove();
});
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
@ -86,7 +120,7 @@ function showPrompt(title, text, buttons) {
event.preventDefault();
var isYes = event.target.getAttribute("isyes")=="1";
if (isYes) resolve();
else reject();
else reject("User cancelled");
modal.remove();
});
});
@ -132,7 +166,14 @@ function handleCustomApp(app) {
var app = event.data;
console.log("Received custom app", app);
modal.remove();
Comms.uploadApp(app).then(resolve,reject);
showProgress(`Uploading ${app.name}`,undefined,"sticky");
Comms.uploadApp(app).then(()=>{
hideProgress("sticky");
resolve();
}).catch(e => {
hideProgress("sticky");
reject(e);
});
}, false);
});
}
@ -270,7 +311,9 @@ function refreshLibrary() {
// upload
icon.classList.remove("icon-upload");
icon.classList.add("loading");
showProgress(`Uploading ${app.name}`,undefined,"sticky");
Comms.uploadApp(app).then((appJSON) => {
hideProgress("sticky");
if (appJSON) appsInstalled.push(appJSON);
showToast(app.name+" Uploaded!", "success");
icon.classList.remove("loading");
@ -278,6 +321,7 @@ function refreshLibrary() {
refreshMyApps();
refreshLibrary();
}).catch(err => {
hideProgress("sticky");
showToast("Upload failed, "+err, "error");
icon.classList.remove("loading");
icon.classList.add("icon-upload");
@ -334,16 +378,19 @@ function removeApp(app) {
}
function updateApp(app) {
showProgress(`Upgrading ${app.name}`,undefined,"sticky");
Comms.removeApp(app).then(()=>{
showToast(app.name+" removed successfully. Updating...",);
appsInstalled = appsInstalled.filter(a=>a.id!=app.id);
return Comms.uploadApp(app);
}).then((appJSON) => {
hideProgress("sticky");
if (appJSON) appsInstalled.push(appJSON);
showToast(app.name+" Updated!", "success");
refreshMyApps();
refreshLibrary();
}, err=>{
hideProgress("sticky");
showToast(app.name+" update failed, "+err,"error");
});
}
@ -413,14 +460,20 @@ return `<div class="tile column col-6 col-sm-12 col-xs-12">
function getInstalledApps() {
showLoadingIndicator("myappscontainer");
showProgress(`Getting app list...`,undefined,"sticky");
// Get apps and files
return Comms.getInstalledApps()
.then(appJSON => {
hideProgress("sticky");
appsInstalled = appJSON;
refreshMyApps();
refreshLibrary();
})
.then(() => handleConnectionChange(true));
.then(() => handleConnectionChange(true))
.catch(err=>{
hideProgress("sticky");
return Promise.reject();
});
}
var connectMyDeviceBtn = document.getElementById("connectmydevice");
@ -475,12 +528,15 @@ document.getElementById("settime").addEventListener("click",event=>{
});
document.getElementById("removeall").addEventListener("click",event=>{
showPrompt("Remove All","Really remove all apps?").then(() => {
showProgress("Removing all apps","animate", "sticky");
return Comms.removeAllApps();
}).then(()=>{
hideProgress("sticky");
appsInstalled = [];
showToast("All apps removed","success");
return getInstalledApps();
}).catch(err=>{
hideProgress("sticky");
showToast("App removal failed, "+err,"error");
});
});
@ -495,18 +551,25 @@ document.getElementById("installdefault").addEventListener("click",event=>{
appCount = defaultApps.length;
return showPrompt("Install Defaults","Remove everything and install default apps?");
}).then(() => {
showProgress("Removing all apps","animate", "sticky");
return Comms.removeAllApps();
}).then(()=>{
hideProgress("sticky");
appsInstalled = [];
showToast(`Existing apps removed. Installing ${appCount} apps...`);
return new Promise(resolve => {
return new Promise((resolve,reject) => {
function upload() {
var app = defaultApps.shift();
if (app===undefined) return resolve();
showProgress(`${app.name} (${appCount-defaultApps.length}/${appCount})`,undefined,"sticky");
Comms.uploadApp(app).then((appJSON) => {
hideProgress("sticky");
if (appJSON) appsInstalled.push(appJSON);
showToast(`(${appCount-defaultApps.length}/${appCount}) ${app.name} Uploaded`);
upload();
}).catch(function() {
hideProgress("sticky");
reject()
});
}
upload();