Merge pull request #517 from jitsi/fix-resizing

An additional fix should be added, which allow for more smooth resizing (we still see thumbnails going on a second row and then coming back up again), but this will be added in a separate commit.
This commit is contained in:
yanas 2016-02-29 13:20:19 -06:00
commit 1339b306e6
14 changed files with 241 additions and 184 deletions

View File

@ -29,5 +29,6 @@ var interfaceConfig = {
*/
filmStripOnly: false,
RANDOM_AVATAR_URL_PREFIX: false,
RANDOM_AVATAR_URL_SUFFIX: false
RANDOM_AVATAR_URL_SUFFIX: false,
FILM_STRIP_MAX_HEIGHT: 160
};

View File

@ -16,6 +16,7 @@ import PreziManager from './prezi/Prezi';
import EtherpadManager from './etherpad/Etherpad';
import VideoLayout from "./videolayout/VideoLayout";
import FilmStrip from "./videolayout/FilmStrip";
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
import Settings from "./../settings/Settings";
import { reload } from '../util/helpers';
@ -293,7 +294,7 @@ function registerListeners() {
function bindEvents() {
function onResize() {
PanelToggler.resizeChat();
VideoLayout.resizeLargeVideoContainer(PanelToggler.isVisible());
VideoLayout.resizeVideoArea(PanelToggler.isVisible());
}
// Resize and reposition videos in full screen mode.
@ -334,12 +335,13 @@ UI.start = function () {
registerListeners();
BottomToolbar.init();
FilmStrip.init();
VideoLayout.init(eventEmitter);
if (!interfaceConfig.filmStripOnly) {
VideoLayout.initLargeVideo(PanelToggler.isVisible());
}
VideoLayout.resizeLargeVideoContainer(PanelToggler.isVisible(), true);
VideoLayout.resizeVideoArea(PanelToggler.isVisible(), true, true);
ContactList.init(eventEmitter);
@ -367,9 +369,9 @@ UI.start = function () {
});
} else {
$("#header").css("display", "none");
$("#bottomToolbar").css("display", "none");
$("#downloadlog").css("display", "none");
BottomToolbar.setupFilmStripOnly();
BottomToolbar.hide();
FilmStrip.setupFilmStripOnly();
messageHandler.disableNotifications();
$('body').popover("disable");
JitsiPopover.enabled = false;
@ -598,7 +600,7 @@ UI.getSettings = function () {
* Toggles film strip.
*/
UI.toggleFilmStrip = function () {
BottomToolbar.toggleFilmStrip();
FilmStrip.toggleFilmStrip();
};
/**

View File

@ -2,7 +2,7 @@
/* jshint -W101 */
import CanvasUtil from './CanvasUtils';
import BottomToolbar from '../toolbars/BottomToolbar';
import FilmStrip from '../videolayout/FilmStrip';
const LOCAL_LEVEL = 'local';
@ -228,7 +228,7 @@ const AudioLevels = {
let canvasWidth = thumbWidth + interfaceConfig.CANVAS_EXTRA;
let canvasHeight = thumbHeight + interfaceConfig.CANVAS_EXTRA;
BottomToolbar.getThumbs().children('canvas').each(function () {
FilmStrip.getThumbs().children('canvas').each(function () {
$(this).attr('width', canvasWidth);
$(this).attr('height', canvasHeight);
});

View File

@ -4,7 +4,7 @@ import VideoLayout from "../videolayout/VideoLayout";
import LargeContainer from '../videolayout/LargeContainer';
import UIUtil from "../util/UIUtil";
import SidePanelToggler from "../side_pannels/SidePanelToggler";
import BottomToolbar from '../toolbars/BottomToolbar';
import FilmStrip from '../videolayout/FilmStrip';
/**
* Etherpad options.
@ -101,7 +101,7 @@ class Etherpad extends LargeContainer {
}
resize (containerWidth, containerHeight, animate) {
let height = containerHeight - BottomToolbar.getFilmStripHeight();
let height = containerHeight - FilmStrip.getFilmStripHeight();
let width = containerWidth;
$(this.iframe).width(width).height(height);

View File

@ -9,7 +9,7 @@ import UIEvents from '../../../service/UI/UIEvents';
import messageHandler from '../util/MessageHandler';
import ToolbarToggler from "../toolbars/ToolbarToggler";
import SidePanelToggler from "../side_pannels/SidePanelToggler";
import BottomToolbar from '../toolbars/BottomToolbar';
import FilmStrip from '../videolayout/FilmStrip';
/**
* Example of Prezi link.
@ -287,7 +287,7 @@ class PreziContainer extends LargeContainer {
}
resize (containerWidth, containerHeight) {
let height = containerHeight - BottomToolbar.getFilmStripHeight();
let height = containerHeight - FilmStrip.getFilmStripHeight();
let width = containerWidth;

View File

@ -96,11 +96,14 @@ var PanelToggler = {
$('#chatspace').trigger('shown');
};
VideoLayout.resizeVideoArea(!Chat.isVisible(), chatCompleteFunction);
VideoLayout.resizeVideoArea(!Chat.isVisible(),
false,
true,
chatCompleteFunction);
toggle(Chat,
'#chatspace',
function () {
toggle(Chat, //Object
'#chatspace', // Selector
function () { //onOpenComplete
// Request the focus in the nickname field or the chat input
// field.
if ($('#nickname').css('visibility') === 'visible') {
@ -109,9 +112,8 @@ var PanelToggler = {
$('#usermsg').focus();
}
},
null,
() => this.resizeChat(),
null);
() => this.resizeChat(), //OnOpen
null); //OnClose
},
resizeChat () {
@ -128,7 +130,11 @@ var PanelToggler = {
: function () {
$('#contactlist').trigger('shown');
};
VideoLayout.resizeVideoArea(!ContactList.isVisible(), completeFunction);
VideoLayout.resizeVideoArea(
!ContactList.isVisible(),
false,
true,
completeFunction);
toggle(ContactList,
'#contactlist',
@ -143,7 +149,8 @@ var PanelToggler = {
* Opens / closes the settings menu
*/
toggleSettingsMenu () {
VideoLayout.resizeVideoArea(!SettingsMenu.isVisible(), function (){});
VideoLayout.resizeVideoArea(
!SettingsMenu.isVisible(), false, true, function (){});
toggle(SettingsMenu,
'#settingsmenu',
null,

View File

@ -1,4 +1,4 @@
/* global $ */
/* global $, APP, interfaceConfig*/
import UIUtil from '../util/UIUtil';
import UIEvents from '../../../service/UI/UIEvents';
import AnalyticsAdapter from '../../statistics/AnalyticsAdapter';
@ -11,7 +11,6 @@ const defaultBottomToolbarButtons = {
const BottomToolbar = {
init () {
this.filmStrip = $('#remoteVideos');
this.toolbar = $('#bottomToolbar');
},
@ -38,71 +37,43 @@ const BottomToolbar = {
);
},
toggleFilmStrip () {
this.filmStrip.toggleClass("hidden");
},
isFilmStripVisible () {
return !this.filmStrip.hasClass('hidden');
},
setupFilmStripOnly () {
this.filmStrip.css({
padding: "0px 0px 18px 0px",
right: 0
});
},
getFilmStripHeight () {
if (this.isFilmStripVisible()) {
return this.filmStrip.outerHeight();
} else {
return 0;
}
},
getFilmStripWidth () {
return this.filmStrip.width();
},
resizeThumbnails (thumbWidth, thumbHeight,
animate = false, forceUpdate = false) {
return new Promise(resolve => {
this.filmStrip.animate({
// adds 2 px because of small video 1px border
height: thumbHeight + 2
}, {
queue: false,
duration: animate ? 500 : 0
});
this.getThumbs(!forceUpdate).animate({
height: thumbHeight,
width: thumbWidth
}, {
queue: false,
duration: animate ? 500 : 0,
complete: resolve
});
if (!animate) {
resolve();
}
});
},
resizeToolbar (thumbWidth, thumbHeight) {
let bottom = (thumbHeight - this.toolbar.outerHeight())/2 + 18;
this.toolbar.css({bottom});
},
getThumbs (only_visible = false) {
let selector = 'span';
if (only_visible) {
selector += ':visible';
}
/**
* Returns true if this toolbar is currently visible, or false otherwise.
* @return <tt>true</tt> if currently visible, <tt>false</tt> - otherwise
*/
isVisible() {
return this.toolbar.is(":visible");
},
return this.filmStrip.children(selector);
/**
* Hides the bottom toolbar with animation or not depending on the animate
* parameter.
* @param animate <tt>true</tt> to hide the bottom toolbar with animation,
* <tt>false</tt> or nothing to hide it without animation.
*/
hide(animate) {
if (animate)
this.toolbar.hide("slide", {direction: "right", duration: 300});
else
this.toolbar.css("display", "none");
},
/**
* Shows the bottom toolbar with animation or not depending on the animate
* parameter.
* @param animate <tt>true</tt> to show the bottom toolbar with animation,
* <tt>false</tt> or nothing to show it without animation.
*/
show(animate) {
if (animate)
this.toolbar.show("slide", {direction: "right", duration: 300});
else
this.toolbar.css("display", "block");
}
};

View File

@ -2,6 +2,7 @@
import UIUtil from '../util/UIUtil';
import BottomToolbar from './BottomToolbar';
import FilmStrip from '../videolayout/FilmStrip.js';
let toolbarTimeoutObject;
let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
@ -28,7 +29,6 @@ function hideToolbar() {
}
let header = $("#header");
let bottomToolbar = $("#bottomToolbar");
let isToolbarHover = false;
header.find('*').each(function () {
let id = $(this).attr('id');
@ -48,10 +48,8 @@ function hideToolbar() {
} else {
header.hide("slide", { direction: "up", duration: 300});
$('#subject').animate({top: "-=40"}, 300);
if (!BottomToolbar.isFilmStripVisible()) {
bottomToolbar.hide(
"slide", {direction: "right", duration: 300}
);
if (!FilmStrip.isFilmStripVisible()) {
BottomToolbar.hide(true);
}
}
}
@ -65,14 +63,11 @@ const ToolbarToggler = {
return;
}
let header = $("#header");
let bottomToolbar = $("#bottomToolbar");
if (!header.is(':visible') || !bottomToolbar.is(":visible")) {
if (!header.is(':visible') || !BottomToolbar.isVisible()) {
header.show("slide", { direction: "up", duration: 300});
$('#subject').animate({top: "+=40"}, 300);
if (!bottomToolbar.is(":visible")) {
bottomToolbar.show(
"slide", {direction: "right", duration: 300}
);
if (!BottomToolbar.isVisible()) {
BottomToolbar.show(true);
}
if (toolbarTimeoutObject) {

View File

@ -32,6 +32,7 @@
return window.innerWidth - rightPanelWidth;
},
/**
* Changes the style class of the element given by id.
*/

View File

@ -0,0 +1,140 @@
/* global $, APP, interfaceConfig, config*/
import UIUtil from "../util/UIUtil";
const thumbAspectRatio = 16.0 / 9.0;
const FilmStrip = {
init () {
this.filmStrip = $('#remoteVideos');
},
toggleFilmStrip () {
this.filmStrip.toggleClass("hidden");
},
isFilmStripVisible () {
return !this.filmStrip.hasClass('hidden');
},
setupFilmStripOnly () {
this.filmStrip.css({
padding: "0px 0px 18px 0px",
right: 0
});
},
getFilmStripHeight () {
if (this.isFilmStripVisible()) {
return this.filmStrip.outerHeight();
} else {
return 0;
}
},
getFilmStripWidth () {
return this.filmStrip.innerWidth()
- parseInt(this.filmStrip.css('paddingLeft'), 10)
- parseInt(this.filmStrip.css('paddingRight'), 10);
},
/**
* Calculates the thumbnail size.
* @param videoAreaAvailableWidth the currently available video area width
* that we want to take into account when calculating the film strip width.
*/
calculateThumbnailSize (videoAreaAvailableWidth) {
// Calculate the available height, which is the inner window height
// minus 39px for the header minus 2px for the delimiter lines on the
// top and bottom of the large video, minus the 36px space inside the
// remoteVideos container used for highlighting shadow.
let availableHeight = 100;
let numvids = this.getThumbs(true).length;
let localVideoContainer = $("#localVideoContainer");
/**
* If the videoAreaAvailableWidth is set we use this one to calculate
* the filmStrip width, because we're probably in a state where the
* film strip size hasn't been updated yet, but it will be.
*/
let filmStripWidth = videoAreaAvailableWidth
? videoAreaAvailableWidth
- parseInt(this.filmStrip.css('right'), 10)
- parseInt(this.filmStrip.css('paddingLeft'), 10)
- parseInt(this.filmStrip.css('paddingRight'), 10)
- parseInt(this.filmStrip.css('borderLeftWidth'), 10)
- parseInt(this.filmStrip.css('borderRightWidth'), 10)
: this.getFilmStripWidth();
let availableWidth = Math.floor(
(filmStripWidth - numvids * (
parseInt(localVideoContainer.css('borderLeftWidth'), 10)
+ parseInt(localVideoContainer.css('borderRightWidth'), 10)
+ parseInt(localVideoContainer.css('paddingLeft'), 10)
+ parseInt(localVideoContainer.css('paddingRight'), 10)
+ parseInt(localVideoContainer.css('marginLeft'), 10)
+ parseInt(localVideoContainer.css('marginRight'), 10)))
/ numvids) - numvids*10;
let maxHeight
// If the MAX_HEIGHT property hasn't been specified
// we have the static value.
= Math.min( interfaceConfig.FILM_STRIP_MAX_HEIGHT || 160,
availableHeight);
availableHeight
= Math.min( maxHeight,
availableWidth / thumbAspectRatio,
window.innerHeight - 18);
if (availableHeight < availableWidth / thumbAspectRatio) {
availableWidth = Math.floor(availableHeight * thumbAspectRatio);
}
return {
thumbWidth: availableWidth,
thumbHeight: availableHeight
};
},
resizeThumbnails (thumbWidth, thumbHeight,
animate = false, forceUpdate = false) {
return new Promise(resolve => {
this.getThumbs(!forceUpdate).animate({
height: thumbHeight,
width: thumbWidth
}, {
queue: false,
duration: animate ? 500 : 0,
complete: resolve
});
this.filmStrip.animate({
// adds 2 px because of small video 1px border
height: thumbHeight + 2
}, {
queue: false,
duration: animate ? 500 : 0
});
if (!animate) {
resolve();
}
});
},
getThumbs (only_visible = false) {
let selector = 'span';
if (only_visible) {
selector += ':visible';
}
return this.filmStrip.children(selector);
}
};
export default FilmStrip;

View File

@ -4,7 +4,7 @@
import UIUtil from "../util/UIUtil";
import UIEvents from "../../../service/UI/UIEvents";
import LargeContainer from './LargeContainer';
import BottomToolbar from '../toolbars/BottomToolbar';
import FilmStrip from './FilmStrip';
import Avatar from "../avatar/Avatar";
import {createDeferred} from '../../util/helpers';
@ -43,7 +43,7 @@ function getDesktopVideoSize(videoWidth,
let availableWidth = Math.max(videoWidth, videoSpaceWidth);
let availableHeight = Math.max(videoHeight, videoSpaceHeight);
videoSpaceHeight -= BottomToolbar.getFilmStripHeight();
videoSpaceHeight -= FilmStrip.getFilmStripHeight();
if (availableWidth / aspectRatio >= videoSpaceHeight) {
availableHeight = videoSpaceHeight;

View File

@ -33,7 +33,7 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
if (APP.conference.isModerator) {
this.addRemoteVideoMenu();
}
let {thumbWidth, thumbHeight} = this.VideoLayout.calculateThumbnailSize();
let {thumbWidth, thumbHeight} = this.VideoLayout.resizeThumbnails();
AudioLevels.updateAudioLevelCanvas(this.id, thumbWidth, thumbHeight);
return this.container;

View File

@ -4,7 +4,7 @@
import AudioLevels from "../audio_levels/AudioLevels";
import Avatar from "../avatar/Avatar";
import BottomToolbar from "../toolbars/BottomToolbar";
import FilmStrip from "./FilmStrip";
import UIEvents from "../../../service/UI/UIEvents";
import UIUtil from "../util/UIUtil";
@ -34,8 +34,6 @@ var eventEmitter = null;
*/
var focusedVideoResourceJid = null;
const thumbAspectRatio = 16.0 / 9.0;
/**
* On contact list item clicked.
*/
@ -149,9 +147,8 @@ var VideoLayout = {
let localId = APP.conference.localId;
this.onVideoTypeChanged(localId, stream.videoType);
let {thumbWidth, thumbHeight} = this.calculateThumbnailSize();
AudioLevels.updateAudioLevelCanvas(
null, thumbWidth, thumbHeight);
let {thumbWidth, thumbHeight} = this.resizeThumbnails(false, true);
AudioLevels.updateAudioLevelCanvas(null, thumbWidth, thumbHeight);
if (!stream.isMuted()) {
localVideoThumbnail.changeVideo(stream);
@ -221,7 +218,7 @@ var VideoLayout = {
electLastVisibleVideo () {
// pick the last visible video in the row
// if nobody else is left, this picks the local video
let thumbs = BottomToolbar.getThumbs(true).filter('[id!="mixedstream"]');
let thumbs = FilmStrip.getThumbs(true).filter('[id!="mixedstream"]');
let lastVisible = thumbs.filter(':visible:last');
if (lastVisible.length) {
@ -235,7 +232,7 @@ var VideoLayout = {
}
console.info("Last visible video no longer exists");
thumbs = BottomToolbar.getThumbs();
thumbs = FilmStrip.getThumbs();
if (thumbs.length) {
let id = getPeerContainerResourceId(thumbs[0]);
if (remoteVideos[id]) {
@ -345,7 +342,7 @@ var VideoLayout = {
// In case this is not currently in the last n we don't show it.
if (localLastNCount && localLastNCount > 0 &&
BottomToolbar.getThumbs().length >= localLastNCount + 2) {
FilmStrip.getThumbs().length >= localLastNCount + 2) {
remoteVideo.showPeerContainer('hide');
} else {
VideoLayout.resizeThumbnails(false, true);
@ -411,74 +408,26 @@ var VideoLayout = {
localVideoThumbnail.showAudioIndicator(isMuted);
},
/**
* Resizes the large video container.
*/
resizeLargeVideoContainer (isSideBarVisible, forceUpdate) {
let animate = false;
if (largeVideo) {
largeVideo.updateContainerSize(isSideBarVisible);
largeVideo.resize(animate);
}
this.resizeVideoSpace(animate, isSideBarVisible);
this.resizeThumbnails(false, forceUpdate);
},
/**
* Resizes thumbnails.
*/
resizeThumbnails (animate = false, forceUpdate = false) {
let {thumbWidth, thumbHeight} = this.calculateThumbnailSize();
resizeThumbnails ( animate = false,
forceUpdate = false,
videoAreaAvailableWidth = null) {
let {thumbWidth, thumbHeight}
= FilmStrip.calculateThumbnailSize(videoAreaAvailableWidth);
$('.userAvatar').css('left', (thumbWidth - thumbHeight) / 2);
BottomToolbar.resizeThumbnails(thumbWidth, thumbHeight,
FilmStrip.resizeThumbnails(thumbWidth, thumbHeight,
animate, forceUpdate)
.then(function () {
BottomToolbar.resizeToolbar(thumbWidth, thumbHeight);
AudioLevels.updateCanvasSize(thumbWidth, thumbHeight);
});
return {thumbWidth, thumbHeight};
},
/**
* Calculates the thumbnail size.
*
*/
calculateThumbnailSize () {
let videoSpaceWidth = BottomToolbar.getFilmStripWidth();
// Calculate the available height, which is the inner window height
// minus 39px for the header minus 2px for the delimiter lines on the
// top and bottom of the large video, minus the 36px space inside the
// remoteVideos container used for highlighting shadow.
let availableHeight = 100;
let numvids = BottomToolbar.getThumbs().length;
if (localLastNCount && localLastNCount > 0) {
numvids = Math.min(localLastNCount + 1, numvids);
}
// Remove the 3px borders arround videos and border around the remote
// videos area and the 4 pixels between the local video and the others
//TODO: Find out where the 4 pixels come from and remove them
let availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 70 - 4;
let availableWidth = availableWinWidth / numvids;
let maxHeight = Math.min(160, availableHeight);
availableHeight
= Math.min( maxHeight,
availableWidth / thumbAspectRatio,
window.innerHeight - 18);
if (availableHeight < availableWidth / thumbAspectRatio) {
availableWidth = Math.floor(availableHeight * thumbAspectRatio);
}
return {
thumbWidth: availableWidth,
thumbHeight: availableHeight
};
},
/**
* On audio muted event.
*/
@ -613,7 +562,7 @@ var VideoLayout = {
var updateLargeVideo = false;
// Handle LastN/local LastN changes.
BottomToolbar.getThumbs().each(( index, element ) => {
FilmStrip.getThumbs().each(( index, element ) => {
var resourceJid = getPeerContainerResourceId(element);
var smallVideo = remoteVideos[resourceJid];
@ -667,7 +616,8 @@ var VideoLayout = {
endpointsEnteringLastN.forEach(function (resourceJid) {
var remoteVideo = remoteVideos[resourceJid];
remoteVideo.showPeerContainer('show');
if (remoteVideo)
remoteVideo.showPeerContainer('show');
if (!remoteVideo.isVisible()) {
console.log("Add to last N", resourceJid);
@ -840,40 +790,31 @@ var VideoLayout = {
* Resizes the video area.
*
* @param isSideBarVisible indicates if the side bar is currently visible
* @param callback a function to be called when the video space is
* @param forceUpdate indicates that hidden thumbnails will be shown
* @param completeFunction a function to be called when the video area is
* resized.
*/
resizeVideoArea (isSideBarVisible, callback) {
let animate = true;
*/resizeVideoArea (isSideBarVisible,
forceUpdate = false,
animate = false,
completeFunction = null) {
if (largeVideo) {
largeVideo.updateContainerSize(isSideBarVisible);
largeVideo.resize(animate);
this.resizeVideoSpace(animate, isSideBarVisible, callback);
}
VideoLayout.resizeThumbnails(animate);
},
/**
* Resizes the #videospace html element
* @param animate boolean property that indicates whether the resize should
* be animated or not.
* @param isChatVisible boolean property that indicates whether the chat
* area is displayed or not.
* If that parameter is null the method will check the chat panel
* visibility.
* @param completeFunction a function to be called when the video space
* is resized.
*/
resizeVideoSpace (animate, isChatVisible, completeFunction) {
// Calculate available width and height.
let availableHeight = window.innerHeight;
let availableWidth = UIUtil.getAvailableVideoWidth(isChatVisible);
let availableWidth = UIUtil.getAvailableVideoWidth(isSideBarVisible);
if (availableWidth < 0 || availableHeight < 0) {
return;
}
// Resize the thumbnails first.
this.resizeThumbnails(false, forceUpdate, availableWidth);
// Resize the video area element.
$('#videospace').animate({
right: window.innerWidth - availableWidth,
width: availableWidth,

View File

@ -47,7 +47,6 @@ function initShortcutHandlers() {
};
}
var KeyboardShortcut = {
init: function () {
initShortcutHandlers();