1 | import omit from 'lodash/omit';
|
2 | import nullthrows from 'nullthrows';
|
3 | import * as React from 'react';
|
4 | import { findNodeHandle, Image, StyleSheet, View } from 'react-native';
|
5 | import { assertStatusValuesInBounds, getNativeSourceAndFullInitialStatusForLoadAsync, getNativeSourceFromSource, getUnloadedStatus, PlaybackMixin, } from './AV';
|
6 | import ExpoVideoManager from './ExpoVideoManager';
|
7 | import ExponentAV from './ExponentAV';
|
8 | import ExponentVideo from './ExponentVideo';
|
9 | import { ResizeMode, } from './Video.types';
|
10 | export { ResizeMode, };
|
11 | export const FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT = 0;
|
12 | export const FULLSCREEN_UPDATE_PLAYER_DID_PRESENT = 1;
|
13 | export const FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS = 2;
|
14 | export const FULLSCREEN_UPDATE_PLAYER_DID_DISMISS = 3;
|
15 | export const IOS_FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT = FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT;
|
16 | export const IOS_FULLSCREEN_UPDATE_PLAYER_DID_PRESENT = FULLSCREEN_UPDATE_PLAYER_DID_PRESENT;
|
17 | export const IOS_FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS = FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS;
|
18 | export const IOS_FULLSCREEN_UPDATE_PLAYER_DID_DISMISS = FULLSCREEN_UPDATE_PLAYER_DID_DISMISS;
|
19 | const _STYLES = StyleSheet.create({
|
20 | base: {
|
21 | overflow: 'hidden',
|
22 | },
|
23 | poster: {
|
24 | position: 'absolute',
|
25 | left: 0,
|
26 | top: 0,
|
27 | right: 0,
|
28 | bottom: 0,
|
29 | resizeMode: 'contain',
|
30 | },
|
31 | video: {
|
32 | position: 'absolute',
|
33 | left: 0,
|
34 | top: 0,
|
35 | right: 0,
|
36 | bottom: 0,
|
37 | },
|
38 | });
|
39 |
|
40 |
|
41 | const ExpoVideoManagerConstants = ExpoVideoManager;
|
42 | const ExpoVideoViewManager = ExpoVideoManager;
|
43 | export default class Video extends React.Component {
|
44 |
|
45 | constructor(props) {
|
46 | super(props);
|
47 | this._nativeRef = React.createRef();
|
48 | this._onPlaybackStatusUpdate = null;
|
49 |
|
50 | this._handleNewStatus = (status) => {
|
51 | if (this.state.showPoster &&
|
52 | status.isLoaded &&
|
53 | (status.isPlaying || status.positionMillis !== 0)) {
|
54 | this.setState({ showPoster: false });
|
55 | }
|
56 | if (this.props.onPlaybackStatusUpdate) {
|
57 | this.props.onPlaybackStatusUpdate(status);
|
58 | }
|
59 | if (this._onPlaybackStatusUpdate) {
|
60 | this._onPlaybackStatusUpdate(status);
|
61 | }
|
62 | };
|
63 | this._performOperationAndHandleStatusAsync = async (operation) => {
|
64 | const video = this._nativeRef.current;
|
65 | if (!video) {
|
66 | throw new Error(`Cannot complete operation because the Video component has not yet loaded`);
|
67 | }
|
68 | const handle = findNodeHandle(this._nativeRef.current);
|
69 | const status = await operation(handle);
|
70 | this._handleNewStatus(status);
|
71 | return status;
|
72 | };
|
73 |
|
74 | this._setFullscreen = async (value) => {
|
75 | return this._performOperationAndHandleStatusAsync((tag) => ExpoVideoViewManager.setFullscreen(tag, value));
|
76 | };
|
77 | this.presentFullscreenPlayer = async () => {
|
78 | return this._setFullscreen(true);
|
79 | };
|
80 | this.presentIOSFullscreenPlayer = () => {
|
81 | console.warn("You're using `presentIOSFullscreenPlayer`. Please migrate your code to use `presentFullscreenPlayer` instead.");
|
82 | return this.presentFullscreenPlayer();
|
83 | };
|
84 | this.presentFullscreenPlayerAsync = async () => {
|
85 | return await this.presentFullscreenPlayer();
|
86 | };
|
87 | this.dismissFullscreenPlayer = async () => {
|
88 | return this._setFullscreen(false);
|
89 | };
|
90 | this.dismissIOSFullscreenPlayer = () => {
|
91 | console.warn("You're using `dismissIOSFullscreenPlayer`. Please migrate your code to use `dismissFullscreenPlayer` instead.");
|
92 | this.dismissFullscreenPlayer();
|
93 | };
|
94 |
|
95 |
|
96 |
|
97 | this.getStatusAsync = async () => {
|
98 | return this._performOperationAndHandleStatusAsync((tag) => ExponentAV.getStatusForVideo(tag));
|
99 | };
|
100 |
|
101 | this.loadAsync = async (source, initialStatus = {}, downloadFirst = true) => {
|
102 | const { nativeSource, fullInitialStatus, } = await getNativeSourceAndFullInitialStatusForLoadAsync(source, initialStatus, downloadFirst);
|
103 | return this._performOperationAndHandleStatusAsync((tag) => ExponentAV.loadForVideo(tag, nativeSource, fullInitialStatus));
|
104 | };
|
105 |
|
106 | this.unloadAsync = async () => {
|
107 | return this._performOperationAndHandleStatusAsync((tag) => ExponentAV.unloadForVideo(tag));
|
108 | };
|
109 |
|
110 | this.setStatusAsync = async (status) => {
|
111 | assertStatusValuesInBounds(status);
|
112 | return this._performOperationAndHandleStatusAsync((tag) => ExponentAV.setStatusForVideo(tag, status));
|
113 | };
|
114 | this.replayAsync = async (status = {}) => {
|
115 | if (status.positionMillis && status.positionMillis !== 0) {
|
116 | throw new Error('Requested position after replay has to be 0.');
|
117 | }
|
118 | return this._performOperationAndHandleStatusAsync((tag) => ExponentAV.replayVideo(tag, {
|
119 | ...status,
|
120 | positionMillis: 0,
|
121 | shouldPlay: true,
|
122 | }));
|
123 | };
|
124 |
|
125 | this._nativeOnPlaybackStatusUpdate = (event) => {
|
126 | this._handleNewStatus(event.nativeEvent);
|
127 | };
|
128 |
|
129 | this._nativeOnLoadStart = () => {
|
130 | if (this.props.onLoadStart) {
|
131 | this.props.onLoadStart();
|
132 | }
|
133 | };
|
134 | this._nativeOnLoad = (event) => {
|
135 | if (this.props.onLoad) {
|
136 | this.props.onLoad(event.nativeEvent);
|
137 | }
|
138 | this._handleNewStatus(event.nativeEvent);
|
139 | };
|
140 | this._nativeOnError = (event) => {
|
141 | const error = event.nativeEvent.error;
|
142 | if (this.props.onError) {
|
143 | this.props.onError(error);
|
144 | }
|
145 | this._handleNewStatus(getUnloadedStatus(error));
|
146 | };
|
147 | this._nativeOnReadyForDisplay = (event) => {
|
148 | if (this.props.onReadyForDisplay) {
|
149 | this.props.onReadyForDisplay(event.nativeEvent);
|
150 | }
|
151 | };
|
152 | this._nativeOnFullscreenUpdate = (event) => {
|
153 | if (this.props.onIOSFullscreenUpdate && this.props.onFullscreenUpdate) {
|
154 | console.warn("You've supplied both `onIOSFullscreenUpdate` and `onFullscreenUpdate`. You're going to receive updates on both the callbacks.");
|
155 | }
|
156 | else if (this.props.onIOSFullscreenUpdate) {
|
157 | console.warn("You're using `onIOSFullscreenUpdate`. Please migrate your code to use `onFullscreenUpdate` instead.");
|
158 | }
|
159 | if (this.props.onIOSFullscreenUpdate) {
|
160 | this.props.onIOSFullscreenUpdate(event.nativeEvent);
|
161 | }
|
162 | if (this.props.onFullscreenUpdate) {
|
163 | this.props.onFullscreenUpdate(event.nativeEvent);
|
164 | }
|
165 | };
|
166 | this._renderPoster = () => this.props.usePoster && this.state.showPoster ? (
|
167 |
|
168 | React.createElement(Image, { style: [_STYLES.poster, this.props.posterStyle], source: this.props.posterSource })) : null;
|
169 | this.state = {
|
170 | showPoster: !!props.usePoster,
|
171 | };
|
172 | }
|
173 | setNativeProps(nativeProps) {
|
174 | const nativeVideo = nullthrows(this._nativeRef.current);
|
175 | nativeVideo.setNativeProps(nativeProps);
|
176 | }
|
177 | setOnPlaybackStatusUpdate(onPlaybackStatusUpdate) {
|
178 | this._onPlaybackStatusUpdate = onPlaybackStatusUpdate;
|
179 | this.getStatusAsync();
|
180 | }
|
181 | render() {
|
182 | const source = getNativeSourceFromSource(this.props.source) || undefined;
|
183 | let nativeResizeMode = ExpoVideoManagerConstants.ScaleNone;
|
184 | if (this.props.resizeMode) {
|
185 | const resizeMode = this.props.resizeMode;
|
186 | if (resizeMode === ResizeMode.STRETCH) {
|
187 | nativeResizeMode = ExpoVideoManagerConstants.ScaleToFill;
|
188 | }
|
189 | else if (resizeMode === ResizeMode.CONTAIN) {
|
190 | nativeResizeMode = ExpoVideoManagerConstants.ScaleAspectFit;
|
191 | }
|
192 | else if (resizeMode === ResizeMode.COVER) {
|
193 | nativeResizeMode = ExpoVideoManagerConstants.ScaleAspectFill;
|
194 | }
|
195 | }
|
196 |
|
197 | const status = { ...this.props.status };
|
198 | [
|
199 | 'progressUpdateIntervalMillis',
|
200 | 'positionMillis',
|
201 | 'shouldPlay',
|
202 | 'rate',
|
203 | 'shouldCorrectPitch',
|
204 | 'volume',
|
205 | 'isMuted',
|
206 | 'isLooping',
|
207 | ].forEach(prop => {
|
208 | if (prop in this.props) {
|
209 | status[prop] = this.props[prop];
|
210 | }
|
211 | });
|
212 |
|
213 |
|
214 | const nativeProps = {
|
215 | ...omit(this.props, 'source', 'onPlaybackStatusUpdate', 'usePoster', 'posterSource', 'posterStyle', ...Object.keys(status)),
|
216 | style: StyleSheet.flatten([_STYLES.base, this.props.style]),
|
217 | source,
|
218 | resizeMode: nativeResizeMode,
|
219 | status,
|
220 | onStatusUpdate: this._nativeOnPlaybackStatusUpdate,
|
221 | onLoadStart: this._nativeOnLoadStart,
|
222 | onLoad: this._nativeOnLoad,
|
223 | onError: this._nativeOnError,
|
224 | onReadyForDisplay: this._nativeOnReadyForDisplay,
|
225 | onFullscreenUpdate: this._nativeOnFullscreenUpdate,
|
226 | };
|
227 | return (React.createElement(View, { style: nativeProps.style, pointerEvents: "box-none" },
|
228 | React.createElement(ExponentVideo, Object.assign({ ref: this._nativeRef }, nativeProps, { style: _STYLES.video })),
|
229 | this._renderPoster()));
|
230 | }
|
231 | }
|
232 | Video.RESIZE_MODE_CONTAIN = ResizeMode.CONTAIN;
|
233 | Video.RESIZE_MODE_COVER = ResizeMode.COVER;
|
234 | Video.RESIZE_MODE_STRETCH = ResizeMode.STRETCH;
|
235 | Video.IOS_FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT = IOS_FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT;
|
236 | Video.IOS_FULLSCREEN_UPDATE_PLAYER_DID_PRESENT = IOS_FULLSCREEN_UPDATE_PLAYER_DID_PRESENT;
|
237 | Video.IOS_FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS = IOS_FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS;
|
238 | Video.IOS_FULLSCREEN_UPDATE_PLAYER_DID_DISMISS = IOS_FULLSCREEN_UPDATE_PLAYER_DID_DISMISS;
|
239 | Video.FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT = FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT;
|
240 | Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT = FULLSCREEN_UPDATE_PLAYER_DID_PRESENT;
|
241 | Video.FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS = FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS;
|
242 | Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS = FULLSCREEN_UPDATE_PLAYER_DID_DISMISS;
|
243 | Object.assign(Video.prototype, PlaybackMixin);
|
244 |
|
\ | No newline at end of file |