feat(sample): merge ios and android samples (#3015)
* chore: split components
This commit is contained in:
parent
a855284d8d
commit
1f0137608a
@ -75,9 +75,9 @@ PODS:
|
|||||||
- hermes-engine/Pre-built (0.72.5)
|
- hermes-engine/Pre-built (0.72.5)
|
||||||
- libevent (2.1.12)
|
- libevent (2.1.12)
|
||||||
- OpenSSL-Universal (1.1.1100)
|
- OpenSSL-Universal (1.1.1100)
|
||||||
- PromisesObjC (2.3.1)
|
- PromisesObjC (2.2.0)
|
||||||
- PromisesSwift (2.3.1):
|
- PromisesSwift (2.2.0):
|
||||||
- PromisesObjC (= 2.3.1)
|
- PromisesObjC (= 2.2.0)
|
||||||
- RCT-Folly (2021.07.22.00):
|
- RCT-Folly (2021.07.22.00):
|
||||||
- boost
|
- boost
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
@ -691,8 +691,8 @@ SPEC CHECKSUMS:
|
|||||||
hermes-engine: f6cf92a471053245614d9d8097736f6337d5b86c
|
hermes-engine: f6cf92a471053245614d9d8097736f6337d5b86c
|
||||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||||
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
|
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
|
||||||
PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
|
PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959
|
||||||
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
||||||
RCTRequired: df81ab637d35fac9e6eb94611cfd20f0feb05455
|
RCTRequired: df81ab637d35fac9e6eb94611cfd20f0feb05455
|
||||||
RCTTypeSafety: 4636e4a36c7c2df332bda6d59b19b41c443d4287
|
RCTTypeSafety: 4636e4a36c7c2df332bda6d59b19b41c443d4287
|
||||||
@ -733,4 +733,4 @@ SPEC CHECKSUMS:
|
|||||||
|
|
||||||
PODFILE CHECKSUM: 6899e375fcfa0d3a42aa6cb55266008b8f7419cb
|
PODFILE CHECKSUM: 6899e375fcfa0d3a42aa6cb55266008b8f7419cb
|
||||||
|
|
||||||
COCOAPODS: 1.13.0
|
COCOAPODS: 1.12.1
|
||||||
|
@ -602,10 +602,7 @@
|
|||||||
);
|
);
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"-Wl",
|
|
||||||
"-ld_classic",
|
|
||||||
" ",
|
" ",
|
||||||
"-Wl -ld_classic ",
|
|
||||||
);
|
);
|
||||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -678,10 +675,7 @@
|
|||||||
);
|
);
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"-Wl",
|
|
||||||
"-ld_classic",
|
|
||||||
" ",
|
" ",
|
||||||
"-Wl -ld_classic ",
|
|
||||||
);
|
);
|
||||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
67
examples/basic/src/MultiValueControl.tsx
Normal file
67
examples/basic/src/MultiValueControl.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextStyle,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MultiValueControl displays a list clickable text view
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface MultiValueControlType {
|
||||||
|
// a list a string or number to be displayed
|
||||||
|
values: Array<string | number>
|
||||||
|
// The selected value in values
|
||||||
|
selected?: string | number
|
||||||
|
// callback to press onPress
|
||||||
|
onPress: (arg: string | number) => any
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultiValueControl = ({ values, selected, onPress }: MultiValueControlType) => {
|
||||||
|
const selectedStyle: TextStyle = StyleSheet.flatten([
|
||||||
|
styles.option,
|
||||||
|
{fontWeight: 'bold'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const unselectedStyle: TextStyle = StyleSheet.flatten([
|
||||||
|
styles.option,
|
||||||
|
{fontWeight: 'normal'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
return <View style={styles.container}>
|
||||||
|
{values.map((value: string | number) => {
|
||||||
|
const _style = value === selected ? selectedStyle : unselectedStyle
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={value}
|
||||||
|
onPress={() => {
|
||||||
|
onPress?.(value)
|
||||||
|
}}>
|
||||||
|
<Text style={_style}>{value}</Text>
|
||||||
|
</TouchableOpacity>)
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
option: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
fontSize: 11,
|
||||||
|
color: 'white',
|
||||||
|
paddingLeft: 2,
|
||||||
|
paddingRight: 2,
|
||||||
|
lineHeight: 12,
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default MultiValueControl;
|
68
examples/basic/src/ToggleControl.tsx
Normal file
68
examples/basic/src/ToggleControl.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextStyle,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ToggleControl displays a 2 states clickable text
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface ToggleControlType {
|
||||||
|
// boolean indicating if text is selected state
|
||||||
|
isSelected?: boolean
|
||||||
|
// value of text when selected
|
||||||
|
selectedText?: string
|
||||||
|
// value of text when NOT selected
|
||||||
|
unselectedText?: string
|
||||||
|
// default text if no only one text field is needed
|
||||||
|
text?: string
|
||||||
|
// callback called when pressing the component
|
||||||
|
onPress: () => any
|
||||||
|
}
|
||||||
|
|
||||||
|
const ToggleControl = ({ isSelected, selectedText, unselectedText, text, onPress }: ToggleControlType) => {
|
||||||
|
const selectedStyle: TextStyle = StyleSheet.flatten([
|
||||||
|
styles.controlOption,
|
||||||
|
{fontWeight: 'bold'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const unselectedStyle: TextStyle = StyleSheet.flatten([
|
||||||
|
styles.controlOption,
|
||||||
|
{fontWeight: 'normal'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const style = isSelected ? selectedStyle : unselectedStyle;
|
||||||
|
const _text = text ? text : isSelected ? selectedText : unselectedText;
|
||||||
|
return (
|
||||||
|
<View style={styles.resizeModeControl}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={onPress}>
|
||||||
|
<Text style={style}>{_text}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
controlOption: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
fontSize: 11,
|
||||||
|
color: 'white',
|
||||||
|
paddingLeft: 2,
|
||||||
|
paddingRight: 2,
|
||||||
|
lineHeight: 12,
|
||||||
|
},
|
||||||
|
resizeModeControl: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ToggleControl;
|
@ -1,475 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
import React, {
|
|
||||||
Component
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Alert,
|
|
||||||
Platform,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
TouchableOpacity,
|
|
||||||
View,
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
import Video,{FilterType} from 'react-native-video';
|
|
||||||
|
|
||||||
const filterTypes = [
|
|
||||||
FilterType.NONE,
|
|
||||||
FilterType.INVERT,
|
|
||||||
FilterType.MONOCHROME,
|
|
||||||
FilterType.POSTERIZE,
|
|
||||||
FilterType.FALSE,
|
|
||||||
FilterType.MAXIMUMCOMPONENT,
|
|
||||||
FilterType.MINIMUMCOMPONENT,
|
|
||||||
FilterType.CHROME,
|
|
||||||
FilterType.FADE,
|
|
||||||
FilterType.INSTANT,
|
|
||||||
FilterType.MONO,
|
|
||||||
FilterType.NOIR,
|
|
||||||
FilterType.PROCESS,
|
|
||||||
FilterType.TONAL,
|
|
||||||
FilterType.TRANSFER,
|
|
||||||
FilterType.SEPIA
|
|
||||||
];
|
|
||||||
|
|
||||||
class VideoPlayer extends Component {
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.onLoad = this.onLoad.bind(this);
|
|
||||||
this.onProgress = this.onProgress.bind(this);
|
|
||||||
this.onBuffer = this.onBuffer.bind(this);
|
|
||||||
}
|
|
||||||
video = React.createRef();
|
|
||||||
|
|
||||||
state = {
|
|
||||||
rate: 1,
|
|
||||||
volume: 1,
|
|
||||||
muted: false,
|
|
||||||
resizeMode: 'contain',
|
|
||||||
duration: 0.0,
|
|
||||||
currentTime: 0.0,
|
|
||||||
controls: false,
|
|
||||||
paused: true,
|
|
||||||
skin: 'custom',
|
|
||||||
ignoreSilentSwitch: null,
|
|
||||||
mixWithOthers: null,
|
|
||||||
isBuffering: false,
|
|
||||||
filter: FilterType.NONE,
|
|
||||||
filterEnabled: true
|
|
||||||
};
|
|
||||||
|
|
||||||
onLoad(data: any) {
|
|
||||||
console.log('On load fired!');
|
|
||||||
this.setState({duration: data.duration});
|
|
||||||
}
|
|
||||||
|
|
||||||
onProgress(data: any) {
|
|
||||||
this.setState({currentTime: data.currentTime});
|
|
||||||
}
|
|
||||||
|
|
||||||
onBuffer({ isBuffering }: { isBuffering: boolean }) {
|
|
||||||
this.setState({ isBuffering });
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentTimePercentage() {
|
|
||||||
if (this.state.currentTime > 0 && this.state.duration !== 0) {
|
|
||||||
return this.state.currentTime / this.state.duration;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter(step: number) {
|
|
||||||
let index = filterTypes.indexOf(this.state.filter) + step;
|
|
||||||
|
|
||||||
if (index === filterTypes.length) {
|
|
||||||
index = 0;
|
|
||||||
} else if (index === -1) {
|
|
||||||
index = filterTypes.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
filter: filterTypes[index]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSkinControl(skin) {
|
|
||||||
const isSelected = this.state.skin == skin;
|
|
||||||
const selectControls = skin == 'native' || skin == 'embed';
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({
|
|
||||||
controls: selectControls,
|
|
||||||
skin: skin
|
|
||||||
}) }}>
|
|
||||||
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
|
|
||||||
{skin}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRateControl(rate: number) {
|
|
||||||
const isSelected = (this.state.rate == rate);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({rate: rate}) }}>
|
|
||||||
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
|
|
||||||
{rate}x
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderResizeModeControl(resizeMode: string) {
|
|
||||||
const isSelected = (this.state.resizeMode == resizeMode);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({resizeMode: resizeMode}) }}>
|
|
||||||
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
|
|
||||||
{resizeMode}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderVolumeControl(volume: number) {
|
|
||||||
const isSelected = (this.state.volume == volume);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({volume: volume}) }}>
|
|
||||||
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
|
|
||||||
{volume * 100}%
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderIgnoreSilentSwitchControl(ignoreSilentSwitch: string) {
|
|
||||||
const isSelected = (this.state.ignoreSilentSwitch == ignoreSilentSwitch);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({ignoreSilentSwitch: ignoreSilentSwitch}) }}>
|
|
||||||
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
|
|
||||||
{ignoreSilentSwitch}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderFullscreenControl(fullscreen: string) {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => {
|
|
||||||
if (fullscreen === 'fullscreen') {
|
|
||||||
this.video.presentFullscreenPlayer()
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Text style={[styles.controlOption]}>
|
|
||||||
{fullscreen}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderMixWithOthersControl(mixWithOthers: string) {
|
|
||||||
const isSelected = (this.state.mixWithOthers == mixWithOthers);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({mixWithOthers: mixWithOthers}) }}>
|
|
||||||
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
|
|
||||||
{mixWithOthers}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCustomSkin() {
|
|
||||||
const flexCompleted = this.getCurrentTimePercentage() * 100;
|
|
||||||
const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
<TouchableOpacity style={styles.fullScreen} onPress={() => {this.setState({paused: !this.state.paused})}}>
|
|
||||||
<Video
|
|
||||||
ref={(ref: Video) => {
|
|
||||||
this.video = ref
|
|
||||||
}}
|
|
||||||
source={require('./broadchurch.mp4')}
|
|
||||||
style={styles.fullScreen}
|
|
||||||
rate={this.state.rate}
|
|
||||||
paused={this.state.paused}
|
|
||||||
volume={this.state.volume}
|
|
||||||
muted={this.state.muted}
|
|
||||||
ignoreSilentSwitch={this.state.ignoreSilentSwitch}
|
|
||||||
mixWithOthers={this.state.mixWithOthers}
|
|
||||||
resizeMode={this.state.resizeMode}
|
|
||||||
onLoad={this.onLoad}
|
|
||||||
onBuffer={this.onBuffer}
|
|
||||||
onProgress={this.onProgress}
|
|
||||||
onEnd={() => { Alert.alert('Done!') }}
|
|
||||||
repeat={true}
|
|
||||||
filter={this.state.filter}
|
|
||||||
filterEnabled={this.state.filterEnabled}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
<View style={styles.controls}>
|
|
||||||
<View style={styles.generalControls}>
|
|
||||||
<View style={styles.skinControl}>
|
|
||||||
{this.renderSkinControl('custom')}
|
|
||||||
{this.renderSkinControl('native')}
|
|
||||||
{this.renderSkinControl('embed')}
|
|
||||||
</View>
|
|
||||||
{
|
|
||||||
(this.state.filterEnabled) ?
|
|
||||||
<View style={styles.skinControl}>
|
|
||||||
<TouchableOpacity onPress={() => {
|
|
||||||
this.setFilter(-1)
|
|
||||||
}}>
|
|
||||||
<Text style={styles.controlOption}>Previous Filter</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity onPress={() => {
|
|
||||||
this.setFilter(1)
|
|
||||||
}}>
|
|
||||||
<Text style={styles.controlOption}>Next Filter</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View> : null
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
<View style={styles.generalControls}>
|
|
||||||
<View style={styles.rateControl}>
|
|
||||||
{this.renderRateControl(0.5)}
|
|
||||||
{this.renderRateControl(1.0)}
|
|
||||||
{this.renderRateControl(2.0)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.volumeControl}>
|
|
||||||
{this.renderVolumeControl(0.5)}
|
|
||||||
{this.renderVolumeControl(1)}
|
|
||||||
{this.renderVolumeControl(1.5)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.resizeModeControl}>
|
|
||||||
{this.renderResizeModeControl('cover')}
|
|
||||||
{this.renderResizeModeControl('contain')}
|
|
||||||
{this.renderResizeModeControl('stretch')}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View style={styles.generalControls}>
|
|
||||||
{
|
|
||||||
(Platform.OS === 'ios') ?
|
|
||||||
<>
|
|
||||||
<View style={styles.ignoreSilentSwitchControl}>
|
|
||||||
{this.renderIgnoreSilentSwitchControl('ignore')}
|
|
||||||
{this.renderIgnoreSilentSwitchControl('obey')}
|
|
||||||
</View>
|
|
||||||
<View style={styles.mixWithOthersControl}>
|
|
||||||
{this.renderMixWithOthersControl('mix')}
|
|
||||||
{this.renderMixWithOthersControl('duck')}
|
|
||||||
</View>
|
|
||||||
<View style={styles.mixWithOthersControl}>
|
|
||||||
{this.renderFullscreenControl('fullscreen')}
|
|
||||||
</View>
|
|
||||||
</> : null
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.trackingControls}>
|
|
||||||
<View style={styles.progress}>
|
|
||||||
<View style={[styles.innerProgressCompleted, {flex: flexCompleted}]} />
|
|
||||||
<View style={[styles.innerProgressRemaining, {flex: flexRemaining}]} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderNativeSkin() {
|
|
||||||
const videoStyle = this.state.skin == 'embed' ? styles.nativeVideoControls : styles.fullScreen;
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
<View style={styles.fullScreen}>
|
|
||||||
<Video
|
|
||||||
source={require('./broadchurch.mp4')}
|
|
||||||
style={videoStyle}
|
|
||||||
rate={this.state.rate}
|
|
||||||
paused={this.state.paused}
|
|
||||||
volume={this.state.volume}
|
|
||||||
muted={this.state.muted}
|
|
||||||
ignoreSilentSwitch={this.state.ignoreSilentSwitch}
|
|
||||||
mixWithOthers={this.state.mixWithOthers}
|
|
||||||
resizeMode={this.state.resizeMode}
|
|
||||||
onLoad={this.onLoad}
|
|
||||||
onBuffer={this.onBuffer}
|
|
||||||
onProgress={this.onProgress}
|
|
||||||
onEnd={() => { Alert.alert('Done!') }}
|
|
||||||
repeat={true}
|
|
||||||
controls={this.state.controls}
|
|
||||||
filter={this.state.filter}
|
|
||||||
filterEnabled={this.state.filterEnabled}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View style={styles.controls}>
|
|
||||||
<View style={styles.generalControls}>
|
|
||||||
<View style={styles.skinControl}>
|
|
||||||
{this.renderSkinControl('custom')}
|
|
||||||
{this.renderSkinControl('native')}
|
|
||||||
{this.renderSkinControl('embed')}
|
|
||||||
</View>
|
|
||||||
{
|
|
||||||
(this.state.filterEnabled) ?
|
|
||||||
<View style={styles.skinControl}>
|
|
||||||
<TouchableOpacity onPress={() => {
|
|
||||||
this.setFilter(-1)
|
|
||||||
}}>
|
|
||||||
<Text style={styles.controlOption}>Previous Filter</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity onPress={() => {
|
|
||||||
this.setFilter(1)
|
|
||||||
}}>
|
|
||||||
<Text style={styles.controlOption}>Next Filter</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View> : null
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
<View style={styles.generalControls}>
|
|
||||||
<View style={styles.rateControl}>
|
|
||||||
{this.renderRateControl(0.5)}
|
|
||||||
{this.renderRateControl(1.0)}
|
|
||||||
{this.renderRateControl(2.0)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.volumeControl}>
|
|
||||||
{this.renderVolumeControl(0.5)}
|
|
||||||
{this.renderVolumeControl(1)}
|
|
||||||
{this.renderVolumeControl(1.5)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.resizeModeControl}>
|
|
||||||
{this.renderResizeModeControl('cover')}
|
|
||||||
{this.renderResizeModeControl('contain')}
|
|
||||||
{this.renderResizeModeControl('stretch')}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View style={styles.generalControls}>
|
|
||||||
{
|
|
||||||
(Platform.OS === 'ios') ?
|
|
||||||
<>
|
|
||||||
<View style={styles.ignoreSilentSwitchControl}>
|
|
||||||
{this.renderIgnoreSilentSwitchControl('ignore')}
|
|
||||||
{this.renderIgnoreSilentSwitchControl('obey')}
|
|
||||||
</View>
|
|
||||||
<View style={styles.mixWithOthersControl}>
|
|
||||||
{this.renderMixWithOthersControl('mix')}
|
|
||||||
{this.renderMixWithOthersControl('duck')}
|
|
||||||
</View>
|
|
||||||
</> : null
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return this.state.controls ? this.renderNativeSkin() : this.renderCustomSkin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: 'black',
|
|
||||||
},
|
|
||||||
fullScreen: {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
bottom: 0,
|
|
||||||
right: 0,
|
|
||||||
},
|
|
||||||
controls: {
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
borderRadius: 5,
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 44,
|
|
||||||
left: 4,
|
|
||||||
right: 4,
|
|
||||||
},
|
|
||||||
progress: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
borderRadius: 3,
|
|
||||||
overflow: 'hidden',
|
|
||||||
},
|
|
||||||
innerProgressCompleted: {
|
|
||||||
height: 20,
|
|
||||||
backgroundColor: '#cccccc',
|
|
||||||
},
|
|
||||||
innerProgressRemaining: {
|
|
||||||
height: 20,
|
|
||||||
backgroundColor: '#2C2C2C',
|
|
||||||
},
|
|
||||||
generalControls: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
overflow: 'hidden',
|
|
||||||
paddingBottom: 10,
|
|
||||||
},
|
|
||||||
skinControl: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
rateControl: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
volumeControl: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
resizeModeControl: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
ignoreSilentSwitchControl: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
mixWithOthersControl: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
controlOption: {
|
|
||||||
alignSelf: 'center',
|
|
||||||
fontSize: 11,
|
|
||||||
color: "white",
|
|
||||||
paddingLeft: 2,
|
|
||||||
paddingRight: 2,
|
|
||||||
lineHeight: 12,
|
|
||||||
},
|
|
||||||
nativeVideoControls: {
|
|
||||||
top: 184,
|
|
||||||
height: 300,
|
|
||||||
},
|
|
||||||
trackingControls: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
export default VideoPlayer
|
|
@ -1,8 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React, {
|
import React, {Component} from 'react';
|
||||||
Component
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
@ -12,14 +10,18 @@ import {
|
|||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
PanResponder,
|
PanResponder,
|
||||||
ToastAndroid,
|
ToastAndroid,
|
||||||
|
Platform,
|
||||||
|
PanResponderInstance,
|
||||||
|
Alert,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
|
||||||
import { Picker } from '@react-native-picker/picker'
|
import {Picker} from '@react-native-picker/picker';
|
||||||
|
|
||||||
import Video, { VideoDecoderProperties, TextTrackType } from 'react-native-video';
|
import Video, {VideoDecoderProperties} from 'react-native-video';
|
||||||
|
import ToggleControl from './ToggleControl';
|
||||||
|
import MultiValueControl from './MultiValueControl';
|
||||||
|
|
||||||
class VideoPlayer extends Component {
|
class VideoPlayer extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
rate: 1,
|
rate: 1,
|
||||||
volume: 1,
|
volume: 1,
|
||||||
@ -46,10 +48,38 @@ class VideoPlayer extends Component {
|
|||||||
showRNVControls: false,
|
showRNVControls: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
seekerWidth = 0
|
seekerWidth = 0;
|
||||||
|
|
||||||
srcList = [
|
srcAllPlatformList = [
|
||||||
require('./broadchurch.mp4'),
|
require('./broadchurch.mp4'),
|
||||||
|
{
|
||||||
|
description: '(hls|live) red bull tv',
|
||||||
|
uri: 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'invalid URL',
|
||||||
|
uri: 'mmt://www.youtube.com',
|
||||||
|
type: 'mpd',
|
||||||
|
},
|
||||||
|
{description: '(no url) Stopped playback', uri: undefined},
|
||||||
|
{
|
||||||
|
description: '(no view) no View',
|
||||||
|
noView: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Another live sample',
|
||||||
|
uri: 'https://live.forstreet.cl/live/livestream.m3u8',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
srcIosList = [
|
||||||
|
]
|
||||||
|
|
||||||
|
srcAndroidList = [
|
||||||
|
{
|
||||||
|
description: 'Another live sample',
|
||||||
|
uri: 'https://live.forstreet.cl/live/livestream.m3u8',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: '(dash) sintel subtitles',
|
description: '(dash) sintel subtitles',
|
||||||
uri: 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd',
|
uri: 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd',
|
||||||
@ -58,31 +88,26 @@ class VideoPlayer extends Component {
|
|||||||
description: '(mp4) big buck bunny',
|
description: '(mp4) big buck bunny',
|
||||||
uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4',
|
uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: '(hls|live) red bull tv',
|
|
||||||
uri: 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: '(mp4|subtitles) demo with sintel Subtitles',
|
description: '(mp4|subtitles) demo with sintel Subtitles',
|
||||||
uri:
|
uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0',
|
||||||
'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0',
|
|
||||||
type: 'mpd',
|
type: 'mpd',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'invalid URL',
|
description: '(mp4) big buck bunny With Ads',
|
||||||
uri:
|
adTagUrl:
|
||||||
'mmt://www.youtube.com',
|
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
|
||||||
type: 'mpd',
|
uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4',
|
||||||
},
|
},
|
||||||
{ description: '(no url) Stopped playback', uri: undefined },
|
];
|
||||||
{
|
|
||||||
description: '(no view) no View',
|
|
||||||
noView: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
video: Video;
|
|
||||||
seekPanResponder: PanResponder | undefined;
|
srcList = this.srcAllPlatformList.concat(
|
||||||
|
Platform.OS === 'android' ? this.srcAndroidList : this.srcIosList,
|
||||||
|
);
|
||||||
|
|
||||||
|
video?: Video;
|
||||||
|
seekPanResponder?: PanResponderInstance;
|
||||||
|
|
||||||
popupInfo = () => {
|
popupInfo = () => {
|
||||||
VideoDecoderProperties.getWidevineLevel().then((widevineLevel: number) => {
|
VideoDecoderProperties.getWidevineLevel().then((widevineLevel: number) => {
|
||||||
@ -105,52 +130,49 @@ class VideoPlayer extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onLoad = (data: any) => {
|
onLoad = (data: any) => {
|
||||||
this.setState({ duration: data.duration, loading: false, });
|
this.setState({duration: data.duration, loading: false});
|
||||||
this.onAudioTracks(data)
|
this.onAudioTracks(data);
|
||||||
this.onTextTracks(data)
|
this.onTextTracks(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
onProgress = (data: any) => {
|
onProgress = (data: any) => {
|
||||||
if (!this.state.seeking) {
|
if (!this.state.seeking) {
|
||||||
const position = this.calculateSeekerPosition()
|
const position = this.calculateSeekerPosition();
|
||||||
this.setSeekerPosition(position)
|
this.setSeekerPosition(position);
|
||||||
}
|
}
|
||||||
this.setState({ currentTime: data.currentTime })
|
this.setState({currentTime: data.currentTime});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
onVideoLoadStart = () => {
|
onVideoLoadStart = () => {
|
||||||
console.log('onVideoLoadStart')
|
console.log('onVideoLoadStart');
|
||||||
this.setState({ isLoading: true })
|
this.setState({isLoading: true});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
onAudioTracks = (data: any) => {
|
onAudioTracks = (data: any) => {
|
||||||
const selectedTrack = data.audioTracks?.find((x: any) => {
|
const selectedTrack = data.audioTracks?.find((x: any) => {
|
||||||
return x.selected
|
return x.selected;
|
||||||
})
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
audioTracks: data.audioTracks,
|
audioTracks: data.audioTracks,
|
||||||
})
|
});
|
||||||
if (selectedTrack?.language) {
|
if (selectedTrack?.language) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedAudioTrack: {
|
selectedAudioTrack: {
|
||||||
type: 'language',
|
type: 'language',
|
||||||
value: selectedTrack?.language,
|
value: selectedTrack?.language,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onTextTracks = (data: any) => {
|
onTextTracks = (data: any) => {
|
||||||
const selectedTrack = data.textTracks?.find((x: any) => {
|
const selectedTrack = data.textTracks?.find((x: any) => {
|
||||||
return x.selected
|
return x.selected;
|
||||||
})
|
});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
textTracks: data.textTracks,
|
textTracks: data.textTracks,
|
||||||
})
|
});
|
||||||
if (selectedTrack?.language) {
|
if (selectedTrack?.language) {
|
||||||
this.setState({
|
this.setState({
|
||||||
textTracks: data,
|
textTracks: data,
|
||||||
@ -158,38 +180,34 @@ class VideoPlayer extends Component {
|
|||||||
type: 'language',
|
type: 'language',
|
||||||
value: selectedTrack?.language,
|
value: selectedTrack?.language,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onAspectRatio = (data: any) => {
|
onAspectRatio = (data: any) => {
|
||||||
console.log('onAspectRadio called ' + JSON.stringify(data))
|
console.log('onAspectRadio called ' + JSON.stringify(data));
|
||||||
this.setState({
|
this.setState({
|
||||||
videoWidth: data.width,
|
videoWidth: data.width,
|
||||||
videoHeight: data.height,
|
videoHeight: data.height,
|
||||||
})
|
});
|
||||||
}
|
|
||||||
|
|
||||||
onVideoBuffer = (param: any) => {
|
|
||||||
console.log('onVideoBuffer')
|
|
||||||
|
|
||||||
this.setState({ isLoading: param.isBuffering })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onReadyForDisplay = () => {
|
|
||||||
console.log('onReadyForDisplay')
|
|
||||||
|
|
||||||
this.setState({ isLoading: false })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onAudioBecomingNoisy = () => {
|
|
||||||
this.setState({ paused: true })
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onAudioFocusChanged = (event: { hasAudioFocus: boolean }) => {
|
onVideoBuffer = (param: any) => {
|
||||||
this.setState({ paused: !event.hasAudioFocus })
|
console.log('onVideoBuffer');
|
||||||
|
this.setState({isLoading: param.isBuffering});
|
||||||
|
};
|
||||||
|
|
||||||
|
onReadyForDisplay = () => {
|
||||||
|
console.log('onReadyForDisplay');
|
||||||
|
this.setState({isLoading: false});
|
||||||
|
};
|
||||||
|
|
||||||
|
onAudioBecomingNoisy = () => {
|
||||||
|
this.setState({paused: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
onAudioFocusChanged = (event: {hasAudioFocus: boolean}) => {
|
||||||
|
this.setState({paused: !event.hasAudioFocus});
|
||||||
};
|
};
|
||||||
|
|
||||||
getCurrentTimePercentage = () => {
|
getCurrentTimePercentage = () => {
|
||||||
@ -199,80 +217,44 @@ class VideoPlayer extends Component {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
renderRateControl(rate: number) {
|
|
||||||
const isSelected = (this.state.rate === rate);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({ rate }) }}>
|
|
||||||
<Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
|
|
||||||
{rate}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderResizeModeControl(resizeMode: string) {
|
|
||||||
const isSelected = (this.state.resizeMode === resizeMode);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({ resizeMode }) }}>
|
|
||||||
<Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
|
|
||||||
{resizeMode}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderVolumeControl(volume: number) {
|
|
||||||
const isSelected = (this.state.volume === volume);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity onPress={() => { this.setState({ volume }) }}>
|
|
||||||
<Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
|
|
||||||
{volume * 100}%
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toast = (visible: boolean, message: string) => {
|
toast = (visible: boolean, message: string) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
ToastAndroid.showWithGravityAndOffset(
|
ToastAndroid.showWithGravityAndOffset(
|
||||||
message,
|
message,
|
||||||
ToastAndroid.LONG,
|
ToastAndroid.LONG,
|
||||||
ToastAndroid.BOTTOM,
|
ToastAndroid.BOTTOM,
|
||||||
25,
|
25,
|
||||||
50,
|
50,
|
||||||
)
|
);
|
||||||
return null
|
} else {
|
||||||
|
Alert.alert(message, message);
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onError = (err: any) => {
|
|
||||||
console.log(JSON.stringify(err?.error.errorCode))
|
|
||||||
this.toast(true, 'error: ' + err?.error.errorCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
onEnd = () => {
|
|
||||||
this.channelUp()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onError = (err: any) => {
|
||||||
|
console.log(JSON.stringify(err?.error.errorCode));
|
||||||
|
this.toast(true, 'error: ' + err?.error.errorCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
onEnd = () => {
|
||||||
|
this.channelUp();
|
||||||
|
};
|
||||||
|
|
||||||
toggleFullscreen() {
|
toggleFullscreen() {
|
||||||
this.setState({ fullscreen: !this.state.fullscreen })
|
this.setState({fullscreen: !this.state.fullscreen});
|
||||||
}
|
}
|
||||||
toggleControls() {
|
toggleControls() {
|
||||||
this.setState({ showRNVControls: !this.state.showRNVControls })
|
this.setState({showRNVControls: !this.state.showRNVControls});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDecoration() {
|
toggleDecoration() {
|
||||||
this.setState({ decoration: !this.state.decoration })
|
this.setState({decoration: !this.state.decoration});
|
||||||
if (this.state.decoration) {
|
if (this.state.decoration) {
|
||||||
this.video.dismissFullscreenPlayer()
|
this.video?.dismissFullscreenPlayer();
|
||||||
} else {
|
} else {
|
||||||
this.video.presentFullscreenPlayer()
|
this.video?.presentFullscreenPlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,115 +270,23 @@ class VideoPlayer extends Component {
|
|||||||
textTracks: [],
|
textTracks: [],
|
||||||
selectedAudioTrack: undefined,
|
selectedAudioTrack: undefined,
|
||||||
selectedTextTrack: undefined,
|
selectedTextTrack: undefined,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
channelUp() {
|
channelUp() {
|
||||||
console.log('channel up')
|
console.log('channel up');
|
||||||
this.goToChannel((this.state.srcListId + 1) % this.srcList.length)
|
this.goToChannel((this.state.srcListId + 1) % this.srcList.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
channelDown() {
|
channelDown() {
|
||||||
console.log('channel down')
|
console.log('channel down');
|
||||||
this.goToChannel((this.state.srcListId + this.srcList.length - 1) % this.srcList.length)
|
this.goToChannel(
|
||||||
|
(this.state.srcListId + this.srcList.length - 1) % this.srcList.length,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.initSeekPanResponder()
|
this.initSeekPanResponder();
|
||||||
}
|
|
||||||
|
|
||||||
renderDecorationsControl() {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.toggleDecoration()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.controlOption]}>{'decoration'}</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderInfoControl() {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.popupInfo()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.controlOption]}>{'decoderInfo'}</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderFullScreenControl() {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.toggleFullscreen()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.controlOption]}>{'fullscreen'}</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPause() {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.setState({ paused: !this.state.paused })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.controlOption]}>
|
|
||||||
{this.state.paused ? 'pause' : 'playing'}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRepeatModeControl() {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.setState({ loop: !this.state.loop })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.controlOption]}>
|
|
||||||
{this.state.loop ? 'loop enable' : 'loop disable'}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLeftControl() {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.channelDown()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.leftRightControlOption]}>{'ChDown'}</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
// onTimelineUpdated
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRightControl() {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => {
|
|
||||||
this.channelUp()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={[styles.leftRightControlOption]}>{'ChUp'}</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -413,11 +303,11 @@ class VideoPlayer extends Component {
|
|||||||
*/
|
*/
|
||||||
constrainToSeekerMinMax(val = 0) {
|
constrainToSeekerMinMax(val = 0) {
|
||||||
if (val <= 0) {
|
if (val <= 0) {
|
||||||
return 0
|
return 0;
|
||||||
} else if (val >= this.seekerWidth) {
|
} else if (val >= this.seekerWidth) {
|
||||||
return this.seekerWidth
|
return this.seekerWidth;
|
||||||
}
|
}
|
||||||
return val
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -428,17 +318,17 @@ class VideoPlayer extends Component {
|
|||||||
* @param {float} position position in px of seeker handle}
|
* @param {float} position position in px of seeker handle}
|
||||||
*/
|
*/
|
||||||
setSeekerPosition(position = 0) {
|
setSeekerPosition(position = 0) {
|
||||||
const state = this.state
|
const state = this.state;
|
||||||
position = this.constrainToSeekerMinMax(position)
|
position = this.constrainToSeekerMinMax(position);
|
||||||
|
|
||||||
state.seekerFillWidth = position
|
state.seekerFillWidth = position;
|
||||||
state.seekerPosition = position
|
state.seekerPosition = position;
|
||||||
|
|
||||||
if (!state.seeking) {
|
if (!state.seeking) {
|
||||||
state.seekerOffset = position
|
state.seekerOffset = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(state)
|
this.setState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -448,8 +338,8 @@ class VideoPlayer extends Component {
|
|||||||
* @return {float} position of seeker handle in px based on currentTime
|
* @return {float} position of seeker handle in px based on currentTime
|
||||||
*/
|
*/
|
||||||
calculateSeekerPosition() {
|
calculateSeekerPosition() {
|
||||||
const percent = this.state.currentTime / this.state.duration
|
const percent = this.state.currentTime / this.state.duration;
|
||||||
return this.seekerWidth * percent
|
return this.seekerWidth * percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -459,8 +349,8 @@ class VideoPlayer extends Component {
|
|||||||
* @return {float} time in ms based on seekerPosition.
|
* @return {float} time in ms based on seekerPosition.
|
||||||
*/
|
*/
|
||||||
calculateTimeFromSeekerPosition() {
|
calculateTimeFromSeekerPosition() {
|
||||||
const percent = this.state.seekerPosition / this.seekerWidth
|
const percent = this.state.seekerPosition / this.seekerWidth;
|
||||||
return this.state.duration * percent
|
return this.state.duration * percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -469,29 +359,29 @@ class VideoPlayer extends Component {
|
|||||||
initSeekPanResponder() {
|
initSeekPanResponder() {
|
||||||
this.seekPanResponder = PanResponder.create({
|
this.seekPanResponder = PanResponder.create({
|
||||||
// Ask to be the responder.
|
// Ask to be the responder.
|
||||||
onStartShouldSetPanResponder: (evt, gestureState) => true,
|
onStartShouldSetPanResponder: (_evt, _gestureState) => true,
|
||||||
onMoveShouldSetPanResponder: (evt, gestureState) => true,
|
onMoveShouldSetPanResponder: (_evt, _gestureState) => true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When we start the pan tell the machine that we're
|
* When we start the pan tell the machine that we're
|
||||||
* seeking. This stops it from updating the seekbar
|
* seeking. This stops it from updating the seekbar
|
||||||
* position in the onProgress listener.
|
* position in the onProgress listener.
|
||||||
*/
|
*/
|
||||||
onPanResponderGrant: (evt, gestureState) => {
|
onPanResponderGrant: (evt, _gestureState) => {
|
||||||
const state = this.state
|
const state = this.state;
|
||||||
// this.clearControlTimeout()
|
// this.clearControlTimeout()
|
||||||
const position = evt.nativeEvent.locationX
|
const position = evt.nativeEvent.locationX;
|
||||||
this.setSeekerPosition(position)
|
this.setSeekerPosition(position);
|
||||||
state.seeking = true
|
state.seeking = true;
|
||||||
this.setState(state)
|
this.setState(state);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When panning, update the seekbar position, duh.
|
* When panning, update the seekbar position, duh.
|
||||||
*/
|
*/
|
||||||
onPanResponderMove: (evt, gestureState) => {
|
onPanResponderMove: (evt, gestureState) => {
|
||||||
const position = this.state.seekerOffset + gestureState.dx
|
const position = this.state.seekerOffset + gestureState.dx;
|
||||||
this.setSeekerPosition(position)
|
this.setSeekerPosition(position);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -499,140 +389,193 @@ class VideoPlayer extends Component {
|
|||||||
* If you seek to the end of the video we fire the
|
* If you seek to the end of the video we fire the
|
||||||
* onEnd callback
|
* onEnd callback
|
||||||
*/
|
*/
|
||||||
onPanResponderRelease: (evt, gestureState) => {
|
onPanResponderRelease: (_evt, _gestureState) => {
|
||||||
const time = this.calculateTimeFromSeekerPosition()
|
const time = this.calculateTimeFromSeekerPosition();
|
||||||
const state = this.state
|
const state = this.state;
|
||||||
if (time >= state.duration && !state.isLoading) {
|
if (time >= state.duration && !state.isLoading) {
|
||||||
state.paused = true
|
state.paused = true;
|
||||||
this.onEnd()
|
this.onEnd();
|
||||||
} else {
|
} else {
|
||||||
this.video?.seek(time)
|
this.video?.seek(time);
|
||||||
state.seeking = false
|
state.seeking = false;
|
||||||
}
|
}
|
||||||
this.setState(state)
|
this.setState(state);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSeekBar() {
|
renderSeekBar() {
|
||||||
if (!this.seekPanResponder) {
|
if (!this.seekPanResponder) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
const seekerStyle = [
|
||||||
|
styles.seekbarFill,
|
||||||
|
{
|
||||||
|
width: this.state.seekerFillWidth > 0 ? this.state.seekerFillWidth : 0,
|
||||||
|
backgroundColor: '#FFF',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const seekerPositionStyle = [
|
||||||
|
styles.seekbarHandle,
|
||||||
|
{
|
||||||
|
left: this.state.seekerPosition > 0 ? this.state.seekerPosition : 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const seekerPointerStyle = [
|
||||||
|
styles.seekbarCircle,
|
||||||
|
{backgroundColor: '#FFF'},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={styles.seekbarContainer}
|
style={styles.seekbarContainer}
|
||||||
{...this.seekPanResponder.panHandlers}
|
{...this.seekPanResponder.panHandlers}
|
||||||
{...styles.generalControls}
|
{...styles.generalControls}>
|
||||||
>
|
|
||||||
<View
|
<View
|
||||||
style={styles.seekbarTrack}
|
style={styles.seekbarTrack}
|
||||||
onLayout={(event) => (this.seekerWidth = event.nativeEvent.layout.width)}
|
onLayout={event =>
|
||||||
pointerEvents={'none'}
|
(this.seekerWidth = event.nativeEvent.layout.width)
|
||||||
>
|
}
|
||||||
<View
|
pointerEvents={'none'}>
|
||||||
style={[
|
<View style={seekerStyle} pointerEvents={'none'} />
|
||||||
styles.seekbarFill,
|
|
||||||
{
|
|
||||||
width:
|
|
||||||
this.state.seekerFillWidth > 0 ? this.state.seekerFillWidth : 0,
|
|
||||||
backgroundColor: '#FFF',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
pointerEvents={'none'}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
<View
|
<View style={seekerPositionStyle} pointerEvents={'none'}>
|
||||||
style={[
|
<View style={seekerPointerStyle} pointerEvents={'none'} />
|
||||||
styles.seekbarHandle,
|
|
||||||
{ left: this.state.seekerPosition > 0 ? this.state.seekerPosition : 0 },
|
|
||||||
]}
|
|
||||||
pointerEvents={'none'}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.seekbarCircle,
|
|
||||||
{ backgroundColor: '#FFF' },
|
|
||||||
]}
|
|
||||||
pointerEvents={'none'}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
IndicatorLoadingView() {
|
IndicatorLoadingView() {
|
||||||
if (this.state.isLoading)
|
if (this.state.isLoading) {
|
||||||
return <ActivityIndicator color="#3235fd" size="large" style={styles.IndicatorStyle} />
|
return (
|
||||||
else return <View />
|
<ActivityIndicator
|
||||||
|
color="#3235fd"
|
||||||
|
size="large"
|
||||||
|
style={styles.IndicatorStyle}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <View />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTopControl() {
|
renderTopControl() {
|
||||||
return (<>
|
return (
|
||||||
|
<>
|
||||||
<Text style={[styles.controlOption]}>
|
<Text style={[styles.controlOption]}>
|
||||||
{this.srcList[this.state.srcListId]?.description || 'local file'}
|
{this.srcList[this.state.srcListId]?.description || 'local file'}
|
||||||
</Text>
|
</Text>
|
||||||
<View >
|
<View>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
this.toggleControls()
|
this.toggleControls();
|
||||||
}}
|
}}>
|
||||||
>
|
<Text style={[styles.leftRightControlOption]}>
|
||||||
<Text style={[styles.leftRightControlOption]}>{this.state.showRNVControls ? 'Hide controls' : 'Show controls'}</Text>
|
{this.state.showRNVControls ? 'Hide controls' : 'Show controls'}
|
||||||
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</>)
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRateSelected = (value: string | number) => {
|
||||||
|
this.setState({rate: value});
|
||||||
|
}
|
||||||
|
onVolumeSelected = (value: string | number) => {
|
||||||
|
this.setState({volume: value});
|
||||||
|
}
|
||||||
|
onResizeModeSelected = (value: string | number) => {
|
||||||
|
this.setState({resizeMode: value});
|
||||||
|
}
|
||||||
|
|
||||||
renderOverlay() {
|
renderOverlay() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{this.IndicatorLoadingView()}
|
{this.IndicatorLoadingView()}
|
||||||
<View style={styles.topControls}>
|
<View style={styles.topControls}>
|
||||||
<View style={styles.resizeModeControl}>{this.renderTopControl()}</View>
|
<View style={styles.resizeModeControl}>
|
||||||
|
{this.renderTopControl()}
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{!this.state.showRNVControls ? (
|
{!this.state.showRNVControls ? (
|
||||||
<>
|
<>
|
||||||
<View style={styles.leftControls}>
|
<View style={styles.leftControls}>
|
||||||
<View style={styles.resizeModeControl}>{this.renderLeftControl()}</View>
|
<ToggleControl
|
||||||
</View><View style={styles.rightControls}>
|
onPress={() => {
|
||||||
<View style={styles.resizeModeControl}>{this.renderRightControl()}</View>
|
this.channelDown();
|
||||||
</View><View style={styles.bottomControls}>
|
}}
|
||||||
|
text='ChDown'
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.rightControls}>
|
||||||
|
<ToggleControl
|
||||||
|
onPress={() => {
|
||||||
|
this.channelUp();
|
||||||
|
}}
|
||||||
|
text='ChUp'
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.bottomControls}>
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
|
{Platform.OS === 'android' ? (
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
<View style={styles.resizeModeControl}>{this.renderInfoControl()}</View>
|
<ToggleControl
|
||||||
</View>
|
onPress={() => {
|
||||||
<View style={styles.resizeModeControl}>{this.renderPause()}</View>
|
this.popupInfo();
|
||||||
<View style={styles.resizeModeControl}>
|
}}
|
||||||
{this.renderRepeatModeControl()}
|
text='decoderInfo'
|
||||||
</View>
|
/>
|
||||||
<View style={styles.resizeModeControl}>
|
|
||||||
{this.renderFullScreenControl()}
|
|
||||||
</View>
|
|
||||||
<View style={styles.resizeModeControl}>
|
|
||||||
{this.renderDecorationsControl()}
|
|
||||||
</View>
|
</View>
|
||||||
|
) : null}
|
||||||
|
<ToggleControl
|
||||||
|
isSelected={this.state.paused}
|
||||||
|
onPress={() => {
|
||||||
|
this.setState({paused: !this.state.paused});
|
||||||
|
}}
|
||||||
|
selectedText='pause'
|
||||||
|
unselectedText='playing'
|
||||||
|
/>
|
||||||
|
<ToggleControl
|
||||||
|
isSelected={this.state.loop}
|
||||||
|
onPress={() => {
|
||||||
|
this.setState({loop: !this.state.loop});
|
||||||
|
}}
|
||||||
|
selectedText='loop enable'
|
||||||
|
unselectedText='loop disable'
|
||||||
|
/>
|
||||||
|
<ToggleControl
|
||||||
|
onPress={() => {
|
||||||
|
this.toggleFullscreen();
|
||||||
|
}}
|
||||||
|
text='fullscreen'
|
||||||
|
/>
|
||||||
|
<ToggleControl
|
||||||
|
onPress={() => {
|
||||||
|
this.toggleDecoration();
|
||||||
|
}}
|
||||||
|
text='decoration'
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
<View style={styles.rateControl}>
|
<MultiValueControl
|
||||||
{this.renderRateControl(0.25)}
|
values={[0.25, 0.5, 1.0, 1.5, 2.0]}
|
||||||
{this.renderRateControl(0.5)}
|
onPress={this.onRateSelected}
|
||||||
{this.renderRateControl(1.0)}
|
selected={this.state.rate}
|
||||||
{this.renderRateControl(1.5)}
|
/>
|
||||||
{this.renderRateControl(2.0)}
|
<MultiValueControl
|
||||||
</View>
|
values={[0.5, 1, 1.5]}
|
||||||
|
onPress={this.onVolumeSelected}
|
||||||
<View style={styles.volumeControl}>
|
selected={this.state.volume}
|
||||||
{this.renderVolumeControl(0.5)}
|
/>
|
||||||
{this.renderVolumeControl(1)}
|
<MultiValueControl
|
||||||
{this.renderVolumeControl(1.5)}
|
values={['cover', 'contain', 'stretch']}
|
||||||
</View>
|
onPress={this.onResizeModeSelected}
|
||||||
|
selected={this.state.resizeMode}
|
||||||
<View style={styles.resizeModeControl}>
|
/>
|
||||||
{this.renderResizeModeControl('cover')}
|
|
||||||
{this.renderResizeModeControl('contain')}
|
|
||||||
{this.renderResizeModeControl('stretch')}
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
{this.renderSeekBar()}
|
{this.renderSeekBar()}
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
@ -651,14 +594,14 @@ class VideoPlayer extends Component {
|
|||||||
value: itemValue,
|
value: itemValue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}>
|
||||||
>
|
{this.state.audioTracks.map(track => {
|
||||||
{this.state.audioTracks.map((track) => {
|
|
||||||
return (
|
return (
|
||||||
<Picker.Item
|
<Picker.Item
|
||||||
label={track.language}
|
label={track.language}
|
||||||
value={track.language}
|
value={track.language}
|
||||||
key={track.language} />
|
key={track.language}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Picker>
|
</Picker>
|
||||||
@ -678,35 +621,38 @@ class VideoPlayer extends Component {
|
|||||||
value: itemValue,
|
value: itemValue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
<Picker.Item label={'none'} value={'none'} key={'none'} />
|
<Picker.Item label={'none'} value={'none'} key={'none'} />
|
||||||
{this.state.textTracks.map((track) => (
|
{this.state.textTracks.map(track => (
|
||||||
<Picker.Item
|
<Picker.Item
|
||||||
label={track.language}
|
label={track.language}
|
||||||
value={track.language}
|
value={track.language}
|
||||||
key={track.language} />
|
key={track.language}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Picker>
|
</Picker>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View></>
|
</View>
|
||||||
) : null
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
)
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderVideoView() {
|
renderVideoView() {
|
||||||
const viewStyle = this.state.fullscreen ? styles.fullScreen : styles.halfScreen
|
const viewStyle = this.state.fullscreen
|
||||||
|
? styles.fullScreen
|
||||||
|
: styles.halfScreen;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity style={viewStyle}>
|
<TouchableOpacity style={viewStyle}>
|
||||||
<Video
|
<Video
|
||||||
ref={(ref: Video) => {
|
ref={(ref: Video) => {
|
||||||
this.video = ref
|
this.video = ref;
|
||||||
}}
|
}}
|
||||||
source={this.srcList[this.state.srcListId]}
|
source={this.srcList[this.state.srcListId]}
|
||||||
|
//adTagUrl={this.srcList[this.state.srcListId]?.adTagUrl}
|
||||||
style={viewStyle}
|
style={viewStyle}
|
||||||
rate={this.state.rate}
|
rate={this.state.rate}
|
||||||
paused={this.state.paused}
|
paused={this.state.paused}
|
||||||
@ -734,21 +680,21 @@ class VideoPlayer extends Component {
|
|||||||
playInBackground={false}
|
playInBackground={false}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{this.srcList[this.state.srcListId]?.noView ? null : this.renderVideoView()}
|
{this.srcList[this.state.srcListId]?.noView
|
||||||
|
? null
|
||||||
|
: this.renderVideoView()}
|
||||||
{this.renderOverlay()}
|
{this.renderOverlay()}
|
||||||
</View>
|
</View>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@ -888,4 +834,4 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default VideoPlayer
|
export default VideoPlayer;
|
Loading…
Reference in New Issue
Block a user