Selaa lähdekoodia

feat(tiles): Add responsive behaviour.

* Enforce fixed column number at various width breakpoints.
* Bring back the filmstrip at small sizes but hide it.
* Change default maximum columns to 7.
master
Mihai-Andrei Uscat 4 vuotta sitten
vanhempi
commit
db84889143

+ 0
- 10
css/_responsive.scss Näytä tiedosto

143
 
143
 
144
     @media only screen and (max-width: $verySmallScreen) {
144
     @media only screen and (max-width: $verySmallScreen) {
145
         @include very-small-button-size();
145
         @include very-small-button-size();
146
-
147
-        #videoResolutionLabel {
148
-            display: none;
149
-        }
150
-        .vertical-filmstrip .filmstrip {
151
-            display: none;
152
-        }
153
-        .chrome-extension-banner {
154
-            display: none;
155
-        }
156
     }
146
     }
157
 
147
 
158
     &.shift-right {
148
     &.shift-right {

+ 9
- 0
css/filmstrip/_tile_view.scss Näytä tiedosto

100
         video {
100
         video {
101
             object-fit: contain;
101
             object-fit: contain;
102
         }
102
         }
103
+
104
+        /**
105
+         * Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants.
106
+         */
107
+        @media only screen and (max-width: 500px) {
108
+            video {
109
+                object-fit: cover;
110
+            }
111
+        }
103
     }
112
     }
104
 
113
 
105
     .has-overflow#filmstripRemoteVideosContainer {
114
     .has-overflow#filmstripRemoteVideosContainer {

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

10
  */
10
  */
11
 export const TILE_ASPECT_RATIO = 16 / 9;
11
 export const TILE_ASPECT_RATIO = 16 / 9;
12
 
12
 
13
+/**
14
+ * The aspect ratio of a square tile in tile view.
15
+ */
16
+export const SQUARE_TILE_ASPECT_RATIO = 1;
17
+
13
 /**
18
 /**
14
  * Width below which the overflow menu(s) will be displayed as drawer(s).
19
  * Width below which the overflow menu(s) will be displayed as drawer(s).
15
  */
20
  */
16
 export const DISPLAY_DRAWER_THRESHOLD = 512;
21
 export const DISPLAY_DRAWER_THRESHOLD = 512;
22
+
23
+/**
24
+ * Breakpoint past which a single column view is enforced in tile view.
25
+ */
26
+export const SINGLE_COLUMN_BREAKPOINT = 300;
27
+
28
+/**
29
+ * Breakpoint past which a two column view is enforced in tile view.
30
+ */
31
+export const TWO_COLUMN_BREAKPOINT = 1000;
32
+
33
+/**
34
+ * Breakpoint past which the aspect ratio is switched in tile view.
35
+ * Also, past this breakpoint, if there are two participants in the conference, we enforce
36
+ * single column view.
37
+ * If this is to be modified, please also change the related media query from the tile_view scss file.
38
+ */
39
+export const ASPECT_RATIO_BREAKPOINT = 500;
40
+
41
+/**
42
+ * The default number of columns for tile view.
43
+ */
44
+export const DEFAULT_MAX_COLUMNS = 5;
45
+
46
+/**
47
+ * An extended number of columns for tile view.
48
+ */
49
+export const ABSOLUTE_MAX_COLUMNS = 7;

+ 4
- 3
react/features/filmstrip/functions.web.js Näytä tiedosto

16
     isRemoteTrackMuted
16
     isRemoteTrackMuted
17
 } from '../base/tracks/functions';
17
 } from '../base/tracks/functions';
18
 
18
 
19
-import { TILE_ASPECT_RATIO } from './constants';
19
+import { ASPECT_RATIO_BREAKPOINT, SQUARE_TILE_ASPECT_RATIO, TILE_ASPECT_RATIO } from './constants';
20
 
20
 
21
 declare var interfaceConfig: Object;
21
 declare var interfaceConfig: Object;
22
 
22
 
142
     clientWidth,
142
     clientWidth,
143
     clientHeight
143
     clientHeight
144
 }: Object) {
144
 }: Object) {
145
+    const aspectRatio = clientWidth < ASPECT_RATIO_BREAKPOINT ? SQUARE_TILE_ASPECT_RATIO : TILE_ASPECT_RATIO;
145
     const viewWidth = clientWidth - TILE_VIEW_SIDE_MARGINS;
146
     const viewWidth = clientWidth - TILE_VIEW_SIDE_MARGINS;
146
     const viewHeight = clientHeight - TILE_VIEW_SIDE_MARGINS;
147
     const viewHeight = clientHeight - TILE_VIEW_SIDE_MARGINS;
147
     const initialWidth = viewWidth / columns;
148
     const initialWidth = viewWidth / columns;
148
-    const aspectRatioHeight = initialWidth / TILE_ASPECT_RATIO;
149
+    const aspectRatioHeight = initialWidth / aspectRatio;
149
     const height = Math.floor(Math.min(aspectRatioHeight, viewHeight / visibleRows));
150
     const height = Math.floor(Math.min(aspectRatioHeight, viewHeight / visibleRows));
150
-    const width = Math.floor(TILE_ASPECT_RATIO * height);
151
+    const width = Math.floor(aspectRatio * height);
151
 
152
 
152
     return {
153
     return {
153
         height,
154
         height,

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

3
 import Filmstrip from '../../../modules/UI/videolayout/Filmstrip';
3
 import Filmstrip from '../../../modules/UI/videolayout/Filmstrip';
4
 import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
4
 import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
5
 import { StateListenerRegistry, equals } from '../base/redux';
5
 import { StateListenerRegistry, equals } from '../base/redux';
6
+import { setFilmstripVisible } from '../filmstrip/actions';
6
 import { setOverflowDrawer } from '../toolbox/actions.web';
7
 import { setOverflowDrawer } from '../toolbox/actions.web';
7
 import { getCurrentLayout, getTileViewGridDimensions, shouldDisplayTileView, LAYOUTS } from '../video-layout';
8
 import { getCurrentLayout, getTileViewGridDimensions, shouldDisplayTileView, LAYOUTS } from '../video-layout';
8
 
9
 
9
 import { setHorizontalViewDimensions, setTileViewDimensions } from './actions.web';
10
 import { setHorizontalViewDimensions, setTileViewDimensions } from './actions.web';
10
-import { DISPLAY_DRAWER_THRESHOLD } from './constants';
11
+import {
12
+    ASPECT_RATIO_BREAKPOINT,
13
+    DISPLAY_DRAWER_THRESHOLD,
14
+    SINGLE_COLUMN_BREAKPOINT,
15
+    TWO_COLUMN_BREAKPOINT
16
+} from './constants';
11
 
17
 
12
 /**
18
 /**
13
  * Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles.
19
  * Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles.
134
     /* listener */ (widthBelowThreshold, store) => {
140
     /* listener */ (widthBelowThreshold, store) => {
135
         store.dispatch(setOverflowDrawer(widthBelowThreshold));
141
         store.dispatch(setOverflowDrawer(widthBelowThreshold));
136
     });
142
     });
143
+
144
+/**
145
+ * Gracefully hide/show the filmstrip when going past threshold.
146
+ */
147
+StateListenerRegistry.register(
148
+    /* selector */ state => state['features/base/responsive-ui'].clientWidth < ASPECT_RATIO_BREAKPOINT,
149
+    /* listener */ (widthBelowThreshold, store) => {
150
+        store.dispatch(setFilmstripVisible(!widthBelowThreshold));
151
+    });
152
+
153
+/**
154
+ * Symbol mapping used for the tile view responsiveness computation.
155
+ */
156
+const responsiveColumnMapping = {
157
+    singleColumn: Symbol('singleColumn'),
158
+    twoColumns: Symbol('twoColumns'),
159
+    twoParticipantsSingleColumn: Symbol('twoParticipantsSingleColumn')
160
+};
161
+
162
+/**
163
+ * Listens for changes in the screen size to recompute
164
+ * the dimensions of the tile view grid and the tiles for responsiveness.
165
+ */
166
+StateListenerRegistry.register(
167
+    /* selector */ state => {
168
+        const { clientWidth } = state['features/base/responsive-ui'];
169
+
170
+        if (clientWidth < TWO_COLUMN_BREAKPOINT && clientWidth >= ASPECT_RATIO_BREAKPOINT) {
171
+            // Forcing the recomputation of tiles when screen switches in or out of
172
+            // the (TWO_COLUMN_BREAKPOINT, ASPECT_RATIO_BREAKPOINT] interval.
173
+            return responsiveColumnMapping.twoColumns;
174
+        } else if (clientWidth < ASPECT_RATIO_BREAKPOINT && clientWidth >= SINGLE_COLUMN_BREAKPOINT) {
175
+            // Forcing the recomputation of tiles when screen switches in or out of
176
+            // the (ASPECT_RATIO_BREAKPOINT, SINGLE_COLUMN_BREAKPOINT] interval.
177
+            return responsiveColumnMapping.twoParticipantsSingleColumn;
178
+        }
179
+
180
+        /**
181
+         * This gets called either when the width of the screen is above {@code TWO_COLUMN_BREAKPOINT}
182
+         * or below {@CODE SINGLE_COLUMN_BREAKPOINT}, however, the internal logic from {@code getMaxColumnCount}
183
+         * only takes the second case into consideration.
184
+         */
185
+        return responsiveColumnMapping.singleColumn;
186
+    },
187
+    /* listener */ (_, store) => {
188
+        const state = store.getState();
189
+
190
+        if (shouldDisplayTileView(state)) {
191
+            const gridDimensions = getTileViewGridDimensions(state);
192
+            const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
193
+            const { isOpen } = state['features/chat'];
194
+
195
+            store.dispatch(
196
+                setTileViewDimensions(
197
+                    gridDimensions,
198
+                    {
199
+                        clientHeight,
200
+                        clientWidth
201
+                    },
202
+                    isOpen
203
+                )
204
+            );
205
+        }
206
+    });

+ 39
- 5
react/features/video-layout/functions.js Näytä tiedosto

2
 
2
 
3
 import { getFeatureFlag, TILE_VIEW_ENABLED } from '../base/flags';
3
 import { getFeatureFlag, TILE_VIEW_ENABLED } from '../base/flags';
4
 import { getPinnedParticipant, getParticipantCount } from '../base/participants';
4
 import { getPinnedParticipant, getParticipantCount } from '../base/participants';
5
+import { CHAT_SIZE } from '../chat/constants';
6
+import {
7
+    ASPECT_RATIO_BREAKPOINT,
8
+    DEFAULT_MAX_COLUMNS,
9
+    ABSOLUTE_MAX_COLUMNS,
10
+    SINGLE_COLUMN_BREAKPOINT,
11
+    TWO_COLUMN_BREAKPOINT
12
+} from '../filmstrip/constants';
5
 import { isYoutubeVideoPlaying } from '../youtube-player/functions';
13
 import { isYoutubeVideoPlaying } from '../youtube-player/functions';
6
 
14
 
7
 import { LAYOUTS } from './constants';
15
 import { LAYOUTS } from './constants';
27
 
35
 
28
 /**
36
 /**
29
  * Returns how many columns should be displayed in tile view. The number
37
  * Returns how many columns should be displayed in tile view. The number
30
- * returned will be between 1 and 5, inclusive.
38
+ * returned will be between 1 and 7, inclusive.
31
  *
39
  *
40
+ * @param {Object} state - The redux store state.
32
  * @returns {number}
41
  * @returns {number}
33
  */
42
  */
34
-export function getMaxColumnCount() {
35
-    const configuredMax = interfaceConfig.TILE_VIEW_MAX_COLUMNS || 5;
43
+export function getMaxColumnCount(state: Object) {
44
+    const configuredMax = interfaceConfig.TILE_VIEW_MAX_COLUMNS || DEFAULT_MAX_COLUMNS;
45
+    const { clientWidth } = state['features/base/responsive-ui'];
46
+    let availableWidth = clientWidth;
47
+    const participantCount = getParticipantCount(state);
48
+    const { isOpen } = state['features/chat'];
49
+
50
+    if (isOpen) {
51
+        availableWidth -= CHAT_SIZE;
52
+    }
53
+
54
+    // If there are just two participants in a conference, enforce single-column view for mobile size.
55
+    if (participantCount === 2 && availableWidth < ASPECT_RATIO_BREAKPOINT) {
56
+        return Math.min(1, Math.max(configuredMax, 1));
57
+    }
36
 
58
 
37
-    return Math.min(Math.max(configuredMax, 1), 5);
59
+    // Enforce single column view at very small screen widths.
60
+    if (availableWidth < SINGLE_COLUMN_BREAKPOINT) {
61
+        return Math.min(1, Math.max(configuredMax, 1));
62
+    }
63
+
64
+    // Enforce two column view below breakpoint.
65
+    if (availableWidth < TWO_COLUMN_BREAKPOINT) {
66
+        return Math.min(2, Math.max(configuredMax, 1));
67
+    }
68
+
69
+    return Math.min(Math.max(configuredMax, 1), ABSOLUTE_MAX_COLUMNS);
38
 }
70
 }
39
 
71
 
40
 /**
72
 /**
48
  * @returns {Object} An object is return with the desired number of columns,
80
  * @returns {Object} An object is return with the desired number of columns,
49
  * rows, and visible rows (the rest should overflow) for the tile view layout.
81
  * rows, and visible rows (the rest should overflow) for the tile view layout.
50
  */
82
  */
51
-export function getTileViewGridDimensions(state: Object, maxColumns: number = getMaxColumnCount()) {
83
+export function getTileViewGridDimensions(state: Object) {
84
+    const maxColumns = getMaxColumnCount(state);
85
+
52
     // When in tile view mode, we must discount ourselves (the local participant) because our
86
     // When in tile view mode, we must discount ourselves (the local participant) because our
53
     // tile is not visible.
87
     // tile is not visible.
54
     const { iAmRecorder } = state['features/base/config'];
88
     const { iAmRecorder } = state['features/base/config'];

Loading…
Peruuta
Tallenna