diff --git a/examples/basic/ios/Podfile.lock b/examples/basic/ios/Podfile.lock index cb4b91ef..89b3029e 100644 --- a/examples/basic/ios/Podfile.lock +++ b/examples/basic/ios/Podfile.lock @@ -75,9 +75,9 @@ PODS: - hermes-engine/Pre-built (0.72.5) - libevent (2.1.12) - OpenSSL-Universal (1.1.1100) - - PromisesObjC (2.3.1) - - PromisesSwift (2.3.1): - - PromisesObjC (= 2.3.1) + - PromisesObjC (2.2.0) + - PromisesSwift (2.2.0): + - PromisesObjC (= 2.2.0) - RCT-Folly (2021.07.22.00): - boost - DoubleConversion @@ -691,8 +691,8 @@ SPEC CHECKSUMS: hermes-engine: f6cf92a471053245614d9d8097736f6337d5b86c libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 - PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 + PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef + PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959 RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: df81ab637d35fac9e6eb94611cfd20f0feb05455 RCTTypeSafety: 4636e4a36c7c2df332bda6d59b19b41c443d4287 @@ -733,4 +733,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 6899e375fcfa0d3a42aa6cb55266008b8f7419cb -COCOAPODS: 1.13.0 +COCOAPODS: 1.12.1 diff --git a/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj b/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj index f7a31159..d33eb0db 100644 --- a/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj +++ b/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj @@ -525,7 +525,7 @@ "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = videoplayer; + PRODUCT_NAME = videoplayer; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; @@ -602,10 +602,7 @@ ); OTHER_LDFLAGS = ( "$(inherited)", - "-Wl", - "-ld_classic", " ", - "-Wl -ld_classic ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -678,10 +675,7 @@ ); OTHER_LDFLAGS = ( "$(inherited)", - "-Wl", - "-ld_classic", " ", - "-Wl -ld_classic ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/examples/basic/ios/videoplayer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/basic/ios/videoplayer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/examples/basic/ios/videoplayer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/examples/basic/src/MultiValueControl.tsx b/examples/basic/src/MultiValueControl.tsx new file mode 100644 index 00000000..522f55eb --- /dev/null +++ b/examples/basic/src/MultiValueControl.tsx @@ -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 + // 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 + {values.map((value: string | number) => { + const _style = value === selected ? selectedStyle : unselectedStyle + return ( + { + onPress?.(value) + }}> + {value} + ) + })} + +} + +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; diff --git a/examples/basic/src/ToggleControl.tsx b/examples/basic/src/ToggleControl.tsx new file mode 100644 index 00000000..65b30c72 --- /dev/null +++ b/examples/basic/src/ToggleControl.tsx @@ -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 ( + + + {_text} + + + ); +} + +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; diff --git a/examples/basic/src/VideoPlayer.ios.tsx b/examples/basic/src/VideoPlayer.ios.tsx deleted file mode 100644 index b8d916c5..00000000 --- a/examples/basic/src/VideoPlayer.ios.tsx +++ /dev/null @@ -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 ( - { this.setState({ - controls: selectControls, - skin: skin - }) }}> - - {skin} - - - ); - } - - renderRateControl(rate: number) { - const isSelected = (this.state.rate == rate); - - return ( - { this.setState({rate: rate}) }}> - - {rate}x - - - ) - } - - renderResizeModeControl(resizeMode: string) { - const isSelected = (this.state.resizeMode == resizeMode); - - return ( - { this.setState({resizeMode: resizeMode}) }}> - - {resizeMode} - - - ) - } - - renderVolumeControl(volume: number) { - const isSelected = (this.state.volume == volume); - - return ( - { this.setState({volume: volume}) }}> - - {volume * 100}% - - - ) - } - - renderIgnoreSilentSwitchControl(ignoreSilentSwitch: string) { - const isSelected = (this.state.ignoreSilentSwitch == ignoreSilentSwitch); - - return ( - { this.setState({ignoreSilentSwitch: ignoreSilentSwitch}) }}> - - {ignoreSilentSwitch} - - - ) - } - - renderFullscreenControl(fullscreen: string) { - return ( - { - if (fullscreen === 'fullscreen') { - this.video.presentFullscreenPlayer() - } - }}> - - {fullscreen} - - - ) - } - - renderMixWithOthersControl(mixWithOthers: string) { - const isSelected = (this.state.mixWithOthers == mixWithOthers); - - return ( - { this.setState({mixWithOthers: mixWithOthers}) }}> - - {mixWithOthers} - - - ) - } - - renderCustomSkin() { - const flexCompleted = this.getCurrentTimePercentage() * 100; - const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; - - return ( - - {this.setState({paused: !this.state.paused})}}> - - - - - - {this.renderSkinControl('custom')} - {this.renderSkinControl('native')} - {this.renderSkinControl('embed')} - - { - (this.state.filterEnabled) ? - - { - this.setFilter(-1) - }}> - Previous Filter - - { - this.setFilter(1) - }}> - Next Filter - - : null - } - - - - {this.renderRateControl(0.5)} - {this.renderRateControl(1.0)} - {this.renderRateControl(2.0)} - - - - {this.renderVolumeControl(0.5)} - {this.renderVolumeControl(1)} - {this.renderVolumeControl(1.5)} - - - - {this.renderResizeModeControl('cover')} - {this.renderResizeModeControl('contain')} - {this.renderResizeModeControl('stretch')} - - - - { - (Platform.OS === 'ios') ? - <> - - {this.renderIgnoreSilentSwitchControl('ignore')} - {this.renderIgnoreSilentSwitchControl('obey')} - - - {this.renderMixWithOthersControl('mix')} - {this.renderMixWithOthersControl('duck')} - - - {this.renderFullscreenControl('fullscreen')} - - : null - } - - - - - - - - - - - ); - } - - renderNativeSkin() { - const videoStyle = this.state.skin == 'embed' ? styles.nativeVideoControls : styles.fullScreen; - return ( - - - - - - - {this.renderSkinControl('custom')} - {this.renderSkinControl('native')} - {this.renderSkinControl('embed')} - - { - (this.state.filterEnabled) ? - - { - this.setFilter(-1) - }}> - Previous Filter - - { - this.setFilter(1) - }}> - Next Filter - - : null - } - - - - {this.renderRateControl(0.5)} - {this.renderRateControl(1.0)} - {this.renderRateControl(2.0)} - - - - {this.renderVolumeControl(0.5)} - {this.renderVolumeControl(1)} - {this.renderVolumeControl(1.5)} - - - - {this.renderResizeModeControl('cover')} - {this.renderResizeModeControl('contain')} - {this.renderResizeModeControl('stretch')} - - - - { - (Platform.OS === 'ios') ? - <> - - {this.renderIgnoreSilentSwitchControl('ignore')} - {this.renderIgnoreSilentSwitchControl('obey')} - - - {this.renderMixWithOthersControl('mix')} - {this.renderMixWithOthersControl('duck')} - - : null - } - - - - - ); - } - - 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 \ No newline at end of file diff --git a/examples/basic/src/VideoPlayer.android.tsx b/examples/basic/src/VideoPlayer.tsx similarity index 55% rename from examples/basic/src/VideoPlayer.android.tsx rename to examples/basic/src/VideoPlayer.tsx index 8b9fb620..bee804af 100644 --- a/examples/basic/src/VideoPlayer.android.tsx +++ b/examples/basic/src/VideoPlayer.tsx @@ -1,8 +1,6 @@ 'use strict'; -import React, { - Component -} from 'react'; +import React, {Component} from 'react'; import { StyleSheet, @@ -12,14 +10,18 @@ import { ActivityIndicator, PanResponder, ToastAndroid, + Platform, + PanResponderInstance, + Alert, } 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 { - state = { rate: 1, volume: 1, @@ -46,10 +48,38 @@ class VideoPlayer extends Component { showRNVControls: false, }; - seekerWidth = 0 + seekerWidth = 0; - srcList = [ + srcAllPlatformList = [ 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', uri: 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd', @@ -58,31 +88,26 @@ class VideoPlayer extends Component { description: '(mp4) big buck bunny', 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', - 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', + 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', type: 'mpd', }, { - description: 'invalid URL', - uri: - 'mmt://www.youtube.com', - type: 'mpd', + description: '(mp4) big buck bunny With Ads', + adTagUrl: + '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=', + 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 = () => { VideoDecoderProperties.getWidevineLevel().then((widevineLevel: number) => { @@ -105,52 +130,49 @@ class VideoPlayer extends Component { }; onLoad = (data: any) => { - this.setState({ duration: data.duration, loading: false, }); - this.onAudioTracks(data) - this.onTextTracks(data) + this.setState({duration: data.duration, loading: false}); + this.onAudioTracks(data); + this.onTextTracks(data); }; onProgress = (data: any) => { if (!this.state.seeking) { - const position = this.calculateSeekerPosition() - this.setSeekerPosition(position) + const position = this.calculateSeekerPosition(); + this.setSeekerPosition(position); } - this.setState({ currentTime: data.currentTime }) + this.setState({currentTime: data.currentTime}); }; - onVideoLoadStart = () => { - console.log('onVideoLoadStart') - this.setState({ isLoading: true }) - } - + console.log('onVideoLoadStart'); + this.setState({isLoading: true}); + }; onAudioTracks = (data: any) => { const selectedTrack = data.audioTracks?.find((x: any) => { - return x.selected - }) + return x.selected; + }); this.setState({ audioTracks: data.audioTracks, - }) + }); if (selectedTrack?.language) { this.setState({ selectedAudioTrack: { type: 'language', value: selectedTrack?.language, }, - }) - + }); } - } + }; onTextTracks = (data: any) => { const selectedTrack = data.textTracks?.find((x: any) => { - return x.selected - }) + return x.selected; + }); this.setState({ textTracks: data.textTracks, - }) + }); if (selectedTrack?.language) { this.setState({ textTracks: data, @@ -158,38 +180,34 @@ class VideoPlayer extends Component { type: 'language', value: selectedTrack?.language, }, - }) + }); } - } + }; onAspectRatio = (data: any) => { - console.log('onAspectRadio called ' + JSON.stringify(data)) + console.log('onAspectRadio called ' + JSON.stringify(data)); this.setState({ videoWidth: data.width, 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 }) => { - this.setState({ paused: !event.hasAudioFocus }) + 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}) => { + this.setState({paused: !event.hasAudioFocus}); }; getCurrentTimePercentage = () => { @@ -199,80 +217,44 @@ class VideoPlayer extends Component { return 0; }; - renderRateControl(rate: number) { - const isSelected = (this.state.rate === rate); - - return ( - { this.setState({ rate }) }}> - - {rate} - - - ); - } - - renderResizeModeControl(resizeMode: string) { - const isSelected = (this.state.resizeMode === resizeMode); - - return ( - { this.setState({ resizeMode }) }}> - - {resizeMode} - - - ) - } - - renderVolumeControl(volume: number) { - const isSelected = (this.state.volume === volume); - - return ( - { this.setState({ volume }) }}> - - {volume * 100}% - - - ) - } - - toast = (visible: boolean, message: string) => { if (visible) { - ToastAndroid.showWithGravityAndOffset( - message, - ToastAndroid.LONG, - ToastAndroid.BOTTOM, - 25, - 50, - ) - return null + if (Platform.OS === 'android') { + ToastAndroid.showWithGravityAndOffset( + message, + ToastAndroid.LONG, + ToastAndroid.BOTTOM, + 25, + 50, + ); + } 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() { - this.setState({ fullscreen: !this.state.fullscreen }) + this.setState({fullscreen: !this.state.fullscreen}); } toggleControls() { - this.setState({ showRNVControls: !this.state.showRNVControls }) + this.setState({showRNVControls: !this.state.showRNVControls}); } toggleDecoration() { - this.setState({ decoration: !this.state.decoration }) + this.setState({decoration: !this.state.decoration}); if (this.state.decoration) { - this.video.dismissFullscreenPlayer() + this.video?.dismissFullscreenPlayer(); } else { - this.video.presentFullscreenPlayer() + this.video?.presentFullscreenPlayer(); } } @@ -288,115 +270,23 @@ class VideoPlayer extends Component { textTracks: [], selectedAudioTrack: undefined, selectedTextTrack: undefined, - }) + }); } - channelUp() { - console.log('channel up') - this.goToChannel((this.state.srcListId + 1) % this.srcList.length) + console.log('channel up'); + this.goToChannel((this.state.srcListId + 1) % this.srcList.length); } channelDown() { - console.log('channel down') - this.goToChannel((this.state.srcListId + this.srcList.length - 1) % this.srcList.length) + console.log('channel down'); + this.goToChannel( + (this.state.srcListId + this.srcList.length - 1) % this.srcList.length, + ); } componentDidMount() { - this.initSeekPanResponder() - } - - renderDecorationsControl() { - return ( - { - this.toggleDecoration() - }} - > - {'decoration'} - - ) - } - - renderInfoControl() { - return ( - { - this.popupInfo() - }} - > - {'decoderInfo'} - - ) - } - - renderFullScreenControl() { - return ( - { - this.toggleFullscreen() - }} - > - {'fullscreen'} - - ) - } - - renderPause() { - return ( - { - this.setState({ paused: !this.state.paused }) - }} - > - - {this.state.paused ? 'pause' : 'playing'} - - - ) - } - - renderRepeatModeControl() { - return ( - { - this.setState({ loop: !this.state.loop }) - }} - > - - {this.state.loop ? 'loop enable' : 'loop disable'} - - - ) - } - - renderLeftControl() { - return ( - - { - this.channelDown() - }} - > - {'ChDown'} - - - // onTimelineUpdated - ) - } - - renderRightControl() { - return ( - - { - this.channelUp() - }} - > - {'ChUp'} - - - ) + this.initSeekPanResponder(); } /** @@ -413,11 +303,11 @@ class VideoPlayer extends Component { */ constrainToSeekerMinMax(val = 0) { if (val <= 0) { - return 0 + return 0; } 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} */ setSeekerPosition(position = 0) { - const state = this.state - position = this.constrainToSeekerMinMax(position) + const state = this.state; + position = this.constrainToSeekerMinMax(position); - state.seekerFillWidth = position - state.seekerPosition = position + state.seekerFillWidth = position; + state.seekerPosition = position; 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 */ calculateSeekerPosition() { - const percent = this.state.currentTime / this.state.duration - return this.seekerWidth * percent + const percent = this.state.currentTime / this.state.duration; + return this.seekerWidth * percent; } /** @@ -459,8 +349,8 @@ class VideoPlayer extends Component { * @return {float} time in ms based on seekerPosition. */ calculateTimeFromSeekerPosition() { - const percent = this.state.seekerPosition / this.seekerWidth - return this.state.duration * percent + const percent = this.state.seekerPosition / this.seekerWidth; + return this.state.duration * percent; } /** @@ -469,29 +359,29 @@ class VideoPlayer extends Component { initSeekPanResponder() { this.seekPanResponder = PanResponder.create({ // Ask to be the responder. - onStartShouldSetPanResponder: (evt, gestureState) => true, - onMoveShouldSetPanResponder: (evt, gestureState) => true, + onStartShouldSetPanResponder: (_evt, _gestureState) => true, + onMoveShouldSetPanResponder: (_evt, _gestureState) => true, /** * When we start the pan tell the machine that we're * seeking. This stops it from updating the seekbar * position in the onProgress listener. */ - onPanResponderGrant: (evt, gestureState) => { - const state = this.state + onPanResponderGrant: (evt, _gestureState) => { + const state = this.state; // this.clearControlTimeout() - const position = evt.nativeEvent.locationX - this.setSeekerPosition(position) - state.seeking = true - this.setState(state) + const position = evt.nativeEvent.locationX; + this.setSeekerPosition(position); + state.seeking = true; + this.setState(state); }, /** * When panning, update the seekbar position, duh. */ onPanResponderMove: (evt, gestureState) => { - const position = this.state.seekerOffset + gestureState.dx - this.setSeekerPosition(position) + const position = this.state.seekerOffset + gestureState.dx; + this.setSeekerPosition(position); }, /** @@ -499,140 +389,193 @@ class VideoPlayer extends Component { * If you seek to the end of the video we fire the * onEnd callback */ - onPanResponderRelease: (evt, gestureState) => { - const time = this.calculateTimeFromSeekerPosition() - const state = this.state + onPanResponderRelease: (_evt, _gestureState) => { + const time = this.calculateTimeFromSeekerPosition(); + const state = this.state; if (time >= state.duration && !state.isLoading) { - state.paused = true - this.onEnd() + state.paused = true; + this.onEnd(); } else { - this.video?.seek(time) - state.seeking = false + this.video?.seek(time); + state.seeking = false; } - this.setState(state) + this.setState(state); }, - }) + }); } renderSeekBar() { 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 ( + {...styles.generalControls}> (this.seekerWidth = event.nativeEvent.layout.width)} - pointerEvents={'none'} - > - 0 ? this.state.seekerFillWidth : 0, - backgroundColor: '#FFF', - }, - ]} - pointerEvents={'none'} - /> + onLayout={event => + (this.seekerWidth = event.nativeEvent.layout.width) + } + pointerEvents={'none'}> + - 0 ? this.state.seekerPosition : 0 }, - ]} - pointerEvents={'none'} - > - + + - ) + ); } IndicatorLoadingView() { - if (this.state.isLoading) - return - else return + if (this.state.isLoading) { + return ( + + ); + } else { + return ; + } } renderTopControl() { - return (<> - - {this.srcList[this.state.srcListId]?.description || 'local file'} - - - { - this.toggleControls() - }} - > - {this.state.showRNVControls ? 'Hide controls' : 'Show controls'} - - - ) + return ( + <> + + {this.srcList[this.state.srcListId]?.description || 'local file'} + + + { + this.toggleControls(); + }}> + + {this.state.showRNVControls ? 'Hide controls' : 'Show controls'} + + + + + ); } + 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() { return ( <> {this.IndicatorLoadingView()} - {this.renderTopControl()} + + {this.renderTopControl()} + {!this.state.showRNVControls ? ( <> - {this.renderLeftControl()} - - {this.renderRightControl()} - + { + this.channelDown(); + }} + text='ChDown' + /> + + + { + this.channelUp(); + }} + text='ChUp' + /> + + - - {this.renderInfoControl()} - - {this.renderPause()} - - {this.renderRepeatModeControl()} - - - {this.renderFullScreenControl()} - - - {this.renderDecorationsControl()} + {Platform.OS === 'android' ? ( + + { + this.popupInfo(); + }} + text='decoderInfo' + /> + ) : null} + { + this.setState({paused: !this.state.paused}); + }} + selectedText='pause' + unselectedText='playing' + /> + { + this.setState({loop: !this.state.loop}); + }} + selectedText='loop enable' + unselectedText='loop disable' + /> + { + this.toggleFullscreen(); + }} + text='fullscreen' + /> + { + this.toggleDecoration(); + }} + text='decoration' + /> - - {this.renderRateControl(0.25)} - {this.renderRateControl(0.5)} - {this.renderRateControl(1.0)} - {this.renderRateControl(1.5)} - {this.renderRateControl(2.0)} - - - - {this.renderVolumeControl(0.5)} - {this.renderVolumeControl(1)} - {this.renderVolumeControl(1.5)} - - - - {this.renderResizeModeControl('cover')} - {this.renderResizeModeControl('contain')} - {this.renderResizeModeControl('stretch')} - + + + {this.renderSeekBar()} @@ -651,14 +594,14 @@ class VideoPlayer extends Component { value: itemValue, }, }); - }} - > - {this.state.audioTracks.map((track) => { + }}> + {this.state.audioTracks.map(track => { return ( + key={track.language} + /> ); })} @@ -678,35 +621,38 @@ class VideoPlayer extends Component { value: itemValue, }, }); - }} - > + }}> - {this.state.textTracks.map((track) => ( + {this.state.textTracks.map(track => ( + key={track.language} + /> ))} )} - - ) : null - } + + + ) : null} - ) + ); } renderVideoView() { - const viewStyle = this.state.fullscreen ? styles.fullScreen : styles.halfScreen + const viewStyle = this.state.fullscreen + ? styles.fullScreen + : styles.halfScreen; return ( - ) + ); } render() { return ( - {this.srcList[this.state.srcListId]?.noView ? null : this.renderVideoView()} + {this.srcList[this.state.srcListId]?.noView + ? null + : this.renderVideoView()} {this.renderOverlay()} - ) + ); } - } - const styles = StyleSheet.create({ container: { flex: 1, @@ -888,4 +834,4 @@ const styles = StyleSheet.create({ }, }); -export default VideoPlayer \ No newline at end of file +export default VideoPlayer;