From 0fa4b44990a9b8f63827b4185f318ced1ee2eb92 Mon Sep 17 00:00:00 2001 From: MaBecker Date: Tue, 14 Apr 2020 08:52:04 +0200 Subject: [PATCH] add favourite functionality * library select/unselect apps/widgets * as library section * as upload * deny unselect for boot and setting --- CHANGELOG.md | 1 + index.html | 4 +- js/index.js | 117 +++++++++++++++++++++++++++++++++++++++++---------- js/ui.js | 1 + js/utils.js | 13 ++++++ 5 files changed, 113 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1cd3d803..6368c2c46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,4 @@ Changed for individual apps are listed in `apps/appname/ChangeLog` * Added optional `README.md` file for apps * Remove 2v04 version warning, add links in About to official/developer versions * Fix issue removing an app that was just installed (Fix #253) +* Add `Favourite` functionality diff --git a/index.html b/index.html index 0d5c17251..f016ffb49 100644 --- a/index.html +++ b/index.html @@ -96,6 +96,7 @@ +
@@ -134,7 +135,8 @@

Utilities

-

+ +

diff --git a/js/index.js b/js/index.js index d2c6d698b..ef9bcb4f1 100644 --- a/js/index.js +++ b/js/index.js @@ -1,6 +1,8 @@ var appJSON = []; // List of apps and info from apps.json var appsInstalled = []; // list of app JSON var files = []; // list of files on Bangle +var favourites = []; // list of user favourite app +const FAVOURITE = "favouriteapps.json"; httpGet("apps.json").then(apps=>{ try { @@ -18,7 +20,7 @@ httpGet("apps.json").then(apps=>{ function showChangeLog(appid) { var app = appNameToApp(appid); function show(contents) { - showPrompt(app.name+" Change Log",contents,{ok:true}).catch(()=>{});; + showPrompt(app.name+" Change Log",contents,{ok:true}).catch(()=>{}); } httpGet(`apps/${appid}/ChangeLog`). then(show).catch(()=>show("No Change Log available")); @@ -142,6 +144,20 @@ function handleAppInterface(app) { }); } +function handleAppFavourite(favourite, app){ + if (favourite) { + favourites = favourites.concat([app.id]); + } else { + if ([ "boot","setting"].includes(app.id)) { + showToast(app.name + ' is required, can\'t remove it' , 'warning'); + }else { + favourites = favourites.filter(e => e != app.id); + } + } + localStorage.setItem("favouriteapps.json", JSON.stringify(favourites)); + refreshLibrary(); +} + // =========================================== Top Navigation function showTab(tabname) { htmlToArray(document.querySelectorAll("#tab-navigate .tab-item")).forEach(tab => { @@ -156,7 +172,7 @@ function showTab(tabname) { // =========================================== Library -var chips = Array.from(document.querySelectorAll('.chip')).map(chip => chip.attributes.filterid.value) +var chips = Array.from(document.querySelectorAll('.chip')).map(chip => chip.attributes.filterid.value); var hash = window.location.hash ? window.location.hash.slice(1) : ''; var activeFilter = !!~chips.indexOf(hash) ? hash : ''; @@ -165,27 +181,34 @@ var currentSearch = ''; function refreshFilter(){ var filtersContainer = document.querySelector("#librarycontainer .filter-nav"); filtersContainer.querySelector('.active').classList.remove('active'); - if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active') - else filtersContainer.querySelector('.chip[filterid]').classList.add('active') + if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active'); + else filtersContainer.querySelector('.chip[filterid]').classList.add('active'); } function refreshLibrary() { var panelbody = document.querySelector("#librarycontainer .panel-body"); var visibleApps = appJSON; if (activeFilter) { - visibleApps = visibleApps.filter(app => app.tags && app.tags.split(',').includes(activeFilter)); + if ( activeFilter == "favourites" ) { + visibleApps = visibleApps.filter(app => app.id && (favourites.filter( e => e == app.id).length)); + }else{ + visibleApps = visibleApps.filter(app => app.tags && app.tags.split(',').includes(activeFilter)); + } } if (currentSearch) { visibleApps = visibleApps.filter(app => app.name.toLowerCase().includes(currentSearch) || app.tags.includes(currentSearch)); } + favourites = (localStorage.getItem(FAVOURITE)) === null ? JSON.parse('["boot","launch","setting"]') : JSON.parse(localStorage.getItem("favouriteapps.json")); + panelbody.innerHTML = visibleApps.map((app,idx) => { var appInstalled = appsInstalled.find(a=>a.id==app.id); var version = getVersionInfo(app, appInstalled); var versionInfo = version.text; if (versionInfo) versionInfo = " ("+versionInfo+")"; var readme = `Read more...`; + var favourite = favourites.find(e => e == app.id); return `
${escapeHtml(app.name)}

@@ -195,7 +218,8 @@ function refreshLibrary() {

${escapeHtml(app.description)}${app.readme?`
${readme}`:""}

See the code on GitHub
-
+
+ @@ -232,7 +256,7 @@ function refreshLibrary() { // upload icon.classList.remove("icon-upload"); icon.classList.add("loading"); - uploadApp(app) + uploadApp(app); } else if (icon.classList.contains("icon-menu")) { // custom HTML update icon.classList.remove("icon-menu"); @@ -250,6 +274,10 @@ function refreshLibrary() { updateApp(app); } else if (icon.classList.contains("icon-download")) { handleAppInterface(app); + } else if ( button.innerText == String.fromCharCode(0x2661)) { + handleAppFavourite(true, app); + } else if ( button.innerText == String.fromCharCode(0x2665) ) { + handleAppFavourite(false, app); } }); }); @@ -262,17 +290,17 @@ refreshLibrary(); function uploadApp(app) { return getInstalledApps().then(()=>{ if (appsInstalled.some(i => i.id === app.id)) { - return updateApp(app) + return updateApp(app); } Comms.uploadApp(app).then((appJSON) => { - Progress.hide({ sticky: true }) + Progress.hide({ sticky: true }); if (appJSON) { - appsInstalled.push(appJSON) + appsInstalled.push(appJSON); } - showToast(app.name + ' Uploaded!', 'success') + showToast(app.name + ' Uploaded!', 'success'); }).catch(err => { - Progress.hide({ sticky: true }) - showToast('Upload failed, ' + err, 'error') + Progress.hide({ sticky: true }); + showToast('Upload failed, ' + err, 'error'); }).finally(()=>{ refreshMyApps(); refreshLibrary(); @@ -286,8 +314,8 @@ function removeApp(app) { return showPrompt("Delete","Really remove '"+app.name+"'?").then(() => { return getInstalledApps().then(()=>{ // a = from appid.info, app = from apps.json - return Comms.removeApp(appsInstalled.find(a => a.id === app.id)) - }) + return Comms.removeApp(appsInstalled.find(a => a.id === app.id)); + }); }).then(()=>{ appsInstalled = appsInstalled.filter(a=>a.id!=app.id); showToast(app.name+" removed successfully","success"); @@ -315,13 +343,13 @@ function updateApp(app) { if (app.custom) return customApp(app); return getInstalledApps().then(() => { // a = from appid.info, app = from apps.json - let remove = appsInstalled.find(a => a.id === app.id) + let remove = appsInstalled.find(a => a.id === app.id); // no need to remove files which will be overwritten anyway remove.files = remove.files.split(',') .filter(f => f !== app.id + '.info') .filter(f => !app.storage.some(s => s.name === f)) - .join(',') - return Comms.removeApp(remove) + .join(','); + return Comms.removeApp(remove); }).then(()=>{ showToast(`Updating ${app.name}...`); appsInstalled = appsInstalled.filter(a=>a.id!=app.id); @@ -397,7 +425,7 @@ return `
// 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); - if (icon.classList.contains("icon-download")) handleAppInterface(app) + if (icon.classList.contains("icon-download")) handleAppInterface(app); }); }); } @@ -405,7 +433,7 @@ return `
let haveInstalledApps = false; function getInstalledApps(refresh) { if (haveInstalledApps && !refresh) { - return Promise.resolve(appsInstalled) + return Promise.resolve(appsInstalled); } showLoadingIndicator("myappscontainer"); // Get apps and files @@ -453,7 +481,7 @@ filtersContainer.addEventListener('click', ({ target }) => { activeFilter = target.getAttribute('filterid') || ''; refreshFilter(); refreshLibrary(); - window.location.hash = activeFilter + window.location.hash = activeFilter; }); var librarySearchInput = document.querySelector("#searchform input"); @@ -526,7 +554,7 @@ document.getElementById("installdefault").addEventListener("click",event=>{ upload(); }).catch(function() { Progress.hide({sticky:true}); - reject() + reject(); }); } upload(); @@ -541,3 +569,48 @@ document.getElementById("installdefault").addEventListener("click",event=>{ showToast("App Install failed, "+err,"error"); }); }); + +// Install all favoutrie apps in one go +document.getElementById("installfavourite").addEventListener("click",event=>{ + var defaultApps, appCount; + asyncLocalStorage.getItem(FAVOURITE).then(json=>{ + defaultApps = JSON.parse(json); + defaultApps = defaultApps.map( appid => appJSON.find(app=>app.id==appid) ); + if (defaultApps.some(x=>x===undefined)) + throw "Not all apps found"; + appCount = defaultApps.length; + return showPrompt("Install Defaults","Remove everything and install favourite apps?"); + }).then(() => { + return Comms.removeAllApps(); + }).then(()=>{ + Progress.hide({sticky:true}); + appsInstalled = []; + showToast(`Existing apps removed. Installing ${appCount} apps...`); + return new Promise((resolve,reject) => { + function upload() { + var app = defaultApps.shift(); + if (app===undefined) return resolve(); + Progress.show({title:`${app.name} (${appCount-defaultApps.length}/${appCount})`,sticky:true}); + Comms.uploadApp(app,"skip_reset").then((appJSON) => { + Progress.hide({sticky:true}); + if (appJSON) appsInstalled.push(appJSON); + showToast(`(${appCount-defaultApps.length}/${appCount}) ${app.name} Uploaded`); + upload(); + }).catch(function() { + Progress.hide({sticky:true}); + reject(); + }); + } + upload(); + }); + }).then(()=>{ + return Comms.setTime(); + }).then(()=>{ + showToast("Favourites apps successfully installed!","success"); + return getInstalledApps(true); + }).catch(err=>{ + Progress.hide({sticky:true}); + showToast("App Install failed, "+err,"error"); + }); +}); + diff --git a/js/ui.js b/js/ui.js index 616a92555..ea6885eac 100644 --- a/js/ui.js +++ b/js/ui.js @@ -86,6 +86,7 @@ function showToast(message, type) { var style = "toast-primary"; if (type=="success") style = "toast-success"; else if (type=="error") style = "toast-error"; + else if (type=="warning") style = "toast-warning"; else if (type!==undefined) console.log("showToast: unknown toast "+type); var toastcontainer = document.getElementById("toastcontainer"); var msgDiv = htmlElement(`
`); diff --git a/js/utils.js b/js/utils.js index 85b6eb0a1..4913c7129 100644 --- a/js/utils.js +++ b/js/utils.js @@ -67,3 +67,16 @@ function getVersionInfo(appListing, appInstalled) { canUpdate : canUpdate } } + +const asyncLocalStorage = { + setItem: function (key, value) { + return Promise.resolve().then(function () { + localStorage.setItem(key, value); + }); + }, + getItem: function (key) { + return Promise.resolve().then(function () { + return localStorage.getItem(key); + }); + } +};