@plusscommunities/pluss-core-app 1.2.0 → 1.2.4

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.2.0",
3
+ "version": "1.2.4",
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": {
@@ -26,10 +26,11 @@ export const reactionActions = {
26
26
  },
27
27
  });
28
28
  },
29
- addComment: (entityId, entityType, site, comment, image) => {
29
+ addComment: (entityId, entityType, entityName, site, comment, image) => {
30
30
  const data = {
31
31
  entityId,
32
32
  entityType,
33
+ entityName,
33
34
  site,
34
35
  comment,
35
36
  };
@@ -96,7 +96,7 @@ class CommentReply extends Component {
96
96
  this.props.commentSection.getWrappedInstance().startedAddingComment();
97
97
  }
98
98
  reactionActions
99
- .addComment(this.props.entityId, this.props.entityType, this.props.site, text, image)
99
+ .addComment(this.props.entityId, this.props.entityType, this.props.entityName, this.props.site, text, image)
100
100
  .then(res => {
101
101
  if (this.props.commentSection) {
102
102
  this.props.commentSection.getWrappedInstance().commentAdded(res.data);
@@ -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() {
@@ -1,14 +1,17 @@
1
1
  import React, { Component } from 'react';
2
- import { View, StyleSheet, Dimensions } from 'react-native';
2
+ import { Platform, View, StyleSheet, Dimensions } from 'react-native';
3
+ import * as ScreenOrientation from 'expo-screen-orientation';
4
+ import { DeviceMotion } from 'expo-sensors';
3
5
  import YoutubePlayer, { getYoutubeMeta } from 'react-native-youtube-iframe';
4
- // import { Vimeo } from 'react-native-vimeo-iframe';
6
+ import { Vimeo } from 'react-native-vimeo-iframe';
5
7
  import WebView from 'react-native-webview';
6
8
  import { Video } from 'expo-av';
7
- import { Spinner } from '../../../../src/components/common';
9
+ import VideoPlayer from 'expo-video-player';
10
+ import { Spinner } from './Spinner';
8
11
 
9
12
  const SCREEN_HEIGHT = Dimensions.get('window').height;
10
13
  const SCREEN_WIDTH = Dimensions.get('window').width;
11
- const EXPO_VIDEO_PROPS = { rate: 1, isMuted: false, volume: 1, shouldPlay: true };
14
+ const EXPO_VIDEO_PROPS = { rate: 1, isMuted: false, volume: 1 };
12
15
  const RETRY_RECOVER = 30000;
13
16
  const RETRY_LOADING = 10000;
14
17
 
@@ -16,27 +19,42 @@ class MediaPlayer extends Component {
16
19
  constructor(props) {
17
20
  super(props);
18
21
  this.state = {
22
+ deviceOrientation: null,
23
+ isLandscape: false,
19
24
  isUrlLink: true,
20
25
  isYoutube: false,
26
+ isVimeo: false,
21
27
  forceWebview: false,
22
- heightFactor: 0.565,
28
+ heightFactor: 0,
23
29
  playbackLoaded: false,
24
30
  playbackBuffering: false,
25
31
  playbackPlaying: false,
32
+ readyToRender: false,
26
33
  };
27
34
  this.youtubePlayer = null;
28
35
  this.videoPlayer = null;
29
36
  this.checkStreamLoaded = null;
30
37
  this.retryLoading = false;
38
+ this.orientationQueue = [];
31
39
  }
32
40
 
33
- componentDidMount() {
34
- this.setupForLiveStreaming();
35
- }
41
+ componentDidMount = async () => {
42
+ await this.setupForPlaying();
36
43
 
37
- componentWillUnmount() {
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 = () => {
38
54
  if (this.checkStreamLoaded) clearInterval(this.checkStreamLoaded);
39
- }
55
+ DeviceMotion.removeAllListeners();
56
+ ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP);
57
+ };
40
58
 
41
59
  getYoutubeVideoId = url => {
42
60
  url = url.replace(/(>|<)/gi, '').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);
@@ -48,23 +66,36 @@ class MediaPlayer extends Component {
48
66
  }
49
67
  };
50
68
 
51
- setupForLiveStreaming = async () => {
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 () => {
52
77
  // Extract live stream info
53
- const { streamUrl } = this.props.streamInfo;
54
- const isUrlLink = streamUrl.startsWith('http');
55
- const isYoutube = streamUrl.includes('youtube.com/watch?v=') || streamUrl.includes('youtu.be/');
56
- this.setState({ isUrlLink, isYoutube });
78
+ const { source, useVideoPlayer } = this.props;
79
+ const isUrlLink = source && source.startsWith('http');
80
+ const isYoutube = source && (source.includes('youtube.com/watch?v=') || source.includes('youtu.be/'));
81
+ const isVimeo = source && source.includes('vimeo.com/');
82
+ let heightFactor = 0;
83
+
84
+ if (isYoutube) {
85
+ const metadata = await getYoutubeMeta(this.getYoutubeVideoId(source));
86
+ heightFactor = metadata.height / metadata.width;
87
+ } else if (useVideoPlayer) {
88
+ heightFactor = 0;
89
+ } else {
90
+ heightFactor = 0.565;
91
+ }
57
92
 
58
- // if (isYoutube) {
59
- // const metadata = await getYoutubeMeta(this.getYoutubeVideoId(streamUrl));
60
- // this.setState({ heightFactor: metadata.height / metadata.width });
61
- // console.log('youtube metadata', metadata);
62
- // }
93
+ this.setState({ isUrlLink, isYoutube, isVimeo, playbackLoaded: isYoutube || isVimeo, heightFactor, readyToRender: true });
63
94
  };
64
95
 
65
96
  getStreamPlaybackUrl = () => {
66
- // return 'https://stream.mux.com/nflNhyFQMlrSt00II01Hjh2BLSW009PH1tl023pdpJ01s1vc.m3u8';
67
- return `https://stream.mux.com/${this.props.streamInfo.playbackId}.m3u8`;
97
+ // return 'https://stream.mux.com/Ym4nKktRpGuZNBBBlzhxpyRwZLpvMlPRchcu01x6Ur600.m3u8';
98
+ return `https://stream.mux.com/${this.props.playbackId}.m3u8`;
68
99
  };
69
100
 
70
101
  checkReloadStream = (wait = RETRY_LOADING, force = false) => {
@@ -90,6 +121,48 @@ class MediaPlayer extends Component {
90
121
  }, wait);
91
122
  };
92
123
 
124
+ isLandscape = deviceRotation => {
125
+ const { beta, gamma } = deviceRotation;
126
+ const absGamma = Math.abs(gamma);
127
+ const absBeta = Math.abs(beta);
128
+ const isGammaNegative = Math.sign(gamma) === -1;
129
+
130
+ if (absGamma <= 0.04 && absBeta <= 0.24) {
131
+ //Portrait mode, on a flat surface.
132
+ return false;
133
+ } else if ((absGamma <= 1.0 || absGamma >= 2.3) && absBeta >= 0.5) {
134
+ //General Portrait mode, accounting for forward and back tilt on the top of the phone.
135
+ return false;
136
+ } else {
137
+ if (isGammaNegative) {
138
+ //Landscape mode with the top of the phone to the left.
139
+ return true;
140
+ } else {
141
+ //Landscape mode with the top of the phone to the right.
142
+ return true;
143
+ }
144
+ }
145
+ };
146
+
147
+ onMotionChange = async changeEvent => {
148
+ const deviceRotation = changeEvent.rotation;
149
+ const deviceOrientation = changeEvent.orientation;
150
+ const isLandscape = this.isLandscape(deviceRotation);
151
+ this.orientationQueue.push(isLandscape);
152
+ if (this.orientationQueue.length > 2) this.orientationQueue = this.orientationQueue.slice(-2);
153
+ // console.log('onMotionChange - orientationQueue', this.orientationQueue);
154
+ if (
155
+ isLandscape !== this.state.isLandscape &&
156
+ isLandscape === (Math.abs(deviceOrientation) === 90) &&
157
+ this.orientationQueue.every(i => i === isLandscape)
158
+ ) {
159
+ this.setState({ isLandscape }, () => {
160
+ // console.log('isLandscape', this.state.isLandscape);
161
+ if (this.props.orientationChanged) this.props.orientationChanged(this.state.isLandscape);
162
+ });
163
+ }
164
+ };
165
+
93
166
  onStreamLoadStart = () => {
94
167
  console.log('Stream load started');
95
168
  this.checkStreamLoaded = setInterval(() => {
@@ -137,16 +210,24 @@ class MediaPlayer extends Component {
137
210
 
138
211
  onYoutubeReady = () => {
139
212
  // console.log('onYoutubeReady');
140
- this.setState({ playbackLoaded: true });
141
213
  };
142
214
 
143
- getYoutubePlayer = (youtubeId, width, height) => (
215
+ onVideoPlayStatusUpdate = status => {
216
+ // console.log('onVideoPlayStatusUpdate', status);
217
+ };
218
+
219
+ onVideoPlayError = error => {
220
+ // console.log('onVideoPlayError', error);
221
+ this.setState({ forceWebview: true });
222
+ };
223
+
224
+ getYoutubePlayer = (youtubeId, width, height, autoPlay) => (
144
225
  <YoutubePlayer
145
226
  ref={ref => (this.youtubePlayer = ref)}
146
227
  height={height}
147
228
  width={width}
148
229
  videoId={youtubeId}
149
- play
230
+ play={autoPlay}
150
231
  // onChangeState={event => console.log('onChangeState', event)}
151
232
  onReady={this.onYoutubeReady}
152
233
  onError={this.onYoutubeError}
@@ -160,6 +241,24 @@ class MediaPlayer extends Component {
160
241
  />
161
242
  );
162
243
 
244
+ getVimeoPlayer = (vimeoId, width, height, autoPlay) => (
245
+ <View style={{ width, height }}>
246
+ <Vimeo
247
+ style={{ marginLeft: -8, marginRight: -5 }}
248
+ videoId={vimeoId}
249
+ // onReady={() => console.log('Video is ready')}
250
+ // onPlay={() => console.log('Video is playing')}
251
+ // onPlayProgress={data => console.log('Video progress data:', data)}
252
+ // onFinish={() => console.log('Video is finished')}
253
+ loop={false}
254
+ autoPlay={autoPlay}
255
+ controls={true}
256
+ speed={true}
257
+ time={'0m0s'}
258
+ />
259
+ </View>
260
+ );
261
+
163
262
  getWebviewPlayer = embedUrl => (
164
263
  <WebView
165
264
  startInLoadingState
@@ -172,13 +271,14 @@ class MediaPlayer extends Component {
172
271
  />
173
272
  );
174
273
 
175
- getVideoPlayer = (embedUrl, width, height) => (
274
+ getStreamPlayer = (embedUrl, width, height, autoPlay) => (
176
275
  <Video
177
276
  ref={vp => {
178
277
  this.videoPlayer = vp;
179
278
  }}
180
279
  source={{ uri: embedUrl }}
181
280
  {...EXPO_VIDEO_PROPS}
281
+ shouldPlay={autoPlay}
182
282
  resizeMode={Video.RESIZE_MODE_CONTAIN}
183
283
  useNativeControls
184
284
  style={{ width, height }}
@@ -189,37 +289,83 @@ class MediaPlayer extends Component {
189
289
  />
190
290
  );
191
291
 
292
+ getVideoPlayer = (embedUrl, width, height, autoPlay) => (
293
+ <VideoPlayer
294
+ videoProps={{
295
+ shouldPlay: autoPlay,
296
+ resizeMode: Video.RESIZE_MODE_CONTAIN,
297
+ source: { uri: embedUrl },
298
+ }}
299
+ showFullscreenButton={false}
300
+ errorCallback={this.onVideoPlayError}
301
+ playbackCallback={this.onVideoPlayStatusUpdate}
302
+ height={height}
303
+ width={width}
304
+ />
305
+ );
306
+
192
307
  render() {
193
308
  let width, height;
194
- const { landscape, streamInfo } = this.props;
195
- if (landscape) {
309
+ const { playbackId, source, autoPlay, useVideoPlayer } = this.props;
310
+ const {
311
+ readyToRender,
312
+ isLandscape,
313
+ heightFactor,
314
+ isUrlLink,
315
+ isYoutube,
316
+ isVimeo,
317
+ forceWebview,
318
+ playbackLoaded,
319
+ playbackBuffering,
320
+ } = this.state;
321
+ if (!readyToRender) return null;
322
+
323
+ if (isLandscape) {
196
324
  width = SCREEN_HEIGHT;
197
325
  height = SCREEN_WIDTH;
198
326
  } else {
199
327
  width = SCREEN_WIDTH;
200
- height = SCREEN_WIDTH * this.state.heightFactor;
328
+ height = heightFactor ? SCREEN_WIDTH * heightFactor : SCREEN_HEIGHT;
201
329
  }
202
330
 
203
- const { isUrlLink, isYoutube, forceWebview, playbackLoaded, playbackBuffering } = this.state;
204
- const { playbackId, streamUrl } = streamInfo;
205
- let embedUrl, player;
206
- if (isYoutube && !forceWebview) {
207
- const youtubeId = this.getYoutubeVideoId(streamUrl);
208
- embedUrl = youtubeId ? `https://www.youtube.com/embed/${youtubeId}` : streamUrl;
209
- player = this.getYoutubePlayer(youtubeId, width, height);
210
- } else if (isUrlLink) {
211
- embedUrl = streamUrl;
331
+ let embedUrl, player, showLoading;
332
+ if (!forceWebview) {
333
+ if (isYoutube) {
334
+ const youtubeId = this.getYoutubeVideoId(source);
335
+ embedUrl = youtubeId ? `https://www.youtube.com/embed/${youtubeId}` : source;
336
+ player = this.getYoutubePlayer(youtubeId, width, height, autoPlay);
337
+ } else if (isVimeo) {
338
+ const vimeoId = this.getVimeoId(source);
339
+ embedUrl = source;
340
+ player = this.getVimeoPlayer(vimeoId, width, height, autoPlay);
341
+ } else if (playbackId) {
342
+ embedUrl = this.getStreamPlaybackUrl();
343
+ player = this.getStreamPlayer(embedUrl, width, height, autoPlay);
344
+ showLoading = true;
345
+ } else if (useVideoPlayer) {
346
+ embedUrl = source;
347
+ player = this.getVideoPlayer(embedUrl, width, height, autoPlay);
348
+ }
349
+ }
350
+ if (!player && isUrlLink) {
351
+ embedUrl = source;
212
352
  player = this.getWebviewPlayer(embedUrl);
213
- } else if (playbackId) {
214
- embedUrl = this.getStreamPlaybackUrl();
215
- player = this.getVideoPlayer(embedUrl, width, height);
216
353
  }
217
354
 
218
- // console.log('Streaming:', embedUrl, 'landscape', landscape, 'playbackLoaded', playbackLoaded, 'playbackBuffering', playbackBuffering);
355
+ // console.log({
356
+ // Streaming: embedUrl,
357
+ // Landscape: isLandscape,
358
+ // Loaded: playbackLoaded,
359
+ // Buffering: playbackBuffering,
360
+ // LoadingIndicator: showLoading,
361
+ // Width: width,
362
+ // Height: height,
363
+ // HeightFactor: heightFactor,
364
+ // });
219
365
  return (
220
- <View style={[styles.container, !isUrlLink && { alignItems: 'center' }, { width, height }]}>
366
+ <View style={styles.container}>
221
367
  {player}
222
- {(!playbackLoaded || playbackBuffering) && (
368
+ {showLoading && (!playbackLoaded || playbackBuffering) && (
223
369
  <View style={styles.loadingContainer}>
224
370
  <Spinner color={'#fff'} />
225
371
  </View>
@@ -232,6 +378,8 @@ class MediaPlayer extends Component {
232
378
  const styles = StyleSheet.create({
233
379
  container: {
234
380
  backgroundColor: '#000',
381
+ alignItems: 'center',
382
+ justifyContent: 'center',
235
383
  },
236
384
  webView: {
237
385
  flex: 1,
@@ -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 { Dimensions, Modal, TouchableOpacity, StyleSheet } from 'react-native';
3
- import { Video } from 'expo-av';
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 './SharingTools';
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
- <VideoPlayer
57
- videoProps={{
58
- shouldPlay: shouldPlay || true,
59
- resizeMode: Video.RESIZE_MODE_CONTAIN,
60
- source: { uri },
61
- }}
62
- showFullscreenButton={showFullscreenButton}
63
- switchToPortrait={switchToPortrait}
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 { visible, onClose, style } = this.props;
66
+ const { isFullScreen } = this.state;
67
+ const { visible, onClose, animationType, style } = this.props;
73
68
 
74
69
  return (
75
- <Modal visible={visible} animationType="fade" onRequestClose={onClose} style={[styles.container, style]}>
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 };