diff --git a/apps/setuichange/ChangeLog b/apps/setuichange/ChangeLog new file mode 100644 index 0000000000..5560f00bce --- /dev/null +++ b/apps/setuichange/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/setuichange/README.md b/apps/setuichange/README.md new file mode 100644 index 0000000000..7803171e6d --- /dev/null +++ b/apps/setuichange/README.md @@ -0,0 +1,24 @@ +# setUI Proposals Preview + +Try out changes to setUI that may or may not eventually en up in the Bangle.js firmware. + +## Usage + +Just install it and it modifies setUI at boot time. + +## Features + +- Add custom handlers on top of the standard modes as well. Previously this was only possible for mode == "custom". + - The goal here is to make it possible to move all input handling inside `setUI` where today some apps add on extra handlers outside of `setUI` calls. +- Change the default behaviour of the hardware button to act immediately on press down. Previously it has been acting on button release. + - This makes the interaction slightly snappier. + - In addition to the existing `btn` key a new `btnRelease` key can now be specified. `btnRelease` will let you listen to the rising edge of the hardware button. + +## Requests + +Please report your experience and thoughts on this issue: +[ Discussion: HW buttons should act on 'rising' edge #3435 ](https://github.com/espruino/BangleApps/issues/3435) or on the related forum conversation (Link will be added when the conversation has opened). + +## Creator + +The changes done here were done by thyttan with help from Gordon Williams. diff --git a/apps/setuichange/app.png b/apps/setuichange/app.png new file mode 100644 index 0000000000..78bea6c3bf Binary files /dev/null and b/apps/setuichange/app.png differ diff --git a/apps/setuichange/boot.js b/apps/setuichange/boot.js new file mode 100644 index 0000000000..dd541e72b2 --- /dev/null +++ b/apps/setuichange/boot.js @@ -0,0 +1,151 @@ +Bangle.setUI = (function(mode, cb) { + var options = {}; + if ("object"==typeof mode) { + options = mode; + mode = options.mode; + if (!mode) throw new Error("Missing mode in setUI({...})"); + } + var redraw = true; + if (global.WIDGETS && WIDGETS.back) { + redraw = false; + WIDGETS.back.remove(mode && options.back); + } + if (Bangle.btnWatches) { + Bangle.btnWatches.forEach(clearWatch); + delete Bangle.btnWatches; + } + if (Bangle.swipeHandler) { + Bangle.removeListener("swipe", Bangle.swipeHandler); + delete Bangle.swipeHandler; + } + if (Bangle.dragHandler) { + Bangle.removeListener("drag", Bangle.dragHandler); + delete Bangle.dragHandler; + } + if (Bangle.touchHandler) { + Bangle.removeListener("touch", Bangle.touchHandler); + delete Bangle.touchHandler; + } + delete Bangle.uiRedraw; + delete Bangle.CLOCK; + if (Bangle.uiRemove) { + let r = Bangle.uiRemove; + delete Bangle.uiRemove; // stop recursion if setUI is called inside uiRemove + r(); + } + g.reset();// reset graphics state, just in case + if (!mode) return; + function b() { + try{Bangle.buzz(30);}catch(e){} + } + if (mode=="updown") { + var dy = 0; + Bangle.dragHandler = e=>{ + dy += e.dy; + if (!e.b) dy=0; + while (Math.abs(dy)>32) { + if (dy>0) { dy-=32; cb(1) } + else { dy+=32; cb(-1) } + Bangle.buzz(20); + } + }; + Bangle.on('drag',Bangle.dragHandler); + Bangle.touchHandler = d => {b();cb();}; + Bangle.btnWatches = [ + setWatch(function() { b();cb(); }, BTN1, {repeat:1, edge:"rising"}), + ]; + } else if (mode=="leftright") { + var dx = 0; + Bangle.dragHandler = e=>{ + dx += e.dx; + if (!e.b) dx=0; + while (Math.abs(dx)>32) { + if (dx>0) { dx-=32; cb(1) } + else { dx+=32; cb(-1) } + Bangle.buzz(20); + } + }; + Bangle.on('drag',Bangle.dragHandler); + Bangle.touchHandler = d => {b();cb();}; + Bangle.btnWatches = [ + setWatch(function() { b();cb(); }, BTN1, {repeat:1, edge:"rising"}), + ]; + } else if (mode=="clock") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN1, {repeat:1,edge:"rising"}) + ]; + } else if (mode=="clockupdown") { + Bangle.CLOCK=1; + Bangle.touchHandler = (d,e) => { + if (e.x < 120) return; + b();cb((e.y > 88) ? 1 : -1); + }; + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN1, {repeat:1,edge:"rising"}) + ]; + } else if (mode=="custom") { + if (options.clock) { + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN1, {repeat:1,edge:"rising"}) + ]; + } + } else + throw new Error("Unknown UI mode "+E.toJS(mode)); + if (options.clock) Bangle.CLOCK=1; + if (options.touch) + Bangle.touchHandler = options.touch; + if (options.drag) { + Bangle.dragHandler = options.drag; + Bangle.on("drag", Bangle.dragHandler); + } + if (options.swipe) { + Bangle.swipeHandler = options.swipe; + Bangle.on("swipe", Bangle.swipeHandler); + } + if (options.btn) Bangle.btnWatches.push(setWatch(options.btn.bind(options), BTN1, {repeat:1,edge:"rising"})) + if (options.btnRelease) Bangle.btnWatches.push(setWatch(options.btnRelease.bind(options), BTN1, {repeat:1,edge:"falling"})) + if (options.remove) // handler for removing the UI (intervals/etc) + Bangle.uiRemove = options.remove; + if (options.redraw) // handler for redrawing the UI + Bangle.uiRedraw = options.redraw; + if (options.back) { + var touchHandler = (_,e) => { + if (e.y<36 && e.x<48) { + e.handled = true; + E.stopEventPropagation(); + options.back(); + } + }; + Bangle.on("touch", touchHandler); + // If a touch handler was needed for setUI, add it - but ignore touches if they've already gone to the 'back' handler + if (Bangle.touchHandler) { + var uiTouchHandler = Bangle.touchHandler; + Bangle.touchHandler = (_,e) => { + if (!e.handled) uiTouchHandler(_,e); + }; + Bangle.on("touch", Bangle.touchHandler); + } + var btnWatch; + if (Bangle.btnWatches===undefined) // only add back button handler if there's no existing watch on BTN1 + btnWatch = setWatch(function() { + btnWatch = undefined; + options.back(); + }, BTN1, {edge:"rising"}); + WIDGETS = Object.assign({back:{ + area:"tl", width:24, + draw:e=>g.reset().setColor("#f00").drawImage(atob("GBiBAAAYAAH/gAf/4A//8B//+D///D///H/P/n+H/n8P/n4f/vwAP/wAP34f/n8P/n+H/n/P/j///D///B//+A//8Af/4AH/gAAYAA=="),e.x,e.y), + remove:(noclear)=>{ + if (btnWatch) clearWatch(btnWatch); + Bangle.removeListener("touch", touchHandler); + if (!noclear) g.reset().clearRect({x:WIDGETS.back.x, y:WIDGETS.back.y, w:24,h:24}); + delete WIDGETS.back; + if (!noclear) Bangle.drawWidgets(); + } + }},global.WIDGETS); + if (redraw) Bangle.drawWidgets(); + } else { // If a touch handler was needed for setUI, add it + if (Bangle.touchHandler) + Bangle.on("touch", Bangle.touchHandler); + } +}) diff --git a/apps/setuichange/metadata.json b/apps/setuichange/metadata.json new file mode 100644 index 0000000000..f8d465cf3d --- /dev/null +++ b/apps/setuichange/metadata.json @@ -0,0 +1,13 @@ +{ "id": "setuichange", + "name": "SetUI Proposals preview", + "version":"0.01", + "description": "Try out potential future changes to `Bangle.setUI`. Makes hardware button interaction snappier. Makes it possible to set custom event handlers on any type/mode, not just `\"custom\"`. Please provide feedback - see `Read more...` below.", + "icon": "app.png", + "tags": "", + "type": "bootloader", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"setuichange.0.boot.js","url":"boot.js"} + ] +}