// @flow import React, { useCallback } from 'react'; import Button from 'component/button'; import UriIndicator from 'component/uriIndicator'; import I18nMessage from 'component/i18nMessage'; import { formatLbryUrlForWeb } from 'util/url'; import { withRouter } from 'react-router'; import debounce from 'util/debounce'; import { COLLECTIONS_CONSTS } from 'lbry-redux'; const DEBOUNCE_SCROLL_HANDLER_MS = 150; const CLASSNAME_AUTOPLAY_COUNTDOWN = 'autoplay-countdown'; type Props = { history: { push: (string) => void }, nextRecommendedClaim: ?StreamClaim, nextRecommendedUri: string, isFloating: boolean, doSetPlayingUri: ({ uri: ?string }) => void, doPlayUri: (string) => void, modal: { id: string, modalProps: {} }, collectionId?: string, }; function AutoplayCountdown(props: Props) { const { nextRecommendedUri, nextRecommendedClaim, doSetPlayingUri, doPlayUri, isFloating, history: { push }, modal, collectionId, } = props; const nextTitle = nextRecommendedClaim && nextRecommendedClaim.value && nextRecommendedClaim.value.title; /* this value is coupled with CSS timing variables on .autoplay-countdown__timer */ const countdownTime = 5; const [timer, setTimer] = React.useState(countdownTime); const [timerCanceled, setTimerCanceled] = React.useState(false); const [timerPaused, setTimerPaused] = React.useState(false); const anyModalPresent = modal !== undefined && modal !== null; const isTimerPaused = timerPaused || anyModalPresent; let navigateUrl; if (nextTitle) { navigateUrl = formatLbryUrlForWeb(nextRecommendedUri); if (collectionId) { const collectionParams = new URLSearchParams(); collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); navigateUrl = navigateUrl + `?` + collectionParams.toString(); } } const doNavigate = useCallback(() => { if (!isFloating) { if (navigateUrl) { push(navigateUrl); doSetPlayingUri({ uri: nextRecommendedUri }); doPlayUri(nextRecommendedUri); } } else { if (nextRecommendedUri) { doSetPlayingUri({ uri: nextRecommendedUri }); doPlayUri(nextRecommendedUri); } } }, [navigateUrl, nextRecommendedUri, isFloating, doSetPlayingUri, doPlayUri, push]); function shouldPauseAutoplay() { const elm = document.querySelector(`.${CLASSNAME_AUTOPLAY_COUNTDOWN}`); return elm && elm.getBoundingClientRect().top < 0; } // Update 'setTimerPaused'. React.useEffect(() => { // Ensure correct 'setTimerPaused' on initial render. setTimerPaused(shouldPauseAutoplay()); const handleScroll = debounce((e) => { setTimerPaused(shouldPauseAutoplay()); }, DEBOUNCE_SCROLL_HANDLER_MS); window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); // Update countdown timer. React.useEffect(() => { if (collectionId) { doNavigate(); } else { let interval; if (!timerCanceled && nextRecommendedUri) { if (isTimerPaused) { clearInterval(interval); setTimer(countdownTime); } else { interval = setInterval(() => { const newTime = timer - 1; if (newTime === 0) { doNavigate(); } else { setTimer(timer - 1); } }, 1000); } } return () => { clearInterval(interval); }; } }, [timer, doNavigate, navigateUrl, push, timerCanceled, isTimerPaused, nextRecommendedUri, collectionId]); if (timerCanceled || !nextRecommendedUri) { return null; } return (
}}> Up Next by %channel%
{nextTitle}
{isTimerPaused && (
{__('Autoplay timer paused.')}{' '}
)} {!isTimerPaused && (
{__('Playing in %seconds_left% seconds...', { seconds_left: timer })}{' '}
)}
); } export default withRouter(AutoplayCountdown);