From 519262793d7ef91dfa91612ef72663e918ea1fe9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 4 Jun 2020 15:19:37 +0100 Subject: [PATCH] Added ability to specify dependencies (used for `notify` at the moment) Gadgetbridge: Modified to use the 'notify' library --- CHANGELOG.md | 1 + README.md | 1 + apps.json | 3 +- apps/gbridge/ChangeLog | 3 +- apps/gbridge/widget.js | 122 ++++------------------------------------- js/appinfo.js | 2 +- js/index.js | 42 ++++++++++++-- 7 files changed, 54 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4829a56f..b1ab0a701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,3 +23,4 @@ Changed for individual apps are listed in `apps/appname/ChangeLog` * Fix `marked is not defined` error (and include in repo, just in case) * Fix error in 'Install Default Apps' if Flash storage is full enough that erasing takes a while * Fixed animated progress bar on app removal +* Added ability to specify dependencies (used for `notify` at the moment) diff --git a/README.md b/README.md index ac4fc716d..c0e225894 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,7 @@ and which gives information about the app for the Launcher. "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 + "dependencies" : { "notify":"type" } // optional, app 'types' we depend on "version":"1.23", // added by BangleApps loader on upload based on apps.json "files:"file1,file2,file3", diff --git a/apps.json b/apps.json index 9e6136310..568e95b17 100644 --- a/apps.json +++ b/apps.json @@ -109,10 +109,11 @@ { "id": "gbridge", "name": "Gadgetbridge", "icon": "app.png", - "version":"0.12", + "version":"0.13", "description": "The default notification handler for Gadgetbridge notifications from Android", "tags": "tool,system,android,widget", "type":"widget", + "dependencies": { "notify":"type" }, "storage": [ {"name":"gbridge.settings.js","url":"settings.js"}, {"name":"gbridge.img","url":"app-icon.js","evaluate":true}, diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog index 0676652c7..501ceea25 100644 --- a/apps/gbridge/ChangeLog +++ b/apps/gbridge/ChangeLog @@ -10,4 +10,5 @@ 0.09: Update Bluetooth connection state automatically 0.10: Make widget play well with other Gadgetbridge widgets/apps 0.11: Report battery status on connect and at regular intervals -0.12: Setting to show/hide icon \ No newline at end of file +0.12: Setting to show/hide icon +0.13: Modified to use the 'notify' library diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index 9fe87be03..3ff3ff763 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -24,84 +24,8 @@ Bluetooth.println(JSON.stringify(message)); } - function showNotification(size, render, turnOn) { - if (turnOn === undefined) turnOn = true - var oldMode = Bangle.getLCDMode(); - - Bangle.setLCDMode("direct"); - g.setClipRect(0, 240, 239, 319); - g.setColor("#222222"); - g.fillRect(1, 241, 238, 318); - - render(320 - size); - - g.setColor("#ffffff"); - g.fillRect(0, 240, 1, 319); - g.fillRect(238, 240, 239, 319); - g.fillRect(2, 318, 238, 319); - - if (turnOn) Bangle.setLCDPower(1); // light up - Bangle.setLCDMode(oldMode); // clears cliprect - - function anim() { - state.scrollPos -= 2; - if (state.scrollPos < -size) { - state.scrollPos = -size; - } - Bangle.setLCDOffset(state.scrollPos); - if (state.scrollPos > -size) setTimeout(anim, 15); - } - anim(); - } - - function hideNotification() { - function anim() { - state.scrollPos += 4; - if (state.scrollPos > 0) state.scrollPos = 0; - Bangle.setLCDOffset(state.scrollPos); - if (state.scrollPos < 0) setTimeout(anim, 10); - } - anim(); - } - function handleNotificationEvent(event) { - - // split text up at word boundaries - var txt = event.body.split("\n"); - var MAXCHARS = 38; - for (var i = 0; i < txt.length; i++) { - txt[i] = txt[i].trim(); - var l = txt[i]; - if (l.length > MAXCHARS) { - var p = MAXCHARS; - while (p > MAXCHARS - 8 && !" \t-_".includes(l[p])) - p--; - if (p === MAXCHARS - 8) p = MAXCHARS; - txt[i] = l.substr(0, p); - txt.splice(i + 1, 0, l.substr(p)); - } - } - - showNotification(80, (y) => { - - // TODO: icon based on src? - var x = 120; - g.setFontAlign(0, 0); - g.setFont("6x8", 1); - g.setColor("#40d040"); - g.drawString(event.src, x, y + 7); - - g.setColor("#ffffff"); - g.setFont("6x8", 2); - if (event.title) - g.drawString(event.title.slice(0,17), x, y + 25); - - g.setFont("6x8", 1); - g.setColor("#ffffff"); - g.setFontAlign(-1, -1); - g.drawString(txt.join("\n"), 10, y + 40); - }); - + require("notify").show(event); Bangle.buzz(); } @@ -110,45 +34,26 @@ state.music = event.state if (state.music === "play") { - showNotification(40, (y) => { - g.setColor("#ffffff"); + require("notify").show({size:40, render:y => { + g.setColor(-1); g.drawImage(require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")), 8, y + 8); - g.setFontAlign(-1, -1); var x = 40; - g.setFont("4x6", 2); - g.setColor("#ffffff"); - g.drawString(state.musicInfo.artist, x, y + 8); - - g.setFont("6x8", 1); - g.setColor("#ffffff"); - g.drawString(state.musicInfo.track, x, y + 22); - }, changed); + g.setFont("4x6", 2).drawString(state.musicInfo.artist, x, y + 8); + g.setFont("6x8", 1).drawString(state.musicInfo.track, x, y + 22); + }}); } if (state.music === "pause") { - hideNotification(); + require("notify").hide(); } } function handleCallEvent(event) { - if (event.cmd === "accept") { - showNotification(40, (y) => { - g.setColor("#ffffff"); - g.drawImage(require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw=")), 8, y + 8); - - g.setFontAlign(-1, -1); - var x = 40; - g.setFont("4x6", 2); - g.setColor("#ffffff"); - g.drawString(event.name, x, y + 8); - - g.setFont("6x8", 1); - g.setColor("#ffffff"); - g.drawString(event.number, x, y + 22); - }); - + require("notify").show({ + size: 55, title: event.name, + body: event.number, icon:require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw="))}); Bangle.buzz(); } } @@ -172,13 +77,6 @@ if(_GB)setTimeout(_GB,0,event); }; - // Touch control - Bangle.on("touch", () => { - if (state.scrollPos) { - hideNotification(); - } - }); - Bangle.on("swipe", (dir) => { if (state.music === "play") { const command = dir > 0 ? "next" : "previous" diff --git a/js/appinfo.js b/js/appinfo.js index b0b4e05ca..3077247ce 100644 --- a/js/appinfo.js +++ b/js/appinfo.js @@ -55,7 +55,7 @@ const AppInfo = { SET_TIME_ON_WRITE : false, PRETOKENISE : options.settings.pretokenise, //MINIFICATION_LEVEL : "ESPRIMA", // disable due to https://github.com/espruino/BangleApps/pull/355#issuecomment-620124162 - builtinModules : "Flash,Storage,heatshrink,tensorflow,locale" + builtinModules : "Flash,Storage,heatshrink,tensorflow,locale,notify" }); } else return content; diff --git a/js/index.js b/js/index.js index 363081a15..e1c77ce66 100644 --- a/js/index.js +++ b/js/index.js @@ -98,7 +98,9 @@ function handleCustomApp(appTemplate) { }); console.log("Received custom app", app); modal.remove(); - Comms.uploadApp(app).then(()=>{ + checkDependencies(app) + .then(()=>Comms.uploadApp(app)) + .then(()=>{ Progress.hide({sticky:true}); resolve(); }).catch(e => { @@ -341,7 +343,9 @@ function uploadApp(app) { if (appsInstalled.some(i => i.id === app.id)) { return updateApp(app); } - Comms.uploadApp(app).then((appJSON) => { + checkDependencies(app) + .then(()=>Comms.uploadApp(app)) + .then((appJSON) => { Progress.hide({ sticky: true }); if (appJSON) { appsInstalled.push(appJSON); @@ -388,6 +392,31 @@ function customApp(app) { }); } +/// check for dependencies the app needs and install them if required +function checkDependencies(app, uploadOptions) { + var promise = Promise.resolve(); + if (app.dependencies) { + Object.keys(app.dependencies).forEach(dependency=>{ + if (app.dependencies[dependency]!="type") + throw new Error("Only supporting dependencies on app types right now"); + console.log(`Searching for dependency on app type '${dependency}'`); + var found = appsInstalled.find(app=>app.type==dependency); + if (found) + console.log(`Found dependency in installed app '${found.id}'`); + else { + found = appJSON.find(app=>app.type==dependency); + if (!found) throw new Error(`Dependency of '${dependency}' listed, but nothing satisfies it!`); + console.log(`Dependency not installed. Installing app id '${found.id}'`); + promise.then(new Promise((resolve,reject)=>{ + console.log(`Install dependency '${dependency}':'${found.id}'`); + return Comms.uploadApp(found); + })); + } + }); + } + return promise; +} + function updateApp(app) { if (app.custom) return customApp(app); return getInstalledApps().then(() => { @@ -410,8 +439,9 @@ function updateApp(app) { }).then(()=>{ showToast(`Updating ${app.name}...`); appsInstalled = appsInstalled.filter(a=>a.id!=app.id); - return Comms.uploadApp(app); - }).then((appJSON) => { + return checkDependencies(app); + }).then(()=>Comms.uploadApp(app) + ).then((appJSON) => { if (appJSON) appsInstalled.push(appJSON); showToast(app.name+" Updated!", "success"); refreshMyApps(); @@ -549,7 +579,9 @@ function installMultipleApps(appIds, promptName) { let app = apps.shift(); if (app===undefined) return resolve(); Progress.show({title:`${app.name} (${appCount-apps.length}/${appCount})`,sticky:true}); - Comms.uploadApp(app,"skip_reset").then((appJSON) => { + checkDependencies(app,"skip_reset") + .then(()=>Comms.uploadApp(app,"skip_reset")) + .then((appJSON) => { Progress.hide({sticky:true}); if (appJSON) appsInstalled.push(appJSON); showToast(`(${appCount-apps.length}/${appCount}) ${app.name} Uploaded`);