unified video player component

This commit is contained in:
noumantahir 2022-01-23 01:11:17 +05:00
parent e8d0f67619
commit 3a99cb1034
5 changed files with 48 additions and 130 deletions

View File

@ -13,7 +13,7 @@ import { navigate } from '../../../../navigation/service';
// Constants // Constants
import { default as ROUTES } from '../../../../constants/routeNames'; import { default as ROUTES } from '../../../../constants/routeNames';
import { PostHtmlRenderer, TextButton } from '../../..'; import { PostHtmlRenderer, TextButton, VideoPlayer } from '../../..';
// Styles // Styles
import styles from './commentBodyStyles'; import styles from './commentBodyStyles';
@ -21,14 +21,12 @@ import styles from './commentBodyStyles';
// Services and Actions // Services and Actions
import { writeToClipboard } from '../../../../utils/clipboard'; import { writeToClipboard } from '../../../../utils/clipboard';
import { toastNotification } from '../../../../redux/actions/uiAction'; import { toastNotification } from '../../../../redux/actions/uiAction';
import VideoPlayerSheet from './videoPlayerSheet';
import { LongPressGestureHandler, State } from 'react-native-gesture-handler'; import { LongPressGestureHandler, State } from 'react-native-gesture-handler';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { OptionsModal } from '../../../atoms'; import { OptionsModal } from '../../../atoms';
import { useAppDispatch } from '../../../../hooks'; import { useAppDispatch } from '../../../../hooks';
import { isCommunity } from '../../../../utils/communityValidation'; import { isCommunity } from '../../../../utils/communityValidation';
import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters'; import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters';
import { startsWith } from 'core-js/core/string';
const WIDTH = Dimensions.get('window').width; const WIDTH = Dimensions.get('window').width;
@ -368,7 +366,12 @@ const CommentBody = ({
setVideoUrl(null); setVideoUrl(null);
}} }}
> >
<VideoPlayerSheet youtubeVideoId={youtubeVideoId} videoUrl={videoUrl} startTime={videoStartTime} /> <VideoPlayer
mode={youtubeVideoId ? 'youtube' : 'url'}
youtubeVideoId={youtubeVideoId}
videoUrl={videoUrl}
startTime={videoStartTime}
/>
</ActionsSheetView> </ActionsSheetView>
</Fragment> </Fragment>
); );

View File

@ -15,11 +15,10 @@ import { toastNotification } from '../../../../redux/actions/uiAction';
// Constants // Constants
import { default as ROUTES } from '../../../../constants/routeNames'; import { default as ROUTES } from '../../../../constants/routeNames';
import VideoPlayerSheet from './videoPlayerSheet';
import { OptionsModal } from '../../../atoms'; import { OptionsModal } from '../../../atoms';
import { isCommunity } from '../../../../utils/communityValidation'; import { isCommunity } from '../../../../utils/communityValidation';
import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters'; import { GLOBAL_POST_FILTERS_VALUE } from '../../../../constants/options/filters';
import { PostHtmlRenderer } from '../../..'; import { PostHtmlRenderer, VideoPlayer } from '../../..';
const WIDTH = Dimensions.get('window').width; const WIDTH = Dimensions.get('window').width;
@ -294,7 +293,8 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
setVideoUrl(null); setVideoUrl(null);
}} }}
> >
<VideoPlayerSheet <VideoPlayer
mode={youtubeVideoId ? 'youtube' : 'url'}
youtubeVideoId={youtubeVideoId} youtubeVideoId={youtubeVideoId}
videoUrl={videoUrl} videoUrl={videoUrl}
startTime={videoStartTime} startTime={videoStartTime}

View File

@ -1,83 +0,0 @@
import React, {useState} from 'react';
import { Dimensions } from 'react-native';
import { View, StyleSheet, ActivityIndicator } from 'react-native';
import WebView from 'react-native-webview';
import YoutubeIframe, { InitialPlayerParams } from 'react-native-youtube-iframe';
interface VideoPlayerSheetProps {
youtubeVideoId?:string;
videoUrl?:string;
startTime?:number;
}
const VideoPlayerSheet = ({youtubeVideoId, videoUrl, startTime}: VideoPlayerSheetProps) => {
const PLAYER_HEIGHT = Dimensions.get('screen').width * (9/16);
const [shouldPlay, setShouldPlay] = useState(false);
const [loading, setLoading] = useState(true);
const _onReady = () => {
setLoading(false)
setShouldPlay(true);
}
const _onChangeState = (event:string) => {
setShouldPlay(!(event == 'paused' || event == 'ended'));
}
const _onError = () => {
setLoading(false)
}
const initialParams:InitialPlayerParams = {
start:startTime
}
return (
<View style={styles.container}>
{youtubeVideoId &&
<YoutubeIframe
height={PLAYER_HEIGHT}
videoId={youtubeVideoId}
initialPlayerParams={initialParams}
onReady={_onReady}
play={shouldPlay}
onChangeState={_onChangeState}
onError={_onError}
/>
}{
videoUrl &&
<View style={{height:PLAYER_HEIGHT}}>
<WebView
scalesPageToFit={true}
bounces={false}
javaScriptEnabled={true}
automaticallyAdjustContentInsets={false}
onLoadEnd={()=>{
setLoading(false);
}}
onLoadStart={()=>{
setLoading(true);
}}
source={{uri:videoUrl}}
/>
</View>
}
{loading && <ActivityIndicator style={styles.activityIndicator}/>}
</View>
);
};
export default VideoPlayerSheet;
const styles = StyleSheet.create({
container: {
paddingVertical:16,
},
activityIndicator: {
position:'absolute', alignItems:'center', justifyContent:'center', top:0, bottom:0, left:0, right:0}
});

View File

@ -218,41 +218,29 @@ export const PostHtmlRenderer = memo(
return <TDefaultRenderer {...props} />; return <TDefaultRenderer {...props} />;
}; };
// iframe renderer for rendering iframes in body // iframe renderer for rendering iframes in body
const _iframeRenderer = function IframeRenderer(props) { const _iframeRenderer = function IframeRenderer(props) {
const iframeProps = useHtmlIframeProps(props); const iframeProps = useHtmlIframeProps(props);
const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi; const checkSrcRegex = /(.*?)\.(mp4|webm|ogg)$/gi;
const isVideoType = iframeProps.source.uri.match(checkSrcRegex); const isVideoFormat = iframeProps.source.uri.match(checkSrcRegex);
const src = isVideoType //this hack help avoid autoplaying fullscreened iframe videos;
? { const src = isVideoFormat ?
{
html: ` html: `
<video width="100%" height="auto" controls> <video width="100%" height="auto" controls>
<source src="${iframeProps.source.uri}" type="video/mp4"> <source src="${iframeProps.source.uri}" type="video/mp4">
</video> </video>`,
`, }:{
}
: {
uri: iframeProps.source.uri, uri: iframeProps.source.uri,
}; };
return ( return (
<WebView <VideoPlayer
scalesPageToFit={true} mode='source'
bounces={false}
javaScriptEnabled={true}
automaticallyAdjustContentInsets={false}
onLoadEnd={() => {
console.log('load end');
}}
onLoadStart={() => {
console.log('load start');
}}
source={src} source={src}
style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} contentWidth={contentWidth}
startInLoadingState={true}
onShouldStartLoadWithRequest={() => true}
mediaPlaybackRequiresUserAction={true}
allowsInlineMediaPlayback={true}
/> />
); );
}; };

View File

@ -1,19 +1,29 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import style from './videoPlayerStyles';
import { Dimensions } from 'react-native'; import { Dimensions } from 'react-native';
import { View, StyleSheet, ActivityIndicator } from 'react-native'; import { View, StyleSheet, ActivityIndicator } from 'react-native';
import WebView from 'react-native-webview'; import WebView from 'react-native-webview';
import YoutubeIframe, { InitialPlayerParams } from 'react-native-youtube-iframe'; import YoutubeIframe, { InitialPlayerParams } from 'react-native-youtube-iframe';
import { WebViewSource } from 'react-native-webview/lib/WebViewTypes';
interface VideoPlayerProps { interface VideoPlayerProps {
mode: 'source'|'youtube'|'url';
contentWidth?: number;
youtubeVideoId?: string; youtubeVideoId?: string;
videoUrl?: string; videoUrl?: string;
startTime?: number; startTime?: number;
contentWidth?: number; source?: WebViewSource;
} }
const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: VideoPlayerProps) => { const VideoPlayer = ({
const PLAYER_HEIGHT = Dimensions.get('screen').width * (9 / 16); youtubeVideoId,
videoUrl,
startTime,
source,
contentWidth = Dimensions.get('screen').width,
mode
}: VideoPlayerProps) => {
const PLAYER_HEIGHT = contentWidth * (9 / 16);
const [shouldPlay, setShouldPlay] = useState(false); const [shouldPlay, setShouldPlay] = useState(false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -40,7 +50,7 @@ const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: Vide
return ( return (
<View style={styles.container}> <View style={styles.container}>
{youtubeVideoId && ( {mode === 'youtube' && youtubeVideoId && (
<View style={{ width: contentWidth, height: PLAYER_HEIGHT }}> <View style={{ width: contentWidth, height: PLAYER_HEIGHT }}>
<YoutubeIframe <YoutubeIframe
height={PLAYER_HEIGHT} height={PLAYER_HEIGHT}
@ -53,7 +63,7 @@ const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: Vide
/> />
</View> </View>
)} )}
{videoUrl && ( {((mode === 'source' && source) || (mode === 'url' && videoUrl)) && (
<View style={{ height: PLAYER_HEIGHT }}> <View style={{ height: PLAYER_HEIGHT }}>
<WebView <WebView
scalesPageToFit={true} scalesPageToFit={true}
@ -66,8 +76,8 @@ const VideoPlayer = ({ youtubeVideoId, videoUrl, startTime, contentWidth }: Vide
onLoadStart={() => { onLoadStart={() => {
setLoading(true); setLoading(true);
}} }}
source={{ uri: videoUrl }} source={source || { uri: videoUrl }}
style={{ width: contentWidth, height: (contentWidth * 9) / 16 }} style={{ width: contentWidth, height: PLAYER_HEIGHT}}
startInLoadingState={true} startInLoadingState={true}
onShouldStartLoadWithRequest={() => true} onShouldStartLoadWithRequest={() => true}
mediaPlaybackRequiresUserAction={true} mediaPlaybackRequiresUserAction={true}