2019-08-13 07:35:13 +02:00
// @flow
// This component is entirely for triggering the start of a file view
2020-01-06 19:32:35 +01:00
// The actual viewer for a file exists in TextViewer and FloatingViewer
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
2020-01-13 19:33:07 +01:00
import React , { useEffect , useCallback } from 'react' ;
2019-08-13 07:35:13 +02:00
import classnames from 'classnames' ;
import Button from 'component/button' ;
import isUserTyping from 'util/detect-typing' ;
2019-09-02 15:24:00 +02:00
import Yrbl from 'component/yrbl' ;
2020-01-13 19:33:07 +01:00
import I18nMessage from 'component/i18nMessage' ;
2020-03-25 22:49:14 +01:00
import { generateDownloadUrl } from 'util/lbrytv' ;
2019-08-13 07:35:13 +02:00
const SPACE _BAR _KEYCODE = 32 ;
type Props = {
play : string => void ,
mediaType : string ,
2020-01-06 21:57:49 +01:00
isText : boolean ,
2019-11-26 20:08:34 +01:00
contentType : string ,
2019-08-13 07:35:13 +02:00
isLoading : boolean ,
isPlaying : boolean ,
fileInfo : FileListItem ,
uri : string ,
obscurePreview : boolean ,
insufficientCredits : boolean ,
isStreamable : boolean ,
thumbnail ? : string ,
autoplay : boolean ,
2019-08-19 20:15:54 +02:00
hasCostInfo : boolean ,
2019-08-29 01:33:38 +02:00
costInfo : any ,
2019-12-10 20:45:41 +01:00
isAutoPlayable : boolean ,
2020-01-06 19:32:35 +01:00
inline : boolean ,
2020-01-13 19:33:07 +01:00
claim : StreamClaim ,
2019-08-13 07:35:13 +02:00
} ;
2020-01-06 19:32:35 +01:00
export default function FileViewerInitiator ( props : Props ) {
2019-08-14 05:09:25 +02:00
const {
play ,
mediaType ,
2020-01-06 21:57:49 +01:00
isText ,
2019-11-26 20:08:34 +01:00
contentType ,
2019-08-14 05:09:25 +02:00
isPlaying ,
fileInfo ,
uri ,
obscurePreview ,
insufficientCredits ,
thumbnail ,
autoplay ,
isStreamable ,
2019-08-19 20:15:54 +02:00
hasCostInfo ,
2019-08-29 01:33:38 +02:00
costInfo ,
2019-12-10 20:45:41 +01:00
isAutoPlayable ,
2020-01-13 19:33:07 +01:00
claim ,
2019-08-14 05:09:25 +02:00
} = props ;
2019-08-29 05:24:04 +02:00
const cost = costInfo && costInfo . cost ;
2019-11-28 17:27:30 +01:00
const forceVideo = [ 'application/x-ext-mkv' , 'video/x-matroska' ] . includes ( contentType ) ;
const isPlayable = [ 'audio' , 'video' ] . includes ( mediaType ) || forceVideo ;
2020-01-07 22:07:12 +01:00
const isImage = mediaType === 'image' ;
2019-08-13 07:35:13 +02:00
const fileStatus = fileInfo && fileInfo . status ;
2019-11-26 20:08:34 +01:00
const webStreamOnly = contentType === 'application/pdf' || mediaType === 'text' ;
2019-12-16 05:02:23 +01:00
const supported = IS _WEB ? ( ! cost && isStreamable ) || webStreamOnly || forceVideo : true ;
2020-01-13 19:33:07 +01:00
const { name , claim _id : claimId , value } = claim ;
const fileName = value && value . source && value . source . name ;
2020-03-25 22:49:14 +01:00
const downloadUrl = generateDownloadUrl ( name , claimId ) ;
2019-12-16 05:02:23 +01:00
2020-01-13 19:33:07 +01:00
function getTitle ( ) {
let message = _ _ ( 'Unsupported File' ) ;
// @if TARGET='web'
if ( cost ) {
message = _ _ ( 'Paid Content Not Supported on lbry.tv' ) ;
} else {
message = _ _ ( "We're not quite ready to display this file on lbry.tv yet" ) ;
2019-12-16 05:02:23 +01:00
}
2020-01-13 19:33:07 +01:00
// @endif
2019-12-16 05:02:23 +01:00
2020-01-13 19:33:07 +01:00
return message ;
2019-12-16 05:02:23 +01:00
}
2019-08-13 07:35:13 +02:00
// Wrap this in useCallback because we need to use it to the keyboard effect
2019-10-10 07:26:56 +02:00
// 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
2019-08-13 07:35:13 +02:00
const viewFile = useCallback (
( e ? : SyntheticInputEvent < * > | KeyboardEvent ) => {
if ( e ) {
e . stopPropagation ( ) ;
}
play ( uri ) ;
} ,
[ play , uri ]
) ;
useEffect ( ( ) => {
// This is just for beginning to download a file
// Play/Pause/Fullscreen will be handled by the respective viewers because not every file type should behave the same
function handleKeyDown ( e : KeyboardEvent ) {
if ( ! isUserTyping ( ) && e . keyCode === SPACE _BAR _KEYCODE ) {
e . preventDefault ( ) ;
if ( ! isPlaying || fileStatus === 'stopped' ) {
viewFile ( e ) ;
}
}
}
window . addEventListener ( 'keydown' , handleKeyDown ) ;
return ( ) => {
window . removeEventListener ( 'keydown' , handleKeyDown ) ;
} ;
} , [ isPlaying , fileStatus , viewFile ] ) ;
useEffect ( ( ) => {
const videoOnPage = document . querySelector ( 'video' ) ;
2020-01-07 22:07:12 +01:00
if ( ( ( autoplay && ! videoOnPage && isAutoPlayable ) || isText || isImage ) && hasCostInfo && cost === 0 ) {
2019-08-13 07:35:13 +02:00
viewFile ( ) ;
}
2020-01-06 19:32:35 +01:00
} , [ autoplay , viewFile , isAutoPlayable , hasCostInfo , cost , isText ] ) ;
2019-08-13 07:35:13 +02:00
return (
< div
2019-08-19 20:15:54 +02:00
disabled = { ! hasCostInfo }
2019-12-19 21:43:49 +01:00
style = { ! obscurePreview && supported && thumbnail && ! isPlaying ? { backgroundImage : ` url(" ${ thumbnail } ") ` } : { } }
2020-01-13 19:33:07 +01:00
onClick = { supported ? viewFile : undefined }
2019-09-02 15:24:00 +02:00
className = { classnames ( {
content _ _cover : supported ,
'content__cover--disabled' : ! supported ,
2020-01-06 19:32:35 +01:00
'content__cover--hidden-for-text' : isText ,
2019-08-13 07:35:13 +02:00
'card__media--nsfw' : obscurePreview ,
2019-09-12 22:21:13 +02:00
'card__media--disabled' : supported && ! fileInfo && insufficientCredits ,
2019-08-13 07:35:13 +02:00
} ) }
>
2019-09-02 15:24:00 +02:00
{ ! supported && (
< Yrbl
type = "happy"
2020-01-13 19:33:07 +01:00
title = { getTitle ( ) }
2019-09-02 15:24:00 +02:00
subtitle = {
2020-01-13 19:33:07 +01:00
< I18nMessage
tokens = { {
download _the _app : < Button button = "link" label = { _ _ ( 'download the app' ) } href = "https://lbry.com/get" / > ,
download _this _file : (
< Button button = "link" label = { _ _ ( 'download this file' ) } download = { fileName } href = { downloadUrl } / >
) ,
} }
>
Good news , though ! You can % download _the _app % and gain access to everything , or % download _this _file % and
view it on your device .
< / I18nMessage >
2019-09-02 15:24:00 +02:00
}
/ >
) }
2020-01-06 19:32:35 +01:00
2019-09-02 15:24:00 +02:00
{ ! isPlaying && supported && (
2019-08-13 07:35:13 +02:00
< Button
onClick = { viewFile }
iconSize = { 30 }
title = { isPlayable ? _ _ ( 'Play' ) : _ _ ( 'View' ) }
className = { classnames ( 'button--icon' , {
'button--play' : isPlayable ,
'button--view' : ! isPlayable ,
} ) }
/ >
) }
< / div >
) ;
}