Skip to content

Commit

Permalink
fix: fine-tune touch gesture recofnition numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
IEduStu committed Apr 20, 2024
1 parent f308360 commit 9834ac4
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/common/MetaPreview/MetaLinks/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
flex-basis: auto;
margin-right: 0.75rem;
margin-bottom: 0.75rem;
padding: 0.4rem 1.25rem;
padding: calc(0.4rem + var(--focus-outline-size)) calc(1.25rem + var(--focus-outline-size));
white-space: nowrap;
text-overflow: ellipsis;
border-radius: 2rem;
border: var(--focus-outline-size) solid transparent;
border: none;
font-size: 1rem;
font-weight: 500;
color: var(--primary-foreground-color);
Expand Down
7 changes: 4 additions & 3 deletions src/common/NavBar/HorizontalNavBar/HorizontalNavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const NavMenu = require('./NavMenu');
const styles = require('./styles');
const { t } = require('i18next');

const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, addonsButton, fullscreenButton, navMenu, ...props }) => {
const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, addonsButton, fullscreenButton, navMenu, reducedTouchSurface, ...props }) => {
const backButtonOnClick = React.useCallback(() => {
window.history.back();
}, []);
Expand All @@ -26,7 +26,7 @@ const HorizontalNavBar = React.memo(({ className, route, query, title, backButto
</Button>
), []);
return (
<nav {...props} className={classnames(className, styles['horizontal-nav-bar-container'])}>
<nav {...props} className={classnames(className, styles['horizontal-nav-bar-container'], {[styles['reduced-touch-surface']]: reducedTouchSurface})}>
{
backButton ?
<Button className={classnames(styles['button-container'], styles['back-button-container'])} tabIndex={-1} onClick={backButtonOnClick}>
Expand Down Expand Up @@ -92,7 +92,8 @@ HorizontalNavBar.propTypes = {
searchBar: PropTypes.bool,
addonsButton: PropTypes.bool,
fullscreenButton: PropTypes.bool,
navMenu: PropTypes.bool
navMenu: PropTypes.bool,
reducedTouchSurface: PropTypes.bool,
};

module.exports = HorizontalNavBar;
10 changes: 10 additions & 0 deletions src/common/NavBar/HorizontalNavBar/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
padding-top: var(--safe-area-inset-top,0px);
box-sizing: content-box;

&.reduced-touch-surface {
pointer-events: none;

>* {
pointer-events: var(--initial-pointer-events, all);
}
}

.logo-container {
flex: none;
display: flex;
Expand Down Expand Up @@ -47,6 +55,8 @@
white-space: nowrap;
text-overflow: ellipsis;
color: @color-secondaryvariant2-light1-90;
pointer-events: none;
--initial-pointer-events: none;
}

.search-bar {
Expand Down
1 change: 1 addition & 0 deletions src/routes/Player/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ const Player = ({ urlParams, queryParams }) => {
fullscreenButton={true}
onMouseMove={onBarMouseMove}
onMouseOver={onBarMouseMove}
reducedTouchSurface
/>
<ControlBar
className={classnames(styles['layer'], styles['control-bar-layer'])}
Expand Down
120 changes: 89 additions & 31 deletions src/routes/Player/Video/MobileControlOverlay/MobileControlOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ const classnames = require('classnames');
const { default: Icon } = require('@stremio/stremio-icons/react');
const styles = require('./styles');

const moveDeltaToBeConsideredGesture = 10;
const moveDeltaToBeConsideredGesture = 50;
const minMoveDeltaToBeConsideredDirectionGesture = () => window.innerHeight / 2;
const maxDelayToBeConsideredTap = 150;
const maxDelayBetweenTapsToBeConsideredDoubleTap = 300;
const middleGapExcludedFromSideGestures = 100;
const maxDelayToBeConsideredTap = 250;
const maxDelayBetweenTapsToBeConsideredDoubleTap = 650;
const middleGapExcludedFromSideGestures = 150;

const MobileControlOverlay = ({ className, paused, visible, setHidden, onPlayPause, onSlideUp, onSlideDown, onSkip10Seconds, onGoBack10Seconds }) => {
const ref = React.useRef();
Expand Down Expand Up @@ -75,39 +75,25 @@ const MobileControlOverlay = ({ className, paused, visible, setHidden, onPlayPau
setHiddenRef.current((visible) => !visible);
}

function onTouchStart(event) {
if (buttonsRef.current !== undefined && buttonsRef.current !== null &&
Array.from(buttonsRef.current.children).some((button) => button !== undefined && button !== null && button.contains(event.target))
)
return;

event.preventDefault();
function onDone() {
touchActive = false;
}

const touch = event.touches[0];
function onFingerDown(x, y) {
touchStartTime = Date.now();
currentTouchStartX = touch.clientX;
currentTouchStartY = touch.clientY;
currentTouchStartX = x;
currentTouchStartY = y;
lastMoveX = currentTouchStartX;
lastMoveY = currentTouchStartY;
touchActive = true;
}

function onDone() {
touchActive = false;
}

function onTouchMove(event) {
if (isDone || !touchActive) {
onDone();
return;
}

const touch = event.touches[0];
lastMoveX = touch.clientX;
lastMoveY = touch.clientY;
function onFingerMove(x, y) {
lastMoveX = x;
lastMoveY = y;
}

function touchFinished(x, y) {
function onFingerUp(x, y) {
const touchEndTime = Date.now();

const deltaX = x - currentTouchStartX;
Expand Down Expand Up @@ -149,14 +135,36 @@ const MobileControlOverlay = ({ className, paused, visible, setHidden, onPlayPau
lastTouchStartY = currentTouchStartY;
}

function onTouchStart(event) {
if (buttonsRef.current !== undefined && buttonsRef.current !== null &&
Array.from(buttonsRef.current.children).some((button) => button !== undefined && button !== null && button.contains(event.target))
)
return;

event.preventDefault();

const touch = event.touches[0];
onFingerDown(touch.clientX, touch.clientY);
}

function onTouchMove(event) {
if (isDone || !touchActive) {
onDone();
return;
}

const touch = event.touches[0];
onFingerMove(touch.clientX, touch.clientY);
}

function onTouchCancel() {
if (isDone || !touchActive) {
onDone();
return;
}

if (lastMoveX !== null && lastMoveY !== null)
touchFinished(lastMoveX, lastMoveY);
onFingerUp(lastMoveX, lastMoveY);

onDone();
}
Expand All @@ -169,7 +177,37 @@ const MobileControlOverlay = ({ className, paused, visible, setHidden, onPlayPau

const touch = event.changedTouches[0];

touchFinished(touch.clientX, touch.clientY);
onFingerUp(touch.clientX, touch.clientY);

onDone();
}

function onMouseDown(event) {
if (buttonsRef.current !== undefined && buttonsRef.current !== null &&
Array.from(buttonsRef.current.children).some((button) => button !== undefined && button !== null && button.contains(event.target))
)
return;

event.preventDefault();
onFingerDown(event.clientX, event.clientY);
}

function onMouseMove(event) {
if (isDone || !touchActive) {
onDone();
return;
}

onFingerMove(event.clientX, event.clientY);
}

function onMouseUp(event) {
if (isDone || !touchActive) {
onDone();
return;
}

onFingerUp(event.clientX, event.clientY);

onDone();
}
Expand All @@ -178,12 +216,18 @@ const MobileControlOverlay = ({ className, paused, visible, setHidden, onPlayPau
tag.addEventListener('touchmove', onTouchMove, {passive: true});
tag.addEventListener('touchend', onTouchEnd, {passive: true});
tag.addEventListener('touchcancel', onTouchCancel, {passive: true});
tag.addEventListener('mousedown', onMouseDown, {passive: false, capture: true});
tag.addEventListener('mousemove', onMouseMove, {passive: true});
tag.addEventListener('mouseup', onMouseUp, {passive: true});

return () => {
tag.removeEventListener('touchstart', onTouchStart, {passive: false, capture: true});
tag.removeEventListener('touchmove', onTouchMove, {passive: true});
tag.removeEventListener('touchend', onTouchEnd, {passive: true});
tag.removeEventListener('touchcancel', onTouchCancel, {passive: true});
tag.removeEventListener('mousedown', onMouseDown, {passive: false, capture: true});
tag.removeEventListener('mousemove', onMouseMove, {passive: true});
tag.removeEventListener('mouseup', onMouseUp, {passive: true});
isDone = true;
touchActive = false;
};
Expand All @@ -204,12 +248,26 @@ const MobileControlOverlay = ({ className, paused, visible, setHidden, onPlayPau
event.preventDefault();
}, [onPlayPause, paused]);

const onPlayPauseButtonMouseUp = React.useCallback((event) => {
// only call `onPlayPause` if the mouse was released on this button
// we use a mouse event to make the button press be instant and have no delay

const rect = event.currentTarget.getBoundingClientRect();
if (event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom) {
onPlayPause();
setHiddenRef.current(paused);
}

if (!visibleRef.current)
event.preventDefault();
}, [onPlayPause, paused]);

return (
<div className={classnames(className, styles['video-mobile-control-overlay'], { [styles['show']]: visible })} ref={ref}>
<div className={styles['buttons']} ref={buttonsRef}>
{
typeof paused === 'boolean' &&
<div className={styles['button']} onTouchEnd={onPlayPauseButtonTouchEnd}>
<div className={styles['button']} onTouchEnd={onPlayPauseButtonTouchEnd} onMouseUp={onPlayPauseButtonMouseUp}>
<Icon className={styles['icon']} name={paused ? 'play' : 'pause'} />
</div>
}
Expand Down

0 comments on commit 9834ac4

Please sign in to comment.