Преглед изворни кода

rn: refactors the YoutubeLargeVideo to be class component. Adds interval for sending the seek time every 5 seconds.

master
Titus-Andrei Moldovan пре 5 година
родитељ
комит
59750ba1f1
1 измењених фајлова са 238 додато и 132 уклоњено
  1. 238
    132
      react/features/youtube-player/components/native/YoutubeLargeVideo.js

+ 238
- 132
react/features/youtube-player/components/native/YoutubeLargeVideo.js Прегледај датотеку

@@ -1,6 +1,6 @@
1 1
 // @flow
2 2
 
3
-import React, { useRef, useEffect } from 'react';
3
+import React, { Component, createRef } from 'react';
4 4
 import { View } from 'react-native';
5 5
 import YoutubePlayer from 'react-native-youtube-iframe';
6 6
 
@@ -60,140 +60,277 @@ type Props = {
60 60
     _isWideScreen: boolean,
61 61
 
62 62
     /**
63
-     * Callback to invoke when the {@code YoutLargeVideo} is ready to play.
63
+     * The id of the participant sharing the video.
64 64
      *
65 65
      * @private
66 66
      */
67
-    _onVideoReady: Function,
67
+    _ownerId: string,
68 68
 
69 69
     /**
70
-     * Callback to invoke when the {@code YoutubeLargeVideo} changes status.
70
+     * The height of the player.
71 71
      *
72 72
      * @private
73 73
      */
74
-    _onVideoChangeEvent: Function,
74
+    _playerHeight: number,
75 75
 
76 76
     /**
77
-     * Callback to invoke when { @code isWideScreen} changes.
77
+     * The width of the player.
78 78
      *
79 79
      * @private
80 80
      */
81
-    _onWideScreenChanged: Function,
81
+    _playerWidth: number,
82 82
 
83 83
     /**
84
-     * The id of the participant sharing the video.
84
+     * Seek time in seconds.
85 85
      *
86 86
      * @private
87 87
      */
88
-    _ownerId: string,
88
+    _seek: number,
89 89
 
90
-    /**
91
-     * The height of the screen.
90
+     /**
91
+     * The status of the player.
92 92
      *
93 93
      * @private
94 94
      */
95
-    _screenHeight: number,
95
+    _status: string,
96 96
 
97 97
     /**
98
-     * The width of the screen.
98
+     * The Redux dispatch function.
99
+     */
100
+    dispatch: Function,
101
+
102
+    /**
103
+     * Youtube id of the video to be played.
99 104
      *
100 105
      * @private
101 106
      */
102
-    _screenWidth: number,
107
+    youtubeId: string
108
+};
103 109
 
110
+/**
111
+ *
112
+ * Implements a React {@code Component} for showing a youtube video.
113
+ *
114
+ * @extends Component
115
+ */
116
+class YoutubeLargeVideo extends Component<Props, *> {
104 117
     /**
105
-     * Seek time in seconds.
118
+     * Saves a handle to the timer for seek time updates,
119
+     * so that it can be cancelled when the component unmounts.
120
+     */
121
+    intervalId: ?IntervalID;
122
+
123
+    /**
124
+     * A React ref to the HTML element containing the {@code YoutubePlayer} instance.
125
+     */
126
+    playerRef: Object;
127
+
128
+    /**
129
+     * Initializes a new {@code YoutubeLargeVideo} instance.
106 130
      *
107
-     * @private
131
+     * @param {Object} props - The read-only properties with which the new
132
+     * instance is to be initialized.
108 133
      */
109
-    _seek: number,
134
+    constructor(props: Props) {
135
+        super(props);
136
+        this.playerRef = createRef();
137
+
138
+        this._onReady = this._onReady.bind(this);
139
+        this._onChangeState = this._onChangeState.bind(this);
140
+
141
+        this.setWideScreenMode(props._isWideScreen);
142
+    }
110 143
 
111 144
     /**
112
-     * Youtube id of the video to be played.
145
+     * Seeks to the new time if the difference between the new one and the current is larger than 5 seconds.
113 146
      *
114
-     * @private
147
+     * @inheritdoc
148
+     * @returns {void}
115 149
      */
116
-    youtubeId: string
117
-};
150
+    componentDidUpdate(prevProps: Props) {
151
+        const playerRef = this.playerRef.current;
152
+        const { _isWideScreen, _seek } = this.props;
153
+
154
+        if (_seek !== prevProps._seek) {
155
+            playerRef && playerRef.getCurrentTime().then(time => {
156
+                if (shouldSeekToPosition(_seek, time)) {
157
+                    playerRef && playerRef.seekTo(_seek);
158
+                }
159
+            });
160
+        }
118 161
 
119
-const YoutubeLargeVideo = (props: Props) => {
120
-    const playerRef = useRef(null);
162
+        if (_isWideScreen !== prevProps._isWideScreen) {
163
+            this.setWideScreenMode(_isWideScreen);
164
+        }
165
+    }
121 166
 
122
-    useEffect(() => {
123
-        playerRef.current && playerRef.current.getCurrentTime().then(time => {
124
-            const { _seek } = props;
167
+    /**
168
+     * Sets the interval for saving the seek time to redux every 5 seconds.
169
+     *
170
+     * @inheritdoc
171
+     * @returns {void}
172
+     */
173
+    componentDidMount() {
174
+        this.intervalId = setInterval(() => {
175
+            this.saveRefTime();
176
+        }, 5000);
177
+    }
125 178
 
126
-            if (shouldSeekToPosition(_seek, time)) {
127
-                playerRef.current && playerRef.current.seekTo(_seek);
128
-            }
129
-        });
130
-    }, [ props._seek ]);
179
+    /**
180
+     * Clears the interval.
181
+     *
182
+     * @inheritdoc
183
+     * @returns {void}
184
+     */
185
+    componentWillUnmount() {
186
+        clearInterval(this.intervalId);
187
+        this.intervalId = null;
188
+    }
189
+
190
+    /**
191
+     * Renders the YoutubeLargeVideo element.
192
+     *
193
+     * @override
194
+     * @returns {ReactElement}
195
+     */
196
+    render() {
197
+        const {
198
+            _enableControls,
199
+            _isPlaying,
200
+            _playerHeight,
201
+            _playerWidth,
202
+            youtubeId
203
+        } = this.props;
204
+
205
+        return (
206
+            <View
207
+                pointerEvents = { _enableControls ? 'auto' : 'none' }
208
+                style = { styles.youtubeVideoContainer } >
209
+                <YoutubePlayer
210
+                    height = { _playerHeight }
211
+                    initialPlayerParams = {{
212
+                        controls: _enableControls,
213
+                        modestbranding: true,
214
+                        preventFullScreen: true
215
+                    }}
216
+                    /* eslint-disable react/jsx-no-bind */
217
+                    onChangeState = { this._onChangeState }
218
+                    /* eslint-disable react/jsx-no-bind */
219
+                    onReady = { this._onReady }
220
+                    play = { _isPlaying }
221
+                    playbackRate = { 1 }
222
+                    ref = { this.playerRef }
223
+                    videoId = { youtubeId }
224
+                    volume = { 50 }
225
+                    webViewProps = {{
226
+                        bounces: false,
227
+                        mediaPlaybackRequiresUserAction: false,
228
+                        scrollEnabled: false,
229
+                        userAgent: webviewUserAgent
230
+                    }}
231
+                    width = { _playerWidth } />
232
+            </View>);
233
+    }
131 234
 
132
-    useEffect(() => {
133
-        props._onWideScreenChanged(props._isWideScreen);
134
-    }, [ props._isWideScreen ]);
235
+    _onReady: () => void;
236
+
237
+    /**
238
+     * Callback invoked when the player is ready to play the video.
239
+     *
240
+     * @private
241
+     * @returns {void}
242
+     */
243
+    _onReady() {
244
+        if (this.props?._isOwner) {
245
+            this.onVideoReady(
246
+                this.props.youtubeId,
247
+                this.playerRef.current && this.playerRef.current.getCurrentTime(),
248
+                this.props._ownerId);
249
+        }
250
+    }
135 251
 
136
-    const onChangeState = e =>
137
-        playerRef.current && playerRef.current.getCurrentTime().then(time => {
252
+    _onChangeState: (status: string) => void;
253
+
254
+    /**
255
+     * Callback invoked when the state of the player changes.
256
+     *
257
+     * @param {string} status - The new status of the player.
258
+     * @private
259
+     * @returns {void}
260
+     */
261
+    _onChangeState(status) {
262
+        this.playerRef?.current && this.playerRef.current.getCurrentTime().then(time => {
138 263
             const {
139 264
                 _isOwner,
140 265
                 _isPlaying,
141 266
                 _isStopped,
142
-                _seek
143
-            } = props;
267
+                _ownerId,
268
+                _seek,
269
+                youtubeId
270
+            } = this.props;
144 271
 
145
-            if (shouldSetNewStatus(_isStopped, _isOwner, e, _isPlaying, time, _seek)) {
146
-                props._onVideoChangeEvent(props.youtubeId, e, time, props._ownerId);
272
+            if (shouldSetNewStatus(_isStopped, _isOwner, status, _isPlaying, time, _seek)) {
273
+                this.onVideoChangeEvent(youtubeId, status, time, _ownerId);
147 274
             }
148 275
         });
149
-    const onReady = () => {
150
-        if (props._isOwner) {
151
-            props._onVideoReady(
152
-                props.youtubeId,
153
-                playerRef.current && playerRef.current.getCurrentTime(),
154
-                props._ownerId);
276
+    }
277
+
278
+    /**
279
+     * Calls onVideoChangeEvent with the refTime.
280
+     *
281
+     * @private
282
+     * @returns {void}
283
+    */
284
+    saveRefTime() {
285
+        const { youtubeId, _status, _ownerId } = this.props;
286
+
287
+        this.playerRef.current && this.playerRef.current.getCurrentTime().then(time => {
288
+            this.onVideoChangeEvent(youtubeId, _status, time, _ownerId);
289
+        });
290
+    }
291
+
292
+    /**
293
+     * Dispatches the video status, time and ownerId if the status is playing or paused.
294
+     *
295
+     * @param {string} videoId - The youtube id of the video.
296
+     * @param {string} status - The status of the player.
297
+     * @param {number} time - The seek time.
298
+     * @param {string} ownerId - The id of the participant sharing the video.
299
+     * @private
300
+     * @returns {void}
301
+    */
302
+    onVideoChangeEvent(videoId, status, time, ownerId) {
303
+        if (![ 'playing', 'paused' ].includes(status)) {
304
+            return;
155 305
         }
156
-    };
157 306
 
158
-    let playerHeight, playerWidth;
307
+        this.props.dispatch(setSharedVideoStatus(videoId, translateStatus(status), time, ownerId));
308
+    }
159 309
 
160
-    if (props._isWideScreen) {
161
-        playerHeight = props._screenHeight;
162
-        playerWidth = playerHeight * 16 / 9;
163
-    } else {
164
-        playerWidth = props._screenWidth;
165
-        playerHeight = playerWidth * 9 / 16;
310
+    /**
311
+     * Dispatches the 'playing' as video status, time and ownerId.
312
+     *
313
+     * @param {string} videoId - The youtube id of the video.
314
+     * @param {number} time - The seek time.
315
+     * @param {string} ownerId - The id of the participant sharing the video.
316
+     * @private
317
+     * @returns {void}
318
+    */
319
+    onVideoReady(videoId, time, ownerId) {
320
+        time.then(t => this.props.dispatch(setSharedVideoStatus(videoId, 'playing', t, ownerId)));
166 321
     }
167 322
 
168
-    return (
169
-        <View
170
-            pointerEvents = { props._enableControls ? 'auto' : 'none' }
171
-            style = { styles.youtubeVideoContainer } >
172
-            <YoutubePlayer
173
-                height = { playerHeight }
174
-                initialPlayerParams = {{
175
-                    controls: props._enableControls,
176
-                    modestbranding: true,
177
-                    preventFullScreen: true
178
-                }}
179
-                /* eslint-disable react/jsx-no-bind */
180
-                onChangeState = { onChangeState }
181
-                /* eslint-disable react/jsx-no-bind */
182
-                onReady = { onReady }
183
-                play = { props._isPlaying }
184
-                playbackRate = { 1 }
185
-                ref = { playerRef }
186
-                videoId = { props.youtubeId }
187
-                volume = { 50 }
188
-                webViewProps = {{
189
-                    bounces: false,
190
-                    mediaPlaybackRequiresUserAction: false,
191
-                    scrollEnabled: false,
192
-                    userAgent: webviewUserAgent
193
-                }}
194
-                width = { playerWidth } />
195
-        </View>);
196
-};
323
+    /**
324
+     * Dispatches action to set the visibility of the toolbox, true if not widescreen, false otherwise.
325
+     *
326
+     * @param {isWideScreen} isWideScreen - Whether the screen is wide.
327
+     * @private
328
+     * @returns {void}
329
+    */
330
+    setWideScreenMode(isWideScreen) {
331
+        this.props.dispatch(setToolboxVisible(!isWideScreen));
332
+    }
333
+}
197 334
 
198 335
 /* eslint-disable max-params */
199 336
 
@@ -249,64 +386,33 @@ function _mapStateToProps(state) {
249 386
     const { ownerId, status, time } = state['features/youtube-player'];
250 387
     const localParticipant = getLocalParticipant(state);
251 388
     const responsiveUi = state['features/base/responsive-ui'];
252
-    const screenHeight = responsiveUi.clientHeight;
253
-    const screenWidth = responsiveUi.clientWidth;
389
+    const { aspectRatio, clientHeight: screenHeight, clientWidth: screenWidth } = responsiveUi;
390
+    const isWideScreen = aspectRatio === ASPECT_RATIO_WIDE;
391
+
392
+    let playerHeight, playerWidth;
393
+
394
+    if (isWideScreen) {
395
+        playerHeight = screenHeight;
396
+        playerWidth = playerHeight * 16 / 9;
397
+    } else {
398
+        playerWidth = screenWidth;
399
+        playerHeight = playerWidth * 9 / 16;
400
+    }
254 401
 
255 402
     return {
256 403
         _enableControls: ownerId === localParticipant.id,
257 404
         _isOwner: ownerId === localParticipant.id,
258 405
         _isPlaying: status === 'playing',
259 406
         _isStopped: status === 'stop',
260
-        _isWideScreen: responsiveUi.aspectRatio === ASPECT_RATIO_WIDE,
407
+        _isWideScreen: isWideScreen,
261 408
         _ownerId: ownerId,
262
-        _screenHeight: screenHeight,
263
-        _screenWidth: screenWidth,
264
-        _seek: time
265
-    };
266
-}
267
-
268
-/**
269
- * Maps dispatching of some action to React component props.
270
- *
271
- * @param {Function} dispatch - Redux action dispatcher.
272
- * @private
273
- * @returns {{
274
- *     onVideoChangeEvent: Function,
275
- *     onVideoReady: Function,
276
- *     onWideScreenChanged: Function
277
- * }}
278
- */
279
-function _mapDispatchToProps(dispatch) {
280
-    return {
281
-        _onVideoChangeEvent: (videoId, status, time, ownerId) => {
282
-            if (![ 'playing', 'paused' ].includes(status)) {
283
-                return;
284
-            }
285
-            dispatch(setSharedVideoStatus(videoId, translateStatus(status), time, ownerId));
286
-        },
287
-        _onVideoReady: (videoId, time, ownerId) => {
288
-            time.then(t => dispatch(setSharedVideoStatus(videoId, 'playing', t, ownerId)));
289
-        },
290
-        _onWideScreenChanged: isWideScreen => {
291
-            dispatch(setToolboxVisible(!isWideScreen));
292
-        }
409
+        _playerHeight: playerHeight,
410
+        _playerWidth: playerWidth,
411
+        _seek: time,
412
+        _status: status
293 413
     };
294 414
 }
295 415
 
296
-/**
297
- * Maps (parts of) the Redux state to the associated YoutubeLargeVideo's props.
298
- *
299
- * @private
300
- * @returns {Props}
301
- */
302
-function _mergeProps({ _isOwner, ...stateProps }, { _onVideoChangeEvent, _onVideoReady, _onWideScreenChanged }) {
303
-    return Object.assign(stateProps, {
304
-        _onVideoChangeEvent: _isOwner ? _onVideoChangeEvent : () => { /* do nothing */ },
305
-        _onVideoReady: _isOwner ? _onVideoReady : () => { /* do nothing */ },
306
-        _onWideScreenChanged
307
-    });
308
-}
309
-
310 416
 /**
311 417
  * In case the status is 'paused', it is translated to 'pause' to match the web functionality.
312 418
  *
@@ -322,4 +428,4 @@ function translateStatus(status) {
322 428
     return status;
323 429
 }
324 430
 
325
-export default connect(_mapStateToProps, _mapDispatchToProps, _mergeProps)(YoutubeLargeVideo);
431
+export default connect(_mapStateToProps)(YoutubeLargeVideo);

Loading…
Откажи
Сачувај