From 4762934d9769eb9cd389d920a31e49d1e2816a83 Mon Sep 17 00:00:00 2001 From: Cal Leung Date: Wed, 8 Nov 2023 22:01:48 -0800 Subject: [PATCH 1/2] Use custom controls for iOS video --- app/components/Views/MediaPlayer/index.js | 115 +++++++++++++++++----- 1 file changed, 93 insertions(+), 22 deletions(-) diff --git a/app/components/Views/MediaPlayer/index.js b/app/components/Views/MediaPlayer/index.js index 5574b6f3d51..613b7698507 100644 --- a/app/components/Views/MediaPlayer/index.js +++ b/app/components/Views/MediaPlayer/index.js @@ -1,32 +1,83 @@ -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; import PropTypes from 'prop-types'; import { StyleSheet, View, ViewPropTypes } from 'react-native'; import AndroidMediaPlayer from './AndroidMediaPlayer'; import Video from 'react-native-video'; import Device from '../../../util/device'; import Loader from './Loader'; +import Ionicons from 'react-native-vector-icons/Ionicons'; +import { TapGestureHandler } from 'react-native-gesture-handler'; +import Animated, { + useAnimatedStyle, + useSharedValue, + withDelay, + withSequence, + withTiming, +} from 'react-native-reanimated'; +import { useStyles } from '../../../component-library/hooks'; -const styles = StyleSheet.create({ - loaderContainer: { - position: 'absolute', - zIndex: 999, - width: '100%', - height: '100%', - }, -}); +const styleSheet = ({ theme: { colors }, vars: { isPlaying } }) => + StyleSheet.create({ + loaderContainer: { + position: 'absolute', + zIndex: 999, + width: '100%', + height: '100%', + }, + playButtonCircle: { + backgroundColor: colors.overlay.default, + height: 44, + width: 44, + borderRadius: 22, + justifyContent: 'center', + alignItems: 'center', + }, + videoControlsStyle: { + ...StyleSheet.absoluteFillObject, + justifyContent: 'center', + alignItems: 'center', + }, + playIcon: { left: isPlaying ? 2 : 0 }, + }); function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { const [loading, setLoading] = useState(true); const [error, setError] = useState(false); + const videoRef = useRef(); + const [isPlaying, setIsPlaying] = useState(true); + const videoControlsOpacity = useSharedValue(0); + const { + styles, + theme: { colors }, + } = useStyles(styleSheet, { isPlaying }); - const onLoad = () => setLoading(false); + const onLoad = () => { + setLoading(false); + setIsPlaying(true); + }; - const onError = () => setError(true); + const onError = () => { + setError(true); + setIsPlaying(false); + }; // Video source can be either a number returned by import for bundled files // or an object of the form { uri: 'http://...' } for remote files const source = Number.isInteger(uri) ? uri : { uri }; + const videoControlsStyle = useAnimatedStyle(() => ({ + ...styles.videoControlsStyle, + opacity: videoControlsOpacity.value, + })); + + const onPressVideoControls = () => { + videoControlsOpacity.value = withSequence( + withTiming(1), + withDelay(500, withTiming(0)), + ); + setIsPlaying(!isPlaying); + }; + return ( {loading && ( @@ -44,17 +95,37 @@ function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { selectedTextTrack={selectedTextTrack} /> ) : ( - ); From 15850b0b4c45e1e3c09cbbe550a3e9f6cb6407e6 Mon Sep 17 00:00:00 2001 From: Cal Leung Date: Thu, 9 Nov 2023 09:19:11 -0800 Subject: [PATCH 2/2] Create mute controls --- app/components/Views/MediaPlayer/index.js | 36 +++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/app/components/Views/MediaPlayer/index.js b/app/components/Views/MediaPlayer/index.js index 613b7698507..8167fb4a01d 100644 --- a/app/components/Views/MediaPlayer/index.js +++ b/app/components/Views/MediaPlayer/index.js @@ -1,6 +1,11 @@ import React, { useRef, useState } from 'react'; import PropTypes from 'prop-types'; -import { StyleSheet, View, ViewPropTypes } from 'react-native'; +import { + StyleSheet, + TouchableOpacity, + View, + ViewPropTypes, +} from 'react-native'; import AndroidMediaPlayer from './AndroidMediaPlayer'; import Video from 'react-native-video'; import Device from '../../../util/device'; @@ -38,6 +43,17 @@ const styleSheet = ({ theme: { colors }, vars: { isPlaying } }) => alignItems: 'center', }, playIcon: { left: isPlaying ? 2 : 0 }, + volumeButtonCircle: { + backgroundColor: colors.overlay.default, + position: 'absolute', + right: 16, + top: 36, + height: 36, + width: 36, + borderRadius: 18, + justifyContent: 'center', + alignItems: 'center', + }, }); function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { @@ -45,6 +61,7 @@ function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { const [error, setError] = useState(false); const videoRef = useRef(); const [isPlaying, setIsPlaying] = useState(true); + const [isMuted, setIsMuted] = useState(true); const videoControlsOpacity = useSharedValue(0); const { styles, @@ -78,6 +95,8 @@ function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { setIsPlaying(!isPlaying); }; + const onPressVolumeControls = () => setIsMuted(!isMuted); + return ( {loading && ( @@ -100,7 +119,7 @@ function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { onLoad={onLoad} onError={onError} style={style} - muted + muted={isMuted} paused={!isPlaying} source={source} controls={false} @@ -125,6 +144,19 @@ function MediaPlayer({ uri, style, onClose, textTracks, selectedTextTrack }) { + {isPlaying ? ( + + + + ) : null} )}