Explorar el Código

Video thumbnails redesign

j8
yanas hace 8 años
padre
commit
0013745783

+ 1
- 1
css/_font.scss Ver fichero

@@ -16,7 +16,7 @@
16 16
     font-weight: normal;
17 17
     font-variant: normal;
18 18
     text-transform: none;
19
-    line-height: 0.75em;
19
+    line-height: 1.22em;
20 20
     font-size: 1.22em;
21 21
 
22 22
     /* Better Font Rendering =========== */

+ 13
- 0
css/_mixins.scss Ver fichero

@@ -36,6 +36,19 @@
36 36
   }
37 37
 }
38 38
 
39
+@mixin circle($diameter) {
40
+    width: $diameter;
41
+    height: $diameter;
42
+    border-radius: 50%;
43
+}
44
+
45
+@mixin absoluteAligning($sizeX, $sizeY) {
46
+    top: 50%;
47
+    left: 50%;
48
+    position: absolute;
49
+    @include transform(translate(-#{$sizeX / 2}, -#{$sizeY / 2}))
50
+}
51
+
39 52
 @mixin transform($func) {
40 53
     -moz-transform: $func;
41 54
     -ms-transform: $func;

+ 22
- 5
css/_variables.scss Ver fichero

@@ -10,6 +10,11 @@ $hangupFontSize: 2em;
10 10
  */
11 11
 $defaultToolbarSize: 50px;
12 12
 
13
+// Video layout.
14
+$thumbnailIndicatorSize: 23px;
15
+$thumbnailIndicatorBorder: 0px;
16
+$thumbnailVideoMargin: 2px;
17
+
13 18
 /**
14 19
  * Color variables.
15 20
  */
@@ -17,13 +22,29 @@ $defaultColor: #F1F1F1;
17 22
 $defaultSemiDarkColor: #ACACAC;
18 23
 $defaultDarkColor: #4F4F4F;
19 24
 $defaultBackground: #474747;
25
+
26
+// Toolbar
20 27
 $toolbarSelectBackground: rgba(0, 0, 0, .6);
28
+
29
+// Main controls
21 30
 $inputBackground: rgba(132, 132, 132, .5);
22 31
 $inputSemiBackground: rgba(132, 132, 132, .8);
23 32
 $inputLightBackground: #EBEBEB;
24 33
 $inputBorderColor: #EBEBEB;
25 34
 $buttonBackground: #44A5FF;
26 35
 
36
+// Video layout.
37
+$videoThumbnailHovered: #44A5FF;
38
+$videoThumbnailSelected: #165ecc;
39
+$participantNameColor: #fff;
40
+$thumbnailPictogramColor: #fff;
41
+$dominantSpeakerBg: #165ecc;
42
+$raiseHandBg: #D6D61E;
43
+
44
+$rateStarDefault: #ccc;
45
+$rateStarActivity: #165ecc;
46
+$rateStarLabelColor: #333;
47
+
27 48
 /**
28 49
  * Misc.
29 50
  */
@@ -34,8 +55,4 @@ $defaultWatermarkLink: '../images/watermark.png';
34 55
  * Z-indexes. TODO: Replace this by a function.
35 56
  */
36 57
 $toolbarZ: 900;
37
-$overlayZ: 800;
38
-
39
-$rateStarDefault: #ccc;
40
-$rateStarActivity: #f6c342;
41
-$rateStarLabelColor: #333;
58
+$overlayZ: 800;

+ 62
- 44
css/_videolayout_default.scss Ver fichero

@@ -13,17 +13,17 @@
13 13
     display: -ms-flexbox;
14 14
     display: -webkit-flex;
15 15
     display: flex;
16
-    flex-direction: row;
16
+    flex-direction: row-reverse;
17 17
     flex-wrap: nowrap;
18
-    justify-content: flex-end;
18
+    justify-content: flex-start;
19 19
 
20 20
     position:absolute;
21 21
     text-align:right;
22 22
     height:196px;
23
-    padding: 18px;
23
+    padding: 10px 10px 10px 5px;
24 24
     bottom: 0;
25 25
     left: 0;
26
-    right: 20px;
26
+    right: 0;
27 27
     width:auto;
28 28
     border:1px solid transparent;
29 29
     z-index: 5;
@@ -43,10 +43,23 @@
43 43
 
44 44
 #remoteVideos .videocontainer {
45 45
     display: none;
46
+    position: relative;
46 47
     background-color: black;
47 48
     background-size: contain;
48 49
     border-radius:1px;
49
-    border: 1px solid #212425;
50
+    margin: 0 $thumbnailVideoMargin;
51
+    border: 1px solid $defaultDarkColor;
52
+}
53
+
54
+.videocontainer__toolbar {
55
+    position: absolute;
56
+    bottom: 0;
57
+    left: 0;
58
+    z-index: 1;
59
+    width: 100%;
60
+    height: 25px;
61
+    max-height: 100%;
62
+    background-color: rgba(0, 0, 0, 0.5);
50 63
 }
51 64
 
52 65
 #remoteVideos .videocontainer.videoContainerFocused {
@@ -58,18 +71,13 @@
58 71
     -webkit-animation-iteration-count: 1;
59 72
 }
60 73
 
61
-#remoteVideos .videocontainer:hover {
62
-    border: 1px solid #c1c1c1;
63
-}
64
-
65 74
 #remoteVideos .videocontainer.videoContainerFocused {
66
-    box-shadow: inset 0 0 28px #006d91;
67
-    border: 1px solid #006d91;
75
+    border: 1px solid $videoThumbnailSelected;
68 76
 }
69 77
 
78
+#remoteVideos .videocontainer:hover,
70 79
 #remoteVideos .videocontainer.videoContainerFocused:hover {
71
-    box-shadow: inset 0 0 5px #c1c1c1, 0 0 10px #c1c1c1, inset 0 0 60px #006d91;
72
-    border: 1px solid #c1c1c1;
80
+    border: 1px solid $videoThumbnailHovered;
73 81
 }
74 82
 
75 83
 #localVideoWrapper {
@@ -145,11 +153,11 @@
145 153
 #remoteVideos .videocontainer>div.remotevideomenu {
146 154
     position: absolute;
147 155
     color: #FFFFFF;
148
-    top: 0;
149
-    left: 0;
156
+    bottom: 0;
157
+    right: 0;
150 158
     padding: 5px 0px;
151 159
     width: 25px;
152
-    font-size: 11pt;
160
+    font-size: 9pt;
153 161
     text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
154 162
     border: 0px;
155 163
     z-index: 2;
@@ -166,22 +174,28 @@
166 174
 
167 175
 .videocontainer>span.displayname,
168 176
 .videocontainer>input.displayname {
169
-    display: none;
177
+    display: inline-block;
170 178
     position: absolute;
171
-    color: #FFFFFF;
172
-    background: rgba(0,0,0,.7);
179
+    bottom: 4px;
180
+    left: 25%;
181
+    color: $participantNameColor;
173 182
     text-align: center;
174 183
     text-overflow: ellipsis;
175
-    width: 70%;
176
-    height: 20%;
177
-    left: 15%;
178
-    top: 40%;
179
-    padding: 5px;
180
-    font-size: 11pt;
184
+    width: 50%;
185
+    font-size: 12px;
186
+    font-weight: 100;
187
+    letter-spacing: 1px;
181 188
     overflow: hidden;
182 189
     white-space: nowrap;
183 190
     z-index: 2;
184
-    border-radius:3px;
191
+}
192
+
193
+.videocontainer>input.displayname {
194
+    outline: none;
195
+    border: none;
196
+    background: none;
197
+    box-shadow: none;
198
+    padding: 0;
185 199
 }
186 200
 
187 201
 .videocontainer>span.status {
@@ -291,7 +305,8 @@
291 305
     display: inline-block;
292 306
     position: absolute;
293 307
     color: #FFFFFF;
294
-    top: 0;
308
+    bottom: 0;
309
+    left: 0;
295 310
     padding: 8px 5px;
296 311
     width: 25px;
297 312
     font-size: 8pt;
@@ -305,8 +320,7 @@
305 320
     display: inline-block;
306 321
     position: absolute;
307 322
     color: #FFFFFF;
308
-    top: 0;
309
-    right: 0;
323
+    bottom: 0;
310 324
     padding: 8px 5px;
311 325
     width: 25px;
312 326
     font-size: 8pt;
@@ -316,24 +330,30 @@
316 330
 }
317 331
 
318 332
 .videocontainer>span.indicator {
319
-    bottom: 0px;
333
+    position: absolute;
334
+    top: 0px;
320 335
     left: 0px;
321
-    width: 25px;
322
-    height: 25px;
336
+    @include circle($thumbnailIndicatorSize);
337
+    box-sizing: border-box;
338
+    line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
323 339
     z-index: 3;
324 340
     text-align: center;
325
-    border-radius: 50%;
326
-    background: #21B9FC;
327
-    margin: 5px;
341
+    background: $dominantSpeakerBg;
342
+    margin: 7px;
328 343
     display: inline-block;
329
-    position: absolute;
330
-    color: #FFFFFF;
331
-    font-size: 11pt;
332
-    border: 0px;
344
+    color: $thumbnailPictogramColor;
345
+    font-size: 8pt;
346
+    border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
347
+}
348
+
349
+.videocontainer>#raisehandindicator {
350
+    background: $raiseHandBg;
333 351
 }
334 352
 
335 353
 #indicatoricon {
336
-    padding-top: 5px;
354
+    width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
355
+    height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
356
+    line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
337 357
 }
338 358
 
339 359
 #reloadPresentation {
@@ -395,10 +415,8 @@
395 415
 }
396 416
 
397 417
 .userAvatar {
398
-    height: 100%;
399
-    position: absolute;
400
-    left: 0;
401
-    border-radius: 2px;
418
+    @include circle(60px);
419
+    @include absoluteAligning(60px, 60px);
402 420
 }
403 421
 
404 422
 .sharedVideoAvatar {

+ 2
- 1
index.html Ver fichero

@@ -238,12 +238,13 @@
238 238
             </div>
239 239
 
240 240
             <div id="remoteVideos">
241
-                <span id="localVideoContainer" class="videocontainer">
241
+                <span id="localVideoContainer" class="videocontainer videocontainer_small">
242 242
                     <span id="localVideoWrapper">
243 243
                         <!--<video id="localVideo" autoplay muted></video> - is now per stream generated -->
244 244
                     </span>
245 245
                     <audio id="localAudio" autoplay muted></audio>
246 246
                     <span class="focusindicator"></span>
247
+                    <div class="videocontainer__toolbar"></div>
247 248
                 </span>
248 249
                 <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
249 250
                 <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>

+ 6
- 2
interface_config.js Ver fichero

@@ -34,5 +34,9 @@ var interfaceConfig = {
34 34
     filmStripOnly: false,
35 35
     RANDOM_AVATAR_URL_PREFIX: false,
36 36
     RANDOM_AVATAR_URL_SUFFIX: false,
37
-    FILM_STRIP_MAX_HEIGHT: 120
38
-};
37
+    FILM_STRIP_MAX_HEIGHT: 120,
38
+    LOCAL_THUMBNAIL_RATIO_WIDTH: 16,
39
+    LOCAL_THUMBNAIL_RATIO_HEIGHT: 9,
40
+    REMOTE_THUMBNAIL_RATIO_WIDTH: 1,
41
+    REMOTE_THUMBNAIL_RATIO_HEIGHT: 1
42
+};

+ 1
- 0
modules/UI/Feedback.js Ver fichero

@@ -1,5 +1,6 @@
1 1
 /* global $, APP, config, interfaceConfig, JitsiMeetJS */
2 2
 import UIEvents from "../../service/UI/UIEvents";
3
+import UIUtil from "./util/UIUtil";
3 4
 
4 5
 /**
5 6
  * Constructs the html for the overall feedback window.

+ 33
- 21
modules/UI/audio_levels/AudioLevels.js Ver fichero

@@ -10,7 +10,7 @@ let ASDrawContext = null;
10 10
 let audioLevelCanvasCache = {};
11 11
 let dominantSpeakerAudioElement = null;
12 12
 
13
-function initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
13
+function _initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
14 14
     let ASRadius = dominantSpeakerAvatarSize / 2;
15 15
     let ASCenter = (dominantSpeakerAvatarSize + ASRadius) / 2;
16 16
 
@@ -28,7 +28,9 @@ function initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
28 28
 /**
29 29
  * Resizes the given audio level canvas to match the given thumbnail size.
30 30
  */
31
-function resizeAudioLevelCanvas(audioLevelCanvas, thumbnailWidth, thumbnailHeight) {
31
+function _resizeAudioLevelCanvas(   audioLevelCanvas,
32
+                                    thumbnailWidth,
33
+                                    thumbnailHeight) {
32 34
     audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
33 35
     audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
34 36
 }
@@ -138,18 +140,18 @@ const AudioLevels = {
138 140
         dominantSpeakerAudioElement.height = dominantSpeakerHeight;
139 141
 
140 142
         let dominantSpeakerAvatar = $("#dominantSpeakerAvatar");
141
-        initDominantSpeakerAudioLevels(dominantSpeakerAvatar.width());
143
+        _initDominantSpeakerAudioLevels(dominantSpeakerAvatar.width());
142 144
     },
143 145
 
144 146
     /**
145 147
      * Updates the audio level canvas for the given id. If the canvas
146 148
      * didn't exist we create it.
147 149
      */
148
-    updateAudioLevelCanvas (id, thumbWidth, thumbHeight) {
149
-        let videoSpanId = 'localVideoContainer';
150
-        if (id) {
151
-            videoSpanId = `participant_${id}`;
152
-        }
150
+    createAudioLevelCanvas (id, thumbWidth, thumbHeight) {
151
+
152
+        let videoSpanId = (id === "local")
153
+                        ? "localVideoContainer"
154
+                        : `participant_${id}`;
153 155
 
154 156
         let videoSpan = document.getElementById(videoSpanId);
155 157
 
@@ -172,13 +174,13 @@ const AudioLevels = {
172 174
                 = `-${interfaceConfig.CANVAS_EXTRA/2}px`;
173 175
             audioLevelCanvas.style.left
174 176
                 = `-${interfaceConfig.CANVAS_EXTRA/2}px`;
175
-            resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
177
+            _resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
176 178
 
177 179
             videoSpan.appendChild(audioLevelCanvas);
178 180
         } else {
179 181
             audioLevelCanvas = audioLevelCanvas.get(0);
180 182
 
181
-            resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
183
+            _resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
182 184
         }
183 185
     },
184 186
 
@@ -242,19 +244,29 @@ const AudioLevels = {
242 244
         ASDrawContext.fill();
243 245
     },
244 246
 
245
-    updateCanvasSize (thumbWidth, thumbHeight) {
246
-        let canvasWidth = thumbWidth + interfaceConfig.CANVAS_EXTRA;
247
-        let canvasHeight = thumbHeight + interfaceConfig.CANVAS_EXTRA;
248
-
249
-        FilmStrip.getThumbs().children('canvas').each(function () {
250
-            $(this).attr('width', canvasWidth);
251
-            $(this).attr('height', canvasHeight);
247
+    updateCanvasSize (localVideo, remoteVideo) {
248
+        let localCanvasWidth
249
+            = localVideo.thumbWidth + interfaceConfig.CANVAS_EXTRA;
250
+        let localCanvasHeight
251
+            = localVideo.thumbHeight + interfaceConfig.CANVAS_EXTRA;
252
+        let remoteCanvasWidth
253
+            = remoteVideo.thumbWidth + interfaceConfig.CANVAS_EXTRA;
254
+        let remoteCanvasHeight
255
+            = remoteVideo.thumbHeight + interfaceConfig.CANVAS_EXTRA;
256
+
257
+        let { remoteThumbs, localThumb } = FilmStrip.getThumbs();
258
+
259
+        remoteThumbs.children('canvas').each(function () {
260
+            $(this).attr('width', remoteCanvasWidth);
261
+            $(this).attr('height', remoteCanvasHeight);
252 262
         });
253 263
 
254
-        Object.keys(audioLevelCanvasCache).forEach(function (id) {
255
-            audioLevelCanvasCache[id].width = canvasWidth;
256
-            audioLevelCanvasCache[id].height = canvasHeight;
257
-        });
264
+        if(localThumb) {
265
+            localThumb.children('canvas').each(function () {
266
+                $(this).attr('width', localCanvasWidth);
267
+                $(this).attr('height', localCanvasHeight);
268
+            });
269
+        }
258 270
     }
259 271
 };
260 272
 

+ 1
- 2
modules/UI/toolbars/Toolbar.js Ver fichero

@@ -7,7 +7,6 @@ import SideContainerToggler from "../side_pannels/SideContainerToggler";
7 7
 let roomUrl = null;
8 8
 let emitter = null;
9 9
 
10
-
11 10
 /**
12 11
  * Opens the invite link dialog.
13 12
  */
@@ -766,4 +765,4 @@ const Toolbar = {
766 765
     }
767 766
 };
768 767
 
769
-export default Toolbar;
768
+export default Toolbar;

+ 126
- 30
modules/UI/videolayout/FilmStrip.js Ver fichero

@@ -3,8 +3,6 @@
3 3
 import UIEvents from "../../../service/UI/UIEvents";
4 4
 import UIUtil from "../util/UIUtil";
5 5
 
6
-const thumbAspectRatio = 1 / 1;
7
-
8 6
 const FilmStrip = {
9 7
     /**
10 8
      *
@@ -66,13 +64,52 @@ const FilmStrip = {
66 64
             - parseInt(this.filmStrip.css('paddingRight'), 10);
67 65
     },
68 66
 
67
+    calculateThumbnailSize() {
68
+        let availableSizes = this.calculateAvailableSize();
69
+        let width = availableSizes.availableWidth;
70
+        let height = availableSizes.availableHeight;
71
+
72
+        return this.calculateThumbnailSizeFromAvailable(width, height);
73
+    },
74
+
69 75
     /**
70
-     * Calculates the thumbnail size.
76
+     * Normalizes local and remote thumbnail ratios
71 77
      */
72
-     calculateThumbnailSize () {
73
-        let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
78
+     normalizeThumbnailRatio () {
79
+        let remoteHeightRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_HEIGHT;
80
+        let remoteWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_WIDTH;
81
+
82
+        let localHeightRatio = interfaceConfig.LOCAL_THUMBNAIL_RATIO_HEIGHT;
83
+        let localWidthRatio = interfaceConfig.LOCAL_THUMBNAIL_RATIO_WIDTH;
84
+
85
+        let commonHeightRatio = remoteHeightRatio * localHeightRatio;
74 86
 
75
-        let numvids = this.getThumbs(true).length;
87
+        let localRatioCoefficient = localWidthRatio / localHeightRatio;
88
+        let remoteRatioCoefficient = remoteWidthRatio / remoteHeightRatio;
89
+
90
+        remoteWidthRatio = commonHeightRatio * remoteRatioCoefficient;
91
+        remoteHeightRatio = commonHeightRatio;
92
+
93
+        localWidthRatio = commonHeightRatio * localRatioCoefficient;
94
+        localHeightRatio = commonHeightRatio;
95
+
96
+        let localRatio = {
97
+            widthRatio: localWidthRatio,
98
+            heightRatio: localHeightRatio
99
+        };
100
+
101
+        let remoteRatio = {
102
+            widthRatio: remoteWidthRatio,
103
+            heightRatio: remoteHeightRatio
104
+        };
105
+
106
+        return { localRatio, remoteRatio };
107
+    },
108
+
109
+    calculateAvailableSize() {
110
+        let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
111
+        let thumbs = this.getThumbs(true);
112
+        let numvids = thumbs.remoteThumbs.length;
76 113
 
77 114
         let localVideoContainer = $("#localVideoContainer");
78 115
 
@@ -92,11 +129,10 @@ const FilmStrip = {
92 129
 
93 130
         let availableWidth = videoAreaAvailableWidth;
94 131
 
95
-        // If the number of videos is 0 or undefined we don't need to calculate
96
-        // further.
97
-        if (numvids)
132
+        // If local thumb is not hidden
133
+        if(thumbs.localThumb) {
98 134
             availableWidth = Math.floor(
99
-                (videoAreaAvailableWidth - numvids * (
135
+                (videoAreaAvailableWidth - (
100 136
                 UIUtil.parseCssInt(
101 137
                     localVideoContainer.css('borderLeftWidth'), 10)
102 138
                 + UIUtil.parseCssInt(
@@ -109,36 +145,90 @@ const FilmStrip = {
109 145
                     localVideoContainer.css('marginLeft'), 10)
110 146
                 + UIUtil.parseCssInt(
111 147
                     localVideoContainer.css('marginRight'), 10)))
112
-                / numvids);
148
+            );
149
+        }
150
+
151
+        // If the number of videos is 0 or undefined we don't need to calculate
152
+        // further.
153
+        if (numvids) {
154
+            let remoteVideoContainer = thumbs.remoteThumbs.eq(0);
155
+            availableWidth = Math.floor(
156
+                (videoAreaAvailableWidth - numvids * (
157
+                UIUtil.parseCssInt(
158
+                    remoteVideoContainer.css('borderLeftWidth'), 10)
159
+                + UIUtil.parseCssInt(
160
+                    remoteVideoContainer.css('borderRightWidth'), 10)
161
+                + UIUtil.parseCssInt(
162
+                    remoteVideoContainer.css('paddingLeft'), 10)
163
+                + UIUtil.parseCssInt(
164
+                    remoteVideoContainer.css('paddingRight'), 10)
165
+                + UIUtil.parseCssInt(
166
+                    remoteVideoContainer.css('marginLeft'), 10)
167
+                + UIUtil.parseCssInt(
168
+                    remoteVideoContainer.css('marginRight'), 10)))
169
+            );
170
+        }
113 171
 
114 172
         let maxHeight
115 173
             // If the MAX_HEIGHT property hasn't been specified
116 174
             // we have the static value.
117
-            = Math.min( interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
118
-                        availableHeight);
175
+            = Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
176
+            availableHeight);
119 177
 
120 178
         availableHeight
121
-            = Math.min( maxHeight, window.innerHeight - 18);
179
+            = Math.min(maxHeight, window.innerHeight - 18);
180
+
181
+        return { availableWidth, availableHeight };
182
+    },
183
+
184
+    calculateThumbnailSizeFromAvailable(availableWidth, availableHeight) {
185
+        let { localRatio, remoteRatio } = this.normalizeThumbnailRatio();
186
+        let { remoteThumbs } = this.getThumbs(true);
187
+        let remoteProportion = remoteRatio.widthRatio * remoteThumbs.length;
188
+        let widthProportion = remoteProportion + localRatio.widthRatio;
122 189
 
123
-        if (availableHeight < availableWidth) {
124
-            availableWidth = availableHeight;
190
+        let heightUnit = availableHeight / localRatio.heightRatio;
191
+        let widthUnit = availableWidth / widthProportion;
192
+
193
+        if (heightUnit < widthUnit) {
194
+            widthUnit = heightUnit;
125 195
         }
126 196
         else
127
-            availableHeight = availableWidth;
197
+            heightUnit = widthUnit;
198
+
199
+        let localVideo = {
200
+            thumbWidth: widthUnit * localRatio.widthRatio,
201
+            thumbHeight: heightUnit * localRatio.heightRatio
202
+        };
203
+        let remoteVideo = {
204
+            thumbWidth: widthUnit * remoteRatio.widthRatio,
205
+            thumbHeight: widthUnit * remoteRatio.heightRatio
206
+        };
128 207
 
129 208
         return {
130
-            thumbWidth: availableWidth,
131
-            thumbHeight: availableHeight
209
+            localVideo,
210
+            remoteVideo
132 211
         };
133 212
     },
134 213
 
135
-    resizeThumbnails (thumbWidth, thumbHeight,
214
+    resizeThumbnails (local, remote,
136 215
                       animate = false, forceUpdate = false) {
137 216
 
138 217
         return new Promise(resolve => {
139
-            this.getThumbs(!forceUpdate).animate({
140
-                height: thumbHeight,
141
-                width: thumbWidth
218
+            let thumbs = this.getThumbs(!forceUpdate);
219
+
220
+            thumbs.localThumb.animate({
221
+                height: local.thumbHeight,
222
+                width: local.thumbWidth
223
+            }, {
224
+                queue: false,
225
+                duration: animate ? 500 : 0,
226
+                complete:  resolve
227
+            });
228
+
229
+            thumbs.remoteThumbs.animate({
230
+                height: remote.thumbHeight,
231
+                width: remote.thumbWidth
142 232
             }, {
143 233
                 queue: false,
144 234
                 duration: animate ? 500 : 0,
@@ -147,7 +237,7 @@ const FilmStrip = {
147 237
 
148 238
             this.filmStrip.animate({
149 239
                 // adds 2 px because of small video 1px border
150
-                height: thumbHeight + 2
240
+                height: remote.thumbHeight + 2
151 241
             }, {
152 242
                 queue: false,
153 243
                 duration: animate ? 500 : 0
@@ -165,13 +255,19 @@ const FilmStrip = {
165 255
             selector += ':visible';
166 256
         }
167 257
 
258
+        let localThumb = $("#localVideoContainer");
259
+        let remoteThumbs = this.filmStrip.children(selector)
260
+            .not("#localVideoContainer");
261
+
168 262
         // Exclude the local video container if it has been hidden.
169
-        if ($("#localVideoContainer").hasClass("hidden"))
170
-            return this.filmStrip.children(selector)
171
-                    .not("#localVideoContainer");
172
-        else
173
-            return this.filmStrip.children(selector);
174
-    }
263
+        if (localThumb.hasClass("hidden")) {
264
+            return { remoteThumbs };
265
+        } else {
266
+            return { remoteThumbs, localThumb };
267
+        }
268
+
269
+    },
270
+
175 271
 };
176 272
 
177 273
 export default FilmStrip;

+ 13
- 15
modules/UI/videolayout/LocalVideo.js Ver fichero

@@ -11,7 +11,6 @@ function LocalVideo(VideoLayout, emitter) {
11 11
     this.videoSpanId = "localVideoContainer";
12 12
     this.container = $("#localVideoContainer").get(0);
13 13
     this.localVideoId = null;
14
-    this.bindHoverHandler();
15 14
     if(config.enableLocalVideoFlip)
16 15
         this._buildContextMenu();
17 16
     this.isLocal = true;
@@ -44,7 +43,7 @@ function createEditDisplayNameButton() {
44 43
     editButton.className = 'displayname';
45 44
     UIUtil.setTooltip(editButton,
46 45
         "videothumbnail.editnickname",
47
-        "top");
46
+        "left");
48 47
     editButton.innerHTML = '<i class="icon-edit"></i>';
49 48
 
50 49
     return editButton;
@@ -72,7 +71,7 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
72 71
             if (displayName && displayName.length > 0) {
73 72
                 meHTML = APP.translation.generateTranslationHTML("me");
74 73
                 $('#localDisplayName').html(
75
-                    UIUtil.escapeHtml(displayName) + ' (' + meHTML + ')'
74
+                    `${UIUtil.escapeHtml(displayName)} (${meHTML})`
76 75
                 );
77 76
             } else {
78 77
                 $('#localDisplayName').html(defaultLocalDisplayName);
@@ -80,11 +79,9 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
80 79
         }
81 80
         this.updateView();
82 81
     } else {
83
-        var editButton = createEditDisplayNameButton();
84
-
85 82
         nameSpan = document.createElement('span');
86 83
         nameSpan.className = 'displayname';
87
-        $('#' + this.videoSpanId)[0].appendChild(nameSpan);
84
+        document.getElementById(this.videoSpanId).appendChild(nameSpan);
88 85
 
89 86
 
90 87
         if (displayName && displayName.length > 0) {
@@ -97,7 +94,6 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
97 94
 
98 95
 
99 96
         nameSpan.id = 'localDisplayName';
100
-        this.container.appendChild(editButton);
101 97
         //translates popover of edit button
102 98
         APP.translation.translateElement($("a.displayname"));
103 99
 
@@ -124,21 +120,23 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
124 120
         var self = this;
125 121
         $('#localVideoContainer .displayname')
126 122
             .bind("click", function (e) {
123
+                let $editDisplayName = $('#editDisplayName');
124
+                let $localDisplayName = $('#localDisplayName');
127 125
 
128
-                var editDisplayName = $('#editDisplayName');
129 126
                 e.preventDefault();
130 127
                 e.stopPropagation();
131
-                $('#localDisplayName').hide();
132
-                editDisplayName.show();
133
-                editDisplayName.focus();
134
-                editDisplayName.select();
128
+                $localDisplayName.hide();
129
+                $editDisplayName.show();
130
+                $editDisplayName.focus();
131
+                $editDisplayName.select();
135 132
 
136
-                editDisplayName.one("focusout", function (e) {
133
+                $editDisplayName.one("focusout", function (e) {
137 134
                     self.emitter.emit(UIEvents.NICKNAME_CHANGED, this.value);
138
-                    $('#editDisplayName').hide();
135
+                    $editDisplayName.hide();
136
+                    $localDisplayName.show();
139 137
                 });
140 138
 
141
-                editDisplayName.on('keydown', function (e) {
139
+                $editDisplayName.on('keydown', function (e) {
142 140
                     if (e.keyCode === 13) {
143 141
                         e.preventDefault();
144 142
                         $('#editDisplayName').hide();

+ 10
- 5
modules/UI/videolayout/RemoteVideo.js Ver fichero

@@ -17,7 +17,6 @@ function RemoteVideo(id, VideoLayout, emitter) {
17 17
     this.addRemoteVideoContainer();
18 18
     this.connectionIndicator = new ConnectionIndicator(this, id);
19 19
     this.setDisplayName();
20
-    this.bindHoverHandler();
21 20
     this.flipX = false;
22 21
     this.isLocal = false;
23 22
     this.isMuted = false;
@@ -34,8 +33,10 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
34 33
     if (APP.conference.isModerator) {
35 34
         this.addRemoteVideoMenu();
36 35
     }
37
-    let {thumbWidth, thumbHeight} = this.VideoLayout.resizeThumbnails();
38
-    AudioLevels.updateAudioLevelCanvas(this.id, thumbWidth, thumbHeight);
36
+
37
+    let { remoteVideo } = this.VideoLayout.resizeThumbnails();
38
+    let { thumbHeight, thumbWidth } = remoteVideo;
39
+    AudioLevels.createAudioLevelCanvas(this.id, thumbWidth, thumbHeight);
39 40
 
40 41
     return this.container;
41 42
 };
@@ -427,12 +428,16 @@ RemoteVideo.prototype.removeRemoteVideoMenu = function() {
427 428
 };
428 429
 
429 430
 RemoteVideo.createContainer = function (spanId) {
430
-    var container = document.createElement('span');
431
+    let container = document.createElement('span');
431 432
     container.id = spanId;
432 433
     container.className = 'videocontainer';
434
+
435
+    let toolbar = document.createElement('div');
436
+    toolbar.className = "videocontainer__toolbar";
437
+    container.appendChild(toolbar);
438
+
433 439
     var remotes = document.getElementById('remoteVideos');
434 440
     return remotes.appendChild(container);
435 441
 };
436 442
 
437
-
438 443
 export default RemoteVideo;

+ 19
- 31
modules/UI/videolayout/SmallVideo.js Ver fichero

@@ -171,26 +171,6 @@ SmallVideo.getStreamElementID = function (stream) {
171 171
     return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
172 172
 };
173 173
 
174
-/**
175
- * Configures hoverIn/hoverOut handlers.
176
- */
177
-SmallVideo.prototype.bindHoverHandler = function () {
178
-    // Add hover handler
179
-    var self = this;
180
-    $(this.container).hover(
181
-        function () {
182
-            self.showDisplayName(true);
183
-        },
184
-        function () {
185
-            // If the video has been "pinned" by the user we want to
186
-            // keep the display name on place.
187
-            if (!self.VideoLayout.isLargeVideoVisible() ||
188
-                !self.VideoLayout.isCurrentlyOnLarge(self.id))
189
-                self.showDisplayName(false);
190
-        }
191
-    );
192
-};
193
-
194 174
 /**
195 175
  * Updates the data for the indicator
196 176
  * @param id the id of the indicator
@@ -219,6 +199,7 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) {
219 199
         if (audioMutedSpan.length > 0) {
220 200
             audioMutedSpan.popover('hide');
221 201
             audioMutedSpan.remove();
202
+            this.updateIconPositions();
222 203
         }
223 204
     }
224 205
     else {
@@ -230,12 +211,14 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) {
230 211
                 "top");
231 212
 
232 213
             this.container.appendChild(audioMutedSpan);
233
-            APP.translation.translateElement($('#' + this.videoSpanId + " > span"));
214
+            APP.translation
215
+                .translateElement($('#' + this.videoSpanId + " > span"));
234 216
             var mutedIndicator = document.createElement('i');
235 217
             mutedIndicator.className = 'icon-mic-disabled';
236 218
             audioMutedSpan.appendChild(mutedIndicator);
237 219
 
238 220
         }
221
+
239 222
         this.updateIconPositions();
240 223
     }
241 224
     this.isMuted = isMuted;
@@ -254,6 +237,7 @@ SmallVideo.prototype.setMutedView = function(isMuted) {
254 237
     if (isMuted === false) {
255 238
         if (videoMutedSpan.length > 0) {
256 239
             videoMutedSpan.remove();
240
+            this.updateIconPositions();
257 241
         }
258 242
     }
259 243
     else {
@@ -270,7 +254,8 @@ SmallVideo.prototype.setMutedView = function(isMuted) {
270 254
                 "top");
271 255
             videoMutedSpan.appendChild(mutedIndicator);
272 256
             //translate texts for muted indicator
273
-            APP.translation.translateElement($('#' + this.videoSpanId  + " > span > i"));
257
+            APP.translation
258
+                .translateElement($('#' + this.videoSpanId  + " > span > i"));
274 259
         }
275 260
 
276 261
         this.updateIconPositions();
@@ -278,13 +263,18 @@ SmallVideo.prototype.setMutedView = function(isMuted) {
278 263
 };
279 264
 
280 265
 SmallVideo.prototype.updateIconPositions = function () {
281
-    var audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
282
-    var connectionIndicator = $('#' + this.videoSpanId + '>div.connectionindicator');
283
-    var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
266
+    let audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
267
+    let videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
268
+    audioMutedSpan.css({left: "0px"});
269
+    videoMutedSpan.css({left: (audioMutedSpan.length > 0? 25 : 0) + "px"});
270
+
271
+    var connectionIndicator
272
+        = $('#' + this.videoSpanId + '>div.connectionindicator');
284 273
     if(connectionIndicator.length > 0 &&
285 274
         connectionIndicator[0].style.display != "none") {
286 275
         audioMutedSpan.css({right: "23px"});
287
-        videoMutedSpan.css({right: ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
276
+        videoMutedSpan.css({right:
277
+            ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
288 278
     } else {
289 279
         audioMutedSpan.css({right: "0px"});
290 280
         videoMutedSpan.css({right: (audioMutedSpan.length > 0? 30 : 0) + "px"});
@@ -317,7 +307,8 @@ SmallVideo.prototype.createModeratorIndicatorElement = function () {
317 307
         "top");
318 308
 
319 309
     //translates text in focus indicators
320
-    APP.translation.translateElement($('#' + this.videoSpanId + ' .focusindicator'));
310
+    APP.translation
311
+        .translateElement($('#' + this.videoSpanId + ' .focusindicator'));
321 312
 };
322 313
 
323 314
 /**
@@ -406,8 +397,6 @@ SmallVideo.prototype.updateView = function () {
406 397
         setVisibility(video, showVideo);
407 398
     }
408 399
     setVisibility(avatar, showAvatar);
409
-
410
-    this.showDisplayName(!showVideo && !showAvatar);
411 400
 };
412 401
 
413 402
 SmallVideo.prototype.avatarChanged = function (avatarUrl) {
@@ -465,9 +454,8 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
465 454
     var indicatorSpanId = "raisehandindicator";
466 455
     var indicatorSpan = this.getIndicatorSpan(indicatorSpanId);
467 456
 
468
-    indicatorSpan.style.background = "#D6D61E";
469 457
     indicatorSpan.innerHTML
470
-        = "<i id='indicatoricon' class='fa fa-hand-paper-o'></i>";
458
+        = "<i id='indicatoricon' class='icon-raised-hand'></i>";
471 459
 
472 460
     // adds a tooltip
473 461
     UIUtil.setTooltip(indicatorSpan, "raisedHand", "left");

+ 14
- 12
modules/UI/videolayout/VideoLayout.js Ver fichero

@@ -105,8 +105,9 @@ var VideoLayout = {
105 105
         localVideoThumbnail.setVideoType(VIDEO_CONTAINER_TYPE);
106 106
         // if we do not resize the thumbs here, if there is no video device
107 107
         // the local video thumb maybe one pixel
108
-        let {thumbWidth, thumbHeight} = this.resizeThumbnails(false, true);
109
-        AudioLevels.updateAudioLevelCanvas(null, thumbWidth, thumbHeight);
108
+        let { localVideo } = this.resizeThumbnails(false, true);
109
+        AudioLevels.createAudioLevelCanvas(
110
+            "local", localVideo.thumbWidth, localVideo.thumbHeight);
110 111
 
111 112
         emitter.addListener(UIEvents.CONTACT_CLICKED, onContactClicked);
112 113
         this.lastNCount = config.channelLastN;
@@ -254,7 +255,8 @@ var VideoLayout = {
254 255
     electLastVisibleVideo () {
255 256
         // pick the last visible video in the row
256 257
         // if nobody else is left, this picks the local video
257
-        let thumbs = FilmStrip.getThumbs(true).filter('[id!="mixedstream"]');
258
+        let remoteThumbs = FilmStrip.getThumbs(true).remoteThumbs;
259
+        let thumbs = remoteThumbs.filter('[id!="mixedstream"]');
258 260
 
259 261
         let lastVisible = thumbs.filter(':visible:last');
260 262
         if (lastVisible.length) {
@@ -268,7 +270,7 @@ var VideoLayout = {
268 270
         }
269 271
 
270 272
         console.info("Last visible video no longer exists");
271
-        thumbs = FilmStrip.getThumbs();
273
+        thumbs = FilmStrip.getThumbs().remoteThumbs;
272 274
         if (thumbs.length) {
273 275
             let id = getPeerContainerResourceId(thumbs[0]);
274 276
             if (remoteVideos[id]) {
@@ -401,7 +403,7 @@ var VideoLayout = {
401 403
 
402 404
         // In case this is not currently in the last n we don't show it.
403 405
         if (localLastNCount && localLastNCount > 0 &&
404
-            FilmStrip.getThumbs().length >= localLastNCount + 2) {
406
+            FilmStrip.getThumbs().remoteThumbs.length >= localLastNCount + 2) {
405 407
             remoteVideo.showPeerContainer('hide');
406 408
         } else {
407 409
             VideoLayout.resizeThumbnails(false, true);
@@ -486,19 +488,19 @@ var VideoLayout = {
486 488
                         forceUpdate = false,
487 489
                         onComplete = null) {
488 490
 
489
-        let {thumbWidth, thumbHeight}
491
+        let { localVideo, remoteVideo }
490 492
             = FilmStrip.calculateThumbnailSize();
491 493
 
492
-        $('.userAvatar').css('left', (thumbWidth - thumbHeight) / 2);
494
+        let {thumbWidth, thumbHeight} = remoteVideo;
493 495
 
494
-        FilmStrip.resizeThumbnails(thumbWidth, thumbHeight,
496
+        FilmStrip.resizeThumbnails(localVideo, remoteVideo,
495 497
             animate, forceUpdate)
496 498
             .then(function () {
497
-                AudioLevels.updateCanvasSize(thumbWidth, thumbHeight);
499
+                AudioLevels.updateCanvasSize(localVideo, remoteVideo);
498 500
                 if (onComplete && typeof onComplete === "function")
499 501
                     onComplete();
500
-        });
501
-        return {thumbWidth, thumbHeight};
502
+            });
503
+        return { localVideo, remoteVideo };
502 504
     },
503 505
 
504 506
     /**
@@ -656,7 +658,7 @@ var VideoLayout = {
656 658
         var updateLargeVideo = false;
657 659
 
658 660
         // Handle LastN/local LastN changes.
659
-        FilmStrip.getThumbs().each(( index, element ) => {
661
+        FilmStrip.getThumbs().remoteThumbs.each(( index, element ) => {
660 662
             var resourceJid = getPeerContainerResourceId(element);
661 663
             var smallVideo = remoteVideos[resourceJid];
662 664
 

+ 5
- 5
package.json Ver fichero

@@ -21,18 +21,18 @@
21 21
     "bootstrap": "3.1.1",
22 22
     "events": "*",
23 23
     "i18next-client": "1.7.7",
24
-    "jquery": "~2.1.1",
25 24
     "jQuery-Impromptu": "git+https://github.com/trentrichardson/jQuery-Impromptu.git#v6.0.0",
26
-    "lib-jitsi-meet": "git+https://github.com/jitsi/lib-jitsi-meet.git",
25
+    "jquery": "~2.1.1",
27 26
     "jquery-contextmenu": "*",
28 27
     "jquery-ui": "1.10.5",
29 28
     "jssha": "1.5.0",
29
+    "jws": "*",
30
+    "lib-jitsi-meet": "git+https://github.com/jitsi/lib-jitsi-meet.git",
31
+    "postis": "^2.2.0",
30 32
     "retry": "0.6.1",
31 33
     "strophe": "^1.2.2",
32 34
     "strophejs-plugins": "^0.0.6",
33
-    "toastr": "^2.0.3",
34
-    "postis": "^2.2.0",
35
-    "jws": "*"
35
+    "toastr": "^2.0.3"
36 36
   },
37 37
   "devDependencies": {
38 38
     "babel-polyfill": "*",

Loading…
Cancelar
Guardar