2019-08-13 07:35:13 +02:00
// @flow
// This component is entirely for triggering the start of a file view
2020-04-14 01:48:11 +02:00
// The actual viewer for a file exists in TextViewer and FileRenderFloating
2019-08-13 07:35:13 +02:00
// They can't exist in one component because we need to handle/listen for the start of a new file view
// while a file is currently being viewed
2022-02-01 21:30:57 +01:00
import { useIsMobile } from 'effects/use-screensize' ;
2022-02-01 21:29:00 +01:00
import React from 'react' ;
2019-08-13 07:35:13 +02:00
import classnames from 'classnames' ;
2020-04-01 20:43:50 +02:00
import * as PAGES from 'constants/pages' ;
import * as RENDER _MODES from 'constants/file_render_modes' ;
2019-08-13 07:35:13 +02:00
import Button from 'component/button' ;
2020-04-01 20:43:50 +02:00
import Nag from 'component/common/nag' ;
2022-02-01 21:29:00 +01:00
import * as COLLECTIONS _CONSTS from 'constants/collections' ;
2022-03-21 15:11:26 +01:00
import { LivestreamContext } from 'page/livestream/view' ;
2022-03-15 17:28:55 +01:00
import { formatLbryUrlForWeb } from 'util/url' ;
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle' ;
2022-03-16 18:35:27 +01:00
import useFetchLiveStatus from 'effects/use-fetch-live' ;
2022-03-17 11:53:18 +01:00
import useThumbnail from 'effects/use-thumbnail' ;
2019-08-13 07:35:13 +02:00
type Props = {
2022-03-15 17:28:55 +01:00
channelClaimId : ? string ,
2019-08-13 07:35:13 +02:00
isPlaying : boolean ,
fileInfo : FileListItem ,
uri : string ,
2021-03-11 18:08:11 +01:00
history : { push : ( string ) => void } ,
2021-09-10 19:27:21 +02:00
location : { search : ? string , pathname : string , href : string , state : { forceAutoplay : boolean } } ,
2019-08-13 07:35:13 +02:00
obscurePreview : boolean ,
insufficientCredits : boolean ,
2021-06-25 06:15:17 +02:00
claimThumbnail ? : string ,
2019-08-13 07:35:13 +02:00
autoplay : boolean ,
2019-08-29 01:33:38 +02:00
costInfo : any ,
2020-01-06 19:32:35 +01:00
inline : boolean ,
2020-04-01 20:43:50 +02:00
renderMode : string ,
2020-05-21 17:38:28 +02:00
claimWasPurchased : boolean ,
authenticated : boolean ,
2021-01-08 16:21:27 +01:00
videoTheaterMode : boolean ,
2022-02-23 22:13:22 +01:00
isCurrentClaimLive ? : boolean ,
2022-03-15 17:18:08 +01:00
isLivestreamClaim : boolean ,
customAction ? : any ,
2022-03-15 17:28:55 +01:00
embedded ? : boolean ,
parentCommentId ? : string ,
isMarkdownPost ? : boolean ,
doUriInitiatePlay : ( playingOptions : PlayingUri , isPlayable : boolean ) => void ,
doFetchChannelLiveStatus : ( string ) => void ,
2019-08-13 07:35:13 +02:00
} ;
2020-04-01 20:43:50 +02:00
export default function FileRenderInitiator ( props : Props ) {
2019-08-14 05:09:25 +02:00
const {
2022-03-15 17:28:55 +01:00
channelClaimId ,
2019-08-14 05:09:25 +02:00
isPlaying ,
fileInfo ,
uri ,
obscurePreview ,
insufficientCredits ,
2020-04-01 20:43:50 +02:00
history ,
2020-05-21 17:38:28 +02:00
location ,
2021-06-25 06:15:17 +02:00
claimThumbnail ,
2022-02-01 21:29:00 +01:00
autoplay ,
2020-04-01 20:43:50 +02:00
renderMode ,
2019-08-29 01:33:38 +02:00
costInfo ,
2020-05-21 17:38:28 +02:00
claimWasPurchased ,
authenticated ,
2021-01-08 16:21:27 +01:00
videoTheaterMode ,
2022-02-23 22:13:22 +01:00
isCurrentClaimLive ,
2022-03-15 17:18:08 +01:00
isLivestreamClaim ,
customAction ,
2022-03-15 17:28:55 +01:00
embedded ,
parentCommentId ,
isMarkdownPost ,
2022-02-01 21:29:00 +01:00
doUriInitiatePlay ,
2022-03-15 17:28:55 +01:00
doFetchChannelLiveStatus ,
2019-08-14 05:09:25 +02:00
} = props ;
2021-05-15 07:59:21 +02:00
2022-04-21 09:31:58 +02:00
const theaterMode = renderMode === 'video' || renderMode === 'audio' ? videoTheaterMode : false ;
2022-03-21 15:11:26 +01:00
const { livestreamPage , layountRendered } = React . useContext ( LivestreamContext ) || { } ;
2022-03-16 22:39:09 +01:00
2022-02-01 21:30:57 +01:00
const isMobile = useIsMobile ( ) ;
2022-03-15 17:18:08 +01:00
const containerRef = React . useRef < any > ( ) ;
2022-02-01 21:29:00 +01:00
2022-03-15 17:28:55 +01:00
const { search , href , state : locationState , pathname } = location ;
2022-02-01 21:29:00 +01:00
const urlParams = search && new URLSearchParams ( search ) ;
const collectionId = urlParams && urlParams . get ( COLLECTIONS _CONSTS . COLLECTION _ID ) ;
2021-09-10 19:27:21 +02:00
// check if there is a time or autoplay parameter, if so force autoplay
2022-02-01 21:29:00 +01:00
const urlTimeParam = href && href . indexOf ( 't=' ) > - 1 ;
const forceAutoplayParam = locationState && locationState . forceAutoplay ;
2022-03-15 17:28:55 +01:00
const shouldAutoplay = ! embedded && ( forceAutoplayParam || urlTimeParam || autoplay ) ;
2021-09-10 19:27:21 +02:00
const isFree = costInfo && costInfo . cost === 0 ;
2022-03-16 22:39:09 +01:00
const canViewFile = isLivestreamClaim
? ( layountRendered || isMobile ) && isCurrentClaimLive
: isFree || claimWasPurchased ;
2022-02-23 22:13:22 +01:00
const isPlayable = RENDER _MODES . FLOATING _MODES . includes ( renderMode ) || isCurrentClaimLive ;
2021-03-11 18:08:11 +01:00
const isText = RENDER _MODES . TEXT _MODES . includes ( renderMode ) ;
2021-06-25 06:15:17 +02:00
2022-02-01 21:29:00 +01:00
const renderUnsupported = RENDER _MODES . UNSUPPORTED _IN _THIS _APP . includes ( renderMode ) ;
2022-03-15 17:18:08 +01:00
const disabled =
( isLivestreamClaim && ! isCurrentClaimLive ) ||
renderUnsupported ||
( ! fileInfo && insufficientCredits && ! claimWasPurchased ) ;
2022-02-01 21:29:00 +01:00
const shouldRedirect = ! authenticated && ! isFree ;
2019-08-13 07:35:13 +02:00
2020-05-21 17:38:28 +02:00
function doAuthRedirect ( ) {
2022-03-15 17:28:55 +01:00
history . push ( ` / $ / ${ PAGES . AUTH } ?redirect= ${ encodeURIComponent ( pathname ) } ` ) ;
2020-05-21 17:38:28 +02:00
}
2022-05-03 13:11:17 +02:00
// in case of a livestream outside of the livestream page component, like embed
useFetchLiveStatus ( isLivestreamClaim && ! livestreamPage ? channelClaimId : undefined , doFetchChannelLiveStatus ) ;
2022-03-15 17:28:55 +01:00
2022-03-17 11:53:18 +01:00
const thumbnail = useThumbnail ( claimThumbnail , containerRef ) ;
2019-08-13 07:35:13 +02:00
2022-03-15 17:28:55 +01:00
function handleClick ( ) {
if ( embedded && ! isPlayable ) {
const formattedUrl = formatLbryUrlForWeb ( uri ) ;
history . push ( formattedUrl ) ;
} else {
viewFile ( ) ;
}
}
2022-02-01 21:29:00 +01:00
// Wrap this in useCallback because we need to use it to the view effect
// If we don't a new instance will be created for every render and react will think the dependencies have changed, which will add/remove the listener for every render
const viewFile = React . useCallback ( ( ) => {
2022-03-15 17:28:55 +01:00
const playingOptions = { uri , collectionId , pathname , source : undefined , commentId : undefined } ;
if ( parentCommentId ) {
playingOptions . source = 'comment' ;
playingOptions . commentId = parentCommentId ;
} else if ( isMarkdownPost ) {
playingOptions . source = 'markdown' ;
}
doUriInitiatePlay ( playingOptions , isPlayable ) ;
} , [ collectionId , doUriInitiatePlay , isMarkdownPost , isPlayable , parentCommentId , pathname , uri ] ) ;
2019-08-13 07:35:13 +02:00
2022-02-01 21:29:00 +01:00
React . useEffect ( ( ) => {
2022-04-04 14:13:15 +02:00
// avoid selecting 'video' anymore -> can cause conflicts with Ad popup videos
const videoOnPage = document . querySelector ( '.vjs-tech' ) ;
2022-02-01 21:29:00 +01:00
2021-05-24 10:46:47 +02:00
if (
2021-09-10 19:27:21 +02:00
( canViewFile || forceAutoplayParam ) &&
2022-02-01 21:29:00 +01:00
( ( shouldAutoplay && ( ! videoOnPage || forceAutoplayParam ) && isPlayable ) ||
2022-03-15 19:38:42 +01:00
( ! embedded && RENDER _MODES . AUTO _RENDER _MODES . includes ( renderMode ) ) )
2021-05-24 10:46:47 +02:00
) {
2019-08-13 07:35:13 +02:00
viewFile ( ) ;
}
2022-03-15 19:38:42 +01:00
} , [ canViewFile , embedded , forceAutoplayParam , isPlayable , renderMode , shouldAutoplay , viewFile ] ) ;
2020-04-01 20:43:50 +02:00
/ *
once content is playing , let the appropriate < FileRender > take care of it ...
but for playables , always render so area can be used to fill with floating player
* /
2022-02-01 21:29:00 +01:00
if ( isPlaying && ! isPlayable && canViewFile && ! collectionId ) {
return null ;
2020-04-01 20:43:50 +02:00
}
2019-08-13 07:35:13 +02:00
return (
< div
2021-06-25 06:15:17 +02:00
ref = { containerRef }
2022-03-15 17:28:55 +01:00
onClick = { disabled ? undefined : shouldRedirect ? doAuthRedirect : handleClick }
2021-06-25 06:15:17 +02:00
style = { thumbnail && ! obscurePreview ? { backgroundImage : ` url(" ${ thumbnail } ") ` } : { } }
2022-03-15 17:28:55 +01:00
className = {
embedded
? 'embed__inline-button'
: classnames ( 'content__cover' , {
'content__cover--disabled' : disabled ,
2022-04-21 09:31:58 +02:00
'content__cover--theater-mode' : theaterMode && ! isMobile ,
2022-03-15 17:28:55 +01:00
'content__cover--text' : isText ,
'card__media--nsfw' : obscurePreview ,
} )
}
2019-08-13 07:35:13 +02:00
>
2022-03-15 17:28:55 +01:00
{ embedded && < FileViewerEmbeddedTitle uri = { uri } isInApp / > }
2022-02-01 21:29:00 +01:00
{ renderUnsupported ? (
2020-04-01 20:43:50 +02:00
< Nag
type = "helpful"
inline
message = { _ _ ( 'This content requires LBRY Desktop to display.' ) }
actionText = { _ _ ( 'Get the App' ) }
href = "https://lbry.com/get"
2019-09-02 15:24:00 +02:00
/ >
2022-02-01 21:29:00 +01:00
) : (
! claimWasPurchased &&
insufficientCredits && (
< Nag
type = "helpful"
inline
message = { _ _ ( 'You need more Credits to purchase this.' ) }
actionText = { _ _ ( 'Open Rewards' ) }
onClick = { ( ) => history . push ( ` / $ / ${ PAGES . REWARDS } ` ) }
/ >
)
2019-09-02 15:24:00 +02:00
) }
2022-02-01 21:29:00 +01:00
2022-03-15 17:28:55 +01:00
{ ( ! disabled || ( embedded && isLivestreamClaim ) ) && (
2019-08-13 07:35:13 +02:00
< Button
2020-05-21 23:25:38 +02:00
requiresAuth = { shouldRedirect }
2022-03-15 17:28:55 +01:00
onClick = { handleClick }
2019-08-13 07:35:13 +02:00
iconSize = { 30 }
title = { isPlayable ? _ _ ( 'Play' ) : _ _ ( 'View' ) }
className = { classnames ( 'button--icon' , {
'button--play' : isPlayable ,
'button--view' : ! isPlayable ,
} ) }
/ >
) }
2022-03-15 17:18:08 +01:00
{ customAction }
2019-08-13 07:35:13 +02:00
< / div >
) ;
}