Merge branch 'development' of github.com:Stremio/stremio-web into mark-external-video-as-watched

This commit is contained in:
unclekingpin 2023-07-17 14:33:31 -07:00
commit 27cbe15538
9 changed files with 82 additions and 16 deletions

17
package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -4,15 +4,20 @@ 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, ...props }, ref) => {
const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => {
const longPress = useLongPress(onLongPress, { detect: 'pointer' });
const onKeyDown = React.useCallback((event) => {
if (typeof props.onKeyDown === 'function') {
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) => {
@ -36,7 +41,8 @@ const Button = React.forwardRef(({ className, href, disabled, children, ...props
className: classnames(className, styles['button-container'], { 'disabled': disabled }),
href,
onKeyDown,
onMouseDown
onMouseDown,
...longPress()
},
children
);
@ -50,7 +56,8 @@ Button.propTypes = {
disabled: PropTypes.bool,
children: PropTypes.node,
onKeyDown: PropTypes.func,
onMouseDown: PropTypes.func
onMouseDown: PropTypes.func,
onLongPress: PropTypes.func,
};
module.exports = Button;

View file

@ -47,16 +47,23 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque
onCloseRequest(closeEvent);
}
break;
case 'pointerdown':
if (event.target !== document.documentElement && !labelRef.current.contains(event.target)) {
onCloseRequest(closeEvent);
}
break;
}
}
};
if (routeFocused && open) {
window.addEventListener('keydown', onCloseEvent);
window.addEventListener('mousedown', onCloseEvent);
window.addEventListener('pointerdown', onCloseEvent);
}
return () => {
window.removeEventListener('keydown', onCloseEvent);
window.removeEventListener('mousedown', onCloseEvent);
window.removeEventListener('pointerdown', onCloseEvent);
};
}, [routeFocused, open, onCloseRequest, dataset]);
React.useLayoutEffect(() => {

View file

@ -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;

View file

@ -19,6 +19,12 @@ const Discover = ({ urlParams, queryParams }) => {
const [inputsModalOpen, openInputsModal, closeInputsModal] = useBinaryState(false);
const [addonModalOpen, openAddonModal, closeAddonModal] = useBinaryState(false);
const [selectedMetaItemIndex, setSelectedMetaItemIndex] = React.useState(0);
const metasContainerRef = React.useRef();
React.useEffect(() => {
if (discover.catalog?.content.type === 'Loading') {
metasContainerRef.current.scrollTop = 0;
}
}, [discover.catalog]);
const selectedMetaItem = React.useMemo(() => {
return discover.catalog !== null &&
discover.catalog.content.type === 'Ready' &&
@ -122,7 +128,7 @@ const Discover = ({ urlParams, queryParams }) => {
</div>
:
discover.catalog.content.type === 'Loading' ?
<div className={classnames(styles['meta-items-container'], 'animation-fade-in')}>
<div ref={metasContainerRef} className={classnames(styles['meta-items-container'], 'animation-fade-in')}>
{Array(CONSTANTS.CATALOG_PAGE_SIZE).fill(null).map((_, index) => (
<div key={index} className={styles['meta-item-placeholder']}>
<div className={styles['poster-container']} />
@ -133,7 +139,7 @@ const Discover = ({ urlParams, queryParams }) => {
))}
</div>
:
<div className={classnames(styles['meta-items-container'], 'animation-fade-in')} onScroll={onScroll} onFocusCapture={metaItemsOnFocusCapture}>
<div ref={metasContainerRef} className={classnames(styles['meta-items-container'], 'animation-fade-in')} onScroll={onScroll} onFocusCapture={metaItemsOnFocusCapture}>
{discover.catalog.content.content.map((metaItem, index) => (
<MetaItem
key={index}
@ -164,6 +170,7 @@ const Discover = ({ urlParams, queryParams }) => {
released={selectedMetaItem.released}
description={selectedMetaItem.description}
deepLinks={selectedMetaItem.deepLinks}
links={selectedMetaItem.links}
trailerStreams={selectedMetaItem.trailerStreams}
inLibrary={selectedMetaItem.inLibrary}
toggleInLibrary={selectedMetaItem.inLibrary ? removeFromLibrary : addToLibrary}

View file

@ -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');
@ -20,21 +21,31 @@ 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();
if (event.nativeEvent.pointerType === 'mouse') {
toggleMenu();
}
}
}, [toggleMenu]);
const popupLabelOnLongPress = React.useCallback((event) => {
if (event.nativeEvent.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) {
toggleMenu();
}
}, [toggleMenu]);
const popupMenuOnPointerDown = React.useCallback((event) => {
event.nativeEvent.togglePopupPrevented = true;
}, []);
const popupMenuOnContextMenu = React.useCallback((event) => {
event.nativeEvent.togglePopupPrevented = true;
}, []);
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();
@ -132,12 +143,12 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w
}, []);
const renderMenu = React.useMemo(() => function renderMenu() {
return (
<div className={styles['context-menu-content']} onContextMenu={popupMenuOnContextMenu} onClick={popupMenuOnClick}>
<div className={styles['context-menu-content']} onPointerDown={popupMenuOnPointerDown} onContextMenu={popupMenuOnContextMenu} onClick={popupMenuOnClick} onKeyDown={popupMenuOnKeyDown}>
<Button className={styles['context-menu-option-container']} title={'Watch'}>
<div className={styles['context-menu-option-label']}>Watch</div>
<div className={styles['context-menu-option-label']}>{t('CTX_WATCH')}</div>
</Button>
<Button className={styles['context-menu-option-container']} title={watched ? 'Mark as non-watched' : 'Mark as watched'} onClick={toggleWatchedOnClick}>
<div className={styles['context-menu-option-label']}>{watched ? 'Mark as non-watched' : 'Mark as watched'}</div>
<div className={styles['context-menu-option-label']}>{watched ? t('CTX_MARK_NON_WATCHED') : t('CTX_MARK_WATCHED')}</div>
</Button>
</div>
);
@ -162,7 +173,7 @@ 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}

View file

@ -27,6 +27,7 @@
flex: none;
.thumbnail {
pointer-events: none;
display: block;
width: 7.5rem;
height: 5rem;

View file

@ -585,11 +585,24 @@ const Player = ({ urlParams, queryParams }) => {
}
}
};
const onWheel = ({ deltaY }) => {
if (deltaY > 0) {
if (!subtitlesMenuOpen && !infoMenuOpen && !videosMenuOpen && !speedMenuOpen && !optionsMenuOpen && !statisticsMenuOpen && videoState.volume !== null) {
onVolumeChangeRequested(videoState.volume - 5);
}
} else {
if (!subtitlesMenuOpen && !infoMenuOpen && !videosMenuOpen && !speedMenuOpen && !optionsMenuOpen && !statisticsMenuOpen && videoState.volume !== null) {
onVolumeChangeRequested(videoState.volume + 5);
}
}
};
if (routeFocused) {
window.addEventListener('keydown', onKeyDown);
window.addEventListener('wheel', onWheel);
}
return () => {
window.removeEventListener('keydown', onKeyDown);
window.removeEventListener('wheel', onWheel);
};
}, [player.metaItem, player.selected, streamingServer.statistics, settings.seekTimeDuration, routeFocused, subtitlesMenuOpen, infoMenuOpen, videosMenuOpen, speedMenuOpen, optionsMenuOpen, statisticsMenuOpen, videoState.paused, videoState.time, videoState.volume, videoState.audioTracks, videoState.subtitlesTracks, videoState.extraSubtitlesTracks, videoState.playbackSpeed, toggleSubtitlesMenu, toggleInfoMenu, toggleVideosMenu, toggleStatisticsMenu]);
React.useLayoutEffect(() => {