From 4f56ea01b505db7d6ae056f951d72344c559579b Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Fri, 30 Jun 2023 20:41:08 +0100 Subject: [PATCH 01/21] add button longPress for mobile --- src/common/Button/Button.js | 21 ++++++++++++++++--- .../MetaDetails/VideosList/Video/Video.js | 4 ++++ .../MetaDetails/VideosList/Video/styles.less | 6 ++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 7235860a8..566355eda 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -5,7 +5,19 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const styles = require('./styles'); -const Button = React.forwardRef(({ className, href, disabled, children, ...props }, ref) => { +const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { + let pressTimer = null; + const onTouchStart = function () { + pressTimer = setTimeout(function () { + if (typeof onLongPress === 'function') { + //alert('longpress detected'); + onLongPress(); + } + }, 600); // values less than 600 will cause an artifact of previous menus staying on screen. + }; + const onTouchEnd = function () { + clearTimeout(pressTimer); + }; const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { props.onKeyDown(event); @@ -36,7 +48,9 @@ const Button = React.forwardRef(({ className, href, disabled, children, ...props className: classnames(className, styles['button-container'], { 'disabled': disabled }), href, onKeyDown, - onMouseDown + onMouseDown, + onTouchStart, + onTouchEnd, }, children ); @@ -50,7 +64,8 @@ Button.propTypes = { disabled: PropTypes.bool, children: PropTypes.node, onKeyDown: PropTypes.func, - onMouseDown: PropTypes.func + onMouseDown: PropTypes.func, + onLongPress: PropTypes.func, }; module.exports = Button; diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index b36bb5aa8..1c352d84f 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -29,6 +29,9 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w toggleMenu(); } }, [toggleMenu]); + const popupLabelOnLongPress = React.useCallback(() => { + toggleMenu(); + }, [toggleMenu]); const popupMenuOnContextMenu = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); @@ -168,6 +171,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w onCloseRequest={closeMenu} renderLabel={renderLabel} renderMenu={renderMenu} + onLongPress={popupLabelOnLongPress} /> ); }; diff --git a/src/routes/MetaDetails/VideosList/Video/styles.less b/src/routes/MetaDetails/VideosList/Video/styles.less index 67bb6e17d..4c82d9a94 100644 --- a/src/routes/MetaDetails/VideosList/Video/styles.less +++ b/src/routes/MetaDetails/VideosList/Video/styles.less @@ -12,6 +12,12 @@ } .video-container { + // IOS specific + // prevents showing the default context-menu when long pressing an anchor in safari. + -webkit-touch-callout: none !important; + // prevents user from selecting text from a div on long pressing in safari. + -webkit-user-select: none!important; + display: flex; flex-direction: row; flex-wrap: wrap; From fab5bf48a1631dead5b22e6f418ebbe42b8a4a09 Mon Sep 17 00:00:00 2001 From: Ahmidi Yasser <127498984+dexter21767-dev@users.noreply.github.com> Date: Fri, 30 Jun 2023 23:35:14 +0100 Subject: [PATCH 02/21] Update the long Press trigger time --- src/common/Button/Button.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 566355eda..feaeee738 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -13,7 +13,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr //alert('longpress detected'); onLongPress(); } - }, 600); // values less than 600 will cause an artifact of previous menus staying on screen. + }, 650); // an artifact of previous menus staying on the screen will happen on Safari if the timeout was set to 600 and less, and 650 for PWA. }; const onTouchEnd = function () { clearTimeout(pressTimer); From 9ef0fe7077748e3f9817b41d0252949dea17a3c4 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Sat, 1 Jul 2023 01:20:04 +0100 Subject: [PATCH 03/21] popup "mark as watched" menu use translation --- src/routes/MetaDetails/VideosList/Video/Video.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 1c352d84f..9128cb6ea 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -3,6 +3,7 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); +const { t } = require('i18next'); const { useServices } = require('stremio/services'); const { useRouteFocused } = require('stremio-router'); const Icon = require('@stremio/stremio-icons/dom'); @@ -137,10 +138,10 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w return (
); From d43a2ade4be93ad75e69a5e198a03f57dce480b0 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 11:22:10 +0100 Subject: [PATCH 04/21] pass the event arguemnt and preventDefault --- src/common/Button/Button.js | 8 ++++---- src/routes/MetaDetails/VideosList/Video/Video.js | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index feaeee738..7d602a0c6 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -7,15 +7,15 @@ const styles = require('./styles'); const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { let pressTimer = null; - const onTouchStart = function () { + const onTouchStart = function (event) { pressTimer = setTimeout(function () { if (typeof onLongPress === 'function') { - //alert('longpress detected'); - onLongPress(); + onLongPress(event); } }, 650); // an artifact of previous menus staying on the screen will happen on Safari if the timeout was set to 600 and less, and 650 for PWA. }; - const onTouchEnd = function () { + const onTouchEnd = function (event) { + //event.preventDefault(); clearTimeout(pressTimer); }; const onKeyDown = React.useCallback((event) => { diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 9128cb6ea..b327b5ce6 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -30,7 +30,8 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w toggleMenu(); } }, [toggleMenu]); - const popupLabelOnLongPress = React.useCallback(() => { + const popupLabelOnLongPress = React.useCallback((event) => { + event.preventDefault(); toggleMenu(); }, [toggleMenu]); const popupMenuOnContextMenu = React.useCallback((event) => { From db2236daddb01d4a19551efc63852e3e13853027 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 12:23:19 +0100 Subject: [PATCH 05/21] add onTouchStart to popup, to fix multiple menus --- src/common/Button/styles.less | 10 +++++++++- src/common/Popup/Popup.js | 9 +++++++-- src/routes/MetaDetails/VideosList/Video/Video.js | 11 ++++++++--- src/routes/MetaDetails/VideosList/Video/styles.less | 6 +----- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index e7b601729..ec44e074c 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -3,11 +3,19 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; .button-container { + // IOS specific + // prevents showing the default context-menu when long pressing an anchor in safari. + -webkit-touch-callout: none !important; + // prevents user from selecting text from a div on long pressing in safari. + -webkit-user-select: none !important; + + user-select: none !important; + outline-width: var(--focus-outline-size); outline-color: @color-surface-light5; outline-offset: calc(-1 * var(--focus-outline-size)); cursor: pointer; - + &:focus { outline-style: solid; } diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index 7c694e6d5..631b474df 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -28,6 +28,9 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque const menuOnMouseDown = React.useCallback((event) => { event.nativeEvent.closePopupPrevented = true; }, []); + const menuOnTouchStart = React.useCallback((event) => { + event.nativeEvent.closePopupPrevented = true; + }, []); React.useEffect(() => { const onCloseEvent = (event) => { if (!event.closePopupPrevented && typeof onCloseRequest === 'function') { @@ -42,7 +45,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque onCloseRequest(closeEvent); } break; - case 'mousedown': + case 'mousedown' || 'touchstart': if (event.target !== document.documentElement && !labelRef.current.contains(event.target)) { onCloseRequest(closeEvent); } @@ -53,10 +56,12 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque if (routeFocused && open) { window.addEventListener('keydown', onCloseEvent); window.addEventListener('mousedown', onCloseEvent); + window.addEventListener('touchstart', onCloseEvent); } return () => { window.removeEventListener('keydown', onCloseEvent); window.removeEventListener('mousedown', onCloseEvent); + window.removeEventListener('touchstart', onCloseEvent); }; }, [routeFocused, open, onCloseRequest, dataset]); React.useLayoutEffect(() => { @@ -104,7 +109,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque ref: labelRef, className: classnames(styles['label-container'], props.className, { 'active': open }), children: open ? - + {renderMenu()} : diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index b327b5ce6..6bf9c2ee9 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -31,9 +31,14 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w } }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { - event.preventDefault(); - toggleMenu(); + if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { + event.preventDefault(); + toggleMenu(); + } }, [toggleMenu]); + const popupMenuOnLongPress = React.useCallback((event) => { + event.nativeEvent.togglePopupPrevented = true; + }, []); const popupMenuOnContextMenu = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); @@ -137,7 +142,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w }, []); const renderMenu = React.useMemo(() => function renderMenu() { return ( -
+
diff --git a/src/routes/MetaDetails/VideosList/Video/styles.less b/src/routes/MetaDetails/VideosList/Video/styles.less index 4c82d9a94..9f029be80 100644 --- a/src/routes/MetaDetails/VideosList/Video/styles.less +++ b/src/routes/MetaDetails/VideosList/Video/styles.less @@ -12,11 +12,6 @@ } .video-container { - // IOS specific - // prevents showing the default context-menu when long pressing an anchor in safari. - -webkit-touch-callout: none !important; - // prevents user from selecting text from a div on long pressing in safari. - -webkit-user-select: none!important; display: flex; flex-direction: row; @@ -33,6 +28,7 @@ flex: none; .thumbnail { + pointer-events: none; display: block; width: 7.5rem; height: 5rem; From 5b0d50a20184ad0d8ec22a17a8dc00fe69d5c1ef Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 12:27:00 +0100 Subject: [PATCH 06/21] fix popup not closing --- src/common/Popup/Popup.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index 631b474df..e134cb7aa 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -28,9 +28,6 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque const menuOnMouseDown = React.useCallback((event) => { event.nativeEvent.closePopupPrevented = true; }, []); - const menuOnTouchStart = React.useCallback((event) => { - event.nativeEvent.closePopupPrevented = true; - }, []); React.useEffect(() => { const onCloseEvent = (event) => { if (!event.closePopupPrevented && typeof onCloseRequest === 'function') { @@ -109,7 +106,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque ref: labelRef, className: classnames(styles['label-container'], props.className, { 'active': open }), children: open ? - + {renderMenu()} : From ddc66198206fe44a893e5c5bc22fad07ba0c4f83 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 12:32:45 +0100 Subject: [PATCH 07/21] fix lint error. --- src/common/Button/Button.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 7d602a0c6..e40864f4a 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -14,8 +14,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr } }, 650); // an artifact of previous menus staying on the screen will happen on Safari if the timeout was set to 600 and less, and 650 for PWA. }; - const onTouchEnd = function (event) { - //event.preventDefault(); + const onTouchEnd = function () { clearTimeout(pressTimer); }; const onKeyDown = React.useCallback((event) => { From 73f9fd7aa65de0b0a1e1f0a243389d13be87daec Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 12:54:42 +0100 Subject: [PATCH 08/21] switch to Callbacks and react refs. --- src/common/Button/Button.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index e40864f4a..b955aabd1 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -6,17 +6,17 @@ const classnames = require('classnames'); const styles = require('./styles'); const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { - let pressTimer = null; - const onTouchStart = function (event) { - pressTimer = setTimeout(function () { + const longPressTimeout = React.useRef(null); + const onTouchStart = React.useCallback((event) => { + longPressTimeout.current = setTimeout(function () { if (typeof onLongPress === 'function') { onLongPress(event); } }, 650); // an artifact of previous menus staying on the screen will happen on Safari if the timeout was set to 600 and less, and 650 for PWA. - }; - const onTouchEnd = function () { - clearTimeout(pressTimer); - }; + }, [onLongPress]); + const onTouchEnd = React.useCallback(() => { + clearTimeout(longPressTimeout.current); + }, []); const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { props.onKeyDown(event); From fafb9838d5e373ce85460998e22a60732534e32d Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 13:10:58 +0100 Subject: [PATCH 09/21] fix attempting to cancel uncancelable event --- src/routes/MetaDetails/VideosList/Video/Video.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 6bf9c2ee9..17aafd28d 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -32,7 +32,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { - event.preventDefault(); + if (event.cancelable) event.preventDefault(); toggleMenu(); } }, [toggleMenu]); From 4843a8f1a9ae6a91c21b00603df3be44a5f3da9c Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Mon, 3 Jul 2023 13:20:01 +0100 Subject: [PATCH 10/21] fix multiple popups, and reduce timeout --- src/common/Button/Button.js | 2 +- src/common/Popup/Popup.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index b955aabd1..6f0526459 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -12,7 +12,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr if (typeof onLongPress === 'function') { onLongPress(event); } - }, 650); // an artifact of previous menus staying on the screen will happen on Safari if the timeout was set to 600 and less, and 650 for PWA. + }, 500); }, [onLongPress]); const onTouchEnd = React.useCallback(() => { clearTimeout(longPressTimeout.current); diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index e134cb7aa..59262c53a 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -42,7 +42,12 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque onCloseRequest(closeEvent); } break; - case 'mousedown' || 'touchstart': + case 'mousedown': + if (event.target !== document.documentElement && !labelRef.current.contains(event.target)) { + onCloseRequest(closeEvent); + } + break; + case 'touchstart': if (event.target !== document.documentElement && !labelRef.current.contains(event.target)) { onCloseRequest(closeEvent); } @@ -106,7 +111,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque ref: labelRef, className: classnames(styles['label-container'], props.className, { 'active': open }), children: open ? - + {renderMenu()} : From d9645c5c725515ca41d4f92f3212b177b49214f7 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Tue, 4 Jul 2023 12:18:30 +0100 Subject: [PATCH 11/21] clear timeout before starting a new one --- src/common/Button/Button.js | 1 + src/routes/MetaDetails/VideosList/Video/Video.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 6f0526459..d2b69e138 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -9,6 +9,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr const longPressTimeout = React.useRef(null); const onTouchStart = React.useCallback((event) => { longPressTimeout.current = setTimeout(function () { + clearTimeout(longPressTimeout.current); if (typeof onLongPress === 'function') { onLongPress(event); } diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 17aafd28d..eda0ca399 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -36,7 +36,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w toggleMenu(); } }, [toggleMenu]); - const popupMenuOnLongPress = React.useCallback((event) => { + const popupMenuOTouchStart = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); const popupMenuOnContextMenu = React.useCallback((event) => { @@ -142,7 +142,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w }, []); const renderMenu = React.useMemo(() => function renderMenu() { return ( -
+
From 7e0c22ec2ad0c9bbf09f740913cad8f46bb326fb Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Tue, 4 Jul 2023 22:47:13 +0100 Subject: [PATCH 12/21] removing unecessary style properties --- src/common/Button/styles.less | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index ec44e074c..b379a4353 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -6,10 +6,6 @@ // IOS specific // prevents showing the default context-menu when long pressing an anchor in safari. -webkit-touch-callout: none !important; - // prevents user from selecting text from a div on long pressing in safari. - -webkit-user-select: none !important; - - user-select: none !important; outline-width: var(--focus-outline-size); outline-color: @color-surface-light5; From dfbfeb43cc88d6c502146708ca05b3fd48068af2 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Wed, 5 Jul 2023 00:35:10 +0100 Subject: [PATCH 13/21] switch to using use-long-press library --- package-lock.json | 17 ++++++++++++++++- package.json | 3 ++- src/common/Button/Button.js | 17 +++-------------- .../MetaDetails/VideosList/Video/Video.js | 3 +-- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2aaa3b51..12f0161d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,8 @@ "react-is": "18.2.0", "spatial-navigation-polyfill": "https://github.com/Stremio/spatial-navigation.git#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", "stremio-translations": "https://github.com/Stremio/stremio-translations.git#92675658de92113c5888cf5e57003e468e8b8c9c", - "url": "0.11.0" + "url": "0.11.0", + "use-long-press": "^3.1.5" }, "devDependencies": { "@babel/core": "7.16.0", @@ -13664,6 +13665,14 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "node_modules/use-long-press": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.1.5.tgz", + "integrity": "sha512-bnwk2SlvLLpeJPkNYSGkc59q5YNV9V/fLDkSOAF2p7Xt0zw3iYHEmgEGkNYkK7zEIEyRFi5CczKsT7MN99UzVQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", @@ -25104,6 +25113,12 @@ } } }, + "use-long-press": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.1.5.tgz", + "integrity": "sha512-bnwk2SlvLLpeJPkNYSGkc59q5YNV9V/fLDkSOAF2p7Xt0zw3iYHEmgEGkNYkK7zEIEyRFi5CczKsT7MN99UzVQ==", + "requires": {} + }, "use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/package.json b/package.json index 771453a81..a6b2a9a28 100755 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "react-is": "18.2.0", "spatial-navigation-polyfill": "https://github.com/Stremio/spatial-navigation.git#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", "stremio-translations": "https://github.com/Stremio/stremio-translations.git#92675658de92113c5888cf5e57003e468e8b8c9c", - "url": "0.11.0" + "url": "0.11.0", + "use-long-press": "^3.1.5" }, "devDependencies": { "@babel/core": "7.16.0", diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index d2b69e138..4c103dae9 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -4,20 +4,10 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const styles = require('./styles'); +const { useLongPress } = require('use-long-press'); const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { - const longPressTimeout = React.useRef(null); - const onTouchStart = React.useCallback((event) => { - longPressTimeout.current = setTimeout(function () { - clearTimeout(longPressTimeout.current); - if (typeof onLongPress === 'function') { - onLongPress(event); - } - }, 500); - }, [onLongPress]); - const onTouchEnd = React.useCallback(() => { - clearTimeout(longPressTimeout.current); - }, []); + const longPress = useLongPress(onLongPress); const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { props.onKeyDown(event); @@ -49,8 +39,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr href, onKeyDown, onMouseDown, - onTouchStart, - onTouchEnd, + ...longPress() }, children ); diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index eda0ca399..ef6dc42e8 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -31,8 +31,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w } }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { - if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { - if (event.cancelable) event.preventDefault(); + if (!event.nativeEvent.togglePopupPrevented) { toggleMenu(); } }, [toggleMenu]); From 02ef06fe49fd13536b8ab64a2a5c33339a6cddf0 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Wed, 5 Jul 2023 15:46:20 +0100 Subject: [PATCH 14/21] adding comments and exposing the exported handlers --- src/common/Button/Button.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 4c103dae9..30bc30be6 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -8,6 +8,9 @@ const { useLongPress } = require('use-long-press'); const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { const longPress = useLongPress(onLongPress); + // exoposing them to make it easier to know which handlers are exported, + // in case a change to one of them is needed in the future. + const {onPointerDown, onPointerMove, onPointerUp, onPointerLeave} = longPress(); const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { props.onKeyDown(event); @@ -39,7 +42,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr href, onKeyDown, onMouseDown, - ...longPress() + onPointerDown, onPointerMove, onPointerUp, onPointerLeave }, children ); From 5246373744ef794229f70015cc5e78e6cbfed838 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Wed, 5 Jul 2023 16:27:17 +0100 Subject: [PATCH 15/21] switch to pointer events for longpress --- src/common/Button/Button.js | 7 ++----- src/routes/MetaDetails/VideosList/Video/Video.js | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 30bc30be6..ea457b66d 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -7,10 +7,7 @@ const styles = require('./styles'); const { useLongPress } = require('use-long-press'); const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { - const longPress = useLongPress(onLongPress); - // exoposing them to make it easier to know which handlers are exported, - // in case a change to one of them is needed in the future. - const {onPointerDown, onPointerMove, onPointerUp, onPointerLeave} = longPress(); + const longPress = useLongPress(onLongPress, { detect: 'pointer' }); const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { props.onKeyDown(event); @@ -42,7 +39,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr href, onKeyDown, onMouseDown, - onPointerDown, onPointerMove, onPointerUp, onPointerLeave + ...longPress() }, children ); diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index ef6dc42e8..2f82d348c 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -31,7 +31,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w } }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { - if (!event.nativeEvent.togglePopupPrevented) { + if (!event.pointerType === 'mouse' && !event.nativeEvent.togglePopupPrevented) { toggleMenu(); } }, [toggleMenu]); From 138b0568005563d79968a3af274a6df9aa54c2d1 Mon Sep 17 00:00:00 2001 From: dexter21767-dev Date: Wed, 5 Jul 2023 16:54:17 +0100 Subject: [PATCH 16/21] move -webkit-touch-callout to popup --- src/common/Button/styles.less | 4 ---- src/common/Popup/styles.less | 4 ++++ src/routes/MetaDetails/VideosList/Video/Video.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index b379a4353..ed2865f14 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -3,10 +3,6 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; .button-container { - // IOS specific - // prevents showing the default context-menu when long pressing an anchor in safari. - -webkit-touch-callout: none !important; - outline-width: var(--focus-outline-size); outline-color: @color-surface-light5; outline-offset: calc(-1 * var(--focus-outline-size)); diff --git a/src/common/Popup/styles.less b/src/common/Popup/styles.less index d906f31ee..902fd550f 100644 --- a/src/common/Popup/styles.less +++ b/src/common/Popup/styles.less @@ -3,6 +3,10 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; .label-container { + // IOS specific + // prevents showing the default context-menu when long pressing an anchor in safari. + -webkit-touch-callout: none !important; + position: relative; overflow: visible; diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 2f82d348c..ac6797283 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -31,7 +31,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w } }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { - if (!event.pointerType === 'mouse' && !event.nativeEvent.togglePopupPrevented) { + if (event.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) { toggleMenu(); } }, [toggleMenu]); From 3638c766cfb178f98caf5186e817623e04ffdfe7 Mon Sep 17 00:00:00 2001 From: unclekingpin <125216544+unclekingpin@users.noreply.github.com> Date: Wed, 5 Jul 2023 18:55:44 +0300 Subject: [PATCH 17/21] remove empty line --- src/routes/MetaDetails/VideosList/Video/styles.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/MetaDetails/VideosList/Video/styles.less b/src/routes/MetaDetails/VideosList/Video/styles.less index 9f029be80..0c63b960d 100644 --- a/src/routes/MetaDetails/VideosList/Video/styles.less +++ b/src/routes/MetaDetails/VideosList/Video/styles.less @@ -12,7 +12,6 @@ } .video-container { - display: flex; flex-direction: row; flex-wrap: wrap; From d65596233204dba7bd3466e097cba7c3c73aca1c Mon Sep 17 00:00:00 2001 From: unclekingpin <125216544+unclekingpin@users.noreply.github.com> Date: Wed, 5 Jul 2023 18:56:09 +0300 Subject: [PATCH 18/21] remove empty line --- src/common/Button/styles.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index ed2865f14..d53e34afa 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -7,7 +7,6 @@ outline-color: @color-surface-light5; outline-offset: calc(-1 * var(--focus-outline-size)); cursor: pointer; - &:focus { outline-style: solid; } From 61eba4d13e844184b41d5184c8a03e105870eeb0 Mon Sep 17 00:00:00 2001 From: unclekingpin <125216544+unclekingpin@users.noreply.github.com> Date: Wed, 5 Jul 2023 18:57:12 +0300 Subject: [PATCH 19/21] fix indent --- src/common/Button/styles.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index d53e34afa..e7b601729 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -7,6 +7,7 @@ outline-color: @color-surface-light5; outline-offset: calc(-1 * var(--focus-outline-size)); cursor: pointer; + &:focus { outline-style: solid; } From cbae03307d159ae4f9ce1ec59102d2545b03bf7a Mon Sep 17 00:00:00 2001 From: nklhtv Date: Wed, 5 Jul 2023 19:55:49 +0300 Subject: [PATCH 20/21] use pointerdown for consistency --- src/common/Popup/Popup.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index 59262c53a..aad02bdf3 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -47,7 +47,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque onCloseRequest(closeEvent); } break; - case 'touchstart': + case 'pointerdown': if (event.target !== document.documentElement && !labelRef.current.contains(event.target)) { onCloseRequest(closeEvent); } @@ -58,12 +58,12 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque if (routeFocused && open) { window.addEventListener('keydown', onCloseEvent); window.addEventListener('mousedown', onCloseEvent); - window.addEventListener('touchstart', onCloseEvent); + window.addEventListener('pointerdown', onCloseEvent); } return () => { window.removeEventListener('keydown', onCloseEvent); window.removeEventListener('mousedown', onCloseEvent); - window.removeEventListener('touchstart', onCloseEvent); + window.removeEventListener('pointerdown', onCloseEvent); }; }, [routeFocused, open, onCloseRequest, dataset]); React.useLayoutEffect(() => { From d6b86492e34e4f4f1a3de79e2e0f0646ffebdb86 Mon Sep 17 00:00:00 2001 From: nklhtv Date: Wed, 5 Jul 2023 21:06:43 +0300 Subject: [PATCH 21/21] consistent UX accross platforms --- src/common/Button/Button.js | 7 +++++-- .../MetaDetails/VideosList/Video/Video.js | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index ea457b66d..9d5ef7c1e 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -13,8 +13,11 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr props.onKeyDown(event); } - if (event.key === 'Enter' && !event.nativeEvent.buttonClickPrevented) { - event.currentTarget.click(); + if (event.key === 'Enter') { + event.preventDefault(); + if (!event.nativeEvent.buttonClickPrevented) { + event.currentTarget.click(); + } } }, [props.onKeyDown]); const onMouseDown = React.useCallback((event) => { diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index ac6797283..6ce900537 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -21,21 +21,20 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w toggleMenu(); } }, []); - const popupLabelOnKeyDown = React.useCallback((event) => { - event.nativeEvent.buttonClickPrevented = true; - }, []); const popupLabelOnContextMenu = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) { event.preventDefault(); - toggleMenu(); + if (event.nativeEvent.pointerType === 'mouse') { + toggleMenu(); + } } }, [toggleMenu]); const popupLabelOnLongPress = React.useCallback((event) => { - if (event.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) { + if (event.nativeEvent.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) { toggleMenu(); } }, [toggleMenu]); - const popupMenuOTouchStart = React.useCallback((event) => { + const popupMenuOnPointerDown = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); const popupMenuOnContextMenu = React.useCallback((event) => { @@ -44,6 +43,9 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w const popupMenuOnClick = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); + const popupMenuOnKeyDown = React.useCallback((event) => { + event.nativeEvent.buttonClickPrevented = true; + }, []); const toggleWatchedOnClick = React.useCallback((event) => { event.preventDefault(); closeMenu(); @@ -141,7 +143,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w }, []); const renderMenu = React.useMemo(() => function renderMenu() { return ( -
+
@@ -171,13 +173,12 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w href={href} {...props} onClick={popupLabelOnClick} - onKeyDown={popupLabelOnKeyDown} + onLongPress={popupLabelOnLongPress} onContextMenu={popupLabelOnContextMenu} open={menuOpen} onCloseRequest={closeMenu} renderLabel={renderLabel} renderMenu={renderMenu} - onLongPress={popupLabelOnLongPress} /> ); };