@plusscommunities/pluss-core-app 1.1.5 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plusscommunities/pluss-core-app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Core extension package for Pluss Communities platform",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
"react-native-elements": "^0.17.0",
|
|
36
36
|
"react-native-image-zoom-viewer": "^3.0.1",
|
|
37
37
|
"react-native-iphone-x-helper": "^1.3.1",
|
|
38
|
+
"react-native-vimeo-iframe": "^1.0.4",
|
|
38
39
|
"react-native-webview": "11.2.3",
|
|
40
|
+
"react-native-youtube-iframe": "^2.2.1",
|
|
39
41
|
"react-redux": "^5.0.5"
|
|
40
42
|
},
|
|
41
43
|
"peerDependencies": {
|
|
@@ -110,9 +110,7 @@ class ImagePopup extends Component {
|
|
|
110
110
|
const { showFullscreenVideo, currentVideoUrl } = this.state;
|
|
111
111
|
if (!currentVideoUrl) return;
|
|
112
112
|
|
|
113
|
-
return
|
|
114
|
-
<VideoPopup uri={currentVideoUrl} visible={showFullscreenVideo} showFullscreenButton={false} onClose={this.toggleFullscreenVideo} />
|
|
115
|
-
);
|
|
113
|
+
return <VideoPopup uri={currentVideoUrl} visible={showFullscreenVideo} onClose={this.toggleFullscreenVideo} />;
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
render() {
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import { Platform, View, StyleSheet, Dimensions } from 'react-native';
|
|
3
|
+
import * as ScreenOrientation from 'expo-screen-orientation';
|
|
4
|
+
import { DeviceMotion } from 'expo-sensors';
|
|
5
|
+
import YoutubePlayer, { getYoutubeMeta } from 'react-native-youtube-iframe';
|
|
6
|
+
import { Vimeo } from 'react-native-vimeo-iframe';
|
|
7
|
+
import WebView from 'react-native-webview';
|
|
8
|
+
import { Video } from 'expo-av';
|
|
9
|
+
import VideoPlayer from 'expo-video-player';
|
|
10
|
+
import { Spinner } from './Spinner';
|
|
11
|
+
|
|
12
|
+
const SCREEN_HEIGHT = Dimensions.get('window').height;
|
|
13
|
+
const SCREEN_WIDTH = Dimensions.get('window').width;
|
|
14
|
+
const EXPO_VIDEO_PROPS = { rate: 1, isMuted: false, volume: 1 };
|
|
15
|
+
const RETRY_RECOVER = 30000;
|
|
16
|
+
const RETRY_LOADING = 10000;
|
|
17
|
+
|
|
18
|
+
class MediaPlayer extends Component {
|
|
19
|
+
constructor(props) {
|
|
20
|
+
super(props);
|
|
21
|
+
this.state = {
|
|
22
|
+
deviceOrientation: null,
|
|
23
|
+
isLandscape: false,
|
|
24
|
+
isUrlLink: true,
|
|
25
|
+
isYoutube: false,
|
|
26
|
+
isVimeo: false,
|
|
27
|
+
forceWebview: false,
|
|
28
|
+
heightFactor: 0,
|
|
29
|
+
playbackLoaded: false,
|
|
30
|
+
playbackBuffering: false,
|
|
31
|
+
playbackPlaying: false,
|
|
32
|
+
readyToRender: false,
|
|
33
|
+
};
|
|
34
|
+
this.youtubePlayer = null;
|
|
35
|
+
this.videoPlayer = null;
|
|
36
|
+
this.checkStreamLoaded = null;
|
|
37
|
+
this.retryLoading = false;
|
|
38
|
+
this.orientationQueue = [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
componentDidMount = async () => {
|
|
42
|
+
this.setupForPlaying();
|
|
43
|
+
|
|
44
|
+
ScreenOrientation.lockAsync(Platform.OS === 'ios' ? ScreenOrientation.OrientationLock.DEFAULT : ScreenOrientation.OrientationLock.ALL);
|
|
45
|
+
const motionAvailalble = await DeviceMotion.isAvailableAsync();
|
|
46
|
+
// console.log('motionAvailalble', motionAvailalble);
|
|
47
|
+
if (motionAvailalble) {
|
|
48
|
+
DeviceMotion.setUpdateInterval(500);
|
|
49
|
+
DeviceMotion.addListener(this.onMotionChange);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
componentWillUnmount = () => {
|
|
54
|
+
if (this.checkStreamLoaded) clearInterval(this.checkStreamLoaded);
|
|
55
|
+
DeviceMotion.removeAllListeners();
|
|
56
|
+
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
getYoutubeVideoId = url => {
|
|
60
|
+
url = url.replace(/(>|<)/gi, '').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);
|
|
61
|
+
if (url[2] !== undefined) {
|
|
62
|
+
const ids = url[2].split(/[^0-9a-z_\-]/i);
|
|
63
|
+
return ids[0];
|
|
64
|
+
} else {
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
getVimeoId = url => {
|
|
70
|
+
const result = url.match(
|
|
71
|
+
/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^\/]*)\/videos\/|album\/(?:\d+)\/video\/|video\/|)(\d+)(?:[a-zA-Z0-9_\-]+)?/i,
|
|
72
|
+
);
|
|
73
|
+
return result[1];
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
setupForPlaying = async () => {
|
|
77
|
+
// Extract live stream info
|
|
78
|
+
const { source } = this.props;
|
|
79
|
+
const isUrlLink = source.startsWith('http');
|
|
80
|
+
const isYoutube = source.includes('youtube.com/watch?v=') || source.includes('youtu.be/');
|
|
81
|
+
const isVimeo = source.includes('vimeo.com/');
|
|
82
|
+
this.setState({ isUrlLink, isYoutube, isVimeo, playbackLoaded: isYoutube || isVimeo });
|
|
83
|
+
|
|
84
|
+
if (isYoutube) {
|
|
85
|
+
const metadata = await getYoutubeMeta(this.getYoutubeVideoId(source));
|
|
86
|
+
this.setState({ heightFactor: metadata.height / metadata.width, readyToRender: true });
|
|
87
|
+
// console.log('youtube metadata', metadata);
|
|
88
|
+
} else if (isVimeo) {
|
|
89
|
+
this.setState({ heightFactor: 0.565, readyToRender: true });
|
|
90
|
+
} else {
|
|
91
|
+
this.setState({ readyToRender: true });
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
getStreamPlaybackUrl = () => {
|
|
96
|
+
// return 'https://stream.mux.com/nflNhyFQMlrSt00II01Hjh2BLSW009PH1tl023pdpJ01s1vc.m3u8';
|
|
97
|
+
return `https://stream.mux.com/${this.props.playbackId}.m3u8`;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
checkReloadStream = (wait = RETRY_LOADING, force = false) => {
|
|
101
|
+
if (!force && this.retryLoading) return;
|
|
102
|
+
|
|
103
|
+
console.log(`Check loading in ${wait} milliseconds...`);
|
|
104
|
+
this.retryLoading = true;
|
|
105
|
+
setTimeout(async () => {
|
|
106
|
+
const { playbackLoaded, playbackBuffering } = this.state;
|
|
107
|
+
try {
|
|
108
|
+
if (playbackLoaded === false || playbackBuffering === true) {
|
|
109
|
+
console.log('Reloading started');
|
|
110
|
+
await this.videoPlayer.loadAsync(
|
|
111
|
+
{ uri: this.getStreamPlaybackUrl(), overrideFileExtensionAndroid: 'm3u8' },
|
|
112
|
+
EXPO_VIDEO_PROPS,
|
|
113
|
+
false,
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
console.log('Already loaded - not reloading');
|
|
117
|
+
}
|
|
118
|
+
this.retryLoading = false;
|
|
119
|
+
} catch {}
|
|
120
|
+
}, wait);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
isLandscape = deviceRotation => {
|
|
124
|
+
const { beta, gamma } = deviceRotation;
|
|
125
|
+
const absGamma = Math.abs(gamma);
|
|
126
|
+
const absBeta = Math.abs(beta);
|
|
127
|
+
const isGammaNegative = Math.sign(gamma) === -1;
|
|
128
|
+
|
|
129
|
+
if (absGamma <= 0.04 && absBeta <= 0.24) {
|
|
130
|
+
//Portrait mode, on a flat surface.
|
|
131
|
+
return false;
|
|
132
|
+
} else if ((absGamma <= 1.0 || absGamma >= 2.3) && absBeta >= 0.5) {
|
|
133
|
+
//General Portrait mode, accounting for forward and back tilt on the top of the phone.
|
|
134
|
+
return false;
|
|
135
|
+
} else {
|
|
136
|
+
if (isGammaNegative) {
|
|
137
|
+
//Landscape mode with the top of the phone to the left.
|
|
138
|
+
return true;
|
|
139
|
+
} else {
|
|
140
|
+
//Landscape mode with the top of the phone to the right.
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
onMotionChange = async changeEvent => {
|
|
147
|
+
const deviceRotation = changeEvent.rotation;
|
|
148
|
+
const deviceOrientation = changeEvent.orientation;
|
|
149
|
+
const isLandscape = this.isLandscape(deviceRotation);
|
|
150
|
+
this.orientationQueue.push(isLandscape);
|
|
151
|
+
if (this.orientationQueue.length > 2) this.orientationQueue = this.orientationQueue.slice(-2);
|
|
152
|
+
// console.log('onMotionChange - orientationQueue', this.orientationQueue);
|
|
153
|
+
if (
|
|
154
|
+
isLandscape !== this.state.isLandscape &&
|
|
155
|
+
isLandscape === (Math.abs(deviceOrientation) === 90) &&
|
|
156
|
+
this.orientationQueue.every(i => i === isLandscape)
|
|
157
|
+
) {
|
|
158
|
+
this.setState({ isLandscape }, () => {
|
|
159
|
+
// console.log('isLandscape', this.state.isLandscape);
|
|
160
|
+
if (this.props.orientationChanged) this.props.orientationChanged(this.state.isLandscape);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
onStreamLoadStart = () => {
|
|
166
|
+
console.log('Stream load started');
|
|
167
|
+
this.checkStreamLoaded = setInterval(() => {
|
|
168
|
+
const { playbackLoaded } = this.state;
|
|
169
|
+
if (playbackLoaded === false) {
|
|
170
|
+
console.log('Stream loading failed unexpectedly');
|
|
171
|
+
this.checkReloadStream(1000, true);
|
|
172
|
+
} else {
|
|
173
|
+
clearInterval(this.checkStreamLoaded);
|
|
174
|
+
}
|
|
175
|
+
}, RETRY_RECOVER);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
onStreamLoaded = status => {
|
|
179
|
+
console.log(`Stream loaded - isLoaded:${status.isLoaded}, isBuffering:${status.isBuffering}, isPlaying:${status.isPlaying}`);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
onStreamError = error => {
|
|
183
|
+
console.log('Stream error', error);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
onStreamStatusUpdate = status => {
|
|
187
|
+
this.setState(
|
|
188
|
+
{
|
|
189
|
+
playbackLoaded: status.isLoaded,
|
|
190
|
+
playbackBuffering: status.isBuffering,
|
|
191
|
+
playbackPlaying: status.isPlaying,
|
|
192
|
+
},
|
|
193
|
+
() => {
|
|
194
|
+
const { playbackLoaded, playbackBuffering, playbackPlaying, shouldPlay } = this.state;
|
|
195
|
+
// console.log(`Status updated - isLoaded:${playbackLoaded}, isBuffering:${playbackBuffering}, isPlaying:${playbackPlaying}`);
|
|
196
|
+
if (playbackLoaded === false && playbackBuffering === undefined && playbackPlaying === undefined) {
|
|
197
|
+
this.checkReloadStream();
|
|
198
|
+
} else if (playbackLoaded === true && playbackBuffering === true) {
|
|
199
|
+
this.checkReloadStream(RETRY_RECOVER);
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
onYoutubeError = e => {
|
|
206
|
+
// console.log('onYoutubeError', e);
|
|
207
|
+
this.setState({ forceWebview: true });
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
onYoutubeReady = () => {
|
|
211
|
+
// console.log('onYoutubeReady');
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
onVideoPlayStatusUpdate = status => {
|
|
215
|
+
// console.log('onVideoPlayStatusUpdate', status);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
onVideoPlayError = error => {
|
|
219
|
+
// console.log('onVideoPlayError', error);
|
|
220
|
+
this.setState({ forceWebview: true });
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
getYoutubePlayer = (youtubeId, width, height, autoPlay) => (
|
|
224
|
+
<YoutubePlayer
|
|
225
|
+
ref={ref => (this.youtubePlayer = ref)}
|
|
226
|
+
height={height}
|
|
227
|
+
width={width}
|
|
228
|
+
videoId={youtubeId}
|
|
229
|
+
play={autoPlay}
|
|
230
|
+
// onChangeState={event => console.log('onChangeState', event)}
|
|
231
|
+
onReady={this.onYoutubeReady}
|
|
232
|
+
onError={this.onYoutubeError}
|
|
233
|
+
// onPlaybackQualityChange={q => console.log('onPlaybackQualityChange', q)}
|
|
234
|
+
volume={50}
|
|
235
|
+
playbackRate={1}
|
|
236
|
+
playerParams={{
|
|
237
|
+
cc_lang_pref: 'us',
|
|
238
|
+
showClosedCaptions: true,
|
|
239
|
+
}}
|
|
240
|
+
/>
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
getVimeoPlayer = (vimeoId, width, height, autoPlay) => (
|
|
244
|
+
<View style={{ width, height }}>
|
|
245
|
+
<Vimeo
|
|
246
|
+
style={{ marginLeft: -8, marginRight: -5 }}
|
|
247
|
+
videoId={vimeoId}
|
|
248
|
+
// onReady={() => console.log('Video is ready')}
|
|
249
|
+
// onPlay={() => console.log('Video is playing')}
|
|
250
|
+
// onPlayProgress={data => console.log('Video progress data:', data)}
|
|
251
|
+
// onFinish={() => console.log('Video is finished')}
|
|
252
|
+
loop={false}
|
|
253
|
+
autoPlay={autoPlay}
|
|
254
|
+
controls={true}
|
|
255
|
+
speed={true}
|
|
256
|
+
time={'0m0s'}
|
|
257
|
+
/>
|
|
258
|
+
</View>
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
getWebviewPlayer = embedUrl => (
|
|
262
|
+
<WebView
|
|
263
|
+
startInLoadingState
|
|
264
|
+
javaScriptEnabled
|
|
265
|
+
scrollEnabled={false}
|
|
266
|
+
automaticallyAdjustContentInsets={false}
|
|
267
|
+
mediaPlaybackRequiresUserAction
|
|
268
|
+
style={styles.webView}
|
|
269
|
+
source={{ uri: embedUrl }}
|
|
270
|
+
/>
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
getStreamPlayer = (embedUrl, width, height, autoPlay) => (
|
|
274
|
+
<Video
|
|
275
|
+
ref={vp => {
|
|
276
|
+
this.videoPlayer = vp;
|
|
277
|
+
}}
|
|
278
|
+
source={{ uri: embedUrl }}
|
|
279
|
+
{...EXPO_VIDEO_PROPS}
|
|
280
|
+
shouldPlay={autoPlay}
|
|
281
|
+
resizeMode={Video.RESIZE_MODE_CONTAIN}
|
|
282
|
+
useNativeControls
|
|
283
|
+
style={{ width, height }}
|
|
284
|
+
onLoadStart={this.onStreamLoadStart}
|
|
285
|
+
onLoad={this.onStreamLoaded}
|
|
286
|
+
onError={this.onStreamError}
|
|
287
|
+
onPlaybackStatusUpdate={this.onStreamStatusUpdate}
|
|
288
|
+
/>
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
getVideoPlayer = (embedUrl, width, height, autoPlay) => (
|
|
292
|
+
<VideoPlayer
|
|
293
|
+
videoProps={{
|
|
294
|
+
shouldPlay: autoPlay,
|
|
295
|
+
resizeMode: Video.RESIZE_MODE_CONTAIN,
|
|
296
|
+
source: { uri: embedUrl },
|
|
297
|
+
}}
|
|
298
|
+
showFullscreenButton={false}
|
|
299
|
+
errorCallback={this.onVideoPlayError}
|
|
300
|
+
playbackCallback={this.onVideoPlayStatusUpdate}
|
|
301
|
+
height={height}
|
|
302
|
+
width={width}
|
|
303
|
+
/>
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
render() {
|
|
307
|
+
let width, height;
|
|
308
|
+
const { playbackId, source, autoPlay, useVideoPlayer } = this.props;
|
|
309
|
+
const {
|
|
310
|
+
readyToRender,
|
|
311
|
+
isLandscape,
|
|
312
|
+
heightFactor,
|
|
313
|
+
isUrlLink,
|
|
314
|
+
isYoutube,
|
|
315
|
+
isVimeo,
|
|
316
|
+
forceWebview,
|
|
317
|
+
playbackLoaded,
|
|
318
|
+
playbackBuffering,
|
|
319
|
+
} = this.state;
|
|
320
|
+
if (!readyToRender) return null;
|
|
321
|
+
|
|
322
|
+
if (isLandscape) {
|
|
323
|
+
width = SCREEN_HEIGHT;
|
|
324
|
+
height = SCREEN_WIDTH;
|
|
325
|
+
} else {
|
|
326
|
+
width = SCREEN_WIDTH;
|
|
327
|
+
height = heightFactor ? SCREEN_WIDTH * heightFactor : SCREEN_HEIGHT;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
let embedUrl, player, showLoading;
|
|
331
|
+
if (!forceWebview) {
|
|
332
|
+
if (isYoutube) {
|
|
333
|
+
const youtubeId = this.getYoutubeVideoId(source);
|
|
334
|
+
embedUrl = youtubeId ? `https://www.youtube.com/embed/${youtubeId}` : source;
|
|
335
|
+
player = this.getYoutubePlayer(youtubeId, width, height, autoPlay);
|
|
336
|
+
} else if (isVimeo) {
|
|
337
|
+
const vimeoId = this.getVimeoId(source);
|
|
338
|
+
embedUrl = source;
|
|
339
|
+
player = this.getVimeoPlayer(vimeoId, width, height, autoPlay);
|
|
340
|
+
} else if (playbackId) {
|
|
341
|
+
embedUrl = this.getStreamPlaybackUrl();
|
|
342
|
+
player = this.getStreamPlayer(embedUrl, width, height, autoPlay);
|
|
343
|
+
showLoading = true;
|
|
344
|
+
} else if (useVideoPlayer) {
|
|
345
|
+
embedUrl = source;
|
|
346
|
+
player = this.getVideoPlayer(embedUrl, width, height, autoPlay);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (!player && isUrlLink) {
|
|
350
|
+
embedUrl = source;
|
|
351
|
+
player = this.getWebviewPlayer(embedUrl);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// console.log({
|
|
355
|
+
// Streaming: embedUrl,
|
|
356
|
+
// Landscape: isLandscape,
|
|
357
|
+
// Loaded: playbackLoaded,
|
|
358
|
+
// Buffering: playbackBuffering,
|
|
359
|
+
// LoadingIndicator: showLoading,
|
|
360
|
+
// Width: width,
|
|
361
|
+
// Height: height,
|
|
362
|
+
// HeightFactor: heightFactor,
|
|
363
|
+
// });
|
|
364
|
+
return (
|
|
365
|
+
<View style={styles.container}>
|
|
366
|
+
{player}
|
|
367
|
+
{showLoading && (!playbackLoaded || playbackBuffering) && (
|
|
368
|
+
<View style={styles.loadingContainer}>
|
|
369
|
+
<Spinner color={'#fff'} />
|
|
370
|
+
</View>
|
|
371
|
+
)}
|
|
372
|
+
</View>
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const styles = StyleSheet.create({
|
|
378
|
+
container: {
|
|
379
|
+
backgroundColor: '#000',
|
|
380
|
+
alignItems: 'center',
|
|
381
|
+
justifyContent: 'center',
|
|
382
|
+
},
|
|
383
|
+
webView: {
|
|
384
|
+
flex: 1,
|
|
385
|
+
},
|
|
386
|
+
loadingContainer: {
|
|
387
|
+
position: 'absolute',
|
|
388
|
+
top: 50,
|
|
389
|
+
left: 0,
|
|
390
|
+
right: 0,
|
|
391
|
+
bottom: 50,
|
|
392
|
+
justifyContent: 'center',
|
|
393
|
+
alignItems: 'center',
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
export default MediaPlayer;
|
|
@@ -713,9 +713,7 @@ class PlussChat extends Component {
|
|
|
713
713
|
const { showFullscreenVideo, currentVideoUrl } = this.state;
|
|
714
714
|
if (!currentVideoUrl) return;
|
|
715
715
|
|
|
716
|
-
return
|
|
717
|
-
<VideoPopup uri={currentVideoUrl} visible={showFullscreenVideo} showFullscreenButton={false} onClose={this.toggleFullscreenVideo} />
|
|
718
|
-
);
|
|
716
|
+
return <VideoPopup uri={currentVideoUrl} visible={showFullscreenVideo} onClose={this.toggleFullscreenVideo} />;
|
|
719
717
|
}
|
|
720
718
|
|
|
721
719
|
renderPDF() {
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import React, { Component } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import VideoPlayer from 'expo-video-player';
|
|
2
|
+
import { Platform, View, Modal, TouchableOpacity, StyleSheet } from 'react-native';
|
|
3
|
+
import * as ScreenOrientation from 'expo-screen-orientation';
|
|
5
4
|
import { StatusBarHeight, getCompressed, imageExists } from '../helper';
|
|
6
5
|
import { Pl60Icon } from '../fonts';
|
|
7
|
-
import { SharingTools } from './
|
|
8
|
-
|
|
9
|
-
const SCREEN_HEIGHT = Dimensions.get('window').height;
|
|
6
|
+
import { SharingTools, MediaPlayer } from './';
|
|
10
7
|
|
|
11
8
|
class VideoPopup extends Component {
|
|
12
9
|
constructor(props) {
|
|
@@ -14,18 +11,26 @@ class VideoPopup extends Component {
|
|
|
14
11
|
|
|
15
12
|
this.state = {
|
|
16
13
|
uri: '',
|
|
14
|
+
isFullScreen: false,
|
|
17
15
|
};
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
UNSAFE_componentWillMount() {
|
|
18
|
+
UNSAFE_componentWillMount = async () => {
|
|
21
19
|
this.checkCompressed(this.props.uri);
|
|
22
|
-
|
|
20
|
+
await ScreenOrientation.lockAsync(
|
|
21
|
+
Platform.OS === 'ios' ? ScreenOrientation.OrientationLock.DEFAULT : ScreenOrientation.OrientationLock.ALL,
|
|
22
|
+
);
|
|
23
|
+
};
|
|
23
24
|
|
|
24
25
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
25
26
|
if (this.props.uri === nextProps.uri) return;
|
|
26
27
|
this.checkCompressed(nextProps.uri);
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
componentWillUnmount = async () => {
|
|
31
|
+
await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP);
|
|
32
|
+
};
|
|
33
|
+
|
|
29
34
|
checkCompressed = url => {
|
|
30
35
|
const compressedUri = getCompressed(url);
|
|
31
36
|
imageExists(compressedUri).then(compressedExists => {
|
|
@@ -33,11 +38,6 @@ class VideoPopup extends Component {
|
|
|
33
38
|
});
|
|
34
39
|
};
|
|
35
40
|
|
|
36
|
-
playbackCallback = status => {
|
|
37
|
-
const { playbackCallback } = this.props;
|
|
38
|
-
if (playbackCallback) playbackCallback(status);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
41
|
renderClose() {
|
|
42
42
|
return (
|
|
43
43
|
<TouchableOpacity style={styles.menuIconContainer} onPress={this.props.onClose} activeOpacity={0.6}>
|
|
@@ -47,35 +47,36 @@ class VideoPopup extends Component {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
renderPlayer() {
|
|
50
|
-
const { shouldPlay, showFullscreenButton, switchToPortrait, switchToLandscape } = this.props;
|
|
51
50
|
const { uri } = this.state;
|
|
52
51
|
if (!uri) return null;
|
|
53
|
-
console.log(`playing video\ncurrent: ${uri}\noriginal: ${this.props.uri}`);
|
|
54
52
|
|
|
55
53
|
return (
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
switchToLandscape={switchToLandscape}
|
|
65
|
-
playbackCallback={this.playbackCallback}
|
|
66
|
-
height={SCREEN_HEIGHT}
|
|
67
|
-
/>
|
|
54
|
+
<View style={styles.playerContainer}>
|
|
55
|
+
<MediaPlayer
|
|
56
|
+
source={uri}
|
|
57
|
+
useVideoPlayer={true}
|
|
58
|
+
autoPlay={true}
|
|
59
|
+
orientationChanged={isFullScreen => this.setState({ isFullScreen })}
|
|
60
|
+
/>
|
|
61
|
+
</View>
|
|
68
62
|
);
|
|
69
63
|
}
|
|
70
64
|
|
|
71
65
|
render() {
|
|
72
|
-
const {
|
|
66
|
+
const { isFullScreen } = this.state;
|
|
67
|
+
const { visible, onClose, animationType, style } = this.props;
|
|
73
68
|
|
|
74
69
|
return (
|
|
75
|
-
<Modal
|
|
70
|
+
<Modal
|
|
71
|
+
visible={visible}
|
|
72
|
+
animationType={animationType || 'fade'}
|
|
73
|
+
onRequestClose={onClose}
|
|
74
|
+
style={[styles.container, style]}
|
|
75
|
+
supportedOrientations={['portrait', 'landscape']}
|
|
76
|
+
>
|
|
76
77
|
{this.renderPlayer()}
|
|
77
|
-
{this.renderClose()}
|
|
78
|
-
<SharingTools uri={this.props.uri} />
|
|
78
|
+
{!isFullScreen && this.renderClose()}
|
|
79
|
+
{!isFullScreen && <SharingTools uri={this.props.uri} />}
|
|
79
80
|
</Modal>
|
|
80
81
|
);
|
|
81
82
|
}
|
|
@@ -101,6 +102,12 @@ const styles = StyleSheet.create({
|
|
|
101
102
|
color: '#fff',
|
|
102
103
|
zIndex: 3,
|
|
103
104
|
},
|
|
105
|
+
playerContainer: {
|
|
106
|
+
flex: 1,
|
|
107
|
+
backgroundColor: '#000',
|
|
108
|
+
alignItems: 'center',
|
|
109
|
+
justifyContent: 'center',
|
|
110
|
+
},
|
|
104
111
|
});
|
|
105
112
|
|
|
106
113
|
export { VideoPopup };
|
package/src/components/index.js
CHANGED
|
@@ -47,3 +47,4 @@ export { default as UserListing } from './UserListing';
|
|
|
47
47
|
export { default as PlussChat } from './PlussChat';
|
|
48
48
|
export { default as PositionedImage } from './PositionedImage';
|
|
49
49
|
export { default as FormattedText } from './FormattedText';
|
|
50
|
+
export { default as MediaPlayer } from './MediaPlayer';
|