If app is installed but older, offer 'update' button (fix #79).

Fix occasional 'null' error from clicking button rather than icon
Tidy up button handling in 'Library'
pull/94/head
Gordon Williams 2020-02-07 14:51:31 +00:00
parent d8e5af43be
commit 575954aaaf
2 changed files with 80 additions and 40 deletions

View File

@ -149,19 +149,10 @@ function refreshLibrary() {
}
panelbody.innerHTML = visibleApps.map((app,idx) => {
var icon = "icon-upload";
var versionInfo = app.version || "";
if (app.custom)
icon = "icon-menu";
if (appsInstalled.find(a=>a.id==app.id)) {
icon = "icon-delete";
versionInfo+=" installed";
}
var buttons = "";
var appInstalled = appsInstalled.find(a=>a.id==app.id);
var version = getVersionInfo(app, appInstalled);
var versionInfo = version.text;
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>`;
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>
@ -171,7 +162,11 @@ function refreshLibrary() {
<p class="tile-subtitle">${escapeHtml(app.description)}</p>
</div>
<div class="tile-action">
${buttons}
<button class="btn btn-link btn-action btn-lg ${app.allow_emulator?"":"d-hide"}" appid="${app.id}" title="Try in Emulator"><i class="icon icon-share"></i></button>
<button class="btn btn-link btn-action btn-lg ${version.canUpdate?"":"d-hide"}" appid="${app.id}" title="Update App"><i class="icon icon-refresh"></i></button>
<button class="btn btn-link btn-action btn-lg ${!appInstalled?"":"d-hide"}" appid="${app.id}" title="Upload App"><i class="icon icon-upload"></i></button>
<button class="btn btn-link btn-action btn-lg ${appInstalled?"":"d-hide"}" appid="${app.id}" title="Remove App"><i class="icon icon-delete"></i></button>
<button class="btn btn-link btn-action btn-lg ${app.custom?"":"d-hide"}" appid="${app.id}" title="Customise and Upload App"><i class="icon icon-menu"></i></button>
</div>
</div>
`;}).join("");
@ -181,10 +176,12 @@ function refreshLibrary() {
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;
var button = event.currentTarget;
var icon = button.firstChild;
var appid = button.getAttribute("appid");
var app = appNameToApp(appid);
if (!app) throw new Error("App "+appid+" not found");
// check icon to figure out what we should do
if (icon.classList.contains("icon-share")) {
// emulator
var file = app.storage.find(f=>f.name[0]=='-');
@ -196,6 +193,7 @@ function refreshLibrary() {
var url = baseurl+"apps/"+app.id+"/"+file.url;
window.open(`https://espruino.com/ide/emulator.html?codeurl=${url}&upload`);
} else if (icon.classList.contains("icon-upload")) {
// upload
icon.classList.remove("icon-upload");
icon.classList.add("loading");
Comms.uploadApp(app).then((appJSON) => {
@ -204,12 +202,14 @@ function refreshLibrary() {
icon.classList.remove("loading");
icon.classList.add("icon-delete");
refreshMyApps();
refreshLibrary();
}).catch(err => {
showToast("Upload failed, "+err, "error");
icon.classList.remove("loading");
icon.classList.add("icon-upload");
});
} else if (icon.classList.contains("icon-menu")) {
// custom HTML update
if (app.custom) {
icon.classList.remove("icon-menu");
icon.classList.add("loading");
@ -219,16 +219,23 @@ function refreshLibrary() {
icon.classList.remove("loading");
icon.classList.add("icon-delete");
refreshMyApps();
refreshLibrary();
}).catch(err => {
showToast("Customise failed, "+err, "error");
icon.classList.remove("loading");
icon.classList.add("icon-menu");
});
}
} else {
} else if (icon.classList.contains("icon-delete")) {
// Remove app
icon.classList.remove("icon-delete");
icon.classList.add("loading");
removeApp(app);
} else if (icon.classList.contains("icon-refresh")) {
// Update app
icon.classList.remove("icon-refresh");
icon.classList.add("loading");
updateApp(app);
}
});
});
@ -239,14 +246,29 @@ refreshLibrary();
function removeApp(app) {
return showPrompt("Delete","Really remove '"+app.name+"'?").then(() => {
Comms.removeApp(app).then(()=>{
appsInstalled = appsInstalled.filter(a=>a.id!=app.id);
showToast(app.name+" removed successfully","success");
refreshMyApps();
refreshLibrary();
}, err=>{
showToast(app.name+" removal failed, "+err,"error");
});
return Comms.removeApp(app);
}).then(()=>{
appsInstalled = appsInstalled.filter(a=>a.id!=app.id);
showToast(app.name+" removed successfully","success");
refreshMyApps();
refreshLibrary();
}, err=>{
showToast(app.name+" removal failed, "+err,"error");
});
}
function updateApp(app) {
Comms.removeApp(app).then(()=>{
showToast(app.name+" removed successfully. Updating...",);
appsInstalled = appsInstalled.filter(a=>a.id!=app.id);
return Comms.uploadApp(app);
}).then((appJSON) => {
if (appJSON) appsInstalled.push(appJSON);
showToast(app.name+" Updated!", "success");
refreshMyApps();
refreshLibrary();
}, err=>{
showToast(app.name+" update failed, "+err,"error");
});
}
@ -281,34 +303,31 @@ function refreshMyApps() {
tab.setAttribute("data-badge", appsInstalled.length);
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;
}
var version = getVersionInfo(app, appJSON);
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)} <small>(${version})</small></p>
<p class="tile-title text-bold">${escapeHtml(app.name)} <small>(${version.text})</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>
<button class="btn btn-link btn-action btn-lg ${version.canUpdate?'':'d-hide'}" appid="${app.id}" title="Update App"><i class="icon icon-refresh"></i></button>
<button class="btn btn-link btn-action btn-lg" appid="${app.id}" title="Remove App"><i class="icon icon-delete"></i></button>
</div>
</div>
`}).join("");
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
button.addEventListener("click",event => {
var icon = event.target;
var appid = icon.getAttribute("appid");
var button = event.currentTarget;
var icon = button.firstChild;
var appid = button.getAttribute("appid");
var app = appNameToApp(appid);
removeApp(app);
if (!app) throw new Error("App "+appid+" not found");
// check icon to figure out what we should do
if (icon.classList.contains("icon-delete")) removeApp(app);
if (icon.classList.contains("icon-refresh")) updateApp(app);
});
});
}

View File

@ -42,3 +42,24 @@ function appSorter(a,b) {
if (sa>sb) return 1;
return (a.name==b.name) ? 0 : ((a.name<b.name) ? -1 : 1);
}
/* Given 2 JSON structures (1st from apps.json, 2nd from an installed app)
work out what to display re: versions and if we can update */
function getVersionInfo(appListing, appInstalled) {
var versionText = "";
var canUpdate = false;
if (!appInstalled) {
if (appListing.version)
versionText = "v"+appListing.version;
} else {
versionText = (appInstalled.version ? ("v"+appInstalled.version) : "Unknown version");
if (appListing.version != appInstalled.version) {
if (appListing.version) versionText += ", latest "+appListing.version;
canUpdate = true;
}
}
return {
text : versionText,
canUpdate : canUpdate
}
}