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 = (
+
+ );
+ }
+
return (
@@ -640,15 +692,7 @@
{spinner}
-
+ {videoPlayer}
{controls}