forked from FOSS/BangleApps
handle printing app versions
parent
bcf0f80d29
commit
e0320bb2f7
28
README.md
28
README.md
|
@ -46,6 +46,8 @@ easily distinguish between file types, we use the following:
|
|||
}
|
||||
```
|
||||
|
||||
See `app.json / widget.json` below for more info on the correct format.
|
||||
|
||||
* Create an entry in `apps.json` as follows:
|
||||
|
||||
```
|
||||
|
@ -155,8 +157,32 @@ The widget example is available in [`apps/_example_widget`](apps/_example_widget
|
|||
* `widget.json` - short widget name and storage names
|
||||
* `widget.js` - widget code
|
||||
|
||||
### `app.json` / `widget.json` format
|
||||
|
||||
#### `apps.json` format
|
||||
This is the file that's loaded onto Bangle.js, which gives information
|
||||
about the app.
|
||||
|
||||
```
|
||||
{
|
||||
"name":"Short Name", // for Bangle.js menu
|
||||
"icon":"*7chname", // for Bangle.js menu
|
||||
"src":"-7chname", // source file
|
||||
"type":"widget/clock/app", // optional, default "app"
|
||||
// if this is 'widget' then it's not displayed in the menu
|
||||
// if it's 'clock' then it'll be loaded by default at boot time
|
||||
"hasWidgets" : true // optional, default false
|
||||
// if true, widgets will be loaded so 'drawWidgets' can be
|
||||
// used from the app. You just need to ensure you leave the
|
||||
// top and bottom 24px alone
|
||||
"version":"1.23",
|
||||
// added by BangleApps loader on upload based on apps.json
|
||||
"files:"file1,file2,file3",
|
||||
// added by BangleApps loader on upload - lists all files
|
||||
// that belong to the app so it can be deleted
|
||||
}
|
||||
```
|
||||
|
||||
### `apps.json` format
|
||||
|
||||
```
|
||||
{ "id": "appid", // 7 character app id
|
||||
|
|
|
@ -31,6 +31,7 @@ var AppInfo = {
|
|||
} catch (e) {
|
||||
reject(storageFile.name+" is not valid JSON");
|
||||
}
|
||||
if (app.version) json.version = app.version;
|
||||
json.files = fileContents.map(storageFile=>storageFile.name).join(",");
|
||||
storageFile.content = JSON.stringify(json);
|
||||
}
|
||||
|
|
13
comms.js
13
comms.js
|
@ -5,6 +5,15 @@ var Comms = {
|
|||
uploadApp : app => {
|
||||
return AppInfo.getFiles(app, httpGet).then(fileContents => {
|
||||
return new Promise((resolve,reject) => {
|
||||
var appJSONFile = fileContents.find(f=>f.name=="+"+app.id);
|
||||
var appJSON = undefined;
|
||||
if (appJSONFile)
|
||||
try {
|
||||
appJSON=JSON.parse(appJSONFile.content);
|
||||
appJSON.id = app.id;
|
||||
} catch(e) {
|
||||
console.log("Error decoding app JSON for",app.id,e);
|
||||
}
|
||||
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
|
||||
|
@ -13,7 +22,7 @@ uploadApp : app => {
|
|||
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();
|
||||
resolve(appJSON);
|
||||
});
|
||||
},500);
|
||||
});
|
||||
|
@ -24,7 +33,7 @@ getInstalledApps : () => {
|
|||
return new Promise((resolve,reject) => {
|
||||
Puck.write("\x03",(result) => {
|
||||
if (result===null) return reject("");
|
||||
Puck.eval('require("Storage").list().filter(f=>f[0]=="+").map(f=>f.substr(1))', (appList,err) => {
|
||||
Puck.eval('require("Storage").list().filter(f=>f[0]=="+").map(f=>{var j=require("Storage").readJSON(f)||{};j.id=f.substr(1);return j})', (appList,err) => {
|
||||
if (appList===null) return reject(err || "");
|
||||
console.log("getInstalledApps", appList);
|
||||
resolve(appList);
|
||||
|
|
41
index.js
41
index.js
|
@ -1,5 +1,5 @@
|
|||
var appJSON = []; // List of apps and info from apps.json
|
||||
var appsInstalled = []; // list of app IDs
|
||||
var appsInstalled = []; // list of app JSON
|
||||
|
||||
httpGet("apps.json").then(apps=>{
|
||||
try {
|
||||
|
@ -149,11 +149,15 @@ function refreshLibrary() {
|
|||
|
||||
panelbody.innerHTML = visibleApps.map((app,idx) => {
|
||||
var icon = "icon-upload";
|
||||
var versionInfo = app.version || "";
|
||||
if (app.custom)
|
||||
icon = "icon-menu";
|
||||
if (appsInstalled.includes(app.id))
|
||||
if (appsInstalled.find(a=>a.id==app.id)) {
|
||||
icon = "icon-delete";
|
||||
versionInfo+=" installed";
|
||||
}
|
||||
var buttons = "";
|
||||
if (versionInfo) versionInfo = " <small>("+versionInfo+")</small>";
|
||||
if (app.allow_emulator)
|
||||
buttons += `<button class="btn btn-link btn-action btn-lg" title="Try in Emulator"><i class="icon icon-share" appid="${app.id}"></i></button>`;
|
||||
buttons += `<button class="btn btn-link btn-action btn-lg"><i class="icon ${icon}" appid="${app.id}"></i></button>`;
|
||||
|
@ -162,7 +166,7 @@ function refreshLibrary() {
|
|||
<figure class="avatar"><img src="apps/${app.icon?`${app.id}/${app.icon}`:"unknown.png"}" alt="${escapeHtml(app.name)}"></figure>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<p class="tile-title text-bold">${escapeHtml(app.name)}</p>
|
||||
<p class="tile-title text-bold">${escapeHtml(app.name)} ${versionInfo}</p>
|
||||
<p class="tile-subtitle">${escapeHtml(app.description)}</p>
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
|
@ -193,8 +197,8 @@ function refreshLibrary() {
|
|||
} else if (icon.classList.contains("icon-upload")) {
|
||||
icon.classList.remove("icon-upload");
|
||||
icon.classList.add("loading");
|
||||
Comms.uploadApp(app).then(() => {
|
||||
appsInstalled.push(app.id);
|
||||
Comms.uploadApp(app).then((appJSON) => {
|
||||
if (appJSON) appsInstalled.push(appJSON);
|
||||
showToast(app.name+" Uploaded!", "success");
|
||||
icon.classList.remove("loading");
|
||||
icon.classList.add("icon-delete");
|
||||
|
@ -208,8 +212,8 @@ function refreshLibrary() {
|
|||
if (app.custom) {
|
||||
icon.classList.remove("icon-menu");
|
||||
icon.classList.add("loading");
|
||||
handleCustomApp(app).then(() => {
|
||||
appsInstalled.push(app.id);
|
||||
handleCustomApp(app).then((appJSON) => {
|
||||
if (appJSON) appsInstalled.push(appJSON);
|
||||
showToast(app.name+" Uploaded!", "success");
|
||||
icon.classList.remove("loading");
|
||||
icon.classList.add("icon-delete");
|
||||
|
@ -235,7 +239,7 @@ refreshLibrary();
|
|||
function removeApp(app) {
|
||||
return showPrompt("Delete","Really remove '"+app.name+"'?").then(() => {
|
||||
Comms.removeApp(app).then(()=>{
|
||||
appsInstalled = appsInstalled.filter(id=>id!=app.id);
|
||||
appsInstalled = appsInstalled.filter(a=>a.id!=app.id);
|
||||
showToast(app.name+" removed successfully","success");
|
||||
refreshMyApps();
|
||||
refreshLibrary();
|
||||
|
@ -274,19 +278,30 @@ 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 => `<div class="tile column col-6 col-sm-12 col-xs-12">
|
||||
panelbody.innerHTML = appsInstalled.map(appJSON => {
|
||||
var app = appNameToApp(appJSON.id);
|
||||
var version = "";
|
||||
if (!appJSON.version) {
|
||||
version = "Unknown version";
|
||||
if (app.version) version += ", latest "+app.version;
|
||||
} else {
|
||||
version = appJSON.version;
|
||||
if (app.version == appJSON.version) version += ", up to date";
|
||||
else if (app.version) version += ", latest "+app.version;
|
||||
}
|
||||
return `<div class="tile column col-6 col-sm-12 col-xs-12">
|
||||
<div class="tile-icon">
|
||||
<figure class="avatar"><img src="apps/${app.icon?`${app.id}/${app.icon}`:"unknown.png"}" alt="${escapeHtml(app.name)}"></figure>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<p class="tile-title text-bold">${escapeHtml(app.name)}</p>
|
||||
<p class="tile-title text-bold">${escapeHtml(app.name)} <small>(${version})</small></p>
|
||||
<p class="tile-subtitle">${escapeHtml(app.description)}</p>
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
<button class="btn btn-link btn-action btn-lg"><i class="icon icon-delete" appid="${app.id}"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
`).join("");
|
||||
`}).join("");
|
||||
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
|
||||
button.addEventListener("click",event => {
|
||||
var icon = event.target;
|
||||
|
@ -300,8 +315,8 @@ function refreshMyApps() {
|
|||
function getInstalledApps() {
|
||||
showLoadingIndicator();
|
||||
// Get apps
|
||||
return Comms.getInstalledApps().then(appIDs => {
|
||||
appsInstalled = appIDs;
|
||||
return Comms.getInstalledApps().then(appJSON => {
|
||||
appsInstalled = appJSON;
|
||||
handleConnectionChange(true);
|
||||
refreshMyApps();
|
||||
refreshLibrary();
|
||||
|
|
Loading…
Reference in New Issue