diff --git a/apps/swipeinv/ChangeLog b/apps/swipeinv/ChangeLog index 62542be608..5e1fc879ee 100644 --- a/apps/swipeinv/ChangeLog +++ b/apps/swipeinv/ChangeLog @@ -1,2 +1,6 @@ 0.01: New app! 0.02: Minor code improvements +0.03: (WIP) Add inversion of drag events. Add per app, per direction setting. + Refactor to hijack and modify the events instead of the handling of them. + This should add compatibility with most apps, even if Bangle.setUI is not + used. diff --git a/apps/swipeinv/README.md b/apps/swipeinv/README.md index 389c4bb6eb..302bc169e8 100644 --- a/apps/swipeinv/README.md +++ b/apps/swipeinv/README.md @@ -2,18 +2,20 @@ Inverts swipe direction globally or per app, see settings. If global inversion is enabled, you can unselect the inversion per app and vice versa. -## Limitations +Can invert swipe as well as drag events. This can be fine tuned for each inverted app in the settings. -Swipe Inversion can only invert directions on apps that use `Bangle.setUI` to set up swipes. Swipes set up with `Bangle.on("swipe", ...)` is currently not managed. +## Limitations -Swiping behavior that uses the `drag` event is not altered either. +Swipe Inversion must sit before other swipe and drag event listeners so they don't run before the event is inverted. If a listener were to be prepended to the list of listeners after Swipe Inversion was, that listener will act on the non-inverted event. ## TODO -- Try to handle swipes from `Bangle.on("swipe", ...)` - - alternatively refactor apps using that to only use `Bangle.setUI` for setting up swipes. - - Think about how to accommodate e.g. `touch` or `back` handlers set up in `Layout` library calls. They are removed if we refactor some `Bangle.on("swipe", ...)` to `Bangle.setUI`. (Is it maybe resolved if we call `Bangle.setUI` before the `Layout` call? - have not tested that yet.) - Add bootloader apps and widgets to the list of apps that can be individually toggled in settings? + - How? Right now we look at `global.__FILE__` to find the active app in order to determine which events to invert. That doesn't work for widgets and bootcode. + - In fact they will probably be inverted along with the currently running app. +- Refactor to invert at time of registering the event listeners? + - This would make it so `swipeinv` does not depend on being first in the call list of event listeners. + - Some work towards this was done in [thyttan@5cbb72e](https://github.com/thyttan/BangleApps/commit/5cbb72ee55f7fb7d335ffba228575a862a0ae612) but it doesn't work yet. ## Requests @@ -25,3 +27,4 @@ nxdefiant ## Contributors +thyttan diff --git a/apps/swipeinv/boot.js b/apps/swipeinv/boot.js index fb64f920dc..bcb8ac6380 100644 --- a/apps/swipeinv/boot.js +++ b/apps/swipeinv/boot.js @@ -1,19 +1,56 @@ { - const settings = Object.assign({ + const SETTINGS = Object.assign({ global: false, apps: [] }, require("Storage").readJSON("swipeinv.json", true) || {}); - if (settings.global || settings.apps.length > 0) { - const setURIOrig = Bangle.setUI; - Bangle.setUI = (mode, callback) => { - if (typeof mode === "object" && mode.swipe) { - if (settings.global ^ settings.apps.includes(global.__FILE__)) { - const origSwipeCb = mode.swipe; - mode.swipe = (dirLR, dirUD) => origSwipeCb(dirLR*-1, dirUD*-1); + const CLOCK_APP_ID = require("Storage").readJSON("setting.json",true).clock.split(".")[0]; + + let getAppIdFromCurrentFile = ()=> { + "ram" + if (!global.__FILE__ || global.__FILE__===".bootcde") { + return CLOCK_APP_ID; + } else {return global.__FILE__.split(".")[0];} + } + + setTimeout(() => { // Timeout so we prepend listeners late, hopefully after all other listerners were added. + if (SETTINGS.global || Object.keys(SETTINGS.apps).length > 0) { + + let swipeInverter = (dirLR, dirUD, obj) => { + "ram" + const APP_ID = getAppIdFromCurrentFile(); + if (SETTINGS.global ^ Object.keys(SETTINGS.apps).includes(APP_ID)) { + if (!(obj && obj.inverted)) { + E.stopEventPropagation(); + obj = Object.assign({inverted:true}, obj); + + if (SETTINGS.global ^ (SETTINGS.apps[APP_ID]&&SETTINGS.apps[APP_ID].swipeH)) {dirLR *= -1;} + if (SETTINGS.global ^ (SETTINGS.apps[APP_ID]&&SETTINGS.apps[APP_ID].swipeV)) {dirUD *= -1;} + + Bangle.emit("swipe", dirLR, dirUD, obj) + } } } - return setURIOrig(mode, callback); - }; - } + + let dragInverter = (e) => { + "ram" + const APP_ID = getAppIdFromCurrentFile(); + if (SETTINGS.global ^ Object.keys(SETTINGS.apps).includes(APP_ID)) { + if (!e.inverted) { + E.stopEventPropagation(); + e.inverted = true; + + if (SETTINGS.global ^ (SETTINGS.apps[APP_ID]&&SETTINGS.apps[APP_ID].dragH)) {e.dx *= -1;} + if (SETTINGS.global ^ (SETTINGS.apps[APP_ID]&&SETTINGS.apps[APP_ID].dragV)) {e.dy *= -1;} + + Bangle.emit("drag", e); + } + } + } + + Bangle.prependListener("swipe", swipeInverter); + Bangle.prependListener("drag", dragInverter); + + } + }, 0) } diff --git a/apps/swipeinv/metadata.json b/apps/swipeinv/metadata.json index 67c26a37d0..f24609e2bf 100644 --- a/apps/swipeinv/metadata.json +++ b/apps/swipeinv/metadata.json @@ -3,7 +3,7 @@ "name": "Swipe inversion", "shortName":"Swipe inv.", "icon": "app.png", - "version": "0.02", + "version": "0.03", "description": "Inverts swipe direction globally or per app, see settings. If global inversion is enabled, you can unselect the inversion per app and vice versa.", "readme":"README.md", "type": "bootloader", diff --git a/apps/swipeinv/settings.js b/apps/swipeinv/settings.js index e32b75e60e..f97ebaa4fd 100644 --- a/apps/swipeinv/settings.js +++ b/apps/swipeinv/settings.js @@ -3,33 +3,45 @@ // Load settings const settings = Object.assign({ global: false, - apps: [] + apps: {} }, require("Storage").readJSON(FILE, true) || {}); function writeSettings() { require('Storage').writeJSON(FILE, settings); } + // Convert settings when coming from ver < 4 + function convertAppsArrayToObject() { + if (Array.isArray(settings.apps)) { + let newObject = {}; + settings.apps.forEach((source)=>{ + let idExtractedFromSource = source.split(".")[0]; + newObject[idExtractedFromSource] = {}; + }) + settings.apps = newObject; + } + } + convertAppsArrayToObject(); + function appMenu() { let menu = { "" : { "title" : /*LANG*/"Swipe inversion apps" }, "< Back" : () => { writeSettings(); mainMenu();} }; - require("Storage").list(/\.info$/).map(app=>require("Storage").readJSON(app,1)).filter(app => app.type === "app" || !app.type).sort((a,b) => { + require("Storage").list(/\.info$/).map(app=>require("Storage").readJSON(app,1)).filter(app => app.type==="app" || app.type==="clock" || app.type==="launch" || !app.type).sort((a,b) => { if (a.nameb.name) return 1; return 0; }).forEach(app => { menu[app.name] = { - value: settings.apps.includes(app.src), + value: Object.keys(settings.apps).includes(app.id), onchange: v => { if (v) { - settings.apps.push(app.src); + if (!settings.apps[app.id] || Object.keys(settings.apps[app.id]).length===0) { + settings.apps[app.id] = {"name":app.name, "swipeH":true, "swipeV":true, "dragH":true, "dragV":true}; + } } else { - const idx = settings.apps.indexOf(app.src); - if (idx !== -1) { - settings.apps.splice(idx, 1); - } + if (settings.apps[app.id]) {delete settings.apps[app.id];} } } }; @@ -38,7 +50,7 @@ } function mainMenu() { - E.showMenu({ + let menu = { "" : { "title" : /*LANG*/"Swipe inversion" }, "< Back" : () => back(), @@ -50,8 +62,34 @@ } }, - /*LANG*/'Select apps': () => appMenu() + /*LANG*/'Select apps': () => appMenu(), + }; + + Object.keys(settings.apps).forEach((appID) => { + // Create a sub menu and show it. + let subMenu = { + "" : { "title" : /*LANG*/"Tune"+" "+appID }, + "< Back" : () => { writeSettings(); mainMenu();} + } + let subMenuEntries = [{name:"Swipe Horizontal", id:"swipeH"}, {name:"Swipe Vertical", id:"swipeV"}, {name:"Drag Horizontal", id:"dragH"}, {name:"Drag Vertical", id:"dragV"}]; + subMenuEntries.forEach((setting)=>{ + if (!Object.keys(settings.apps).includes(appID)) {settings.apps[appID] = {"swipeH":true, "swipeV":true, "dragH":true, "dragV":true}} + subMenu[setting.name] = { + value: settings.apps[appID][setting.id], + onchange: v => { + if (v) { + settings.apps[appID][setting.id] = true; + } else { + settings.apps[appID][setting.id] = false; + } + } + }; + }) + + menu[settings.apps[appID].name] = ()=>E.showMenu(subMenu); }); + + E.showMenu(menu); } mainMenu();