diff --git a/apps.json b/apps.json index dbfc51d49..a0a819ca5 100644 --- a/apps.json +++ b/apps.json @@ -4,11 +4,12 @@ "tags": "tool,system", "type":"bootloader", "icon": "bootloader.png", - "version":"0.22", + "version":"0.23", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, - {"name":".bootcde","url":"bootloader.js"} + {"name":".bootcde","url":"bootloader.js"}, + {"name":"bootupdate.js","url":"bootupdate.js"} ], "sortorder" : -10 }, @@ -41,7 +42,7 @@ "name": "Launcher (Default)", "shortName":"Launcher", "icon": "app.png", - "version":"0.04", + "version":"0.05", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "tags": "tool,system,launcher", "type":"launch", @@ -171,13 +172,12 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.24", + "version":"0.25", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "readme": "README.md", "storage": [ {"name":"setting.app.js","url":"settings.js"}, - {"name":"setting.boot.js","url":"boot.js"}, {"name":"setting.img","url":"settings-icon.js","evaluate":true} ], "data": [ @@ -571,7 +571,7 @@ { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", - "version":"0.05", + "version":"0.06", "description": "Show the current battery level and charging status in the top right of the clock", "tags": "widget,battery", "type":"widget", @@ -579,6 +579,17 @@ {"name":"widbat.wid.js","url":"widget.js"} ] }, + { "id": "widlock", + "name": "Lock Widget", + "icon": "widget.png", + "version":"0.01", + "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", + "tags": "widget,lock", + "type":"widget", + "storage": [ + {"name":"widlock.wid.js","url":"widget.js"} + ] + }, { "id": "widbatpc", "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", @@ -3123,7 +3134,7 @@ {"name":"gps.kit.js","url":"gps.kit.js"}, {"name":"digi.kit.js","url":"digi.kit.js"}, {"name":"heart.kit.js","url":"heart.kit.js"}, - {"name":"swatch.kit.js","url":"swatch.kit.js"}, + {"name":"swatch.kit.js","url":"swatch.kit.js"}, {"name":"compass.kit.js","url":"compass.kit.js"}, {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} ], diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 7e9fd4a81..adfdb2709 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -21,3 +21,4 @@ 0.20: Allow Gadgetbridge to work even with programmable:off 0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558) 0.22: Stop LCD timeout being disabled on first run (when there is no settings.json) +0.23: Move to a precalculated .boot0 file which should speed up load time diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index 550513b11..3e567d9b8 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -1,68 +1,2 @@ -// This ALWAYS runs at boot -E.setFlags({pretokenise:1}); -// Load settings... -var s = require('Storage').readJSON('setting.json',1)||{}; -if (s.ble!==false) { - if (s.HID) { // Human interface device - if (s.HID=="joy") Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA=")); - else if (s.HID=="kb") Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA==")); - else /*kbmedia*/Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==")); - NRF.setServices({}, {uart:true, hid:Bangle.HID}); - } -} -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 - /* If not programmable add our own handler for Bluetooth data - to allow Gadgetbridge commands to be received*/ - Bluetooth.line=""; - Bluetooth.on('data',function(d) { - var l = (Bluetooth.line + d).split("\n"); - Bluetooth.line = l.pop(); - l.forEach(n=>Bluetooth.emit("line",n)); - }); - Bluetooth.on('line',function(l) { - if (l.startsWith('\x10')) l=l.slice(1); - if (l.startsWith('GB({') && l.endsWith('})') && global.GB) - try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {} - }); -} else { - 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. -// 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 (!Bangle.F_BEEPSET) { - if (!s.vibrate) Bangle.buzz=Promise.resolve; - if (s.beep===false) Bangle.beep=Promise.resolve; - else if (s.beep=="vib") Bangle.beep = function (time, freq) { - return new Promise(function(resolve) { - if ((0|freq)<=0) freq=4000; - if ((0|time)<=0) time=200; - if (time>5000) time=5000; - analogWrite(D13,0.1,{freq:freq}); - setTimeout(function() { - digitalWrite(D13,0); - resolve(); - }, time); - }); - }; -} -if (s.timeout!==undefined) Bangle.setLCDTimeout(s.timeout); -if (!s.timeout) Bangle.setLCDPower(1); -E.setTimeZone(s.timezone); -delete s; -// Draw out of memory errors onto the screen -E.on('errorFlag', function(errorFlags) { - g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); - print("Interpreter error:", errorFlags); - E.getErrorFlags(); // clear flags so we get called next time -}); -// stop users doing bad things! -global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); } -// Load *.boot.js files -require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ - eval(require('Storage').read(bootFile)); -}); +// Initially this runs and rewrites itself +eval(require('Storage').read('bootupdate.js')); diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js new file mode 100644 index 000000000..4f380b948 --- /dev/null +++ b/apps/boot/bootupdate.js @@ -0,0 +1,95 @@ +/* This rewrites boot0.js based on current settings. If settings changed then it +recalculates, but this avoids us doing a whole bunch of reconfiguration most +of the time. */ +E.showMessage("Updating boot0..."); +var s = require('Storage').readJSON('setting.json',1)||{}; +var boot = ""; +var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/)); +boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))!=${CRC}) { eval(require('Storage').read('bootupdate.js'));} else {\n`; +boot += `E.setFlags({pretokenise:1});\n`; +if (s.ble!==false) { + if (s.HID) { // Human interface device + if (s.HID=="joy") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA="));`; + else if (s.HID=="kb") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA=="));` + else /*kbmedia*/boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));`; + boot += `NRF.setServices({}, {uart:true, hid:Bangle.HID});\n`; + } +} +if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth + if (s.log) boot += `Terminal.setConsole(true);\n`; // if showing debug, force REPL onto terminal + else boot += `E.setConsole(null,{force:true});\n`; // on new (2v05+) firmware we have E.setConsole which allows a 'null' console + /* If not programmable add our own handler for Bluetooth data + to allow Gadgetbridge commands to be received*/ + boot += ` +Bluetooth.line=""; +Bluetooth.on('data',function(d) { + var l = (Bluetooth.line + d).split("\n"); + Bluetooth.line = l.pop(); + l.forEach(n=>Bluetooth.emit("line",n)); +}); +Bluetooth.on('line',function(l) { + if (l.startsWith('\x10')) l=l.slice(1); + if (l.startsWith('GB({') && l.endsWith('})') && global.GB) + try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {} +});\n`; +} else { + if (s.log) boot += `if (!NRF.getSecurityStatus().connected) Terminal.setConsole();\n`; // if showing debug, put REPL on terminal (until connection) + else boot += `Bluetooth.setConsole(true);\n`; // else if no debug, force REPL to Bluetooth +} +// we just reset, so BLE should be on. +// Don't disconnect if something is already connected to us +if (s.ble===false) boot += `if (!NRF.getSecurityStatus().connected) NRF.sleep();\n`; +// Set time +if (s.timeout!==undefined) boot += `Bangle.setLCDTimeout(${s.timeout});\n`; +if (!s.timeout) boot += `Bangle.setLCDPower(1);\n`; +boot += `E.setTimeZone(${s.timezone});`; +// Set vibrate, beep, etc IF on older firmwares +if (!Bangle.F_BEEPSET) { + if (!s.vibrate) boot += `Bangle.buzz=Promise.resolve;\n` + if (s.beep===false) boot += `Bangle.beep=Promise.resolve;\n` + else if (s.beep=="vib") boot += `Bangle.beep = function (time, freq) { + return new Promise(function(resolve) { + if ((0|freq)<=0) freq=4000; + if ((0|time)<=0) time=200; + if (time>5000) time=5000; + analogWrite(D13,0.1,{freq:freq}); + setTimeout(function() { + digitalWrite(D13,0); + resolve(); + }, time); + }); + };\n`; +} +// Draw out of memory errors onto the screen +boot += `E.on('errorFlag', function(errorFlags) { + g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); + print("Interpreter error:", errorFlags); + E.getErrorFlags(); // clear flags so we get called next time +});\n`; +// stop users doing bad things! +if (global.save) boot += `global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); }\n`; +// Apply any settings-specific stuff +if (s.options) boot+=`Bangle.setOptions(${E.toJS(s.options)});\n`; +if (s.quiet && s.qmOptions) boot+=`Bangle.setOptions(${E.toJS(s.qmOptions)});\n`; +if (s.quiet && s.qmBrightness) { + if (s.qmBrightness!=1) boot+=`Bangle.setLCDBrightness(${s.qmBrightness});\n`; +} else { + if (s.brightness && s.brightness!=1) boot+=`Bangle.setLCDBrightness(${s.brightness});\n`; +} +if (s.quiet && s.qmTimeout) boot+=`Bangle.setLCDTimeout(${s.qmTimeout});\n`; +if (s.passkey!==undefined && s.passkey.length==6) boot+=`NRF.setSecurity({passkey:${s.passkey}, mitm:1, display:1});\n`; +if (s.whitelist) boot+=`NRF.on('connect', function(addr) { if (!(require('Storage').readJSON('setting.json',1)||{}).whitelist.includes(addr)) NRF.disconnect(); });\n`; +// Pre-2v10 firmwares without a theme +if (!g.theme) { + boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7};\n`; +} +// Append *.boot.js files +require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ + boot += "//"+bootFile+"\n"+require('Storage').read(bootFile)+"\n"; +}); +boot += "}\n";// initial 'if' +var s = require('Storage').write('.boot0',boot); +delete boot; +E.showMessage("Reloading..."); +eval(require('Storage').read('.boot0')); +eval(require('Storage').read('.bootcde')); diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 7e7ea65ab..8be4ef463 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -2,3 +2,4 @@ 0.02: Only store relevant app data (saves RAM when many apps) 0.03: Allow scrolling to wrap around (fix #382) 0.04: Now displays widgets +0.05: Use g.theme for colours diff --git a/apps/launch/app.js b/apps/launch/app.js index 9795d8901..0d9d0b004 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -12,35 +12,36 @@ var menuScroll = 0; var menuShowing = false; function drawMenu() { - g.setFont("6x8",2); - g.setFontAlign(-1,0); - var n = 3; + g.reset().setFont("6x8",2).setFontAlign(-1,0); + var w = g.getWidth(); + var h = g.getHeight(); + var m = w/2; + var n = (h-48)/64; if (selected>=n+menuScroll) menuScroll = 1+selected-n; if (selectedn+menuScroll) ? -1 : 0); - g.fillPoly([120,233,106,219,134,219]); + g.setColor(menuScroll ? g.theme.fg : g.theme.bg); + g.fillPoly([m,6,m-14,20,m+14,20]); + g.setColor((apps.length>n+menuScroll) ? g.theme.fg : g.theme.bg); + g.fillPoly([m,h-7,m-14,h-21,m+14,h-21]); // draw - g.setColor(-1); + g.setColor(g.theme.fg); for (var i=0;i { - var settings = require('Storage').readJSON('setting.json', true); - if (!settings) return; - if (settings.options) Bangle.setOptions(settings.options); - if (settings.quiet && settings.qmOptions) Bangle.setOptions(settings.qmOptions); - if (settings.quiet && settings.qmBrightness) { - if (settings.qmBrightness!=1) Bangle.setLCDBrightness(settings.qmBrightness); - } else { - if (settings.brightness && settings.brightness!=1) Bangle.setLCDBrightness(settings.brightness); - } - if (settings.quiet && settings.qmTimeout) Bangle.setLCDTimeout(s.qmTimeout); - if (settings.passkey!==undefined && settings.passkey.length==6) NRF.setSecurity({passkey:settings.passkey, mitm:1, display:1}); - if (settings.whitelist) NRF.on('connect', function(addr) { if (!settings.whitelist.includes(addr)) NRF.disconnect(); }); - delete settings; -})() diff --git a/apps/widbat/ChangeLog b/apps/widbat/ChangeLog index b9d50ab8b..128cee034 100644 --- a/apps/widbat/ChangeLog +++ b/apps/widbat/ChangeLog @@ -2,3 +2,4 @@ 0.03: Tweaks for variable size widget system 0.04: Ensure redrawing works with variable size widget system 0.05: Fix regression stopping correct widget updates +0.06: Use 'g.theme' (requires bootloader 0.23) diff --git a/apps/widbat/widget.js b/apps/widbat/widget.js index bca3ae046..95fad1b20 100644 --- a/apps/widbat/widget.js +++ b/apps/widbat/widget.js @@ -7,16 +7,16 @@ function draw() { var s = 39; var x = this.x, y = this.y; + g.reset(); if (Bangle.isCharging()) { g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); x+=16; } - g.setColor(-1); + g.setColor(g.theme.fg); g.fillRect(x,y+2,x+s-4,y+21); g.clearRect(x+2,y+4,x+s-6,y+19); g.fillRect(x+s-3,y+10,x+s,y+14); 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) { if(charging) Bangle.buzz(); diff --git a/apps/widlock/ChangeLog b/apps/widlock/ChangeLog new file mode 100644 index 000000000..b4d1ae593 --- /dev/null +++ b/apps/widlock/ChangeLog @@ -0,0 +1 @@ +0.01: First commit diff --git a/apps/widlock/widget.js b/apps/widlock/widget.js new file mode 100644 index 000000000..b710de8c6 --- /dev/null +++ b/apps/widlock/widget.js @@ -0,0 +1,10 @@ +(function(){ + Bangle.on('lcdPower', function(on) { + WIDGETS["lock"].width = Bangle.isLCDOn()?0:16; + Bangle.drawWidgets(); + }); + WIDGETS["lock"]={area:"tl",width:Bangle.isLCDOn()?0:16,draw:function(w) { + if (!Bangle.isLCDOn()) + g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x, w.y); + }}; +})() diff --git a/apps/widlock/widget.png b/apps/widlock/widget.png new file mode 100644 index 000000000..e0eaa4aa9 Binary files /dev/null and b/apps/widlock/widget.png differ