diff --git a/apps/widhid/ChangeLog b/apps/widhid/ChangeLog new file mode 100644 index 000000000..a6ed84766 --- /dev/null +++ b/apps/widhid/ChangeLog @@ -0,0 +1,3 @@ +0.01: New widget - music control via a swipe +0.02: Improve interactivity - avoid responding to swipes when a menu or + launcher is active. diff --git a/apps/widhid/README.md b/apps/widhid/README.md index 7651d74eb..652a2ed49 100644 --- a/apps/widhid/README.md +++ b/apps/widhid/README.md @@ -13,6 +13,7 @@ Swipe down to enable - note the icon changes from blue to orange, indicating it' All other watch interaction is disabled for 3 seconds, to prevent clashing taps/drags - this period is extended as you continue to alter the volume, play/pause and jump between tracks. +Requires espruino firmware > 2v17 to avoid event handler clashes. # Setup / Technical details diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json index 10e75fadc..84334636b 100644 --- a/apps/widhid/metadata.json +++ b/apps/widhid/metadata.json @@ -2,7 +2,7 @@ "id": "widhid", "name": "Bluetooth Music Swipe Control Widget", "shortName": "BLE Swipe Widget", - "version": "0.01", + "version": "0.02", "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", "icon": "icon.png", "readme": "README.md", diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index ed1e78e76..dd411513e 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -11,16 +11,13 @@ var activeTimeout; var waitForRelease = true; var onSwipe = (function (_lr, ud) { - if (Bangle.CLKINFO_FOCUS) - return; - if (!activeTimeout && ud > 0) { + if (ud > 0 && !activeTimeout && !Bangle.CLKINFO_FOCUS) { listen(); Bangle.buzz(20); } }); var onDrag = (function (e) { - if (Bangle.CLKINFO_FOCUS) - return; + E.stopEventPropagation && E.stopEventPropagation(); if (e.b === 0) { var wasDragging = dragging; dragging = false; @@ -82,9 +79,9 @@ var listen = function () { var wasActive = !!activeTimeout; if (!wasActive) { - suspendOthers(); waitForRelease = true; Bangle.on("drag", onDrag); + Bangle["#ondrag"] = [onDrag].concat(Bangle["#ondrag"].filter(function (f) { return f !== onDrag; })); redraw(); } if (activeTimeout) @@ -92,7 +89,6 @@ activeTimeout = setTimeout(function () { activeTimeout = undefined; Bangle.removeListener("drag", onDrag); - resumeOthers(); redraw(); }, 3000); }; @@ -131,46 +127,4 @@ var toggle = function () { return sendHid(0x10); }; var up = function () { return sendHid(0x40); }; var down = function () { return sendHid(0x80); }; - var touchEvents = { - tap: null, - gesture: null, - aiGesture: null, - swipe: null, - touch: null, - drag: null, - stroke: null, - }; - var suspendOthers = function () { - for (var event in touchEvents) { - var handlers = Bangle["#on".concat(event)]; - if (!handlers) - continue; - var newEvents = void 0; - if (handlers instanceof Array) - newEvents = handlers.slice(); - else - newEvents = [handlers]; - for (var _i = 0, newEvents_1 = newEvents; _i < newEvents_1.length; _i++) { - var handler = newEvents_1[_i]; - Bangle.removeListener(event, handler); - } - touchEvents[event] = newEvents; - } - }; - var resumeOthers = function () { - for (var event in touchEvents) { - var handlers = touchEvents[event]; - touchEvents[event] = null; - if (handlers) - for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) { - var handler = handlers_1[_i]; - try { - Bangle.on(event, handler); - } - catch (e) { - console.log("couldn't restore \"".concat(event, "\" handler:"), e); - } - } - } - }; })(); diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 6b5e38855..3291c188d 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -14,16 +14,16 @@ let waitForRelease = true; const onSwipe = ((_lr, ud) => { - if((Bangle as BangleExt).CLKINFO_FOCUS) return; - - if(!activeTimeout && ud! > 0){ + // do these checks in order of cheapness + if(ud! > 0 && !activeTimeout && !(Bangle as BangleExt).CLKINFO_FOCUS){ listen(); Bangle.buzz(20); } }) satisfies SwipeCallback; const onDrag = (e => { - if((Bangle as BangleExt).CLKINFO_FOCUS) return; + // Espruino/35c8cb9be11 + (E as any).stopEventPropagation && (E as any).stopEventPropagation(); if(e.b === 0){ // released @@ -81,9 +81,14 @@ const listen = () => { const wasActive = !!activeTimeout; if(!wasActive){ - suspendOthers(); waitForRelease = true; // wait for first touch up before accepting gestures + Bangle.on("drag", onDrag); + // move our drag to the start of the event listener array + (Bangle as any)["#ondrag"] = [onDrag].concat( + (Bangle as any)["#ondrag"].filter((f: unknown) => f !== onDrag) + ); + redraw(); } @@ -92,7 +97,6 @@ activeTimeout = undefined; Bangle.removeListener("drag", onDrag); - resumeOthers(); redraw(); }, 3000); @@ -147,53 +151,4 @@ const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10); const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40); const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80); - - // similarly to the lightswitch app, we tangle with the listener arrays to - // disable event handlers - type Handler = () => void; - const touchEvents: { - [key: string]: null | Handler[] - } = { - tap: null, - gesture: null, - aiGesture: null, - swipe: null, - touch: null, - drag: null, - stroke: null, - }; - - const suspendOthers = () => { - for(const event in touchEvents){ - const handlers: Handler[] | Handler | undefined - = (Bangle as any)[`#on${event}`]; - - if(!handlers) continue; - - let newEvents; - if(handlers instanceof Array) - newEvents = handlers.slice(); - else - newEvents = [handlers /* single fn */]; - - for(const handler of newEvents) - Bangle.removeListener(event, handler); - - touchEvents[event] = newEvents; - } - }; - const resumeOthers = () => { - for(const event in touchEvents){ - const handlers = touchEvents[event]; - touchEvents[event] = null; - - if(handlers) - for(const handler of handlers) - try{ - Bangle.on(event as any, handler); - }catch(e){ - console.log(`couldn't restore "${event}" handler:`, e); - } - } - }; })()