178 lines
5.4 KiB
React
178 lines
5.4 KiB
React
|
// @flow
|
||
|
import * as RENDER_MODES from 'constants/file_render_modes';
|
||
|
import React, { useEffect, useState } from 'react';
|
||
|
import { onFullscreenChange } from 'util/full-screen';
|
||
|
import { generateListSearchUrlParams, formatLbryUrlForWeb } from 'util/url';
|
||
|
import { useHistory } from 'react-router';
|
||
|
import LoadingScreen from 'component/common/loading-screen';
|
||
|
import FileRender from 'component/fileRender';
|
||
|
import AutoplayCountdown from 'component/autoplayCountdown';
|
||
|
import LivestreamIframeRender from 'component/livestreamLayout/iframe-render';
|
||
|
|
||
|
const PRIMARY_PLAYER_WRAPPER_CLASS = 'file-page__video-container';
|
||
|
export const INLINE_PLAYER_WRAPPER_CLASS = 'inline-player__wrapper';
|
||
|
|
||
|
// ****************************************************************************
|
||
|
// ****************************************************************************
|
||
|
|
||
|
type Props = {
|
||
|
claimId?: string,
|
||
|
uri: string,
|
||
|
streamingUrl?: string,
|
||
|
renderMode: string,
|
||
|
collectionId: string,
|
||
|
costInfo: any,
|
||
|
claimWasPurchased: boolean,
|
||
|
nextListUri: string,
|
||
|
previousListUri: string,
|
||
|
activeLivestreamForChannel?: any,
|
||
|
channelClaimId?: any,
|
||
|
doPlayUri: (string) => void,
|
||
|
};
|
||
|
|
||
|
export default function FileRenderMobile(props: Props) {
|
||
|
const {
|
||
|
claimId,
|
||
|
uri,
|
||
|
streamingUrl,
|
||
|
renderMode,
|
||
|
collectionId,
|
||
|
costInfo,
|
||
|
claimWasPurchased,
|
||
|
nextListUri,
|
||
|
previousListUri,
|
||
|
activeLivestreamForChannel,
|
||
|
channelClaimId,
|
||
|
doPlayUri,
|
||
|
} = props;
|
||
|
|
||
|
const { push } = useHistory();
|
||
|
|
||
|
const [fileViewerRect, setFileViewerRect] = useState();
|
||
|
const [doNavigate, setDoNavigate] = useState(false);
|
||
|
const [playNextUrl, setPlayNextUrl] = useState(true);
|
||
|
const [countdownCanceled, setCountdownCanceled] = useState(false);
|
||
|
|
||
|
const isCurrentClaimLive = activeLivestreamForChannel && activeLivestreamForChannel.claimId === claimId;
|
||
|
const isFree = costInfo && costInfo.cost === 0;
|
||
|
const canViewFile = isFree || claimWasPurchased;
|
||
|
const isPlayable = RENDER_MODES.FLOATING_MODES.includes(renderMode) || activeLivestreamForChannel;
|
||
|
const isReadyToPlay = isPlayable && streamingUrl;
|
||
|
|
||
|
const handleResize = React.useCallback(() => {
|
||
|
const element = document.querySelector(`.${PRIMARY_PLAYER_WRAPPER_CLASS}`);
|
||
|
|
||
|
if (!element) return;
|
||
|
|
||
|
const rect = element.getBoundingClientRect();
|
||
|
|
||
|
// getBoundingClientRect returns a DomRect, not an object
|
||
|
const objectRect = {
|
||
|
top: rect.top,
|
||
|
right: rect.right,
|
||
|
bottom: rect.bottom,
|
||
|
left: rect.left,
|
||
|
width: rect.width,
|
||
|
height: rect.height,
|
||
|
// $FlowFixMe
|
||
|
x: rect.x,
|
||
|
};
|
||
|
|
||
|
// $FlowFixMe
|
||
|
setFileViewerRect({ ...objectRect });
|
||
|
}, []);
|
||
|
|
||
|
// Initial resize, will place the player correctly above the cover when starts playing
|
||
|
// (remember the URI here is from playingUri). The cover then keeps on the page and kind of serves as a placeholder
|
||
|
// for the player size and gives the content layered behind the player a "max scroll height"
|
||
|
useEffect(() => {
|
||
|
if (uri) {
|
||
|
handleResize();
|
||
|
setCountdownCanceled(false);
|
||
|
}
|
||
|
}, [handleResize, uri]);
|
||
|
|
||
|
useEffect(() => {
|
||
|
handleResize();
|
||
|
|
||
|
window.addEventListener('resize', handleResize);
|
||
|
onFullscreenChange(window, 'add', handleResize);
|
||
|
|
||
|
return () => {
|
||
|
window.removeEventListener('resize', handleResize);
|
||
|
onFullscreenChange(window, 'remove', handleResize);
|
||
|
};
|
||
|
}, [handleResize]);
|
||
|
|
||
|
const doPlay = React.useCallback(
|
||
|
(playUri) => {
|
||
|
setDoNavigate(false);
|
||
|
const navigateUrl = formatLbryUrlForWeb(playUri);
|
||
|
push({
|
||
|
pathname: navigateUrl,
|
||
|
search: collectionId && generateListSearchUrlParams(collectionId),
|
||
|
state: { collectionId, forceAutoplay: true, hideFloatingPlayer: true },
|
||
|
});
|
||
|
},
|
||
|
[collectionId, push]
|
||
|
);
|
||
|
|
||
|
React.useEffect(() => {
|
||
|
if (!doNavigate) return;
|
||
|
|
||
|
if (playNextUrl && nextListUri) {
|
||
|
doPlay(nextListUri);
|
||
|
} else if (previousListUri) {
|
||
|
doPlay(previousListUri);
|
||
|
}
|
||
|
setPlayNextUrl(true);
|
||
|
}, [doNavigate, doPlay, nextListUri, playNextUrl, previousListUri]);
|
||
|
|
||
|
if (!isPlayable || !uri || countdownCanceled || (collectionId && !canViewFile && !nextListUri)) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
return (
|
||
|
<div
|
||
|
className="content__viewer content__viewer--inline content__viewer--mobile"
|
||
|
style={
|
||
|
fileViewerRect
|
||
|
? {
|
||
|
width: fileViewerRect.width,
|
||
|
height: fileViewerRect.height,
|
||
|
left: fileViewerRect.x,
|
||
|
}
|
||
|
: {}
|
||
|
}
|
||
|
>
|
||
|
<div className="content__wrapper">
|
||
|
<React.Suspense fallback={<Loading />}>
|
||
|
{isCurrentClaimLive && channelClaimId ? (
|
||
|
<LivestreamIframeRender channelClaimId={channelClaimId} showLivestream mobileVersion />
|
||
|
) : isReadyToPlay ? (
|
||
|
<FileRender uri={uri} />
|
||
|
) : !canViewFile ? (
|
||
|
<div className="content__loading">
|
||
|
<AutoplayCountdown
|
||
|
nextRecommendedUri={nextListUri}
|
||
|
doNavigate={() => setDoNavigate(true)}
|
||
|
doReplay={() => doPlayUri(uri)}
|
||
|
doPrevious={() => {
|
||
|
setPlayNextUrl(false);
|
||
|
setDoNavigate(true);
|
||
|
}}
|
||
|
onCanceled={() => setCountdownCanceled(true)}
|
||
|
skipPaid
|
||
|
/>
|
||
|
</div>
|
||
|
) : (
|
||
|
<Loading />
|
||
|
)}
|
||
|
</React.Suspense>
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
const Loading = () => <LoadingScreen status={__('Loading')} />;
|