diff --git a/native/media/video-playback-modal.react.js b/native/media/video-playback-modal.react.js --- a/native/media/video-playback-modal.react.js +++ b/native/media/video-playback-modal.react.js @@ -5,6 +5,7 @@ import * as React from 'react'; import { useState } from 'react'; import { View, Text, TouchableOpacity } from 'react-native'; +import filesystem from 'react-native-fs'; import { TapGestureHandler } from 'react-native-gesture-handler'; import * as Progress from 'react-native-progress'; import Animated from 'react-native-reanimated'; @@ -14,6 +15,7 @@ import { useIsAppBackgroundedOrInactive } from 'lib/shared/lifecycle-utils.js'; import type { MediaInfo } from 'lib/types/media-types.js'; +import { decryptMedia } from './encryption-utils.js'; import { formatDuration } from './video-utils.js'; import ConnectedStatusBar from '../connected-status-bar.react.js'; import type { AppNavigationProp } from '../navigation/app-navigator.react.js'; @@ -76,6 +78,41 @@ function VideoPlaybackModal(props: Props): React.Node { const { mediaInfo } = props.route.params; + const { uri, holder, encryptionKey } = mediaInfo; + const [videoSource, setVideoSource] = React.useState( + uri ? { uri } : undefined, + ); + + React.useEffect(() => { + // skip for unencrypted videos + if (!holder || !encryptionKey) { + return; + } + + let isMounted = true; + let uriToDispose; + setVideoSource(undefined); + + const loadDecrypted = async () => { + const { result } = await decryptMedia(holder, encryptionKey, { + destination: 'file', + }); + if (result.success && isMounted) { + uriToDispose = result.uri; + setVideoSource({ uri: result.uri }); + } + }; + loadDecrypted(); + + return () => { + isMounted = false; + if (uriToDispose) { + // remove the temporary file created by decryptMedia + filesystem.unlink(uriToDispose); + } + }; + }, [holder, encryptionKey]); + const closeButtonX = useValue(-1); const closeButtonY = useValue(-1); const closeButtonWidth = useValue(-1); @@ -517,14 +554,7 @@ } }, [backgroundedOrInactive, controlsShowing]); - const { - navigation, - route: { - params: { - mediaInfo: { uri: videoUri }, - }, - }, - } = props; + const { navigation } = props; const togglePlayback = React.useCallback(() => { setPaused(!paused); @@ -573,52 +603,59 @@ styles.contentContainer, ]); - const controls = ( - - - - - + let controls; + if (videoSource) { + controls = ( + + + + + + + + + + + - + + + + + + {timeElapsed} / {totalDuration} + - - - - - - - - - {timeElapsed} / {totalDuration} - - - - - - ); + + + ); + } let spinner; if (spinnerVisible) { @@ -632,6 +669,21 @@ ); } + let videoPlayer; + if (videoSource) { + videoPlayer = ( +