From c02e388cd910e68eda8993d784023ed3c0367a31 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Sun, 10 Nov 2019 14:01:12 +0000 Subject: [PATCH] more tweaking --- apps/start-tf.js | 2 +- apps/start.js | 5 ++--- bin/firmwaremaker.js | 15 ++++++++++----- firmware.js | 20 ++++++++++++++------ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/apps/start-tf.js b/apps/start-tf.js index 5be986c32..d09185caf 100644 --- a/apps/start-tf.js +++ b/apps/start-tf.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("+FrghC/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AD0RiIEDiBG/KqAABKbp3/O7JYDO/530KjkBO/7NYKgQGCL4UBBAQLEAYINDNgYEBO4wYDAQIMEAH53JJwIDDBgYLFBIRvCRggFDEwYbEO/53Ma4RWDAwgLGO44MEO44MCUwgA/O4wAEcoRWBO4jRCfIbyCAQZqHBgYaDA4QA/O5RQCMYZ3GbQhnDA4ocDN4aSEO/53MLQh1DQYp3Od453DQYgA/O4wECO5UQO4cAO4wECd5YSDN/53PAQJxCAQoUCM4YCEd5QHCO/53PKAZ6HBYoHGO4INEEAryDAYIA/O55VEO5YLBRYh3/O7gGFO4YLGMAchAgZ3JBgR3/AG6WEAH53/AH4AqiMQIP532IH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACPdABPQG+nQAYR3/O/53/O/53/O/53/O/4AWho5yNpJ38ddh3/O55BCA4b+DBQwLDSYwJH5oGBEAx3NAwQHDEgggDSER3GHIY1GMgY0DA4iMHLA4IEO54oHO+JZFFQQIGIopuNBIR3VGYwyBBo53pNpB3HGoKBJBI53XGRB3HGQMMKoh3gMaJ3FJIbGEaBJ3RGRgSEIwh3megoJGIAZEECYRtECQhwECgqIKGRPQO5h2dGopOFNpJEIO4a7GdBR3QGRISECY533NwYhGDop3UChAyEAYR3sJIxkFIBJ3rBQY2GCYx3zCgoMHAwp3kEoQCDO/C5EA4ooHMRQAFO/53TCox3rOhB38eIoSGO8wFJO8wOLO45MEO5RiLO/53YNooZCO4xiOO6QlBO95aHO5o7DLAp3cGRIPEDQR3rOYp3S7hGDTQx3XNYp3FApB3iUIilEO5JODAAaVFBIp3UHhJ3/O6xwIO5wfGNQYGFIgp3jHQwOKbgjFJZBB3SD4xNGKZB3jPAqqIAopNIBJB3WHg53KOz6bILIx3LJwa3FBIfAA4XNO6o8HO9YA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4Ae")) +require("heatshrink").decompress(atob("4M7ghC/AH4A/AEcBiMQAgY+3iIACIAQhcAgYjdTzZgfYH5giYHo5BIIQGDAQYLHgMQBoZZFYAoYENGREDGgI6BAYYMDBYrXDA4RTDAobnFLgbNEYF5LFVAIGCAghsEBQYMFYAoMEC4TAxAAg5DLoqiCZQZ2CAQa2DYAiGFA4bAvXYj6DAIZkEVYizHLYhyDNoaGCL9zAEHw5aGOIwHJYAqBFL96zCHxJsEKwcBYAx5GYA4SCFobAuMohoDAQ4UCKgYCEYBR7FYGqsDIIwLFYAzUFYAhbEL+IyGIojAFBYbAEKYZYHCgghEYGoGFWoQGFJIYHBgRZDbQpsFYGiNuIP4AedooA/L/4A5gJf/AH4A/AH4A/AH4A/AH4A/AH4A/ACsN7oAJG+oJC6AoaL5QmbG7PQTLrA/YH7A/YH7AhFgxbrYA4JQFkTArWwzAlEQhnCA4bPDBQwLDHwwJH5oGBEAydNAwQHDEgggDcaJBDEY4JDJoYSEH5A7GBAbAPHg5aHCQoiSEYpNHBIxpIBIQHGTpwzGGQJlMESZCIFowTNCQLAVSZAXFGQnNL5AiNBJAeBBIYsDNJIJHTpwyMCQhGEQQwsFYo7kGAoQJDEQQyDS5ChDCgxRJGRJ4DUIpAFYBQiFJgwUGBIr3IIAy5EaJgyNcgoTGcZZCFWwxMLboxqLYBoUJGw5GIYBaSGFoo3GLApAOYCAUJQYycLYBCSHDIoUJYBfdYDwKDEwQFCBAbAfIwwHEFA6rKTpLAPEoQCDYEBgIFgzAMHwzAOXpDAkMIxALYD4wEAozAOaA7AKMIxAJVZjAWApLAOBxasGEYYZCIAyrOYCQlBYC4jGhpHCYBBpJAYSrSTp4FELQZmFYBoRDBQjAMGwvcHQYiEdBDANHgpTFApbALaYgWERpISGHYoJFYCo8JVBKAHFg5COAoY2JBI65IYBofHOYZmIYBxgGNIr4KSxJJHYCQfGCQhmIYBwjFPZDVKQg53IYCI8IBIgFIERgjEPZLVJEhHcAwUMYCo8IYBIfGAH4A/AHw")) diff --git a/apps/start.js b/apps/start.js index 959532993..d852a7edc 100644 --- a/apps/start.js +++ b/apps/start.js @@ -48,7 +48,7 @@ function logos() { }], ['bangle', 70, 90, ()=>{}], ['nodew', 20, 90, ()=>{}], - ['tf', 5, 60, ()=>{}], + ['tf', 24, 90, ()=>{}], ]; function next() { var n = logos.shift(); @@ -88,8 +88,7 @@ function info() { }, () => { g.clear(); - E.showMessage('Hold both\nto return\nto clock'); - g.drawImage(c([0,8,12,14,255,14,12,8]),d,40); + E.showMessage('Hold\nto return\nto clock'); g.drawImage(c([0,8,12,14,255,14,12,8]),d,194); }, () => { diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 2f7241335..c4d854bff 100644 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -13,13 +13,13 @@ var APPS = [ // IDs of apps to install "boot", "mclock", "setting", - "trex", + "astroid", "gpstime", "compass", "sbat", "funrun5", "nceuwid", - //"start" + "start" ]; var fs = require("fs"); @@ -29,9 +29,14 @@ var appfiles = []; function fileGetter(url) { console.log("Loading "+url) - if (url.endsWith(".js")) { - // 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"; + }*/ return Promise.resolve(fs.readFileSync(url).toString()); } diff --git a/firmware.js b/firmware.js index 91ea427d9..5a102d1df 100644 --- a/firmware.js +++ b/firmware.js @@ -1,10 +1,10 @@ -require('Storage').write(".bootcde","E.setTimeZone(1);\nE.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.setLCDMode(\"direct\");\n g.clear();\n clearInterval();\n clearWatch();\n Bangle.removeAllListeners();\n\n var s = require(\"Storage\");\n\n 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+1WIDGETS[k].draw());\n }\n\n var clockApp = require(\"Storage\").list().filter(a=>a[0]=='+').map(app=>{\n try { return require(\"Storage\").readJSON(app); }\n catch (e) {}\n }).find(app=>app.type==\"clock\");\n if (clockApp) eval(require(\"Storage\").read(clockApp.src));\n else E.showMessage(\"No Clock Found\");\n delete clockApp;\n require(\"Storage\").list().filter(a=>a[0]=='=').forEach(widget=>eval(require(\"Storage\").read(widget)));\n setTimeout(drawWidgets,100);\n}\n"); +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 delete startapp;\n setWatch(function displayMenu() {\n Bangle.setLCDMode(\"direct\");\n g.clear();\n clearInterval();\n clearWatch();\n Bangle.removeAllListeners();\n var s = require(\"Storage\");\n\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+1WIDGETS[k].draw());\n }\n var clockApp = require(\"Storage\").list().filter(a=>a[0]=='+').map(app=>{\n try { return require(\"Storage\").readJSON(app); }\n catch (e) {}\n }).find(app=>app.type==\"clock\");\n if (clockApp) eval(require(\"Storage\").read(clockApp.src));\n else E.showMessage(\"No Clock Found\");\n delete clockApp;\n require(\"Storage\").list().filter(a=>a[0]=='=').forEach(widget=>eval(require(\"Storage\").read(widget)));\n setTimeout(drawWidgets,100);\n}\n"); require('Storage').write("+mclock",{"name":"Morphing Clock","type":"clock","icon":"*mclock","src":"-mclock","sortorder":-10,"files":"+mclock,-mclock,*mclock"}); require('Storage').write("-mclock","// Enable 'Set Current Time' in Settings -> Communications before sending\n(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","files":"+setting,-setting,=setting,@setting,*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'); // - not needed, just causes extra writes if settings were the same\n storage.write('@setting', settings);\n}\n\nfunction resetSettings() {\n settings = {\n ble: false,\n dev: false,\n timeout: 10,\n vibrate: true,\n beep: true,\n timezone: 0,\n HID : false,\n HIDGestures: false,\n debug: false,\n };\n setLCDTimeout(settings.timeout);\n updateSettings();\n}\n\ntry {\n settings = storage.readJSON('@setting');\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 'Dev': {\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 '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');\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 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}\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: d.getFullYear() - 10,\n max: d.getFullYear() + 10,\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","// Report from https://notes.iopush.net/custom-usb-hid-device-descriptor-media-keyboard/\n/*Bangle.HID = new Uint8Array([\n // Keyboard Controls\n 0x05, 0x01,\n 0x09, 0x06,\n 0xA1, 0x01,\n 0x85, 0x02,\n 0x05, 0x07,\n 0x19, 0xe0,\n 0x29, 0xe7,\n 0x15, 0x00,\n 0x25, 0x01,\n 0x75, 0x01,\n 0x95, 0x08,\n 0x81, 0x02,\n 0x95, 0x01,\n 0x75, 0x08,\n 0x81, 0x01,\n 0x95, 0x05,\n 0x75, 0x01,\n 0x05, 0x08,\n 0x19, 0x01,\n 0x29, 0x05,\n 0x91, 0x02,\n 0x95, 0x01,\n 0x75, 0x03,\n 0x91, 0x01,\n 0x95, 0x06,\n 0x75, 0x08,\n 0x15, 0x00,\n 0x25, 0x73,\n 0x05, 0x07,\n 0x19, 0x00,\n 0x29, 0x73,\n 0x81, 0x00,\n 0x09, 0x05,\n 0x15, 0x00,\n 0x26, 0xFF, 0x00,\n 0x75, 0x08,\n 0x95, 0x02,\n 0xB1, 0x02,\n 0xC0,\n\n // Music Controls\n 0x05, 0x0C,\n 0x09, 0x01,\n 0xA1, 0x01,\n 0x85, 0x01,\n 0x15, 0x00,\n 0x25, 0x01,\n 0x75, 0x01,\n 0x95, 0x01,\n 0x09, 0xB5,\n 0x81, 0x02,\n 0x09, 0xB6,\n 0x81, 0x02,\n 0x09, 0xB7,\n 0x81, 0x02,\n 0x09, 0xB8,\n 0x81, 0x02,\n 0x09, 0xCD,\n 0x81, 0x02,\n 0x09, 0xE2,\n 0x81, 0x02,\n 0x09, 0xE9,\n 0x81, 0x02,\n 0x09, 0xEA,\n 0x81, 0x02,\n 0xC0\n]);*/\n// More compact HID representation\nBangle.HID = E.toUint8Array(atob(\"BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==\"));\n(function() {\n var s = require('Storage').readJSON('@setting');\n if (s.ble) {\n if (s.dev)\n Bluetooth.setConsole();\n else\n LoopbackA.setConsole(true);\n var adv = { uart: true };\n if (s.HID) {\n adv.hid = Bangle.HID;\n } else\n delete Bangle.HID;\n NRF.setServices({}, adv);\n try {\n NRF.wake();\n } catch (e) {}\n } else {\n NRF.sleep();\n }\n\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","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'); // - not needed, just causes extra writes if settings were the same\n storage.write('@setting', settings);\n}\n\nfunction resetSettings() {\n settings = {\n ble: false,\n dev: false,\n timeout: 10,\n vibrate: true,\n beep: true,\n timezone: 0,\n HID : false,\n HIDGestures: false,\n debug: false,\n };\n setLCDTimeout(settings.timeout);\n updateSettings();\n}\n\ntry {\n settings = storage.readJSON('@setting');\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 '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');\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}\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: d.getFullYear() - 10,\n max: d.getFullYear() + 10,\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');\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 setTimeout(function() {\n NRF.setServices({}, adv);\n if (s.ble) NRF.wake();\n else NRF.sleep();\n },10);\n\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",{ ble: false, // Bluetooth disabled by default dev: false, // Espruino IDE disabled by default @@ -17,9 +17,9 @@ 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("+trex",{"name":"T-Rex","type":"app","icon":"*trex","src":"-trex","files":"+trex,-trex,*trex"}); -require('Storage').write("-trex","greal = g;\ng.clear();\ng = Graphics.createArrayBuffer(120,64,1,{msb:true});\ng.flip = function() {\n greal.drawImage({\n width:120,\n height:64,\n buffer:g.buffer\n },0,(240-128)/2,{scale:2});\n};\nvar W = g.getWidth();\nvar BTNL = BTN4;\nvar BTNR = BTN5;\nvar BTNU = BTN1;\n\n// Images can be added like this in Espruino v2.00\nvar IMG = {\n rex: [Graphics.createImage(`\n ########\n ##########\n ## #######\n ##########\n ##########\n ##########\n #####\n ########\n# #####\n# #######\n## ##########\n### ######### #\n##############\n##############\n ############\n ###########\n #########\n #######\n ### ##\n ## #\n #\n ##\n`),Graphics.createImage(`\n ########\n ##########\n ## #######\n ##########\n ##########\n ##########\n #####\n ########\n# #####\n# #######\n## ##########\n### ######### #\n##############\n##############\n ############\n ###########\n #########\n #######\n ### ##\n ## ##\n #\n ##\n`),Graphics.createImage(`\n ########\n # ######\n # # ######\n # ######\n ##########\n ##########\n #####\n ########\n# #####\n# #######\n## ##########\n### ######### #\n##############\n##############\n ############\n ###########\n #########\n #######\n ### ##\n ## #\n # #\n ## ##\n`)],\n cacti: [Graphics.createImage(`\n ##\n ####\n ####\n ####\n ####\n #### #\n # #### ###\n### #### ###\n### #### ###\n### #### ###\n### #### ###\n### #### ###\n### #### ###\n### #### ###\n###########\n #########\n ####\n ####\n ####\n ####\n ####\n ####\n ####\n ####\n`),Graphics.createImage(`\n ##\n ##\n # ##\n## ## #\n## ## #\n## ## #\n## ## #\n##### #\n #### #\n #####\n ####\n ##\n ##\n ##\n ##\n ##\n ##\n ##\n`)],\n};\nIMG.rex.forEach(i=>i.transparent=0);\nIMG.cacti.forEach(i=>i.transparent=0);\nvar cacti, rex, frame;\n\nfunction gameStart() {\n rex = {\n alive : true,\n img : 0,\n x : 10, y : 0,\n vy : 0,\n score : 0\n };\n cacti = [ { x:W, img:1 } ];\n var random = new Uint8Array(128*3/8);\n for (var i=0;i<50;i++) {\n var a = 0|(Math.random()*random.length);\n var b = 0|(Math.random()*8);\n random[a]|=1<0) rex.x--;\n if (BTNR.read() && rex.x<20) rex.x++;\n if (BTNU.read() && rex.y==0) rex.vy=4;\n rex.y += rex.vy;\n rex.vy -= 0.2;\n if (rex.y<=0) {rex.y=0; rex.vy=0; }\n // move cacti\n var lastCactix = cacti.length?cacti[cacti.length-1].x:W-1;\n if (lastCactix0.5)?1:0\n });\n }\n cacti.forEach(c=>c.x--);\n while (cacti.length && cacti[0].x<0) cacti.shift();\n } else {\n g.drawString(\"Game Over!\",(W-g.stringWidth(\"Game Over!\"))/2,20);\n }\n g.drawLine(0,60,239,60);\n cacti.forEach(c=>g.drawImage(IMG.cacti[c.img],c.x,60-IMG.cacti[c.img].height));\n // check against actual pixels\n var rexx = rex.x;\n var rexy = 38-rex.y;\n if (rex.alive &&\n (g.getPixel(rexx+0, rexy+13) ||\n g.getPixel(rexx+2, rexy+15) ||\n g.getPixel(rexx+5, rexy+19) ||\n g.getPixel(rexx+10, rexy+19) ||\n g.getPixel(rexx+12, rexy+15) ||\n g.getPixel(rexx+13, rexy+13) ||\n g.getPixel(rexx+15, rexy+11) ||\n g.getPixel(rexx+17, rexy+7) ||\n g.getPixel(rexx+19, rexy+5) ||\n g.getPixel(rexx+19, rexy+1))) {\n return gameStop();\n }\n g.drawImage(IMG.rex[rex.img], rexx, rexy);\n var groundOffset = frame&127;\n g.drawImage(IMG.ground, -groundOffset, 61);\n g.drawImage(IMG.ground, 128-groundOffset, 61);\n g.drawString(rex.score,(W-1)-g.stringWidth(rex.score));\n g.flip();\n}\n\ngameStart();\n"); -require('Storage').write("*trex",require("heatshrink").decompress(atob("mEwgIXUn//4AFI///+AFC+YFKCIoFeHQYFH/4FGhkAgYKCAo8fApEPGggFG4YFBmAFHAgIdDAqA/BAo38K4gFJWIJ7DAoUB/AqC4EDLwIFCh0GFQPD4EYgP/4YABDwfwSggFFgAFCgOAAoYSDAox4BABQA=="))); +require('Storage').write("+astroid",{"name":"Asteroids!","type":"app","icon":"*astroid","src":"-astroid","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","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="))); @@ -33,3 +33,11 @@ require('Storage').write("*funrun5",require("heatshrink").decompress(atob("mEwwgurglEC6tDmYYUgkzAANAFygXKKYIADBwgXDkg8LBwwXMoQXEH4hHNC4s0O6BfECAKhDHYKnOghCB3cga6dEnYYBaScC2cznewC6W7OQU7BYyIFAAhFBAAYwGC5RFBC5QAJlY0FSIQAMkUjGgrTJRYoXFPQIXGLg8iAAJFDDgIXGgYXJGAWweQJHOC4jtBC6cidgQXUUQQXBogACDYR3HmQXHAAYzKU4IACC48kJBwFBgg7EMZYwDJAReDoh5PC4QARJAoARJAYXTJChtDoSgNAAaeEAAU0C5wqCC4q5LOYYvWgjOEaJ4AGoZGQPY6OPFw0yF34uFRlYXCFykAoQuVeIQWUAB4A="))); require('Storage').write("+nceuwid",{"name":"nceuwid","type":"widget","src":"=nceuwid","files":"+nceuwid,=nceuwid"}); require('Storage').write("=nceuwid","(function(){\nvar 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\"));\nvar xpos = WIDGETPOS.tl;\nWIDGETPOS.tl+=75;\n\n\nWIDGETS[\"nceu\"]={draw:()=>{\n var x = xpos, y = 0;\n g.setColor(0.17,0.2,0.5);\n g.drawImage(img,x,y);\n g.setColor(1,1,1);\n}};\n})()\n"); +require('Storage').write("+start",{"name":"Start","type":"app","icon":"*start","src":"-start","files":"+start,-start,*start,*bangle,*nceu,*nfr,*nodew,*tf"}); +require('Storage').write("-start","var g = Graphics.getInstance();\ng.setFontAlign(1, 1, 0);\nconst d = g.getWidth() - 18;\nfunction c(a) {\n return {\n width: 8,\n height: a.length,\n bpp: 1,\n buffer: (new Uint8Array(a)).buffer\n };\n}\n\nfunction welcome() {\n var welcomes = [\n 'Welcome',\n 'Failte',\n 'Bienvenue',\n 'Willkommen',\n 'Bienvenido'\n ];\n function next() {\n var n = welcomes.shift();\n E.showMessage(n);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n welcomes.push(n);\n }\n return new Promise((res) => {\n next();\n var i = setInterval(next, 2000);\n setWatch(() => {\n clearInterval(i);\n clearWatch();\n E.showMessage('Loading...');\n res();\n }, BTN2, {repeat:false});\n });\n}\n\nfunction logos() {\n var logos = [\n ['nfr', 20, 90, ()=>{}],\n ['nceu', 20, 90, ()=>{\n g.setFont(\"6x8\", 2);\n g.setColor(0,0,1);\n g.drawString('Welcome To', 160, 110);\n g.drawString('NodeConfEU', 160, 130);\n g.drawString('2019', 200, 150);\n }],\n ['bangle', 70, 90, ()=>{}],\n ['nodew', 20, 90, ()=>{}],\n ['tf', 24, 90, ()=>{}],\n ];\n function next() {\n var n = logos.shift();\n var img = require(\"Storage\").read(\"*\"+n[0]);\n g.clear();\n g.drawImage(img, n[1], n[2]);\n n[3]();\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n logos.push(n);\n }\n return new Promise((res) => {\n next();\n var i = setInterval(next, 2000);\n setWatch(() => {\n clearInterval(i);\n clearWatch();\n res();\n }, BTN2, {repeat:false});\n });\n}\n\nfunction info() {\n var slides = [\n () => E.showMessage('Visit\\nnodewatch.dev\\nfor info'),\n () => E.showMessage('Visit\\nbanglejs.com/apps\\nfor apps'),\n () => E.showMessage('Remember\\nto charge\\nyour watch!'),\n () => {\n g.clear();\n g.setFont('6x8',2);\n g.setColor(1,1,1);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,40);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,194);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n g.drawString('Menu Up', d - 50, 42);\n g.drawString('Select', d - 40, 118);\n g.drawString('Menu Down', d - 60, 196);\n },\n () => {\n g.clear();\n E.showMessage('Hold both\\nto return\\nto clock');\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,40);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,194);\n },\n () => {\n g.clear();\n E.showMessage('Hold both\\nto reboot');\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,40);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n },\n () => E.showMessage('Open Settings\\nto enable\\nBluetooth')\n ];\n function next() {\n var n = slides.shift();\n n();\n slides.push(n);\n }\n return new Promise((res) => {\n next();\n var i = setInterval(next, 2000);\n setWatch(()=>{\n clearInterval(i);\n clearWatch();\n res();\n }, BTN2, {repeat:false});\n });\n}\n\nfunction cleanup() {\n E.showMessage('Loading...');\n var s = require('Storage');\n s.erase('*nfr');\n s.erase('*nceu');\n s.erase('*bangle');\n s.erase('*nodew');\n s.erase('*tf');\n s.erase('+start');\n s.erase('-start');\n s.erase('*start');\n return Promise.resolve();\n}\n\nwelcome()\n .then(logos)\n .then(info)\n .then(cleanup)\n .then(load);\n"); +require('Storage').write("*start",require("heatshrink").decompress(atob("mEwxH+AHMPADQv/F+YxZYtb1wFto7SEbwwQBIsen0/ADU+jxfOjwtbAAYwDWZVWF79WfBAvEq4vfq4vIGQgviR44AEFz4vEGRQvnGA4v/F79YX9IHEq4aKh//jwvRrBcHG4ovL/4ABB5gAFRAwvVGIQveoAAIF4oABq0/CZIACF8BiBrAvTGIoaKF5AABIpVXd44AFJBQvKh4vOGBIvVL54vdX5iPhqztLoFYFpYvSh8/FxgABFpYvQRRgveoEP/8eFqAvbACi/CeA4IDP6IvUGIYGEF+EMADwvJR4ovmdoovnFoowDF8QsIF4dZF79ZF5RpCj1AFztAjy7JAAgwdFwbAFFwwAmF/4vhGFrxLFkoAvA="))); +require('Storage').write("*bangle",require("heatshrink").decompress(atob("s8wxH+AH4AQ/4AJJX5mmM/5m/AH5m/M34A/M35l/M35mqM/5m/AH5m/M34A/MqQKQJm5laOh7kNM35MGbiQxLM9osWIiZnGDI5m/VTBm/MsrOGM35maB4xm/MsoZFORZm/Fq5mDAAwUKBhAHBDJYLGAY4rOPShmRF44TIIoqlJCIxmKEZLMSBxY1GE5RTIJpwYSP5hmQZxodKLBKpIDBQZHMxS4MM1IKCMzKNQHJJmtFwbbUMy4AIM35mcJR5mbLCo1GZrxLOLZ6BMH5wOHMyAYRSRLOWGRY+MAxRmODCZeNMyLNMAA4TIBgpmPFA4YMHBZnPFIp/cADa0cC9Zm2J5YkKMtgsIGjZRTCYLMsFow0dDqJluGAgzhEJwxiAGpYLMn70hAA5N/M34A/M35mzJn5m/AH5nNJf5m/AH5m/M34A/M35m/MpgA="))); +require('Storage').write("*nceu",require("heatshrink").decompress(atob("o9HxH+AEOAwAkiIkIADIv5CEI/4/IJHbNLbPA4Iv1+JHREIwkmk2EJBBE2IoUnIwJHBCx5GoBA2DIgQACBw5G3aQQADwRG+wEmagQCBvxGufoQpDFxOCI4YNIDgxNeD4gDHCY+EwgMKBQIjGJDJlHA4YlKvzRHDRZHZDJQkMBZojVECb+OHJgkOZ6w6KCJAHJCgY1dK5wPDCg4GICYjDZBY9+vxGMArItLeRgWDwOEwmBJA5Ggv2GlMMwJGTwRFBI5JGfv2HlIACwRGRwBFDAAIUGIz+FIYMMI4R0CIxzSCRwhaMIBy2FAAaMBhmHI4QjIRqwUFIxxFJOgLTDlMGRqJHFwF+CpAWDIxgwJBgN+aoSMEIyAGBweDXBg6FABIWLAgOCw+GMhRGKByI9IIxYtQIywaJC5YTTIzwRGOyQqTIzLGNCTJGgXqIRTIzILIIzQvUI5a4EBgh6TDI7dKZJo7IAwQLFIzAjKIhwQGChBvMEhojLIqIjGBaZGPEbppOEerrLBYpGVEZrVOBpJjJIzCHNcpoqPI6gaUIywfSCLJGgXBYSZIzwRFCxoSGFSJGYCA4XLCRArQIywOJYxDPLFqA3OwFPp4HCy4lKHogAIM5uulukMIxGNy1MAAWW2JENFBJIMv8B0ksAAQQDIx2AptMpoCCChZGQGROYIocslsBIyGVIQNOp5HByhaMIxj9IAAWMIYUtRwiNPaIKNCpgUGIB4FNAAMXRq/+yhDBAAOUtJGlgKOCAAOvCJRGH2OVp1OypFGI0BHB0jUBzCMCIyAABtJEHI0RICIgYRMJBBGMCg4GICYgnPCBhHPBwQSIA5IUDGpxWOJBwgLfpgkOIhwVOEBj9WIipsKA4YiKgMBERojIIqphHAgYjKy+n1VpTJYjIADZlGEpOVlwABhTJKRL4oHFxIIEIgUKlula44/hShwIG1RFB02lJQJVII2zTC0iNBhVpI24vGgOmlpIBl2WagwWIJGFp1UKhRFGImI0FGouAaIoPIJGQMWJG5E7H5BE/I4pF/JA4kiA"))); +require('Storage').write("*nfr",require("heatshrink").decompress(atob("5EuxH+AAkPABIQFABIaKDiIA/AH6qaVpwbbAH4A/YzysMDbYA/AH7GfVhbHgChrr0MT5FoTDobOQijH/Y/6aYcqzH/Y/5EeZDLHmFxTH/Y/4TVY84uJY/7H7TibHuC4rH5XmiHRZC7HpDAjSQF5QpJCgYGJY6Y8MFR4bJBSrITY9RNJb6LFNY5ALFP6CsVY55PQTzDH6MhrGPY7opYY7IZFAgqfRY9xzIWx7GQY6QsYFTTHQZDLHlL44ONDxIfJdKS3PA54qSCRL1MWpDIRY8yLNCg5FICB7ZMHZwrKaB4bQEpTHZH5bHgRhiZNbCTZSY5qBNHiDHZZCbHsOZjHPRSTHYOZbHyZDLH/Y8pQRY+zIYY8xPLG6bHsDJjHuUiTbQdTjHfQBjHYVaLHyUqbHoKJC2KCBgRDBA7HeThbHvZETHdVxKKPTkzISfJLHpZELHeOZLGOY9g8OY+TIgY74OJLqDHqFZIMJY/7HuFxRcPYJbHeXi7HUKAqGYCSgdRAH4A/XC7IdY/4A/Y9rIZY/4A/Y/7H/AH7H2ZDDH/AH7HvZC7H/SMrH/Io7IZDCoVIBgwNFBSA7JBRoZOJ5jboY6IOBY9oWKDpYLFApZkNH6YIHJ5BMNY97IZY6yvTTJCGRBwQRIExYVKB4zH+ZDDHpBQ7HgH5Q+QY/7IYY9KDJY6QeKY6xDOY/7H7BhRiPCRQGHA4SsRCJDH4ZDJqUfpQiIBR6UNDRISQOJ52TY9DIYNSyvSIZLfOAxoaIY/7HVZC4SQQBSJUC57HTDIw9QGZzH/Y7xmINyTHTAAwfKHyzH/OBTH3CRg1LYxAUFD5Y+QY9RXLLxQaWY6yIYY6g5SH57kHY9StRcbZPQQJivRC6AKJEBpGHBxrH/DcbHUEpQKQBojSPH5gpIXx7HjVp4caJkbjRGv4AkA=="))); +require('Storage').write("*nodew",require("heatshrink").decompress(atob("5E1xH+AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A6hEICD4A/AH7FlY6TJ/AH7G1Y6bI/AH7FyY6rJ/AH7GyY6zI/AH7H/Y/4A/Y3DHXg5g/AH4Ak5jH/AH4A/Y9VXq5l/AH4Ag47HjZAJm/AH7GgY5S9KZBjHDZH4A/Y9S5KBxrH/AH7GkY5DGOCIrHJZA4pGBiQAPKpAQLHKQmPADRSQY6LFQCZLHPQJjIeQqwKVHTLHoEpDISY4rIGJRbH/IjBYXC67GCY5LGRY7CCaY8hEPV87Ha4zHEYyoXGY6SOKY9IQJIhRDUY+YdEY64YCAgTIBY6CDPMBxRIDpAvMIaZALV5z/NFRrHH5glGYyqOFY4LIJDJoHKaZolPMZIRMUZAyLHxotLLJzHJ4zGBY8TICY6KXJO6wdQWiJCHGRp+QJaTINYoRbQY6bICZINRY8RJQDhowPY8RMYY5YABgR9US6MHgIwGJ5QMLE44GIURY4NBSoyKIZQRObhrIMg7HkgQvIJBapSBzrBPCBhdJY5w+NeBgAFzO93rIFY8AFBxmGwydKFxSFOMJR6JFZhXLIKbHVPhbHPZALJBZA7HcAgLFBY5qFYY+KsLY/DICY4rIWC4kC/2MY6CGJOZjWPRBy8KY95MHY62ZAoLICY64/G/zGIMRxcQdB7HWBZqeQEZxcIY7e9Y4ZMHY/AwJIByrOY7JzLCJAbNY8jITCozHVURqDRDrY/MGSDHWPhTHOZAbHFZCgxHY4gxGIJbrLT6AQIDiRLQOp7ITGBbHcZB4wKY5o+IOxwWLBoQdUY54zMCJTTQBQ6GSZAjHGZCJCLY5IA/AH4AWY5L7LBpzHDNH4A/ZEDHIXQoALaZLH/AH7HsZB4WHgTHCM34A/AELHjY34A/AErHhAH4A/AEzH/AH4A/Y8xe/AH7IwCsgA/AH7IiCkYA/AH7IjCcQA/AH7JkCMAA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHIA="))); +require('Storage').write("*tf",require("heatshrink").decompress(atob("4M7ghC/AH4A/AEcBiMQAgY+3iIACIAQhcAgYjdTzZgfYH5giYHo5BIIQGDAQYLHgMQBoZZFYAoYENGREDGgI6BAYYMDBYrXDA4RTDAobnFLgbNEYF5LFVAIGCAghsEBQYMFYAoMEC4TAxAAg5DLoqiCZQZ2CAQa2DYAiGFA4bAvXYj6DAIZkEVYizHLYhyDNoaGCL9zAEHw5aGOIwHJYAqBFL96zCHxJsEKwcBYAx5GYA4SCFobAuMohoDAQ4UCKgYCEYBR7FYGqsDIIwLFYAzUFYAhbEL+IyGIojAFBYbAEKYZYHCgghEYGoGFWoQGFJIYHBgRZDbQpsFYGiNuIP4AedooA/L/4A5gJf/AH4A/AH4A/AH4A/AH4A/AH4A/ACsN7oAJG+oJC6AoaL5QmbG7PQTLrA/YH7A/YH7AhFgxbrYA4JQFkTArWwzAlEQhnCA4bPDBQwLDHwwJH5oGBEAydNAwQHDEgggDcaJBDEY4JDJoYSEH5A7GBAbAPHg5aHCQoiSEYpNHBIxpIBIQHGTpwzGGQJlMESZCIFowTNCQLAVSZAXFGQnNL5AiNBJAeBBIYsDNJIJHTpwyMCQhGEQQwsFYo7kGAoQJDEQQyDS5ChDCgxRJGRJ4DUIpAFYBQiFJgwUGBIr3IIAy5EaJgyNcgoTGcZZCFWwxMLboxqLYBoUJGw5GIYBaSGFoo3GLApAOYCAUJQYycLYBCSHDIoUJYBfdYDwKDEwQFCBAbAfIwwHEFA6rKTpLAPEoQCDYEBgIFgzAMHwzAOXpDAkMIxALYD4wEAozAOaA7AKMIxAJVZjAWApLAOBxasGEYYZCIAyrOYCQlBYC4jGhpHCYBBpJAYSrSTp4FELQZmFYBoRDBQjAMGwvcHQYiEdBDANHgpTFApbALaYgWERpISGHYoJFYCo8JVBKAHFg5COAoY2JBI65IYBofHOYZmIYBxgGNIr4KSxJJHYCQfGCQhmIYBwjFPZDVKQg53IYCI8IBIgFIERgjEPZLVJEhHcAwUMYCo8IYBIfGAH4A/AHw")));