mirror of https://github.com/espruino/BangleApps
popcon: use E.stopEventPropagation() for the drag handler
parent
b12fa58215
commit
109fd078f4
|
@ -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.
|
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
|
# Setup / Technical details
|
||||||
|
|
||||||
|
|
|
@ -10,34 +10,14 @@
|
||||||
var dragging = false;
|
var dragging = false;
|
||||||
var activeTimeout;
|
var activeTimeout;
|
||||||
var waitForRelease = true;
|
var waitForRelease = true;
|
||||||
var mayInterceptSwipe = function () {
|
|
||||||
if (Bangle.CLKINFO_FOCUS)
|
|
||||||
return 0;
|
|
||||||
if (Bangle.CLOCK)
|
|
||||||
return 1;
|
|
||||||
var swipes = Bangle["#onswipe"];
|
|
||||||
if (typeof swipes === "function") {
|
|
||||||
if (swipes !== onSwipe)
|
|
||||||
return swipes.length > 1;
|
|
||||||
}
|
|
||||||
else if (swipes) {
|
|
||||||
for (var _i = 0, swipes_1 = swipes; _i < swipes_1.length; _i++) {
|
|
||||||
var handler = swipes_1[_i];
|
|
||||||
if (handler !== onSwipe && (handler === null || handler === void 0 ? void 0 : handler.length) > 1)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Bangle["#ondrag"])
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
var onSwipe = (function (_lr, ud) {
|
var onSwipe = (function (_lr, ud) {
|
||||||
if (ud > 0 && !activeTimeout && mayInterceptSwipe()) {
|
if (ud > 0 && !activeTimeout && !Bangle.CLKINFO_FOCUS) {
|
||||||
listen();
|
listen();
|
||||||
Bangle.buzz(20);
|
Bangle.buzz(20);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var onDrag = (function (e) {
|
var onDrag = (function (e) {
|
||||||
|
E.stopEventPropagation && E.stopEventPropagation();
|
||||||
if (e.b === 0) {
|
if (e.b === 0) {
|
||||||
var wasDragging = dragging;
|
var wasDragging = dragging;
|
||||||
dragging = false;
|
dragging = false;
|
||||||
|
@ -99,9 +79,9 @@
|
||||||
var listen = function () {
|
var listen = function () {
|
||||||
var wasActive = !!activeTimeout;
|
var wasActive = !!activeTimeout;
|
||||||
if (!wasActive) {
|
if (!wasActive) {
|
||||||
suspendOthers();
|
|
||||||
waitForRelease = true;
|
waitForRelease = true;
|
||||||
Bangle.on("drag", onDrag);
|
Bangle.on("drag", onDrag);
|
||||||
|
Bangle["#ondrag"] = [onDrag].concat(Bangle["#ondrag"].filter(function (f) { return f !== onDrag; }));
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
if (activeTimeout)
|
if (activeTimeout)
|
||||||
|
@ -109,7 +89,6 @@
|
||||||
activeTimeout = setTimeout(function () {
|
activeTimeout = setTimeout(function () {
|
||||||
activeTimeout = undefined;
|
activeTimeout = undefined;
|
||||||
Bangle.removeListener("drag", onDrag);
|
Bangle.removeListener("drag", onDrag);
|
||||||
resumeOthers();
|
|
||||||
redraw();
|
redraw();
|
||||||
}, 3000);
|
}, 3000);
|
||||||
};
|
};
|
||||||
|
@ -148,48 +127,4 @@
|
||||||
var toggle = function () { return sendHid(0x10); };
|
var toggle = function () { return sendHid(0x10); };
|
||||||
var up = function () { return sendHid(0x40); };
|
var up = function () { return sendHid(0x40); };
|
||||||
var down = function () { return sendHid(0x80); };
|
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 event = event_;
|
|
||||||
var handlers = Bangle["#on".concat(event)];
|
|
||||||
if (!handlers)
|
|
||||||
continue;
|
|
||||||
var newEvents = void 0;
|
|
||||||
if (handlers instanceof Array)
|
|
||||||
newEvents = handlers.filter(function (f) { return f; });
|
|
||||||
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 event = event_;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
(() => {
|
(() => {
|
||||||
type BangleEventKeys = "tap" | "gesture" | "aiGesture" | "swipe" | "touch" | "drag" | "stroke";
|
|
||||||
type BangleEvents = {
|
|
||||||
[key in BangleEventKeys as `#on${key}`]?: Handler | (Handler | undefined)[]
|
|
||||||
};
|
|
||||||
|
|
||||||
const settings: Settings = require("Storage").readJSON("setting.json", true) || { HID: false } as Settings;
|
const settings: Settings = require("Storage").readJSON("setting.json", true) || { HID: false } as Settings;
|
||||||
if (settings.HID !== "kbmedia") {
|
if (settings.HID !== "kbmedia") {
|
||||||
console.log("widhid: can't enable, HID setting isn't \"kbmedia\"");
|
console.log("widhid: can't enable, HID setting isn't \"kbmedia\"");
|
||||||
|
@ -18,40 +13,18 @@
|
||||||
let activeTimeout: number | undefined;
|
let activeTimeout: number | undefined;
|
||||||
let waitForRelease = true;
|
let waitForRelease = true;
|
||||||
|
|
||||||
// If the user shows a menu, we want to temporarily disable ourselves
|
|
||||||
//
|
|
||||||
// We could detect showing of a menu by overriding E.showMenu
|
|
||||||
// and to detect hiding of a menu, we hook setUI
|
|
||||||
//
|
|
||||||
// Perhaps easier to check Bangle.swipeHandler - set by setUI,
|
|
||||||
// called by E.showMenu
|
|
||||||
const mayInterceptSwipe = () => {
|
|
||||||
if((Bangle as BangleExt).CLKINFO_FOCUS) return 0;
|
|
||||||
if(Bangle.CLOCK) return 1;
|
|
||||||
|
|
||||||
const swipes = (Bangle as BangleEvents)["#onswipe"];
|
|
||||||
if(typeof swipes === "function"){
|
|
||||||
if(swipes !== onSwipe)
|
|
||||||
return swipes.length > 1; // second argument is up/down
|
|
||||||
}else if(swipes){
|
|
||||||
for(const handler of swipes)
|
|
||||||
if(handler !== onSwipe && handler?.length > 1)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((Bangle as BangleEvents)["#ondrag"]) return 0;
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSwipe = ((_lr, ud) => {
|
const onSwipe = ((_lr, ud) => {
|
||||||
// do these checks in order of cheapness
|
// do these checks in order of cheapness
|
||||||
if(ud! > 0 && !activeTimeout && mayInterceptSwipe()){
|
if(ud! > 0 && !activeTimeout && !(Bangle as BangleExt).CLKINFO_FOCUS){
|
||||||
listen();
|
listen();
|
||||||
Bangle.buzz(20);
|
Bangle.buzz(20);
|
||||||
}
|
}
|
||||||
}) satisfies SwipeCallback;
|
}) satisfies SwipeCallback;
|
||||||
|
|
||||||
const onDrag = (e => {
|
const onDrag = (e => {
|
||||||
|
// Espruino/35c8cb9be11
|
||||||
|
(E as any).stopEventPropagation && (E as any).stopEventPropagation();
|
||||||
|
|
||||||
if(e.b === 0){
|
if(e.b === 0){
|
||||||
// released
|
// released
|
||||||
const wasDragging = dragging;
|
const wasDragging = dragging;
|
||||||
|
@ -108,9 +81,14 @@
|
||||||
const listen = () => {
|
const listen = () => {
|
||||||
const wasActive = !!activeTimeout;
|
const wasActive = !!activeTimeout;
|
||||||
if(!wasActive){
|
if(!wasActive){
|
||||||
suspendOthers();
|
|
||||||
waitForRelease = true; // wait for first touch up before accepting gestures
|
waitForRelease = true; // wait for first touch up before accepting gestures
|
||||||
|
|
||||||
Bangle.on("drag", onDrag);
|
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();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +97,6 @@
|
||||||
activeTimeout = undefined;
|
activeTimeout = undefined;
|
||||||
|
|
||||||
Bangle.removeListener("drag", onDrag);
|
Bangle.removeListener("drag", onDrag);
|
||||||
resumeOthers();
|
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
@ -174,54 +151,4 @@
|
||||||
const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10);
|
const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10);
|
||||||
const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40);
|
const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40);
|
||||||
const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80);
|
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 in BangleEventKeys]: null | Handler[]
|
|
||||||
} = {
|
|
||||||
tap: null,
|
|
||||||
gesture: null,
|
|
||||||
aiGesture: null,
|
|
||||||
swipe: null,
|
|
||||||
touch: null,
|
|
||||||
drag: null,
|
|
||||||
stroke: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const suspendOthers = () => {
|
|
||||||
for(const event_ in touchEvents){
|
|
||||||
const event = event_ as BangleEventKeys;
|
|
||||||
const handlers = (Bangle as BangleEvents)[`#on${event}`];
|
|
||||||
|
|
||||||
if(!handlers) continue;
|
|
||||||
|
|
||||||
let newEvents;
|
|
||||||
if(handlers instanceof Array)
|
|
||||||
newEvents = handlers.filter(f=>f) as Handler[];
|
|
||||||
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 event = event_ as BangleEventKeys;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})()
|
})()
|
||||||
|
|
Loading…
Reference in New Issue