/YouTube.android.js

https://github.com/inProgress-team/react-native-youtube · JavaScript · 230 lines · 185 code · 37 blank · 8 comment · 8 complexity · 4fb0c83dec0039e2d3e7017356dce420 MD5 · raw file

  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import ReactNative, {
  4. View,
  5. ViewPropTypes,
  6. Text,
  7. StyleSheet,
  8. requireNativeComponent,
  9. UIManager,
  10. NativeModules,
  11. BackHandler,
  12. } from 'react-native';
  13. const RCTYouTube = requireNativeComponent('ReactYouTube', YouTube, {
  14. nativeOnly: {
  15. onYouTubeError: true,
  16. onYouTubeErrorReady: true,
  17. onYouTubeErrorChangeState: true,
  18. onYouTubeErrorChangeQuality: true,
  19. onYouTubeChangeFullscreen: true,
  20. },
  21. });
  22. export default class YouTube extends React.Component {
  23. static propTypes = {
  24. apiKey: PropTypes.string.isRequired,
  25. videoId: PropTypes.string,
  26. videoIds: PropTypes.arrayOf(PropTypes.string),
  27. playlistId: PropTypes.string,
  28. play: PropTypes.bool,
  29. loop: PropTypes.bool,
  30. fullscreen: PropTypes.bool,
  31. controls: PropTypes.oneOf([0, 1, 2]),
  32. showFullscreenButton: PropTypes.bool,
  33. resumePlayAndroid: PropTypes.bool,
  34. onError: PropTypes.func,
  35. onReady: PropTypes.func,
  36. onChangeState: PropTypes.func,
  37. onChangeQuality: PropTypes.func,
  38. onChangeFullscreen: PropTypes.func,
  39. style: ViewPropTypes.style,
  40. };
  41. static defaultProps = {
  42. showFullscreenButton: true,
  43. resumePlayAndroid: true,
  44. };
  45. _interval = null;
  46. _nativeComponentRef = React.createRef();
  47. constructor(props) {
  48. super(props);
  49. BackHandler.addEventListener('hardwareBackPress', this._backPress);
  50. this.state = {
  51. fullscreen: props.fullscreen,
  52. resizingHackFlag: false,
  53. };
  54. }
  55. componentDidMount() {
  56. // Make sure the Loading indication is displayed so use this hack before the video loads
  57. this._fireResizingHack();
  58. }
  59. componentDidUpdate(prevProps) {
  60. // Translate next `fullscreen` prop to state
  61. if (prevProps.fullscreen !== this.props.fullscreen) {
  62. this.setState({ fullscreen: this.props.fullscreen });
  63. }
  64. }
  65. componentWillUnmount() {
  66. BackHandler.removeEventListener('hardwareBackPress', this._backPress);
  67. clearInterval(this._timeout);
  68. }
  69. // The Android YouTube native module is pretty problematic when it comes to mounting correctly
  70. // and rendering inside React-Native's views hierarchy. For now we must trigger some layout
  71. // changes to force a real render on it so it will respotision it's controls after several
  72. // specific events
  73. _fireResizingHack() {
  74. clearInterval(this._timeout);
  75. let wait = 0.2;
  76. const next = () => {
  77. this.setState((state) => ({ resizingHackFlag: !state.resizingHackFlag }));
  78. wait = wait >= 1.5 ? 1.5 : wait * 1.4;
  79. this._timeout = setTimeout(next, wait * 1000);
  80. };
  81. next();
  82. }
  83. _backPress = () => {
  84. if (this.state.fullscreen) {
  85. this.setState({ fullscreen: false });
  86. return true;
  87. }
  88. return false;
  89. };
  90. _onLayout = () => {
  91. // When the Native player changes it's layout, we should also force a resizing hack to make
  92. // sure the controls are in their correct place
  93. this._fireResizingHack();
  94. };
  95. _onError = (event) => {
  96. if (this.props.onError) {
  97. this.props.onError(event.nativeEvent);
  98. }
  99. };
  100. _onReady = (event) => {
  101. this._fireResizingHack();
  102. if (this.props.onReady) {
  103. this.props.onReady(event.nativeEvent);
  104. }
  105. };
  106. _onChangeState = (event) => {
  107. if (this.props.onChangeState) {
  108. this.props.onChangeState(event.nativeEvent);
  109. }
  110. };
  111. _onChangeQuality = (event) => {
  112. if (this.props.onChangeQuality) {
  113. this.props.onChangeQuality(event.nativeEvent);
  114. }
  115. };
  116. _onChangeFullscreen = (event) => {
  117. const { isFullscreen } = event.nativeEvent;
  118. if (this.state.fullscreen !== isFullscreen) {
  119. this.setState({ fullscreen: isFullscreen });
  120. }
  121. if (this.props.onChangeFullscreen) {
  122. this.props.onChangeFullscreen(event.nativeEvent);
  123. }
  124. };
  125. seekTo(seconds) {
  126. UIManager.dispatchViewManagerCommand(
  127. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  128. UIManager.getViewManagerConfig('ReactYouTube').Commands.seekTo,
  129. [parseInt(seconds, 10)],
  130. );
  131. }
  132. nextVideo() {
  133. UIManager.dispatchViewManagerCommand(
  134. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  135. UIManager.getViewManagerConfig('ReactYouTube').Commands.nextVideo,
  136. [],
  137. );
  138. }
  139. previousVideo() {
  140. UIManager.dispatchViewManagerCommand(
  141. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  142. UIManager.getViewManagerConfig('ReactYouTube').Commands.previousVideo,
  143. [],
  144. );
  145. }
  146. playVideoAt(index) {
  147. UIManager.dispatchViewManagerCommand(
  148. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  149. UIManager.getViewManagerConfig('ReactYouTube').Commands.playVideoAt,
  150. [parseInt(index, 10)],
  151. );
  152. }
  153. getVideosIndex = () =>
  154. NativeModules.YouTubeModule.getVideosIndex(
  155. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  156. );
  157. getCurrentTime = () =>
  158. NativeModules.YouTubeModule.getCurrentTime(
  159. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  160. );
  161. getDuration = () =>
  162. NativeModules.YouTubeModule.getDuration(
  163. ReactNative.findNodeHandle(this._nativeComponentRef.current),
  164. );
  165. render() {
  166. return (
  167. <View onLayout={this._onLayout} style={[styles.container, this.props.style]}>
  168. <RCTYouTube
  169. ref={this._nativeComponentRef}
  170. {...this.props}
  171. fullscreen={this.state.fullscreen}
  172. style={[
  173. styles.module,
  174. { marginRight: this.state.resizingHackFlag ? StyleSheet.hairlineWidth : 0 },
  175. ]}
  176. onYouTubeError={this._onError}
  177. onYouTubeReady={this._onReady}
  178. onYouTubeChangeState={this._onChangeState}
  179. onYouTubeChangeQuality={this._onChangeQuality}
  180. onYouTubeChangeFullscreen={this._onChangeFullscreen}
  181. />
  182. </View>
  183. );
  184. }
  185. }
  186. const styles = StyleSheet.create({
  187. container: {
  188. backgroundColor: 'black',
  189. },
  190. module: {
  191. flex: 1,
  192. },
  193. });