Changeset View
Changeset View
Standalone View
Standalone View
web/media/encrypted-multimedia.react.js
// @flow | // @flow | ||||
import invariant from 'invariant'; | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import 'react-circular-progressbar/dist/styles.css'; | import 'react-circular-progressbar/dist/styles.css'; | ||||
import { AlertCircle as AlertCircleIcon } from 'react-feather'; | import { AlertCircle as AlertCircleIcon } from 'react-feather'; | ||||
import type { Shape } from 'lib/types/core.js'; | |||||
import type { EncryptedMediaType } from 'lib/types/media-types.js'; | import type { EncryptedMediaType } from 'lib/types/media-types.js'; | ||||
import { decryptMedia } from './encryption-utils.js'; | import { decryptMedia } from './encryption-utils.js'; | ||||
import LoadableVideo from './loadable-video.react.js'; | |||||
import css from './media.css'; | import css from './media.css'; | ||||
import LoadingIndicator from '../loading-indicator.react.js'; | import LoadingIndicator from '../loading-indicator.react.js'; | ||||
type Props = { | type Props = { | ||||
+holder: string, | +holder: string, | ||||
+encryptionKey: string, | +encryptionKey: string, | ||||
+type: EncryptedMediaType, | +type: EncryptedMediaType, | ||||
+thumbnailHolder: ?string, | |||||
+thumbnailEncryptionKey: ?string, | |||||
+placeholderSrc?: ?string, | |||||
+elementStyle?: ?Shape<CSSStyleDeclaration>, | |||||
}; | }; | ||||
function EncryptedMultimedia(props: Props): React.Node { | function EncryptedMultimedia(props: Props): React.Node { | ||||
const { holder, encryptionKey } = props; | const { holder, encryptionKey, placeholderSrc, elementStyle } = props; | ||||
const [source, setSource] = React.useState(null); | const [source, setSource] = React.useState(null); | ||||
const videoRef = React.useRef(null); | const videoRef = React.useRef(null); | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
let isMounted = true, | let isMounted = true, | ||||
uriToDispose; | uriToDispose; | ||||
setSource(null); | setSource(null); | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | function EncryptedMultimedia(props: Props): React.Node { | ||||
} | } | ||||
if (source?.error) { | if (source?.error) { | ||||
errorIndicator = <AlertCircleIcon className={css.uploadError} size={36} />; | errorIndicator = <AlertCircleIcon className={css.uploadError} size={36} />; | ||||
} | } | ||||
let mediaNode; | let mediaNode; | ||||
if (props.type === 'encrypted_photo') { | if (props.type === 'encrypted_photo') { | ||||
mediaNode = <img src={source?.uri} key={holder} />; | mediaNode = ( | ||||
<img | |||||
src={source?.uri ?? placeholderSrc} | |||||
key={holder} | |||||
style={elementStyle} | |||||
/> | |||||
); | |||||
} else { | } else { | ||||
mediaNode = <video controls ref={videoRef} key={holder} />; | const { thumbnailHolder, thumbnailEncryptionKey } = props; | ||||
invariant( | |||||
thumbnailHolder && thumbnailEncryptionKey, | |||||
'Thumbnail missing for encrypted video', | |||||
); | |||||
mediaNode = ( | |||||
<LoadableVideo | |||||
uri={null} | |||||
ref={videoRef} | |||||
key={holder} | |||||
thumbnailSource={{ thumbnailHolder, thumbnailEncryptionKey }} | |||||
elementStyle={elementStyle} | |||||
thumbHashDataURL={placeholderSrc} | |||||
/> | |||||
); | |||||
} | } | ||||
return ( | return ( | ||||
<> | <> | ||||
{mediaNode} | {mediaNode} | ||||
{loadingIndicator} | {loadingIndicator} | ||||
{errorIndicator} | {errorIndicator} | ||||
</> | </> | ||||
); | ); | ||||
} | } | ||||
export default EncryptedMultimedia; | export default EncryptedMultimedia; |