瀏覽代碼

rn,responsive-ui: refactor dimensions detection

Use a dimensions detecting root component. The Dimensions module does not
measure the app's view size, but the Window, which may not be the same, for
example on iOS when PiP is used.

Also refactor the aspect ratio wrap component since it can be taken directly
from the store.

Last, remove the use of DimensionsDetector on LargeVideo and TileView since they
occupy the full-screen anyway.

Fixes PiP mode on iOS.
master
Saúl Ibarra Corretgé 5 年之前
父節點
當前提交
d740752522

+ 35
- 1
react/features/app/components/App.native.js 查看文件

9
 import { CALL_INTEGRATION_ENABLED, updateFlags } from '../../base/flags';
9
 import { CALL_INTEGRATION_ENABLED, updateFlags } from '../../base/flags';
10
 import '../../base/jwt';
10
 import '../../base/jwt';
11
 import { Platform } from '../../base/react';
11
 import { Platform } from '../../base/react';
12
-import '../../base/responsive-ui';
12
+import { DimensionsDetector, clientResized } from '../../base/responsive-ui';
13
 import { updateSettings } from '../../base/settings';
13
 import { updateSettings } from '../../base/settings';
14
 import '../../google-api';
14
 import '../../google-api';
15
 import '../../mobile/audio-mode';
15
 import '../../mobile/audio-mode';
78
         // This will effectively kill the app. In accord with the Web, do not
78
         // This will effectively kill the app. In accord with the Web, do not
79
         // kill the app.
79
         // kill the app.
80
         this._maybeDisableExceptionsManager();
80
         this._maybeDisableExceptionsManager();
81
+
82
+        // Bind event handler so it is only bound once per instance.
83
+        this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
81
     }
84
     }
82
 
85
 
83
     /**
86
     /**
107
         });
110
         });
108
     }
111
     }
109
 
112
 
113
+    /**
114
+     * Overrides the parent method to inject {@link DimensionsDetector} as
115
+     * the top most component.
116
+     *
117
+     * @override
118
+     */
119
+    _createMainElement(component, props) {
120
+        return (
121
+            <DimensionsDetector
122
+                onDimensionsChanged = { this._onDimensionsChanged }>
123
+                { super._createMainElement(component, props) }
124
+            </DimensionsDetector>
125
+        );
126
+    }
127
+
110
     /**
128
     /**
111
      * Attempts to disable the use of React Native
129
      * Attempts to disable the use of React Native
112
      * {@link ExceptionsManager#handleException} on platforms and in
130
      * {@link ExceptionsManager#handleException} on platforms and in
144
         }
162
         }
145
     }
163
     }
146
 
164
 
165
+    _onDimensionsChanged: (width: number, height: number) => void;
166
+
167
+    /**
168
+     * Updates the known available size for the app to occupy.
169
+     *
170
+     * @param {number} width - The component's current width.
171
+     * @param {number} height - The component's current height.
172
+     * @private
173
+     * @returns {void}
174
+     */
175
+    _onDimensionsChanged(width: number, height: number) {
176
+        const { dispatch } = this.state.store;
177
+
178
+        dispatch(clientResized(width, height));
179
+    }
180
+
147
     /**
181
     /**
148
      * Renders the platform specific dialog container.
182
      * Renders the platform specific dialog container.
149
      *
183
      *

+ 0
- 70
react/features/base/responsive-ui/components/AspectRatioAware.js 查看文件

1
-// @flow
2
-
3
-import React, { Component } from 'react';
4
-
5
-import { connect } from '../../redux';
6
-import { ASPECT_RATIO_NARROW, ASPECT_RATIO_WIDE } from '../constants';
7
-
8
-/**
9
- * The type of the React {@code Component} props of {@link AspectRatioAware}.
10
- */
11
-type Props = {
12
-    aspectRatio: ASPECT_RATIO_NARROW | ASPECT_RATIO_WIDE
13
-};
14
-
15
-/**
16
- * Determines whether a specific React {@code Component} decorated into an
17
- * {@link AspectRatioAware} has {@link ASPECT_RATIO_NARROW} as the value of its
18
- * {@code aspectRatio} React prop.
19
- *
20
- * @param {AspectRatioAware} component - An {@link AspectRatioAware} which may
21
- * have an {@code aspectRatio} React prop.
22
- * @returns {boolean}
23
- */
24
-export function isNarrowAspectRatio(component: React$Component<*>) {
25
-    return component.props.aspectRatio === ASPECT_RATIO_NARROW;
26
-}
27
-
28
-/**
29
- * Decorates a specific React {@code Component} class into an
30
- * {@link AspectRatioAware} which provides the React prop {@code aspectRatio}
31
- * updated on each redux state change.
32
- *
33
- * @param {Class<React$Component>} WrappedComponent - A React {@code Component}
34
- * class to be wrapped.
35
- * @returns {AspectRatioAwareWrapper}
36
- */
37
-export function makeAspectRatioAware(
38
-        WrappedComponent: Class<React$Component<*>>
39
-): Class<React$Component<*>> {
40
-    /**
41
-     * Renders {@code WrappedComponent} with the React prop {@code aspectRatio}.
42
-     */
43
-    class AspectRatioAware extends Component<Props> {
44
-        /**
45
-         * Implement's React render method to wrap the nested component.
46
-         *
47
-         * @returns {React$Element}
48
-         */
49
-        render(): React$Element<*> {
50
-            return <WrappedComponent { ...this.props } />;
51
-        }
52
-    }
53
-
54
-    return connect(_mapStateToProps)(AspectRatioAware);
55
-}
56
-
57
-/**
58
- * Maps (parts of) the redux state to {@link AspectRatioAware} props.
59
- *
60
- * @param {Object} state - The whole redux state.
61
- * @private
62
- * @returns {{
63
- *     aspectRatio: Symbol
64
- * }}
65
- */
66
-function _mapStateToProps(state) {
67
-    return {
68
-        aspectRatio: state['features/base/responsive-ui'].aspectRatio
69
-    };
70
-}

+ 2
- 6
react/features/base/responsive-ui/components/DimensionsDetector.native.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
 import React, { PureComponent } from 'react';
3
 import React, { PureComponent } from 'react';
4
-import { View } from 'react-native';
4
+import { StyleSheet, View } from 'react-native';
5
 
5
 
6
-import styles from './styles';
7
 
6
 
8
-/**
9
- * AspectRatioDetector component's property types.
10
- */
11
 type Props = {
7
 type Props = {
12
 
8
 
13
     /**
9
     /**
64
         return (
60
         return (
65
             <View
61
             <View
66
                 onLayout = { this._onLayout }
62
                 onLayout = { this._onLayout }
67
-                style = { styles.dimensionsDetector } >
63
+                style = { StyleSheet.absoluteFillObject } >
68
                 { this.props.children }
64
                 { this.props.children }
69
             </View>
65
             </View>
70
         );
66
         );

+ 0
- 1
react/features/base/responsive-ui/components/index.js 查看文件

1
-export * from './AspectRatioAware';
2
 export { default as DimensionsDetector } from './DimensionsDetector';
1
 export { default as DimensionsDetector } from './DimensionsDetector';

+ 0
- 14
react/features/base/responsive-ui/components/styles.js 查看文件

1
-import { createStyleSheet } from '../../styles';
2
-
3
-/**
4
- * The styles of the feature base/responsive-ui.
5
- */
6
-export default createStyleSheet({
7
-    /**
8
-     * The style of {@link DimensionsDetector} used on react-native.
9
-     */
10
-    dimensionsDetector: {
11
-        alignSelf: 'stretch',
12
-        flex: 1
13
-    }
14
-});

+ 7
- 59
react/features/base/responsive-ui/middleware.native.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { Dimensions } from 'react-native';
4
-
5
-import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../base/app';
6
 import { MiddlewareRegistry } from '../../base/redux';
3
 import { MiddlewareRegistry } from '../../base/redux';
7
 
4
 
5
+import { CLIENT_RESIZED } from './actionTypes';
8
 import { setAspectRatio, setReducedUI } from './actions';
6
 import { setAspectRatio, setReducedUI } from './actions';
9
 
7
 
10
-/**
11
- * Dimensions change handler.
12
- */
13
-let handler;
14
 
8
 
15
 /**
9
 /**
16
  * Middleware that handles widnow dimension changes and updates the aspect ratio and
10
  * Middleware that handles widnow dimension changes and updates the aspect ratio and
19
  * @param {Store} store - The redux store.
13
  * @param {Store} store - The redux store.
20
  * @returns {Function}
14
  * @returns {Function}
21
  */
15
  */
22
-MiddlewareRegistry.register(store => next => action => {
16
+MiddlewareRegistry.register(({ dispatch }) => next => action => {
23
     const result = next(action);
17
     const result = next(action);
24
 
18
 
25
     switch (action.type) {
19
     switch (action.type) {
26
-    case APP_WILL_UNMOUNT: {
27
-        _appWillUnmount();
20
+    case CLIENT_RESIZED: {
21
+        const { clientWidth: width, clientHeight: height } = action;
22
+
23
+        dispatch(setAspectRatio(width, height));
24
+        dispatch(setReducedUI(width, height));
28
         break;
25
         break;
29
     }
26
     }
30
-    case APP_WILL_MOUNT:
31
-        _appWillMount(store);
32
-        break;
33
 
27
 
34
     }
28
     }
35
 
29
 
36
     return result;
30
     return result;
37
 });
31
 });
38
-
39
-/**
40
- * Notifies this feature that the action {@link APP_WILL_MOUNT} is being
41
- * dispatched within a specific redux {@code store}.
42
- *
43
- * @param {Store} store - The redux store in which the specified {@code action}
44
- * is being dispatched.
45
- * @private
46
- * @returns {void}
47
- */
48
-function _appWillMount(store) {
49
-    handler = dim => {
50
-        _onDimensionsChange(dim, store);
51
-    };
52
-
53
-    Dimensions.addEventListener('change', handler);
54
-}
55
-
56
-/**
57
- * Notifies this feature that the action {@link APP_WILL_UNMOUNT} is being
58
- * dispatched within a specific redux {@code store}.
59
- *
60
- * @private
61
- * @returns {void}
62
- */
63
-function _appWillUnmount() {
64
-    Dimensions.removeEventListener('change', handler);
65
-
66
-    handler = undefined;
67
-}
68
-
69
-/**
70
- * Handles window dimension changes.
71
- *
72
- * @param {Object} dimensions - The new dimensions.
73
- * @param {Store} store - The redux store.
74
- * @private
75
- * @returns {void}
76
- */
77
-function _onDimensionsChange(dimensions, store) {
78
-    const { width, height } = dimensions.window;
79
-    const { dispatch } = store;
80
-
81
-    dispatch(setAspectRatio(width, height));
82
-    dispatch(setReducedUI(width, height));
83
-}

+ 0
- 1
react/features/base/responsive-ui/reducer.js 查看文件

23
 ReducerRegistry.register('features/base/responsive-ui', (state = DEFAULT_STATE, action) => {
23
 ReducerRegistry.register('features/base/responsive-ui', (state = DEFAULT_STATE, action) => {
24
     switch (action.type) {
24
     switch (action.type) {
25
     case CLIENT_RESIZED: {
25
     case CLIENT_RESIZED: {
26
-
27
         return {
26
         return {
28
             ...state,
27
             ...state,
29
             clientWidth: action.clientWidth,
28
             clientWidth: action.clientWidth,

+ 15
- 78
react/features/conference/components/native/Conference.js 查看文件

8
 import { PIP_ENABLED, getFeatureFlag } from '../../../base/flags';
8
 import { PIP_ENABLED, getFeatureFlag } from '../../../base/flags';
9
 import { Container, LoadingIndicator, TintedView } from '../../../base/react';
9
 import { Container, LoadingIndicator, TintedView } from '../../../base/react';
10
 import { connect } from '../../../base/redux';
10
 import { connect } from '../../../base/redux';
11
-import {
12
-    isNarrowAspectRatio,
13
-    makeAspectRatioAware
14
-} from '../../../base/responsive-ui';
11
+import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
15
 import { TestConnectionInfo } from '../../../base/testing';
12
 import { TestConnectionInfo } from '../../../base/testing';
16
 import { ConferenceNotification, isCalendarEnabled } from '../../../calendar-sync';
13
 import { ConferenceNotification, isCalendarEnabled } from '../../../calendar-sync';
17
 import { Chat } from '../../../chat';
14
 import { Chat } from '../../../chat';
45
  */
42
  */
46
 type Props = AbstractProps & {
43
 type Props = AbstractProps & {
47
 
44
 
45
+    /**
46
+     * Application's aspect ratio.
47
+     */
48
+    _aspectRatio: Symbol,
49
+
48
     /**
50
     /**
49
      * Wherther the calendar feature is enabled or not.
51
      * Wherther the calendar feature is enabled or not.
50
-     *
51
-     * @private
52
      */
52
      */
53
     _calendarEnabled: boolean,
53
     _calendarEnabled: boolean,
54
 
54
 
57
      * conference which includes establishing the XMPP connection and then
57
      * conference which includes establishing the XMPP connection and then
58
      * joining the room. If truthy, then an activity/loading indicator will be
58
      * joining the room. If truthy, then an activity/loading indicator will be
59
      * rendered.
59
      * rendered.
60
-     *
61
-     * @private
62
      */
60
      */
63
     _connecting: boolean,
61
     _connecting: boolean,
64
 
62
 
65
     /**
63
     /**
66
      * Set to {@code true} when the filmstrip is currently visible.
64
      * Set to {@code true} when the filmstrip is currently visible.
67
-     *
68
-     * @private
69
      */
65
      */
70
     _filmstripVisible: boolean,
66
     _filmstripVisible: boolean,
71
 
67
 
76
 
72
 
77
     /**
73
     /**
78
      * Whether Picture-in-Picture is enabled.
74
      * Whether Picture-in-Picture is enabled.
79
-     *
80
-     * @private
81
      */
75
      */
82
     _pictureInPictureEnabled: boolean,
76
     _pictureInPictureEnabled: boolean,
83
 
77
 
84
     /**
78
     /**
85
      * The indicator which determines whether the UI is reduced (to accommodate
79
      * The indicator which determines whether the UI is reduced (to accommodate
86
      * smaller display areas).
80
      * smaller display areas).
87
-     *
88
-     * @private
89
      */
81
      */
90
     _reducedUI: boolean,
82
     _reducedUI: boolean,
91
 
83
 
92
-    /**
93
-     * The handler which dispatches the (redux) action {@link setToolboxVisible}
94
-     * to show/hide the {@link Toolbox}.
95
-     *
96
-     * @param {boolean} visible - {@code true} to show the {@code Toolbox} or
97
-     * {@code false} to hide it.
98
-     * @private
99
-     * @returns {void}
100
-     */
101
-    _setToolboxVisible: Function,
102
-
103
     /**
84
     /**
104
      * The indicator which determines whether the Toolbox is visible.
85
      * The indicator which determines whether the Toolbox is visible.
105
-     *
106
-     * @private
107
      */
86
      */
108
     _toolboxVisible: boolean,
87
     _toolboxVisible: boolean,
109
 
88
 
249
      */
228
      */
250
     _renderContent() {
229
     _renderContent() {
251
         const {
230
         const {
231
+            _aspectRatio,
252
             _connecting,
232
             _connecting,
253
             _filmstripVisible,
233
             _filmstripVisible,
254
             _largeVideoParticipantId,
234
             _largeVideoParticipantId,
257
             _toolboxVisible
237
             _toolboxVisible
258
         } = this.props;
238
         } = this.props;
259
         const showGradient = _toolboxVisible;
239
         const showGradient = _toolboxVisible;
260
-        const applyGradientStretching = _filmstripVisible && isNarrowAspectRatio(this) && !_shouldDisplayTileView;
240
+        const applyGradientStretching
241
+            = _filmstripVisible && _aspectRatio === ASPECT_RATIO_NARROW && !_shouldDisplayTileView;
261
 
242
 
262
         if (_reducedUI) {
243
         if (_reducedUI) {
263
             return this._renderContentForReducedUi();
244
             return this._renderContentForReducedUi();
393
         // flex layout. The only option that seemed to limit the notification's
374
         // flex layout. The only option that seemed to limit the notification's
394
         // size was explicit 'width' value which is not better than the margin
375
         // size was explicit 'width' value which is not better than the margin
395
         // added here.
376
         // added here.
396
-        if (this.props._filmstripVisible && !isNarrowAspectRatio(this)) {
377
+        const { _aspectRatio, _filmstripVisible } = this.props;
378
+
379
+        if (_filmstripVisible && _aspectRatio !== ASPECT_RATIO_NARROW) {
397
             notificationsStyle.marginRight = FILMSTRIP_SIZE;
380
             notificationsStyle.marginRight = FILMSTRIP_SIZE;
398
         }
381
         }
399
 
382
 
433
         joining,
416
         joining,
434
         leaving
417
         leaving
435
     } = state['features/base/conference'];
418
     } = state['features/base/conference'];
436
-    const { reducedUI } = state['features/base/responsive-ui'];
419
+    const { aspectRatio, reducedUI } = state['features/base/responsive-ui'];
437
 
420
 
438
     // XXX There is a window of time between the successful establishment of the
421
     // XXX There is a window of time between the successful establishment of the
439
     // XMPP connection and the subsequent commencement of joining the MUC during
422
     // XMPP connection and the subsequent commencement of joining the MUC during
449
 
432
 
450
     return {
433
     return {
451
         ...abstractMapStateToProps(state),
434
         ...abstractMapStateToProps(state),
452
-
453
-        /**
454
-         * Wherther the calendar feature is enabled or not.
455
-         *
456
-         * @private
457
-         * @type {boolean}
458
-         */
435
+        _aspectRatio: aspectRatio,
459
         _calendarEnabled: isCalendarEnabled(state),
436
         _calendarEnabled: isCalendarEnabled(state),
460
-
461
-        /**
462
-         * The indicator which determines that we are still connecting to the
463
-         * conference which includes establishing the XMPP connection and then
464
-         * joining the room. If truthy, then an activity/loading indicator will
465
-         * be rendered.
466
-         *
467
-         * @private
468
-         * @type {boolean}
469
-         */
470
         _connecting: Boolean(connecting_),
437
         _connecting: Boolean(connecting_),
471
-
472
-        /**
473
-         * Is {@code true} when the filmstrip is currently visible.
474
-         */
475
         _filmstripVisible: isFilmstripVisible(state),
438
         _filmstripVisible: isFilmstripVisible(state),
476
-
477
-        /**
478
-         * The ID of the participant currently on stage.
479
-         */
480
         _largeVideoParticipantId: state['features/large-video'].participantId,
439
         _largeVideoParticipantId: state['features/large-video'].participantId,
481
-
482
-        /**
483
-         * Whether Picture-in-Picture is enabled.
484
-         *
485
-         * @private
486
-         * @type {boolean}
487
-         */
488
         _pictureInPictureEnabled: getFeatureFlag(state, PIP_ENABLED),
440
         _pictureInPictureEnabled: getFeatureFlag(state, PIP_ENABLED),
489
-
490
-        /**
491
-         * The indicator which determines whether the UI is reduced (to
492
-         * accommodate smaller display areas).
493
-         *
494
-         * @private
495
-         * @type {boolean}
496
-         */
497
         _reducedUI: reducedUI,
441
         _reducedUI: reducedUI,
498
-
499
-        /**
500
-         * The indicator which determines whether the Toolbox is visible.
501
-         *
502
-         * @private
503
-         * @type {boolean}
504
-         */
505
         _toolboxVisible: isToolboxVisible(state)
442
         _toolboxVisible: isToolboxVisible(state)
506
     };
443
     };
507
 }
444
 }
508
 
445
 
509
-export default connect(_mapStateToProps)(makeAspectRatioAware(Conference));
446
+export default connect(_mapStateToProps)(Conference);

+ 15
- 11
react/features/conference/components/native/Labels.js 查看文件

5
 
5
 
6
 import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
6
 import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
7
 import { connect } from '../../../base/redux';
7
 import { connect } from '../../../base/redux';
8
-import {
9
-    isNarrowAspectRatio,
10
-    makeAspectRatioAware
11
-} from '../../../base/responsive-ui';
8
+import { ASPECT_RATIO_WIDE } from '../../../base/responsive-ui/constants';
12
 import {
9
 import {
13
     RecordingExpandedLabel
10
     RecordingExpandedLabel
14
 } from '../../../recording';
11
 } from '../../../recording';
29
 type Props = AbstractLabelsProps & {
26
 type Props = AbstractLabelsProps & {
30
 
27
 
31
     /**
28
     /**
32
-     * Function to translate i18n labels.
29
+     * Application's aspect ratio.
33
      */
30
      */
34
-    t: Function,
31
+    _aspectRatio: Symbol,
35
 
32
 
36
     /**
33
     /**
37
      * True if the labels should be visible, false otherwise.
34
      * True if the labels should be visible, false otherwise.
38
      */
35
      */
39
-    _visible: boolean
36
+    _visible: boolean,
37
+
38
+    /**
39
+     * Function to translate i18n labels.
40
+     */
41
+    t: Function
40
 };
42
 };
41
 
43
 
42
 type State = {
44
 type State = {
149
      * @inheritdoc
151
      * @inheritdoc
150
      */
152
      */
151
     render() {
153
     render() {
152
-        if (!this.props._visible) {
154
+        const { _aspectRatio, _filmstripVisible, _visible } = this.props;
155
+
156
+        if (!_visible) {
153
             return null;
157
             return null;
154
         }
158
         }
155
 
159
 
156
-        const wide = !isNarrowAspectRatio(this);
157
-        const { _filmstripVisible } = this.props;
160
+        const wide = _aspectRatio === ASPECT_RATIO_WIDE;
158
 
161
 
159
         return (
162
         return (
160
             <View
163
             <View
354
 function _mapStateToProps(state) {
357
 function _mapStateToProps(state) {
355
     return {
358
     return {
356
         ..._abstractMapStateToProps(state),
359
         ..._abstractMapStateToProps(state),
360
+        _aspectRatio: state['features/base/responsive-ui'].aspectRatio,
357
         _visible: !shouldDisplayNotifications(state)
361
         _visible: !shouldDisplayNotifications(state)
358
     };
362
     };
359
 }
363
 }
360
 
364
 
361
-export default connect(_mapStateToProps)(makeAspectRatioAware(Labels));
365
+export default connect(_mapStateToProps)(Labels);

+ 1
- 2
react/features/conference/components/web/Labels.js 查看文件

41
      */
41
      */
42
     static getDerivedStateFromProps(props: Props, prevState: State) {
42
     static getDerivedStateFromProps(props: Props, prevState: State) {
43
         return {
43
         return {
44
-            filmstripBecomingVisible: !prevState.filmstripBecomingVisible
45
-                && props._filmstripVisible
44
+            filmstripBecomingVisible: !prevState.filmstripBecomingVisible && props._filmstripVisible
46
         };
45
         };
47
     }
46
     }
48
 
47
 

+ 24
- 58
react/features/filmstrip/components/native/Filmstrip.js 查看文件

5
 
5
 
6
 import { Container, Platform } from '../../../base/react';
6
 import { Container, Platform } from '../../../base/react';
7
 import { connect } from '../../../base/redux';
7
 import { connect } from '../../../base/redux';
8
-import {
9
-    isNarrowAspectRatio,
10
-    makeAspectRatioAware
11
-} from '../../../base/responsive-ui';
8
+import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
12
 import { isFilmstripVisible } from '../../functions';
9
 import { isFilmstripVisible } from '../../functions';
13
 
10
 
14
 import LocalThumbnail from './LocalThumbnail';
11
 import LocalThumbnail from './LocalThumbnail';
20
  */
17
  */
21
 type Props = {
18
 type Props = {
22
 
19
 
20
+    /**
21
+     * Application's aspect ratio.
22
+     */
23
+    _aspectRatio: Symbol,
24
+
23
     /**
25
     /**
24
      * The indicator which determines whether the filmstrip is enabled.
26
      * The indicator which determines whether the filmstrip is enabled.
25
-     *
26
-     * @private
27
      */
27
      */
28
     _enabled: boolean,
28
     _enabled: boolean,
29
 
29
 
30
     /**
30
     /**
31
      * The participants in the conference.
31
      * The participants in the conference.
32
-     *
33
-     * @private
34
      */
32
      */
35
     _participants: Array<any>,
33
     _participants: Array<any>,
36
 
34
 
37
     /**
35
     /**
38
      * The indicator which determines whether the filmstrip is visible.
36
      * The indicator which determines whether the filmstrip is visible.
39
-     *
40
-     * @private
41
      */
37
      */
42
     _visible: boolean
38
     _visible: boolean
43
 };
39
 };
90
      * @returns {ReactElement}
86
      * @returns {ReactElement}
91
      */
87
      */
92
     render() {
88
     render() {
93
-        if (!this.props._enabled) {
89
+        const { _aspectRatio, _enabled, _participants, _visible } = this.props;
90
+
91
+        if (!_enabled) {
94
             return null;
92
             return null;
95
         }
93
         }
96
 
94
 
97
-        const isNarrowAspectRatio_ = isNarrowAspectRatio(this);
98
-        const filmstripStyle
99
-            = isNarrowAspectRatio_
100
-                ? styles.filmstripNarrow
101
-                : styles.filmstripWide;
95
+        const isNarrowAspectRatio = _aspectRatio === ASPECT_RATIO_NARROW;
96
+        const filmstripStyle = isNarrowAspectRatio ? styles.filmstripNarrow : styles.filmstripWide;
102
 
97
 
103
         return (
98
         return (
104
             <Container
99
             <Container
105
                 style = { filmstripStyle }
100
                 style = { filmstripStyle }
106
-                visible = { this.props._visible }>
101
+                visible = { _visible }>
107
                 {
102
                 {
108
                     this._separateLocalThumbnail
103
                     this._separateLocalThumbnail
109
-                        && !isNarrowAspectRatio_
104
+                        && !isNarrowAspectRatio
110
                         && <LocalThumbnail />
105
                         && <LocalThumbnail />
111
                 }
106
                 }
112
                 <ScrollView
107
                 <ScrollView
113
-                    horizontal = { isNarrowAspectRatio_ }
108
+                    horizontal = { isNarrowAspectRatio }
114
                     showsHorizontalScrollIndicator = { false }
109
                     showsHorizontalScrollIndicator = { false }
115
                     showsVerticalScrollIndicator = { false }
110
                     showsVerticalScrollIndicator = { false }
116
                     style = { styles.scrollView } >
111
                     style = { styles.scrollView } >
117
                     {
112
                     {
118
-                        !this._separateLocalThumbnail
119
-                            && !isNarrowAspectRatio_
113
+                        !this._separateLocalThumbnail && !isNarrowAspectRatio
120
                             && <LocalThumbnail />
114
                             && <LocalThumbnail />
121
                     }
115
                     }
122
                     {
116
                     {
123
 
117
 
124
-                        this._sort(
125
-                                this.props._participants,
126
-                                isNarrowAspectRatio_)
118
+                        this._sort(_participants, isNarrowAspectRatio)
127
                             .map(p => (
119
                             .map(p => (
128
                                 <Thumbnail
120
                                 <Thumbnail
129
                                     key = { p.id }
121
                                     key = { p.id }
131
 
123
 
132
                     }
124
                     }
133
                     {
125
                     {
134
-                        !this._separateLocalThumbnail
135
-                            && isNarrowAspectRatio_
126
+                        !this._separateLocalThumbnail && isNarrowAspectRatio
136
                             && <LocalThumbnail />
127
                             && <LocalThumbnail />
137
                     }
128
                     }
138
                 </ScrollView>
129
                 </ScrollView>
139
                 {
130
                 {
140
-                    this._separateLocalThumbnail
141
-                        && isNarrowAspectRatio_
131
+                    this._separateLocalThumbnail && isNarrowAspectRatio
142
                         && <LocalThumbnail />
132
                         && <LocalThumbnail />
143
                 }
133
                 }
144
             </Container>
134
             </Container>
150
      *
140
      *
151
      * @param {Participant[]} participants - The array of {@code Participant}s
141
      * @param {Participant[]} participants - The array of {@code Participant}s
152
      * to sort in display order.
142
      * to sort in display order.
153
-     * @param {boolean} isNarrowAspectRatio_ - Indicates if the aspect ratio is
143
+     * @param {boolean} isNarrowAspectRatio - Indicates if the aspect ratio is
154
      * wide or narrow.
144
      * wide or narrow.
155
      * @private
145
      * @private
156
      * @returns {Participant[]} A new array containing the elements of the
146
      * @returns {Participant[]} A new array containing the elements of the
157
      * specified {@code participants} array sorted in display order.
147
      * specified {@code participants} array sorted in display order.
158
      */
148
      */
159
-    _sort(participants, isNarrowAspectRatio_) {
149
+    _sort(participants, isNarrowAspectRatio) {
160
         // XXX Array.prototype.sort() is not appropriate because (1) it operates
150
         // XXX Array.prototype.sort() is not appropriate because (1) it operates
161
         // in place and (2) it is not necessarily stable.
151
         // in place and (2) it is not necessarily stable.
162
 
152
 
164
             ...participants
154
             ...participants
165
         ];
155
         ];
166
 
156
 
167
-        if (isNarrowAspectRatio_) {
157
+        if (isNarrowAspectRatio) {
168
             // When the narrow aspect ratio is used, we want to have the remote
158
             // When the narrow aspect ratio is used, we want to have the remote
169
             // participants from right to left with the newest added/joined to
159
             // participants from right to left with the newest added/joined to
170
             // the leftmost side. The local participant is the leftmost item.
160
             // the leftmost side. The local participant is the leftmost item.
180
  *
170
  *
181
  * @param {Object} state - The redux state.
171
  * @param {Object} state - The redux state.
182
  * @private
172
  * @private
183
- * @returns {{
184
- *     _participants: Participant[],
185
- *     _visible: boolean
186
- * }}
173
+ * @returns {Props}
187
  */
174
  */
188
 function _mapStateToProps(state) {
175
 function _mapStateToProps(state) {
189
     const participants = state['features/base/participants'];
176
     const participants = state['features/base/participants'];
190
     const { enabled } = state['features/filmstrip'];
177
     const { enabled } = state['features/filmstrip'];
191
 
178
 
192
     return {
179
     return {
193
-        /**
194
-         * The indicator which determines whether the filmstrip is enabled.
195
-         *
196
-         * @private
197
-         * @type {boolean}
198
-         */
180
+        _aspectRatio: state['features/base/responsive-ui'].aspectRatio,
199
         _enabled: enabled,
181
         _enabled: enabled,
200
-
201
-        /**
202
-         * The remote participants in the conference.
203
-         *
204
-         * @private
205
-         * @type {Participant[]}
206
-         */
207
         _participants: participants.filter(p => !p.local),
182
         _participants: participants.filter(p => !p.local),
208
-
209
-        /**
210
-         * The indicator which determines whether the filmstrip is visible. The
211
-         * mobile/react-native Filmstrip is visible when there are at least 2
212
-         * participants in the conference (including the local one).
213
-         *
214
-         * @private
215
-         * @type {boolean}
216
-         */
217
         _visible: isFilmstripVisible(state)
183
         _visible: isFilmstripVisible(state)
218
     };
184
     };
219
 }
185
 }
220
 
186
 
221
-export default connect(_mapStateToProps)(makeAspectRatioAware(Filmstrip));
187
+export default connect(_mapStateToProps)(Filmstrip);

+ 49
- 94
react/features/filmstrip/components/native/TileView.js 查看文件

13
     setMaxReceiverVideoQuality
13
     setMaxReceiverVideoQuality
14
 } from '../../../base/conference';
14
 } from '../../../base/conference';
15
 import { connect } from '../../../base/redux';
15
 import { connect } from '../../../base/redux';
16
-import {
17
-    DimensionsDetector,
18
-    isNarrowAspectRatio,
19
-    makeAspectRatioAware
20
-} from '../../../base/responsive-ui';
16
+import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
21
 
17
 
22
 import Thumbnail from './Thumbnail';
18
 import Thumbnail from './Thumbnail';
23
 import styles from './styles';
19
 import styles from './styles';
28
 type Props = {
24
 type Props = {
29
 
25
 
30
     /**
26
     /**
31
-     * The participants in the conference.
27
+     * Application's aspect ratio.
32
      */
28
      */
33
-    _participants: Array<Object>,
29
+    _aspectRatio: Symbol,
34
 
30
 
35
     /**
31
     /**
36
-     * Invoked to update the receiver video quality.
32
+     * Application's viewport height.
37
      */
33
      */
38
-    dispatch: Dispatch<any>,
34
+    _height: number,
39
 
35
 
40
     /**
36
     /**
41
-     * Callback to invoke when tile view is tapped.
37
+     * The participants in the conference.
42
      */
38
      */
43
-    onClick: Function
44
-};
39
+    _participants: Array<Object>,
45
 
40
 
46
-/**
47
- * The type of the React {@link Component} state of {@link TileView}.
48
- */
49
-type State = {
41
+    /**
42
+     * Application's viewport height.
43
+     */
44
+    _width: number,
50
 
45
 
51
     /**
46
     /**
52
-     * The available width for {@link TileView} to occupy.
47
+     * Invoked to update the receiver video quality.
53
      */
48
      */
54
-    height: number,
49
+    dispatch: Dispatch<any>,
55
 
50
 
56
     /**
51
     /**
57
-     * The available height for {@link TileView} to occupy.
52
+     * Callback to invoke when tile view is tapped.
58
      */
53
      */
59
-    width: number
54
+    onClick: Function
60
 };
55
 };
61
 
56
 
62
 /**
57
 /**
82
  *
77
  *
83
  * @extends Component
78
  * @extends Component
84
  */
79
  */
85
-class TileView extends Component<Props, State> {
86
-    state = {
87
-        height: 0,
88
-        width: 0
89
-    };
90
-
91
-    /**
92
-     * Initializes a new {@code TileView} instance.
93
-     *
94
-     * @param {Object} props - The read-only properties with which the new
95
-     * instance is to be initialized.
96
-     */
97
-    constructor(props: Props) {
98
-        super(props);
99
-
100
-        // Bind event handler so it is only bound once per instance.
101
-        this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
102
-    }
103
-
80
+class TileView extends Component<Props> {
104
     /**
81
     /**
105
      * Implements React's {@link Component#componentDidMount}.
82
      * Implements React's {@link Component#componentDidMount}.
106
      *
83
      *
126
      * @returns {ReactElement}
103
      * @returns {ReactElement}
127
      */
104
      */
128
     render() {
105
     render() {
129
-        const { onClick } = this.props;
130
-        const { height, width } = this.state;
131
-        const rowElements = this._groupIntoRows(
132
-            this._renderThumbnails(), this._getColumnCount());
106
+        const { _height, _width, onClick } = this.props;
107
+        const rowElements = this._groupIntoRows(this._renderThumbnails(), this._getColumnCount());
133
 
108
 
134
         return (
109
         return (
135
-            <DimensionsDetector
136
-                onDimensionsChanged = { this._onDimensionsChanged }>
137
-                <ScrollView
138
-                    style = {{
139
-                        ...styles.tileView,
140
-                        height,
141
-                        width
142
-                    }}>
143
-                    <TouchableWithoutFeedback onPress = { onClick }>
144
-                        <View
145
-                            style = {{
146
-                                ...styles.tileViewRows,
147
-                                minHeight: height,
148
-                                minWidth: width
149
-                            }}>
150
-                            { rowElements }
151
-                        </View>
152
-                    </TouchableWithoutFeedback>
153
-                </ScrollView>
154
-            </DimensionsDetector>
110
+            <ScrollView
111
+                style = {{
112
+                    ...styles.tileView,
113
+                    height: _height,
114
+                    width: _width
115
+                }}>
116
+                <TouchableWithoutFeedback onPress = { onClick }>
117
+                    <View
118
+                        style = {{
119
+                            ...styles.tileViewRows,
120
+                            minHeight: _height,
121
+                            minWidth: _width
122
+                        }}>
123
+                        { rowElements }
124
+                    </View>
125
+                </TouchableWithoutFeedback>
126
+            </ScrollView>
155
         );
127
         );
156
     }
128
     }
157
 
129
 
167
         // For narrow view, tiles should stack on top of each other for a lonely
139
         // For narrow view, tiles should stack on top of each other for a lonely
168
         // call and a 1:1 call. Otherwise tiles should be grouped into rows of
140
         // call and a 1:1 call. Otherwise tiles should be grouped into rows of
169
         // two.
141
         // two.
170
-        if (isNarrowAspectRatio(this)) {
142
+        if (this.props._aspectRatio === ASPECT_RATIO_NARROW) {
171
             return participantCount >= 3 ? 2 : 1;
143
             return participantCount >= 3 ? 2 : 1;
172
         }
144
         }
173
 
145
 
209
      * @returns {Object}
181
      * @returns {Object}
210
      */
182
      */
211
     _getTileDimensions() {
183
     _getTileDimensions() {
212
-        const { _participants } = this.props;
213
-        const { height, width } = this.state;
184
+        const { _height, _participants, _width } = this.props;
214
         const columns = this._getColumnCount();
185
         const columns = this._getColumnCount();
215
         const participantCount = _participants.length;
186
         const participantCount = _participants.length;
216
-        const heightToUse = height - (MARGIN * 2);
217
-        const widthToUse = width - (MARGIN * 2);
187
+        const heightToUse = _height - (MARGIN * 2);
188
+        const widthToUse = _width - (MARGIN * 2);
218
         let tileWidth;
189
         let tileWidth;
219
 
190
 
220
         // If there is going to be at least two rows, ensure that at least two
191
         // If there is going to be at least two rows, ensure that at least two
221
         // rows display fully on screen.
192
         // rows display fully on screen.
222
         if (participantCount / columns > 1) {
193
         if (participantCount / columns > 1) {
223
-            tileWidth
224
-                = Math.min(widthToUse / columns, heightToUse / 2);
194
+            tileWidth = Math.min(widthToUse / columns, heightToUse / 2);
225
         } else {
195
         } else {
226
             tileWidth = Math.min(widthToUse / columns, heightToUse);
196
             tileWidth = Math.min(widthToUse / columns, heightToUse);
227
         }
197
         }
247
 
217
 
248
         for (let i = 0; i < thumbnails.length; i++) {
218
         for (let i = 0; i < thumbnails.length; i++) {
249
             if (i % rowLength === 0) {
219
             if (i % rowLength === 0) {
250
-                const thumbnailsInRow
251
-                    = thumbnails.slice(i, i + rowLength);
220
+                const thumbnailsInRow = thumbnails.slice(i, i + rowLength);
252
 
221
 
253
                 rowElements.push(
222
                 rowElements.push(
254
                     <View
223
                     <View
263
         return rowElements;
232
         return rowElements;
264
     }
233
     }
265
 
234
 
266
-    _onDimensionsChanged: (width: number, height: number) => void;
267
-
268
-    /**
269
-     * Updates the known available state for {@link TileView} to occupy.
270
-     *
271
-     * @param {number} width - The component's current width.
272
-     * @param {number} height - The component's current height.
273
-     * @private
274
-     * @returns {void}
275
-     */
276
-    _onDimensionsChanged(width: number, height: number) {
277
-        this.setState({
278
-            height,
279
-            width
280
-        });
281
-    }
282
-
283
     /**
235
     /**
284
      * Creates React Elements to display each participant in a thumbnail. Each
236
      * Creates React Elements to display each participant in a thumbnail. Each
285
      * tile will be.
237
      * tile will be.
326
  *
278
  *
327
  * @param {Object} state - The redux state.
279
  * @param {Object} state - The redux state.
328
  * @private
280
  * @private
329
- * @returns {{
330
- *     _participants: Participant[]
331
- * }}
281
+ * @returns {Props}
332
  */
282
  */
333
 function _mapStateToProps(state) {
283
 function _mapStateToProps(state) {
284
+    const responsiveUi = state['features/base/responsive-ui'];
285
+
334
     return {
286
     return {
335
-        _participants: state['features/base/participants']
287
+        _aspectRatio: responsiveUi.aspectRatio,
288
+        _height: responsiveUi.clientHeight,
289
+        _participants: state['features/base/participants'],
290
+        _width: responsiveUi.clientWidth
336
     };
291
     };
337
 }
292
 }
338
 
293
 
339
-export default connect(_mapStateToProps)(makeAspectRatioAware(TileView));
294
+export default connect(_mapStateToProps)(TileView);

+ 36
- 46
react/features/large-video/components/LargeVideo.native.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import React, { Component } from 'react';
3
+import React, { PureComponent } from 'react';
4
 
4
 
5
 import { ColorSchemeRegistry } from '../../base/color-scheme';
5
 import { ColorSchemeRegistry } from '../../base/color-scheme';
6
 import { ParticipantView } from '../../base/participants';
6
 import { ParticipantView } from '../../base/participants';
7
 import { connect } from '../../base/redux';
7
 import { connect } from '../../base/redux';
8
-import { DimensionsDetector } from '../../base/responsive-ui';
9
 import { StyleType } from '../../base/styles';
8
 import { StyleType } from '../../base/styles';
10
 
9
 
11
 import { AVATAR_SIZE } from './styles';
10
 import { AVATAR_SIZE } from './styles';
15
  */
14
  */
16
 type Props = {
15
 type Props = {
17
 
16
 
17
+    /**
18
+     * Application's viewport height.
19
+     */
20
+    _height: number,
21
+
18
     /**
22
     /**
19
      * The ID of the participant (to be) depicted by LargeVideo.
23
      * The ID of the participant (to be) depicted by LargeVideo.
20
      *
24
      *
27
      */
31
      */
28
     _styles: StyleType,
32
     _styles: StyleType,
29
 
33
 
34
+    /**
35
+     * Application's viewport height.
36
+     */
37
+    _width: number,
38
+
30
     /**
39
     /**
31
      * Callback to invoke when the {@code LargeVideo} is clicked/pressed.
40
      * Callback to invoke when the {@code LargeVideo} is clicked/pressed.
32
      */
41
      */
62
  *
71
  *
63
  * @extends Component
72
  * @extends Component
64
  */
73
  */
65
-class LargeVideo extends Component<Props, State> {
74
+class LargeVideo extends PureComponent<Props, State> {
66
     state = {
75
     state = {
67
         ...DEFAULT_STATE
76
         ...DEFAULT_STATE
68
     };
77
     };
69
 
78
 
70
-    /** Initializes a new {@code LargeVideo} instance.
71
-     *
72
-     * @param {Object} props - The read-only properties with which the new
73
-     * instance is to be initialized.
74
-     */
75
-    constructor(props: Props) {
76
-        super(props);
77
-
78
-        // Bind event handlers so they are only bound once per instance.
79
-        this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
80
-    }
81
-
82
-    _onDimensionsChanged: (width: number, height: number) => void;
83
-
84
     /**
79
     /**
85
-     * Handle this component's dimension changes. In case we deem it's too
80
+     * Handles dimension changes. In case we deem it's too
86
      * small, the connectivity indicator won't be rendered and the avatar
81
      * small, the connectivity indicator won't be rendered and the avatar
87
      * will occupy the entirety of the available screen state.
82
      * will occupy the entirety of the available screen state.
88
      *
83
      *
89
-     * @param {number} width - The component's current width.
90
-     * @param {number} height - The component's current height.
91
-     * @private
92
-     * @returns {void}
84
+     * @inheritdoc
93
      */
85
      */
94
-    _onDimensionsChanged(width: number, height: number) {
86
+    static getDerivedStateFromProps(props: Props) {
87
+        const { _height, _width } = props;
88
+
95
         // Get the size, rounded to the nearest even number.
89
         // Get the size, rounded to the nearest even number.
96
-        const size = 2 * Math.round(Math.min(height, width) / 2);
97
-        let nextState;
90
+        const size = 2 * Math.round(Math.min(_height, _width) / 2);
98
 
91
 
99
         if (size < AVATAR_SIZE * 1.5) {
92
         if (size < AVATAR_SIZE * 1.5) {
100
-            nextState = {
93
+            return {
101
                 avatarSize: size - 15, // Leave some margin.
94
                 avatarSize: size - 15, // Leave some margin.
102
                 useConnectivityInfoLabel: false
95
                 useConnectivityInfoLabel: false
103
             };
96
             };
104
-        } else {
105
-            nextState = DEFAULT_STATE;
106
         }
97
         }
107
 
98
 
108
-        this.setState(nextState);
99
+        return DEFAULT_STATE;
100
+
109
     }
101
     }
110
 
102
 
111
     /**
103
     /**
126
         } = this.props;
118
         } = this.props;
127
 
119
 
128
         return (
120
         return (
129
-            <DimensionsDetector
130
-                onDimensionsChanged = { this._onDimensionsChanged }>
131
-                <ParticipantView
132
-                    avatarSize = { avatarSize }
133
-                    onPress = { onClick }
134
-                    participantId = { _participantId }
135
-                    style = { _styles.largeVideo }
136
-                    testHintId = 'org.jitsi.meet.LargeVideo'
137
-                    useConnectivityInfoLabel = { useConnectivityInfoLabel }
138
-                    zOrder = { 0 }
139
-                    zoomEnabled = { true } />
140
-            </DimensionsDetector>
121
+            <ParticipantView
122
+                avatarSize = { avatarSize }
123
+                onPress = { onClick }
124
+                participantId = { _participantId }
125
+                style = { _styles.largeVideo }
126
+                testHintId = 'org.jitsi.meet.LargeVideo'
127
+                useConnectivityInfoLabel = { useConnectivityInfoLabel }
128
+                zOrder = { 0 }
129
+                zoomEnabled = { true } />
141
         );
130
         );
142
     }
131
     }
143
 }
132
 }
147
  *
136
  *
148
  * @param {Object} state - Redux state.
137
  * @param {Object} state - Redux state.
149
  * @private
138
  * @private
150
- * @returns {{
151
- *     _participantId: string,
152
- *     _styles: StyleType
153
- * }}
139
+ * @returns {Props}
154
  */
140
  */
155
 function _mapStateToProps(state) {
141
 function _mapStateToProps(state) {
142
+    const { clientHeight: height, clientWidth: width } = state['features/base/responsive-ui'];
143
+
156
     return {
144
     return {
145
+        _height: height,
157
         _participantId: state['features/large-video'].participantId,
146
         _participantId: state['features/large-video'].participantId,
158
-        _styles: ColorSchemeRegistry.get(state, 'LargeVideo')
147
+        _styles: ColorSchemeRegistry.get(state, 'LargeVideo'),
148
+        _width: width
159
     };
149
     };
160
 }
150
 }
161
 
151
 

Loading…
取消
儲存