Selaa lähdekoodia

feat(RN-filmtrip) stop reordering small meetings

master
Hristo Terezov 3 vuotta sitten
vanhempi
commit
adef5095da
No account linked to committer's email address

+ 27
- 5
react/features/app/components/App.native.js Näytä tiedosto

@@ -1,6 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import React from 'react';
4
+import { SafeAreaProvider } from 'react-native-safe-area-context';
4 5
 import SplashScreen from 'react-native-splash-screen';
5 6
 
6 7
 import { DialogContainer } from '../../base/dialog';
@@ -8,7 +9,7 @@ import { updateFlags } from '../../base/flags/actions';
8 9
 import { CALL_INTEGRATION_ENABLED, SERVER_URL_CHANGE_ENABLED } from '../../base/flags/constants';
9 10
 import { getFeatureFlag } from '../../base/flags/functions';
10 11
 import { Platform } from '../../base/react';
11
-import { DimensionsDetector, clientResized } from '../../base/responsive-ui';
12
+import { DimensionsDetector, clientResized, setSafeAreaInsets } from '../../base/responsive-ui';
12 13
 import { updateSettings } from '../../base/settings';
13 14
 import { _getRouteToRender } from '../getRouteToRender.native';
14 15
 import logger from '../logger';
@@ -76,6 +77,7 @@ export class App extends AbstractApp {
76 77
 
77 78
         // Bind event handler so it is only bound once per instance.
78 79
         this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
80
+        this._onSafeAreaInsetsChanged = this._onSafeAreaInsetsChanged.bind(this);
79 81
     }
80 82
 
81 83
     /**
@@ -138,10 +140,13 @@ export class App extends AbstractApp {
138 140
      */
139 141
     _createMainElement(component, props) {
140 142
         return (
141
-            <DimensionsDetector
142
-                onDimensionsChanged = { this._onDimensionsChanged }>
143
-                { super._createMainElement(component, props) }
144
-            </DimensionsDetector>
143
+            <SafeAreaProvider>
144
+                <DimensionsDetector
145
+                    onDimensionsChanged = { this._onDimensionsChanged }
146
+                    onSafeAreaInsetsChanged = { this._onSafeAreaInsetsChanged }>
147
+                    { super._createMainElement(component, props) }
148
+                </DimensionsDetector>
149
+            </SafeAreaProvider>
145 150
         );
146 151
     }
147 152
 
@@ -198,6 +203,23 @@ export class App extends AbstractApp {
198 203
         dispatch(clientResized(width, height));
199 204
     }
200 205
 
206
+    /**
207
+     * Updates the safe are insets values.
208
+     *
209
+     * @param {Object} insets - The insets.
210
+     * @param {number} insets.top - The top inset.
211
+     * @param {number} insets.right - The right inset.
212
+     * @param {number} insets.bottom - The bottom inset.
213
+     * @param {number} insets.left - The left inset.
214
+     * @private
215
+     * @returns {void}
216
+     */
217
+    _onSafeAreaInsetsChanged(insets) {
218
+        const { dispatch } = this.state.store;
219
+
220
+        dispatch(setSafeAreaInsets(insets));
221
+    }
222
+
201 223
     /**
202 224
      * Renders the platform specific dialog container.
203 225
      *

+ 10
- 0
react/features/base/responsive-ui/actionTypes.ts Näytä tiedosto

@@ -7,6 +7,16 @@
7 7
  */
8 8
 export const CLIENT_RESIZED = 'CLIENT_RESIZED';
9 9
 
10
+/**
11
+ * The type of (redux) action which indicates that the insets from the SafeAreaProvider have changed.
12
+ *
13
+ * {
14
+ *    type: SAFE_AREA_INSETS_CHANGED,
15
+ *    insets: Object
16
+ * }
17
+ */
18
+ export const SAFE_AREA_INSETS_CHANGED = 'SAFE_AREA_INSETS_CHANGED';
19
+
10 20
 /**
11 21
  * The type of (redux) action which sets the aspect ratio of the app's user
12 22
  * interface.

+ 23
- 1
react/features/base/responsive-ui/actions.js Näytä tiedosto

@@ -7,7 +7,13 @@ import { CHAT_SIZE } from '../../chat/constants';
7 7
 import { getParticipantsPaneOpen } from '../../participants-pane/functions';
8 8
 import theme from '../components/themes/participantsPaneTheme.json';
9 9
 
10
-import { CLIENT_RESIZED, SET_ASPECT_RATIO, SET_CONTEXT_MENU_OPEN, SET_REDUCED_UI } from './actionTypes';
10
+import {
11
+    CLIENT_RESIZED,
12
+    SAFE_AREA_INSETS_CHANGED,
13
+    SET_ASPECT_RATIO,
14
+    SET_CONTEXT_MENU_OPEN,
15
+    SET_REDUCED_UI
16
+} from './actionTypes';
11 17
 import { ASPECT_RATIO_NARROW, ASPECT_RATIO_WIDE } from './constants';
12 18
 
13 19
 /**
@@ -123,3 +129,19 @@ export function setParticipantContextMenuOpen(isOpen: boolean) {
123 129
         isOpen
124 130
     };
125 131
 }
132
+
133
+/**
134
+ * Sets the insets from the SafeAreaProvider.
135
+ *
136
+ * @param {Object} insets - The new insets to be set.
137
+ * @returns {{
138
+ *    type: SAFE_AREA_INSETS_CHANGED,
139
+ *    insets: Object
140
+ * }}
141
+ */
142
+export function setSafeAreaInsets(insets) {
143
+    return {
144
+        type: SAFE_AREA_INSETS_CHANGED,
145
+        insets
146
+    };
147
+}

+ 31
- 33
react/features/base/responsive-ui/components/DimensionsDetector.native.js Näytä tiedosto

@@ -1,8 +1,8 @@
1 1
 // @flow
2 2
 
3
-import React, { PureComponent } from 'react';
3
+import React, { useCallback, useEffect } from 'react';
4 4
 import { StyleSheet, View } from 'react-native';
5
-
5
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
6 6
 
7 7
 type Props = {
8 8
 
@@ -11,6 +11,11 @@ type Props = {
11 11
      */
12 12
     onDimensionsChanged: Function,
13 13
 
14
+    /**
15
+     * The safe are insets handler.
16
+     */
17
+    onSafeAreaInsetsChanged: Function,
18
+
14 19
     /**
15 20
      * Any nested components.
16 21
      */
@@ -20,21 +25,23 @@ type Props = {
20 25
 /**
21 26
  * A {@link View} which captures the 'onLayout' event and calls a prop with the
22 27
  * component size.
28
+ *
29
+ * @param {Props} props - The read-only properties with which the new
30
+ * instance is to be initialized.
31
+ * @returns {Component} - Renders the root view and it's children.
23 32
  */
24
-export default class DimensionsDetector extends PureComponent<Props> {
25
-    /**
26
-     * Initializes a new DimensionsDetector instance.
27
-     *
28
-     * @param {Object} props - The read-only properties with which the new
29
-     * instance is to be initialized.
30
-     */
31
-    constructor(props: Object) {
32
-        super(props);
33
-
34
-        this._onLayout = this._onLayout.bind(this);
35
-    }
33
+export default function DimensionsDetector(props: Props) {
34
+    const { top = 0, right = 0, bottom = 0, left = 0 } = useSafeAreaInsets();
35
+    const { children, onDimensionsChanged, onSafeAreaInsetsChanged } = props;
36 36
 
37
-    _onLayout: (Object) => void;
37
+    useEffect(() => {
38
+        onSafeAreaInsetsChanged && onSafeAreaInsetsChanged({
39
+            top,
40
+            right,
41
+            bottom,
42
+            left
43
+        });
44
+    }, [ onSafeAreaInsetsChanged, top, right, bottom, left ]);
38 45
 
39 46
     /**
40 47
      * Handles the "on layout" View's event and calls the onDimensionsChanged
@@ -45,24 +52,15 @@ export default class DimensionsDetector extends PureComponent<Props> {
45 52
      * @private
46 53
      * @returns {void}
47 54
      */
48
-    _onLayout({ nativeEvent: { layout: { height, width } } }) {
49
-        const { onDimensionsChanged } = this.props;
50
-
55
+    const onLayout = useCallback(({ nativeEvent: { layout: { height, width } } }) => {
51 56
         onDimensionsChanged && onDimensionsChanged(width, height);
52
-    }
57
+    }, [ onDimensionsChanged ]);
53 58
 
54
-    /**
55
-     * Renders the root view and it's children.
56
-     *
57
-     * @returns {Component}
58
-     */
59
-    render() {
60
-        return (
61
-            <View
62
-                onLayout = { this._onLayout }
63
-                style = { StyleSheet.absoluteFillObject } >
64
-                { this.props.children }
65
-            </View>
66
-        );
67
-    }
59
+    return (
60
+        <View
61
+            onLayout = { onLayout }
62
+            style = { StyleSheet.absoluteFillObject } >
63
+            { children }
64
+        </View>
65
+    );
68 66
 }

+ 14
- 1
react/features/base/responsive-ui/reducer.js Näytä tiedosto

@@ -2,7 +2,13 @@
2 2
 
3 3
 import { ReducerRegistry, set } from '../redux';
4 4
 
5
-import { CLIENT_RESIZED, SET_ASPECT_RATIO, SET_CONTEXT_MENU_OPEN, SET_REDUCED_UI } from './actionTypes';
5
+import {
6
+    CLIENT_RESIZED,
7
+    SAFE_AREA_INSETS_CHANGED,
8
+    SET_ASPECT_RATIO,
9
+    SET_CONTEXT_MENU_OPEN,
10
+    SET_REDUCED_UI
11
+} from './actionTypes';
6 12
 import { ASPECT_RATIO_NARROW } from './constants';
7 13
 
8 14
 const {
@@ -30,6 +36,13 @@ ReducerRegistry.register('features/base/responsive-ui', (state = DEFAULT_STATE,
30 36
             clientHeight: action.clientHeight
31 37
         };
32 38
     }
39
+
40
+    case SAFE_AREA_INSETS_CHANGED:
41
+        return {
42
+            ...state,
43
+            safeAreaInsets: action.insets
44
+        };
45
+
33 46
     case SET_ASPECT_RATIO:
34 47
         return set(state, 'aspectRatio', action.aspectRatio);
35 48
 

+ 17
- 8
react/features/filmstrip/actions.native.js Näytä tiedosto

@@ -1,10 +1,12 @@
1 1
 // @flow
2 2
 
3
-import { getParticipantCountWithFake } from '../base/participants';
3
+import conferenceStyles from '../conference/components/native/styles';
4 4
 
5 5
 import { SET_TILE_VIEW_DIMENSIONS } from './actionTypes';
6
+import { styles } from './components';
6 7
 import { SQUARE_TILE_ASPECT_RATIO, TILE_MARGIN } from './constants';
7
-import { getColumnCount } from './functions.native';
8
+import { getColumnCount } from './functions';
9
+import { getTileViewParticipantCount } from './functions.native';
8 10
 
9 11
 export * from './actions.any';
10 12
 
@@ -18,16 +20,19 @@ export * from './actions.any';
18 20
 export function setTileViewDimensions() {
19 21
     return (dispatch: Function, getState: Function) => {
20 22
         const state = getState();
21
-        const participantCount = getParticipantCountWithFake(state);
22
-        const { clientHeight: height, clientWidth: width } = state['features/base/responsive-ui'];
23
+        const participantCount = getTileViewParticipantCount(state);
24
+        const { clientHeight: height, clientWidth: width, safeAreaInsets = {} } = state['features/base/responsive-ui'];
25
+        const { left = 0, right = 0, top = 0, bottom = 0 } = safeAreaInsets;
23 26
         const columns = getColumnCount(state);
24
-        const heightToUse = height - (TILE_MARGIN * 2);
25
-        const widthToUse = width - (TILE_MARGIN * 2);
27
+        const rows = Math.ceil(participantCount / columns);
28
+        const conferenceBorder = conferenceStyles.conference.borderWidth || 0;
29
+        const heightToUse = height - top - (2 * conferenceBorder);
30
+        const widthToUse = width - (TILE_MARGIN * 2) - left - right - (2 * conferenceBorder);
26 31
         let tileWidth;
27 32
 
28 33
         // If there is going to be at least two rows, ensure that at least two
29 34
         // rows display fully on screen.
30
-        if (participantCount / columns > 1) {
35
+        if (rows / columns > 1) {
31 36
             tileWidth = Math.min(widthToUse / columns, heightToUse / 2);
32 37
         } else {
33 38
             tileWidth = Math.min(widthToUse / columns, heightToUse);
@@ -37,6 +42,9 @@ export function setTileViewDimensions() {
37 42
 
38 43
         tileWidth = Math.floor(tileWidth);
39 44
 
45
+        // Adding safeAreaInsets.bottom to the total height of all thumbnails because we add it as a padding to the
46
+        // thumbnails container.
47
+        const hasScroll = heightToUse < ((tileHeight + (2 * styles.thumbnail.margin)) * rows) + bottom;
40 48
 
41 49
         dispatch({
42 50
             type: SET_TILE_VIEW_DIMENSIONS,
@@ -45,7 +53,8 @@ export function setTileViewDimensions() {
45 53
                 thumbnailSize: {
46 54
                     height: tileHeight,
47 55
                     width: tileWidth
48
-                }
56
+                },
57
+                hasScroll
49 58
             }
50 59
         });
51 60
     };

+ 32
- 19
react/features/filmstrip/components/native/Filmstrip.js Näytä tiedosto

@@ -2,7 +2,7 @@
2 2
 
3 3
 import React, { PureComponent } from 'react';
4 4
 import { FlatList } from 'react-native';
5
-import { SafeAreaView } from 'react-native-safe-area-context';
5
+import { SafeAreaView, withSafeAreaInsets } from 'react-native-safe-area-context';
6 6
 
7 7
 import { getLocalParticipant } from '../../../base/participants';
8 8
 import { Platform } from '../../../base/react';
@@ -11,7 +11,12 @@ import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
11 11
 import { shouldHideSelfView } from '../../../base/settings/functions.any';
12 12
 import { isToolboxVisible } from '../../../toolbox/functions';
13 13
 import { setVisibleRemoteParticipants } from '../../actions';
14
-import { isFilmstripVisible, shouldRemoteVideosBeVisible } from '../../functions';
14
+import {
15
+    getFilmstripDimensions,
16
+    isFilmstripVisible,
17
+    shouldDisplayLocalThumbnailSeparately,
18
+    shouldRemoteVideosBeVisible
19
+} from '../../functions';
15 20
 
16 21
 import LocalThumbnail from './LocalThumbnail';
17 22
 import Thumbnail from './Thumbnail';
@@ -60,6 +65,11 @@ type Props = {
60 65
      * Invoked to trigger state changes in Redux.
61 66
      */
62 67
     dispatch: Function,
68
+
69
+    /**
70
+     * Object containing the safe area insets.
71
+     */
72
+    insets: Object,
63 73
 };
64 74
 
65 75
 /**
@@ -105,7 +115,7 @@ class Filmstrip extends PureComponent<Props> {
105 115
         // indicators such as moderator, audio and video muted, etc. For now we
106 116
         // do not have much of a choice but to continue rendering LocalThumbnail
107 117
         // as any other remote Thumbnail on Android.
108
-        this._separateLocalThumbnail = Platform.OS !== 'android';
118
+        this._separateLocalThumbnail = shouldDisplayLocalThumbnailSeparately();
109 119
 
110 120
         this._viewabilityConfig = {
111 121
             itemVisiblePercentThreshold: 30,
@@ -136,20 +146,23 @@ class Filmstrip extends PureComponent<Props> {
136 146
      * @returns {Object} - The width and the height.
137 147
      */
138 148
     _getDimensions() {
139
-        const { _aspectRatio, _clientWidth, _clientHeight } = this.props;
140
-        const { height, width, margin } = styles.thumbnail;
141
-
142
-        if (_aspectRatio === ASPECT_RATIO_NARROW) {
143
-            return {
144
-                height,
145
-                width: this._separateLocalThumbnail ? _clientWidth - width - (margin * 2) : _clientWidth
146
-            };
147
-        }
148
-
149
-        return {
150
-            height: this._separateLocalThumbnail ? _clientHeight - height - (margin * 2) : _clientHeight,
151
-            width
152
-        };
149
+        const {
150
+            _aspectRatio,
151
+            _clientWidth,
152
+            _clientHeight,
153
+            _disableSelfView,
154
+            _localParticipantId,
155
+            insets
156
+        } = this.props;
157
+        const localParticipantVisible = Boolean(_localParticipantId) && !_disableSelfView;
158
+
159
+        return getFilmstripDimensions({
160
+            aspectRatio: _aspectRatio,
161
+            clientHeight: _clientHeight,
162
+            clientWidth: _clientWidth,
163
+            insets,
164
+            localParticipantVisible
165
+        });
153 166
     }
154 167
 
155 168
     _getItemLayout: (?Array<string>, number) => {length: number, offset: number, index: number};
@@ -312,7 +325,7 @@ function _mapStateToProps(state) {
312 325
     const responsiveUI = state['features/base/responsive-ui'];
313 326
 
314 327
     return {
315
-        _aspectRatio: state['features/base/responsive-ui'].aspectRatio,
328
+        _aspectRatio: responsiveUI.aspectRatio,
316 329
         _clientHeight: responsiveUI.clientHeight,
317 330
         _clientWidth: responsiveUI.clientWidth,
318 331
         _disableSelfView: disableSelfView,
@@ -323,4 +336,4 @@ function _mapStateToProps(state) {
323 336
     };
324 337
 }
325 338
 
326
-export default connect(_mapStateToProps)(Filmstrip);
339
+export default withSafeAreaInsets(connect(_mapStateToProps)(Filmstrip));

+ 1
- 1
react/features/filmstrip/constants.js Näytä tiedosto

@@ -218,7 +218,7 @@ export const SHOW_TOOLBAR_CONTEXT_MENU_AFTER = 600;
218 218
 
219 219
 /**
220 220
  * The margin for each side of the tile view. Taken away from the available
221
- * height and width for the tile container to display in.
221
+ * width for the tile container to display in.
222 222
  *
223 223
  * NOTE: Mobile specific.
224 224
  *

+ 15
- 1
react/features/filmstrip/functions.any.js Näytä tiedosto

@@ -4,7 +4,7 @@ import { getSourceNameSignalingFeatureFlag } from '../base/config';
4 4
 import { getVirtualScreenshareParticipantOwnerId } from '../base/participants';
5 5
 
6 6
 import { setRemoteParticipants } from './actions';
7
-import { isReorderingEnabled } from './functions';
7
+import { isFilmstripScrollVisible } from './functions';
8 8
 
9 9
 /**
10 10
  * Computes the reorderd list of the remote participants.
@@ -118,3 +118,17 @@ export function updateRemoteParticipantsOnLeave(store: Object, participantId: ?s
118 118
     reorderedParticipants.delete(participantId)
119 119
         && store.dispatch(setRemoteParticipants(Array.from(reorderedParticipants)));
120 120
 }
121
+
122
+/**
123
+ * Returns true if thumbnail reordering is enabled and false otherwise.
124
+ * Note: The function will return false if all participants are displayed on the screen.
125
+ *
126
+ * @param {Object} state - The redux state.
127
+ * @returns {boolean} - True if thumbnail reordering is enabled and false otherwise.
128
+ */
129
+export function isReorderingEnabled(state) {
130
+    const { testing = {} } = state['features/base/config'];
131
+    const enableThumbnailReordering = testing.enableThumbnailReordering ?? true;
132
+
133
+    return enableThumbnailReordering && isFilmstripScrollVisible(state);
134
+}

+ 121
- 8
react/features/filmstrip/functions.native.js Näytä tiedosto

@@ -1,9 +1,19 @@
1 1
 // @flow
2 2
 
3 3
 import { getFeatureFlag, FILMSTRIP_ENABLED } from '../base/flags';
4
-import { getParticipantCountWithFake, getPinnedParticipant } from '../base/participants';
4
+import {
5
+    getLocalParticipant,
6
+    getParticipantCountWithFake,
7
+    getPinnedParticipant
8
+} from '../base/participants';
9
+import { Platform } from '../base/react';
5 10
 import { toState } from '../base/redux';
6 11
 import { ASPECT_RATIO_NARROW } from '../base/responsive-ui/constants';
12
+import { shouldHideSelfView } from '../base/settings/functions.any';
13
+import conferenceStyles from '../conference/components/native/styles';
14
+import { shouldDisplayTileView } from '../video-layout';
15
+
16
+import { styles } from './components';
7 17
 
8 18
 export * from './functions.any';
9 19
 
@@ -61,6 +71,22 @@ export function shouldRemoteVideosBeVisible(state: Object) {
61 71
             || disable1On1Mode);
62 72
 }
63 73
 
74
+/**
75
+ * Returns the number of participants displayed in tile view.
76
+ *
77
+ * @param {Object | Function} stateful - The Object or Function that can be
78
+ * resolved to a Redux state object with the toState function.
79
+ * @returns {number} - The number of participants displayed in tile view.
80
+ */
81
+export function getTileViewParticipantCount(stateful: Object | Function) {
82
+    const state = toState(stateful);
83
+    const disableSelfView = shouldHideSelfView(state);
84
+    const localParticipant = getLocalParticipant(state);
85
+    const participantCount = getParticipantCountWithFake(state) - (disableSelfView && localParticipant ? 1 : 0);
86
+
87
+    return participantCount;
88
+}
89
+
64 90
 /**
65 91
  * Returns how many columns should be displayed for tile view.
66 92
  *
@@ -71,7 +97,7 @@ export function shouldRemoteVideosBeVisible(state: Object) {
71 97
  */
72 98
 export function getColumnCount(stateful: Object | Function) {
73 99
     const state = toState(stateful);
74
-    const participantCount = getParticipantCountWithFake(state);
100
+    const participantCount = getTileViewParticipantCount(state);
75 101
     const { aspectRatio } = state['features/base/responsive-ui'];
76 102
 
77 103
     // For narrow view, tiles should stack on top of each other for a lonely
@@ -90,16 +116,38 @@ export function getColumnCount(stateful: Object | Function) {
90 116
 }
91 117
 
92 118
 /**
93
- * Returns true if thumbnail reordering is enabled and false otherwise.
119
+ * Returns true if the filmstrip has a scroll and false otherwise.
94 120
  *
95 121
  * @param {Object} state - The redux state.
96
- * @returns {boolean} - True if thumbnail reordering is enabled and false otherwise.
122
+ * @returns {boolean} - True if the scroll is displayed and false otherwise.
97 123
  */
98
-export function isReorderingEnabled(state) {
99
-    const { testing = {} } = state['features/base/config'];
100
-    const enableThumbnailReordering = testing.enableThumbnailReordering ?? true;
124
+export function isFilmstripScrollVisible(state) {
125
+    if (shouldDisplayTileView(state)) {
126
+        return state['features/filmstrip']?.tileViewDimensions?.hasScroll;
127
+    }
101 128
 
102
-    return enableThumbnailReordering;
129
+    const { aspectRatio, clientWidth, clientHeight, safeAreaInsets = {} } = state['features/base/responsive-ui'];
130
+    const isNarrowAspectRatio = aspectRatio === ASPECT_RATIO_NARROW;
131
+    const disableSelfView = shouldHideSelfView(state);
132
+    const localParticipant = Boolean(getLocalParticipant(state));
133
+    const localParticipantVisible = localParticipant && !disableSelfView;
134
+    const participantCount
135
+        = getParticipantCountWithFake(state)
136
+            - (localParticipant && (shouldDisplayLocalThumbnailSeparately() || disableSelfView) ? 1 : 0);
137
+    const { height: thumbnailHeight, width: thumbnailWidth, margin } = styles.thumbnail;
138
+    const { height, width } = getFilmstripDimensions({
139
+        aspectRatio,
140
+        clientWidth,
141
+        clientHeight,
142
+        insets: safeAreaInsets,
143
+        localParticipantVisible
144
+    });
145
+
146
+    if (isNarrowAspectRatio) {
147
+        return width < (thumbnailWidth + (2 * margin)) * participantCount;
148
+    }
149
+
150
+    return height < (thumbnailHeight + (2 * margin)) * participantCount;
103 151
 }
104 152
 
105 153
 /**
@@ -120,3 +168,68 @@ export function isStageFilmstripAvailable() {
120 168
 export function isStageFilmstripEnabled() {
121 169
     return false;
122 170
 }
171
+
172
+/**
173
+ * Calculates the width and height of the filmstrip based on the screen size and aspect ratio.
174
+ *
175
+ * @param {Object} options - The screen aspect ratio, width, height and safe are insets.
176
+ * @returns {Object} - The width and the height.
177
+ */
178
+export function getFilmstripDimensions({
179
+    aspectRatio,
180
+    clientWidth,
181
+    clientHeight,
182
+    insets = {},
183
+    localParticipantVisible = true
184
+}) {
185
+    const { height, width, margin } = styles.thumbnail;
186
+    const conferenceBorder = conferenceStyles.conference.borderWidth || 0;
187
+    const { left = 0, right = 0, top = 0, bottom = 0 } = insets;
188
+
189
+    if (aspectRatio === ASPECT_RATIO_NARROW) {
190
+        return {
191
+            height,
192
+            width:
193
+                (shouldDisplayLocalThumbnailSeparately() && localParticipantVisible
194
+                    ? clientWidth - width - (margin * 2) : clientWidth)
195
+                    - left - right - (styles.filmstripNarrow.margin * 2) - (conferenceBorder * 2)
196
+
197
+        };
198
+    }
199
+
200
+    return {
201
+        height:
202
+            (shouldDisplayLocalThumbnailSeparately() && localParticipantVisible
203
+                ? clientHeight - height - (margin * 2) : clientHeight)
204
+                - top - bottom - (conferenceBorder * 2),
205
+        width
206
+    };
207
+}
208
+
209
+/**
210
+ * Returns true if the local thumbnail should be displayed separately and false otherwise.
211
+ *
212
+ * @returns {boolean} - True if the local thumbnail should be displayed separately and flase otherwise.
213
+ */
214
+export function shouldDisplayLocalThumbnailSeparately() {
215
+    // XXX Our current design is to have the local participant separate from
216
+    // the remote participants. Unfortunately, Android's Video
217
+    // implementation cannot accommodate that because remote participants'
218
+    // videos appear on top of the local participant's video at times.
219
+    // That's because Android's Video utilizes EGL and EGL gives us only two
220
+    // practical layers in which we can place our participants' videos:
221
+    // layer #0 sits behind the window, creates a hole in the window, and
222
+    // there we render the LargeVideo; layer #1 is known as media overlay in
223
+    // EGL terms, renders on top of layer #0, and, consequently, is for the
224
+    // Filmstrip. With the separate LocalThumbnail, we should have left the
225
+    // remote participants' Thumbnails in layer #1 and utilized layer #2 for
226
+    // LocalThumbnail. Unfortunately, layer #2 is not practical (that's why
227
+    // I said we had two practical layers only) because it renders on top of
228
+    // everything which in our case means on top of participant-related
229
+    // indicators such as moderator, audio and video muted, etc. For now we
230
+    // do not have much of a choice but to continue rendering LocalThumbnail
231
+    // as any other remote Thumbnail on Android.
232
+    return Platform.OS !== 'android';
233
+}
234
+
235
+

+ 0
- 14
react/features/filmstrip/functions.web.js Näytä tiedosto

@@ -652,20 +652,6 @@ export function getVerticalViewMaxWidth(state) {
652 652
     return maxWidth;
653 653
 }
654 654
 
655
-/**
656
- * Returns true if thumbnail reordering is enabled and false otherwise.
657
- * Note: The function will return false if all participants are displayed on the screen.
658
- *
659
- * @param {Object} state - The redux state.
660
- * @returns {boolean} - True if thumbnail reordering is enabled and false otherwise.
661
- */
662
-export function isReorderingEnabled(state) {
663
-    const { testing = {} } = state['features/base/config'];
664
-    const enableThumbnailReordering = testing.enableThumbnailReordering ?? true;
665
-
666
-    return enableThumbnailReordering && isFilmstripScrollVisible(state);
667
-}
668
-
669 655
 /**
670 656
  * Returns true if the scroll is displayed and false otherwise.
671 657
  *

+ 2
- 1
react/features/filmstrip/middleware.native.js Näytä tiedosto

@@ -2,7 +2,7 @@
2 2
 
3 3
 import { PARTICIPANT_JOINED, PARTICIPANT_LEFT } from '../base/participants';
4 4
 import { MiddlewareRegistry } from '../base/redux';
5
-import { CLIENT_RESIZED, SET_ASPECT_RATIO } from '../base/responsive-ui';
5
+import { CLIENT_RESIZED, SAFE_AREA_INSETS_CHANGED, SET_ASPECT_RATIO } from '../base/responsive-ui';
6 6
 
7 7
 import { setTileViewDimensions } from './actions';
8 8
 import { updateRemoteParticipants, updateRemoteParticipantsOnLeave } from './functions';
@@ -25,6 +25,7 @@ MiddlewareRegistry.register(store => next => action => {
25 25
 
26 26
     switch (action.type) {
27 27
     case CLIENT_RESIZED:
28
+    case SAFE_AREA_INSETS_CHANGED:
28 29
     case SET_ASPECT_RATIO:
29 30
         store.dispatch(setTileViewDimensions());
30 31
         break;

+ 7
- 4
react/features/filmstrip/reducer.js Näytä tiedosto

@@ -204,12 +204,15 @@ ReducerRegistry.register(
204 204
                 }
205 205
             };
206 206
         case SET_VISIBLE_REMOTE_PARTICIPANTS: {
207
+            const { endIndex, startIndex } = action;
208
+            const { remoteParticipants } = state;
209
+            const visibleRemoteParticipants = new Set(remoteParticipants.slice(startIndex, endIndex + 1));
210
+
207 211
             return {
208 212
                 ...state,
209
-                visibleParticipantsStartIndex: action.startIndex,
210
-                visibleParticipantsEndIndex: action.endIndex,
211
-                visibleRemoteParticipants:
212
-                    new Set(state.remoteParticipants.slice(action.startIndex, action.endIndex + 1))
213
+                visibleParticipantsStartIndex: startIndex,
214
+                visibleParticipantsEndIndex: endIndex,
215
+                visibleRemoteParticipants
213 216
             };
214 217
         }
215 218
         case PARTICIPANT_LEFT: {

+ 8
- 1
react/features/filmstrip/subscriber.any.js Näytä tiedosto

@@ -2,7 +2,7 @@
2 2
 
3 3
 import { StateListenerRegistry } from '../base/redux';
4 4
 
5
-import { updateRemoteParticipants } from './functions';
5
+import { isFilmstripScrollVisible, updateRemoteParticipants } from './functions';
6 6
 
7 7
 /**
8 8
  * Listens for changes to the screensharing status of the remote participants to recompute the reordered list of the
@@ -25,3 +25,10 @@ StateListenerRegistry.register(
25 25
 StateListenerRegistry.register(
26 26
     /* selector */ state => state['features/base/participants'].dominantSpeaker,
27 27
     /* listener */ (dominantSpeaker, store) => updateRemoteParticipants(store));
28
+
29
+/**
30
+ * Listens for changes in the filmstrip scroll visibility.
31
+ */
32
+StateListenerRegistry.register(
33
+    /* selector */ state => isFilmstripScrollVisible(state),
34
+    /* listener */ (_, store) => updateRemoteParticipants(store));

+ 2
- 10
react/features/filmstrip/subscriber.native.js Näytä tiedosto

@@ -1,25 +1,17 @@
1 1
 // @flow
2 2
 
3
-import { getParticipantCountWithFake } from '../base/participants';
4 3
 import { StateListenerRegistry } from '../base/redux';
5 4
 import { shouldDisplayTileView } from '../video-layout';
6 5
 
7 6
 import { setTileViewDimensions } from './actions';
7
+import { getTileViewParticipantCount } from './functions.native';
8 8
 import './subscriber.any';
9 9
 
10 10
 /**
11 11
  * Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles.
12 12
  */
13 13
 StateListenerRegistry.register(
14
-    /* selector */ state => {
15
-        const participantCount = getParticipantCountWithFake(state);
16
-
17
-        if (participantCount < 6) { // the dimensions are updated only when the participant count is lower than 6.
18
-            return participantCount;
19
-        }
20
-
21
-        return 5; // make sure we don't update the dimensions.
22
-    },
14
+    /* selector */ state => getTileViewParticipantCount(state),
23 15
     /* listener */ (_, store) => {
24 16
         const state = store.getState();
25 17
 

+ 1
- 10
react/features/filmstrip/subscriber.web.js Näytä tiedosto

@@ -23,9 +23,7 @@ import {
23 23
     DISPLAY_DRAWER_THRESHOLD
24 24
 } from './constants';
25 25
 import {
26
-    isFilmstripResizable,
27
-    isFilmstripScrollVisible,
28
-    updateRemoteParticipants
26
+    isFilmstripResizable
29 27
 } from './functions';
30 28
 
31 29
 import './subscriber.any';
@@ -166,13 +164,6 @@ StateListenerRegistry.register(
166 164
         store.dispatch(setVerticalViewDimensions());
167 165
     });
168 166
 
169
-/**
170
- * Listens for changes in the filmstrip scroll visibility.
171
- */
172
-StateListenerRegistry.register(
173
-    /* selector */ state => isFilmstripScrollVisible(state),
174
-    /* listener */ (_, store) => updateRemoteParticipants(store));
175
-
176 167
 /**
177 168
  * Listens for changes to determine the size of the stage filmstrip tiles.
178 169
  */

+ 35
- 38
react/features/mobile/navigation/components/RootNavigationContainer.js Näytä tiedosto

@@ -1,7 +1,6 @@
1 1
 import { NavigationContainer } from '@react-navigation/native';
2 2
 import { createStackNavigator } from '@react-navigation/stack';
3 3
 import React from 'react';
4
-import { SafeAreaProvider } from 'react-native-safe-area-context';
5 4
 
6 5
 import { connect } from '../../../base/redux';
7 6
 import { DialInSummary } from '../../../invite';
@@ -36,43 +35,41 @@ const RootNavigationContainer = ({ isWelcomePageAvailable }: Props) => {
36 35
         ? screen.root : screen.connecting;
37 36
 
38 37
     return (
39
-        <SafeAreaProvider>
40
-            <NavigationContainer
41
-                independent = { true }
42
-                ref = { rootNavigationRef }
43
-                theme = { navigationContainerTheme }>
44
-                <RootStack.Navigator
45
-                    initialRouteName = { initialRouteName }>
46
-                    {
47
-                        isWelcomePageAvailable
48
-                            && <>
49
-                                <RootStack.Screen
50
-                                    component = { WelcomePageNavigationContainer }
51
-                                    name = { screen.root }
52
-                                    options = { drawerNavigatorScreenOptions } />
53
-                                <RootStack.Screen
54
-                                    component = { DialInSummary }
55
-                                    name = { screen.dialInSummary }
56
-                                    options = { dialInSummaryScreenOptions } />
57
-                            </>
58
-                    }
59
-                    <RootStack.Screen
60
-                        component = { ConnectingPage }
61
-                        name = { screen.connecting }
62
-                        options = {{
63
-                            gestureEnabled: false,
64
-                            headerShown: false
65
-                        }} />
66
-                    <RootStack.Screen
67
-                        component = { ConferenceNavigationContainer }
68
-                        name = { screen.conference.root }
69
-                        options = {{
70
-                            gestureEnabled: false,
71
-                            headerShown: false
72
-                        }} />
73
-                </RootStack.Navigator>
74
-            </NavigationContainer>
75
-        </SafeAreaProvider>
38
+        <NavigationContainer
39
+            independent = { true }
40
+            ref = { rootNavigationRef }
41
+            theme = { navigationContainerTheme }>
42
+            <RootStack.Navigator
43
+                initialRouteName = { initialRouteName }>
44
+                {
45
+                    isWelcomePageAvailable
46
+                        && <>
47
+                            <RootStack.Screen
48
+                                component = { WelcomePageNavigationContainer }
49
+                                name = { screen.root }
50
+                                options = { drawerNavigatorScreenOptions } />
51
+                            <RootStack.Screen
52
+                                component = { DialInSummary }
53
+                                name = { screen.dialInSummary }
54
+                                options = { dialInSummaryScreenOptions } />
55
+                        </>
56
+                }
57
+                <RootStack.Screen
58
+                    component = { ConnectingPage }
59
+                    name = { screen.connecting }
60
+                    options = {{
61
+                        gestureEnabled: false,
62
+                        headerShown: false
63
+                    }} />
64
+                <RootStack.Screen
65
+                    component = { ConferenceNavigationContainer }
66
+                    name = { screen.conference.root }
67
+                    options = {{
68
+                        gestureEnabled: false,
69
+                        headerShown: false
70
+                    }} />
71
+            </RootStack.Navigator>
72
+        </NavigationContainer>
76 73
     );
77 74
 };
78 75
 

Loading…
Peruuta
Tallenna