瀏覽代碼

fix(vertical-filmstrip): different label animations for filmstrip states (#1596)

* fix(vertical-filmstrip): different label animations for filmstrip states

Instead of one timing for sliding the video status label left and right,
have different timings depending on the filmstrip state. To facilitate
triggering the different animations, add more classes to the labels
that need to move that specify the filmstrip state.

- Faster transition if focusing on self-view with videos present so
  the label does not overlap videos transitioning from 0 opacity.
- Transition delay when de-focusing on self-view with videos present
  so videos have time to go away before the label moves over them.
- Maintain no movement if there are no videos, regardless of
  filmstrip toggle state.
- Different delays for when the filmstrip is being toggled visible
  and hidden if there are remote videos visible.

* SQUASH: remove remote videos count

* SQUASH: add docs to scss
j8
virtuacoplenny 8 年之前
父節點
當前提交
d5b40280ab

+ 3
- 2
conference.js 查看文件

1844
             const remoteVideosCount = APP.UI.getRemoteVideosCount();
1844
             const remoteVideosCount = APP.UI.getRemoteVideosCount();
1845
 
1845
 
1846
             const shouldShowRemoteThumbnails = interfaceConfig.filmStripOnly
1846
             const shouldShowRemoteThumbnails = interfaceConfig.filmStripOnly
1847
-                || APP.UI.isPinned(localUserId)
1847
+                || (APP.UI.isPinned(localUserId) && remoteVideosCount)
1848
                 || remoteVideosCount > 1
1848
                 || remoteVideosCount > 1
1849
                 || remoteParticipantsCount !== remoteVideosCount;
1849
                 || remoteParticipantsCount !== remoteVideosCount;
1850
 
1850
 
1851
-            APP.UI.setRemoteThumbnailsVisibility(shouldShowRemoteThumbnails);
1851
+            APP.UI.setRemoteThumbnailsVisibility(
1852
+                Boolean(shouldShowRemoteThumbnails));
1852
         }
1853
         }
1853
     },
1854
     },
1854
     /**
1855
     /**

+ 29
- 4
css/_vertical_filmstrip_overrides.scss 查看文件

88
     }
88
     }
89
 
89
 
90
     /**
90
     /**
91
-     * For video labels that display on the top right to adjust its position as
92
-     * the filmstrip itself or filmstrip remote videos appear and disappear.
91
+     * These styles are for the video labels that display on the top right. The
92
+     * styles adjust the labels' positioning as the filmstrip itself or
93
+     * filmstrip's remote videos appear and disappear.
94
+     *
95
+     * The class with-filmstrip is for when the filmstrip is visible.
96
+     * The class without-filmstrip is for when the filmstrip has been toggled to
97
+     * be hidden.
98
+     * The class opening is for when the filmstrip is transitioning from hidden
99
+     * to visible.
100
+     * The class with-remote-videos is for when the filmstrip has remote videos
101
+     * displayed, as opposed to 1-on-1 mode where they might be hidden.
102
+     * The class without-remote-videos is for when the filmstrip is visible
103
+     * but it has no videos to display.
93
      */
104
      */
94
     .video-state-indicator.moveToCorner {
105
     .video-state-indicator.moveToCorner {
95
-        transition: right 2s;
106
+        transition: right 0.5s;
96
 
107
 
97
-        &.with-filmstrip {
108
+        &.with-filmstrip.with-remote-videos {
98
             &#recordingLabel {
109
             &#recordingLabel {
99
                 right: 200px;
110
                 right: 200px;
100
             }
111
             }
103
                 right: 150px;
114
                 right: 150px;
104
             }
115
             }
105
         }
116
         }
117
+
118
+        &.with-filmstrip.without-remote-videos {
119
+            transition-delay: 0.5s;
120
+        }
121
+
122
+        &.with-filmstrip.with-remote-videos.opening {
123
+            transition: 0.9s;
124
+            transition-timing-function: ease-in-out;
125
+        }
126
+
127
+        &.without-filmstrip {
128
+            transition: 1.2s ease-in-out;
129
+            transition-delay: 0.1s;
130
+        }
106
     }
131
     }
107
 
132
 
108
     /**
133
     /**

+ 17
- 9
modules/UI/recording/Recording.js 查看文件

196
 
196
 
197
 /**
197
 /**
198
  * Moves the element given by {selector} to the top right corner of the screen.
198
  * Moves the element given by {selector} to the top right corner of the screen.
199
+ * Set additional classes that can be used to style the selector relative to the
200
+ * state of the filmstrip.
201
+ *
199
  * @param selector the selector for the element to move
202
  * @param selector the selector for the element to move
200
  * @param move {true} to move the element, {false} to move it back to its intial
203
  * @param move {true} to move the element, {false} to move it back to its intial
201
  * position
204
  * position
202
  */
205
  */
203
 function moveToCorner(selector, move) {
206
 function moveToCorner(selector, move) {
204
-    const {
205
-        remoteVideosCount,
206
-        remoteVideosVisible,
207
-        visible
208
-    } = APP.store.getState()['features/filmstrip'];
209
-    selector.toggleClass(
210
-        'with-filmstrip',
211
-        Boolean(remoteVideosCount && remoteVideosVisible && visible));
212
-
213
     let moveToCornerClass = "moveToCorner";
207
     let moveToCornerClass = "moveToCorner";
214
     let containsClass = selector.hasClass(moveToCornerClass);
208
     let containsClass = selector.hasClass(moveToCornerClass);
215
 
209
 
217
         selector.addClass(moveToCornerClass);
211
         selector.addClass(moveToCornerClass);
218
     else if (!move && containsClass)
212
     else if (!move && containsClass)
219
         selector.removeClass(moveToCornerClass);
213
         selector.removeClass(moveToCornerClass);
214
+
215
+    const {
216
+        remoteVideosVisible,
217
+        visible
218
+    } = APP.store.getState()['features/filmstrip'];
219
+    const filmstripWasHidden = selector.hasClass('without-filmstrip');
220
+    const filmstipIsOpening = filmstripWasHidden && visible;
221
+    selector.toggleClass('opening', filmstipIsOpening);
222
+
223
+    selector.toggleClass('with-filmstrip', visible);
224
+    selector.toggleClass('without-filmstrip', !visible);
225
+
226
+    selector.toggleClass('with-remote-videos', remoteVideosVisible);
227
+    selector.toggleClass('without-remote-videos', !remoteVideosVisible);
220
 }
228
 }
221
 
229
 
222
 /**
230
 /**

+ 0
- 6
modules/UI/videolayout/VideoLayout.js 查看文件

1
 /* global APP, $, interfaceConfig */
1
 /* global APP, $, interfaceConfig */
2
 const logger = require("jitsi-meet-logger").getLogger(__filename);
2
 const logger = require("jitsi-meet-logger").getLogger(__filename);
3
 
3
 
4
-import {
5
-    setFilmstripRemoteVideosCount
6
-} from '../../../react/features/filmstrip';
7
-
8
 import Filmstrip from "./Filmstrip";
4
 import Filmstrip from "./Filmstrip";
9
 import UIEvents from "../../../service/UI/UIEvents";
5
 import UIEvents from "../../../service/UI/UIEvents";
10
 import UIUtil from "../util/UIUtil";
6
 import UIUtil from "../util/UIUtil";
555
                     onComplete();
551
                     onComplete();
556
             });
552
             });
557
 
553
 
558
-        APP.store.dispatch(
559
-            setFilmstripRemoteVideosCount(this.getRemoteVideosCount()));
560
         return { localVideo, remoteVideo };
554
         return { localVideo, remoteVideo };
561
     },
555
     },
562
 
556
 

+ 1
- 13
react/features/filmstrip/actionTypes.js 查看文件

1
 import { Symbol } from '../base/react';
1
 import { Symbol } from '../base/react';
2
 
2
 
3
-/**
4
- * The type of action which signals to change the count of known remote videos
5
- * displayed in the filmstrip.
6
- *
7
- * {
8
- *     type: SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
9
- *     remoteVideosCount: number
10
- * }
11
- */
12
-export const SET_FILMSTRIP_REMOTE_VIDEOS_COUNT
13
-    = Symbol('SET_FILMSTRIP_REMOTE_VIDEOS_COUNT');
14
-
15
 /**
3
 /**
16
  * The type of action which signals to change the visibility of remote videos in
4
  * The type of action which signals to change the visibility of remote videos in
17
  * the filmstrip.
5
  * the filmstrip.
18
  *
6
  *
19
  * {
7
  * {
20
  *     type: SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
8
  *     type: SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
21
- *     removeVideosVisible: boolean
9
+ *     remoteVideosVisible: boolean
22
  * }
10
  * }
23
  */
11
  */
24
 export const SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY
12
 export const SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY

+ 0
- 17
react/features/filmstrip/actions.js 查看文件

1
 import {
1
 import {
2
-    SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
3
     SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
2
     SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
4
     SET_FILMSTRIP_VISIBILITY
3
     SET_FILMSTRIP_VISIBILITY
5
 } from './actionTypes';
4
 } from './actionTypes';
21
     };
20
     };
22
 }
21
 }
23
 
22
 
24
-/**
25
- * Sets how many remote videos are currently in the filmstrip.
26
- *
27
- * @param {number} remoteVideosCount - The number of remote videos.
28
- * @returns {{
29
- *     type: SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
30
- *     remoteVideosCount: number
31
- * }}
32
- */
33
-export function setFilmstripRemoteVideosCount(remoteVideosCount) {
34
-    return {
35
-        type: SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
36
-        remoteVideosCount
37
-    };
38
-}
39
-
40
 /**
23
 /**
41
  * Sets if the entire filmstrip should be visible.
24
  * Sets if the entire filmstrip should be visible.
42
  *
25
  *

+ 0
- 2
react/features/filmstrip/middleware.js 查看文件

3
 import { MiddlewareRegistry } from '../base/redux';
3
 import { MiddlewareRegistry } from '../base/redux';
4
 
4
 
5
 import {
5
 import {
6
-    SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
7
     SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
6
     SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
8
     SET_FILMSTRIP_VISIBILITY
7
     SET_FILMSTRIP_VISIBILITY
9
 } from './actionTypes';
8
 } from './actionTypes';
15
     const result = next(action);
14
     const result = next(action);
16
 
15
 
17
     switch (action.type) {
16
     switch (action.type) {
18
-    case SET_FILMSTRIP_REMOTE_VIDEOS_COUNT:
19
     case SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY:
17
     case SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY:
20
     case SET_FILMSTRIP_VISIBILITY: {
18
     case SET_FILMSTRIP_VISIBILITY: {
21
         if (typeof APP !== 'undefined') {
19
         if (typeof APP !== 'undefined') {

+ 0
- 7
react/features/filmstrip/reducer.js 查看文件

1
 import { ReducerRegistry } from '../base/redux';
1
 import { ReducerRegistry } from '../base/redux';
2
 import {
2
 import {
3
-    SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
4
     SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
3
     SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
5
     SET_FILMSTRIP_VISIBILITY
4
     SET_FILMSTRIP_VISIBILITY
6
 } from './actionTypes';
5
 } from './actionTypes';
7
 
6
 
8
 const DEFAULT_STATE = {
7
 const DEFAULT_STATE = {
9
-    remoteVideosCount: 0,
10
     remoteVideosVisible: true,
8
     remoteVideosVisible: true,
11
     visible: true
9
     visible: true
12
 };
10
 };
15
     'features/filmstrip',
13
     'features/filmstrip',
16
     (state = DEFAULT_STATE, action) => {
14
     (state = DEFAULT_STATE, action) => {
17
         switch (action.type) {
15
         switch (action.type) {
18
-        case SET_FILMSTRIP_REMOTE_VIDEOS_COUNT:
19
-            return {
20
-                ...state,
21
-                remoteVideosCount: action.remoteVideosCount
22
-            };
23
         case SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY:
16
         case SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY:
24
             return {
17
             return {
25
                 ...state,
18
                 ...state,

+ 46
- 8
react/features/video-status-label/components/VideoStatusLabel.js 查看文件

29
         _conferenceStarted: React.PropTypes.bool,
29
         _conferenceStarted: React.PropTypes.bool,
30
 
30
 
31
         /**
31
         /**
32
-         * Whether or not the filmstrip is displayed with remote videos.
32
+         * Whether or not the filmstrip is displayed with remote videos. Used to
33
+         * determine display classes to set.
33
          */
34
          */
34
         _filmstripVisible: React.PropTypes.bool,
35
         _filmstripVisible: React.PropTypes.bool,
35
 
36
 
38
          */
39
          */
39
         _largeVideoHD: React.PropTypes.bool,
40
         _largeVideoHD: React.PropTypes.bool,
40
 
41
 
42
+        /**
43
+         * Whether or note remote videos are visible in the filmstrip,
44
+         * regardless of count. Used to determine display classes to set.
45
+         */
46
+        _remoteVideosVisible: React.PropTypes.bool,
47
+
41
         /**
48
         /**
42
          * Invoked to request toggling of audio only mode.
49
          * Invoked to request toggling of audio only mode.
43
          */
50
          */
58
     constructor(props) {
65
     constructor(props) {
59
         super(props);
66
         super(props);
60
 
67
 
68
+        this.state = {
69
+            // Whether or not the filmstrip is transitioning from not visible
70
+            // to visible. Used to set a transition class for animation.
71
+            togglingToVisible: false
72
+        };
73
+
61
         // Bind event handler so it is only bound once for every instance.
74
         // Bind event handler so it is only bound once for every instance.
62
         this._toggleAudioOnly = this._toggleAudioOnly.bind(this);
75
         this._toggleAudioOnly = this._toggleAudioOnly.bind(this);
63
     }
76
     }
64
 
77
 
78
+    /**
79
+     * Updates the state for whether or not the filmstrip is being toggled to
80
+     * display after having being hidden.
81
+     *
82
+     * @inheritdoc
83
+     * @param {Object} nextProps - The read-only props which this Component will
84
+     * receive.
85
+     * @returns {void}
86
+     */
87
+    componentWillReceiveProps(nextProps) {
88
+        this.setState({
89
+            togglingToVisible: nextProps._filmstripVisible
90
+                && !this.props._filmstripVisible
91
+        });
92
+    }
93
+
65
     /**
94
     /**
66
      * Implements React's {@link Component#render()}.
95
      * Implements React's {@link Component#render()}.
67
      *
96
      *
73
             _audioOnly,
102
             _audioOnly,
74
             _conferenceStarted,
103
             _conferenceStarted,
75
             _filmstripVisible,
104
             _filmstripVisible,
105
+            _remoteVideosVisible,
76
             _largeVideoHD,
106
             _largeVideoHD,
77
             t
107
             t
78
         } = this.props;
108
         } = this.props;
93
                 ? t('videoStatus.hd') : t('videoStatus.sd');
123
                 ? t('videoStatus.hd') : t('videoStatus.sd');
94
         }
124
         }
95
 
125
 
96
-        const filmstripClassName
126
+        // Determine which classes should be set on the component. These classes
127
+        // will used to help with animations and setting position.
128
+        const baseClasses = 'video-state-indicator moveToCorner';
129
+        const filmstrip
97
             = _filmstripVisible ? 'with-filmstrip' : 'without-filmstrip';
130
             = _filmstripVisible ? 'with-filmstrip' : 'without-filmstrip';
131
+        const remoteVideosVisible = _remoteVideosVisible
132
+            ? 'with-remote-videos'
133
+            : 'without-remote-videos';
134
+        const opening = this.state.togglingToVisible ? 'opening' : '';
98
         const classNames
135
         const classNames
99
-            = `video-state-indicator moveToCorner ${filmstripClassName}`;
136
+            = `${baseClasses} ${filmstrip} ${remoteVideosVisible} ${opening}`;
100
 
137
 
101
         return (
138
         return (
102
             <div
139
             <div
159
  * @returns {{
196
  * @returns {{
160
  *     _audioOnly: boolean,
197
  *     _audioOnly: boolean,
161
  *     _conferenceStarted: boolean,
198
  *     _conferenceStarted: boolean,
162
- *     _largeVideoHD: (boolean|undefined)
199
+ *     _filmstripVisible: true,
200
+ *     _largeVideoHD: (boolean|undefined),
201
+ *     _remoteVideosVisible: boolean
163
  * }}
202
  * }}
164
  */
203
  */
165
 function _mapStateToProps(state) {
204
 function _mapStateToProps(state) {
169
         isLargeVideoHD
208
         isLargeVideoHD
170
     } = state['features/base/conference'];
209
     } = state['features/base/conference'];
171
     const {
210
     const {
172
-        remoteVideosCount,
173
         remoteVideosVisible,
211
         remoteVideosVisible,
174
         visible
212
         visible
175
     } = state['features/filmstrip'];
213
     } = state['features/filmstrip'];
177
     return {
215
     return {
178
         _audioOnly: audioOnly,
216
         _audioOnly: audioOnly,
179
         _conferenceStarted: Boolean(conference),
217
         _conferenceStarted: Boolean(conference),
180
-        _filmstripVisible:
181
-            Boolean(remoteVideosCount && remoteVideosVisible && visible),
182
-        _largeVideoHD: isLargeVideoHD
218
+        _filmstripVisible: visible,
219
+        _largeVideoHD: isLargeVideoHD,
220
+        _remoteVideosVisible: remoteVideosVisible
183
     };
221
     };
184
 }
222
 }
185
 
223
 

Loading…
取消
儲存