From 1eab865e4548928a920f3118d65b11920285de44 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Sun, 3 Nov 2019 11:13:21 +0000 Subject: [PATCH] Added proper remove app behaviour --- comms.js | 49 ++++++++++----- index.html | 8 ++- index.js | 180 ++++++++++++++++++++++++++++++++--------------------- 3 files changed, 148 insertions(+), 89 deletions(-) diff --git a/comms.js b/comms.js index b03ac9359..6bbf3ef26 100644 --- a/comms.js +++ b/comms.js @@ -1,28 +1,35 @@ Puck.debug=3; +/* 'app' is of the form: +{ name: "T-Rex", + icon: "trex.png", + description: "T-Rex game in the style of Chrome's offline game", + storage: [ + {name:"+trex",file:"trex.json"}, + {name:"-trex",file:"trex.js"}, + {name:"*trex",file:"trex-icon.js"} + ] +} +*/ + +// FIXME: use UART lib so that we handle errors properly var Comms = { uploadApp : app => { - /* eg - { name: "T-Rex", - icon: "trex.png", - description: "T-Rex game in the style of Chrome's offline game", - storage: [ - {name:"+trex",file:"trex.json"}, - {name:"-trex",file:"trex.js"}, - {name:"*trex",file:"trex-icon.js"} - ] - } - */ return new Promise((resolve,reject) => { // Load all files Promise.all(app.storage.map(storageFile => httpGet("apps/"+storageFile.file) // map each file to a command to load into storage - .then(contents=>`require('Storage').write(${toJS(storageFile.name)},${toJS(contents)});`))) - // + .then(contents=>`\x10require('Storage').write(${toJS(storageFile.name)},${storageFile.evaluate ? contents : toJS(contents)});`))) .then(function(fileContents) { fileContents = fileContents.join("\n"); - Puck.write(fileContents,function() { - resolve(); + console.log("uploadApp",fileContents); + // reset to ensure we have enough memory to upload what we need to + Puck.write("\x03reset();\n", function() { + setTimeout(function() { // wait for reset + Puck.write(fileContents,function() { + resolve(); + }); + },500); }); }); }); @@ -31,9 +38,21 @@ getInstalledApps : () => { return new Promise((resolve,reject) => { Puck.write("\x03",() => { Puck.eval('require("Storage").list().filter(f=>f[0]=="+").map(f=>f.substr(1))', appList => { + console.log("getInstalledApps", appList); resolve(appList); }); }); }); +}, +removeApp : app => { // expects an app structure + var cmds = app.storage.map(file=>{ + return `\x10require("Storage").erase(${toJS(file.name)});\n`; + }).join(""); + console.log("removeApp", cmds); + return new Promise((resolve,reject) => { + Puck.write("\x03"+cmds,() => { + resolve(); + }); + }); } }; diff --git a/index.html b/index.html index bad0efe90..f4485d452 100644 --- a/index.html +++ b/index.html @@ -9,10 +9,14 @@ Bangle.js loader diff --git a/index.js b/index.js index 770c6e5e5..25519dfc9 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,15 @@ -var appjson = []; +var appJSON = []; // List of apps and info from apps.json +var appsInstalled = []; // list of app IDs + httpGet("apps.json").then(apps=>{ - appjson = JSON.parse(apps); - appjson.sort(appSorter); + appJSON = JSON.parse(apps); + appJSON.sort(appSorter); refreshLibrary(); }); // Status // =========================================== Top Navigation -function showToast(message) { +function showToast(message, type) { // toast-primary, toast-success, toast-warning or toast-error var toastcontainer = document.getElementById("toastcontainer"); var msgDiv = htmlElement(`
`); @@ -42,7 +44,7 @@ function showPrompt(title, text) { document.body.append(modal); htmlToArray(modal.getElementsByTagName("button")).forEach(button => { button.addEventListener("click",event => { - var isYes = event.target.getAttribute("isyes"); + var isYes = event.target.getAttribute("isyes")=="1"; if (isYes) resolve(); else reject(); modal.remove(); @@ -65,7 +67,98 @@ function showTab(tabname) { // =========================================== Library function refreshLibrary() { var panelbody = document.querySelector("#librarycontainer .panel-body"); - panelbody.innerHTML = appjson.map((app,idx) => `
+ panelbody.innerHTML = appJSON.map((app,idx) => `
+
+
${escapeHtml(app.name)}
+
+
+

${escapeHtml(app.name)}

+

${escapeHtml(app.description)}

+
+
+ +
+
+ `); + // set badge up top + var tab = document.querySelector("#tab-librarycontainer a"); + tab.classList.add("badge"); + tab.setAttribute("data-badge", appJSON.length); + htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => { + button.addEventListener("click",event => { + var icon = event.target; + var appid = icon.getAttribute("appid"); + var app = appJSON.find(app=>app.id==appid); + if (!app) return; + if (icon.classList.contains("icon-upload")) { + icon.classList.remove("icon-upload"); + icon.classList.add("loading"); + Comms.uploadApp(app).then(() => { + appsInstalled.push(app.id); + showToast(app.name+" Uploaded!", "success"); + icon.classList.remove("loading"); + icon.classList.add("icon-delete"); + refreshMyApps(); + }).catch(err => { + showToast("Upload failed, "+err, "error"); + icon.classList.remove("loading"); + icon.classList.add("icon-upload"); + }); + } else { + icon.classList.remove("icon-delete"); + icon.classList.add("loading"); + removeApp(app); + } + }); + }); +} + +refreshLibrary(); +// =========================================== My Apps + +function removeApp(app) { + return showPrompt("Delete","Really remove app '"+appid+"'?").then(() => { + Comms.removeApp(app).then(()=>{ + appsInstalled = appsInstalled.filter(id=>id!=app.id); + showToast(app.name+" removed successfully","success"); + refreshMyApps(); + refreshLibrary(); + }, err=>{ + showToast(app.name+" removal failed, "+err,"error"); + }); + }); +} + +function appNameToApp(appName) { + var app = appJSON.find(app=>app.id==appName); + if (app) return app; + /* If app not known, add just one file + which is the JSON - so we'll remove it from + the menu but may not get rid of all files. */ + return { id: appName, + name: "Unknown app "+appName, + icon: "unknown.png", + description: "Unknown app", + storage: [ {name:"+"+appName}], + unknown: true, + }; +} + +function showLoadingIndicator() { + var panelbody = document.querySelector("#myappscontainer .panel-body"); + var tab = document.querySelector("#tab-myappscontainer a"); + // set badge up top + tab.classList.add("badge"); + tab.setAttribute("data-badge", ""); + // Loading indicator + panelbody.innerHTML = '
'; +} + +function refreshMyApps() { + var panelbody = document.querySelector("#myappscontainer .panel-body"); + var tab = document.querySelector("#tab-myappscontainer a"); + tab.setAttribute("data-badge", appsInstalled.length); + panelbody.innerHTML = appsInstalled.map(appNameToApp).sort(appSorter).map(app => `
${escapeHtml(app.name)}
@@ -74,88 +167,31 @@ function refreshLibrary() {

${escapeHtml(app.description)}

- +
`); - // set badge up top - var tab = document.querySelector("#tab-librarycontainer a"); - tab.classList.add("badge"); - tab.setAttribute("data-badge", appjson.length); htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => { button.addEventListener("click",event => { var icon = event.target; var appid = icon.getAttribute("appid"); - var app = appjson.find(app=>app.id==appid); - if (!app) return; - icon.classList.remove("icon-upload"); - icon.classList.add("loading"); - Comms.uploadApp(app).then(() => { - showToast(app.name+" Uploaded!"); - icon.classList.remove("loading"); - icon.classList.add("icon-delete"); - }).catch(() => { - icon.classList.remove("loading"); - icon.classList.add("icon-upload"); - }); + var app = appNameToApp(appid); + removeApp(app); }); }); } -refreshLibrary(); -// =========================================== My Apps - -function appNameToApp(appName) { - var app = appjson.find(app=>app.id==appName); - if (app) return app; - return { id: "appName", - name: "Unknown app "+appName, - icon: "unknown.png", - description: "Unknown app", - storage: [], - unknown: true, - }; -} - -function refreshMyApps() { - var panelbody = document.querySelector("#myappscontainer .panel-body"); - var tab = document.querySelector("#tab-myappscontainer a"); - // set badge up top - tab.classList.add("badge"); - tab.setAttribute("data-badge", ""); - // Loading indicator - panelbody.innerHTML = '
'; +function getInstalledApps() { + showLoadingIndicator(); // Get apps Comms.getInstalledApps().then(appIDs => { - tab.setAttribute("data-badge", appIDs.length); - panelbody.innerHTML = appIDs.map(appNameToApp).sort(appSorter).map(app => `
-
-
${escapeHtml(app.name)}
-
-
-

${escapeHtml(app.name)}

-

${escapeHtml(app.description)}

-
-
- -
-
- `); - htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => { - button.addEventListener("click",event => { - var icon = event.target; - var appid = icon.getAttribute("appid"); - var app = appNameToApp(appid); - showPrompt("Delete","Really remove app '"+appid+"'?").then(() => { - // remove app! - refreshMyApps(); - }); - }); - }); + appsInstalled = appIDs; + refreshMyApps(); + refreshLibrary(); }); } document.getElementById("myappsrefresh").addEventListener("click",event=>{ - refreshMyApps(); + getInstalledApps(); });