From 399868817919afe782cc8a7277cc77563f9f5e4b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 Feb 2020 17:01:29 +0000 Subject: [PATCH 01/55] Tweaks - now try and parse files --- bin/sanitycheck.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) mode change 100644 => 100755 bin/sanitycheck.js diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js old mode 100644 new mode 100755 index a2e912527..d32041cda --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -18,11 +18,11 @@ try { var BASEDIR = __dirname+"/../"; var APPSDIR = BASEDIR+"apps/"; function ERROR(s) { - console.error(s); + console.error("ERROR: "+s); process.exit(1); } function WARN(s) { - console.log(s); + console.log("Warning: "+s); } var appsFile, apps; @@ -39,7 +39,7 @@ try{ apps.forEach((app,addIdx) => { if (!app.id) ERROR(`App ${appIdx} has no id`); - console.log(`Checking ${app.id}...`); + //console.log(`Checking ${app.id}...`); var appDir = APPSDIR+app.id+"/"; if (!fs.existsSync(APPSDIR+app.id)) ERROR(`App ${app.id} has no directory`); if (!app.name) ERROR(`App ${app.id} has no name`); @@ -59,8 +59,10 @@ apps.forEach((app,addIdx) => { fileNames.push(file.name); if (file.url) if (!fs.existsSync(appDir+file.url)) ERROR(`App ${app.id} file ${file.url} doesn't exist`); if (!file.url && !file.content && !app.custom) ERROR(`App ${app.id} file ${file.name} has no contents`); + var fileContents = ""; + if (file.content) fileContents = file.content; + if (file.url) fileContents = fs.readFileSync(appDir+file.url).toString(); if (file.evaluate) { - var fileContents = file.content ? file.content : fs.readFileSync(appDir+file.url).toString(); try { acorn.parse("("+fileContents+")"); } catch(e) { @@ -74,6 +76,21 @@ apps.forEach((app,addIdx) => { ERROR(`App ${app.id}'s ${file.name} has evaluate:true but is not valid JS expression`); } } + if (file.name.endsWith(".js")) { + // TODO: actual lint? + try { + acorn.parse(fileContents); + } catch(e) { + console.log("====================================================="); + console.log(" PARSE OF "+appDir+file.url+" failed."); + console.log(""); + console.log(e); + console.log("====================================================="); + console.log(fileContents); + console.log("====================================================="); + ERROR(`App ${app.id}'s ${file.name} is a JS file but isn't valid JS`); + } + } }); //console.log(fileNames); if (isApp && !fileNames.includes(app.id+".app.js")) ERROR(`App ${app.id} has no entrypoint`); From 6cfe9c340b54555939823061b1e060cee76e649f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 Feb 2020 17:02:26 +0000 Subject: [PATCH 02/55] Take advantage of recent nonbreaking change that stops readJSON from causing errors --- README.md | 5 +++++ apps/about/app.js | 2 +- apps/alarm/alarm.js | 2 +- apps/alarm/app.js | 2 +- apps/alarm/widget.js | 2 +- apps/boot/boot0.js | 4 ++-- apps/boot/bootloader.js | 8 ++------ apps/files/files.js | 2 +- apps/gpsrec/app.js | 2 +- apps/gpsrec/widget.js | 2 +- apps/hidbkbd/hid-binary-keyboard.js | 2 +- apps/hidkbd/hid-keyboard.js | 2 +- apps/hidmsic/hid-music.js | 2 +- apps/launch/app.js | 5 +---- apps/ncstart/start.js | 8 +++----- apps/sclock/clock-simple.js | 2 +- apps/setting/settings.js | 4 +--- apps/welcome/app.js | 8 +++----- apps/widpedom/widget.js | 2 +- comms.js | 4 ++-- 20 files changed, 31 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 45643d6df..fbe7e2522 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,11 @@ See [apps/gpsrec/interface.html](the GPS Recorder) for a full example. - 'Welcome' apps define a file called `welcome.js` which the booloader picks up. This then chain-loads the welcome app itself. +- 'Alarm' apps define a file called `alarm.js` which handles the actual alarm window. + +- Locale is handled by `require("locale")`. An app may create a `locale` file in Storage which is +a module that overwrites Bangle.js's default locale. + ### Graphic areas diff --git a/apps/about/app.js b/apps/about/app.js index 35ea07828..634a23b71 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -11,7 +11,7 @@ g.drawString("Powered by Espruino",0,y+=4+h); g.drawString("Version "+ENV.VERSION,0,y+=h); g.drawString("Commit "+ENV.GIT_COMMIT,0,y+=h); function getVersion(name,file) { - var j = s.readJSON(file); + var j = s.readJSON(file,1); var v = ("object"==typeof j)?j.version:false; g.drawString(v?(name+" "+(v?"v"+v:"Unknown")):"NO "+name,0,y+=h); } diff --git a/apps/alarm/alarm.js b/apps/alarm/alarm.js index 70dc75b49..78dd23482 100644 --- a/apps/alarm/alarm.js +++ b/apps/alarm/alarm.js @@ -48,7 +48,7 @@ function showAlarm(alarm) { // Check for alarms var day = (new Date()).getDate(); var hr = getCurrentHr(); -var alarms = require("Storage").readJSON("alarm.json")||[]; +var alarms = require("Storage").readJSON("alarm.json",1)||[]; var active = alarms.filter(a=>a.on&&(a.hr { - var alarms = require('Storage').readJSON('alarm.json')||[]; + var alarms = require('Storage').readJSON('alarm.json',1)||[]; alarms = alarms.filter(alarm=>alarm.on); if (!alarms.length) return; delete alarms; diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index 7741dd376..cdfa03a73 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -1,7 +1,7 @@ // This ALWAYS runs at boot E.setFlags({pretokenise:1}); // Load settings... -var s = require('Storage').readJSON('setting.json')||{}; +var s = require('Storage').readJSON('setting.json',1)||{}; if (s.ble!==false) { if (s.HID) { // Human interface device Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==")); @@ -26,7 +26,7 @@ E.setTimeZone(s.timezone); delete s; // check for alarms function checkAlarm() { - var alarms = require('Storage').readJSON('alarm.json')||[]; + var alarms = require('Storage').readJSON('alarm.json',1)||[]; var time = new Date(); var active = alarms.filter(a=>a.on&&(a.last!=time.getDate())); if (active.length) { diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index 07a1623eb..fca89d23a 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -1,6 +1,5 @@ // This runs after a 'fresh' boot -var settings={}; -try { settings = require("Storage").readJSON('setting.json'); } catch (e) {} +var settings=require("Storage").readJSON('setting.json',1)||{}; if (!settings.welcomed && require("Storage").read("welcome.js")!==undefined) { setTimeout(()=>load("welcome.js")); } else { @@ -8,10 +7,7 @@ if (!settings.welcomed && require("Storage").read("welcome.js")!==undefined) { var clockApp = settings.clock; if (clockApp) clockApp = require("Storage").read(clockApp) if (!clockApp) { - var clockApps = require("Storage").list(/\.info$/).map(app=>{ - try { return require("Storage").readJSON(app); } - catch (e) {} - }).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder); + var clockApps = require("Storage").list(/\.info$/).map(app=>require("Storage").readJSON(app,1)||{}).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder); if (clockApps && clockApps.length > 0) clockApp = require("Storage").read(clockApps[0].src); delete clockApps; diff --git a/apps/files/files.js b/apps/files/files.js index ab8324b43..31353cf96 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -69,7 +69,7 @@ function showApps() { var list = storage.list(/\.info$/).filter((a)=> { return a !== 'setting.info'; }).sort().map((app) => { - var ret = storage.readJSON(app); + var ret = storage.readJSON(app,1)||{}; ret[''] = app; return ret; }); diff --git a/apps/gpsrec/app.js b/apps/gpsrec/app.js index bac7e92f8..58b4295a6 100644 --- a/apps/gpsrec/app.js +++ b/apps/gpsrec/app.js @@ -1,7 +1,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); -var settings = require("Storage").readJSON("gpsrec.json")||{}; +var settings = require("Storage").readJSON("gpsrec.json",1)||{}; function getFN(n) { return ".gpsrc"+n.toString(36); diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js index 7e25a92ad..5c120dcbb 100644 --- a/apps/gpsrec/widget.js +++ b/apps/gpsrec/widget.js @@ -55,7 +55,7 @@ // Called by the GPS app to reload settings and decide what's function reload() { - settings = require("Storage").readJSON("gpsrec.json")||{}; + settings = require("Storage").readJSON("gpsrec.json",1)||{}; settings.period = settings.period||1; settings.file |= 0; diff --git a/apps/hidbkbd/hid-binary-keyboard.js b/apps/hidbkbd/hid-binary-keyboard.js index d48d97b47..fa1017714 100644 --- a/apps/hidbkbd/hid-binary-keyboard.js +++ b/apps/hidbkbd/hid-binary-keyboard.js @@ -5,7 +5,7 @@ the touchscreen var storage = require('Storage'); -const settings = storage.readJSON('setting.json') || { HID: false }; +const settings = storage.readJSON('setting.json',1) || { HID: false }; const KEY = { A : 4 , B : 5 , diff --git a/apps/hidkbd/hid-keyboard.js b/apps/hidkbd/hid-keyboard.js index fe850024e..ed406e093 100644 --- a/apps/hidkbd/hid-keyboard.js +++ b/apps/hidkbd/hid-keyboard.js @@ -1,6 +1,6 @@ var storage = require('Storage'); -const settings = storage.readJSON('setting.json') || { HID: false }; +const settings = storage.readJSON('setting.json',1) || { HID: false }; var sendHid, next, prev, toggle, up, down, profile; diff --git a/apps/hidmsic/hid-music.js b/apps/hidmsic/hid-music.js index afee7ade9..034bbd231 100644 --- a/apps/hidmsic/hid-music.js +++ b/apps/hidmsic/hid-music.js @@ -1,6 +1,6 @@ var storage = require('Storage'); -const settings = storage.readJSON('setting.json') || { HID: false }; +const settings = storage.readJSON('setting.json',1) || { HID: false }; var sendHid, next, prev, toggle, up, down, profile; diff --git a/apps/launch/app.js b/apps/launch/app.js index e93c2a330..682122f82 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -1,8 +1,5 @@ var s = require("Storage"); -var apps = s.list(/\.info$/).map(app=>{ - try { return s.readJSON(app); } - catch (e) { return {name:"DEAD: "+app.substr(1)} } -}).filter(app=>app.type=="app" || app.type=="clock" || !app.type); +var apps = s.list(/\.info$/).map(app=>s.readJSON(app,1)||{name:"DEAD: "+app.substr(1)}).filter(app=>app.type=="app" || app.type=="clock" || !app.type); apps.sort((a,b)=>{ var n=(0|a.sortorder)-(0|b.sortorder); if (n) return n; // do sortorder first diff --git a/apps/ncstart/start.js b/apps/ncstart/start.js index 208c554fd..f1d8fb52e 100644 --- a/apps/ncstart/start.js +++ b/apps/ncstart/start.js @@ -115,11 +115,9 @@ function info() { } function cleanup() { - try { - var settings = require("Storage").readJSON('setting.json'); - settings.welcomed = true; - require("Storage").write('setting.json',settings); - } catch (e) {} + var settings = require("Storage").readJSON('setting.json',1)||{}; + settings.welcomed = true; + require("Storage").write('setting.json',settings); return Promise.resolve(); } diff --git a/apps/sclock/clock-simple.js b/apps/sclock/clock-simple.js index 9bedbc2d0..dc0eb159c 100644 --- a/apps/sclock/clock-simple.js +++ b/apps/sclock/clock-simple.js @@ -11,7 +11,7 @@ const yposYear = 175; const yposGMT = 220; // Check settings for what type our clock should be -var is12Hour = (require("Storage").readJSON("setting.json")||{})["12hour"]; +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; function drawSimpleClock() { // get date diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 568a64047..94a2a2d94 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -27,9 +27,7 @@ function resetSettings() { updateSettings(); } -try { - settings = storage.readJSON('setting.json'); -} catch (e) {} +settings = storage.readJSON('setting.json',1); if (!settings) resetSettings(); const boolFormat = v => v ? "On" : "Off"; diff --git a/apps/welcome/app.js b/apps/welcome/app.js index 79a085b14..688dd2cd3 100644 --- a/apps/welcome/app.js +++ b/apps/welcome/app.js @@ -283,11 +283,9 @@ setWatch(()=>move(1), BTN3, {repeat:true}); setWatch(()=>{ // If we're on the last page if (sceneNumber == scenes.length-1) { - try { - var settings = require("Storage").readJSON('setting.json'); - settings.welcomed = true; - require("Storage").write('setting.json',settings); - } catch (e) {} + var settings = require("Storage").readJSON('setting.json'); + settings.welcomed = true; + require("Storage").write('setting.json',settings); load(); } }, BTN2, {repeat:true,edge:"rising"}); diff --git a/apps/widpedom/widget.js b/apps/widpedom/widget.js index 84a4bb211..e827702c9 100644 --- a/apps/widpedom/widget.js +++ b/apps/widpedom/widget.js @@ -57,7 +57,7 @@ // add your widget WIDGETS["wpedom"]={draw:draw}; // Load data at startup - let pedomData = require("Storage").readJSON(PEDOMFILE); + let pedomData = require("Storage").readJSON(PEDOMFILE,1); if (pedomData) { if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate); diff --git a/comms.js b/comms.js index 9f685500e..74b0b6049 100644 --- a/comms.js +++ b/comms.js @@ -32,7 +32,7 @@ getInstalledApps : () => { return new Promise((resolve,reject) => { Puck.write("\x03",(result) => { if (result===null) return reject(""); - Puck.eval('require("Storage").list(/\.info$/).map(f=>{var j=require("Storage").readJSON(f)||{};j.id=f.slice(0,-5);return j})', (appList,err) => { + Puck.eval('require("Storage").list(/\.info$/).map(f=>{var j=require("Storage").readJSON(f,1)||{};j.id=f.slice(0,-5);return j})', (appList,err) => { if (appList===null) return reject(err || ""); console.log("getInstalledApps", appList); resolve(appList); @@ -68,7 +68,7 @@ setTime : () => { var cmd = '\x03\x10setTime('+(d.getTime()/1000)+');'; // in 1v93 we have timezones too cmd += 'E.setTimeZone('+tz+');'; - cmd += "(s=>{s&&(s.timezone="+tz+")&&require('Storage').write('setting.json',s);})(require('Storage').readJSON('setting.json'))\n"; + cmd += "(s=>{s&&(s.timezone="+tz+")&&require('Storage').write('setting.json',s);})(require('Storage').readJSON('setting.json',1))\n"; Puck.write(cmd, (result) => { if (result===null) return reject(""); resolve(); From 6eabd601393b9d50167723d23a1e3538989bc625 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Sun, 1 Mar 2020 18:14:13 +0000 Subject: [PATCH 03/55] Fix 'try in emulator' after recent filename changes (fix #107) --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 1162c7fef..56d6b4cc2 100644 --- a/index.js +++ b/index.js @@ -302,7 +302,7 @@ function refreshLibrary() { // 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]=='-'); + var file = app.storage.find(f=>f.name.endsWith('.js')); if (!file) { console.error("No entrypoint found for "+appid); return; From e755d64cc1df08d560735f6fe2cb860757fe3b27 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 2 Mar 2020 07:55:26 +0000 Subject: [PATCH 04/55] tweak welcome app to cope with no JSON --- apps.json | 2 +- apps/welcome/ChangeLog | 1 + apps/welcome/app.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index f856c9b7e..90efd4166 100644 --- a/apps.json +++ b/apps.json @@ -40,7 +40,7 @@ { "id": "welcome", "name": "Welcome", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "Appears at first boot and explains how to use Bangle.js", "tags": "start,welcome", "allow_emulator":true, diff --git a/apps/welcome/ChangeLog b/apps/welcome/ChangeLog index 8747cdad3..d8d647138 100644 --- a/apps/welcome/ChangeLog +++ b/apps/welcome/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Animate balloon intro 0.03: BTN3 now won't restart when at the end +0.04: Fix regression after tweaks to Storage.readJSON diff --git a/apps/welcome/app.js b/apps/welcome/app.js index 688dd2cd3..44705b94c 100644 --- a/apps/welcome/app.js +++ b/apps/welcome/app.js @@ -283,7 +283,7 @@ setWatch(()=>move(1), BTN3, {repeat:true}); setWatch(()=>{ // If we're on the last page if (sceneNumber == scenes.length-1) { - var settings = require("Storage").readJSON('setting.json'); + var settings = require("Storage").readJSON('setting.json',1)||{}; settings.welcomed = true; require("Storage").write('setting.json',settings); load(); From 9a63beefb8cc621d7ea826577c0e17c90462528b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 2 Mar 2020 17:16:51 +0000 Subject: [PATCH 05/55] About app: Update version checker for new filename type --- apps.json | 2 +- apps/about/ChangeLog | 1 + apps/about/app.js | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index 90efd4166..06842139e 100644 --- a/apps.json +++ b/apps.json @@ -28,7 +28,7 @@ { "id": "about", "name": "About", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "tags": "tool,system", "allow_emulator":true, diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index 5560f00bc..fe1d0f3e0 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Update version checker for new filename type diff --git a/apps/about/app.js b/apps/about/app.js index 634a23b71..773d960ba 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -15,9 +15,9 @@ function getVersion(name,file) { var v = ("object"==typeof j)?j.version:false; g.drawString(v?(name+" "+(v?"v"+v:"Unknown")):"NO "+name,0,y+=h); } -getVersion("Bootloader","+boot"); -getVersion("Launcher","+launch"); -getVersion("Settings","+setting"); +getVersion("Bootloader","boot.info"); +getVersion("Launcher","launch.info"); +getVersion("Settings","setting.info"); y+=h; g.drawString(MEM.total+" JS Variables available",0,y+=h); From 441e518885fc67f6df3d0f5df6285e1612152e1f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 2 Mar 2020 17:32:01 +0000 Subject: [PATCH 06/55] Alarm: fix More alarm scheduling issues --- apps.json | 2 +- apps/alarm/ChangeLog | 1 + apps/alarm/alarm.js | 6 +++--- apps/alarm/app.js | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index 06842139e..63e053820 100644 --- a/apps.json +++ b/apps.json @@ -93,7 +93,7 @@ "name": "Default Alarm", "shortName":"Alarms", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Set and respond to alarms", "tags": "tool,alarm,widget", "storage": [ diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 248faad95..8cf79a91d 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fix issues with alarm scheduling +0.03: More alarm scheduling issues diff --git a/apps/alarm/alarm.js b/apps/alarm/alarm.js index 78dd23482..7f0027bc8 100644 --- a/apps/alarm/alarm.js +++ b/apps/alarm/alarm.js @@ -10,7 +10,7 @@ function formatTime(t) { function getCurrentHr() { var time = new Date(); - return time.getHours()+(time.getMinutes()/60); + return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); } function showAlarm(alarm) { @@ -47,7 +47,7 @@ function showAlarm(alarm) { // Check for alarms var day = (new Date()).getDate(); -var hr = getCurrentHr(); +var hr = getCurrentHr()+10000; // get current time - 10s in future to ensure we alarm if we've started the app a tad early var alarms = require("Storage").readJSON("alarm.json",1)||[]; var active = alarms.filter(a=>a.on&&(a.hr Date: Mon, 2 Mar 2020 17:43:56 +0000 Subject: [PATCH 07/55] Fix issues if BLE=off, 'Make Connectable' is chosen, and the loader resets Bangle.js (fix #108) --- apps.json | 2 +- apps/boot/ChangeLog | 1 + apps/boot/boot0.js | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 63e053820..b7d1bb3a8 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "boot", "name": "Bootloader", "icon": "bootloader.png", - "version":"0.07", + "version":"0.08", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "tags": "tool,system", "type":"bootloader", diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 3c6dfec29..62adcecdc 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -4,3 +4,4 @@ 0.05: Add Welcome screen on boot 0.06: Disable GPS time log messages, add (default=1) setting to hide log messages 0.07: Fix issues with alarm scheduling +0.08: Fix issues if BLE=off, 'Make Connectable' is chosen, and the loader resets Bangle.js (fix #108) diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index cdfa03a73..a5b4b45af 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -15,8 +15,9 @@ if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth if (s.log) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection) else Bluetooth.setConsole(true); // else if no debug, force REPL to Bluetooth } -// we just reset, so BLE should be on -if (s.ble===false) NRF.sleep(); +// we just reset, so BLE should be on. +// Don't disconnect if something is already connected to us +if (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep(); // Set time, vibrate, beep, etc if (!s.vibrate) Bangle.buzz=Promise.resolve; if (!s.beep) Bangle.beep=Promise.resolve; From b9822314085dd0ca7bc8d0b2f60f66dcb6776ebb Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 Mar 2020 09:03:10 +0000 Subject: [PATCH 08/55] Upload files one by one, avoiding flow control issues on Android - should make uploads much more reliable --- comms.js | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/comms.js b/comms.js index 74b0b6049..25ec45f89 100644 --- a/comms.js +++ b/comms.js @@ -11,12 +11,31 @@ reset : () => new Promise((resolve,reject) => { uploadApp : (app,skipReset) => { return AppInfo.getFiles(app, httpGet).then(fileContents => { return new Promise((resolve,reject) => { - fileContents = fileContents.map(storageFile=>storageFile.cmd).join("\n")+"\n"; - console.log("uploadApp",fileContents); + console.log("uploadApp",fileContents.map(f=>f.name).join(", ")); + // Upload each file one at a time + function doUploadFiles() { + // No files left - print 'reboot' message + if (fileContents.length==0) { + Puck.write(`\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => { + if (result===null) return reject(""); + resolve(appJSON); + }); + return; + } + var f = fileContents.shift(); + console.log(`Upload ${f.name} => ${JSON.stringify(f.content)}`); + // Chould check CRC here if needed instead of returning 'OK'... + // E.CRC32(require("Storage").read(${JSON.stringify(app.name)})) + Puck.write(`\x10${f.cmd};Bluetooth.println("OK")\n`,(result) => { + if (!result || result.trim()!="OK") return reject("Unexpected response "+(result||"")); + doUploadFiles(); + }, true); // wait for a newline + } + // Start the upload function doUpload() { - Puck.write(`\x10E.showMessage('Uploading\\n${app.id}...')\n${fileContents}\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => { + Puck.write(`\x10E.showMessage('Uploading\\n${app.id}...')\n`,(result) => { if (result===null) return reject(""); - resolve(appJSON); + doUploadFiles(); }); } if (skipReset) { From 4fe8cc3fd6602c5ac87e18724ede65515a445e2b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 Mar 2020 09:10:28 +0000 Subject: [PATCH 09/55] Fix "Unknown app undefined" in 'My Apps' when installing a new app (fix #106) --- comms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comms.js b/comms.js index 25ec45f89..e9a6234ce 100644 --- a/comms.js +++ b/comms.js @@ -18,7 +18,7 @@ uploadApp : (app,skipReset) => { if (fileContents.length==0) { Puck.write(`\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => { if (result===null) return reject(""); - resolve(appJSON); + resolve(app); }); return; } From 7823f1cc83491fbaee6336ebbfdfcc22760d73cb Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 Mar 2020 15:58:52 +0000 Subject: [PATCH 10/55] Update examples to new firmware style --- apps/_example_app/add_to_apps.json | 5 ++--- apps/_example_widget/add_to_apps.json | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/_example_app/add_to_apps.json b/apps/_example_app/add_to_apps.json index c75f9ed7d..ca75a7bd8 100644 --- a/apps/_example_app/add_to_apps.json +++ b/apps/_example_app/add_to_apps.json @@ -7,8 +7,7 @@ "description": "A detailed description of my great app", "tags": "", "storage": [ - {"name":"+7chname","url":"app.json"}, - {"name":"-7chname","url":"app.js"}, - {"name":"*7chname","url":"app-icon.js","evaluate":true} + {"name":"7chname.app.js","url":"app.js"}, + {"name":"7chname.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/_example_widget/add_to_apps.json b/apps/_example_widget/add_to_apps.json index 3011fe744..5d0057960 100644 --- a/apps/_example_widget/add_to_apps.json +++ b/apps/_example_widget/add_to_apps.json @@ -8,7 +8,6 @@ "tags": "widget", "type": "widget", "storage": [ - {"name":"+7chname","url":"widget.json"}, - {"name":"=7chname","url":"widget.js"} + {"name":"7chname.wid.js","url":"widget.js"} ] } From 107d8ef7e03121260a06b4731dcb2be31b0f7d5a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 Mar 2020 15:59:00 +0000 Subject: [PATCH 11/55] Add torch app --- apps.json | 13 +++++++++++++ apps/torch/ChangeLog | 1 + apps/torch/app-icon.js | 1 + apps/torch/app.js | 8 ++++++++ apps/torch/app.png | Bin 0 -> 1667 bytes apps/torch/widget.js | 16 ++++++++++++++++ 6 files changed, 39 insertions(+) create mode 100644 apps/torch/ChangeLog create mode 100644 apps/torch/app-icon.js create mode 100644 apps/torch/app.js create mode 100644 apps/torch/app.png create mode 100644 apps/torch/widget.js diff --git a/apps.json b/apps.json index b7d1bb3a8..4a1e164bb 100644 --- a/apps.json +++ b/apps.json @@ -773,5 +773,18 @@ {"name":"pipboy.app.js","url":"app.js"}, {"name":"pipboy.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "torch", + "name": "Torch", + "shortName":"Torch", + "icon": "app.png", + "version":"0.01", + "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN3 four times in quick succession to start when in normal clock mode", + "tags": "tool,torch", + "storage": [ + {"name":"torch.app.js","url":"app.js"}, + {"name":"torch.wid.js","url":"widget.js"}, + {"name":"torch.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/torch/ChangeLog b/apps/torch/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/torch/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/torch/app-icon.js b/apps/torch/app-icon.js new file mode 100644 index 000000000..13fc792fe --- /dev/null +++ b/apps/torch/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4Acq0yF1tWlksF10yqwuuSVIuGSVF/FwySm5nM0YuGSUovBGAIuGAgIukGAQuGAgIvlSQozEF0iSEeowvlGAT1HF0iSDeo4vlegSShF5fMv4uFSLQkC0QACSRguevErld4GBKSDFz4ABF5CSBLsIvLdDK7GFwiPIF0AvEFw4tbFwztKFrguDF4gADFkAuFF44unF4wuoGAouqAAwu/ABtWqwutmUsmQutF4JhKF0iSJdT4uFAoIwGFz4wCFwgECF0qRCFwo3BF0qSDMQiSBF0owCFwgFBF86SBF1qSFF1SSDF1gA/AH4A1A")) diff --git a/apps/torch/app.js b/apps/torch/app.js new file mode 100644 index 000000000..28aa00bd6 --- /dev/null +++ b/apps/torch/app.js @@ -0,0 +1,8 @@ +Bangle.setLCDPower(1); +Bangle.setLCDTimeout(0); +g.reset(); +g.fillRect(0,0,g.getWidth(),g.getHeight()); +// Any button turns off +setWatch(()=>load(), BTN1); +setWatch(()=>load(), BTN2); +setWatch(()=>load(), BTN3); diff --git a/apps/torch/app.png b/apps/torch/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a02a835f006431f7928350e29e829347df8262b8 GIT binary patch literal 1667 zcmV-}27LL6P)ZJKCDS?Q3% zwQHtv>3TscjEbpLpaMhSO7sJKp+YEYCs@U{57kPgiNOXdVZxsJ(5bq z9!kX%-#_`nGly>`pSo0F#mMLLDIvAyXnJyD=a_#;OQ(_@A6mch{rQc`Vq2#d{mcM`Hz_zs?xjS~D_uT1Xa+lqJ?5Vm3DW3&In={HCo?%{k%f*#&7$Fqg zt6FB@vxJ5Q$Rv{jDK@Wr@N+%yzS%RdtOle+VZd+#Xu8(su8vcqC3&OYgR7zG+RPIg zyhJ9Q!eBDvX>Jv&qHJAz*L~;SJNrg|p)tx^13l*5An(p??r87lsqO#5S!14oA0U%X zVlbJhYiUDO4I~p2mXS++f7tY;U3&`+QMMJ3uVX+MehWDAJ+HUM_@H~3bfvhSswW4rjDNTr@II8W%37??1is@vr8~QAPvev0}nH+WR@Y?F?44ejQ#)eHz}|2tZ^cXo+6F z{9L~6R2BpBWz4|Gi;chC9bn%*FA@$8Ps7)^=E5@(4TF?u)s`RS_ASo}ShahBs#3b# z=^bMKXZomhJ8{-~fmwJV1fHfAG>h#-ZoefjVkr>}s!suHq=Y~~a^WHbgOJIB-7XLd z9O7@Q8)scxn12l4#%M4!1Fzs|YQbD>JvLTr`r5#$Q+nA9NQt1^dtV)u4YZ8ZJ;cJMyI*!vg$}8ur2o&5+Eojs5+fMm>+1&UgGcX7KiEHqG z>2+|Z`&JTZ1Ietydm$SStPau8Q1~9zRvX2nRlR#D)o#=**5^gAZ`aFRT~qmD4NDFW zT(~IdK5yq2J-3k6XJL)1L@Zu)QwVwB(S2tRZWm|u#e#3zK)#ueMBvwFTIRtU6v>Wt zgLvEpv%QHT_lWhGw~8JArVK0u4=|Mj|E={GxW7F{V`JX!a}mTrHl&UU!J@N1S2ujA zp9>G*_e=bN+2{ZCJ2-l#1*0n2`LRJZ+!15Vt@GYMSAia+JVGe_JMl1i_jp+h&t_m^ zVt!k>;h_Wri_N^Kh?G=dNcwz_7{N7r!Qs{de8|K~uMtBS!xo*GaT`RB+; zaP_sb`1EnsLf@#1FCTr7P~1`|Uq#^|kAW-WBkC-CGg`HUsce?fp#et5Q+)l{Caz}8 z`Epep9`YCvy7_*SRu!9uw_byQ*!D&~^AkoUs{rTdfOeX}!3d@UY02_|;=w zL+;v!wW_L~o=n8A|6*pVby4H-_6e2GRtj_>6?GQ+!j8Q)f#X7eN8Y(~wzW_NiK20hzx?3X_aEZ%EHD_T*x^=CLICK_COUNT) clickTimes.shift(); + clickTimes.push(e.time); + var clickPeriod = e.time-clickTimes[0]; + if (clickTimes.length==CLICK_COUNT && clickPeriod Date: Wed, 4 Mar 2020 15:04:21 +0000 Subject: [PATCH 12/55] Fix GPS apps if time not set in GPS (fix #110) --- apps.json | 5 ++-- apps/boot/ChangeLog | 1 + apps/boot/boot0.js | 58 +++++++++++++--------------------------- apps/boot/bootloader.js | 27 ++++++++++++++++--- apps/gpsinfo/ChangeLog | 1 + apps/gpsinfo/gps-info.js | 1 + 6 files changed, 48 insertions(+), 45 deletions(-) create mode 100644 apps/gpsinfo/ChangeLog diff --git a/apps.json b/apps.json index 4a1e164bb..718224cdd 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "boot", "name": "Bootloader", "icon": "bootloader.png", - "version":"0.08", + "version":"0.09", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "tags": "tool,system", "type":"bootloader", @@ -638,7 +638,7 @@ "id": "gpsinfo", "name": "GPS Info", "icon": "gps-info.png", - "version":"0.01", + "version":"0.02", "description": "An application that displays information about altitude, lat/lon, satellites and time", "tags": "gps", "type": "app", @@ -753,6 +753,7 @@ { "id": "flagrse", "name": "Espruino Flag Raiser", "icon": "app.png", + "version":"0.01", "description": "App to send a command to another Espruino to cause it to raise a flag", "tags": "", "storage": [ diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 62adcecdc..8cd322022 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -5,3 +5,4 @@ 0.06: Disable GPS time log messages, add (default=1) setting to hide log messages 0.07: Fix issues with alarm scheduling 0.08: Fix issues if BLE=off, 'Make Connectable' is chosen, and the loader resets Bangle.js (fix #108) +0.09: Only check GPS for time after a fresh boot diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index a5b4b45af..db2533400 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -26,44 +26,24 @@ if (!s.timeout) Bangle.setLCDPower(1); E.setTimeZone(s.timezone); delete s; // check for alarms -function checkAlarm() { - var alarms = require('Storage').readJSON('alarm.json',1)||[]; - var time = new Date(); - var active = alarms.filter(a=>a.on&&(a.last!=time.getDate())); - if (active.length) { - active = active.sort((a,b)=>a.hr-b.hr); - var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); - if (!require('Storage').read("alarm.js")) { - console.log("No alarm app!"); - require('Storage').write('alarm.json',"[]") - } else { - var t = 3600000*(active[0].hr-hr); - if (t<1000) t=1000; - /* execute alarm at the correct time. We avoid execing immediately - since this code will get called AGAIN when alarm.js is loaded. alarm.js - will then clearInterval() to get rid of this call so it can proceed - normally. */ - setTimeout(function() { - load("alarm.js"); - },t); - } +var alarms = require('Storage').readJSON('alarm.json',1)||[]; +var time = new Date(); +var active = alarms.filter(a=>a.on&&(a.last!=time.getDate())); +if (active.length) { + active = active.sort((a,b)=>a.hr-b.hr); + var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); + if (!require('Storage').read("alarm.js")) { + console.log("No alarm app!"); + require('Storage').write('alarm.json',"[]") + } else { + var t = 3600000*(active[0].hr-hr); + if (t<1000) t=1000; + /* execute alarm at the correct time. We avoid execing immediately + since this code will get called AGAIN when alarm.js is loaded. alarm.js + will then clearInterval() to get rid of this call so it can proceed + normally. */ + setTimeout(function() { + load("alarm.js"); + },t); } } -// check to see if our clock is wrong - if it is use GPS time -if ((new Date()).getFullYear()==1970) { - //console.log("Searching for GPS time"); - Bangle.on('GPS',function cb(g) { - Bangle.setGPSPower(0); - Bangle.removeListener("GPS",cb); - if (!g.time || (g.time.getFullYear()<2000) || - (g.time.getFullYear()==2250)) { - //console.log("GPS receiver's time not set"); - return; - } - setTime(g.time.getTime()/1000); - //console.log("GPS time",g.time.toString()); - checkAlarm(); - }); - Bangle.setGPSPower(1); -} else checkAlarm(); -delete checkAlarm; diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index fca89d23a..febc4fc19 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -12,8 +12,27 @@ if (!settings.welcomed && require("Storage").read("welcome.js")!==undefined) { clockApp = require("Storage").read(clockApps[0].src); delete clockApps; } - if (clockApp) eval(clockApp); - else E.showMessage("No Clock Found"); - delete clockApp; + if (!clockApp) clockApp='E.showMessage("No Clock Found")'; + delete settings; + // check to see if our clock is wrong - if it is use GPS time + if ((new Date()).getFullYear()==1970) { + E.showMessage("Searching for\nGPS time"); + Bangle.on('GPS',function cb(g) { + Bangle.setGPSPower(0); + Bangle.removeListener("GPS",cb); + if (!g.time || (g.time.getFullYear()<2000) || + (g.time.getFullYear()==2250)) { + // GPS receiver's time not set - just boot clock anyway + eval(clockApp);delete clockApp; + return; + } + // We have a GPS time. Set time and reboot (to load alarms properly) + setTime(g.time.getTime()/1000); + load(); + }); + Bangle.setGPSPower(1); + } else { + eval(clockApp); + delete clockApp; + } } -delete settings; diff --git a/apps/gpsinfo/ChangeLog b/apps/gpsinfo/ChangeLog new file mode 100644 index 000000000..50d79e72d --- /dev/null +++ b/apps/gpsinfo/ChangeLog @@ -0,0 +1 @@ +0.02: Ensure screen doesn't display garbage at startup diff --git a/apps/gpsinfo/gps-info.js b/apps/gpsinfo/gps-info.js index 334310755..f7daf245a 100644 --- a/apps/gpsinfo/gps-info.js +++ b/apps/gpsinfo/gps-info.js @@ -2,6 +2,7 @@ var img = require("heatshrink").decompress(atob("mEwghC/AH4AKg9wC6t3u4uVC6wWBI6t Bangle.setGPSPower(1); Bangle.setLCDMode("doublebuffered"); +E.showMessage("Loading..."); // avoid showing rubbish on screen var lastFix = { fix: 0, From 7f27796093c3be9878d707c34995ef4d15c48b7c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 Mar 2020 16:40:25 +0000 Subject: [PATCH 13/55] Fix issue uploading then cancelling custom app --- comms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/comms.js b/comms.js index e9a6234ce..691a60ca7 100644 --- a/comms.js +++ b/comms.js @@ -4,7 +4,7 @@ Puck.debug=3; var Comms = { reset : () => new Promise((resolve,reject) => { Puck.write("\x03\x10reset();\n", (result) => { - if (result===null) return reject(""); + if (result===null) return reject("Connection failed"); setTimeout(resolve,500); }); }), @@ -42,7 +42,7 @@ uploadApp : (app,skipReset) => { doUpload(); } else { // reset to ensure we have enough memory to upload what we need to - Comms.reset().then(doUpload) + Comms.reset().then(doUpload, reject) } }); }); From 909a2b4641f5f5a402ba3be914093bbfcb30d28a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 Mar 2020 16:41:10 +0000 Subject: [PATCH 14/55] style --- apps/qrcode/qrcode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/qrcode/qrcode.html b/apps/qrcode/qrcode.html index 8a0027929..5d372aa59 100644 --- a/apps/qrcode/qrcode.html +++ b/apps/qrcode/qrcode.html @@ -4,7 +4,7 @@ -

Enter a URL:

+

Enter a URL:

Try your QR Code:

Click

From e0ccfe82e716238d606dcb79c600da90335da67e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 Mar 2020 16:42:44 +0000 Subject: [PATCH 15/55] Added locale loader courtesy of @MaBe's extremely hard work! (ref #105) --- apps.json | 12 ++ apps/locale/ChangeLog | 1 + apps/locale/locale.html | 89 +++++++++++ apps/locale/locale.png | Bin 0 -> 1708 bytes apps/locale/locales.js | 323 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 425 insertions(+) create mode 100644 apps/locale/ChangeLog create mode 100644 apps/locale/locale.html create mode 100644 apps/locale/locale.png create mode 100644 apps/locale/locales.js diff --git a/apps.json b/apps.json index 718224cdd..da00f124c 100644 --- a/apps.json +++ b/apps.json @@ -37,6 +37,18 @@ {"name":"about.img","url":"app-icon.js","evaluate":true} ] }, + { "id": "locale", + "name": "Languages", + "icon": "locale.png", + "version":"0.01", + "description": "Translations for different countries", + "tags": "tool,system", + "custom":"locale.html", + "storage": [ + {"name":"locale"} + ], + "sortorder" : -10 + }, { "id": "welcome", "name": "Welcome", "icon": "app.png", diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/locale/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/locale/locale.html b/apps/locale/locale.html new file mode 100644 index 000000000..a6abce4f8 --- /dev/null +++ b/apps/locale/locale.html @@ -0,0 +1,89 @@ + + + + + + +

Please choose a language from the following list:

+
+ +
+

Then click

+ + + + + + + diff --git a/apps/locale/locale.png b/apps/locale/locale.png new file mode 100644 index 0000000000000000000000000000000000000000..1719f618189fcde9ef14891421a27d8ad4013f75 GIT binary patch literal 1708 zcmV;d22=ToP)OB*gx`_S;vmsThU z(LNL*plzbWrGWYZMJ-k(B%UfH>OfUgKx!puktn65Pz8~N><#+E=+EW!+FeCuMmvPwfRM4Uu%d)wif$E2Dm<6A`uOFC z+ak3a@MmU#!D=U%%MNn;?0ZG~N7@XZ=-k}sSPI?=XIaa-M3)f8rjNJ2SdIRC1GJQ2 zDSUb^P9jr$cz;m%WS2qKwIwrfHf&iv_5cV5Ib<^M`zi?>4NB1rP<;10)l|K$XrMs?~ z0S*agrElsq+|Yt+JELpL)D`D>IR$HZ>l=zGs&Gq>VX##Iy{Dmh<)u5v)ql+l*gz@^ zZ-8st(3mHe8dl##FqC|7A`GY z`h$jG!}|OR??x>1E1PN(?f+(J_%~!5u2iEggvwD4{o!@kfgJ#7^ubM?o8$pR;8VMe z^P#RIGW6SO$pZ```pm{lz5z9#hSgwir{uzErZHOUG(#H?n+7OH*t$M??16J5u?vkJi;T2`LZL4J3LL#li(=Z#eEboBN7s6$L zI5(-Xm|L+7wfS-<;bhbjitV7UY{ksRgIBT?^k~cBaP;r|Wa>%!lHrQA%{TV)*uEz? z-E~Lh6pLd9YmaWcxV&ZbWGo3Z790JKH}9e^wNSOzxu!mD|KeY_v`ydoO#nLQj?gi8 zB-d^P4iEdb$ex+ETuo|n`b2AUe!EvH5idog7V-f7$$8KALh|6G;@N`JZv8!0INoJ| z!dy)ZYe0twd2oWn`G{k{2g}Y)Etvtt&CO+iQKoi)D*y-k44qAzUfbzGegpF>%A2#6 z|6Q>pGV9k(m@JfY?||r;y0G;?dy{Z$pW)^`hCoC4icTV}7=iTq?M>Cq%@u_dJtcLj zcNN3#fY2QfW|o!dtCmcO@>WN)5KTJnWYl-6u-~-<7sG9Dkr!uo3IYtbIhXmKK=B3J z-7G9Q_oWXmEC$XN_Pe9dxL8$rp?*|LqtU=;_89yg@lXJtQC2gGA}@HAB0Xf9wPIIEw`h?(#j>uJFIj|4&j&w2Gdw(p6$8WBsu^oQOlh+iPO zs-Qd@Iv%*}B~#S-27h(6t0843f!*67_=E7TIr^Sc9eL;*=Un~oge{A!C3C1qgHQKQ z9cx?i>MVMx4?Wl(RpC3;(RJgeJ>TN@w|w8T@4|;#jy%BeV&uU)nakng@z&pcd?I$I z3dhPaErCBB_%;De=H9bbITulu5@pFxOrL0dsgyw3vdV=$!7+iCD`M&a0Rn#Em77lh z&Yj_33zd+U*G9s@@0FXsd|l{X$*%c=_p9n(Dj{5m-j>Z{aU}(3=Pg%LWy!yq^tIeu zNrk$i!q)6DNp$;Lj|lv-68U^I`5pS_qn3ZpWm!p=cbk!L%U5QPNurz})bNYxV-vCa zM0lDCqtj=54L))5`7&4p#>)A8A!#_>07V-`a;o^nUWneHCIxk>@jFCW;+Wm7qRp=eU~D-sOXWd`Xep zfPE+fs*?RnDy^ibnsN?_a@p%)YyBKl+0000 Date: Wed, 4 Mar 2020 16:46:49 +0000 Subject: [PATCH 16/55] tweak for sanity checker --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index da00f124c..51ce6a091 100644 --- a/apps.json +++ b/apps.json @@ -43,6 +43,7 @@ "version":"0.01", "description": "Translations for different countries", "tags": "tool,system", + "type": "locale", "custom":"locale.html", "storage": [ {"name":"locale"} From 2c1397ab929827328bde8e72eb2870c6201b7149 Mon Sep 17 00:00:00 2001 From: MaBecker Date: Wed, 4 Mar 2020 20:59:27 +0100 Subject: [PATCH 17/55] widid --- apps.json | 11 +++++++++++ apps/widid/ChangeLog | 1 + apps/widid/widget.js | 15 +++++++++++++++ apps/widid/widget.png | Bin 0 -> 2174 bytes 4 files changed, 27 insertions(+) create mode 100644 apps/widid/ChangeLog create mode 100644 apps/widid/widget.js create mode 100644 apps/widid/widget.png diff --git a/apps.json b/apps.json index 51ce6a091..ceacbc0be 100644 --- a/apps.json +++ b/apps.json @@ -800,5 +800,16 @@ {"name":"torch.wid.js","url":"widget.js"}, {"name":"torch.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "widid", + "name": "My NRF ID Widget", + "icon": "widid.png", + "version":"0.01", + "description": "Display the last two tupple of you Bangle.js address in the widget section.", + "tags": "widget", + "type":"widget", + "storage": [ + {"name":"widid.wid.js","url":"widget.js"} + ] } ] diff --git a/apps/widid/ChangeLog b/apps/widid/ChangeLog new file mode 100644 index 000000000..2b3617f98 --- /dev/null +++ b/apps/widid/ChangeLog @@ -0,0 +1 @@ +0.01: New Widget! \ No newline at end of file diff --git a/apps/widid/widget.js b/apps/widid/widget.js new file mode 100644 index 000000000..fcace0f55 --- /dev/null +++ b/apps/widid/widget.js @@ -0,0 +1,15 @@ +/* */ +(() => { + var xpos = WIDGETPOS.tr-16; + WIDGETPOS.tr-= 16; + id = NRF.getAddress().split(":"); + + // draw your widget at xpos + function draw() { + var x = xpos, y = 0; + g.setColor(0,0.5,1).setFont("6x8",1); + g.drawString(addr[4],x,0,true); + g.drawString(addr[5],x,10),true; + } + WIDGETS["widid"]={draw:draw}; +})() diff --git a/apps/widid/widget.png b/apps/widid/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5ce863f578d53c5ddc5930cf1b5b38f4d67213 GIT binary patch literal 2174 zcmXw3dpOhW8-ErPD)e(m@*`4+qQg5Cm5Pct$E5d-C_2bFc{_{HPt-DI&cm2PPIDT@ z46`vd3~81*&5%>hGDh#WKYsUhJ@<3npXa{s&*!v3#b$Yp`pazf{@M^S4$ zrCSNt0-_1zo*~A-cU&{~eKmVeJn12UIq_qunKw@99Rd06p+qJ`ok0CcXy@_1&kKGm zfzO>FrW`uz;m;JZ`m@`H?iMt+4orfW(!~018duN*5ur+Y1yjVX;osB9>!|7)hK2wN zIw5x5n2N80-vbRMwnJ+BCVptglz1eQ0G@RMM}u(Q_`Go{4dk)1nmL!EihgTGmx;xc z!m}74t{lXZpyuK!^{~tq$qc#}x)Pq%CYDYUizaN3tJ;Zc28m=?G6kejWph}PsSV67t<&JLjkdM!&CExEFQkKKfmQ`1gR^kiuJmj1JiG1EPd>XJqAm6jqyZy+Sl-ugO# zZBr4G6yGJGBxk0#wJ8#|-#>p$S8H=|l8cV9x_IH(j?DoMr?(S_dh74$;^cV4!R++m z1N&9wH%05~Ys(7@v$NCFljCETGmS>2QpgqM1VT}MP9_$MMt%Aa78V*B z6!gT;+xy;aXJ@F1t&RDmbAOyLlzoWGhXWv9WMOu};c5%E2W~2Frz$c33u%>m=h^>l zBG8)det58>l70Y51tLwzhWgm61~AR$pE1tJgzy#?6hvnaPUDPA^&PZ5T@h zgS7L%E?94g=zluoAAjyJne>nJAM&B)7Z0k`i|#eJ*hL z(fNc(x`JduDtGz%|9WmBBI#~T7}J(i*X=i{E*&Z@fd<(bOsI zubBf%ewym)>SSSt&-DzU{n&Amc<3Q{gFKpLg+iqA%Lc@P4b~3X2~Xv@r|0>H&A+|f z&+a^GqUrI`?y#5`rt^k+Kp1x81twr$0vBHEEUs%6FIUcWL)`xEpfD5VVyo*T)i)GK8UoCzZ9MEw!3;C&*K-BI2;@|`4QN9Nw@%|$~6C?465DzPS zy9X z^C1JTu>cg7bCzM@tAjmK>2Imu^ty0|Db}6r*1BXAl^u3_M^LqyFIKmLA#FyNLb0&w_2E5jr4dH4JZ1@q6lH-&-tzH>_(wsiDmZe-O zyLuP5S7|&4VKawPAxI9C=aYdX8XXCnH3R`DfpKG%h7Rl8+t-P!~ z7-HUM_65Jsv73<$5=gQo4+}2A^X~=fAjcD9xB2tc3XCuJzcpGtKKkHEh^km-lj}=$ zsXYTalgn=q(x{eK{gI|-;d-9KDcG6mple#uj^vI}>-+UeFux{q8SXpx#Sm&p;jDIa z#}jSSk&WyCZmNmPyRtgpw#S1+Q7O-n7x3Cw2=RMT+=DNrh%-){IG}laC2c6|DlzwAoYpbB%;@EI zPO-1A8l5?5H+sV{M?BJ!mPFIBhbp@-8V^~sx`Mk&t*PyZ8&)2U^ zN&ZzOoOxgt8e!z8KuP51sig-j{l_=jNFfL=n##MAdp;^-%^-Dvt-Lmd5QQCmoe{nd zu@!_ Date: Wed, 4 Mar 2020 21:14:49 +0100 Subject: [PATCH 18/55] widid --- apps/widid/widget.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widid/widget.js b/apps/widid/widget.js index fcace0f55..3ef7e3b9f 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -8,8 +8,8 @@ function draw() { var x = xpos, y = 0; g.setColor(0,0.5,1).setFont("6x8",1); - g.drawString(addr[4],x,0,true); - g.drawString(addr[5],x,10),true; + g.drawString(id[4],x,0,true); + g.drawString(id[5],x,10),true; } WIDGETS["widid"]={draw:draw}; })() From 54f5a3b8ea657ee903a3b65ce36ba6b7f3fe847b Mon Sep 17 00:00:00 2001 From: MaBecker Date: Wed, 4 Mar 2020 21:21:47 +0100 Subject: [PATCH 19/55] widid --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index ceacbc0be..f5e655e88 100644 --- a/apps.json +++ b/apps.json @@ -805,7 +805,7 @@ "name": "My NRF ID Widget", "icon": "widid.png", "version":"0.01", - "description": "Display the last two tupple of you Bangle.js address in the widget section.", + "description": "Display the last two tupple of your Bangle.js address in the widget section.", "tags": "widget", "type":"widget", "storage": [ From 0da5b38b3e80d58db4c809ca0c11222e4b27db58 Mon Sep 17 00:00:00 2001 From: MaBecker Date: Wed, 4 Mar 2020 21:24:34 +0100 Subject: [PATCH 20/55] widid --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index f5e655e88..c76106909 100644 --- a/apps.json +++ b/apps.json @@ -805,7 +805,7 @@ "name": "My NRF ID Widget", "icon": "widid.png", "version":"0.01", - "description": "Display the last two tupple of your Bangle.js address in the widget section.", + "description": "Display the last two tuple of your Bangle.js address in the widget section.", "tags": "widget", "type":"widget", "storage": [ From 98d5c2543666307c0d450d28f35184da25fbd65d Mon Sep 17 00:00:00 2001 From: MaBecker Date: Thu, 5 Mar 2020 06:48:50 +0100 Subject: [PATCH 21/55] widid ident and syntax --- apps/widid/widget.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widid/widget.js b/apps/widid/widget.js index 3ef7e3b9f..111284812 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -1,4 +1,4 @@ -/* */ +/* jshint esversion: 6 */ (() => { var xpos = WIDGETPOS.tr-16; WIDGETPOS.tr-= 16; @@ -8,7 +8,7 @@ function draw() { var x = xpos, y = 0; g.setColor(0,0.5,1).setFont("6x8",1); - g.drawString(id[4],x,0,true); + g.drawString(id[4],x,0,true); g.drawString(id[5],x,10),true; } WIDGETS["widid"]={draw:draw}; From ffc59450b51a5fc09f5e8c06ffb99464fa1f5747 Mon Sep 17 00:00:00 2001 From: MaBecker Date: Thu, 5 Mar 2020 06:50:32 +0100 Subject: [PATCH 22/55] widid indent --- apps/widid/widget.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/widid/widget.js b/apps/widid/widget.js index 111284812..7c500baf2 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -1,15 +1,16 @@ /* jshint esversion: 6 */ (() => { - var xpos = WIDGETPOS.tr-16; - WIDGETPOS.tr-= 16; - id = NRF.getAddress().split(":"); + var xpos = WIDGETPOS.tr - 16; + WIDGETPOS.tr -= 16; + id = NRF.getAddress().split(":"); - // draw your widget at xpos - function draw() { - var x = xpos, y = 0; - g.setColor(0,0.5,1).setFont("6x8",1); - g.drawString(id[4],x,0,true); - g.drawString(id[5],x,10),true; - } - WIDGETS["widid"]={draw:draw}; -})() + // draw your widget at xpos + function draw() { + var x = xpos, + y = 0; + g.setColor(0, 0.5, 1).setFont("6x8", 1); + g.drawString(id[4], x, 0, true); + g.drawString(id[5], x, 10, true); + } + WIDGETS["widid"] = { draw: draw }; +})(); From 1bf8ac0ed76dd9c59f2c1954817c61c986af64e0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 08:27:49 +0000 Subject: [PATCH 23/55] minor tweaks after merge --- apps.json | 8 ++++---- apps/widid/widget.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index c76106909..e4b92eb14 100644 --- a/apps.json +++ b/apps.json @@ -800,12 +800,12 @@ {"name":"torch.wid.js","url":"widget.js"}, {"name":"torch.img","url":"app-icon.js","evaluate":true} ] - }, + }, { "id": "widid", - "name": "My NRF ID Widget", - "icon": "widid.png", + "name": "Bluetooth ID Widget", + "icon": "widget.png", "version":"0.01", - "description": "Display the last two tuple of your Bangle.js address in the widget section.", + "description": "Display the last two tuple of your Bangle.js address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", "tags": "widget", "type":"widget", "storage": [ diff --git a/apps/widid/widget.js b/apps/widid/widget.js index 7c500baf2..84f5fe5f0 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -8,7 +8,7 @@ function draw() { var x = xpos, y = 0; - g.setColor(0, 0.5, 1).setFont("6x8", 1); + g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); g.drawString(id[4], x, 0, true); g.drawString(id[5], x, 10, true); } From 0232fc00cca487b688c1178973f1393292c0fbad Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 09:12:32 +0000 Subject: [PATCH 24/55] Translate now returns untranslated text if it can't find a translation --- apps/locale/locale.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/locale/locale.html b/apps/locale/locale.html index a6abce4f8..d160ad331 100644 --- a/apps/locale/locale.html +++ b/apps/locale/locale.html @@ -62,7 +62,6 @@ var app = ` locale = ${JSON.stringify(locales[lang])}; - exports = { lang: locale.lang, currencySym: String.fromCharCode(locale.currency_symbol), @@ -73,7 +72,7 @@ distance: n => (n < 1000) ? Math.round(n) + locale.distance[0] : Math.round(n/1000) + locale.distance[1], speed: s => Math.round(s) +locale.speed, temp: t => Math.round(t) + locale.temperature, - translate: s => (locale.lang.substr(2) == "en")? s: locale.trans[s], + translate: s => locale.trans[s]||locale.trans[s.toLowerCase()]||s, date: (d,short) => (short) ? \`${dateS}\`: \`${dateN}\`, time: (d,short) => (short) ? \`${timeS}\`: \`${timeN}\`, };`; From 18a9f2c71fb646d5824aaa8f8db6237d3446b73b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 10:01:16 +0000 Subject: [PATCH 25/55] Allow translate to work even if not given a string --- apps/locale/locale.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/locale/locale.html b/apps/locale/locale.html index d160ad331..931bde033 100644 --- a/apps/locale/locale.html +++ b/apps/locale/locale.html @@ -72,7 +72,7 @@ distance: n => (n < 1000) ? Math.round(n) + locale.distance[0] : Math.round(n/1000) + locale.distance[1], speed: s => Math.round(s) +locale.speed, temp: t => Math.round(t) + locale.temperature, - translate: s => locale.trans[s]||locale.trans[s.toLowerCase()]||s, + translate: s => {s=""+s;return locale.trans[s]||locale.trans[s.toLowerCase()]||s}, date: (d,short) => (short) ? \`${dateS}\`: \`${dateN}\`, time: (d,short) => (short) ? \`${timeS}\`: \`${timeN}\`, };`; From c3d6513d92789887cf7c11e07489aabb71784511 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 11:10:22 +0000 Subject: [PATCH 26/55] keywords --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index e4b92eb14..952011799 100644 --- a/apps.json +++ b/apps.json @@ -42,7 +42,7 @@ "icon": "locale.png", "version":"0.01", "description": "Translations for different countries", - "tags": "tool,system", + "tags": "tool,system,locale,translate", "type": "locale", "custom":"locale.html", "storage": [ From a7722808711e379651bc0efc1891a239e55e0579 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 13:15:03 +0000 Subject: [PATCH 27/55] Add ChangeLog checking --- apps/gbridge/{Changelog => ChangeLog} | 0 bin/sanitycheck.js | 11 +++++++++++ 2 files changed, 11 insertions(+) rename apps/gbridge/{Changelog => ChangeLog} (100%) diff --git a/apps/gbridge/Changelog b/apps/gbridge/ChangeLog similarity index 100% rename from apps/gbridge/Changelog rename to apps/gbridge/ChangeLog diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index d32041cda..d911a20d6 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -46,6 +46,17 @@ apps.forEach((app,addIdx) => { var isApp = !app.type || app.type=="app"; if (app.name.length>20 && !app.shortName && isApp) ERROR(`App ${app.id} has a long name, but no shortName`); if (!app.version) WARN(`App ${app.id} has no version`); + else { + if (!fs.existsSync(appDir+"ChangeLog")) { + if (app.version != "0.01") + WARN(`App ${app.id} has no ChangeLog`); + } else { + var versions = fs.readFileSync(appDir+"ChangeLog").toString().match(/\d+\.\d+:/g); + var lastChangeLog = versions.pop().slice(0,-1); + if (lastChangeLog != app.version) + WARN(`App ${app.id} app version (${app.version}) and ChangeLog (${lastChangeLog}) don't agree`); + } + } if (!app.description) ERROR(`App ${app.id} has no description`); if (!app.icon) ERROR(`App ${app.id} has no icon`); if (!fs.existsSync(appDir+app.icon)) ERROR(`App ${app.id} icon doesn't exist`); From e0d29c81f281ef76d8a1db93a9701c111d17c75e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 13:15:27 +0000 Subject: [PATCH 28/55] Big refactor #2 - variable width widgets --- README.md | 26 +++++++++++++++--- apps.json | 25 ++++++++---------- apps/_example_widget/widget.js | 13 +++++---- apps/alarm/ChangeLog | 1 + apps/alarm/widget.js | 12 +++------ apps/gbridge/ChangeLog | 1 + apps/gbridge/Changelog | 4 +++ apps/gbridge/widget.js | 10 +++---- apps/gpsrec/ChangeLog | 1 + apps/gpsrec/widget.js | 48 ++++++++++++++++------------------ apps/torch/widget.js | 2 ++ apps/widbat/ChangeLog | 1 + apps/widbat/widget.js | 24 ++++++++++------- apps/widbt/ChangeLog | 1 + apps/widbt/widget.js | 9 +++---- apps/widclk/ChangeLog | 1 + apps/widclk/widget.js | 42 +++++++++++------------------ apps/widhrm/ChangeLog | 1 + apps/widhrm/widget.js | 12 ++++----- apps/widid/ChangeLog | 3 ++- apps/widid/widget.js | 12 +++------ apps/widnceu/ChangeLog | 2 ++ apps/widnceu/widget.js | 14 +++------- apps/widpedom/ChangeLog | 1 + apps/widpedom/widget.js | 18 +++++-------- 25 files changed, 137 insertions(+), 147 deletions(-) create mode 100644 apps/gbridge/Changelog create mode 100644 apps/widbt/ChangeLog create mode 100644 apps/widclk/ChangeLog create mode 100644 apps/widnceu/ChangeLog diff --git a/README.md b/README.md index fbe7e2522..a0a5e5ba4 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Apps are listed in the Bangle.js menu, accessible from a clock app via the middl #### `app-icon.js` -The icon image and short description is used in the menu entry as selection possibility. +The icon image and short description is used in Bangle.js's launcher. Use the Espruino [image converter](https://www.espruino.com/Image+Converter) and upload your `app.png` file. @@ -136,11 +136,14 @@ Follow this steps to create a readable icon as image string. Replace this line with the image converter output: ``` -require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA==")); +require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA==")) ``` -Keep in mind to use this converter for creating images you like to draw with `g.drawImage()` with your app. +You can also use this converter for creating images you like to draw with `g.drawImage()` with your app. +Apps that need widgets can call `Bangle.loadWidgets()` **once** at startup to load +them, and then `Bangle.drawWidgets()` to draw them onto the screen whenever the app +has call to completely clear the screen. Widgets themselves will update as and when needed. ### Widget Example @@ -149,6 +152,23 @@ The widget example is available in [`apps/_example_widget`](apps/_example_widget * `add_to_apps.json` - insert into `apps.json`, describes the widget to bootloader and loader * `widget.js` - widget code +Widgets are just small bits of code that run whenever an app that supports them +calls `Bangle.loadWidgets()`. If they want to display something in the 24px high +widget bars at the top and bottom of the screen they can add themselves to +the global `WIDGETS` array with: + +``` +WIDGETS["mywidget"]={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: 24, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout + draw:draw // called to draw the widget +}; +``` + +When the widget is to be drawn, `x` and `y` values are set up in `WIDGETS["mywidget"]` +and `draw` can then use `this.x` and `this.y` to figure out where it needs to draw to. + + ### `app.info` format This is the file that's **auto-generated** and loaded onto Bangle.js by the App Loader, diff --git a/apps.json b/apps.json index 952011799..96536940d 100644 --- a/apps.json +++ b/apps.json @@ -66,7 +66,7 @@ { "id": "gbridge", "name": "Gadgetbridge", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "The default notification handler for Gadgetbridge notifications from Android", "tags": "tool,system,android,widget", "storage": [ @@ -106,7 +106,7 @@ "name": "Default Alarm", "shortName":"Alarms", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "Set and respond to alarms", "tags": "tool,alarm,widget", "storage": [ @@ -249,7 +249,7 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.04", + "version":"0.05", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", @@ -285,7 +285,7 @@ { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", - "version":"0.02", + "version":"0.03", "description": "Show the current battery level and charging status in the top right of the clock", "tags": "widget,battery", "type":"widget", @@ -296,7 +296,7 @@ { "id": "widbt", "name": "Bluetooth Widget", "icon": "widget.png", - "version":"0.01", + "version":"0.02", "description": "Show the current Bluetooth connection status in the top right of the clock", "tags": "widget,bluetooth", "type":"widget", @@ -318,7 +318,7 @@ { "id": "widhrm", "name": "Simple Heart Rate widget", "icon": "widget.png", - "version":"0.01", + "version":"0.02", "description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.", "tags": "health,widget", "type": "widget", @@ -329,7 +329,7 @@ { "id": "stetho", "name": "Stethoscope", "icon": "stetho.png", - "version":"0.0198", + "version":"0.01", "description": "Hear your heart rate", "tags": "health", "storage": [ @@ -472,7 +472,7 @@ { "id": "widnceu", "name": "NCEU Logo Widget", "icon": "widget.png", - "version":"0.01", + "version":"0.02", "description": "Show the NodeConf EU logo in the top left", "tags": "widget", "type":"widget", @@ -480,9 +480,6 @@ {"name":"widnceu.wid.js","url":"widget.js"} ] }, - - - { "id": "sclock", "name": "Simple Clock", "icon": "clock-simple.png", @@ -704,7 +701,7 @@ { "id": "widclk", "name": "Digital clock widget", "icon": "widget.png", - "version":"0.01", + "version":"0.02", "description": "A simple digital clock widget", "tags": "widget,clock", "type":"widget", @@ -715,7 +712,7 @@ { "id": "widpedom", "name": "Pedometer widget", "icon": "widget.png", - "version":"0.06", + "version":"0.07", "description": "Daily pedometer widget", "tags": "widget", "type":"widget", @@ -804,7 +801,7 @@ { "id": "widid", "name": "Bluetooth ID Widget", "icon": "widget.png", - "version":"0.01", + "version":"0.02", "description": "Display the last two tuple of your Bangle.js address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", "tags": "widget", "type":"widget", diff --git a/apps/_example_widget/widget.js b/apps/_example_widget/widget.js index 9ee9bfee8..3893e3096 100644 --- a/apps/_example_widget/widget.js +++ b/apps/_example_widget/widget.js @@ -1,17 +1,16 @@ /* run widgets in their own function scope so they don't interfere with currently-running apps */ (() => { - // add the width - var xpos = WIDGETPOS.tr-24;/**/; - WIDGETPOS.tr-= 28;/* the widget width plus some extra pixel to keep distance to others */; - - // draw your widget at xpos function draw() { g.reset(); // reset the graphics context to defaults (color/font/etc) // add your code + g.drawString("X", this.x, this.y); } // add your widget - WIDGETS["mywidget"]={draw:draw}; - + WIDGETS["mywidget"]={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: 28, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout + draw:draw // called to draw the widget + }; })() diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 8cf79a91d..67feb024f 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Fix issues with alarm scheduling 0.03: More alarm scheduling issues +0.04: Tweaks for variable size widget system diff --git a/apps/alarm/widget.js b/apps/alarm/widget.js index 02d412270..dbe91b3dd 100644 --- a/apps/alarm/widget.js +++ b/apps/alarm/widget.js @@ -1,17 +1,11 @@ (() => { var alarms = require('Storage').readJSON('alarm.json',1)||[]; alarms = alarms.filter(alarm=>alarm.on); - if (!alarms.length) return; + if (!alarms.length) return; // no alarms, no widget! delete alarms; - // add the width - var xpos = WIDGETPOS.tl; - WIDGETPOS.tl += 24;/* the widget width plus some extra pixel to keep distance to others */; - - // draw your widget at xpos - // add the widget - WIDGETS["alarm"]={draw:function() { + WIDGETS["alarm"]={area:"tl",width:24,draw:function() { g.setColor(-1); - g.drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),xpos,0); + g.drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); }}; })() diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog index 3180266ad..28789ec04 100644 --- a/apps/gbridge/ChangeLog +++ b/apps/gbridge/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial version 0.02: Increase contrast (darker notification background, white text) 0.03: Gadgetbridge widget now shows connection state +0.04: Tweaks for variable size widget system diff --git a/apps/gbridge/Changelog b/apps/gbridge/Changelog new file mode 100644 index 000000000..28789ec04 --- /dev/null +++ b/apps/gbridge/Changelog @@ -0,0 +1,4 @@ +0.01: Initial version +0.02: Increase contrast (darker notification background, white text) +0.03: Gadgetbridge widget now shows connection state +0.04: Tweaks for variable size widget system diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index 5eb4f70d4..a787d7e0b 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -109,19 +109,17 @@ function draw() { g.setColor(-1); if (NRF.getSecurityStatus().connected) - g.drawImage(require("heatshrink").decompress(atob("i0WwgHExAABCIwJCBYwJEBYkIBQ2ACgvzCwoECx/z/AKDD4WD+YLBEIYKCx//+cvnAKCBwU/mc4/8/HYv//Ev+Y4EEAePn43DBQkzn4rCEIoABBIwKHO4cjmczK42I6mqlqEEBQeIBQaDED4IgDUhi6KaBbmIA==")),xpos+1,1); + g.drawImage(require("heatshrink").decompress(atob("i0WwgHExAABCIwJCBYwJEBYkIBQ2ACgvzCwoECx/z/AKDD4WD+YLBEIYKCx//+cvnAKCBwU/mc4/8/HYv//Ev+Y4EEAePn43DBQkzn4rCEIoABBIwKHO4cjmczK42I6mqlqEEBQeIBQaDED4IgDUhi6KaBbmIA==")),this.x+1,this.y+1); else - g.drawImage(require("heatshrink").decompress(atob("i0WwQFC1WgAgYFDAgIFClQFCwEK1W/AoIPB1f+CAMq1f7/WqwQPB/fq1Gq1/+/4dC/2/CAIaB/YbBAAO///qAoX/B4QbBDQQ7BDQQrBAAWoIIIACIIIVC0ECB4cACAZiBAoRtCAoIDBA")),xpos+1,1); + g.drawImage(require("heatshrink").decompress(atob("i0WwQFC1WgAgYFDAgIFClQFCwEK1W/AoIPB1f+CAMq1f7/WqwQPB/fq1Gq1/+/4dC/2/CAIaB/YbBAAO///qAoX/B4QbBDQQ7BDQQrBAAWoIIIACIIIVC0ECB4cACAZiBAoRtCAoIDBA")),this.x+1,this.y+1); } function changed() { - draw(); + WIDGETS["gbridgew"].draw(); g.flip();// turns screen on } NRF.on('connected',changed); NRF.on('disconnected',changed); -var xpos = WIDGETPOS.tl; -WIDGETPOS.tl+=24; -WIDGETS["gbridgew"]={draw:draw}; +WIDGETS["gbridgew"]={area:"tl",width:24,draw:draw}; })(); diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 668ce1991..0f31ef93d 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fix GPS time logging 0.03: Fix GPS time display in gpsrec app 0.04: Properly Fix GPS time display in gpsrec app +0.05: Tweaks for variable size widget system diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js index 5c120dcbb..c55c650c5 100644 --- a/apps/gpsrec/widget.js +++ b/apps/gpsrec/widget.js @@ -1,38 +1,29 @@ (() => { - // add the width - var xpos = WIDGETPOS.tl; - WIDGETPOS.tl += 24;/* the widget width plus some extra pixel to keep distance to others */; var settings = {}; var hasFix = false; var fixToggle = false; // toggles once for each reading var gpsTrack; // file for GPS track var periodCtr = 0; - // draw your widget at xpos + // draw your widget function draw() { + if (!settings.recording) return; g.reset(); g.setFont("4x6"); g.setFontAlign(0,0); - g.clearRect(xpos,0,xpos+23,23); - - if (!settings.recording) { - g.setColor("#606060"); + g.clearRect(this.x,this.y,this.x+23,this.y+23); + g.setColor("#ff0000"); + if (hasFix) { + if (fixToggle) { + g.fillCircle(this.x+11,this.y+11,9); + g.setColor("#000000"); + } else + g.drawCircle(this.x+11,this.y+11,9); } else { - g.setColor("#ff0000"); - if (hasFix) { - if (fixToggle) { - g.fillCircle(xpos+11,11,9); - g.setColor("#000000"); - } else - g.drawCircle(xpos+11,11,9); - } else { - g.setColor(fixToggle ? "#ff0000" : "#7f0000"); - g.drawString("NO",xpos+12,5); - g.drawString("FIX",xpos+12,19); - } + g.drawString("NO",this.x+12,this.y+5); + g.drawString("FIX",this.x+12,this.y+19); } - g.drawString("GPS",xpos+12,12); - g.setColor(-1); // change color back to be nice to other apps + g.drawString("GPS",this.x+12,this.y+12); } function onGPS(fix) { @@ -53,7 +44,7 @@ } } - // Called by the GPS app to reload settings and decide what's + // Called by the GPS app to reload settings and decide what to do function reload() { settings = require("Storage").readJSON("gpsrec.json",1)||{}; settings.period = settings.period||1; @@ -61,17 +52,22 @@ Bangle.removeListener('GPS',onGPS); if (settings.recording) { + WIDGETS["gpsrec"].width = 24; Bangle.on('GPS',onGPS); Bangle.setGPSPower(1); var n = settings.file.toString(36); gpsTrack = require("Storage").open(".gpsrc"+n,"a"); } else { + WIDGETS["gpsrec"].width = 0; Bangle.setGPSPower(0); gpsTrack = undefined; } - draw(); } - reload(); // add the widget - WIDGETS["gpsrec"]={draw:draw,reload:reload}; + WIDGETS["gpsrec"]={area:"tl",width:24,draw:draw,reload:function() { + reload(); + Bangle.drawWidgets(); // relayout all widgets + }}; + // load settings, set correct widget width + reload(); })() diff --git a/apps/torch/widget.js b/apps/torch/widget.js index c17d203e1..e3d1ea22f 100644 --- a/apps/torch/widget.js +++ b/apps/torch/widget.js @@ -2,6 +2,8 @@ var clickTimes = []; var CLICK_COUNT = 4; // number of taps var CLICK_PERIOD = 1; // second +// we don't actually create/draw a widget here at all... + Bangle.on("lcdPower",function(on) { // First click (that turns LCD on) isn't given to // setWatch, so handle it here diff --git a/apps/widbat/ChangeLog b/apps/widbat/ChangeLog index ba01ef944..b19144b47 100644 --- a/apps/widbat/ChangeLog +++ b/apps/widbat/ChangeLog @@ -1 +1,2 @@ 0.02: Now refresh battery monitor every minute if LCD on +0.03: Tweaks for variable size widget system diff --git a/apps/widbat/widget.js b/apps/widbat/widget.js index d6f277b50..c209821cc 100644 --- a/apps/widbat/widget.js +++ b/apps/widbat/widget.js @@ -1,17 +1,15 @@ (function(){ -var img_charge = E.toArrayBuffer(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg")); var CHARGING = 0x07E0; -var xpos = WIDGETPOS.tr-64; -WIDGETPOS.tr-=68; +function setWidth() { + WIDGETS["bat"].width = 40 + (Bangle.isCharging()?16:0); +} function draw() { - var s = 63; - var x = xpos, y = 0; - g.clearRect(x,y,x+s,y+23); + var s = 39; + var x = this.x, y = this.y; if (Bangle.isCharging()) { - g.setColor(CHARGING).drawImage(img_charge,x,y); + g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); x+=16; - s-=16; } g.setColor(-1); g.fillRect(x,y+2,x+s-4,y+21); @@ -20,7 +18,12 @@ function draw() { g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17); g.setColor(-1); } -Bangle.on('charging',function(charging) { draw(); g.flip(); if(charging)Bangle.buzz(); }); +Bangle.on('charging',function(charging) { + if(charging) Bangle.buzz(); + setWidth(); + Bangle.drawWidgets(); // relayout widgets + g.flip(); +}); var batteryInterval; Bangle.on('lcdPower', function(on) { if (on) { @@ -35,5 +38,6 @@ Bangle.on('lcdPower', function(on) { } } }); -WIDGETS["battery"]={draw:draw}; +WIDGETS["bat"]={area:"tr",width:40,draw:draw}; +setWidth(); })() diff --git a/apps/widbt/ChangeLog b/apps/widbt/ChangeLog new file mode 100644 index 000000000..1a85a6b12 --- /dev/null +++ b/apps/widbt/ChangeLog @@ -0,0 +1 @@ +0.02: Tweaks for variable size widget system diff --git a/apps/widbt/widget.js b/apps/widbt/widget.js index c4074a797..0ffd0dd4c 100644 --- a/apps/widbt/widget.js +++ b/apps/widbt/widget.js @@ -1,16 +1,13 @@ (function(){ var img_bt = E.toArrayBuffer(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==")); -var xpos = WIDGETPOS.tr-24; -WIDGETPOS.tr-=24; function draw() { - var x = xpos, y = 0; + g.reset(); if (NRF.getSecurityStatus().connected) g.setColor(0,0.5,1); else g.setColor(0.3,0.3,0.3); - g.drawImage(img_bt,10+x,2+y); - g.setColor(1,1,1); + g.drawImage(img_bt,10+this.x,2+this.y); } function changed() { draw(); @@ -18,5 +15,5 @@ function changed() { } NRF.on('connected',changed); NRF.on('disconnected',changed); -WIDGETS["bluetooth"]={draw:draw}; +WIDGETS["bluetooth"]={area:"tr",width:24,draw:draw}; })() diff --git a/apps/widclk/ChangeLog b/apps/widclk/ChangeLog new file mode 100644 index 000000000..ba01ef944 --- /dev/null +++ b/apps/widclk/ChangeLog @@ -0,0 +1 @@ +0.02: Now refresh battery monitor every minute if LCD on diff --git a/apps/widclk/widget.js b/apps/widclk/widget.js index f73f8688b..a1129328f 100644 --- a/apps/widclk/widget.js +++ b/apps/widclk/widget.js @@ -1,39 +1,27 @@ (() => { let intervalRef = null; var width = 5 * 6*2 - var xpos = WIDGETPOS.tr - width; - WIDGETPOS.tr -= (width + 2); - + function draw() { - // Widget (0,0,239,23) - let date = new Date(); - var dateArray = date.toString().split(" "); - g.setColor(1,1,1); - g.setFont("6x8", 2); - g.setFontAlign(-1, 0); - g.drawString(dateArray[4].substr(0, 5), xpos, 11, true); // 5 * 6*2 = 60 - g.flip(); + g.reset().setFont("6x8", 2).setFontAlign(-1, 0); + var time = require("locale").time(new Date(),1); + g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 } function clearTimers(){ - if(intervalRef) { - clearInterval(intervalRef); - intervalRef = null; - } + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = null; + } } function startTimers(){ - if(intervalRef) clearTimers(); - intervalRef = setInterval(draw, 60*1000); - draw(); + intervalRef = setInterval(draw, 60*1000); + draw(); } Bangle.on('lcdPower', (on) => { - if (on) { - // startTimers(); // comment out as it is called by app anyway - } else { - clearTimers(); - } + clearTimers(); + if (on) startTimers(); }); - // add your widget - WIDGETS["wdclk"]={draw:startTimers}; - -})() \ No newline at end of file + WIDGETS["wdclk"]={area:"tr",width:width,draw:draw}; + if (Bangle.isLCDOn) intervalRef = setInterval(draw, 60*1000); +})() diff --git a/apps/widhrm/ChangeLog b/apps/widhrm/ChangeLog index 4c21f3ace..4152a8406 100644 --- a/apps/widhrm/ChangeLog +++ b/apps/widhrm/ChangeLog @@ -1 +1,2 @@ 0.01: New Widget! +0.02: Tweaks for variable size widget system diff --git a/apps/widhrm/widget.js b/apps/widhrm/widget.js index 3a1d5da09..f0af08f46 100644 --- a/apps/widhrm/widget.js +++ b/apps/widhrm/widget.js @@ -1,16 +1,14 @@ (() => { - var xpos = WIDGETPOS.tl; - var width = 24; - WIDGETPOS.tl += width+2; var currentBPM = undefined; var lastBPM = undefined; var firstBPM = true; // first reading since sensor turned on function draw() { + var width = 24; g.reset(); g.setFont("6x8", 1); g.setFontAlign(0, 0); - g.clearRect(xpos,15,xpos+width,24); // erase background + g.clearRect(this.x,this.y+15,this.x+width,this.y+23); // erase background var bpm = currentBPM, isCurrent = true; if (bpm===undefined) { bpm = lastBPM; @@ -19,9 +17,9 @@ if (bpm===undefined) bpm = "--"; g.setColor(isCurrent ? "#ffffff" : "#808080"); - g.drawString(bpm, xpos+width/2, 19); + g.drawString(bpm, this.x+width/2, this.y+19); g.setColor(isCurrent ? "#ff0033" : "#808080"); - g.drawImage(atob("CgoCAAABpaQ//9v//r//5//9L//A/+AC+AAFAA=="),xpos+(width-10)/2,1); + g.drawImage(atob("CgoCAAABpaQ//9v//r//5//9L//A/+AC+AAFAA=="),this.x+(width-10)/2,this.y+1); g.setColor(-1); } @@ -49,5 +47,5 @@ Bangle.setHRMPower(Bangle.isLCDOn()); // add your widget - WIDGETS["hrm"]={draw:draw}; + WIDGETS["hrm"]={area:"tl",width:24,draw:draw}; })(); diff --git a/apps/widid/ChangeLog b/apps/widid/ChangeLog index 2b3617f98..4152a8406 100644 --- a/apps/widid/ChangeLog +++ b/apps/widid/ChangeLog @@ -1 +1,2 @@ -0.01: New Widget! \ No newline at end of file +0.01: New Widget! +0.02: Tweaks for variable size widget system diff --git a/apps/widid/widget.js b/apps/widid/widget.js index 84f5fe5f0..efbfdfd19 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -1,16 +1,12 @@ /* jshint esversion: 6 */ (() => { - var xpos = WIDGETPOS.tr - 16; - WIDGETPOS.tr -= 16; - id = NRF.getAddress().split(":"); + var id = NRF.getAddress().substr().substr(12).split(":"); // draw your widget at xpos function draw() { - var x = xpos, - y = 0; g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); - g.drawString(id[4], x, 0, true); - g.drawString(id[5], x, 10, true); + g.drawString(id[0], this.x+2, this.y+4, true); + g.drawString(id[1], this.x+2, this.y+14, true); } - WIDGETS["widid"] = { draw: draw }; + WIDGETS["widid"] = { area:"tr", width:16, draw: draw }; })(); diff --git a/apps/widnceu/ChangeLog b/apps/widnceu/ChangeLog new file mode 100644 index 000000000..4152a8406 --- /dev/null +++ b/apps/widnceu/ChangeLog @@ -0,0 +1,2 @@ +0.01: New Widget! +0.02: Tweaks for variable size widget system diff --git a/apps/widnceu/widget.js b/apps/widnceu/widget.js index fa0e11cd1..44f8acdb4 100644 --- a/apps/widnceu/widget.js +++ b/apps/widnceu/widget.js @@ -1,13 +1,5 @@ -(function(){ -var img = E.toArrayBuffer(atob("SxgCAAAAAAAAAAAAAAAAAAAAAAAAALwDwH/gD/0B//Af+AAD4C8f/wL8Dwf/8H//C//C//AAD9C8f/wL9Dw//+H//i4AD0AH8D/C8fAAL/Dz///H//y8ALgAf/D/i8fAALrzz///H//2//PAAv/Dz28f/gLz7z///H//29VPQAv/Dx+8fqQLw/y///H//y4ALwAP/Dwv8fAALwfw//9H//i+qD8FC0DwP8fAALwPwP/4H/+C//A//AADwD8fAAAAAAC/QD+gAAAAL4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGqooBkD+AP0fgvgAAAAAAAAAAL/88C4NBw0NBjQcAAAAAAAAAALQA8C4AAyQDBjAJAAAAAAAAAALQA8C4AAzACBjAKAAAAAAAAAAL/88C4ABTACRjQbAAAAAAAAAAL/48C4AHDACRgvjAAAAAAAAAALQA8C4AcDACBgACAAAAAAAAAALQA+D0BwCQDBgANAAAAAAAAAAL/8P/wHAA0NBgAoAAAAAAAAAAGqoC+AP/0HgAQuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); -var xpos = WIDGETPOS.tl; -WIDGETPOS.tl+=75; - - -WIDGETS["nceu"]={draw:()=>{ - var x = xpos, y = 0; - g.setColor(0.17,0.2,0.5); - g.drawImage(img,x,y); +WIDGETS["nceu"]={area:"tl",width:75,draw:function(){ + g.reset().setColor(0.17,0.2,0.5); + g.drawImage(atob("SxgCAAAAAAAAAAAAAAAAAAAAAAAAALwDwH/gD/0B//Af+AAD4C8f/wL8Dwf/8H//C//C//AAD9C8f/wL9Dw//+H//i4AD0AH8D/C8fAAL/Dz///H//y8ALgAf/D/i8fAALrzz///H//2//PAAv/Dz28f/gLz7z///H//29VPQAv/Dx+8fqQLw/y///H//y4ALwAP/Dwv8fAALwfw//9H//i+qD8FC0DwP8fAALwPwP/4H/+C//A//AADwD8fAAAAAAC/QD+gAAAAL4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGqooBkD+AP0fgvgAAAAAAAAAAL/88C4NBw0NBjQcAAAAAAAAAALQA8C4AAyQDBjAJAAAAAAAAAALQA8C4AAzACBjAKAAAAAAAAAAL/88C4ABTACRjQbAAAAAAAAAAL/48C4AHDACRgvjAAAAAAAAAALQA8C4AcDACBgACAAAAAAAAAALQA+D0BwCQDBgANAAAAAAAAAAL/8P/wHAA0NBgAoAAAAAAAAAAGqoC+AP/0HgAQuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),this.x,this.y); g.setColor(1,1,1); }}; -})() diff --git a/apps/widpedom/ChangeLog b/apps/widpedom/ChangeLog index b6907b9c7..b0b0753fd 100644 --- a/apps/widpedom/ChangeLog +++ b/apps/widpedom/ChangeLog @@ -3,3 +3,4 @@ 0.04: Fix pedometer reload when going back to clock app 0.05: Add foot icon, use tidier font, and move to the left of the screen 0.06: Fix widget position increment +0.07: Tweaks for variable size widget system diff --git a/apps/widpedom/widget.js b/apps/widpedom/widget.js index e827702c9..6ab837c81 100644 --- a/apps/widpedom/widget.js +++ b/apps/widpedom/widget.js @@ -1,17 +1,11 @@ (() => { const PEDOMFILE = "wpedom.json"; - // add the width - // WIDGETPOS.tr is originally 208 without any widgets - var xpos = WIDGETPOS.tl; - var width = 24; - WIDGETPOS.tl += (width + 2); - let lastUpdate = new Date(); let stp_today = 0; - // draw your widget at xpos + // draw your widget function draw() { - // Widget (0,0,239,23) + var width = 24; if (stp_today > 99999){ stp_today = stp_today % 100000; // cap to five digits + comma = 6 characters } @@ -24,9 +18,9 @@ g.setFont("6x8", 1); } g.setFontAlign(0, 0); // align to x: center, y: center - g.clearRect(xpos,15,xpos+width,24); // erase background - g.drawString(stps, xpos+width/2, 19); - g.drawImage(atob("CgoCLguH9f2/7+v6/79f56CtAAAD9fw/n8Hx9A=="),xpos+(width-10)/2,2); + g.clearRect(this.x,this.y+15,this.x+width,this.y+23); // erase background + g.drawString(stps, this.x+width/2, this.y+19); + g.drawImage(atob("CgoCLguH9f2/7+v6/79f56CtAAAD9fw/n8Hx9A=="),this.x+(width-10)/2,this.y+2); } Bangle.on('step', (up) => { @@ -55,7 +49,7 @@ }); // add your widget - WIDGETS["wpedom"]={draw:draw}; + WIDGETS["wpedom"]={area:"tl",width:26,draw:draw}; // Load data at startup let pedomData = require("Storage").readJSON(PEDOMFILE,1); if (pedomData) { From f1ba5d8284c8895a4190e93f2f2d4a602026a54a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 15:25:29 +0000 Subject: [PATCH 29/55] pixel update --- apps.json | 2 +- apps/about/ChangeLog | 1 + apps/about/app.js | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 96536940d..88a4cb735 100644 --- a/apps.json +++ b/apps.json @@ -28,7 +28,7 @@ { "id": "about", "name": "About", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "tags": "tool,system", "allow_emulator":true, diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index fe1d0f3e0..ccf7cf46d 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Update version checker for new filename type +0.03: Actual pixels as of 5 Mar 2020 diff --git a/apps/about/app.js b/apps/about/app.js index 773d960ba..559d77052 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -28,6 +28,6 @@ g.setFontAlign(0,-1); g.drawString(NRF.getAddress(),120,232); g.flip(); -// Pixel chooser 'test' image -g.drawImage(require("heatshrink").decompress(atob("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")),0,135); +// Pixel chooser image +g.drawImage(require("heatshrink").decompress(atob("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")),0,135); g.flip(); From 589d18b4fc08ed1726572ddebb04b41c66eda963 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Mar 2020 15:34:37 +0000 Subject: [PATCH 30/55] Remove info file when removing an app (fix #113) --- comms.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/comms.js b/comms.js index 691a60ca7..4a0022aa4 100644 --- a/comms.js +++ b/comms.js @@ -60,7 +60,8 @@ getInstalledApps : () => { }); }, removeApp : app => { // expects an app structure - var cmds = app.storage.map(file=>{ + var storage = [{name:app.id+".info"}].concat(app.storage); + var cmds = storage.map(file=>{ return `\x10require("Storage").erase(${toJS(file.name)});\n`; }).join(""); console.log("removeApp", cmds); From 048a9bb64f2022925ecd96a7da6bb410f99ec56e Mon Sep 17 00:00:00 2001 From: sebi Date: Fri, 6 Mar 2020 17:09:45 +0100 Subject: [PATCH 31/55] Changing name from clck3x2 to clock2x3, setting clock type, simplifying app code --- apps.json | 15 ++++++++------- apps/{clck3x2 => clock2x3}/ChangeLog | 1 + .../clock3x2.js => clock2x3/clock2x3-app.js} | 3 +-- .../clock2x3-icon.js} | 0 .../clock3x2.png => clock2x3/clock2x3.png} | Bin 5 files changed, 10 insertions(+), 9 deletions(-) rename apps/{clck3x2 => clock2x3}/ChangeLog (73%) rename apps/{clck3x2/clock3x2.js => clock2x3/clock2x3-app.js} (95%) rename apps/{clck3x2/clock3x2-icon.js => clock2x3/clock2x3-icon.js} (100%) rename apps/{clck3x2/clock3x2.png => clock2x3/clock2x3.png} (100%) diff --git a/apps.json b/apps.json index 88a4cb735..1cc65b6f9 100644 --- a/apps.json +++ b/apps.json @@ -143,16 +143,17 @@ {"name":"aclock.img","url":"clock-analog-icon.js","evaluate":true} ] }, - { "id": "clck3x2", - "name": "3x2 Pixel Clock", - "icon": "clock3x2.png", - "version":"0.03", - "description": "This is a simple clock using minimalistic 3x2 pixel numerical digits", + { "id": "clock2x3", + "name": "2x3 Pixel Clock", + "icon": "clock2x3.png", + "version":"0.04", + "description": "This is a simple clock using minimalist 2x3 pixel numerical digits", "tags": "clock", + "type": "clock", "allow_emulator":true, "storage": [ - {"name":"clck3x2.app.js","url":"clock3x2.js"}, - {"name":"clck3x2.img","url":"clock3x2-icon.js","evaluate":true} + {"name":"clock2x3.app.js","url":"clock2x3-app.js"}, + {"name":"clock2x3.img","url":"clock2x3-icon.js","evaluate":true} ] }, { "id": "trex", diff --git a/apps/clck3x2/ChangeLog b/apps/clock2x3/ChangeLog similarity index 73% rename from apps/clck3x2/ChangeLog rename to apps/clock2x3/ChangeLog index c10571cae..88876affa 100644 --- a/apps/clck3x2/ChangeLog +++ b/apps/clock2x3/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Added 'reset' so we don't get the font color from widgets +0.04: Changed name from clck3x2 to clock2x3 diff --git a/apps/clck3x2/clock3x2.js b/apps/clock2x3/clock2x3-app.js similarity index 95% rename from apps/clck3x2/clock3x2.js rename to apps/clock2x3/clock2x3-app.js index 49c18b747..511a7662b 100644 --- a/apps/clck3x2/clock3x2.js +++ b/apps/clock2x3/clock2x3-app.js @@ -76,8 +76,7 @@ function drawTime() { } let t = d.getSeconds()*1000 + d.getMilliseconds(); - let delta = (60000 - t) % 60000; // time till next minute - idTimeout = setTimeout(drawTime, delta); + idTimeout = setTimeout(drawTime, 60000 - t); // time till next minute } // special function to handle display switch on diff --git a/apps/clck3x2/clock3x2-icon.js b/apps/clock2x3/clock2x3-icon.js similarity index 100% rename from apps/clck3x2/clock3x2-icon.js rename to apps/clock2x3/clock2x3-icon.js diff --git a/apps/clck3x2/clock3x2.png b/apps/clock2x3/clock2x3.png similarity index 100% rename from apps/clck3x2/clock3x2.png rename to apps/clock2x3/clock2x3.png From f77816a1a681192af249f61637ff638d9a552d78 Mon Sep 17 00:00:00 2001 From: sebi Date: Sun, 8 Mar 2020 11:39:13 +0100 Subject: [PATCH 32/55] Adjusting french locales --- apps/locale/locales.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 006c435e7..71818d84c 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -130,8 +130,8 @@ var locales = { temperature: "°C", ampm: {0:"",1:""}, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 // 01/03/2020 - abmonth: "anv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", + datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 // 01/03/2020 + abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", abday: "dim,lun,mar,mer,jeu,ven,sam", day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", From b4a24b34d02f9057f240daa9ba93f0543d67c7b7 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 09:54:54 +0000 Subject: [PATCH 33/55] 0.06: Ensure widget update itself (fix #118) and change to using icons --- apps.json | 2 +- apps/gpsrec/ChangeLog | 1 + apps/gpsrec/widget.js | 20 +++++++------------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/apps.json b/apps.json index 1cc65b6f9..b078ea6ae 100644 --- a/apps.json +++ b/apps.json @@ -250,7 +250,7 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.05", + "version":"0.06", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 0f31ef93d..9a47bdd9a 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -3,3 +3,4 @@ 0.03: Fix GPS time display in gpsrec app 0.04: Properly Fix GPS time display in gpsrec app 0.05: Tweaks for variable size widget system +0.06: Ensure widget update itself (fix #118) and change to using icons diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js index c55c650c5..2ad0cfc8c 100644 --- a/apps/gpsrec/widget.js +++ b/apps/gpsrec/widget.js @@ -9,27 +9,21 @@ function draw() { if (!settings.recording) return; g.reset(); - g.setFont("4x6"); - g.setFontAlign(0,0); - g.clearRect(this.x,this.y,this.x+23,this.y+23); - g.setColor("#ff0000"); + g.drawImage(atob("GBgCAAAAAAAAAAQAAAAAAD8AAAAAAP/AAAAAAP/wAAAAAH/8C9AAAB/8L/QAAAfwv/wAAAHS//wAAAAL//gAAAAf/+AAAAAf/4AAAAL//gAAAAD/+DwAAAB/Uf8AAAAfA//AAAACAf/wAAAAAH/0AAAAAB/wAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),this.x,this.y); if (hasFix) { - if (fixToggle) { - g.fillCircle(this.x+11,this.y+11,9); - g.setColor("#000000"); - } else - g.drawCircle(this.x+11,this.y+11,9); + g.setColor("#FF0000"); + g.drawImage(fixToggle ? atob("CgoCAAAAA0AAOAAD5AAPwAAAAAAAAAAAAAAAAA==") : atob("CgoCAAABw0AcOAHj5A8PwHwAAvgAB/wABUAAAA=="),this.x,this.y+14); } else { - g.drawString("NO",this.x+12,this.y+5); - g.drawString("FIX",this.x+12,this.y+19); + g.setColor("#0000FF"); + if (fixToggle) + g.setFont("6x8").drawString("?",this.x,this.y+14); } - g.drawString("GPS",this.x+12,this.y+12); } function onGPS(fix) { hasFix = fix.fix; fixToggle = !fixToggle; - draw(); + WIDGETS["gpsrec"].draw(); if (hasFix) { periodCtr--; if (periodCtr<=0) { From 0ebc1c3a50f3d212fbe164758461bd9feea9c775 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 12:28:04 +0000 Subject: [PATCH 34/55] Allow tracks numbered>10 to be downloaded (fix #117) --- apps/gpsrec/interface.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gpsrec/interface.html b/apps/gpsrec/interface.html index d86800923..b87d75b3c 100644 --- a/apps/gpsrec/interface.html +++ b/apps/gpsrec/interface.html @@ -176,7 +176,7 @@ function getTrackList() { for (var i=0;i { var button = event.currentTarget; - var trackid = button.getAttribute("trackid"); + var trackid = parseInt(button.getAttribute("trackid")); var task = button.getAttribute("task"); if (task=="delete") { showModal("Deleting Track..."); From 47575f0f809ced9eff24e6a958f0f505324012d0 Mon Sep 17 00:00:00 2001 From: sebi Date: Mon, 9 Mar 2020 13:24:38 +0100 Subject: [PATCH 35/55] New heart rate recorder app --- apps.json | 14 ++++ apps/heart/ChangeLog | 2 + apps/heart/app-icon.js | 1 + apps/heart/app-settings.json | 4 + apps/heart/app.js | 100 +++++++++++++++++++++++ apps/heart/app.png | Bin 0 -> 883 bytes apps/heart/interface.html | 149 +++++++++++++++++++++++++++++++++++ apps/heart/widget.js | 50 ++++++++++++ 8 files changed, 320 insertions(+) create mode 100644 apps/heart/ChangeLog create mode 100644 apps/heart/app-icon.js create mode 100644 apps/heart/app-settings.json create mode 100644 apps/heart/app.js create mode 100644 apps/heart/app.png create mode 100644 apps/heart/interface.html create mode 100644 apps/heart/widget.js diff --git a/apps.json b/apps.json index b078ea6ae..eb2644df9 100644 --- a/apps.json +++ b/apps.json @@ -261,6 +261,20 @@ {"name":"gpsrec.wid.js","url":"widget.js"} ] }, + { "id": "heart", + "name": "Heart Rate Recorder", + "icon": "app.png", + "version":"0.01", + "interface": "interface.html", + "description": "Application that allows you to record your heart rate. Can run in background", + "tags": "tool,health,widget", + "storage": [ + {"name":"heart.app.js","url":"app.js"}, + {"name":"heart.json","url":"app-settings.json","evaluate":true}, + {"name":"heart.img","url":"app-icon.js","evaluate":true}, + {"name":"heart.wid.js","url":"widget.js"} + ] + }, { "id": "slevel", "name": "Spirit Level", "icon": "spiritlevel.png", diff --git a/apps/heart/ChangeLog b/apps/heart/ChangeLog new file mode 100644 index 000000000..4c4db83bc --- /dev/null +++ b/apps/heart/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! + diff --git a/apps/heart/app-icon.js b/apps/heart/app-icon.js new file mode 100644 index 000000000..a7f67291e --- /dev/null +++ b/apps/heart/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4AWzIAByAHDhIICCpINDDAgIIFpAADBBQuKE4QIIFxgAKC7g9HABSbIBQQXWGxgXEKQxOMC5AhBC66WMC5AuBJ5h3ICoI3LeAwKBBAICBD4TmHC48ACgQCCfxC/HAgYXDL44vFA4YRDAoiOIHAgXFYRAXFBwwIIOw4OGIxKmIC5ylHGAoXIXpBIGLxxIIIx6IJFxwwNCxQwLFxYwLCxgwJFxowJCxwwHFx4wHCyAwFFyIwFCyQYDCygA/AH4AFA")) \ No newline at end of file diff --git a/apps/heart/app-settings.json b/apps/heart/app-settings.json new file mode 100644 index 000000000..d57d970d0 --- /dev/null +++ b/apps/heart/app-settings.json @@ -0,0 +1,4 @@ +{ + "isRecording":false, + "fileNbr":0 +} diff --git a/apps/heart/app.js b/apps/heart/app.js new file mode 100644 index 000000000..366a1068d --- /dev/null +++ b/apps/heart/app.js @@ -0,0 +1,100 @@ +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +var settings = require("Storage").readJSON("heart.json",1)||{}; + +function getFileNbr(n) { + return ".heart"+n.toString(36); +} + +function updateSettings() { + require("Storage").write("heart.json", settings); + if (WIDGETS["heart"]) + WIDGETS["heart"].reload(); +} + +function showMainMenu() { + const mainMenu = { + '': { 'title': 'Heart Recorder' }, + 'RECORD': { + value: !!settings.isRecording, + format: v=>v?"On":"Off", + onchange: v => { + settings.isRecording = v; + updateSettings(); + } + }, + 'File Number': { + value: settings.fileNbr|0, + min: 0, + max: 35, + step: 1, + onchange: v => { + settings.isRecording = false; + settings.fileNbr = v; + updateSettings(); + } + }, + 'View Records': viewRecords, + '< Back': ()=>{load();} + }; + return E.showMenu(mainMenu); +} + +function viewRecords() { + const menu = { + '': { 'title': 'Heart Records' } + }; + var found = false; + for (var n=0;n<36;n++) { + var f = require("Storage").open(getFileNbr(n),"r"); + if (f.readLine()!==undefined) { + menu["Record "+n] = viewRecord.bind(null,n); + found = true; + } + } + if (!found) + menu["No Records Found"] = function(){}; + menu['< Back'] = showMainMenu; + return E.showMenu(menu); +} + +function viewRecord(n) { + const menu = { + '': { 'title': 'Heart Record '+n } + }; + var heartCount = 0; + var heartTime; + var f = require("Storage").open(getFileNbr(n),"r"); + var l = f.readLine(); + if (l!==undefined) { + var c = l.split(","); + heartTime = new Date(c[0]*1000); + } + while (l!==undefined) { + heartCount++; + // TODO: min/max/average of heart rate? + l = f.readLine(); + } + if (heartTime) + menu[" "+heartTime.toString().substr(4,17)] = function(){}; + menu[heartCount+" records"] = function(){}; + // TODO: option to draw it? Just scan through, project using min/max + menu['Erase'] = function() { + E.showPrompt("Delete Record?").then(function(v) { + if (v) { + settings.isRecording = false; + updateSettings(); + var f = require("Storage").open(getFileNbr(n),"r"); + f.erase(); + viewRecords(); + } else + viewRecord(n); + }); + }; + menu['< Back'] = viewRecords; + print(menu); + return E.showMenu(menu); +} + +showMainMenu(); diff --git a/apps/heart/app.png b/apps/heart/app.png new file mode 100644 index 0000000000000000000000000000000000000000..72b2805b860448283e7888c0bbd0c81b1d3866b4 GIT binary patch literal 883 zcmV-(1C0EMP)vd?16wr4LL(MiMb%)I=w9U36cjrl7@9BtqyRPk#v zNN=l*-9E$sdblhlfc1%F)!Bzj4Bn*L+WM-)*fWrt$9p1er}1Ip_&yHfZG4f?cP@qS zV)?VbHn@HuVSL}7uJGKAvjh6Cm551fENwF$!RG-{nEMlWE%+Tvqp$Hewg$X6*Z6*^ zM*K{w_&SW?d5dTNUHpm*gSPhq$1lpOdbf!O@IfQh5nLWzPnh4p?g-lZX_WgsP!xi( z03ORBS&6;akCzo?a12v{gM&ePKaD1XwsE{ra_(1@)zxKj1wM(0|J%ZeOTxZ@;3tbq z+i>=K7N^lOmHr<^gngxWE>`0fMViEB|Mgt)6y-r!i2aP~gZqafj>0qwm*~{JC1$g@ zu}J`MphETwp2M3p&JM&Z=nyt2BEl>XqZJXcGW=8&frn;K7FC zdx}c86TFk*w3&7WbWZ)fL>Oc$Lf*e;Ri#gWf1M$tyXIXmRE_EUd$qmKOgFu3jdMOJWt?QZIhW z5O&zEF@|R?T%pckw`O02mUK2O++_Yk$CTnD$p|BiFv9-~{{eYm*St3QPn-Y%002ov JPDHLkV1n(LqG134 literal 0 HcmV?d00001 diff --git a/apps/heart/interface.html b/apps/heart/interface.html new file mode 100644 index 000000000..7d56e8461 --- /dev/null +++ b/apps/heart/interface.html @@ -0,0 +1,149 @@ + + + + + +
+ + + + + + + diff --git a/apps/heart/widget.js b/apps/heart/widget.js new file mode 100644 index 000000000..7d46aa239 --- /dev/null +++ b/apps/heart/widget.js @@ -0,0 +1,50 @@ +(() => { + var settings = {}; + var hrmToggle = true; // toggles once for each reading + var recFile; // file for heart rate recording + + // draw your widget + function draw() { + if (!settings.isRecording) return; + g.reset(); + g.setFontAlign(0,0); + g.clearRect(this.x,this.y,this.x+23,this.y+23); + g.setColor(hrmToggle?"#ff0000":"#ff8000"); + g.fillCircle(this.x+6,this.y+6,4); // draw heart left circle + g.fillCircle(this.x+16,this.y+6,4); // draw heart right circle + g.fillPoly([this.x+2,this.y+8,this.x+20,this.y+8,this.x+11,this.y+18]); // draw heart bottom triangle + g.setColor(-1); // change color back to be nice to other apps + } + + function onHRM(hrm) { + hrmToggle = !hrmToggle; + WIDGETS["heart"].draw(); + if (recFile) recFile.write([getTime().toFixed(0),hrm.bpm,hrm.confidence].join(",")+"\n"); + } + + // Called by the heart app to reload settings and decide what's + function reload() { + settings = require("Storage").readJSON("heart.json",1)||{}; + settings.fileNbr |= 0; + + Bangle.removeListener('HRM',onHRM); + if (settings.isRecording) { + WIDGETS["heart"].width = 24; + Bangle.on('HRM',onHRM); + Bangle.setHRMPower(1); + var n = settings.fileNbr.toString(36); + recFile = require("Storage").open(".heart"+n,"a"); + } else { + WIDGETS["heart"].width = 0; + Bangle.setHRMPower(0); + recFile = undefined; + } + } + // add the widget + WIDGETS["heart"]={area:"tl",width:24,draw:draw,reload:function() { + reload(); + Bangle.drawWidgets(); // relayout all widgets + }}; + // load settings, set correct widget width + reload(); +})() From 827fadeac0d48752593aae6d06c968148206929e Mon Sep 17 00:00:00 2001 From: sebi Date: Mon, 9 Mar 2020 13:38:28 +0100 Subject: [PATCH 36/55] Allow record numbered>10 to be downloaded (fix #117) --- apps/heart/interface.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/heart/interface.html b/apps/heart/interface.html index 7d56e8461..c2f115564 100644 --- a/apps/heart/interface.html +++ b/apps/heart/interface.html @@ -123,7 +123,7 @@ function getRecordList() { for (var i=0;i { var button = event.currentTarget; - var recordNbr = button.getAttribute("recordNbr"); + var recordNbr = parseInt(button.getAttribute("recordNbr")); var task = button.getAttribute("task"); if (task=="delete") { showModal("Deleting record..."); From 0da0acefd2dab2fc1b5d773e0d9b4eb2cdb09106 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 14:30:56 +0000 Subject: [PATCH 37/55] Tweaks for issues redrawing after variable size widget addition (partial #121) --- apps.json | 10 +++++----- apps/widbat/ChangeLog | 1 + apps/widbat/widget.js | 2 +- apps/widbt/ChangeLog | 1 + apps/widbt/widget.js | 2 +- apps/widclk/ChangeLog | 1 + apps/widclk/widget.js | 2 +- apps/widhrm/ChangeLog | 1 + apps/widhrm/widget.js | 4 ++-- apps/widpedom/ChangeLog | 1 + apps/widpedom/widget.js | 4 ++-- 11 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index b078ea6ae..f55c327fa 100644 --- a/apps.json +++ b/apps.json @@ -286,7 +286,7 @@ { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", - "version":"0.03", + "version":"0.04", "description": "Show the current battery level and charging status in the top right of the clock", "tags": "widget,battery", "type":"widget", @@ -297,7 +297,7 @@ { "id": "widbt", "name": "Bluetooth Widget", "icon": "widget.png", - "version":"0.02", + "version":"0.03", "description": "Show the current Bluetooth connection status in the top right of the clock", "tags": "widget,bluetooth", "type":"widget", @@ -319,7 +319,7 @@ { "id": "widhrm", "name": "Simple Heart Rate widget", "icon": "widget.png", - "version":"0.02", + "version":"0.03", "description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.", "tags": "health,widget", "type": "widget", @@ -702,7 +702,7 @@ { "id": "widclk", "name": "Digital clock widget", "icon": "widget.png", - "version":"0.02", + "version":"0.03", "description": "A simple digital clock widget", "tags": "widget,clock", "type":"widget", @@ -713,7 +713,7 @@ { "id": "widpedom", "name": "Pedometer widget", "icon": "widget.png", - "version":"0.07", + "version":"0.08", "description": "Daily pedometer widget", "tags": "widget", "type":"widget", diff --git a/apps/widbat/ChangeLog b/apps/widbat/ChangeLog index b19144b47..cd9993c02 100644 --- a/apps/widbat/ChangeLog +++ b/apps/widbat/ChangeLog @@ -1,2 +1,3 @@ 0.02: Now refresh battery monitor every minute if LCD on 0.03: Tweaks for variable size widget system +0.04: Ensure redrawing works with variable size widget system diff --git a/apps/widbat/widget.js b/apps/widbat/widget.js index c209821cc..2f1f29802 100644 --- a/apps/widbat/widget.js +++ b/apps/widbat/widget.js @@ -27,7 +27,7 @@ Bangle.on('charging',function(charging) { var batteryInterval; Bangle.on('lcdPower', function(on) { if (on) { - draw(); + WIDGETS["bat"].draw(); // refresh once a minute if LCD on if (!batteryInterval) batteryInterval = setInterval(draw, 60000); diff --git a/apps/widbt/ChangeLog b/apps/widbt/ChangeLog index 1a85a6b12..c268d6df0 100644 --- a/apps/widbt/ChangeLog +++ b/apps/widbt/ChangeLog @@ -1 +1,2 @@ 0.02: Tweaks for variable size widget system +0.03: Ensure redrawing works with variable size widget system diff --git a/apps/widbt/widget.js b/apps/widbt/widget.js index 0ffd0dd4c..8e96a395d 100644 --- a/apps/widbt/widget.js +++ b/apps/widbt/widget.js @@ -10,7 +10,7 @@ function draw() { g.drawImage(img_bt,10+this.x,2+this.y); } function changed() { - draw(); + WIDGETS["bluetooth"].draw(); g.flip();// turns screen on } NRF.on('connected',changed); diff --git a/apps/widclk/ChangeLog b/apps/widclk/ChangeLog index ba01ef944..5370129cc 100644 --- a/apps/widclk/ChangeLog +++ b/apps/widclk/ChangeLog @@ -1 +1,2 @@ 0.02: Now refresh battery monitor every minute if LCD on +0.03: Ensure redrawing works with variable size widget system diff --git a/apps/widclk/widget.js b/apps/widclk/widget.js index a1129328f..1d5df36b2 100644 --- a/apps/widclk/widget.js +++ b/apps/widclk/widget.js @@ -15,7 +15,7 @@ } function startTimers(){ intervalRef = setInterval(draw, 60*1000); - draw(); + WIDGETS["wdclk"].draw(); } Bangle.on('lcdPower', (on) => { clearTimers(); diff --git a/apps/widhrm/ChangeLog b/apps/widhrm/ChangeLog index 4152a8406..d6c076227 100644 --- a/apps/widhrm/ChangeLog +++ b/apps/widhrm/ChangeLog @@ -1,2 +1,3 @@ 0.01: New Widget! 0.02: Tweaks for variable size widget system +0.03: Ensure redrawing works with variable size widget system diff --git a/apps/widhrm/widget.js b/apps/widhrm/widget.js index f0af08f46..ca66f8b44 100644 --- a/apps/widhrm/widget.js +++ b/apps/widhrm/widget.js @@ -29,7 +29,7 @@ Bangle.setHRMPower(1); firstBPM = true; currentBPM = undefined; - draw(); + WIDGETS["hrm"].draw(); } else { Bangle.setHRMPower(0); } @@ -42,7 +42,7 @@ currentBPM = d.bpm; lastBPM = currentBPM; } - draw(); + WIDGETS["hrm"].draw(); }); Bangle.setHRMPower(Bangle.isLCDOn()); diff --git a/apps/widpedom/ChangeLog b/apps/widpedom/ChangeLog index b0b0753fd..980494acb 100644 --- a/apps/widpedom/ChangeLog +++ b/apps/widpedom/ChangeLog @@ -4,3 +4,4 @@ 0.05: Add foot icon, use tidier font, and move to the left of the screen 0.06: Fix widget position increment 0.07: Tweaks for variable size widget system +0.08: Ensure redrawing works with variable size widget system diff --git a/apps/widpedom/widget.js b/apps/widpedom/widget.js index 6ab837c81..1cc14fc2c 100644 --- a/apps/widpedom/widget.js +++ b/apps/widpedom/widget.js @@ -33,11 +33,11 @@ } lastUpdate = date; //console.log("up: " + up + " stp: " + stp_today + " " + date.toString()); - if (Bangle.isLCDOn()) draw(); + if (Bangle.isLCDOn()) WIDGETS["wpedom"].draw(); }); // redraw when the LCD turns on Bangle.on('lcdPower', function(on) { - if (on) draw(); + if (on) WIDGETS["wpedom"].draw(); }); // When unloading, save state E.on('kill', () => { From 4e19affb7677a83ca5a4b9151b8b9d9d464055b1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 14:31:29 +0000 Subject: [PATCH 38/55] Fix for errors from Bangle.js when resetting a device that may already have code in `.boot0`/etc --- comms.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/comms.js b/comms.js index 4a0022aa4..de2c328b3 100644 --- a/comms.js +++ b/comms.js @@ -2,8 +2,8 @@ Puck.debug=3; // FIXME: use UART lib so that we handle errors properly var Comms = { -reset : () => new Promise((resolve,reject) => { - Puck.write("\x03\x10reset();\n", (result) => { +reset : (opt) => new Promise((resolve,reject) => { + Puck.write(`\x03\x10reset(${opt=="wipe"?"1":""});\n`, (result) => { if (result===null) return reject("Connection failed"); setTimeout(resolve,500); }); @@ -73,7 +73,7 @@ removeApp : app => { // expects an app structure })); }, removeAllApps : () => { - return Comms.reset().then(() => new Promise((resolve,reject) => { + return Comms.reset("wipe").then(() => new Promise((resolve,reject) => { // Use write with newline here so we wait for it to finish Puck.write('\x10E.showMessage("Erasing...");require("Storage").eraseAll();Bluetooth.println("OK")\n', (result,err) => { if (!result || result.trim()!="OK") return reject(err || ""); From 22a2f75bd4f3e8c237f8d7d722227f39739f680f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 15:59:36 +0000 Subject: [PATCH 39/55] Update about page pixels... 9 Mar 2020 --- apps.json | 2 +- apps/about/ChangeLog | 1 + apps/about/app.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index ccc96de97..10341b54f 100644 --- a/apps.json +++ b/apps.json @@ -28,7 +28,7 @@ { "id": "about", "name": "About", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "tags": "tool,system", "allow_emulator":true, diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index ccf7cf46d..2c81c0537 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Update version checker for new filename type 0.03: Actual pixels as of 5 Mar 2020 +0.04: Actual pixels as of 9 Mar 2020 diff --git a/apps/about/app.js b/apps/about/app.js index 559d77052..7f794583f 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -29,5 +29,5 @@ g.drawString(NRF.getAddress(),120,232); g.flip(); // Pixel chooser image -g.drawImage(require("heatshrink").decompress(atob("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")),0,135); +g.drawImage(require("heatshrink").decompress(atob("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")),0,135); g.flip(); From c1e414a0c54426ee780f731e0d2d8455be0ab4df Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 16:45:41 +0000 Subject: [PATCH 40/55] Fix simulator links if using URLs like `index.html` or `../#` (#122) --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 56d6b4cc2..83abfdc4b 100644 --- a/index.js +++ b/index.js @@ -308,7 +308,8 @@ function refreshLibrary() { return; } var baseurl = window.location.href; - var url = baseurl+"apps/"+app.id+"/"+file.url; + baseurl = baseurl.substr(0,baseurl.lastIndexOf("/")); + 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 From 9bae225fd21631c67bf3b1ea10829219ba9f9e2b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 9 Mar 2020 17:06:13 +0000 Subject: [PATCH 41/55] Firmware maker tweaks --- bin/firmwaremaker.js | 39 ++++++++++++++------------ firmware.js | 66 +++++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 8346b3c00..8d52bd33f 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -10,16 +10,10 @@ var APPDIR = ROOTDIR+'/apps'; var APPJSON = ROOTDIR+'/apps.json'; var OUTFILE = ROOTDIR+'/firmware.js'; var APPS = [ // IDs of apps to install - "boot", - "launch", - "mclock", - "setting", - "astroid", - "gpstime", - "compass", - "sbt", - "sbat" + "boot","launch","mclock","setting", + "about","alarm","widbat","widbt","welcome" ]; +var MINIFY = true; var fs = require("fs"); var AppInfo = require(ROOTDIR+"/appinfo.js"); @@ -28,14 +22,25 @@ var appfiles = []; function fileGetter(url) { console.log("Loading "+url) - /*if (url.endsWith(".js")) { - var f = url.slice(0,-3); - console.log("MINIFYING "+f); - const execSync = require('child_process').execSync; - code = execSync(`espruino --board BANGLEJS --minify ${f}.js -o ${f}.min.js`); - console.log(code.toString()); - url = f+".min.js"; - }*/ + if (MINIFY) { + if (url.endsWith(".js")) { + var f = url.slice(0,-3); + console.log("MINIFYING "+f); + const execSync = require('child_process').execSync; + code = execSync(`espruino --board BANGLEJS --minify ${f}.js -o ${f}.min.js`); + console.log(code.toString()); + url = f+".min.js"; + } + if (url.endsWith(".json")) { + var f = url.slice(0,-5); + console.log("MINIFYING JSON "+f); + var j = eval("("+fs.readFileSync(url).toString()+")"); + var code = JSON.stringify(j); + //console.log(code); + url = f+".min.json"; + fs.writeFileSync(url, code); + } + } return Promise.resolve(fs.readFileSync(url).toString()); } diff --git a/firmware.js b/firmware.js index a6923ab1c..5bc1e222d 100644 --- a/firmware.js +++ b/firmware.js @@ -1,33 +1,35 @@ // Generated by BangleApps/bin/firmwaremaker.js -require('Storage').write(".bootcde","E.setFlags({pretokenise:1});\nvar startapp;\ntry {\n startapp = require('Storage').readJSON('+start');\n} catch (e) {}\nif (startapp) {\n eval(require(\"Storage\").read(startapp.src));\n} else {\n setWatch(function displayMenu() {\n Bangle.setLCDOffset(0); // remove notifications\n Bangle.setLCDMode(\"direct\");\n g.clear();\n // attempt to remove any currently-running code\n clearInterval();\n clearWatch();\n Bangle.removeAllListeners();\n NRF.removeAllListeners();\n Bluetooth.removeAllListeners();\n E.removeAllListeners();\n delete GB;\n delete WIDGETS;\n delete WIDGETPOS;\n delete drawWidgets;\n var s = require(\"Storage\");\n var apps = s.list().filter(a=>a[0]=='+').map(app=>{\n try { return s.readJSON(app); }\n catch (e) { return {name:\"DEAD: \"+app.substr(1)} }\n }).filter(app=>app.type==\"app\" || app.type==\"clock\" || !app.type);\n apps.sort((a,b)=>{\n var n=(0|a.sortorder)-(0|b.sortorder);\n if (n) return n; // do sortorder first\n if (a.nameb.name) return 1;\n return 0;\n });\n var selected = 0;\n var menuScroll = 0;\n var menuShowing = false;\n\n function drawMenu() {\n g.setFont(\"6x8\",2);\n g.setFontAlign(-1,0);\n var n = 3;\n if (selected>=n+menuScroll) menuScroll = 1+selected-n;\n if (selectedn+menuScroll) g.fillPoly([120,239,100,219,140,219]);\n else g.clearRect(100,219,140,239);\n for (var i=0;i0) {\n selected--;\n drawMenu();\n }\n }, BTN1, {repeat:true});\n setWatch(function() {\n if (selected+1a[0]=='=').forEach(widget=>eval(require(\"Storage\").read(widget)));\n setTimeout(drawWidgets,100);\n // load clock if specified\n var clockApp = settings.clock;\n if (clockApp) clockApp = require(\"Storage\").read(clockApp)\n if (!clockApp) {\n var clockApps = require(\"Storage\").list().filter(a=>a[0]=='+').map(app=>{\n try { return require(\"Storage\").readJSON(app); }\n catch (e) {}\n }).filter(app=>app.type==\"clock\").sort((a, b) => a.sortorder - b.sortorder);\n if (clockApps && clockApps.length > 0)\n clockApp = require(\"Storage\").read(clockApps[0].src);\n delete clockApps;\n }\n if (clockApp) eval(clockApp);\n else E.showMessage(\"No Clock Found\");\n delete clockApp;\n}\n"); -require('Storage').write("+mclock",{"name":"Morphing Clock","type":"clock","icon":"*mclock","src":"-mclock","sortorder":-10,"version":"0.01","files":"+mclock,-mclock,*mclock"}); -require('Storage').write("-mclock","(function(){ // make our own scope so this is GC'd when intervals are cleared\n// Offscreen buffer\nvar buf = Graphics.createArrayBuffer(240,86,1,{msb:true});\nfunction flip() {\n g.setColor(1,1,1);\n g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},0,50);\n}\n// The last time that we displayed\nvar lastTime = \" \";\n// If animating, this is the interval's id\nvar animInterval;\n\n/* Get array of lines from digit d to d+1.\n n is the amount (0..1)\n maxFive is true is this digit only counts 0..5 */\nconst DIGITS = {\n\" \":n=>[],\n\"0\":n=>[\n[n,0,1,0],\n[1,0,1,1],\n[1,1,1,2],\n[n,2,1,2],\n[n,1,n,2],\n[n,0,n,1]],\n\"1\":n=>[\n[1-n,0,1,0],\n[1,0,1,1],\n[1-n,1,1,1],\n[1-n,1,1-n,2],\n[1-n,2,1,2]],\n\"2\":n=>[\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1,1],\n[0,1+n,0,2],\n[1,2-n,1,2],\n[0,2,1,2]],\n\"3\":n=>[\n[0,0,1-n,0],\n[0,0,0,n],\n[1,0,1,1],\n[0,1,1,1],\n[1,1,1,2],\n[n,2,1,2]],\n\"4\":n=>[\n[0,0,0,1],\n[1,0,1-n,0],\n[1,0,1,1-n],\n[0,1,1,1],\n[1,1,1,2],\n[1-n,2,1,2]],\n\"5\": (n,maxFive)=>maxFive ? [ // 5 -> 0\n[0,0,0,1],\n[0,0,1,0],\n[n,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,2,0,2],\n[1,1-n,1,1],\n[0,1,0,1+n]] : [ // 5 -> 6\n[0,0,0,1],\n[0,0,1,0],\n[0,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,2-n,0,2]],\n\"6\":n=>[\n[0,0,0,1-n],\n[0,0,1,0],\n[n,1,1,1],\n[1,1-n,1,1],\n[1,1,1,2],\n[n,2,1,2],\n[0,1-n,0,2-2*n]],\n\"7\":n=>[\n[0,0,0,n],\n[0,0,1,0],\n[1,0,1,1],\n[1-n,1,1,1],\n[1,1,1,2],\n[1-n,2,1,2],\n[1-n,1,1-n,2]],\n\"8\":n=>[\n[0,0,0,1],\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,1,0,2-n]],\n\"9\":n=>[\n[0,0,0,1],\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1-n,1],\n[0,1,0,1+n],\n[1,1,1,2],\n[0,2,1,2]],\n\":\":n=>[\n[0.4,0.4,0.6,0.4],\n[0.6,0.4,0.6,0.6],\n[0.6,0.6,0.4,0.6],\n[0.4,0.4,0.4,0.6],\n[0.4,1.4,0.6,1.4],\n[0.6,1.4,0.6,1.6],\n[0.6,1.6,0.4,1.6],\n[0.4,1.4,0.4,1.6]]\n};\n\n/* Draw a transition between lastText and thisText.\n 'n' is the amount - 0..1 */\nfunction draw(lastText,thisText,n) {\n buf.clear();\n var x = 1; // x offset\n const p = 2; // padding around digits\n var y = p; // y offset\n const s = 34; // character size\n for (var i=0;i{\n if (c[0]!=c[2]) // horiz\n buf.fillRect(x+c[0]*s,y+c[1]*s-p,x+c[2]*s,y+c[3]*s+p);\n else if (c[1]!=c[3]) // vert\n buf.fillRect(x+c[0]*s-p,y+c[1]*s,x+c[2]*s+p,y+c[3]*s);\n });\n if (thisCh==\":\") x-=4;\n x+=s+p+7;\n }\n y += 2*s;\n var d = new Date();\n buf.setFont(\"6x8\");\n buf.setFontAlign(-1,-1);\n buf.drawString((\"0\"+d.getSeconds()).substr(-2), x, y-8);\n // date\n buf.setFontAlign(0,-1);\n var date = d.toString().substr(0,15);\n buf.drawString(date, buf.getWidth()/2, y+8);\n flip();\n}\n\n/* Show the current time, and animate if needed */\nfunction showTime() {\n if (!Bangle.isLCDOn()) return;\n if (animInterval) return; // in animation - quit\n var d = new Date();\n var t = (\" \"+d.getHours()).substr(-2)+\":\"+\n (\"0\"+d.getMinutes()).substr(-2);\n var l = lastTime;\n // same - don't animate\n if (t==l) {\n draw(t,l,0);\n return;\n }\n var n = 0;\n animInterval = setInterval(function() {\n n += 1/10;\n if (n>=1) {\n n=1;\n clearInterval(animInterval);\n animInterval=0;\n }\n draw(l,t,n);\n }, 20);\n lastTime = t;\n}\n\nBangle.on('lcdPower',function(on) {\n if (on) {\n showTime();\n drawWidgets();\n }\n});\n\ng.clear();\n// Update time once a second\nsetInterval(showTime, 1000);\nshowTime();\n})();\n"); -require('Storage').write("*mclock",require("heatshrink").decompress(atob("mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWPmf//8zDBpFDwYVBAAc4JJYWJDAoXKn4SC+EPAgXzC5JGCx4qDC4n//BIIEIRCEC4v/GBBdHC4xhCIw5dDC5BhCJAgXCRQoXGJAQXEUhAXHJAyNGC5KRCC7p2FC5B4CC5kggQXOBwvyBQMvSA4XL+EIwCoIC8ZHCgYXNO44LBBIiPPCAIwFC5DXGAAMwGAjvPGA4XIwYXHGALBDnAXFhCQHGAaOFwAXGPA4bFC4xIMIxIXDJBJGEC4xICSJCNEIwowEMJBdCFwwXEMJBdCC5BICDA4WDIw4wEAAMzCoMzBAgWIDAwAGCxRJEAAxFJDBgWNDBAWPAH4AYA=="))); -require('Storage').write("+setting",{"name":"Settings","type":"app","icon":"*settings","src":"-settings","version":"0.01","files":"+setting,-setting,=setting,setting.json,*setting"}); -require('Storage').write("-setting","Bangle.setLCDPower(1);\nBangle.setLCDTimeout(0);\n\ng.clear();\nconst storage = require('Storage');\nlet settings;\n\nfunction debug(msg, arg) {\n if (settings.debug)\n console.log(msg, arg);\n}\n\nfunction updateSettings() {\n debug('updating settings', settings);\n //storage.erase('setting.json'); // - not needed, just causes extra writes if settings were the same\n storage.write('setting.json', settings);\n}\n\nfunction resetSettings() {\n settings = {\n ble: true,\n dev: true,\n timeout: 10,\n vibrate: true,\n beep: true,\n timezone: 0,\n HID : false,\n HIDGestures: false,\n debug: false,\n clock: null\n };\n setLCDTimeout(settings.timeout);\n updateSettings();\n}\n\ntry {\n settings = storage.readJSON('setting.json');\n} catch (e) {}\nif (!settings) resetSettings();\n\nconst boolFormat = (v) => v ? \"On\" : \"Off\";\n\nfunction showMainMenu() {\n const mainmenu = {\n '': { 'title': 'Settings' },\n 'BLE': {\n value: settings.ble,\n format: boolFormat,\n onchange: () => {\n settings.ble = !settings.ble;\n updateSettings();\n }\n },\n 'Programmable': {\n value: settings.dev,\n format: boolFormat,\n onchange: () => {\n settings.dev = !settings.dev;\n updateSettings();\n }\n },\n 'LCD Timeout': {\n value: settings.timeout,\n min: 0,\n max: 60,\n step: 5,\n onchange: v => {\n settings.timeout = 0 | v;\n updateSettings();\n Bangle.setLCDTimeout(settings.timeout);\n }\n },\n 'Beep': {\n value: settings.beep,\n format: boolFormat,\n onchange: () => {\n settings.beep = !settings.beep;\n updateSettings();\n if (settings.beep) {\n Bangle.beep(1);\n }\n }\n },\n 'Vibration': {\n value: settings.vibrate,\n format: boolFormat,\n onchange: () => {\n settings.vibrate = !settings.vibrate;\n updateSettings();\n if (settings.vibrate) {\n VIBRATE.write(1);\n setTimeout(()=>VIBRATE.write(0), 10);\n }\n }\n },\n 'Select Clock': showClockMenu,\n 'Time Zone': {\n value: settings.timezone,\n min: -11,\n max: 12,\n step: 1,\n onchange: v => {\n settings.timezone = 0 | v;\n updateSettings();\n }\n },\n 'HID': {\n value: settings.HID,\n format: boolFormat,\n onchange: () => {\n settings.HID = !settings.HID;\n updateSettings();\n }\n },\n 'HID Gestures': {\n value: settings.HIDGestures,\n format: boolFormat,\n onchange: () => {\n settings.HIDGestures = !settings.HIDGestures;\n updateSettings();\n }\n },\n 'Debug': {\n value: settings.debug,\n format: boolFormat,\n onchange: () => {\n settings.debug = !settings.debug;\n updateSettings();\n }\n },\n 'Set Time': showSetTimeMenu,\n 'Make Connectable': makeConnectable,\n 'Reset Settings': showResetMenu,\n 'Turn Off': Bangle.off,\n '< Back': load\n };\n return Bangle.menu(mainmenu);\n}\n\nfunction showResetMenu() {\n const resetmenu = {\n '': { 'title': 'Reset' },\n '< Back': showMainMenu,\n 'Reset Settings': () => {\n E.showPrompt('Reset Settings?').then((v) => {\n if (v) {\n E.showMessage('Resetting');\n resetSettings();\n }\n setTimeout(showMainMenu, 50);\n });\n },\n // this is include for debugging. remove for production\n /*'Erase': () => {\n storage.erase('=setting');\n storage.erase('-setting');\n storage.erase('setting.json');\n storage.erase('*setting');\n storage.erase('+setting');\n E.reboot();\n }*/\n };\n return Bangle.menu(resetmenu);\n}\n\nfunction makeConnectable() {\n try { NRF.wake(); } catch(e) {}\n Bluetooth.setConsole(1);\n var name=\"Bangle.js \"+NRF.getAddress().substr(-5).replace(\":\",\"\");\n E.showPrompt(name+\"\\nStay Connectable?\",{title:\"Connectable\"}).then(r=>{\n if (settings.ble!=r) {\n settings.ble = r;\n updateSettings();\n }\n if (!r) try { NRF.sleep(); } catch(e) {}\n showMainMenu();\n });\n}\nfunction showClockMenu() {\n var clockApps = require(\"Storage\").list().filter(a=>a[0]=='+').map(app=>{\n try { return require(\"Storage\").readJSON(app); }\n catch (e) {}\n }).filter(app=>app.type==\"clock\").sort((a, b) => a.sortorder - b.sortorder);\n const clockMenu = {\n '': {\n 'title': 'Select Clock',\n },\n '< Back': showMainMenu,\n };\n clockApps.forEach((app,index) => {\n var label = app.name;\n if ((!settings.clock && index === 0) || (settings.clock === app.src)) {\n label = \"* \"+label;\n }\n clockMenu[label] = () => {\n if (settings.clock !== app.src) {\n settings.clock = app.src;\n updateSettings();\n showMainMenu();\n }\n };\n });\n if (clockApps.length === 0) {\n clockMenu[\"No Clocks Found\"] = () => {};\n }\n return Bangle.menu(clockMenu);\n}\n\n\n\nfunction showSetTimeMenu() {\n d = new Date();\n const timemenu = {\n '': {\n 'title': 'Set Time',\n 'predraw': function() {\n d = new Date();\n timemenu.Hour.value = d.getHours();\n timemenu.Minute.value = d.getMinutes();\n timemenu.Second.value = d.getSeconds();\n timemenu.Date.value = d.getDate();\n timemenu.Month.value = d.getMonth() + 1;\n timemenu.Year.value = d.getFullYear();\n }\n },\n '< Back': showMainMenu,\n 'Hour': {\n value: d.getHours(),\n min: 0,\n max: 23,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setHours(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Minute': {\n value: d.getMinutes(),\n min: 0,\n max: 59,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setMinutes(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Second': {\n value: d.getSeconds(),\n min: 0,\n max: 59,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setSeconds(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Date': {\n value: d.getDate(),\n min: 1,\n max: 31,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setDate(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Month': {\n value: d.getMonth() + 1,\n min: 1,\n max: 12,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setMonth(v - 1);\n setTime(d.getTime()/1000);\n }\n },\n 'Year': {\n value: d.getFullYear(),\n min: 2019,\n max: 2100,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setFullYear(v);\n setTime(d.getTime()/1000);\n }\n }\n };\n return Bangle.menu(timemenu);\n}\n\nshowMainMenu();\n"); -require('Storage').write("=setting","Bangle.HID = E.toUint8Array(atob(\"BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==\"));\n\n(function() {\n var s = require('Storage').readJSON('setting.json');\n var adv = { uart: true };\n if (s.ble) {\n if (s.dev)\n Bluetooth.setConsole(true);\n else\n Terminal.setConsole(true);\n if (s.HID) {\n adv.hid = Bangle.HID;\n } else\n delete Bangle.HID;\n }\n NRF.setServices({}, adv);\n // we just reset, so BLE should be on\n try { // disable advertising if BLE should be off\n if (!s.ble) NRF.sleep();\n else NRF.wake();\n } catch(e) {}\n if (!s.vibrate) Bangle.buzz=Promise.resolve;\n if (!s.beep) Bangle.beep=Promise.resolve;\n Bangle.setLCDTimeout(s.timeout);\n if (!s.timeout) Bangle.setLCDPower(1);\n E.setTimeZone(s.timezone);\n})()\n"); -require('Storage').write("setting.json",{ - ble: true, // Bluetooth enabled by default - dev: true, // Espruino IDE enabled by default - timeout: 10, // Default LCD timeout in seconds - vibrate: true, // Vibration enabled by default. App must support - beep: true, // Beep enabled by default. App must support - timezone: 0, // Set the timezone for the device - HID : false, // BLE HID mode, off by default - HIDGestures: false, - debug: false, // Debug mode disabled by default. App must support -}); -require('Storage').write("*setting",require("heatshrink").decompress(atob("mEwghC/AFEiAAgX/C/4SFkADBgQXFBIgECAAYSCkAWGBIoXGyQTHABBZLkUhiMRiQXLIQwVBAAZlIC44tCAAYxGIxIWFGA4XIFwwwHXBAWHGAwXHFxAwGPAYXTX44XDiAJBgIXGyDAHFAYKDMAq+EGAgXNCwwX/C453XU6IWHa6ZFCC6JJCC4hgEAAoOEC5AwIFwhgEBAgwIBoqmGGBIuFVAgXFGAwLFYAoLFGIYtFeA4MGABMpC4pICkBMGBIpGFC4SuIBIoWFAAxZLC/4X/AFQ"))); -require('Storage').write("+astroid",{"name":"Asteroids!","type":"app","icon":"*astroid","src":"-astroid","version":"0.01","files":"+astroid,-astroid,*astroid"}); -require('Storage').write("-astroid","Bangle.setLCDMode(\"doublebuffered\");\n\nvar W = g.getWidth();\nvar H = g.getHeight();\ng.setFontAlign(0,-1);\nvar BTNL = BTN4;\nvar BTNR = BTN5;\nvar BTNU = BTN1;\nvar BTNA = BTN2;\n\nfunction newAst(x,y) {\n var a = {\n x:x,y:y,\n vx:Math.random()-0.5,\n vy:Math.random()-0.5,\n rad:3+Math.random()*5\n };\n return a;\n}\n\nvar running = true;\nvar ship = {};\nvar ammo = [];\nvar ast = [];\nvar score = 0;\nvar level = 4;\nvar timeSinceFired = 0;\nvar lastFrame;\n\nfunction gameStop() {\n running = false;\n g.clear();\n g.drawString(\"Game Over!\",120,(H-6)/2);\n g.flip();\n}\n\nfunction addAsteroids() {\n for (var i=0;i=W) ship.x-=W;\n if (ship.y>=H) ship.y-=H;\n timeSinceFired+=d;\n if (BTNA.read() && timeSinceFired>4) { // fire!\n Bangle.beep(10);\n timeSinceFired = 0;\n ammo.push({\n x:ship.x+Math.cos(ship.r)*4,\n y:ship.y+Math.sin(ship.r)*4,\n vx:Math.cos(ship.r)*3,\n vy:Math.sin(ship.r)*3,\n });\n }\n\n g.clear();\n\n g.drawString(score,120,0);\n var rs = Math.PI*0.8;\n g.drawPoly([\n ship.x+Math.cos(ship.r)*4, ship.y+Math.sin(ship.r)*4,\n ship.x+Math.cos(ship.r+rs)*3, ship.y+Math.sin(ship.r+rs)*3,\n ship.x+Math.cos(ship.r-rs)*3, ship.y+Math.sin(ship.r-rs)*3,\n ],true);\n var na = [];\n ammo.forEach(function(a) {\n a.x += a.vx*d;\n a.y += a.vy*d;\n g.fillRect(a.x-1, a.y, a.x+1, a.y);\n g.fillRect(a.x, a.y-1, a.x, a.y+1);\n var hit = false;\n ast.forEach(function(b) {\n var dx = a.x-b.x;\n var dy = a.y-b.y;\n var d = Math.sqrt(dx*dx+dy*dy);\n if (d=0 && a.y>=0 && a.x=W) a.x-=W;\n if (a.y>=H) a.y-=H;\n if (!a.hit) {\n na.push(a);\n } else if (a.rad>4) {\n Bangle.buzz(100);\n a.hit = false;\n var vx = 1*(Math.random()-0.5);\n var vy = 1*(Math.random()-0.5);\n a.rad/=2;\n na.push({\n x:a.x,\n y:a.y,\n vx:a.vx-vx,\n vy:a.vy-vy,\n rad:a.rad,\n });\n a.vx += vx;\n a.vy += vy;\n na.push(a);\n }\n\n var dx = a.x-ship.x;\n var dy = a.y-ship.y;\n var d = Math.sqrt(dx*dx+dy*dy);\n if (d < a.rad) crashed = true;\n });\n ast=na;\n if (!ast.length) {\n level++;\n addAsteroids();\n }\n g.flip();\n if (crashed) {\n Bangle.buzz(500);\n gameStop();\n }\n}\n\ngameStart();\nsetInterval(onFrame, 50);\n"); -require('Storage').write("*astroid",require("heatshrink").decompress(atob("mEwghC/ADkN6APN7oDGC64AWDRw9DIIgXVLh/eAYQtEFxsN7oqCCQQDBC5oOBC4IDHFxgmBAY4uvGJQuMC5IuLhpdWMBQuMSBQuMF5IubhqHDFyIfGX5giFkWQGYa/KEQcCkQACmA6KFwwWDkUgNJJVGFwgABFwoXGBYIuGC4jrL8AuBmczJAgLBRhAXCFwQXGRhIXGkUjI4i/CapReHC4KEEC6a/KC48jmQXCfQoXNX44XJawx3CX5gXHXwQuJcYYXHFxaaEhIXEFxiyFGIeQFxqEIFxy0HhwuOFAgAFCxowDAAguODA4WRAH4ADA=="))); -require('Storage').write("+gpstime",{"name":"GPS Time","type":"app","icon":"*gpstime","src":"-gpstime","version":"0.01","files":"+gpstime,-gpstime,*gpstime"}); -require('Storage').write("-gpstime","var img = require(\"heatshrink\").decompress(atob(\"mEwghC/AH8A1QWVhWq0AuVAAIuVAAIwT1WinQwTFwMzmQwTCYMjlUqGCIuBlWi0UzC6JdBIoMjC4UDmAuOkYXBPAWgmczLp2ilUiVAUDC4IwLFwIUBLoJ2BFwQwM1WjCgJ1DFwQwLFwJ1B0SQCkQWDGBQXBCgK9BDgKQBAAgwJOwUzRgIDBC54wCkZdGPBwACRgguDBIIwLFxEJBQIwLFxGaBYQwKFxQwLgAWGmQuBcAQwJC48ifYYwJgUidgsyC4L7DGBIXBdohnBCgL7BcYIXIGAqMCIoL7DL5IwERgIUBLoL7BO5QXBGAK7DkWiOxQXGFwOjFoUyFxZhDgBdCCgJ1CCxYxCgBABkcqOwIuNGAQXC0S9BLpgAFXoIwBmYuPAAYwCLp4wHFyYwDFyYwDFygwCCyoA/AFQA=\"));\n\nBangle.setLCDPower(1);\nBangle.setLCDTimeout(0);\n\ng.clear();\n\n\n\nvar fix;\nBangle.on('GPS',function(f) {\n fix = f;\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n g.clearRect(90,30,239,90);\n if (fix.fix) {\n g.drawString(\"GPS\",170,40);\n g.drawString(\"Acquired\",170,60);\n } else {\n g.drawString(\"Waiting for\",170,40);\n g.drawString(\"GPS Fix\",170,60);\n }\n g.setFont(\"6x8\");\n g.drawString(fix.satellites+\" satellites\",170,80);\n \n g.clearRect(0,100,239,239);\n var t = fix.time.toString().split(\" \");/*\n [\n \"Sun\",\n \"Nov\",\n \"10\",\n \"2019\",\n \"15:55:35\",\n \"GMT+0100\"\n ]\n */\n //g.setFont(\"6x8\",2);\n //g.drawString(t[0],120,110); // day\n g.setFont(\"6x8\",3);\n g.drawString(t[1]+\" \"+t[2],120,135); // date\n g.setFont(\"6x8\",2);\n g.drawString(t[3],120,160); // year\n g.setFont(\"6x8\",3);\n g.drawString(t[4],120,185); // time\n // timezone\n var tz = (new Date()).getTimezoneOffset()/60;\n if (tz==0) tz=\"UTC\";\n else if (tz>0) tz=\"UTC+\"+tz;\n else tz=\"UTC\"+tz;\n g.setFont(\"6x8\",2);\n g.drawString(tz,120,210); // gmt\n g.setFontAlign(0,0,3);\n g.drawString(\"Set\",230,120);\n g.setFontAlign(0,0);\n});\n\nsetInterval(function() {\n g.drawImage(img,48,48,{scale:1.5,rotate:Math.sin(getTime()*2)/2});\n},100);\nsetWatch(function() {\n setTime(fix.time.getTime()/1000);\n}, BTN2, {repeat:true});\n\nBangle.setGPSPower(1)\n"); -require('Storage').write("*gpstime",require("heatshrink").decompress(atob("mEwghC/AH8A1QWVhWq0AuVAAIuVAAIwT1WinQwTFwMzmQwTCYMjlUqGCIuBlWi0UzC6JdBIoMjC4UDmAuOkYXBPAWgmczLp2ilUiVAUDC4IwLFwIUBLoJ2BFwQwM1WjCgJ1DFwQwLFwJ1B0SQCkQWDGBQXBCgK9BDgKQBAAgwJOwUzRgIDBC54wCkZdGPBwACRgguDBIIwLFxEJBQIwLFxGaBYQwKFxQwLgAWGmQuBcAQwJC48ifYYwJgUidgsyC4L7DGBIXBdohnBCgL7BcYIXIGAqMCIoL7DL5IwERgIUBLoL7BO5QXBGAK7DkWiOxQXGFwOjFoUyFxZhDgBdCCgJ1CCxYxCgBABkcqOwIuNGAQXC0S9BLpgAFXoIwBmYuPAAYwCLp4wHFyYwDFyYwDFygwCCyoA/AFQA="))); -require('Storage').write("+compass",{"name":"Compass","type":"app","icon":"*compass","src":"-compass","version":"0.01","files":"+compass,-compass,*compass"}); -require('Storage').write("-compass","g.clear();\ng.setColor(0,0.5,1);\ng.fillCircle(120,130,80,80);\ng.setColor(0,0,0);\ng.fillCircle(120,130,70,70);\n\nfunction arrow(r,c) {\n r=r*Math.PI/180;\n var p = Math.PI/2;\n g.setColor(c);\n g.fillPoly([\n 120+60*Math.sin(r), 130-60*Math.cos(r),\n 120+10*Math.sin(r+p), 130-10*Math.cos(r+p),\n 120+10*Math.sin(r+-p), 130-10*Math.cos(r-p),\n ]);\n}\n\nvar oldHeading = 0;\nBangle.on('mag', function(m) {\n if (!Bangle.isLCDOn()) return;\n g.setFont(\"6x8\",3);\n g.setColor(0);\n g.fillRect(70,0,170,24);\n g.setColor(0xffff);\n g.setFontAlign(0,0);\n g.drawString(isNaN(m.heading)?\"---\":Math.round(m.heading),120,12);\n g.setColor(0,0,0);\n arrow(oldHeading,0);\n arrow(oldHeading+180,0);\n arrow(m.heading,0xF800);\n arrow(m.heading+180,0x001F);\n oldHeading = m.heading;\n});\nBangle.setCompassPower(1);\n"); -require('Storage').write("*compass",require("heatshrink").decompress(atob("mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWOwcz///mc4DBhFDwYVBAAYYDJJAWJDAoXKCw//+YXJIwWPCQk/Aof4JBAuHC4v/GBBdHC4nzMIZGHCAIOBC4vz75hDJAgXCCgS9CC4fdAYQXGIwsyCAPyl//nvdVQoXFRofzkYXCCwJGBSIgXFQ4kymcykfdIwZgDC5XzkUyCwJGDC6FNCwPTC5i9FmQXCMgLZFC48zLgMilUv/vdkUjBII9BC6HSC55HD1WiklDNIgXIBok61QYBkSBFC5kqCwMjC6RGB1RcCR4gXIx4MC+Wqkfyl70BEQf4C4+DIwYqBC4XzGAc4C4sISAfz0QDCFgUzRwmAC4wQB+QTCC4f/AYJeCC4hIEPQi9FIwwXDbIzVHC4xICSIYXGRoRGFGAgqFXgouGC4iqDLo4XIJAQYHCwZGHGAgYBXQUzCwYuIDAwAHCxRJEAAxFJDBgWNDBAWPAH4AYA="))); -require('Storage').write("+sbt",{"name":"bluetooth","type":"widget","src":"=sbt","version":"0.01","files":"+sbt,=sbt"}); -require('Storage').write("=sbt","(function(){\nvar img_bt = E.toArrayBuffer(atob(\"CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==\"));\nvar xpos = WIDGETPOS.tr-24;\nWIDGETPOS.tr-=24;\n\nfunction draw() {\n var x = xpos, y = 0;\n if (NRF.getSecurityStatus().connected)\n g.setColor(0,0.5,1);\n else\n g.setColor(0.3,0.3,0.3);\n g.drawImage(img_bt,10+x,2+y);\n g.setColor(1,1,1);\n}\nfunction changed() {\n draw();\n g.flip();\n}\nNRF.on('connected',changed);\nNRF.on('disconnected',changed);\nWIDGETS[\"bluetooth\"]={draw:draw};\n})()\n"); -require('Storage').write("+sbat",{"name":"Battery Level","type":"widget","src":"=sbat","version":"0.01","files":"+sbat,=sbat"}); -require('Storage').write("=sbat","(function(){\nvar img_charge = E.toArrayBuffer(atob(\"DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg\"));\nvar CHARGING = 0x07E0;\nvar xpos = WIDGETPOS.tr-64;\nWIDGETPOS.tr-=68;\n\nfunction draw() {\n var s = 63;\n var x = xpos, y = 0;\n g.clearRect(x,y,x+s,y+23);\n if (Bangle.isCharging()) {\n g.setColor(CHARGING).drawImage(img_charge,x,y);\n x+=16;\n s-=16;\n }\n g.setColor(1,1,1);\n g.fillRect(x,y+2,x+s-4,y+21);\n g.clearRect(x+2,y+4,x+s-6,y+19);\n g.fillRect(x+s-3,y+10,x+s,y+14);\n g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17);\n g.setColor(1,1,1);\n}\nBangle.on('charging',function(charging) { draw(); g.flip(); if(charging)Bangle.buzz(); });\nWIDGETS[\"battery\"]={draw:draw};\n})()\n"); +require('Storage').write(".boot0","setTime(1583773540.682);E.setTimeZone(0)\nE.setFlags({pretokenise:1});var s=require('Storage').readJSON('setting.json',1)||{};s.ble!==!1&&s.HID&&(Bangle.HID=E.toUint8Array(atob('BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==')),NRF.setServices({},{uart:!0,hid:Bangle.HID})),s.blerepl===!1?s.log?Terminal.setConsole(!0):E.setConsole(null,{force:!0}):s.log?Terminal.setConsole():Bluetooth.setConsole(!0),s.ble===!1&&!NRF.getSecurityStatus().connected&&NRF.sleep(),s.vibrate||(Bangle.buzz=Promise.resolve),s.beep||(Bangle.beep=Promise.resolve),Bangle.setLCDTimeout(s.timeout),s.timeout||Bangle.setLCDPower(1),E.setTimeZone(s.timezone),delete s;var alarms=require('Storage').readJSON('alarm.json',1)||[],time=new Date,active=alarms.filter(a=>a.on&&a.last!=time.getDate());if(active.length){active=active.sort((a,b)=>a.hr-b.hr);var hr=time.getHours()+time.getMinutes()/60+time.getSeconds()/3600;if(!require('Storage').read('alarm.js'))console.log('No alarm app!'),require('Storage').write('alarm.json','[]');else{var t=36e5*(active[0].hr-hr);t<1e3&&(t=1e3),setTimeout(function(){load('alarm.js')},t)}}"); +require('Storage').write(".bootcde","setTime(1583773540.935);E.setTimeZone(0)\nvar settings=require('Storage').readJSON('setting.json',1)||{};if(!settings.welcomed&&require('Storage').read('welcome.js')!==undefined)setTimeout(()=>load('welcome.js'));else{var clockApp=settings.clock;if(clockApp&&(clockApp=require('Storage').read(clockApp)),!clockApp){var clockApps=require('Storage').list(/\\.info$/).map(app=>require('Storage').readJSON(app,1)||{}).filter(app=>app.type=='clock').sort((a,b)=>a.sortorder-b.sortorder);clockApps&&clockApps.length>0&&(clockApp=require('Storage').read(clockApps[0].src)),delete clockApps}clockApp||(clockApp='E.showMessage(\"No Clock Found\")'),delete settings,new Date().getFullYear()==1970?(E.showMessage('Searching for\\nGPS time'),Bangle.on('GPS',function cb(g){if(Bangle.setGPSPower(0),Bangle.removeListener('GPS',cb),!g.time||g.time.getFullYear()<2e3||g.time.getFullYear()==2250){eval(clockApp),delete clockApp;return}setTime(g.time.getTime()/1e3),load()}),Bangle.setGPSPower(1)):(eval(clockApp),delete clockApp)}"); +require('Storage').write("boot.info","{\"id\":\"boot\",\"name\":\"Bootloader\",\"type\":\"bootloader\",\"sortorder\":-10,\"version\":\"0.09\",\"files\":\"boot.info,.boot0,.bootcde\"}"); +require('Storage').write("launch.app.js","setTime(1583773541.231);E.setTimeZone(0)\nfunction drawMenu(){g.setFont('6x8',2),g.setFontAlign(-1,0);var c=3;selected>=c+menuScroll&&(menuScroll=1+selected-c),selectedc+menuScroll?g.fillPoly([120,239,100,219,140,219]):g.clearRect(100,219,140,239);for(var b=0;bs.readJSON(app,1)||{name:'DEAD: '+app.substr(1)}).filter(app=>app.type=='app'||app.type=='clock'||!app.type);apps.sort((a,b)=>{var n=(0|a.sortorder)-(0|b.sortorder);return n?n:a.nameb.name?1:0});var selected=0,menuScroll=0,menuShowing=!1;drawMenu(),setWatch(function(){selected>0&&(selected--,drawMenu())},BTN1,{repeat:!0}),setWatch(function(){selected+1c[0]!=c[2]?buf.fillRect(b+c[0]*a,d+c[1]*a-f,b+c[2]*a,d+c[3]*a+f):c[1]!=c[3]&&buf.fillRect(b+c[0]*a-f,d+c[1]*a,b+c[2]*a+f,d+c[3]*a);),e==':'&&(b-=4),b+=a+f+7}d+=2*a;var i=new Date;buf.setFont('6x8'),buf.setFontAlign(-1,-1),buf.drawString(('0'+i.getSeconds()).substr(-2),b,d-8),buf.setFontAlign(0,-1);var n=i.toString().substr(0,15);buf.drawString(n,buf.getWidth()/2,d+8),flip()}function showTime(){if(!Bangle.isLCDOn())return;if(animInterval)return;var d=new Date,a=(' '+d.getHours()).substr(-2)+':'+('0'+d.getMinutes()).substr(-2),c=lastTime;if(a==c){draw(a,c,0);return}var b=0;animInterval=setInterval(function(){b+=.1,b>=1&&(b=1,clearInterval(animInterval),animInterval=0),draw(c,a,b)},20),lastTime=a}var buf=Graphics.createArrayBuffer(240,86,1,{msb:!0}),lastTime=' ',animInterval;const DIGITS={' ':n=>[],0:n=>[[n,0,1,0],[1,0,1,1],[1,1,1,2],[n,2,1,2],[n,1,n,2],[n,0,n,1]],1:n=>[[1-n,0,1,0],[1,0,1,1],[1-n,1,1,1],[1-n,1,1-n,2],[1-n,2,1,2]],2:n=>[[0,0,1,0],[1,0,1,1],[0,1,1,1],[0,1+n,0,2],[1,2-n,1,2],[0,2,1,2]],3:n=>[[0,0,1-n,0],[0,0,0,n],[1,0,1,1],[0,1,1,1],[1,1,1,2],[n,2,1,2]],4:n=>[[0,0,0,1],[1,0,1-n,0],[1,0,1,1-n],[0,1,1,1],[1,1,1,2],[1-n,2,1,2]],5:(n,maxFive)=>maxFive?[[0,0,0,1],[0,0,1,0],[n,1,1,1],[1,1,1,2],[0,2,1,2],[0,2,0,2],[1,1-n,1,1],[0,1,0,1+n]]:[[0,0,0,1],[0,0,1,0],[0,1,1,1],[1,1,1,2],[0,2,1,2],[0,2-n,0,2]],6:n=>[[0,0,0,1-n],[0,0,1,0],[n,1,1,1],[1,1-n,1,1],[1,1,1,2],[n,2,1,2],[0,1-n,0,2-2*n]],7:n=>[[0,0,0,n],[0,0,1,0],[1,0,1,1],[1-n,1,1,1],[1,1,1,2],[1-n,2,1,2],[1-n,1,1-n,2]],8:n=>[[0,0,0,1],[0,0,1,0],[1,0,1,1],[0,1,1,1],[1,1,1,2],[0,2,1,2],[0,1,0,2-n]],9:n=>[[0,0,0,1],[0,0,1,0],[1,0,1,1],[0,1,1-n,1],[0,1,0,1+n],[1,1,1,2],[0,2,1,2]],':':n=>[[.4,.4,.6,.4],[.6,.4,.6,.6],[.6,.6,.4,.6],[.4,.4,.4,.6],[.4,1.4,.6,1.4],[.6,1.4,.6,1.6],[.6,1.6,.4,1.6],[.4,1.4,.4,1.6]]};Bangle.on('lcdPower',function(a){a&&showTime()}),g.clear(),Bangle.loadWidgets(),Bangle.drawWidgets(),setInterval(showTime,1e3),showTime(),setWatch(Bangle.showLauncher,BTN2,{repeat:!1,edge:'falling'})"); +require('Storage').write("mclock.img",setTime(1583773541.816);E.setTimeZone(0) +require('heatshrink').decompress(atob('mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWPmf//8zDBpFDwYVBAAc4JJYWJDAoXKn4SC+EPAgXzC5JGCx4qDC4n//BIIEIRCEC4v/GBBdHC4xhCIw5dDC5BhCJAgXCRQoXGJAQXEUhAXHJAyNGC5KRCC7p2FC5B4CC5kggQXOBwvyBQMvSA4XL+EIwCoIC8ZHCgYXNO44LBBIiPPCAIwFC5DXGAAMwGAjvPGA4XIwYXHGALBDnAXFhCQHGAaOFwAXGPA4bFC4xIMIxIXDJBJGEC4xICSJCNEIwowEMJBdCFwwXEMJBdCC5BICDA4WDIw4wEAAMzCoMzBAgWIDAwAGCxRJEAAxFJDBgWNDBAWPAH4AYA=='))); +require('Storage').write("mclock.info","{\"id\":\"mclock\",\"name\":\"Morphing Clock\",\"type\":\"clock\",\"src\":\"mclock.app.js\",\"icon\":\"mclock.img\",\"sortorder\":-9,\"version\":\"0.02\",\"files\":\"mclock.info,mclock.app.js,mclock.img\"}"); +require('Storage').write("setting.app.js","setTime(1583773542.218);E.setTimeZone(0)\nfunction updateSettings(){storage.write('setting.json',settings)}function resetSettings(){settings={ble:!0,blerepl:!0,log:!1,timeout:10,vibrate:!0,beep:!0,timezone:0,HID:!1,clock:null,'12hour':!1,distance:'kilometer'},updateSettings()}function showMainMenu(){const a={'':{title:'Settings'},'Make Connectable':makeConnectable,BLE:{value:settings.ble,format:boolFormat,onchange:()=>settings.ble=!settings.ble,updateSettings();},Programmable:{value:settings.blerepl,format:boolFormat,onchange:()=>settings.blerepl=!settings.blerepl,updateSettings();},'Debug info':{value:settings.log,format:v=>v?'Show':'Hide',onchange:()=>settings.log=!settings.log,updateSettings();},'LCD Timeout':{value:settings.timeout,min:0,max:60,step:5,onchange:v=>settings.timeout=0|v,updateSettings(),Bangle.setLCDTimeout(settings.timeout);},Beep:{value:settings.beep,format:boolFormat,onchange:()=>settings.beep=!settings.beep,updateSettings(),settings.beep&&Bangle.beep(1);},Vibration:{value:settings.vibrate,format:boolFormat,onchange:()=>settings.vibrate=!settings.vibrate,updateSettings(),settings.vibrate&&(VIBRATE.write(1),setTimeout(()=>VIBRATE.write(0),10));},'Welcome App':{value:!settings.welcomed,format:boolFormat,onchange:v=>settings.welcomed=v?undefined:!0,updateSettings();},Locale:showLocaleMenu,'Select Clock':showClockMenu,HID:{value:settings.HID,format:boolFormat,onchange:()=>settings.HID=!settings.HID,updateSettings();},'Set Time':showSetTimeMenu,'Reset Settings':showResetMenu,'Turn Off':Bangle.off,'< Back':()=>load();};return E.showMenu(a)}function showLocaleMenu(){const a={'':{title:'Locale'},'< Back':showMainMenu,'Time Zone':{value:settings.timezone,min:-11,max:12,step:.5,onchange:v=>settings.timezone=v||0,updateSettings();},'Clock Style':{value:!!settings['12hour'],format:v=>v?'12hr':'24hr',onchange:v=>settings['12hour']=v,updateSettings();},'Distance/Speed':{value:settings.distance=='mile',format:v=>v?'mile':'km',onchange:v=>settings.distance=v?'mile':'kilometer',updateSettings();}};return E.showMenu(a)}function showResetMenu(){const a={'':{title:'Reset'},'< Back':showMainMenu,'Reset Settings':()=>E.showPrompt('Reset Settings?').then(v=>v&&(E.showMessage('Resetting'),resetSettings()),setTimeout(showMainMenu,50););};return E.showMenu(a)}function makeConnectable(){try{NRF.wake()}catch(a){}Bluetooth.setConsole(1);var a='Bangle.js '+NRF.getAddress().substr(-5).replace(':','');E.showPrompt(a+'\\nStay Connectable?',{title:'Connectable'}).then(r=>{if(settings.ble!=r&&(settings.ble=r,updateSettings()),!r)try{NRF.sleep()}catch(a){}showMainMenu()})}function showClockMenu(){var c=require('Storage').list(/\\.info$/).map(app=>try{return require('Storage').readJSON(app)}catch(a){}).filter(app=>app.type=='clock').sort((a,b)=>a.sortorder-b.sortorder);const d={'':{title:'Select Clock'},'< Back':showMainMenu};return c.forEach((app,index)=>var e=app.name;),c.length===0&&(d['No Clocks Found']=()=>;),E.showMenu(d)}function showSetTimeMenu(){d=new Date;const a={'':{title:'Set Time',predraw:function(){d=new Date,a.Hour.value=d.getHours(),a.Minute.value=d.getMinutes(),a.Second.value=d.getSeconds(),a.Date.value=d.getDate(),a.Month.value=d.getMonth()+1,a.Year.value=d.getFullYear()}},'< Back':showMainMenu,Hour:{value:d.getHours(),min:0,max:23,step:1,onchange:v=>d=new Date,d.setHours(v),setTime(d.getTime()/1e3);},Minute:{value:d.getMinutes(),min:0,max:59,step:1,onchange:v=>d=new Date,d.setMinutes(v),setTime(d.getTime()/1e3);},Second:{value:d.getSeconds(),min:0,max:59,step:1,onchange:v=>d=new Date,d.setSeconds(v),setTime(d.getTime()/1e3);},Date:{value:d.getDate(),min:1,max:31,step:1,onchange:v=>d=new Date,d.setDate(v),setTime(d.getTime()/1e3);},Month:{value:d.getMonth()+1,min:1,max:12,step:1,onchange:v=>d=new Date,d.setMonth(v-1),setTime(d.getTime()/1e3);},Year:{value:d.getFullYear(),min:2019,max:2100,step:1,onchange:v=>d=new Date,d.setFullYear(v),setTime(d.getTime()/1e3);}};return E.showMenu(a)}Bangle.loadWidgets(),Bangle.drawWidgets();const storage=require('Storage');let settings;settings=storage.readJSON('setting.json',1),settings||resetSettings();const boolFormat=v=>v?'On':'Off';showMainMenu()"); +require('Storage').write("setting.json",{"ble":true,"blerepl":true,"log":false,"timeout":10,"vibrate":true,"beep":true,"timezone":0,"HID":false,"clock":null,"12hour":false,"distance":"kilometer"}); +require('Storage').write("setting.img",setTime(1583773542.426);E.setTimeZone(0) +require('heatshrink').decompress(atob('mEwghC/AFEiAAgX/C/4SFkADBgQXFBIgECAAYSCkAWGBIoXGyQTHABBZLkUhiMRiQXLIQwVBAAZlIC44tCAAYxGIxIWFGA4XIFwwwHXBAWHGAwXHFxAwGPAYXTX44XDiAJBgIXGyDAHFAYKDMAq+EGAgXNCwwX/C453XU6IWHa6ZFCC6JJCC4hgEAAoOEC5AwIFwhgEBAgwIBoqmGGBIuFVAgXFGAwLFYAoLFGIYtFeA4MGABMpC4pICkBMGBIpGFC4SuIBIoWFAAxZLC/4X/AFQ'))); +require('Storage').write("setting.info","{\"id\":\"setting\",\"name\":\"Settings\",\"src\":\"setting.app.js\",\"icon\":\"setting.img\",\"sortorder\":-2,\"version\":\"0.05\",\"files\":\"setting.info,setting.app.js,setting.json,setting.img\"}"); +require('Storage').write("about.app.js","setTime(1583773542.703);E.setTimeZone(0)\nfunction getVersion(c,d){var b=s.readJSON(d,1),a='object'==typeof b?b.version:!1;g.drawString(a?c+' '+(a?'v'+a:'Unknown'):'NO '+c,0,y+=h)}var ENV=process.env,MEM=process.memory(),s=require('Storage');g.clear(1),g.setFont('6x8');var y=24,h=8;g.drawImage(require('heatshrink').decompress(atob('vE4gQZWg//AAI3Zh4dCoAd6wAd64Ad2j4d6l4dcn4dC6Adc+AdYv4dUggHG//kgN//AGB1WkDpkOAwsH/gDBgJ4CTRwdGl6RDl/0gHQgJeMDo2/AgcDIAIkBnAdRgJyCAAQdDlgdRgZPDgbWBDoUcDqMPRYcJgEfoA7Uh9AAgQ1BEgIdBngdRKQIACmBbB6AdB2gdRnoEDyB+C8tbbQVpgNAqOkAwMGyEQDoMB1AIBvgdDPYMC+H//7zBg//+fAA4OAgH//twDoMv/4WB3iyEAAPwHINvTYMAv/A/sC6BmBh/wDoP4gIuBdwayBAAP/DoMH4F4ToQSB+EPJQUOgKmDBgIABhAdFB4L7BgfAAYNwjpKChwJBTIQdDiAdFgHgAYIdDmDaCO4MD9Wq14dM+CdCDoU0nDjChyhBAAIdFsgdTZgaVDmPYLJk0LIodDaIcxcILRDSo80jiVECgUAvgDCmG0YQTRHDoTRBgLRCMwJDBnodDeAMDKoUvAIU/DocD6ELDoKRCAIM/LIcGG4PQUIKCBU4PzDoaEB/p3BFQKKCh9ADoXsKIVVqonCtVBoFQcAUKyFwghdB3IPBCwJZCAQMfEgQAL2AGFgZJBDoZgDABEMWYQJFgLwCkACB/gdLWYMCfoQAE35BEDpkH8EfdgYADl4mDl68BABazBFBA2CgK8CABcBUZP/8kBv58CAC1//4ABUQwASn4dgOxoALl4dC4AdYj4d6h4d+wAd6oAd2g4dCAwQA=')),120,y),g.drawString('BANGLEJS.COM',120,y-4),g.drawString('Powered by Espruino',0,y+=4+h),g.drawString('Version '+ENV.VERSION,0,y+=h),g.drawString('Commit '+ENV.GIT_COMMIT,0,y+=h),getVersion('Bootloader','boot.info'),getVersion('Launcher','launch.info'),getVersion('Settings','setting.info'),y+=h,g.drawString(MEM.total+' JS Variables available',0,y+=h),g.drawString('Storage: '+(require('Storage').getFree()>>10)+'k free',0,y+=h),ENV.STORAGE&&g.drawString(' '+(ENV.STORAGE>>10)+'k total',0,y+=h),ENV.SPIFLASH&&g.drawString('SPI Flash: '+(ENV.SPIFLASH>>10)+'k',0,y+=h),g.setFontAlign(0,-1),g.drawString(NRF.getAddress(),120,232),g.flip(),g.drawImage(require('heatshrink').decompress(atob('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')),0,135),g.flip()"); +require('Storage').write("about.img",setTime(1583773542.911);E.setTimeZone(0) +require('heatshrink').decompress(atob('mEwxH+AH4A/AH4AQqoAHFtovlFxQzOiEQF0QwJFwIwSFyIwIF6YuTGBQule7IvuEp150d5GBS+DSBwtO5wABGA4vUFxvIFwXO44wJF7hcEAAejYJQvYFpAwJF7ejRQgAHF7BcH44tLF47xGF6QtNF8l5vIqFA4gv/R/4vZABwv25ovudYwAHvIvfp+dFxlPFy4wHp9PvPHFo/HFwIvEFqYxHEINP43G4/H5vNAYIHBBgQuaGAgvEAA4vEFzIxDq0zh5YCAAvHh8zqwud/1lssPh+AF4+ABYIPBFroABnUPnPNFwvNnMPnQRDFzgvCh/OdgKMC5vOBIIvEGC4bESAeB5wAErqODGDIbGMAekFwekLw4wWDY9liAoBrpdEiASIFzdloIpBAAkQoITJF7aSERhQvUDhYATF/4v/F74A/AH4A5A='))); +require('Storage').write("about.info","{\"id\":\"about\",\"name\":\"About\",\"src\":\"about.app.js\",\"icon\":\"about.img\",\"version\":\"0.04\",\"files\":\"about.info,about.app.js,about.img\"}"); +require('Storage').write("alarm.app.js","setTime(1583773543.22);E.setTimeZone(0)\nfunction formatTime(b){var a=0|b,c=Math.round((b-a)*60);return a+':'+('0'+c).substr(-2)}function getCurrentHr(){var a=new Date;return a.getHours()+a.getMinutes()/60+a.getSeconds()/3600}function showMainMenu(){const a={'':{title:'Alarms'},'New Alarm':()=>editAlarm(-1)};return alarms.forEach((alarm,idx)=>txt=(alarm.on?'on ':'off ')+formatTime(alarm.hr),alarm.rp&&(txt+=' (repeat)'),a[txt]=function(){editAlarm(idx)};),a['< Back']=()=>load();,E.showMenu(a)}function editAlarm(g){function i(){var d=a+c/60,e=0;return d23&&(b=0),a=b,this.value=b}},Minutes:{value:c,onchange:function(a){a<0&&(a=59),a>59&&(a=0),c=a,this.value=a}},Enabled:{value:b,format:v=>v?'On':'Off',onchange:v=>b=v},Repeat:{value:b,format:v=>v?'Yes':'No',onchange:v=>f=v}};return h?e['> New Alarm']=function(){alarms.push(i()),require('Storage').write('alarm.json',JSON.stringify(alarms)),showMainMenu()}:e['> Save']=function(){alarms[g]=i(),require('Storage').write('alarm.json',JSON.stringify(alarms)),showMainMenu()},e['< Back']=showMainMenu,E.showMenu(e)}Bangle.loadWidgets(),Bangle.drawWidgets();var alarms=require('Storage').readJSON('alarm.json',1)||[];showMainMenu()"); +require('Storage').write("alarm.js","setTime(1583773543.508);E.setTimeZone(0)\nfunction formatTime(b){var a=0|b,c=Math.round((b-a)*60);return a+':'+('0'+c).substr(-2)}function getCurrentHr(){var a=new Date;return a.getHours()+a.getMinutes()/60+a.getSeconds()/3600}function showAlarm(a){function d(){Bangle.buzz(100).then(()=>setTimeout(()=>Bangle.buzz(100).then(function(){c--&&setTimeout(d,3e3)});,100);)}var b=formatTime(a.hr),c=10;a.msg&&(b+='\\n'+a.msg),E.showPrompt(b,{title:'ALARM!',buttons:{Sleep:!0,Ok:!1}}).then(function(b){c=0,b?a.hr+=.16666666666666666:(a.last=new Date().getDate(),a.rp||(a.on=!1)),require('Storage').write('alarm.json',JSON.stringify(alarms)),load()}),d()}clearInterval();var day=new Date().getDate(),hr=getCurrentHr()+1e4,alarms=require('Storage').readJSON('alarm.json',1)||[],active=alarms.filter(a=>a.on&&a.hra.hr-b.hr),showAlarm(active[0])):setTimeout(load,100)"); +require('Storage').write("alarm.json","[]"); +require('Storage').write("alarm.img",setTime(1583773543.713);E.setTimeZone(0) +require('heatshrink').decompress(atob('mEwwkGswAhiMRCCAREAo4eHBIQLEAgwYHsIJDiwHB5gACBpIhHCoYZEGA4gFCw4ABGA4HEjgXJ4IXGAwcUB4VEmf//8zogICoJIFAodMBoNDCoIADmgJB4gXIFwXDCwoABngwFC4guB4k/CQXwh4EC+YMCC44iBp4qDC4n/+gNBC41sEIJCEC4v/GAPGC4dhXYRdFC4xhCCYIXCdQRdDC5HzegQXCsxGHC45IDCwQXCUgwXHJAIXGRogXJSIIXcOw4XIPAYXcBwv/mEDBAwXOgtQC65QGC5vzoEAJAx3Nmk/mEABIiPN+dDAQIwFC4zXGFwKRCGAjvMFwQECGAgXI4YuGGAUvAgU8C4/EFwwGCAgdMC4p4EFwobFOwoXDJAIoEAApGBC4xIEABJGHGAapEAAqNBFwwXD4heI+YuBC5BIBVQhdHIw4wD5inFS4IKCCxFmigNCokzCoMzogICoIWIsMRjgPCAA3BiMWC48RBQIXJEgMRFxAJCCw4lEC44IECooOIBAaBJKwhgIAH4ACA=='))); +require('Storage').write("alarm.wid.js","setTime(1583773543.966);E.setTimeZone(0)\n(()=>{var alarms=require('Storage').readJSON('alarm.json',1)||[];if(alarms=alarms.filter(alarm=>alarm.on),!alarms.length)return;delete alarms,WIDGETS.alarm={area:'tl',width:24,draw:function(){g.setColor(-1),g.drawImage(atob('GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA'),this.x,this.y)}}})()"); +require('Storage').write("alarm.info","{\"id\":\"alarm\",\"name\":\"Alarms\",\"src\":\"alarm.app.js\",\"icon\":\"alarm.img\",\"version\":\"0.04\",\"files\":\"alarm.info,alarm.app.js,alarm.js,alarm.json,alarm.img,alarm.wid.js\"}"); +require('Storage').write("widbat.wid.js","setTime(1583773544.233);E.setTimeZone(0)\n!function(b,a){function c(){WIDGETS.bat.width=Bangle.isCharging()?56:40}function d(){var d=39,a=this.x,c=this.y;Bangle.isCharging()&&(g.setColor(b).drawImage(atob('DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg'),a,c),a+=16),g.setColor(-1),g.fillRect(a,c+2,a+d-4,c+21),g.clearRect(a+2,c+4,a+d-6,c+19),g.fillRect(a+d-3,c+10,a+d,c+14),g.setColor(b).fillRect(a+4,c+6,a+4+E.getBattery()*(d-12)/100,c+17),g.setColor(-1)}b=2016,Bangle.on('charging',function(a){a&&Bangle.buzz(),c(),Bangle.drawWidgets(),g.flip()}),Bangle.on('lcdPower',function(b){b?(WIDGETS.bat.draw(),a||(a=setInterval(d,6e4))):a&&(clearInterval(a),a=undefined)}),WIDGETS.bat={area:'tr',width:40,draw:d},c()}()"); +require('Storage').write("widbat.info","{\"id\":\"widbat\",\"name\":\"Battery Level Widget\",\"type\":\"widget\",\"version\":\"0.04\",\"files\":\"widbat.info,widbat.wid.js\"}"); +require('Storage').write("widbt.wid.js","setTime(1583773544.468);E.setTimeZone(0)\n!function(a){function c(){g.reset(),NRF.getSecurityStatus().connected?g.setColor(0,.5,1):g.setColor(.3,.3,.3),g.drawImage(a,10+this.x,2+this.y)}function b(){WIDGETS.bluetooth.draw(),g.flip()}a=E.toArrayBuffer(atob('CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==')),NRF.on('connected',b),NRF.on('disconnected',b),WIDGETS.bluetooth={area:'tr',width:24,draw:c}}()"); +require('Storage').write("widbt.info","{\"id\":\"widbt\",\"name\":\"Bluetooth Widget\",\"type\":\"widget\",\"version\":\"0.03\",\"files\":\"widbt.info,widbt.wid.js\"}"); +require('Storage').write("welcome.js","setTime(1583773544.671);E.setTimeZone(0)\neval(require('Storage').read('welcome.app.js'))"); +require('Storage').write("welcome.app.js","setTime(1583773545.108);E.setTimeZone(0)\nfunction animate(a,c){var b=setInterval(function(){if(a.length){var c=a.shift();c&&c()}else clearInterval(b)},c)}function fade(c){function b(){for(var d=a;d<240;d+=10)g.drawLine(d,0,0,d),g.drawLine(d,240,240,d);g.flip(),a++,a<10?setTimeout(b,0):c()}var a=0;b()}function move(d){if(d>0&&sceneNumber+1==scenes.length)return;if(sceneNumber=(sceneNumber+d)%scenes.length,sceneNumber<0&&(sceneNumber=0),clearInterval(),scenes[sceneNumber](),sceneNumber>1){var c=scenes.length;for(var a=0;a=1&&(clearInterval(b),setTimeout(()=>g.drawString('Open',34,144),500),setTimeout(()=>g.drawString('Hackable',34,156),1e3),setTimeout(()=>g.drawString('Smart Watch',34,168),1500))},50)},function(){function c(f){a-=b;var e=81.5;g.drawImage(d,e,a),g.clearRect(e,a+81,e+77,a+81+b),a>60?setTimeout(c,0,f):f()}var d=require('heatshrink').decompress(atob('ptRxH+qYAfvl70mj5gAC0ekvd8FkAAdz3HJAYAH4+eJXWkJJYAF0hK2vfNJaIAB5t7S3fN5/V6wAD6vOTg9SumXy2W3QAB3eXul2JdnO63XAApPEVYvAJQIACJoRQDzBLoJQ3W5/NIwr4GJohMFAAROgJYvVJQiPGABZNN3bsdvYyESwnWJSIAC3RNM3V1JjZAES4nVJSYAB4xMNJrbkE56WD5xLVdB5NbFofNJbgABJh26qREPrFXrlbAAWjFgfWJgRLaTQhMLy5KNJINhsJLDrYrD5xLC6pLa5nGTR7oLq9bJQJMKTAXWJbbnR3RLJSoRMHv4pC5rkec6SaIrBLGw2r2XW1epcoqYeJiOXJYziEsOH2RBBw7lF56Yg5nGc6FScZOGJQPX2TmDFIfVTEBMSc4hLEw5KB6+rsJMH63X6pMf5hMQzBLCq5LD1ZLEJhTlfJiWXTA2GJYpMIcwPNc2O6TAuGRIPX1igDJg/PJmyYDcgXWwxMH1ApC53XcsHAJiVYcg2HJYZME0YpC5vWJkhLNJgLlDTAeFJhF/FQfVJkG6JiGXcomyJgOrJYhMErYqD53NJj7lRzBMDcoeGJhzoBJb3GJiN1qZBCJgWyJYpNF1LigAAXAJiNSJgzlGJgt/JkZLRy9TJgeHJhznFcuSZGw5MHJomjcuhLBqdcJiSaiTChMV1CYxy5LCqdXIAWy6+rJhCalTCN2JgdYH4WHJiGpTF7kDc43W2RMJTUZLQzBLFc4mr6+GJh2jTFmXJYyaEwuyc5Sag4xLZTQmG2WFJhxNaJYZMLJZSaEJoOHTR9/Ja+6JbdTqRNETRRNF1JLV4BLcAANYI5ToK1BLYJhWYJZwABq5NoJZ91JaAABdAZNS0ZLey9SJaRNYv5KM426JZmXuxKUJrKcL0lTzBLKzBKYJrVXvfGSol7EYWXJI27zF1JLQADq5NUrgYB4wAEEIV0comXI7wAFrCcPJgYWBTIIAETIN2JYmWuhMkdSdYCgOeJgueqRLFyzhfTi9bq4TC45MF49TuuXJlpONcogAC0hKB0gHDvZMEqRMpAANSq9crlbJAYADqwRDxGk0mIA4eCTQOeveXJdYAHqxNFdAeIAAQGCrOI0oHEAGVXTRJMGvgGCwRM7TAZMHwQGCvhM1rBMERIhMGAwdZJmtSqVTwNcwJEDJg19cvIADa4d9JhANDJnSLHJgrl6AAhFFAwpZDegjn7vhMGcvwABrJAFJgjl/TQpBBI4jl/AAN8TQhHDcv4ADcJBMDvpM+IYaeDAAhL+qd9SgycEJn7iEAA18Jf7nEcv4AIrJLIcv6aMcv4ADvhMHrJJ/AAbl/c6ZM/AAt9cv7nSIv7nLcv4AHrLl/TRpJBvgnjA=='));g.reset(),g.setColor('#6633ff'),g.setBgColor('#6633ff');var a=240,b=5;fade(function(){c(function(){g.setColor(-1),g.setFont('6x8',3),g.setFontAlign(0,0),g.drawString('Welcome.',120,160)})}),setTimeout(function(){var a=0,b=setInterval(function(){a+=5,g.scroll(0,-5),a>170&&clearInterval(b)},20)},3500)},function(){g.reset(),g.setBgColor('#ffa800'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var a=80,b=35,c=35;animate([()=>g.drawString('Your',a,b+=c),()=>g.drawString('Bangle.js',a,b+=c),()=>g.drawString('has',a,b+=c),()=>g.drawString('3 buttons',a,b+=c),()=>g.setFont('Vector',36),g.drawString('1',200,40);,()=>g.drawString('2',200,120),()=>g.drawString('3',200,200)],200)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('1',200,40),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('Move up\\nin menus\\n\\nTurn Bangle.js on\\nif it was off',20,40)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('2',200,120),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('Select menu\\nitem\\n\\nLaunch app\\nwhen watch\\nis showing',20,70)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('3',200,200),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('Move down\\nin menus\\n\\nLong press\\nto exit app\\nand go back\\nto clock',20,100)},function(){g.reset(),g.setBgColor('#ff3300'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('1',200,40),g.drawString('2',200,120),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('If Bangle.js\\never stops,\\nhold buttons\\n1 and 2 for\\naround six\\nseconds.\\n\\n\\n\\nBangle.js will\\nthen reboot.',20,20)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var a=120,b=10,c=21;animate([()=>g.drawString('Bangle.js has a',a,b+=c),g.drawString('simple touchscreen',a,b+=c);,0,0,()=>g.drawString(\"It'll detect touch\",a,b+=c*2),g.drawString('on left and right',a,b+=c);,0,0,()=>g.drawString('Horizontal swipes',a,b+=c*2),g.drawString('work too. Try now',a,b+=c),g.drawString('to change page.',a,b+=c);],300)},function(){g.reset(),g.setBgColor('#339900'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var a=120,b=10,c=21;animate([()=>g.drawString('Bangle.js',a,b+=c),g.drawString('comes with',a,b+=c),g.drawString('a few simple',a,b+=c),g.drawString('apps installed',a,b+=c);,0,0,()=>g.drawString('To add more, visit',a,b+=c*2),g.drawString('banglejs.com/apps',a,b+=c),g.drawString('with a Bluetooth',a,b+=c),g.drawString('capable device',a,b+=c);],400)},function(){function f(){function c(b,c,a){var d;return d=b*i+a*j,a=a*i-b*j,b=d,d=c*f+a*h,a=a*f-c*h,c=d,a+=4,[96*(.5+b/a),96*(.5+c/a)]}d+=.1,e+=.11;var f=Math.cos(d),h=Math.sin(d),i=Math.cos(e),j=Math.sin(e),b;a.clear(),b=c(-1,-1,-1),a.moveTo(b[0],b[1]),b=c(1,-1,-1),a.lineTo(b[0],b[1]),b=c(1,1,-1),a.lineTo(b[0],b[1]),b=c(-1,1,-1),a.lineTo(b[0],b[1]),b=c(-1,-1,-1),a.lineTo(b[0],b[1]),b=c(-1,-1,1),a.moveTo(b[0],b[1]),b=c(1,-1,1),a.lineTo(b[0],b[1]),b=c(1,1,1),a.lineTo(b[0],b[1]),b=c(-1,1,1),a.lineTo(b[0],b[1]),b=c(-1,-1,1),a.lineTo(b[0],b[1]),b=c(-1,-1,-1),a.moveTo(b[0],b[1]),b=c(-1,-1,1),a.lineTo(b[0],b[1]),b=c(1,-1,-1),a.moveTo(b[0],b[1]),b=c(1,-1,1),a.lineTo(b[0],b[1]),b=c(1,1,-1),a.moveTo(b[0],b[1]),b=c(1,1,1),a.lineTo(b[0],b[1]),b=c(-1,1,-1),a.moveTo(b[0],b[1]),b=c(-1,1,1),a.lineTo(b[0],b[1]),g.drawImage({width:96,height:96,buffer:a.buffer},72,68)}g.reset(),g.setBgColor('#990066'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var c=120,b=10,a=21;g.drawString('You can also make',c,b+=a),g.drawString('your own apps!',c,b+=a),b=160,g.drawString('Check out',c,b+=a),g.drawString('banglejs.com',c,b+=a);var d=0,e=0,a=Graphics.createArrayBuffer(96,96,1,{msb:!0});setInterval(f,50)},function(){g.reset(),g.setBgColor('#660099'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',36),g.drawString('2',200,120),g.setFont('6x8',2);var a=90,b=30,c=21;animate([()=>g.drawString(\"That's it!\",a,b+=c),()=>g.drawString('Press',a,b+=c*3),g.drawString('Button 2',a,b+=c),g.drawString('to start',a,b+=c),g.drawString('Bangle.js',a,b+=c);],400)}],sceneNumber=0;Bangle.on('swipe',move),setWatch(()=>move(1),BTN3,{repeat:!0}),setWatch(()=>if(sceneNumber==scenes.length-1){var settings=require('Storage').readJSON('setting.json',1)||{};settings.welcomed=!0,require('Storage').write('setting.json',settings),load()},BTN2,{repeat:!0,edge:'rising'}),setWatch(()=>move(-1),BTN1,{repeat:!0}),Bangle.setLCDTimeout(0),Bangle.setLCDPower(1),move(0)"); +require('Storage').write("welcome.img",setTime(1583773545.313);E.setTimeZone(0) +require('heatshrink').decompress(atob('mEwxH+AH4A/AH4AU5gAEFtoxnEwXN53WAAXO5oJB42Wy26AAIueFoPXFggAD4AwEGTQiB6otBFgwAD3QvFGC5dCFxiRGGClhrdbv67BXAIuLMBIwPsIABF4OpLwXOFxjBCF6gtBw2r1mHXoXWFxqQWFwOH62rL4IeB6xeOAAIvHGBYuC6+rR4QvCXpovXw3X1i/DR4QuPR5AvKFQOs6+GF4eod4IvPd5AvLwvWLwQvCv4fBR54vURwOHF4iQCX0yOCF4aQBX0QvHSAoAN3SOSd4WyF4yQPLyhgD1YvDMCJeIFxhgCF47BN4BeHFxpgDSAiRORpAuPMIYAFGBYuaF5aSHFwQvEFqQwOeggSBLa4xNF4X+4wAC/xeCFjIADrYwGBIIvlMQiPDBAOk0gDBz2XF8BlEF4eIxADFF8lcF9n+wIrFF05bHF9AsGF9wupGAYv/F8QupGAov/F/4wOF1gA/AH4Ap'))); +require('Storage').write("welcome.info","{\"id\":\"welcome\",\"name\":\"Welcome\",\"src\":\"welcome.app.js\",\"icon\":\"welcome.img\",\"version\":\"0.04\",\"files\":\"welcome.info,welcome.js,welcome.app.js,welcome.img\"}"); From b64ddff607eafd4e8567d9552f8bb11239d43597 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 10 Mar 2020 10:23:02 +0000 Subject: [PATCH 42/55] Final pixels --- apps/about/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/about/app.js b/apps/about/app.js index 7f794583f..dc7b0cad8 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -29,5 +29,5 @@ g.drawString(NRF.getAddress(),120,232); g.flip(); // Pixel chooser image -g.drawImage(require("heatshrink").decompress(atob("+FQgl+xnu8AIBwGQgHuAoN3gF/hcLgEHu943G3gHdhvdDwIBCAAV3uEAhoBBhsO90OgHgoACBh0IhP5AAQZD8Hw+GwAwXn4AECxGAh0MEAOeJAMP3+/Lw0GswGEHgMM9gCBAIX//5PBhvQ7gJBxAAB9ng8vs5nMDgOg8HnOwIBBgBHDAAfQNAJBBgBQDgF4HQfd7veKoKbBO4Pr30IEAhgBAIIAG3oJDx+AQwLBBYgR3JsABCzOQzOeO4cP4HPc4QCBPoPN4HNO4QoB9wAByDvBO4L2COwZ4Gd4UP/7vEf4LvGKoUAooDB9x3FgEQI4TwBgEIN4NpwEMXILvBO4bvD/Y3BO46eDgGdO4n8CoXw+cQh/w/kNd4fodoXJhLvCKYJ4Dhe7AYJXFwBHBUAgABewMPhvQd4bwB8FQqDvHO4YADhH4B4XM9nABQTsCAAf/awbXBO4Vmd4xED57vD+EwFgOIBoUNxv/1////5zOAy8AvPN6AQCbQIiCOIIKB7EILwZIEO4YACKYlFoB3CHIZ2CAIJHBEAToCMwLvBAArvCAAnAAALvDAIIPByA5BEQUM/n8O4TzCAAQtBhvd/X8d4YYBvwOBO4bBFO4b2D4ASELoP/d4IbGABMBiINLV4YAD9LyFO5bvCYYfPCARKBmAcDh3ud4Wt7vdDgONwF8O4Q8Bh5jCBAOPO4o0BgFAAoLcB/4UBLIgBDAAPI5DeKIQIDChcLL4IABGIOAJITvHAAkGs0HgG7AAO99p3Dhi2N43N7rLCxGHgF56AHCRwUwAYIlBhsNGoR3CqALCh54CFAXHAIg/CRAIDBIgtHGIR3D3ZhCWwXQwA1CAAMP5/M/nPMhp3BwAJGWIQ7Dgczt1pzIHCa4IABhpkBOgQACD4ZRCs1m4AyEO4IBBABUMXYYZDgEEvoRFd4TwBO5IAJ5nAFAMNTYZEBGgRiD7p0CO4nM43JmZABAIICBAAOA+HwgUgkEiGxFsAQOwGQLeBhPpz2QChEO8AoCd4R5CdwZpCNgdVqq0B7vQ7vdMQWIbYJkFAAIjBEoR3DCoOA8A3CYAOvh/wgH/d4hVBd4VAgn/eIYAGX4cAgw2DNQ2e9I0DBgxIBxGAWgS1DAAZrBLAi2DeAJwDOoLcFNQOA5jbCd4gACO4OgAgMHu4aBDokKgGIZ4LtBogABBgXw4HwhnL5lwEQRmJb4bvBO4/uIAfQKAJ3JhvX67kCO5oeCO4YHBXAQCBO4yvBNYIVDNwIBBhWq0HDwEOCIPuoDtIhruDeAgAEg5/IfgZ9BFYKHBd5hrBAQZ3GfYLvI5nMd4fAeILvB6A2BAIQ5BgDwCAAkKBAXAxDdCb4yfBLgJ3Cd5BqCu1gd4QAGHQaLJDgQPEhoxDACJ3BBZPwAAIDBd4TwDXwbvFO5LvQhnMu1wNQoABBAMOM4RqDuFwY4IUEGpKUCcYPwAQIXEAAnu9wbJBQPg+ArCcoIBBhkMMoqCBO4IVBEYfuNYsNLISHDZYkM/93CgmIOwJtBh3uAIPuNQZ3BLwsOSYuIAIOABYPex2P9+JxncZAJcCO5VgXYRPCWQQzF4AABDohHB5gACBYPeSAYAHdwcJQYfc/OQIAQZBwB2BABQMBhiBBcQYNEcgMA/Hwd5GoxWI1AqKsy7CcIoAGBosOh7WChuNAYXvL4IYFh/wE4otGO4Pt9pfBd4I3Hf4TlD5x9DAAsId4jYBB4NwgwFBd4LxCIoQcGdwJIBdAoAHBongD4PghMN7oIBdwK9GGIMP4AaEhpeDdAICBd4bIBh/PAAXMNgVwsAYC5nOV4OXFwg3Bd4QADs8HsF2g1QSwQWFC4IAERILhD/5cHMAgEFg2AzuNV4bvFhp3C5igN73u6DQBMwIAC/4/BcgaQDhwtBO4O72AgEd4IADqEFAQgbDY4RcCJALwGBgSdFwEMg6XBBgIXDO4WJhuNHQyOF+DvFAAwLB9vdVg7vJAAeXhbuEbAUIwABBVJfQVALvCgcDd4Z3HEAYDBg63DYQgRCzp1BGwpQGgGgAAIGD93tBwp2B8B5HAAKwBAQInFO4gAEhAACLQJKCAYSGCO4TrBdgjuE24uB/7uCMQTvE+CFDD4eIhvdxCuMO4OqO4MOhxtH93u8ABBD5jdGO4XAIYQDBd5/dAogZBmAHEO4QABhOZyAEBxB3Bd43QhoCB/GIUYYAEQIMPTQMAhTvGu/uJorvCQgIADHQMMA4mIFw272CHGeISYME4IABgEDJQQlFHoh3CAAjoBAIJ3Ex+PLwNwSYYTCz8P5/QDwpsCuEHO4j5Cd4XAJAPAO45kF/6uDdgPA7vdO4QpB8A4GABg3BACJ2COoIBCxH4wEM28A5hYCgEGszvCH4sO9yMBu7vFHwR6B4AACyH/YwPM5g/HgZ3DAAZDBF4YFCP4OAwD4GJgQCBhkJJQquGAwqpBVgZIBhjvChfLuAICTKGIwBSDhoEB9yEBNwMM4GfgH8hnPO4wuBmB3EIYIfCTYivBhAwBfAQABuA/GVAKKCADH4xHwhm8RYSICAALNIO4vQfgZfB8Hgd5H//gqBeYIrB5fLF4gAC6ENzIQBd453FYoUPO4ZUBCQMP/5SLuHwSg5UBAoggBxCiEJoe8714zUQCYbvBO4pDFXwRPBd4UOfwIzB5e7O44ABzP/LYp3CPAIHCu4XGhgiBBwR3IRQcP54ECyEJzJ3DkYUDGIIABRQTvJhvcZghFCu4XBZgRKGbQQAEO4m7hewGIIAEEJJjIKASKDNwh3Id4cJhJ5BOoMOgE9mAQCxGAd4jBHDAMN3p2Dd4Z+FSYThHhYDCnm8AgWwPAIVB/nM9nDO5kP//wBZD+DF4kPOoIBBC4rtCLwMO8EAgchd4w6JzwYBhHdegYkBO4oMDJwxKEgcAQgZ3D5//53Onk8O4a+BAIO62DbJwEJKIMIZoa1D+AABR4X/O4jvDO4PHyEQu0GfoIADegIAB5vmwGrd4YADSYMGy2WO4jODd4j5EAA52BMwLvB53uO4MNTIUBgIRB1WgCwXuEZYABg4EDHYI9CXAK6FLQcOO4IFBsACBGoMRgGHO4mJO4IAChkKyENNoTvFKwLGHhh5BhnMPoQEDBAnM5jvB4YIBFQUQ+EQd4vgV4LuDAAI0F6DUDO5eZzIFDO4TvDGYIBBd4OHw53BxR3E4GqyHA2ArBgwJBhe7XRH/O4UAhzONAAp3Bh8B+KWBAAnu8CRCAAVVgtQAoULeAq3GABOOSwp3DBIMICg0LW4MJyEIBoTvC38vYgeQyGZBYI3BfAx/DO5wcBSoLsDEILuBhn8BQdA+FAeIw/DBAbuDuEHf4adDbgQBB4IiF2ELbwQBBAwIMDEAuy+R3DOgJ4BO4vQIwfMGQJdB5nM55rELYo4CAAXvO4cIxDdEbw5MDO4n/PAMHAAQJCg/ud4UMAAYMCzOIwB3CEwWwO4oABJQbvFAAg3BHAPgFIKpDO4TgB//5RYIABjUAhUQeAYABxAeC7qWDABJXDOwYABBAsHu7vEAwIbD5h3FhKCBd45qD7ACB1StDBwK4CXY7vGO4cJzOZznMKgoUBO4g/BLYp5MO4sNO4UODYbuCKITvB54TBd453Fd48NhADBZwSnD/7aBh7KBOYZNNhx9CAAQoCO4uIOCIbCAAaiBI4Xg8AUGaoLvB4HwO4bzB34MBhI3BhZxBd4YGBd4t3agRCI7sNAAJsDAQMMN4oKB5jvEAAUNSIhkBh7tDAIcADQuIAALMBd4YBCh0JeAZ3G93Ah7RDAAO7+EJd4QAKd4IOB9x3LOwoADOwxJB5wgBhZHEAYq3B+Hw/8AuAIBAQScBDQQBBd4RtBF4OQAALvOzJ2DRATvCzJ3McQh3BhIfCZghrH7Z3CPAZEC+P4ZwwAHh7vBh/wg4ABTgpRBAIPuEwXteAhlEAAkL3YEC/PwAgW5VoYAGFIYACJ4nMRYIxCc4vMNgUJm4MBIoR3DhxFC/8QDAYiBu7cBRIdwUwLvBAAp3DdwYlBNga3LAA7vHLIZmBBQYMEhGIAodVDwQfB7sNHAf/JgUJMIML7wGBMogACiMf/4VBhKZBuFwhgODuHQE4LwBgDvFCIO7hbNCYokNAgMLXYUPAAp4G+xPCd4vHvgSGPIbvEAAKVCGITwDUAcJ06uHEQSsFhZ3Cd4ZBCO4bqCuAJCO4ULhZ4Bd4Y7C4AqCCQQAK+B9B/9gIQ53FwBxEhAFB5ncDYIsMAA5CD8DCBAQQADd5AFB7ruCh7sBAIaQCAARMBhAzGd52ZzMAsx3CYAZFB5nMTQTMFBgOAJQPQBghYCAQJBBO5wAKIQNwg7vBO4buBABewAAK+DGime9L0DNoI2BeQXAWoZ2Ef4Z3ILAMJyG5IQKoD9wABgHN8F5f5wAGcgJ3GdocAgjuDABLvCdQcGAoh3Fh/vdIJ3CcQLbFPAgAD5ncgEKAIPdRoMJCoJCD/4CBEYIaB4HguGgKBYDGTAKBKfIYQBCQnwaoICCd49gsDKGzLvHKYQADxAIC8HuAQINDd4Wg0HQ5j4ByAaEHoTvFO4OwMouYmcwh//AIIKDhByGZgZ3Bg7dBgxoFCAWACYjoDh7uBgwGDBocN5YfFhz1Bg4GCxOAd5B3BOILwBd4PMZJQAOxEwRoJFCqACBxw3DAASEEd4I7BAwQ4Sd46OCLQIAHO4cIH4R2BPAwAHgYIHhpODO55qBMwMI9HoeYZBC5kM4DvEZ4XAxGAg93zLeC3ew2DwFdwIFEO4kJFoRxDFoQFDBwMA8B2ChjrBAAaAFyBeBAA3QzOZOxQrBUoLvDVYXdSIR3DhnMAALvC6Hgd4YQCIAXwgELfCMPqAcCuF3O4l3AwgAF4AABIQJ3HyYCB1MK7gOCYwOQB4cMNYP/WoYMByDtBBAQHBhv9/p3FOwXMeAK6ChKMCKYV5U4Z3Bd4bqDAAZ3F81wdA14KQggEd4ZlBhn8Qg7vCyGQ6EMgF3O4LvLhQEDxEIMAOgO4MPDQJ3G553DABC4EO4zvM8HgFoQAB+CiBHoIgCAQbwFPQcAgjvHSgPQCINwvvQgEJhe7AAIbBhIWCGARrCwACBKoPd+H9DQJ3DGgPMVwfHyBwEO4ziDWoLvJCgXw9wDBO4f/gHcSYcMDwT0CAAgJDolANAPpeQgfBDQNwuDvD2CaC4HACALuEd4iRB7vzO4MIhEHJITwCZIMMvLYIgf/+RwBaoLWBAYQAHhwLBd4YACqHwAILlFAILyHPAUEAAIkBTIQAGO4QXDO4wAJdQMN7vddwOIg93XIXMhxRBdwIcJ+Hw/7iChnsBgkNhsMHoUOCAJ3BegQABgtVNQwzBAYMLWYIADO4VAOwNAd4oAEKwR3GgEJWwaREVAS6EAA4PCOA7KEO4QDBAIIjBSIPMDYxyDhaCBb4zvJ9wAE2C4CO4IAGFQPgLoVt5nODoJ3B3YTGWQhnIBQkMQoSGMAAwXCh///5/BNgJtC7q9D2HQ2G9BAT/BhLDChgfCCYYADSwZ3I93gAIJ3FABMO7wECCoJmMhkN7o2ChOQzOQcgQAD3ewKYJVFg93u9wEgp3Dd4R6CVYXA2GQgyLCfhTvHyBZCO5vvvaVBD4QkE9wRE/5mDAQR3BhoWCOgIBBAA2q0D3Md4IOMABBPDO5DvGO47YIh8O+65GNAQRF/7dFgHMd4mIwABBQoISEBAMOAAUA8DjDAA/MAYRAF7rxCABsPd5oAN995Z4mAwHM4AQF/+IO4wAGyDvFepB3BgBhCNYNwg93hGIgHAGoUHCwibDoAeDagQXBAIIRCC4h3EgxRLXQQLIhDUBO4cIhZ3Bd44AFzJxDCIMM/IxEd4kNDIsHg8IAgJ3DeAt3AoJiBRIUO9zFDJwIAB2BIJ8C2JIogMJwBBEAAMwaQoAQHBYAChruBd4QHB5iBECgzaCN4MMCQTvF35mGQYR3Ex2wAYP8O4gvG9ns8GIwEMO4cLeAQlCO4hNHAAS4CHAQaBhgACd4sOuHnd4RdDdwYBBCwK+GRIOIJALuBSQUPIQV3DIIABhGZwB3EP4UGRAjXEhp9CdQruI9x4BDIPgEwUA3YABNwQAC4GQHIOwV4QAUUIRpBAwUGKwLvCxjvGVgVwTYIfDBgJvExx3Cd4gBCAAPdpxjCHwigBhLwCBQnuUoVQHARqBAARCDhn5DQIABDIUEYAbnFABDuCAAIJEDIUM5iPKO4tAgGQMIbvGhwACdwR/Dd4MHu48Bh5oCAAkOd4cwbogEBdwgABdwLvJIAJCCdxjvEP4NgB4mIDpF3AAJBCHoZ3EBQTvDc4TwDBIh1BO4X/O44FEfgLvEO4JuHQIQoBd4Z3Gh8Pdw4ABdwqWGS5LuEADp3CBQ/uCpLvH5n5eASQBSIuIaIsP+BCOMoUIDwcIhGIO6DFDABpLEuAhC/4ABDJpXBhe7gG7dw4AC8AABaAjPIAAmgdZoDCAoX8ShIJEzOZXAetFZTDFX4f/FZHP/ieQFQgrFO4g2HTQOqEBLpBeAPAPonAAwTNBKwnvd5Pb6ADB9wACFALDBIALEGAA71C4EMVBAAMFIcLO4o0EKgMPhcz9zEKOIMMHYI8DXAcHg8AxApCIwIHBAAzvEOIUAu9wO40IO5EJzIoBd4p3Fh3dAwg7Eh6TCuDFEhxRDd4uu3QFBokEoEA9RHCY4J1BhnMHYbvCuGAvAPBeoZlBH4V3GYOOXgsOFAJNBO4YSB+/3MgPMhJLBJoUJ/JvFgcAmAHE93QOoZtBAQSKDhcIeAKHIgHA53u93qeAVAAAJWB1wRDd4wAEsEIO4MGs1mu4ABHQQCBhHIO4wDB2GwG4Pu8BRBv9/CwMM/ON6ABBd4h3KhzvEOgMHAQKeBO4TvGIwQAD5nA8Hg92u1R3BAITwEd4Z3Hg0GgGIgB2BO4d2IITvJO4ZDEKQKRCd40P/+QGwsiAwsOd4hnCOAQbBKYLuLMoJFB9wA=")),0,135); +g.drawImage(require("heatshrink").decompress(atob("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")),0,135); g.flip(); From af686919a1a9ff6824384100368f87a926d56b8a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 10 Mar 2020 12:35:45 +0000 Subject: [PATCH 43/55] Remove distance setting as there's a separate app for Locale now --- apps.json | 2 +- apps/setting/ChangeLog | 1 + apps/setting/settings-default.json | 1 - apps/setting/settings.js | 11 +---------- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index 10341b54f..f8188e88d 100644 --- a/apps.json +++ b/apps.json @@ -92,7 +92,7 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.05", + "version":"0.06", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "storage": [ diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index b23865f81..1485d5c12 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -2,3 +2,4 @@ 0.03: Add support for Welcome app 0.04: Add setting to disable log messages 0.05: Fix Settings json +0.06: Remove distance setting as there's a separate app for Locale now diff --git a/apps/setting/settings-default.json b/apps/setting/settings-default.json index efaf83bc3..2fa66cbdd 100644 --- a/apps/setting/settings-default.json +++ b/apps/setting/settings-default.json @@ -9,6 +9,5 @@ HID : false, // BLE HID mode, off by default clock: null, // a string for the default clock's name "12hour" : false, // 12 or 24 hour clock? - distance : "kilometer" // or "mile" // welcomed : undefined/true (whether welcome app should show) } diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 94a2a2d94..49af98318 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -21,7 +21,6 @@ function resetSettings() { HID : false, // BLE HID mode, off by default clock: null, // a string for the default clock's name "12hour" : false, // 12 or 24 hour clock? - distance : "kilometer" // or "mile" // welcomed : undefined/true (whether welcome app should show) }; updateSettings(); @@ -141,15 +140,7 @@ function showLocaleMenu() { settings["12hour"] = v; updateSettings(); } - }, - 'Distance/Speed': { - value: settings.distance=="mile", - format: v => v?"mile":"km", - onchange: v => { - settings.distance = v?"mile":"kilometer"; - updateSettings(); - } - }, + } }; return E.showMenu(localemenu); } From 503e370f70b23be8b1fe1c2b1b1bb25637181c08 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 10 Mar 2020 15:33:41 +0000 Subject: [PATCH 44/55] firmware tweaks --- bin/firmwaremaker.js | 13 ++++++++---- firmware.js | 47 +++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 8d52bd33f..13d4504ec 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -23,14 +23,16 @@ var appfiles = []; function fileGetter(url) { console.log("Loading "+url) if (MINIFY) { - if (url.endsWith(".js")) { + /*if (url.endsWith(".js")) { var f = url.slice(0,-3); console.log("MINIFYING "+f); const execSync = require('child_process').execSync; - code = execSync(`espruino --board BANGLEJS --minify ${f}.js -o ${f}.min.js`); + // --config PRETOKENISE=true + // --minify + code = execSync(`espruino --config SET_TIME_ON_WRITE=false --minify --board BANGLEJS ${f}.js -o ${f}.min.js`); console.log(code.toString()); url = f+".min.js"; - } + }*/ if (url.endsWith(".json")) { var f = url.slice(0,-5); console.log("MINIFYING JSON "+f); @@ -52,9 +54,12 @@ Promise.all(APPS.map(appid => { }); })).then(() => { //console.log(appfiles); - var js = "// Generated by BangleApps/bin/firmwaremaker.js\n"; + var js = "// Generated by BangleApps/bin/firmwaremaker.js\nreset(1)\nvar FAIL=0;\n"; appfiles.forEach((file) => { js += file.cmd+"\n"; + /*if (file.crc && file.evaluate!==true) { + js += `\x10if (E.CRC32(require('Storage').read(${JSON.stringify(file.name)}))!=${file.crc}){console.log("${file.name} invalid");FAIL++}\n`; + }*/ }); fs.writeFileSync(OUTFILE, js); console.log("Output written to "+OUTFILE); diff --git a/firmware.js b/firmware.js index 5bc1e222d..2a3a697a3 100644 --- a/firmware.js +++ b/firmware.js @@ -1,35 +1,32 @@ // Generated by BangleApps/bin/firmwaremaker.js -require('Storage').write(".boot0","setTime(1583773540.682);E.setTimeZone(0)\nE.setFlags({pretokenise:1});var s=require('Storage').readJSON('setting.json',1)||{};s.ble!==!1&&s.HID&&(Bangle.HID=E.toUint8Array(atob('BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==')),NRF.setServices({},{uart:!0,hid:Bangle.HID})),s.blerepl===!1?s.log?Terminal.setConsole(!0):E.setConsole(null,{force:!0}):s.log?Terminal.setConsole():Bluetooth.setConsole(!0),s.ble===!1&&!NRF.getSecurityStatus().connected&&NRF.sleep(),s.vibrate||(Bangle.buzz=Promise.resolve),s.beep||(Bangle.beep=Promise.resolve),Bangle.setLCDTimeout(s.timeout),s.timeout||Bangle.setLCDPower(1),E.setTimeZone(s.timezone),delete s;var alarms=require('Storage').readJSON('alarm.json',1)||[],time=new Date,active=alarms.filter(a=>a.on&&a.last!=time.getDate());if(active.length){active=active.sort((a,b)=>a.hr-b.hr);var hr=time.getHours()+time.getMinutes()/60+time.getSeconds()/3600;if(!require('Storage').read('alarm.js'))console.log('No alarm app!'),require('Storage').write('alarm.json','[]');else{var t=36e5*(active[0].hr-hr);t<1e3&&(t=1e3),setTimeout(function(){load('alarm.js')},t)}}"); -require('Storage').write(".bootcde","setTime(1583773540.935);E.setTimeZone(0)\nvar settings=require('Storage').readJSON('setting.json',1)||{};if(!settings.welcomed&&require('Storage').read('welcome.js')!==undefined)setTimeout(()=>load('welcome.js'));else{var clockApp=settings.clock;if(clockApp&&(clockApp=require('Storage').read(clockApp)),!clockApp){var clockApps=require('Storage').list(/\\.info$/).map(app=>require('Storage').readJSON(app,1)||{}).filter(app=>app.type=='clock').sort((a,b)=>a.sortorder-b.sortorder);clockApps&&clockApps.length>0&&(clockApp=require('Storage').read(clockApps[0].src)),delete clockApps}clockApp||(clockApp='E.showMessage(\"No Clock Found\")'),delete settings,new Date().getFullYear()==1970?(E.showMessage('Searching for\\nGPS time'),Bangle.on('GPS',function cb(g){if(Bangle.setGPSPower(0),Bangle.removeListener('GPS',cb),!g.time||g.time.getFullYear()<2e3||g.time.getFullYear()==2250){eval(clockApp),delete clockApp;return}setTime(g.time.getTime()/1e3),load()}),Bangle.setGPSPower(1)):(eval(clockApp),delete clockApp)}"); +reset(1) +var FAIL=0; +require('Storage').write(".boot0","// This ALWAYS runs at boot\nE.setFlags({pretokenise:1});\n// Load settings...\nvar s = require('Storage').readJSON('setting.json',1)||{};\nif (s.ble!==false) {\n if (s.HID) { // Human interface device\n Bangle.HID = E.toUint8Array(atob(\"BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==\"));\n NRF.setServices({}, {uart:true, hid:Bangle.HID});\n }\n}\nif (s.blerepl===false) { // If not programmable, force terminal off Bluetooth\n if (s.log) Terminal.setConsole(true); // if showing debug, force REPL onto terminal\n else E.setConsole(null,{force:true}); // on new (2v05+) firmware we have E.setConsole which allows a 'null' console\n} else {\n if (s.log) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection)\n else Bluetooth.setConsole(true); // else if no debug, force REPL to Bluetooth\n}\n// we just reset, so BLE should be on.\n// Don't disconnect if something is already connected to us\nif (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep();\n// Set time, vibrate, beep, etc\nif (!s.vibrate) Bangle.buzz=Promise.resolve;\nif (!s.beep) Bangle.beep=Promise.resolve;\nBangle.setLCDTimeout(s.timeout);\nif (!s.timeout) Bangle.setLCDPower(1);\nE.setTimeZone(s.timezone);\ndelete s;\n// check for alarms\nvar alarms = require('Storage').readJSON('alarm.json',1)||[];\nvar time = new Date();\nvar active = alarms.filter(a=>a.on&&(a.last!=time.getDate()));\nif (active.length) {\n active = active.sort((a,b)=>a.hr-b.hr);\n var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);\n if (!require('Storage').read(\"alarm.js\")) {\n console.log(\"No alarm app!\");\n require('Storage').write('alarm.json',\"[]\")\n } else {\n var t = 3600000*(active[0].hr-hr);\n if (t<1000) t=1000;\n /* execute alarm at the correct time. We avoid execing immediately\n since this code will get called AGAIN when alarm.js is loaded. alarm.js\n will then clearInterval() to get rid of this call so it can proceed\n normally. */\n setTimeout(function() {\n load(\"alarm.js\");\n },t);\n }\n}\n"); +require('Storage').write(".bootcde","// This runs after a 'fresh' boot\nvar settings=require(\"Storage\").readJSON('setting.json',1)||{};\nif (!settings.welcomed && require(\"Storage\").read(\"welcome.js\")!==undefined) {\n setTimeout(()=>load(\"welcome.js\"));\n} else {\n // load clock if specified\n var clockApp = settings.clock;\n if (clockApp) clockApp = require(\"Storage\").read(clockApp)\n if (!clockApp) {\n var clockApps = require(\"Storage\").list(/\\.info$/).map(app=>require(\"Storage\").readJSON(app,1)||{}).filter(app=>app.type==\"clock\").sort((a, b) => a.sortorder - b.sortorder);\n if (clockApps && clockApps.length > 0)\n clockApp = require(\"Storage\").read(clockApps[0].src);\n delete clockApps;\n }\n if (!clockApp) clockApp='E.showMessage(\"No Clock Found\")';\n delete settings;\n // check to see if our clock is wrong - if it is use GPS time\n if ((new Date()).getFullYear()==1970) {\n E.showMessage(\"Searching for\\nGPS time\");\n Bangle.on('GPS',function cb(g) {\n Bangle.setGPSPower(0);\n Bangle.removeListener(\"GPS\",cb);\n if (!g.time || (g.time.getFullYear()<2000) ||\n (g.time.getFullYear()==2250)) {\n // GPS receiver's time not set - just boot clock anyway\n eval(clockApp);delete clockApp;\n return;\n }\n // We have a GPS time. Set time and reboot (to load alarms properly)\n setTime(g.time.getTime()/1000);\n load();\n });\n Bangle.setGPSPower(1);\n } else {\n eval(clockApp);\n delete clockApp;\n }\n}\n"); require('Storage').write("boot.info","{\"id\":\"boot\",\"name\":\"Bootloader\",\"type\":\"bootloader\",\"sortorder\":-10,\"version\":\"0.09\",\"files\":\"boot.info,.boot0,.bootcde\"}"); -require('Storage').write("launch.app.js","setTime(1583773541.231);E.setTimeZone(0)\nfunction drawMenu(){g.setFont('6x8',2),g.setFontAlign(-1,0);var c=3;selected>=c+menuScroll&&(menuScroll=1+selected-c),selectedc+menuScroll?g.fillPoly([120,239,100,219,140,219]):g.clearRect(100,219,140,239);for(var b=0;bs.readJSON(app,1)||{name:'DEAD: '+app.substr(1)}).filter(app=>app.type=='app'||app.type=='clock'||!app.type);apps.sort((a,b)=>{var n=(0|a.sortorder)-(0|b.sortorder);return n?n:a.nameb.name?1:0});var selected=0,menuScroll=0,menuShowing=!1;drawMenu(),setWatch(function(){selected>0&&(selected--,drawMenu())},BTN1,{repeat:!0}),setWatch(function(){selected+1s.readJSON(app,1)||{name:\"DEAD: \"+app.substr(1)}).filter(app=>app.type==\"app\" || app.type==\"clock\" || !app.type);\napps.sort((a,b)=>{\n var n=(0|a.sortorder)-(0|b.sortorder);\n if (n) return n; // do sortorder first\n if (a.nameb.name) return 1;\n return 0;\n});\nvar selected = 0;\nvar menuScroll = 0;\nvar menuShowing = false;\n\nfunction drawMenu() {\n g.setFont(\"6x8\",2);\n g.setFontAlign(-1,0);\n var n = 3;\n if (selected>=n+menuScroll) menuScroll = 1+selected-n;\n if (selectedn+menuScroll) g.fillPoly([120,239,100,219,140,219]);\n else g.clearRect(100,219,140,239);\n for (var i=0;i0) {\n selected--;\n drawMenu();\n }\n}, BTN1, {repeat:true});\nsetWatch(function() {\n if (selected+1c[0]!=c[2]?buf.fillRect(b+c[0]*a,d+c[1]*a-f,b+c[2]*a,d+c[3]*a+f):c[1]!=c[3]&&buf.fillRect(b+c[0]*a-f,d+c[1]*a,b+c[2]*a+f,d+c[3]*a);),e==':'&&(b-=4),b+=a+f+7}d+=2*a;var i=new Date;buf.setFont('6x8'),buf.setFontAlign(-1,-1),buf.drawString(('0'+i.getSeconds()).substr(-2),b,d-8),buf.setFontAlign(0,-1);var n=i.toString().substr(0,15);buf.drawString(n,buf.getWidth()/2,d+8),flip()}function showTime(){if(!Bangle.isLCDOn())return;if(animInterval)return;var d=new Date,a=(' '+d.getHours()).substr(-2)+':'+('0'+d.getMinutes()).substr(-2),c=lastTime;if(a==c){draw(a,c,0);return}var b=0;animInterval=setInterval(function(){b+=.1,b>=1&&(b=1,clearInterval(animInterval),animInterval=0),draw(c,a,b)},20),lastTime=a}var buf=Graphics.createArrayBuffer(240,86,1,{msb:!0}),lastTime=' ',animInterval;const DIGITS={' ':n=>[],0:n=>[[n,0,1,0],[1,0,1,1],[1,1,1,2],[n,2,1,2],[n,1,n,2],[n,0,n,1]],1:n=>[[1-n,0,1,0],[1,0,1,1],[1-n,1,1,1],[1-n,1,1-n,2],[1-n,2,1,2]],2:n=>[[0,0,1,0],[1,0,1,1],[0,1,1,1],[0,1+n,0,2],[1,2-n,1,2],[0,2,1,2]],3:n=>[[0,0,1-n,0],[0,0,0,n],[1,0,1,1],[0,1,1,1],[1,1,1,2],[n,2,1,2]],4:n=>[[0,0,0,1],[1,0,1-n,0],[1,0,1,1-n],[0,1,1,1],[1,1,1,2],[1-n,2,1,2]],5:(n,maxFive)=>maxFive?[[0,0,0,1],[0,0,1,0],[n,1,1,1],[1,1,1,2],[0,2,1,2],[0,2,0,2],[1,1-n,1,1],[0,1,0,1+n]]:[[0,0,0,1],[0,0,1,0],[0,1,1,1],[1,1,1,2],[0,2,1,2],[0,2-n,0,2]],6:n=>[[0,0,0,1-n],[0,0,1,0],[n,1,1,1],[1,1-n,1,1],[1,1,1,2],[n,2,1,2],[0,1-n,0,2-2*n]],7:n=>[[0,0,0,n],[0,0,1,0],[1,0,1,1],[1-n,1,1,1],[1,1,1,2],[1-n,2,1,2],[1-n,1,1-n,2]],8:n=>[[0,0,0,1],[0,0,1,0],[1,0,1,1],[0,1,1,1],[1,1,1,2],[0,2,1,2],[0,1,0,2-n]],9:n=>[[0,0,0,1],[0,0,1,0],[1,0,1,1],[0,1,1-n,1],[0,1,0,1+n],[1,1,1,2],[0,2,1,2]],':':n=>[[.4,.4,.6,.4],[.6,.4,.6,.6],[.6,.6,.4,.6],[.4,.4,.4,.6],[.4,1.4,.6,1.4],[.6,1.4,.6,1.6],[.6,1.6,.4,1.6],[.4,1.4,.4,1.6]]};Bangle.on('lcdPower',function(a){a&&showTime()}),g.clear(),Bangle.loadWidgets(),Bangle.drawWidgets(),setInterval(showTime,1e3),showTime(),setWatch(Bangle.showLauncher,BTN2,{repeat:!1,edge:'falling'})"); -require('Storage').write("mclock.img",setTime(1583773541.816);E.setTimeZone(0) -require('heatshrink').decompress(atob('mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWPmf//8zDBpFDwYVBAAc4JJYWJDAoXKn4SC+EPAgXzC5JGCx4qDC4n//BIIEIRCEC4v/GBBdHC4xhCIw5dDC5BhCJAgXCRQoXGJAQXEUhAXHJAyNGC5KRCC7p2FC5B4CC5kggQXOBwvyBQMvSA4XL+EIwCoIC8ZHCgYXNO44LBBIiPPCAIwFC5DXGAAMwGAjvPGA4XIwYXHGALBDnAXFhCQHGAaOFwAXGPA4bFC4xIMIxIXDJBJGEC4xICSJCNEIwowEMJBdCFwwXEMJBdCC5BICDA4WDIw4wEAAMzCoMzBAgWIDAwAGCxRJEAAxFJDBgWNDBAWPAH4AYA=='))); +require('Storage').write("mclock.app.js","// Offscreen buffer\nvar buf = Graphics.createArrayBuffer(240,86,1,{msb:true});\nfunction flip() {\n g.setColor(1,1,1);\n g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},0,50);\n}\n// The last time that we displayed\nvar lastTime = \" \";\n// If animating, this is the interval's id\nvar animInterval;\n\n/* Get array of lines from digit d to d+1.\n n is the amount (0..1)\n maxFive is true is this digit only counts 0..5 */\nconst DIGITS = {\n\" \":n=>[],\n\"0\":n=>[\n[n,0,1,0],\n[1,0,1,1],\n[1,1,1,2],\n[n,2,1,2],\n[n,1,n,2],\n[n,0,n,1]],\n\"1\":n=>[\n[1-n,0,1,0],\n[1,0,1,1],\n[1-n,1,1,1],\n[1-n,1,1-n,2],\n[1-n,2,1,2]],\n\"2\":n=>[\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1,1],\n[0,1+n,0,2],\n[1,2-n,1,2],\n[0,2,1,2]],\n\"3\":n=>[\n[0,0,1-n,0],\n[0,0,0,n],\n[1,0,1,1],\n[0,1,1,1],\n[1,1,1,2],\n[n,2,1,2]],\n\"4\":n=>[\n[0,0,0,1],\n[1,0,1-n,0],\n[1,0,1,1-n],\n[0,1,1,1],\n[1,1,1,2],\n[1-n,2,1,2]],\n\"5\": (n,maxFive)=>maxFive ? [ // 5 -> 0\n[0,0,0,1],\n[0,0,1,0],\n[n,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,2,0,2],\n[1,1-n,1,1],\n[0,1,0,1+n]] : [ // 5 -> 6\n[0,0,0,1],\n[0,0,1,0],\n[0,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,2-n,0,2]],\n\"6\":n=>[\n[0,0,0,1-n],\n[0,0,1,0],\n[n,1,1,1],\n[1,1-n,1,1],\n[1,1,1,2],\n[n,2,1,2],\n[0,1-n,0,2-2*n]],\n\"7\":n=>[\n[0,0,0,n],\n[0,0,1,0],\n[1,0,1,1],\n[1-n,1,1,1],\n[1,1,1,2],\n[1-n,2,1,2],\n[1-n,1,1-n,2]],\n\"8\":n=>[\n[0,0,0,1],\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,1,0,2-n]],\n\"9\":n=>[\n[0,0,0,1],\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1-n,1],\n[0,1,0,1+n],\n[1,1,1,2],\n[0,2,1,2]],\n\":\":n=>[\n[0.4,0.4,0.6,0.4],\n[0.6,0.4,0.6,0.6],\n[0.6,0.6,0.4,0.6],\n[0.4,0.4,0.4,0.6],\n[0.4,1.4,0.6,1.4],\n[0.6,1.4,0.6,1.6],\n[0.6,1.6,0.4,1.6],\n[0.4,1.4,0.4,1.6]]\n};\n\n/* Draw a transition between lastText and thisText.\n 'n' is the amount - 0..1 */\nfunction draw(lastText,thisText,n) {\n buf.clear();\n var x = 1; // x offset\n const p = 2; // padding around digits\n var y = p; // y offset\n const s = 34; // character size\n for (var i=0;i{\n if (c[0]!=c[2]) // horiz\n buf.fillRect(x+c[0]*s,y+c[1]*s-p,x+c[2]*s,y+c[3]*s+p);\n else if (c[1]!=c[3]) // vert\n buf.fillRect(x+c[0]*s-p,y+c[1]*s,x+c[2]*s+p,y+c[3]*s);\n });\n if (thisCh==\":\") x-=4;\n x+=s+p+7;\n }\n y += 2*s;\n var d = new Date();\n buf.setFont(\"6x8\");\n buf.setFontAlign(-1,-1);\n buf.drawString((\"0\"+d.getSeconds()).substr(-2), x, y-8);\n // date\n buf.setFontAlign(0,-1);\n var date = d.toString().substr(0,15);\n buf.drawString(date, buf.getWidth()/2, y+8);\n flip();\n}\n\n/* Show the current time, and animate if needed */\nfunction showTime() {\n if (!Bangle.isLCDOn()) return;\n if (animInterval) return; // in animation - quit\n var d = new Date();\n var t = (\" \"+d.getHours()).substr(-2)+\":\"+\n (\"0\"+d.getMinutes()).substr(-2);\n var l = lastTime;\n // same - don't animate\n if (t==l) {\n draw(t,l,0);\n return;\n }\n var n = 0;\n animInterval = setInterval(function() {\n n += 1/10;\n if (n>=1) {\n n=1;\n clearInterval(animInterval);\n animInterval=0;\n }\n draw(l,t,n);\n }, 20);\n lastTime = t;\n}\n\nBangle.on('lcdPower',function(on) {\n if (on)\n showTime();\n});\n\ng.clear();\nBangle.loadWidgets();\nBangle.drawWidgets();\n// Update time once a second\nsetInterval(showTime, 1000);\nshowTime();\n\n// Show launcher when middle button pressed\nsetWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:\"falling\"});\n"); +require('Storage').write("mclock.img",require("heatshrink").decompress(atob("mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWPmf//8zDBpFDwYVBAAc4JJYWJDAoXKn4SC+EPAgXzC5JGCx4qDC4n//BIIEIRCEC4v/GBBdHC4xhCIw5dDC5BhCJAgXCRQoXGJAQXEUhAXHJAyNGC5KRCC7p2FC5B4CC5kggQXOBwvyBQMvSA4XL+EIwCoIC8ZHCgYXNO44LBBIiPPCAIwFC5DXGAAMwGAjvPGA4XIwYXHGALBDnAXFhCQHGAaOFwAXGPA4bFC4xIMIxIXDJBJGEC4xICSJCNEIwowEMJBdCFwwXEMJBdCC5BICDA4WDIw4wEAAMzCoMzBAgWIDAwAGCxRJEAAxFJDBgWNDBAWPAH4AYA=="))); require('Storage').write("mclock.info","{\"id\":\"mclock\",\"name\":\"Morphing Clock\",\"type\":\"clock\",\"src\":\"mclock.app.js\",\"icon\":\"mclock.img\",\"sortorder\":-9,\"version\":\"0.02\",\"files\":\"mclock.info,mclock.app.js,mclock.img\"}"); -require('Storage').write("setting.app.js","setTime(1583773542.218);E.setTimeZone(0)\nfunction updateSettings(){storage.write('setting.json',settings)}function resetSettings(){settings={ble:!0,blerepl:!0,log:!1,timeout:10,vibrate:!0,beep:!0,timezone:0,HID:!1,clock:null,'12hour':!1,distance:'kilometer'},updateSettings()}function showMainMenu(){const a={'':{title:'Settings'},'Make Connectable':makeConnectable,BLE:{value:settings.ble,format:boolFormat,onchange:()=>settings.ble=!settings.ble,updateSettings();},Programmable:{value:settings.blerepl,format:boolFormat,onchange:()=>settings.blerepl=!settings.blerepl,updateSettings();},'Debug info':{value:settings.log,format:v=>v?'Show':'Hide',onchange:()=>settings.log=!settings.log,updateSettings();},'LCD Timeout':{value:settings.timeout,min:0,max:60,step:5,onchange:v=>settings.timeout=0|v,updateSettings(),Bangle.setLCDTimeout(settings.timeout);},Beep:{value:settings.beep,format:boolFormat,onchange:()=>settings.beep=!settings.beep,updateSettings(),settings.beep&&Bangle.beep(1);},Vibration:{value:settings.vibrate,format:boolFormat,onchange:()=>settings.vibrate=!settings.vibrate,updateSettings(),settings.vibrate&&(VIBRATE.write(1),setTimeout(()=>VIBRATE.write(0),10));},'Welcome App':{value:!settings.welcomed,format:boolFormat,onchange:v=>settings.welcomed=v?undefined:!0,updateSettings();},Locale:showLocaleMenu,'Select Clock':showClockMenu,HID:{value:settings.HID,format:boolFormat,onchange:()=>settings.HID=!settings.HID,updateSettings();},'Set Time':showSetTimeMenu,'Reset Settings':showResetMenu,'Turn Off':Bangle.off,'< Back':()=>load();};return E.showMenu(a)}function showLocaleMenu(){const a={'':{title:'Locale'},'< Back':showMainMenu,'Time Zone':{value:settings.timezone,min:-11,max:12,step:.5,onchange:v=>settings.timezone=v||0,updateSettings();},'Clock Style':{value:!!settings['12hour'],format:v=>v?'12hr':'24hr',onchange:v=>settings['12hour']=v,updateSettings();},'Distance/Speed':{value:settings.distance=='mile',format:v=>v?'mile':'km',onchange:v=>settings.distance=v?'mile':'kilometer',updateSettings();}};return E.showMenu(a)}function showResetMenu(){const a={'':{title:'Reset'},'< Back':showMainMenu,'Reset Settings':()=>E.showPrompt('Reset Settings?').then(v=>v&&(E.showMessage('Resetting'),resetSettings()),setTimeout(showMainMenu,50););};return E.showMenu(a)}function makeConnectable(){try{NRF.wake()}catch(a){}Bluetooth.setConsole(1);var a='Bangle.js '+NRF.getAddress().substr(-5).replace(':','');E.showPrompt(a+'\\nStay Connectable?',{title:'Connectable'}).then(r=>{if(settings.ble!=r&&(settings.ble=r,updateSettings()),!r)try{NRF.sleep()}catch(a){}showMainMenu()})}function showClockMenu(){var c=require('Storage').list(/\\.info$/).map(app=>try{return require('Storage').readJSON(app)}catch(a){}).filter(app=>app.type=='clock').sort((a,b)=>a.sortorder-b.sortorder);const d={'':{title:'Select Clock'},'< Back':showMainMenu};return c.forEach((app,index)=>var e=app.name;),c.length===0&&(d['No Clocks Found']=()=>;),E.showMenu(d)}function showSetTimeMenu(){d=new Date;const a={'':{title:'Set Time',predraw:function(){d=new Date,a.Hour.value=d.getHours(),a.Minute.value=d.getMinutes(),a.Second.value=d.getSeconds(),a.Date.value=d.getDate(),a.Month.value=d.getMonth()+1,a.Year.value=d.getFullYear()}},'< Back':showMainMenu,Hour:{value:d.getHours(),min:0,max:23,step:1,onchange:v=>d=new Date,d.setHours(v),setTime(d.getTime()/1e3);},Minute:{value:d.getMinutes(),min:0,max:59,step:1,onchange:v=>d=new Date,d.setMinutes(v),setTime(d.getTime()/1e3);},Second:{value:d.getSeconds(),min:0,max:59,step:1,onchange:v=>d=new Date,d.setSeconds(v),setTime(d.getTime()/1e3);},Date:{value:d.getDate(),min:1,max:31,step:1,onchange:v=>d=new Date,d.setDate(v),setTime(d.getTime()/1e3);},Month:{value:d.getMonth()+1,min:1,max:12,step:1,onchange:v=>d=new Date,d.setMonth(v-1),setTime(d.getTime()/1e3);},Year:{value:d.getFullYear(),min:2019,max:2100,step:1,onchange:v=>d=new Date,d.setFullYear(v),setTime(d.getTime()/1e3);}};return E.showMenu(a)}Bangle.loadWidgets(),Bangle.drawWidgets();const storage=require('Storage');let settings;settings=storage.readJSON('setting.json',1),settings||resetSettings();const boolFormat=v=>v?'On':'Off';showMainMenu()"); -require('Storage').write("setting.json",{"ble":true,"blerepl":true,"log":false,"timeout":10,"vibrate":true,"beep":true,"timezone":0,"HID":false,"clock":null,"12hour":false,"distance":"kilometer"}); -require('Storage').write("setting.img",setTime(1583773542.426);E.setTimeZone(0) -require('heatshrink').decompress(atob('mEwghC/AFEiAAgX/C/4SFkADBgQXFBIgECAAYSCkAWGBIoXGyQTHABBZLkUhiMRiQXLIQwVBAAZlIC44tCAAYxGIxIWFGA4XIFwwwHXBAWHGAwXHFxAwGPAYXTX44XDiAJBgIXGyDAHFAYKDMAq+EGAgXNCwwX/C453XU6IWHa6ZFCC6JJCC4hgEAAoOEC5AwIFwhgEBAgwIBoqmGGBIuFVAgXFGAwLFYAoLFGIYtFeA4MGABMpC4pICkBMGBIpGFC4SuIBIoWFAAxZLC/4X/AFQ'))); -require('Storage').write("setting.info","{\"id\":\"setting\",\"name\":\"Settings\",\"src\":\"setting.app.js\",\"icon\":\"setting.img\",\"sortorder\":-2,\"version\":\"0.05\",\"files\":\"setting.info,setting.app.js,setting.json,setting.img\"}"); -require('Storage').write("about.app.js","setTime(1583773542.703);E.setTimeZone(0)\nfunction getVersion(c,d){var b=s.readJSON(d,1),a='object'==typeof b?b.version:!1;g.drawString(a?c+' '+(a?'v'+a:'Unknown'):'NO '+c,0,y+=h)}var ENV=process.env,MEM=process.memory(),s=require('Storage');g.clear(1),g.setFont('6x8');var y=24,h=8;g.drawImage(require('heatshrink').decompress(atob('vE4gQZWg//AAI3Zh4dCoAd6wAd64Ad2j4d6l4dcn4dC6Adc+AdYv4dUggHG//kgN//AGB1WkDpkOAwsH/gDBgJ4CTRwdGl6RDl/0gHQgJeMDo2/AgcDIAIkBnAdRgJyCAAQdDlgdRgZPDgbWBDoUcDqMPRYcJgEfoA7Uh9AAgQ1BEgIdBngdRKQIACmBbB6AdB2gdRnoEDyB+C8tbbQVpgNAqOkAwMGyEQDoMB1AIBvgdDPYMC+H//7zBg//+fAA4OAgH//twDoMv/4WB3iyEAAPwHINvTYMAv/A/sC6BmBh/wDoP4gIuBdwayBAAP/DoMH4F4ToQSB+EPJQUOgKmDBgIABhAdFB4L7BgfAAYNwjpKChwJBTIQdDiAdFgHgAYIdDmDaCO4MD9Wq14dM+CdCDoU0nDjChyhBAAIdFsgdTZgaVDmPYLJk0LIodDaIcxcILRDSo80jiVECgUAvgDCmG0YQTRHDoTRBgLRCMwJDBnodDeAMDKoUvAIU/DocD6ELDoKRCAIM/LIcGG4PQUIKCBU4PzDoaEB/p3BFQKKCh9ADoXsKIVVqonCtVBoFQcAUKyFwghdB3IPBCwJZCAQMfEgQAL2AGFgZJBDoZgDABEMWYQJFgLwCkACB/gdLWYMCfoQAE35BEDpkH8EfdgYADl4mDl68BABazBFBA2CgK8CABcBUZP/8kBv58CAC1//4ABUQwASn4dgOxoALl4dC4AdYj4d6h4d+wAd6oAd2g4dCAwQA=')),120,y),g.drawString('BANGLEJS.COM',120,y-4),g.drawString('Powered by Espruino',0,y+=4+h),g.drawString('Version '+ENV.VERSION,0,y+=h),g.drawString('Commit '+ENV.GIT_COMMIT,0,y+=h),getVersion('Bootloader','boot.info'),getVersion('Launcher','launch.info'),getVersion('Settings','setting.info'),y+=h,g.drawString(MEM.total+' JS Variables available',0,y+=h),g.drawString('Storage: '+(require('Storage').getFree()>>10)+'k free',0,y+=h),ENV.STORAGE&&g.drawString(' '+(ENV.STORAGE>>10)+'k total',0,y+=h),ENV.SPIFLASH&&g.drawString('SPI Flash: '+(ENV.SPIFLASH>>10)+'k',0,y+=h),g.setFontAlign(0,-1),g.drawString(NRF.getAddress(),120,232),g.flip(),g.drawImage(require('heatshrink').decompress(atob('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')),0,135),g.flip()"); -require('Storage').write("about.img",setTime(1583773542.911);E.setTimeZone(0) -require('heatshrink').decompress(atob('mEwxH+AH4A/AH4AQqoAHFtovlFxQzOiEQF0QwJFwIwSFyIwIF6YuTGBQule7IvuEp150d5GBS+DSBwtO5wABGA4vUFxvIFwXO44wJF7hcEAAejYJQvYFpAwJF7ejRQgAHF7BcH44tLF47xGF6QtNF8l5vIqFA4gv/R/4vZABwv25ovudYwAHvIvfp+dFxlPFy4wHp9PvPHFo/HFwIvEFqYxHEINP43G4/H5vNAYIHBBgQuaGAgvEAA4vEFzIxDq0zh5YCAAvHh8zqwud/1lssPh+AF4+ABYIPBFroABnUPnPNFwvNnMPnQRDFzgvCh/OdgKMC5vOBIIvEGC4bESAeB5wAErqODGDIbGMAekFwekLw4wWDY9liAoBrpdEiASIFzdloIpBAAkQoITJF7aSERhQvUDhYATF/4v/F74A/AH4A5A='))); +require('Storage').write("setting.app.js","Bangle.loadWidgets();\nBangle.drawWidgets();\n\nconst storage = require('Storage');\nlet settings;\n\nfunction updateSettings() {\n //storage.erase('setting.json'); // - not needed, just causes extra writes if settings were the same\n storage.write('setting.json', settings);\n}\n\nfunction resetSettings() {\n settings = {\n ble: true, // Bluetooth enabled by default\n blerepl: true, // Is REPL on Bluetooth - can Espruino IDE be used?\n log: false, // Do log messages appear on screen?\n timeout: 10, // Default LCD timeout in seconds\n vibrate: true, // Vibration enabled by default. App must support\n beep: true, // Beep enabled by default. App must support\n timezone: 0, // Set the timezone for the device\n HID : false, // BLE HID mode, off by default\n clock: null, // a string for the default clock's name\n \"12hour\" : false, // 12 or 24 hour clock?\n // welcomed : undefined/true (whether welcome app should show)\n };\n updateSettings();\n}\n\nsettings = storage.readJSON('setting.json',1);\nif (!settings) resetSettings();\n\nconst boolFormat = v => v ? \"On\" : \"Off\";\n\nfunction showMainMenu() {\n const mainmenu = {\n '': { 'title': 'Settings' },\n 'Make Connectable': makeConnectable,\n 'BLE': {\n value: settings.ble,\n format: boolFormat,\n onchange: () => {\n settings.ble = !settings.ble;\n updateSettings();\n }\n },\n 'Programmable': {\n value: settings.blerepl,\n format: boolFormat,\n onchange: () => {\n settings.blerepl = !settings.blerepl;\n updateSettings();\n }\n },\n 'Debug info': {\n value: settings.log,\n format: v => v ? \"Show\" : \"Hide\",\n onchange: () => {\n settings.log = !settings.log;\n updateSettings();\n }\n },\n 'LCD Timeout': {\n value: settings.timeout,\n min: 0,\n max: 60,\n step: 5,\n onchange: v => {\n settings.timeout = 0 | v;\n updateSettings();\n Bangle.setLCDTimeout(settings.timeout);\n }\n },\n 'Beep': {\n value: settings.beep,\n format: boolFormat,\n onchange: () => {\n settings.beep = !settings.beep;\n updateSettings();\n if (settings.beep) {\n Bangle.beep(1);\n }\n }\n },\n 'Vibration': {\n value: settings.vibrate,\n format: boolFormat,\n onchange: () => {\n settings.vibrate = !settings.vibrate;\n updateSettings();\n if (settings.vibrate) {\n VIBRATE.write(1);\n setTimeout(()=>VIBRATE.write(0), 10);\n }\n }\n },\n 'Welcome App': {\n value: !settings.welcomed,\n format: boolFormat,\n onchange: v => {\n settings.welcomed = v?undefined:true;\n updateSettings();\n }\n },\n 'Locale': showLocaleMenu,\n 'Select Clock': showClockMenu,\n 'HID': {\n value: settings.HID,\n format: boolFormat,\n onchange: () => {\n settings.HID = !settings.HID;\n updateSettings();\n }\n },\n 'Set Time': showSetTimeMenu,\n 'Reset Settings': showResetMenu,\n 'Turn Off': Bangle.off,\n '< Back': ()=> {load();}\n };\n return E.showMenu(mainmenu);\n}\n\nfunction showLocaleMenu() {\n const localemenu = {\n '': { 'title': 'Locale' },\n '< Back': showMainMenu,\n 'Time Zone': {\n value: settings.timezone,\n min: -11,\n max: 12,\n step: 0.5,\n onchange: v => {\n settings.timezone = v || 0;\n updateSettings();\n }\n },\n 'Clock Style': {\n value: !!settings[\"12hour\"],\n format : v => v?\"12hr\":\"24hr\",\n onchange: v => {\n settings[\"12hour\"] = v;\n updateSettings();\n }\n }\n };\n return E.showMenu(localemenu);\n}\n\nfunction showResetMenu() {\n const resetmenu = {\n '': { 'title': 'Reset' },\n '< Back': showMainMenu,\n 'Reset Settings': () => {\n E.showPrompt('Reset Settings?').then((v) => {\n if (v) {\n E.showMessage('Resetting');\n resetSettings();\n }\n setTimeout(showMainMenu, 50);\n });\n }\n };\n return E.showMenu(resetmenu);\n}\n\nfunction makeConnectable() {\n try { NRF.wake(); } catch(e) {}\n Bluetooth.setConsole(1);\n var name=\"Bangle.js \"+NRF.getAddress().substr(-5).replace(\":\",\"\");\n E.showPrompt(name+\"\\nStay Connectable?\",{title:\"Connectable\"}).then(r=>{\n if (settings.ble!=r) {\n settings.ble = r;\n updateSettings();\n }\n if (!r) try { NRF.sleep(); } catch(e) {}\n showMainMenu();\n });\n}\nfunction showClockMenu() {\n var clockApps = require(\"Storage\").list(/\\.info$/).map(app=>{\n try { return require(\"Storage\").readJSON(app); }\n catch (e) {}\n }).filter(app=>app.type==\"clock\").sort((a, b) => a.sortorder - b.sortorder);\n const clockMenu = {\n '': {\n 'title': 'Select Clock',\n },\n '< Back': showMainMenu,\n };\n clockApps.forEach((app,index) => {\n var label = app.name;\n if ((!settings.clock && index === 0) || (settings.clock === app.src)) {\n label = \"* \"+label;\n }\n clockMenu[label] = () => {\n if (settings.clock !== app.src) {\n settings.clock = app.src;\n updateSettings();\n showMainMenu();\n }\n };\n });\n if (clockApps.length === 0) {\n clockMenu[\"No Clocks Found\"] = () => {};\n }\n return E.showMenu(clockMenu);\n}\n\n\n\nfunction showSetTimeMenu() {\n d = new Date();\n const timemenu = {\n '': {\n 'title': 'Set Time',\n 'predraw': function() {\n d = new Date();\n timemenu.Hour.value = d.getHours();\n timemenu.Minute.value = d.getMinutes();\n timemenu.Second.value = d.getSeconds();\n timemenu.Date.value = d.getDate();\n timemenu.Month.value = d.getMonth() + 1;\n timemenu.Year.value = d.getFullYear();\n }\n },\n '< Back': showMainMenu,\n 'Hour': {\n value: d.getHours(),\n min: 0,\n max: 23,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setHours(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Minute': {\n value: d.getMinutes(),\n min: 0,\n max: 59,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setMinutes(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Second': {\n value: d.getSeconds(),\n min: 0,\n max: 59,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setSeconds(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Date': {\n value: d.getDate(),\n min: 1,\n max: 31,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setDate(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Month': {\n value: d.getMonth() + 1,\n min: 1,\n max: 12,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setMonth(v - 1);\n setTime(d.getTime()/1000);\n }\n },\n 'Year': {\n value: d.getFullYear(),\n min: 2019,\n max: 2100,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setFullYear(v);\n setTime(d.getTime()/1000);\n }\n }\n };\n return E.showMenu(timemenu);\n}\n\nshowMainMenu();\n"); +require('Storage').write("setting.json",{"ble":true,"blerepl":true,"log":false,"timeout":10,"vibrate":true,"beep":true,"timezone":0,"HID":false,"clock":null,"12hour":false}); +require('Storage').write("setting.img",require("heatshrink").decompress(atob("mEwghC/AFEiAAgX/C/4SFkADBgQXFBIgECAAYSCkAWGBIoXGyQTHABBZLkUhiMRiQXLIQwVBAAZlIC44tCAAYxGIxIWFGA4XIFwwwHXBAWHGAwXHFxAwGPAYXTX44XDiAJBgIXGyDAHFAYKDMAq+EGAgXNCwwX/C453XU6IWHa6ZFCC6JJCC4hgEAAoOEC5AwIFwhgEBAgwIBoqmGGBIuFVAgXFGAwLFYAoLFGIYtFeA4MGABMpC4pICkBMGBIpGFC4SuIBIoWFAAxZLC/4X/AFQ"))); +require('Storage').write("setting.info","{\"id\":\"setting\",\"name\":\"Settings\",\"src\":\"setting.app.js\",\"icon\":\"setting.img\",\"sortorder\":-2,\"version\":\"0.06\",\"files\":\"setting.info,setting.app.js,setting.json,setting.img\"}"); +require('Storage').write("about.app.js","var ENV = process.env;\nvar MEM = process.memory();\nvar s = require(\"Storage\");\n\ng.clear(1);\ng.setFont(\"6x8\");\nvar y = 24, h=8;\ng.drawImage(require(\"heatshrink\").decompress(atob(\"vE4gQZWg//AAI3Zh4dCoAd6wAd64Ad2j4d6l4dcn4dC6Adc+AdYv4dUggHG//kgN//AGB1WkDpkOAwsH/gDBgJ4CTRwdGl6RDl/0gHQgJeMDo2/AgcDIAIkBnAdRgJyCAAQdDlgdRgZPDgbWBDoUcDqMPRYcJgEfoA7Uh9AAgQ1BEgIdBngdRKQIACmBbB6AdB2gdRnoEDyB+C8tbbQVpgNAqOkAwMGyEQDoMB1AIBvgdDPYMC+H//7zBg//+fAA4OAgH//twDoMv/4WB3iyEAAPwHINvTYMAv/A/sC6BmBh/wDoP4gIuBdwayBAAP/DoMH4F4ToQSB+EPJQUOgKmDBgIABhAdFB4L7BgfAAYNwjpKChwJBTIQdDiAdFgHgAYIdDmDaCO4MD9Wq14dM+CdCDoU0nDjChyhBAAIdFsgdTZgaVDmPYLJk0LIodDaIcxcILRDSo80jiVECgUAvgDCmG0YQTRHDoTRBgLRCMwJDBnodDeAMDKoUvAIU/DocD6ELDoKRCAIM/LIcGG4PQUIKCBU4PzDoaEB/p3BFQKKCh9ADoXsKIVVqonCtVBoFQcAUKyFwghdB3IPBCwJZCAQMfEgQAL2AGFgZJBDoZgDABEMWYQJFgLwCkACB/gdLWYMCfoQAE35BEDpkH8EfdgYADl4mDl68BABazBFBA2CgK8CABcBUZP/8kBv58CAC1//4ABUQwASn4dgOxoALl4dC4AdYj4d6h4d+wAd6oAd2g4dCAwQA=\")),120,y);\ng.drawString(\"BANGLEJS.COM\",120,y-4);\ng.drawString(\"Powered by Espruino\",0,y+=4+h);\ng.drawString(\"Version \"+ENV.VERSION,0,y+=h);\ng.drawString(\"Commit \"+ENV.GIT_COMMIT,0,y+=h);\nfunction getVersion(name,file) {\n var j = s.readJSON(file,1);\n var v = (\"object\"==typeof j)?j.version:false;\n g.drawString(v?(name+\" \"+(v?\"v\"+v:\"Unknown\")):\"NO \"+name,0,y+=h);\n}\ngetVersion(\"Bootloader\",\"boot.info\");\ngetVersion(\"Launcher\",\"launch.info\");\ngetVersion(\"Settings\",\"setting.info\");\n\ny+=h;\ng.drawString(MEM.total+\" JS Variables available\",0,y+=h);\ng.drawString(\"Storage: \"+(require(\"Storage\").getFree()>>10)+\"k free\",0,y+=h);\nif (ENV.STORAGE) g.drawString(\" \"+(ENV.STORAGE>>10)+\"k total\",0,y+=h);\nif (ENV.SPIFLASH) g.drawString(\"SPI Flash: \"+(ENV.SPIFLASH>>10)+\"k\",0,y+=h);\ng.setFontAlign(0,-1);\ng.drawString(NRF.getAddress(),120,232);\ng.flip();\n\n// Pixel chooser image\ng.drawImage(require(\"heatshrink\").decompress(atob(\"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\")),0,135);\ng.flip();\n"); +require('Storage').write("about.img",require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AQqoAHFtovlFxQzOiEQF0QwJFwIwSFyIwIF6YuTGBQule7IvuEp150d5GBS+DSBwtO5wABGA4vUFxvIFwXO44wJF7hcEAAejYJQvYFpAwJF7ejRQgAHF7BcH44tLF47xGF6QtNF8l5vIqFA4gv/R/4vZABwv25ovudYwAHvIvfp+dFxlPFy4wHp9PvPHFo/HFwIvEFqYxHEINP43G4/H5vNAYIHBBgQuaGAgvEAA4vEFzIxDq0zh5YCAAvHh8zqwud/1lssPh+AF4+ABYIPBFroABnUPnPNFwvNnMPnQRDFzgvCh/OdgKMC5vOBIIvEGC4bESAeB5wAErqODGDIbGMAekFwekLw4wWDY9liAoBrpdEiASIFzdloIpBAAkQoITJF7aSERhQvUDhYATF/4v/F74A/AH4A5A="))); require('Storage').write("about.info","{\"id\":\"about\",\"name\":\"About\",\"src\":\"about.app.js\",\"icon\":\"about.img\",\"version\":\"0.04\",\"files\":\"about.info,about.app.js,about.img\"}"); -require('Storage').write("alarm.app.js","setTime(1583773543.22);E.setTimeZone(0)\nfunction formatTime(b){var a=0|b,c=Math.round((b-a)*60);return a+':'+('0'+c).substr(-2)}function getCurrentHr(){var a=new Date;return a.getHours()+a.getMinutes()/60+a.getSeconds()/3600}function showMainMenu(){const a={'':{title:'Alarms'},'New Alarm':()=>editAlarm(-1)};return alarms.forEach((alarm,idx)=>txt=(alarm.on?'on ':'off ')+formatTime(alarm.hr),alarm.rp&&(txt+=' (repeat)'),a[txt]=function(){editAlarm(idx)};),a['< Back']=()=>load();,E.showMenu(a)}function editAlarm(g){function i(){var d=a+c/60,e=0;return d23&&(b=0),a=b,this.value=b}},Minutes:{value:c,onchange:function(a){a<0&&(a=59),a>59&&(a=0),c=a,this.value=a}},Enabled:{value:b,format:v=>v?'On':'Off',onchange:v=>b=v},Repeat:{value:b,format:v=>v?'Yes':'No',onchange:v=>f=v}};return h?e['> New Alarm']=function(){alarms.push(i()),require('Storage').write('alarm.json',JSON.stringify(alarms)),showMainMenu()}:e['> Save']=function(){alarms[g]=i(),require('Storage').write('alarm.json',JSON.stringify(alarms)),showMainMenu()},e['< Back']=showMainMenu,E.showMenu(e)}Bangle.loadWidgets(),Bangle.drawWidgets();var alarms=require('Storage').readJSON('alarm.json',1)||[];showMainMenu()"); -require('Storage').write("alarm.js","setTime(1583773543.508);E.setTimeZone(0)\nfunction formatTime(b){var a=0|b,c=Math.round((b-a)*60);return a+':'+('0'+c).substr(-2)}function getCurrentHr(){var a=new Date;return a.getHours()+a.getMinutes()/60+a.getSeconds()/3600}function showAlarm(a){function d(){Bangle.buzz(100).then(()=>setTimeout(()=>Bangle.buzz(100).then(function(){c--&&setTimeout(d,3e3)});,100);)}var b=formatTime(a.hr),c=10;a.msg&&(b+='\\n'+a.msg),E.showPrompt(b,{title:'ALARM!',buttons:{Sleep:!0,Ok:!1}}).then(function(b){c=0,b?a.hr+=.16666666666666666:(a.last=new Date().getDate(),a.rp||(a.on=!1)),require('Storage').write('alarm.json',JSON.stringify(alarms)),load()}),d()}clearInterval();var day=new Date().getDate(),hr=getCurrentHr()+1e4,alarms=require('Storage').readJSON('alarm.json',1)||[],active=alarms.filter(a=>a.on&&a.hra.hr-b.hr),showAlarm(active[0])):setTimeout(load,100)"); +require('Storage').write("alarm.app.js","Bangle.loadWidgets();\nBangle.drawWidgets();\n\nvar alarms = require(\"Storage\").readJSON(\"alarm.json\",1)||[];\n/*alarms = [\n { on : true,\n hr : 6.5, // hours + minutes/60\n msg : \"Eat chocolate\",\n last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!\n rp : true, // repeat\n }\n];*/\n\nfunction formatTime(t) {\n var hrs = 0|t;\n var mins = Math.round((t-hrs)*60);\n return hrs+\":\"+(\"0\"+mins).substr(-2);\n}\n\nfunction getCurrentHr() {\n var time = new Date();\n return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);\n}\n\nfunction showMainMenu() {\n const menu = {\n '': { 'title': 'Alarms' },\n 'New Alarm': ()=>editAlarm(-1)\n };\n alarms.forEach((alarm,idx)=>{\n txt = (alarm.on?\"on \":\"off \")+formatTime(alarm.hr);\n if (alarm.rp) txt += \" (repeat)\";\n menu[txt] = function() {\n editAlarm(idx);\n };\n });\n menu['< Back'] = ()=>{load();};\n return E.showMenu(menu);\n}\n\nfunction editAlarm(alarmIndex) {\n var newAlarm = alarmIndex<0;\n var hrs = 12;\n var mins = 0;\n var en = true;\n var repeat = true;\n if (!newAlarm) {\n var a = alarms[alarmIndex];\n hrs = 0|a.hr;\n mins = Math.round((a.hr-hrs)*60);\n en = a.on;\n repeat = a.rp;\n }\n const menu = {\n '': { 'title': 'Alarms' },\n 'Hours': {\n value: hrs,\n onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'\n },\n 'Minutes': {\n value: mins,\n onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'\n },\n 'Enabled': {\n value: en,\n format: v=>v?\"On\":\"Off\",\n onchange: v=>en=v\n },\n 'Repeat': {\n value: en,\n format: v=>v?\"Yes\":\"No\",\n onchange: v=>repeat=v\n }\n };\n function getAlarm() {\n var hr = hrs+(mins/60);\n var day = 0;\n // If alarm is for tomorrow not today (eg, in the past), set day\n if (hr < getCurrentHr())\n day = (new Date()).getDate();\n // Save alarm\n return {\n on : en, hr : hr,\n last : day, rp : repeat\n };\n }\n if (newAlarm) {\n menu[\"> New Alarm\"] = function() {\n alarms.push(getAlarm());\n require(\"Storage\").write(\"alarm.json\",JSON.stringify(alarms));\n showMainMenu();\n };\n } else {\n menu[\"> Save\"] = function() {\n alarms[alarmIndex] = getAlarm();\n require(\"Storage\").write(\"alarm.json\",JSON.stringify(alarms));\n showMainMenu();\n };\n }\n menu['< Back'] = showMainMenu;\n return E.showMenu(menu);\n}\n\nshowMainMenu();\n"); +require('Storage').write("alarm.js","// Chances are boot0.js got run already and scheduled *another*\n// 'load(alarm.js)' - so let's remove it first!\nclearInterval();\n\nfunction formatTime(t) {\n var hrs = 0|t;\n var mins = Math.round((t-hrs)*60);\n return hrs+\":\"+(\"0\"+mins).substr(-2);\n}\n\nfunction getCurrentHr() {\n var time = new Date();\n return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);\n}\n\nfunction showAlarm(alarm) {\n var msg = formatTime(alarm.hr);\n var buzzCount = 10;\n if (alarm.msg)\n msg += \"\\n\"+alarm.msg;\n E.showPrompt(msg,{\n title:\"ALARM!\",\n buttons : {\"Sleep\":true,\"Ok\":false} // default is sleep so it'll come back in 10 mins\n }).then(function(sleep) {\n buzzCount = 0;\n if (sleep) {\n alarm.hr += 10/60; // 10 minutes\n } else {\n alarm.last = (new Date()).getDate();\n if (!alarm.rp) alarm.on = false;\n }\n require(\"Storage\").write(\"alarm.json\",JSON.stringify(alarms));\n load();\n });\n function buzz() {\n Bangle.buzz(100).then(()=>{\n setTimeout(()=>{\n Bangle.buzz(100).then(function() {\n if (buzzCount--)\n setTimeout(buzz, 3000);\n });\n },100);\n });\n }\n buzz();\n}\n\n// Check for alarms\nvar day = (new Date()).getDate();\nvar hr = getCurrentHr()+10000; // get current time - 10s in future to ensure we alarm if we've started the app a tad early\nvar alarms = require(\"Storage\").readJSON(\"alarm.json\",1)||[];\nvar active = alarms.filter(a=>a.on&&(a.hra.hr-b.hr);\n showAlarm(active[0]);\n} else {\n // otherwise just go back to default app\n setTimeout(load, 100);\n}\n"); require('Storage').write("alarm.json","[]"); -require('Storage').write("alarm.img",setTime(1583773543.713);E.setTimeZone(0) -require('heatshrink').decompress(atob('mEwwkGswAhiMRCCAREAo4eHBIQLEAgwYHsIJDiwHB5gACBpIhHCoYZEGA4gFCw4ABGA4HEjgXJ4IXGAwcUB4VEmf//8zogICoJIFAodMBoNDCoIADmgJB4gXIFwXDCwoABngwFC4guB4k/CQXwh4EC+YMCC44iBp4qDC4n/+gNBC41sEIJCEC4v/GAPGC4dhXYRdFC4xhCCYIXCdQRdDC5HzegQXCsxGHC45IDCwQXCUgwXHJAIXGRogXJSIIXcOw4XIPAYXcBwv/mEDBAwXOgtQC65QGC5vzoEAJAx3Nmk/mEABIiPN+dDAQIwFC4zXGFwKRCGAjvMFwQECGAgXI4YuGGAUvAgU8C4/EFwwGCAgdMC4p4EFwobFOwoXDJAIoEAApGBC4xIEABJGHGAapEAAqNBFwwXD4heI+YuBC5BIBVQhdHIw4wD5inFS4IKCCxFmigNCokzCoMzogICoIWIsMRjgPCAA3BiMWC48RBQIXJEgMRFxAJCCw4lEC44IECooOIBAaBJKwhgIAH4ACA=='))); -require('Storage').write("alarm.wid.js","setTime(1583773543.966);E.setTimeZone(0)\n(()=>{var alarms=require('Storage').readJSON('alarm.json',1)||[];if(alarms=alarms.filter(alarm=>alarm.on),!alarms.length)return;delete alarms,WIDGETS.alarm={area:'tl',width:24,draw:function(){g.setColor(-1),g.drawImage(atob('GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA'),this.x,this.y)}}})()"); +require('Storage').write("alarm.img",require("heatshrink").decompress(atob("mEwwkGswAhiMRCCAREAo4eHBIQLEAgwYHsIJDiwHB5gACBpIhHCoYZEGA4gFCw4ABGA4HEjgXJ4IXGAwcUB4VEmf//8zogICoJIFAodMBoNDCoIADmgJB4gXIFwXDCwoABngwFC4guB4k/CQXwh4EC+YMCC44iBp4qDC4n/+gNBC41sEIJCEC4v/GAPGC4dhXYRdFC4xhCCYIXCdQRdDC5HzegQXCsxGHC45IDCwQXCUgwXHJAIXGRogXJSIIXcOw4XIPAYXcBwv/mEDBAwXOgtQC65QGC5vzoEAJAx3Nmk/mEABIiPN+dDAQIwFC4zXGFwKRCGAjvMFwQECGAgXI4YuGGAUvAgU8C4/EFwwGCAgdMC4p4EFwobFOwoXDJAIoEAApGBC4xIEABJGHGAapEAAqNBFwwXD4heI+YuBC5BIBVQhdHIw4wD5inFS4IKCCxFmigNCokzCoMzogICoIWIsMRjgPCAA3BiMWC48RBQIXJEgMRFxAJCCw4lEC44IECooOIBAaBJKwhgIAH4ACA=="))); +require('Storage').write("alarm.wid.js","(() => {\n var alarms = require('Storage').readJSON('alarm.json',1)||[];\n alarms = alarms.filter(alarm=>alarm.on);\n if (!alarms.length) return; // no alarms, no widget!\n delete alarms;\n // add the widget\n WIDGETS[\"alarm\"]={area:\"tl\",width:24,draw:function() {\n g.setColor(-1);\n g.drawImage(atob(\"GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA\"),this.x,this.y);\n }};\n})()\n"); require('Storage').write("alarm.info","{\"id\":\"alarm\",\"name\":\"Alarms\",\"src\":\"alarm.app.js\",\"icon\":\"alarm.img\",\"version\":\"0.04\",\"files\":\"alarm.info,alarm.app.js,alarm.js,alarm.json,alarm.img,alarm.wid.js\"}"); -require('Storage').write("widbat.wid.js","setTime(1583773544.233);E.setTimeZone(0)\n!function(b,a){function c(){WIDGETS.bat.width=Bangle.isCharging()?56:40}function d(){var d=39,a=this.x,c=this.y;Bangle.isCharging()&&(g.setColor(b).drawImage(atob('DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg'),a,c),a+=16),g.setColor(-1),g.fillRect(a,c+2,a+d-4,c+21),g.clearRect(a+2,c+4,a+d-6,c+19),g.fillRect(a+d-3,c+10,a+d,c+14),g.setColor(b).fillRect(a+4,c+6,a+4+E.getBattery()*(d-12)/100,c+17),g.setColor(-1)}b=2016,Bangle.on('charging',function(a){a&&Bangle.buzz(),c(),Bangle.drawWidgets(),g.flip()}),Bangle.on('lcdPower',function(b){b?(WIDGETS.bat.draw(),a||(a=setInterval(d,6e4))):a&&(clearInterval(a),a=undefined)}),WIDGETS.bat={area:'tr',width:40,draw:d},c()}()"); +require('Storage').write("widbat.wid.js","(function(){\nvar CHARGING = 0x07E0;\n\nfunction setWidth() {\n WIDGETS[\"bat\"].width = 40 + (Bangle.isCharging()?16:0);\n}\nfunction draw() {\n var s = 39;\n var x = this.x, y = this.y;\n if (Bangle.isCharging()) {\n g.setColor(CHARGING).drawImage(atob(\"DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg\"),x,y);\n x+=16;\n }\n g.setColor(-1);\n g.fillRect(x,y+2,x+s-4,y+21);\n g.clearRect(x+2,y+4,x+s-6,y+19);\n g.fillRect(x+s-3,y+10,x+s,y+14);\n g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17);\n g.setColor(-1);\n}\nBangle.on('charging',function(charging) {\n if(charging) Bangle.buzz();\n setWidth();\n Bangle.drawWidgets(); // relayout widgets\n g.flip();\n});\nvar batteryInterval;\nBangle.on('lcdPower', function(on) {\n if (on) {\n WIDGETS[\"bat\"].draw();\n // refresh once a minute if LCD on\n if (!batteryInterval)\n batteryInterval = setInterval(draw, 60000);\n } else {\n if (batteryInterval) {\n clearInterval(batteryInterval);\n batteryInterval = undefined;\n }\n }\n});\nWIDGETS[\"bat\"]={area:\"tr\",width:40,draw:draw};\nsetWidth();\n})()\n"); require('Storage').write("widbat.info","{\"id\":\"widbat\",\"name\":\"Battery Level Widget\",\"type\":\"widget\",\"version\":\"0.04\",\"files\":\"widbat.info,widbat.wid.js\"}"); -require('Storage').write("widbt.wid.js","setTime(1583773544.468);E.setTimeZone(0)\n!function(a){function c(){g.reset(),NRF.getSecurityStatus().connected?g.setColor(0,.5,1):g.setColor(.3,.3,.3),g.drawImage(a,10+this.x,2+this.y)}function b(){WIDGETS.bluetooth.draw(),g.flip()}a=E.toArrayBuffer(atob('CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==')),NRF.on('connected',b),NRF.on('disconnected',b),WIDGETS.bluetooth={area:'tr',width:24,draw:c}}()"); +require('Storage').write("widbt.wid.js","(function(){\nvar img_bt = E.toArrayBuffer(atob(\"CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==\"));\n\nfunction draw() {\n g.reset();\n if (NRF.getSecurityStatus().connected)\n g.setColor(0,0.5,1);\n else\n g.setColor(0.3,0.3,0.3);\n g.drawImage(img_bt,10+this.x,2+this.y);\n}\nfunction changed() {\n WIDGETS[\"bluetooth\"].draw();\n g.flip();// turns screen on\n}\nNRF.on('connected',changed);\nNRF.on('disconnected',changed);\nWIDGETS[\"bluetooth\"]={area:\"tr\",width:24,draw:draw};\n})()\n"); require('Storage').write("widbt.info","{\"id\":\"widbt\",\"name\":\"Bluetooth Widget\",\"type\":\"widget\",\"version\":\"0.03\",\"files\":\"widbt.info,widbt.wid.js\"}"); -require('Storage').write("welcome.js","setTime(1583773544.671);E.setTimeZone(0)\neval(require('Storage').read('welcome.app.js'))"); -require('Storage').write("welcome.app.js","setTime(1583773545.108);E.setTimeZone(0)\nfunction animate(a,c){var b=setInterval(function(){if(a.length){var c=a.shift();c&&c()}else clearInterval(b)},c)}function fade(c){function b(){for(var d=a;d<240;d+=10)g.drawLine(d,0,0,d),g.drawLine(d,240,240,d);g.flip(),a++,a<10?setTimeout(b,0):c()}var a=0;b()}function move(d){if(d>0&&sceneNumber+1==scenes.length)return;if(sceneNumber=(sceneNumber+d)%scenes.length,sceneNumber<0&&(sceneNumber=0),clearInterval(),scenes[sceneNumber](),sceneNumber>1){var c=scenes.length;for(var a=0;a=1&&(clearInterval(b),setTimeout(()=>g.drawString('Open',34,144),500),setTimeout(()=>g.drawString('Hackable',34,156),1e3),setTimeout(()=>g.drawString('Smart Watch',34,168),1500))},50)},function(){function c(f){a-=b;var e=81.5;g.drawImage(d,e,a),g.clearRect(e,a+81,e+77,a+81+b),a>60?setTimeout(c,0,f):f()}var d=require('heatshrink').decompress(atob('ptRxH+qYAfvl70mj5gAC0ekvd8FkAAdz3HJAYAH4+eJXWkJJYAF0hK2vfNJaIAB5t7S3fN5/V6wAD6vOTg9SumXy2W3QAB3eXul2JdnO63XAApPEVYvAJQIACJoRQDzBLoJQ3W5/NIwr4GJohMFAAROgJYvVJQiPGABZNN3bsdvYyESwnWJSIAC3RNM3V1JjZAES4nVJSYAB4xMNJrbkE56WD5xLVdB5NbFofNJbgABJh26qREPrFXrlbAAWjFgfWJgRLaTQhMLy5KNJINhsJLDrYrD5xLC6pLa5nGTR7oLq9bJQJMKTAXWJbbnR3RLJSoRMHv4pC5rkec6SaIrBLGw2r2XW1epcoqYeJiOXJYziEsOH2RBBw7lF56Yg5nGc6FScZOGJQPX2TmDFIfVTEBMSc4hLEw5KB6+rsJMH63X6pMf5hMQzBLCq5LD1ZLEJhTlfJiWXTA2GJYpMIcwPNc2O6TAuGRIPX1igDJg/PJmyYDcgXWwxMH1ApC53XcsHAJiVYcg2HJYZME0YpC5vWJkhLNJgLlDTAeFJhF/FQfVJkG6JiGXcomyJgOrJYhMErYqD53NJj7lRzBMDcoeGJhzoBJb3GJiN1qZBCJgWyJYpNF1LigAAXAJiNSJgzlGJgt/JkZLRy9TJgeHJhznFcuSZGw5MHJomjcuhLBqdcJiSaiTChMV1CYxy5LCqdXIAWy6+rJhCalTCN2JgdYH4WHJiGpTF7kDc43W2RMJTUZLQzBLFc4mr6+GJh2jTFmXJYyaEwuyc5Sag4xLZTQmG2WFJhxNaJYZMLJZSaEJoOHTR9/Ja+6JbdTqRNETRRNF1JLV4BLcAANYI5ToK1BLYJhWYJZwABq5NoJZ91JaAABdAZNS0ZLey9SJaRNYv5KM426JZmXuxKUJrKcL0lTzBLKzBKYJrVXvfGSol7EYWXJI27zF1JLQADq5NUrgYB4wAEEIV0comXI7wAFrCcPJgYWBTIIAETIN2JYmWuhMkdSdYCgOeJgueqRLFyzhfTi9bq4TC45MF49TuuXJlpONcogAC0hKB0gHDvZMEqRMpAANSq9crlbJAYADqwRDxGk0mIA4eCTQOeveXJdYAHqxNFdAeIAAQGCrOI0oHEAGVXTRJMGvgGCwRM7TAZMHwQGCvhM1rBMERIhMGAwdZJmtSqVTwNcwJEDJg19cvIADa4d9JhANDJnSLHJgrl6AAhFFAwpZDegjn7vhMGcvwABrJAFJgjl/TQpBBI4jl/AAN8TQhHDcv4ADcJBMDvpM+IYaeDAAhL+qd9SgycEJn7iEAA18Jf7nEcv4AIrJLIcv6aMcv4ADvhMHrJJ/AAbl/c6ZM/AAt9cv7nSIv7nLcv4AHrLl/TRpJBvgnjA=='));g.reset(),g.setColor('#6633ff'),g.setBgColor('#6633ff');var a=240,b=5;fade(function(){c(function(){g.setColor(-1),g.setFont('6x8',3),g.setFontAlign(0,0),g.drawString('Welcome.',120,160)})}),setTimeout(function(){var a=0,b=setInterval(function(){a+=5,g.scroll(0,-5),a>170&&clearInterval(b)},20)},3500)},function(){g.reset(),g.setBgColor('#ffa800'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var a=80,b=35,c=35;animate([()=>g.drawString('Your',a,b+=c),()=>g.drawString('Bangle.js',a,b+=c),()=>g.drawString('has',a,b+=c),()=>g.drawString('3 buttons',a,b+=c),()=>g.setFont('Vector',36),g.drawString('1',200,40);,()=>g.drawString('2',200,120),()=>g.drawString('3',200,200)],200)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('1',200,40),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('Move up\\nin menus\\n\\nTurn Bangle.js on\\nif it was off',20,40)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('2',200,120),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('Select menu\\nitem\\n\\nLaunch app\\nwhen watch\\nis showing',20,70)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('3',200,200),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('Move down\\nin menus\\n\\nLong press\\nto exit app\\nand go back\\nto clock',20,100)},function(){g.reset(),g.setBgColor('#ff3300'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',48),g.drawString('1',200,40),g.drawString('2',200,120),g.setFontAlign(-1,-1),g.setFont('6x8',2),g.drawString('If Bangle.js\\never stops,\\nhold buttons\\n1 and 2 for\\naround six\\nseconds.\\n\\n\\n\\nBangle.js will\\nthen reboot.',20,20)},function(){g.reset(),g.setBgColor('#00a8ff'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var a=120,b=10,c=21;animate([()=>g.drawString('Bangle.js has a',a,b+=c),g.drawString('simple touchscreen',a,b+=c);,0,0,()=>g.drawString(\"It'll detect touch\",a,b+=c*2),g.drawString('on left and right',a,b+=c);,0,0,()=>g.drawString('Horizontal swipes',a,b+=c*2),g.drawString('work too. Try now',a,b+=c),g.drawString('to change page.',a,b+=c);],300)},function(){g.reset(),g.setBgColor('#339900'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var a=120,b=10,c=21;animate([()=>g.drawString('Bangle.js',a,b+=c),g.drawString('comes with',a,b+=c),g.drawString('a few simple',a,b+=c),g.drawString('apps installed',a,b+=c);,0,0,()=>g.drawString('To add more, visit',a,b+=c*2),g.drawString('banglejs.com/apps',a,b+=c),g.drawString('with a Bluetooth',a,b+=c),g.drawString('capable device',a,b+=c);],400)},function(){function f(){function c(b,c,a){var d;return d=b*i+a*j,a=a*i-b*j,b=d,d=c*f+a*h,a=a*f-c*h,c=d,a+=4,[96*(.5+b/a),96*(.5+c/a)]}d+=.1,e+=.11;var f=Math.cos(d),h=Math.sin(d),i=Math.cos(e),j=Math.sin(e),b;a.clear(),b=c(-1,-1,-1),a.moveTo(b[0],b[1]),b=c(1,-1,-1),a.lineTo(b[0],b[1]),b=c(1,1,-1),a.lineTo(b[0],b[1]),b=c(-1,1,-1),a.lineTo(b[0],b[1]),b=c(-1,-1,-1),a.lineTo(b[0],b[1]),b=c(-1,-1,1),a.moveTo(b[0],b[1]),b=c(1,-1,1),a.lineTo(b[0],b[1]),b=c(1,1,1),a.lineTo(b[0],b[1]),b=c(-1,1,1),a.lineTo(b[0],b[1]),b=c(-1,-1,1),a.lineTo(b[0],b[1]),b=c(-1,-1,-1),a.moveTo(b[0],b[1]),b=c(-1,-1,1),a.lineTo(b[0],b[1]),b=c(1,-1,-1),a.moveTo(b[0],b[1]),b=c(1,-1,1),a.lineTo(b[0],b[1]),b=c(1,1,-1),a.moveTo(b[0],b[1]),b=c(1,1,1),a.lineTo(b[0],b[1]),b=c(-1,1,-1),a.moveTo(b[0],b[1]),b=c(-1,1,1),a.lineTo(b[0],b[1]),g.drawImage({width:96,height:96,buffer:a.buffer},72,68)}g.reset(),g.setBgColor('#990066'),g.clear(),g.setFont('6x8',2),g.setFontAlign(0,0);var c=120,b=10,a=21;g.drawString('You can also make',c,b+=a),g.drawString('your own apps!',c,b+=a),b=160,g.drawString('Check out',c,b+=a),g.drawString('banglejs.com',c,b+=a);var d=0,e=0,a=Graphics.createArrayBuffer(96,96,1,{msb:!0});setInterval(f,50)},function(){g.reset(),g.setBgColor('#660099'),g.clear(),g.setFontAlign(0,0),g.setFont('Vector',36),g.drawString('2',200,120),g.setFont('6x8',2);var a=90,b=30,c=21;animate([()=>g.drawString(\"That's it!\",a,b+=c),()=>g.drawString('Press',a,b+=c*3),g.drawString('Button 2',a,b+=c),g.drawString('to start',a,b+=c),g.drawString('Bangle.js',a,b+=c);],400)}],sceneNumber=0;Bangle.on('swipe',move),setWatch(()=>move(1),BTN3,{repeat:!0}),setWatch(()=>if(sceneNumber==scenes.length-1){var settings=require('Storage').readJSON('setting.json',1)||{};settings.welcomed=!0,require('Storage').write('setting.json',settings),load()},BTN2,{repeat:!0,edge:'rising'}),setWatch(()=>move(-1),BTN1,{repeat:!0}),Bangle.setLCDTimeout(0),Bangle.setLCDPower(1),move(0)"); -require('Storage').write("welcome.img",setTime(1583773545.313);E.setTimeZone(0) -require('heatshrink').decompress(atob('mEwxH+AH4A/AH4AU5gAEFtoxnEwXN53WAAXO5oJB42Wy26AAIueFoPXFggAD4AwEGTQiB6otBFgwAD3QvFGC5dCFxiRGGClhrdbv67BXAIuLMBIwPsIABF4OpLwXOFxjBCF6gtBw2r1mHXoXWFxqQWFwOH62rL4IeB6xeOAAIvHGBYuC6+rR4QvCXpovXw3X1i/DR4QuPR5AvKFQOs6+GF4eod4IvPd5AvLwvWLwQvCv4fBR54vURwOHF4iQCX0yOCF4aQBX0QvHSAoAN3SOSd4WyF4yQPLyhgD1YvDMCJeIFxhgCF47BN4BeHFxpgDSAiRORpAuPMIYAFGBYuaF5aSHFwQvEFqQwOeggSBLa4xNF4X+4wAC/xeCFjIADrYwGBIIvlMQiPDBAOk0gDBz2XF8BlEF4eIxADFF8lcF9n+wIrFF05bHF9AsGF9wupGAYv/F8QupGAov/F/4wOF1gA/AH4Ap'))); +require('Storage').write("welcome.js","eval(require(\"Storage\").read(\"welcome.app.js\"))\n"); +require('Storage').write("welcome.app.js","// exec each function from seq one after the other\nfunction animate(seq,period) {\n var i = setInterval(function() {\n if (seq.length) {\n var f = seq.shift();\n if (f) f();\n } else clearInterval(i);\n },period);\n}\n\n// Fade in to FG color with angled lines\nfunction fade(callback) {\n var n = 0;\n function f() {\n for (var i=n;i<240;i+=10) {\n g.drawLine(i,0,0,i);\n g.drawLine(i,240,240,i);\n }\n g.flip();\n n++;\n if (n<10) setTimeout(f,0);\n else callback();\n }\n f();\n}\n\n\nvar scenes = [\n function() {\n g.clear(1);\n g.setFont(\"4x6\",2);\n var n=0;\n var i = setInterval(function() {\n n+=0.04;\n g.setColor(n,n,n);\n g.drawImage(Bangle.getLogo(),(240-222)/2,(240-100)/2);\n if (n>=1) {\n clearInterval(i);\n setTimeout(()=>g.drawString(\"Open\",34,144), 500);\n setTimeout(()=>g.drawString(\"Hackable\",34,156), 1000);\n setTimeout(()=>g.drawString(\"Smart Watch\",34,168), 1500);\n }\n },50);\n },function() {\n var img = require(\"heatshrink\").decompress(atob(\"ptRxH+qYAfvl70mj5gAC0ekvd8FkAAdz3HJAYAH4+eJXWkJJYAF0hK2vfNJaIAB5t7S3fN5/V6wAD6vOTg9SumXy2W3QAB3eXul2JdnO63XAApPEVYvAJQIACJoRQDzBLoJQ3W5/NIwr4GJohMFAAROgJYvVJQiPGABZNN3bsdvYyESwnWJSIAC3RNM3V1JjZAES4nVJSYAB4xMNJrbkE56WD5xLVdB5NbFofNJbgABJh26qREPrFXrlbAAWjFgfWJgRLaTQhMLy5KNJINhsJLDrYrD5xLC6pLa5nGTR7oLq9bJQJMKTAXWJbbnR3RLJSoRMHv4pC5rkec6SaIrBLGw2r2XW1epcoqYeJiOXJYziEsOH2RBBw7lF56Yg5nGc6FScZOGJQPX2TmDFIfVTEBMSc4hLEw5KB6+rsJMH63X6pMf5hMQzBLCq5LD1ZLEJhTlfJiWXTA2GJYpMIcwPNc2O6TAuGRIPX1igDJg/PJmyYDcgXWwxMH1ApC53XcsHAJiVYcg2HJYZME0YpC5vWJkhLNJgLlDTAeFJhF/FQfVJkG6JiGXcomyJgOrJYhMErYqD53NJj7lRzBMDcoeGJhzoBJb3GJiN1qZBCJgWyJYpNF1LigAAXAJiNSJgzlGJgt/JkZLRy9TJgeHJhznFcuSZGw5MHJomjcuhLBqdcJiSaiTChMV1CYxy5LCqdXIAWy6+rJhCalTCN2JgdYH4WHJiGpTF7kDc43W2RMJTUZLQzBLFc4mr6+GJh2jTFmXJYyaEwuyc5Sag4xLZTQmG2WFJhxNaJYZMLJZSaEJoOHTR9/Ja+6JbdTqRNETRRNF1JLV4BLcAANYI5ToK1BLYJhWYJZwABq5NoJZ91JaAABdAZNS0ZLey9SJaRNYv5KM426JZmXuxKUJrKcL0lTzBLKzBKYJrVXvfGSol7EYWXJI27zF1JLQADq5NUrgYB4wAEEIV0comXI7wAFrCcPJgYWBTIIAETIN2JYmWuhMkdSdYCgOeJgueqRLFyzhfTi9bq4TC45MF49TuuXJlpONcogAC0hKB0gHDvZMEqRMpAANSq9crlbJAYADqwRDxGk0mIA4eCTQOeveXJdYAHqxNFdAeIAAQGCrOI0oHEAGVXTRJMGvgGCwRM7TAZMHwQGCvhM1rBMERIhMGAwdZJmtSqVTwNcwJEDJg19cvIADa4d9JhANDJnSLHJgrl6AAhFFAwpZDegjn7vhMGcvwABrJAFJgjl/TQpBBI4jl/AAN8TQhHDcv4ADcJBMDvpM+IYaeDAAhL+qd9SgycEJn7iEAA18Jf7nEcv4AIrJLIcv6aMcv4ADvhMHrJJ/AAbl/c6ZM/AAt9cv7nSIv7nLcv4AHrLl/TRpJBvgnjA==\"));\n g.reset();\n g.setColor(\"#6633ff\");\n g.setBgColor(\"#6633ff\");\n var y = 240, speed = 5;\n function balloon(callback) {\n y-=speed;\n var x = (240-77)/2;\n g.drawImage(img,x,y);\n g.clearRect(x,y+81,x+77,y+81+speed);\n if (y>60) setTimeout(balloon,0,callback);\n else callback();\n }\n fade(function() {\n balloon(function() {\n g.setColor(-1);\n g.setFont(\"6x8\",3);\n g.setFontAlign(0,0);\n g.drawString(\"Welcome.\",120,160);\n });\n });\n setTimeout(function() {\n var n=0;\n var i = setInterval(function() {\n n+=5;\n g.scroll(0,-5);\n if (n>170)\n clearInterval(i);\n },20);\n },3500);\n\n },function() {\n g.reset();\n g.setBgColor(\"#ffa800\");g.clear();\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n var x = 80, y = 35, h=35;\n animate([\n ()=>g.drawString(\"Your\",x,y+=h),\n ()=>g.drawString(\"Bangle.js\",x,y+=h),\n ()=>g.drawString(\"has\",x,y+=h),\n ()=>g.drawString(\"3 buttons\",x,y+=h),\n ()=>{g.setFont(\"Vector\",36);g.drawString(\"1\",200,40);},\n ()=>g.drawString(\"2\",200,120),\n ()=>g.drawString(\"3\",200,200)\n ],200);\n },\n function() {\n g.reset();\n g.setBgColor(\"#00a8ff\");g.clear();\n g.setFontAlign(0,0);\n g.setFont(\"Vector\",48);\n g.drawString(\"1\",200,40);\n g.setFontAlign(-1,-1);\n g.setFont(\"6x8\",2);\n g.drawString(\"Move up\\nin menus\\n\\nTurn Bangle.js on\\nif it was off\", 20,40);\n },\n function() {\n g.reset();\n g.setBgColor(\"#00a8ff\");g.clear();\n g.setFontAlign(0,0);\n g.setFont(\"Vector\",48);\n g.drawString(\"2\",200,120);\n g.setFontAlign(-1,-1);\n g.setFont(\"6x8\",2);\n g.drawString(\"Select menu\\nitem\\n\\nLaunch app\\nwhen watch\\nis showing\", 20,70);\n },\n function() {\n g.reset();\n g.setBgColor(\"#00a8ff\");g.clear();\n g.setFontAlign(0,0);\n g.setFont(\"Vector\",48);\n g.drawString(\"3\",200,200);\n g.setFontAlign(-1,-1);\n g.setFont(\"6x8\",2);\n g.drawString(\"Move down\\nin menus\\n\\nLong press\\nto exit app\\nand go back\\nto clock\", 20,100);\n },\n function() {\n g.reset();\n g.setBgColor(\"#ff3300\");g.clear();\n g.setFontAlign(0,0);\n g.setFont(\"Vector\",48);\n g.drawString(\"1\",200,40);\n g.drawString(\"2\",200,120);\n g.setFontAlign(-1,-1);\n g.setFont(\"6x8\",2);\n g.drawString(\"If Bangle.js\\never stops,\\nhold buttons\\n1 and 2 for\\naround six\\nseconds.\\n\\n\\n\\nBangle.js will\\nthen reboot.\", 20,20);\n },\n function() {\n g.reset();\n g.setBgColor(\"#00a8ff\");g.clear();\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n var x = 120, y = 10, h=21;\n animate([\n ()=>{g.drawString(\"Bangle.js has a\",x,y+=h);\n g.drawString(\"simple touchscreen\",x,y+=h);},\n 0,0,\n ()=>{g.drawString(\"It'll detect touch\",x,y+=h*2);\n g.drawString(\"on left and right\",x,y+=h);},\n 0,0,\n ()=>{g.drawString(\"Horizontal swipes\",x,y+=h*2);\n g.drawString(\"work too. Try now\",x,y+=h);\n g.drawString(\"to change page.\",x,y+=h);}\n ],300);\n },\n function() {\n g.reset();\n g.setBgColor(\"#339900\");g.clear();\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n var x = 120, y = 10, h=21;\n animate([\n ()=>{g.drawString(\"Bangle.js\",x,y+=h);\n g.drawString(\"comes with\",x,y+=h);\n g.drawString(\"a few simple\",x,y+=h);\n g.drawString(\"apps installed\",x,y+=h);},\n 0,0,\n ()=>{g.drawString(\"To add more, visit\",x,y+=h*2);\n g.drawString(\"banglejs.com/apps\",x,y+=h);\n g.drawString(\"with a Bluetooth\",x,y+=h);\n g.drawString(\"capable device\",x,y+=h);},\n ],400);\n },\n function() {\n g.reset();\n g.setBgColor(\"#990066\");g.clear();\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n var x = 120, y = 10, h=21;\n g.drawString(\"You can also make\",x,y+=h);\n g.drawString(\"your own apps!\",x,y+=h);\n y=160;\n g.drawString(\"Check out\",x,y+=h);\n g.drawString(\"banglejs.com\",x,y+=h);\n\n var rx = 0, ry = 0;\n var h = Graphics.createArrayBuffer(96,96,1,{msb:true});\n // draw a cube\n function draw() {\n // rotate\n rx += 0.1;\n ry += 0.11;\n var rcx=Math.cos(rx),\n rsx=Math.sin(rx),\n rcy=Math.cos(ry),\n rsy=Math.sin(ry);\n // Project 3D coordinates into 2D\n function p(x,y,z) {\n var t;\n t = x*rcy + z*rsy;\n z = z*rcy - x*rsy;\n x=t;\n t = y*rcx + z*rsx;\n z = z*rcx - y*rsx;\n y=t;\n z += 4;\n return [96*(0.5+x/z), 96*(0.5+y/z)];\n }\n\n var a;\n // draw a series of lines to make up our cube\n h.clear();\n a = p(-1,-1,-1); h.moveTo(a[0],a[1]);\n a = p(1,-1,-1); h.lineTo(a[0],a[1]);\n a = p(1,1,-1); h.lineTo(a[0],a[1]);\n a = p(-1,1,-1); h.lineTo(a[0],a[1]);\n a = p(-1,-1,-1); h.lineTo(a[0],a[1]);\n a = p(-1,-1,1); h.moveTo(a[0],a[1]);\n a = p(1,-1,1); h.lineTo(a[0],a[1]);\n a = p(1,1,1); h.lineTo(a[0],a[1]);\n a = p(-1,1,1); h.lineTo(a[0],a[1]);\n a = p(-1,-1,1); h.lineTo(a[0],a[1]);\n a = p(-1,-1,-1); h.moveTo(a[0],a[1]);\n a = p(-1,-1,1); h.lineTo(a[0],a[1]);\n a = p(1,-1,-1); h.moveTo(a[0],a[1]);\n a = p(1,-1,1); h.lineTo(a[0],a[1]);\n a = p(1,1,-1); h.moveTo(a[0],a[1]);\n a = p(1,1,1); h.lineTo(a[0],a[1]);\n a = p(-1,1,-1); h.moveTo(a[0],a[1]);\n a = p(-1,1,1); h.lineTo(a[0],a[1]);\n g.drawImage({width:96,height:96,buffer:h.buffer},(240-96)/2,68);\n }\n\n setInterval(draw,50);\n },\n function() {\n g.reset();\n g.setBgColor(\"#660099\");g.clear();\n g.setFontAlign(0,0);\n g.setFont(\"Vector\",36);\n g.drawString(\"2\",200,120);\n g.setFont(\"6x8\",2);\n\n var x = 90, y = 30, h=21;\n animate([\n ()=>g.drawString(\"That's it!\",x,y+=h),\n ()=>{g.drawString(\"Press\",x,y+=h*3);\n g.drawString(\"Button 2\",x,y+=h);\n g.drawString(\"to start\",x,y+=h);\n g.drawString(\"Bangle.js\",x,y+=h);}\n ],400);\n }\n];\n\nvar sceneNumber = 0;\n\nfunction move(dir) {\n if (dir>0 && sceneNumber+1 == scenes.length) return; // at the end\n sceneNumber = (sceneNumber+dir)%scenes.length;\n if (sceneNumber<0) sceneNumber=0;\n clearInterval();\n scenes[sceneNumber]();\n if (sceneNumber>1) {\n var l = scenes.length;\n for (var i=0;imove(1), BTN3, {repeat:true});\nsetWatch(()=>{\n // If we're on the last page\n if (sceneNumber == scenes.length-1) {\n var settings = require(\"Storage\").readJSON('setting.json',1)||{};\n settings.welcomed = true;\n require(\"Storage\").write('setting.json',settings);\n load();\n }\n}, BTN2, {repeat:true,edge:\"rising\"});\nsetWatch(()=>move(-1), BTN1, {repeat:true});\n\n\n\nBangle.setLCDTimeout(0);\nBangle.setLCDPower(1);\nmove(0);\n"); +require('Storage').write("welcome.img",require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AU5gAEFtoxnEwXN53WAAXO5oJB42Wy26AAIueFoPXFggAD4AwEGTQiB6otBFgwAD3QvFGC5dCFxiRGGClhrdbv67BXAIuLMBIwPsIABF4OpLwXOFxjBCF6gtBw2r1mHXoXWFxqQWFwOH62rL4IeB6xeOAAIvHGBYuC6+rR4QvCXpovXw3X1i/DR4QuPR5AvKFQOs6+GF4eod4IvPd5AvLwvWLwQvCv4fBR54vURwOHF4iQCX0yOCF4aQBX0QvHSAoAN3SOSd4WyF4yQPLyhgD1YvDMCJeIFxhgCF47BN4BeHFxpgDSAiRORpAuPMIYAFGBYuaF5aSHFwQvEFqQwOeggSBLa4xNF4X+4wAC/xeCFjIADrYwGBIIvlMQiPDBAOk0gDBz2XF8BlEF4eIxADFF8lcF9n+wIrFF05bHF9AsGF9wupGAYv/F8QupGAov/F/4wOF1gA/AH4Ap"))); require('Storage').write("welcome.info","{\"id\":\"welcome\",\"name\":\"Welcome\",\"src\":\"welcome.app.js\",\"icon\":\"welcome.img\",\"version\":\"0.04\",\"files\":\"welcome.info,welcome.js,welcome.app.js,welcome.img\"}"); From 2318d10a0107d54e22999f0ea921db118c64e9ab Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 10 Mar 2020 15:34:07 +0000 Subject: [PATCH 45/55] better titles --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index f8188e88d..f2d655f9f 100644 --- a/apps.json +++ b/apps.json @@ -817,8 +817,8 @@ "name": "Bluetooth ID Widget", "icon": "widget.png", "version":"0.02", - "description": "Display the last two tuple of your Bangle.js address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", - "tags": "widget", + "description": "Display the last two tuple of your Bangle.js MAC address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", + "tags": "widget,address,mac", "type":"widget", "storage": [ {"name":"widid.wid.js","url":"widget.js"} From 5bcff17dc20d623a948f5e2cf302ffa6cd218c11 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 11 Mar 2020 16:30:36 +0000 Subject: [PATCH 46/55] remove unused code --- bin/firmwaremaker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 13d4504ec..e5db392dd 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -54,7 +54,7 @@ Promise.all(APPS.map(appid => { }); })).then(() => { //console.log(appfiles); - var js = "// Generated by BangleApps/bin/firmwaremaker.js\nreset(1)\nvar FAIL=0;\n"; + var js = "// Generated by BangleApps/bin/firmwaremaker.js\n"; appfiles.forEach((file) => { js += file.cmd+"\n"; /*if (file.crc && file.evaluate!==true) { From 6c7c9c2bc1a53c60b311063bdd9aeba00c271808 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 11 Mar 2020 16:30:51 +0000 Subject: [PATCH 47/55] Make 2v04 text less annoying --- index.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index eeac78468..324fda468 100644 --- a/index.html +++ b/index.html @@ -50,9 +50,8 @@
-

App Loader is incompatible with 'old' Bangle.js firmwares - (more info) Please update to the latest firmware or - use the legacy apps. +

Note: If you have a version of Bangle.js firmware before 2v04, please update to the latest firmware or + use the legacy app loader.

From d07dc1de6fe9948edd0418c69352200f28d07f6a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 12 Mar 2020 16:46:39 +0000 Subject: [PATCH 48/55] Stop users calling save() (fix #125) If Debug info is set to 'show' don't move to Terminal if connected! --- apps.json | 2 +- apps/boot/ChangeLog | 2 ++ apps/boot/boot0.js | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index f2d655f9f..350dc7a72 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "boot", "name": "Bootloader", "icon": "bootloader.png", - "version":"0.09", + "version":"0.10", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "tags": "tool,system", "type":"bootloader", diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 8cd322022..093f017b2 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -6,3 +6,5 @@ 0.07: Fix issues with alarm scheduling 0.08: Fix issues if BLE=off, 'Make Connectable' is chosen, and the loader resets Bangle.js (fix #108) 0.09: Only check GPS for time after a fresh boot +0.10: Stop users calling save() (fix #125) + If Debug info is set to 'show' don't move to Terminal if connected! diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index db2533400..cb8d49ba0 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -12,7 +12,7 @@ if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth if (s.log) Terminal.setConsole(true); // if showing debug, force REPL onto terminal else E.setConsole(null,{force:true}); // on new (2v05+) firmware we have E.setConsole which allows a 'null' console } else { - if (s.log) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection) + if (s.log && !NRF.getSecurityStatus().connected) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection) else Bluetooth.setConsole(true); // else if no debug, force REPL to Bluetooth } // we just reset, so BLE should be on. @@ -25,6 +25,8 @@ Bangle.setLCDTimeout(s.timeout); if (!s.timeout) Bangle.setLCDPower(1); E.setTimeZone(s.timezone); delete s; +// stop users doing bad things! +global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); } // check for alarms var alarms = require('Storage').readJSON('alarm.json',1)||[]; var time = new Date(); From 77ad48f016c9070398f5089caeecd4cc60610c84 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 16 Mar 2020 09:04:13 +0000 Subject: [PATCH 49/55] Add github link to repo in the app overview (fix #127) --- index.html | 20 +++++++++++++------- index.js | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 324fda468..f18c05352 100644 --- a/index.html +++ b/index.html @@ -29,13 +29,19 @@ } .chip { cursor: pointer; + } + .tile-content { position: relative; } + .link-github { + position:absolute; + top: 36px; + left: -24px; }
-

Note: If you have a version of Bangle.js firmware before 2v04, please update to the latest firmware or +

Note: If you have a version of Bangle.js firmware before 2v04, please update to the latest firmware or use the legacy app loader.

@@ -103,15 +109,15 @@