Two-finger swipe now switches windows (#3901)

The Alt+Up and Alt+Down keybindings on Desktop did not have an
equivalent for Mobile users. Now a two-finger swipe left on a
touchscreen is equivalent to Alt+Up (similarly swipe right is
equivalent to Alt+Down).
This commit is contained in:
itsjohncs 2021-10-06 22:59:19 -07:00
parent 7b28d3c0f8
commit ebe39b26dc
2 changed files with 123 additions and 5 deletions

View File

@ -0,0 +1,108 @@
"use strict";
// onTwoFingerSwipe will be called with a cardinal direction ("n", "e", "s" or
// "w") as its only argument.
function listenForTwoFingerSwipes(onTwoFingerSwipe) {
let history = [];
document.body.addEventListener(
"touchmove",
function (event) {
if (event.touches.length !== 2) {
return;
}
const a = event.touches.item(0);
const b = event.touches.item(1);
const timestamp = window.performance.now();
const center = [(a.screenX + b.screenX) / 2, (a.screenY + b.screenY) / 2];
if (history.length > 0) {
const last = history[history.length - 1];
const centersAreEqual =
last.center[0] === center[0] && last.center[1] === center[1];
if (last.timestamp === timestamp || centersAreEqual) {
// Touches with the same timestamps or center don't help us
// see the speed of movement. Ignore them.
return;
}
}
history.push({timestamp, center});
},
{passive: true}
);
document.body.addEventListener(
"touchend",
function () {
if (event.touches.length >= 2) {
return;
}
try {
const direction = getSwipe(history);
if (direction) {
onTwoFingerSwipe(direction);
}
} finally {
history = [];
}
},
{passive: true}
);
document.body.addEventListener(
"touchcancel",
function () {
history = [];
},
{passive: true}
);
}
// Returns the cardinal direction of the swipe or null if there is no swipe.
function getSwipe(hist) {
// Speed is in pixels/millisecond. Must be maintained throughout swipe.
const MIN_SWIPE_SPEED = 0.2;
if (hist.length < 2) {
return null;
}
for (let i = 1; i < hist.length; ++i) {
const previous = hist[i - 1];
const current = hist[i];
const speed =
distance(previous.center, current.center) /
Math.abs(previous.timestamp - current.timestamp);
if (speed < MIN_SWIPE_SPEED) {
return null;
}
}
return getCardinalDirection(hist[0].center, hist[hist.length - 1].center);
}
function distance([x1, y1], [x2, y2]) {
return Math.hypot(x1 - x2, y1 - y2);
}
function getCardinalDirection([x1, y1], [x2, y2]) {
// If θ is the angle of the vector then this is tan(θ)
const tangent = (y2 - y1) / (x2 - x1);
// All values of |tan(-45° to 45°)| are less than 1, same for 145° to 225°
if (Math.abs(tangent) < 1) {
return x1 < x2 ? "e" : "w";
}
return y1 < y2 ? "s" : "n";
}
export default listenForTwoFingerSwipes;

View File

@ -6,6 +6,7 @@ import store from "./store";
import {switchToChannel} from "./router"; import {switchToChannel} from "./router";
import isChannelCollapsed from "./helpers/isChannelCollapsed"; import isChannelCollapsed from "./helpers/isChannelCollapsed";
import isIgnoredKeybind from "./helpers/isIgnoredKeybind"; import isIgnoredKeybind from "./helpers/isIgnoredKeybind";
import listenForTwoFingerSwipes from "./helpers/listenForTwoFingerSwipes";
// Switch to the next/previous window in the channel list. // Switch to the next/previous window in the channel list.
Mousetrap.bind(["alt+up", "alt+down"], function (e, keys) { Mousetrap.bind(["alt+up", "alt+down"], function (e, keys) {
@ -13,11 +14,22 @@ Mousetrap.bind(["alt+up", "alt+down"], function (e, keys) {
return true; return true;
} }
if (store.state.networks.length === 0) { navigateWindow(keys.split("+").pop() === "up" ? -1 : 1);
return false; return false;
});
listenForTwoFingerSwipes(function (cardinalDirection) {
if (cardinalDirection === "e" || cardinalDirection === "w") {
navigateWindow(cardinalDirection === "e" ? -1 : 1);
}
});
function navigateWindow(direction) {
if (store.state.networks.length === 0) {
return;
} }
const direction = keys.split("+").pop() === "up" ? -1 : 1;
const flatChannels = []; const flatChannels = [];
let index = -1; let index = -1;
@ -44,9 +56,7 @@ Mousetrap.bind(["alt+up", "alt+down"], function (e, keys) {
index = (((index + direction) % length) + length) % length; index = (((index + direction) % length) + length) % length;
jumpToChannel(flatChannels[index]); jumpToChannel(flatChannels[index]);
}
return false;
});
// Switch to the next/previous lobby in the channel list // Switch to the next/previous lobby in the channel list
Mousetrap.bind(["alt+shift+up", "alt+shift+down"], function (e, keys) { Mousetrap.bind(["alt+shift+up", "alt+shift+down"], function (e, keys) {