import THREE from 'three' ; import { PropsWithChildren , useCallback , useContext , useEffect , useState } from 'react' ; import { useDispatch , useStore } from 'react-redux' ; import { omit } from 'lodash' ; import { DriveMetadata , MapProperties , MiniProperties } from '../util/googleDriveUtils' ; import { TextureLoaderContextObject } from '../context/fileAPIContextBridge' ; import TextureService from '../service/textureService' ; import { isVideoTexture } from '../util/threeUtils' ; import { getAllFilesFromStore , getTabletopFromStore } from '../redux/mainReducer' ; import { updateTabletopAction } from '../redux/tabletopReducer' ; import { updateFileAction } from '../redux/fileIndexReducer' ; interface TextureContainerProps < T > { metadata : DriveMetadata ; setTexture : ( texture : THREE . Texture | THREE . VideoTexture ) => void ; calculateProperties : ( properties : T , update ? : Partial < T > ) => T ; } const TextureLoaderContainer = < T extends MapProperties | MiniProperties > ( { metadata , setTexture , calculateProperties } ) => { const textureLoader = useContext ( TextureLoaderContextObject ) ; const dispatch = useDispatch ( ) ; const store = useStore ( ) ; const [ stateTexture , setStateTexture ] = useState < THREE . Texture | THREE . VideoTexture | undefined > ( ) ; const metadataId = metadata . id ; const metadataMimeType = metadata . mimeType ; useEffect ( ( ) => { if ( metadataMimeType === undefined ) { return ; } ( async ( ) => { const { texture , width , height } = await TextureService . getTexture ( { id : metadataId , mimeType : metadataMimeType } as DriveMetadata , textureLoader ) ; setTexture ( texture ) ; setStateTexture ( texture ) ; const { driveMetadata } = getAllFilesFromStore ( store . getState ( ) ) ; const myMetadata = driveMetadata [ metadataId ] as DriveMetadata < void , T > ; if ( ! myMetadata ?. properties ?. width ) { dispatch ( updateFileAction ( { ... myMetadata , properties : calculateProperties ( myMetadata ?. properties , { width , height } as Partial < T > ) } ) ) ; } } ) ( ) ; return ( ) => { ( async ( ) => { const lastUse = await TextureService . releaseTexture ( metadataId ) ; if ( lastUse ) { const { videoMuted } = getTabletopFromStore ( store . getState ( ) ) ; if ( videoMuted [ metadataId ] !== undefined ) { dispatch ( updateTabletopAction ( { videoMuted : omit ( videoMuted , metadataId ) } ) ) ; } } } ) ( ) ; } ; } , [ metadataId , metadataMimeType , textureLoader , setTexture , dispatch , store , calculateProperties ] ) ; const playUntilSuccess = useCallback ( async ( ) => { if ( isVideoTexture ( stateTexture ) ) { try { await stateTexture . image . play ( ) ; } catch ( e ) { setTimeout ( playUntilSuccess , 500 ) ; } } } , [ stateTexture ] ) ; const { videoMuted } = getTabletopFromStore ( store . getState ( ) ) ; const muted = videoMuted [ metadata . id ] ; useEffect ( ( ) => { if ( isVideoTexture ( stateTexture ) ) { if ( muted === undefined ) { const { videoMuted } = getTabletopFromStore ( store . getState ( ) ) ; dispatch ( updateTabletopAction ( { videoMuted : { ... videoMuted , [ metadata . id ] : false } } ) ) ; } else { stateTexture . image . muted = muted ; if ( stateTexture . image . paused ) { playUntilSuccess ( ) ; } } } } , [ stateTexture , playUntilSuccess , muted , store , dispatch , metadata ] ) ; return null ; } ; export default TextureLoaderContainer ;