Ongoing work on video thumbnail layout

This commit is contained in:
yanas 2016-10-25 22:05:32 -05:00 committed by damencho
parent 3fe43abdea
commit a17a98991c
10 changed files with 171 additions and 193 deletions

View File

@ -1279,10 +1279,6 @@ export default {
APP.UI.updateRecordingState(status);
});
room.on(ConferenceEvents.USER_STATUS_CHANGED, function (id, status) {
APP.UI.updateUserStatus(id, status);
});
room.on(ConferenceEvents.KICKED, () => {
APP.UI.hideStats();
APP.UI.notifyKicked();

View File

@ -11,10 +11,10 @@ $hangupFontSize: 2em;
$defaultToolbarSize: 50px;
// Video layout.
$thumbnailIndicatorSize: 23px;
$thumbnailToolbarHeight: 22px;
$thumbnailIndicatorBorder: 0px;
$thumbnailIndicatorSize: $thumbnailToolbarHeight;
$thumbnailVideoMargin: 2px;
$thumbnailToolbarHeight: 25px;
/**
* Color variables.
@ -46,6 +46,7 @@ $thumbnailPictogramColor: #fff;
$dominantSpeakerBg: #165ecc;
$raiseHandBg: #D6D61E;
$audioLevelBg: #44A5FF;
$connectionIndicatorBg: #48CC8C;
$audioLevelShadow: rgba(9, 36, 77, 0.9);
$videoStateIndicatorColor: $defaultColor;
$videoStateIndicatorBackground: $toolbarBackground;

View File

@ -58,18 +58,25 @@
/**
* The toolbar of the video thumbnail.
*/
.videocontainer__toolbar {
.videocontainer__toolbar,
.videocontainer__toptoolbar {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
box-sizing: border-box; // Includes the padding in the 100% width.
height: $thumbnailToolbarHeight;
max-height: 100%;
padding: 0 5px 0 5px;
}
.videocontainer__toolbar {
bottom: 0;
}
.videocontainer__toptoolbar {
top: 0;
}
#remoteVideos .videocontainer.videoContainerFocused,
#remoteVideos .videocontainer:hover {
cursor: hand;
@ -201,72 +208,10 @@
padding: 0;
}
.videocontainer>span.status {
display: inline-block;
position: absolute;
color: #FFFFFF;
background: rgba(0,0,0,.7);
text-align: center;
text-overflow: ellipsis;
width: 70%;
height: 15%;
left: 15%;
bottom: 2%;
padding: 5px;
font-size: 10pt;
overflow: hidden;
white-space: nowrap;
z-index: 2;
border-radius:3px;
}
.connectionindicator
{
display: inline-block;
position: absolute;
top: 7px;
right: 0;
padding: 0px 5px;
z-index: 3;
width: 18px;
height: 13px;
}
.connection.connection_empty
{
color: #8B8B8B;/*#FFFFFF*/
overflow: hidden;
}
.connection.connection_lost
{
color: #8B8B8B;
overflow: visible;
}
.connection.connection_full
{
color: #FFFFFF;/*#15A1ED*/
overflow: hidden;
}
.connection
{
position: absolute;
left: 0px;
top: 0px;
font-size: 8pt;
border: 0px;
width: 18px;
height: 13px;
}
#localVideoContainer>span.status:hover,
#localVideoContainer .displayname:hover {
cursor: text;
}
.videocontainer>span.status,
.videocontainer .displayname {
pointer-events: none;
}
@ -279,7 +224,6 @@
pointer-events: auto !important;
}
.videocontainer>a.status,
.videocontainer>a.displayname {
display: inline-block;
position: absolute;
@ -324,25 +268,81 @@
margin: 0px 0px 0px 5px;
}
.videocontainer>span.indicator {
position: absolute;
top: 0px;
left: 0px;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
z-index: 3;
text-align: center;
background: $dominantSpeakerBg;
margin: 7px;
display: inline-block;
color: $thumbnailPictogramColor;
font-size: 8pt;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
#raisehandindicator {
background: $raiseHandBg;
}
.videocontainer>#raisehandindicator {
background: $raiseHandBg;
#connectionindicator {
background: $connectionIndicatorBg;
}
.videocontainer__toptoolbar span.indicator {
font-size: 8pt;
text-align: center;
line-height: $thumbnailToolbarHeight;
padding: 0;
margin-right: 5px;
float: left;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
z-index: 3;
background: $dominantSpeakerBg;
color: $thumbnailPictogramColor;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
.indicatoricon {
width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
margin-left: 5px; // TOP toolbar padding;
}
.connection.connection_empty
{
color: #8B8B8B;/*#FFFFFF*/
overflow: hidden;
}
.connection.connection_lost
{
color: #8B8B8B;
overflow: visible;
}
.connection.connection_full
{
color: #FFFFFF;/*#15A1ED*/
overflow: hidden;
}
.connection,
.icon-connection,
.icon-connection-lost {
font-size: 6pt;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
}
.connection
{
position: absolute;
left: 0px;
top: 0px;
border: 0px;
}
}
.remotevideomenu
{
display: inline-block;
position: absolute;
top: 0px;
right: 0;
margin: 7px;
z-index: 3;
width: 18px;
height: 13px;
color: #FFF;
font-size: 8pt;
}
/**
@ -385,12 +385,6 @@
}
}
#indicatoricon {
width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
}
#reloadPresentation {
display: none;
position: absolute;

View File

@ -254,6 +254,7 @@
</span>
<audio id="localAudio" autoplay muted></audio>
<div class="videocontainer__toolbar"></div>
<div class="videocontainer__toptoolbar"></div>
</span>
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>

View File

@ -609,10 +609,6 @@ UI.removeUser = function (id, displayName) {
VideoLayout.removeParticipantContainer(id);
};
UI.updateUserStatus = function (id, status) {
VideoLayout.setPresenceStatus(id, status);
};
/**
* Update videotype for specified user.
* @param {string} id user id

View File

@ -136,7 +136,7 @@ const TOOLTIP_POSITIONS = {
element.setAttribute('data-i18n', '[content]' + key);
APP.translation.translateElement($(element));
}
}
},
/**
@ -388,6 +388,45 @@ const TOOLTIP_POSITIONS = {
"cursor": "default"
});
}
},
/**
* Gets an "indicator" span for a video thumbnail.
* If element doesn't exist then creates it and appends
* video span container.
*
* @param {object} opts
* @param opts.indicatorId {String} - identificator of indicator
* @param opts.videoSpanId {String} - identificator of video span
* @param opts.content {String} HTML content of indicator
* @param opts.tooltip {String} - tooltip key for translation
*
* @returns {HTMLSpanElement} indicatorSpan
*/
getVideoThumbnailIndicatorSpan(opts = {}) {
let indicatorId = opts.indicatorId;
let videoSpanId = opts.videoSpanId;
let indicators = $(`#${videoSpanId} #${indicatorId}]`);
let indicatorSpan;
if (indicators.length <= 0) {
indicatorSpan = document.createElement('span');
indicatorSpan.className = 'indicator';
indicatorSpan.id = indicatorId;
indicatorSpan.innerHTML = opts.content;
this.setTooltip(indicatorSpan, opts.tooltip, "top");
APP.translation.translateElement($(indicatorSpan));
document.getElementById(videoSpanId)
.querySelector('.videocontainer__toptoolbar')
.appendChild(indicatorSpan);
} else {
indicatorSpan = indicators[0];
}
return indicatorSpan;
}
};

View File

@ -2,13 +2,15 @@
/* jshint -W101 */
import JitsiPopover from "../util/JitsiPopover";
import VideoLayout from "./VideoLayout";
import UIUtil from "../util/UIUtil";
/**
* Constructs new connection indicator.
* @param videoContainer the video container associated with the indicator.
* @param videoId the identifier of the video
* @constructor
*/
function ConnectionIndicator(videoContainer, id) {
function ConnectionIndicator(videoContainer, videoId) {
this.videoContainer = videoContainer;
this.bandwidth = null;
this.packetLoss = null;
@ -18,7 +20,7 @@ function ConnectionIndicator(videoContainer, id) {
this.isResolutionHD = null;
this.transport = [];
this.popover = null;
this.id = id;
this.id = videoId;
this.create();
}
@ -247,6 +249,7 @@ ConnectionIndicator.prototype.showMore = function () {
function createIcon(classes, iconClass) {
var icon = document.createElement("span");
icon.classList.add("indicatoricon");
for(var i in classes) {
icon.classList.add(classes[i]);
}
@ -259,18 +262,22 @@ function createIcon(classes, iconClass) {
* Creates the indicator
*/
ConnectionIndicator.prototype.create = function () {
this.connectionIndicatorContainer = document.createElement("div");
this.connectionIndicatorContainer.className = "connectionindicator";
this.connectionIndicatorContainer.style.display = "none";
this.videoContainer.container.appendChild(
this.connectionIndicatorContainer);
this.popover = new JitsiPopover(
$("#" + this.videoContainer.videoSpanId + " > .connectionindicator"), {
content: "<div class=\"connection-info\" " +
"data-i18n='connectionindicator.na'></div>",
skin: "black",
onBeforePosition: el => APP.translation.translateElement(el)
});
let indicatorId = 'connectionindicator';
let element = UIUtil.getVideoThumbnailIndicatorSpan({
videoSpanId: this.videoContainer.videoSpanId,
indicatorId
});
element.classList.add('hide');
this.connectionIndicatorContainer = element;
let popoverContent = (
`<div class="connection-info" data-i18n="${indicatorId}.na"></div>`
);
this.popover = new JitsiPopover(element, {
content: popoverContent,
skin: "black",
onBeforePosition: el => APP.translation.translateElement(el)
});
// override popover show method to make sure we will update the content
// before showing the popover

View File

@ -233,11 +233,9 @@ if (!interfaceConfig.filmStripOnly) {
RemoteVideo.prototype.addRemoteVideoMenu = function () {
var spanElement = document.createElement('span');
spanElement.className = 'remotevideomenu toolbar-icon right';
spanElement.className = 'remotevideomenu';
this.container
.querySelector('.videocontainer__toolbar')
.appendChild(spanElement);
this.container.appendChild(spanElement);
var menuElement = document.createElement('i');
menuElement.className = 'icon-menu-up';
@ -569,6 +567,10 @@ RemoteVideo.createContainer = function (spanId) {
container.id = spanId;
container.className = 'videocontainer';
let indicatorBar = document.createElement('div');
indicatorBar.className = "videocontainer__toptoolbar";
container.appendChild(indicatorBar);
let toolbar = document.createElement('div');
toolbar.className = "videocontainer__toolbar";
container.appendChild(toolbar);

View File

@ -126,37 +126,6 @@ SmallVideo.prototype.getVideoType = function () {
return this.videoType;
};
/**
* Shows the presence status message for the given video.
*/
SmallVideo.prototype.setPresenceStatus = function (statusMsg) {
if (!this.container) {
// No container
return;
}
var statusSpan = $('#' + this.videoSpanId + '>span.status');
if (!statusSpan.length) {
//Add status span
statusSpan = document.createElement('span');
statusSpan.className = 'status';
statusSpan.id = this.videoSpanId + '_status';
$('#' + this.videoSpanId)[0].appendChild(statusSpan);
statusSpan = $('#' + this.videoSpanId + '>span.status');
}
// Display status
if (statusMsg && statusMsg.length) {
$('#' + this.videoSpanId + '_status').text(statusMsg);
statusSpan.get(0).setAttribute("style", "display:inline-block;");
}
else {
// Hide
statusSpan.get(0).setAttribute("style", "display:none;");
}
};
/**
* Creates an audio or video element for a particular MediaStream.
*/
@ -528,13 +497,19 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
return;
}
var indicatorSpan = this.getIndicatorSpan({
id: 'dominantspeakerindicator',
let indicatorSpanId = "dominantspeakerindicator";
let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({
videoSpanId: this.videoSpanId,
indicatorId: indicatorSpanId,
content: '<i id="indicatoricon" class="fa fa-bullhorn"></i>',
tooltip: 'speaker'
});
indicatorSpan.style.display = show ? "" : "none";
if (show) {
indicatorSpan.classList.add('hide');
} else {
indicatorSpan.classList.remove('hide')
}
};
/**
@ -548,43 +523,19 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
return;
}
var indicatorSpan = this.getIndicatorSpan({
id: 'raisehandindicator',
let indicatorSpanId = "raisehandindicator";
let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({
indicatorId: indicatorSpanId,
videoSpanId: this.videoSpanId,
content: '<i id="indicatoricon" class="icon-raised-hand"></i>',
tooltip: 'raisedHand'
});
indicatorSpan.style.display = show ? "" : "none";
};
/**
* Gets (creating if necessary) the "indicator" span for this SmallVideo.
*
* @param options.id {String} element ID
* @param options.content {String} HTML content of the indicator
* @param options.tooltip {String} The key that should be passed to tooltip
*
* @returns {HTMLElement} DOM represention of the indicator
*/
SmallVideo.prototype.getIndicatorSpan = function(options) {
var indicator = this.container.querySelector('#' + options.id);
if (indicator) {
return indicator;
if (show) {
indicatorSpan.classList.add('hide');
} else {
indicatorSpan.classList.remove('hide')
}
indicator = document.createElement('span');
indicator.className = 'indicator';
indicator.id = options.id;
indicator.innerHTML = options.content;
UIUtil.setTooltip(indicator, options.tooltip, "top");
APP.translation.translateElement($(indicator));
this.container.appendChild(indicator);
return indicator;
};
/**

View File

@ -449,15 +449,6 @@ var VideoLayout = {
}
},
/**
* Shows the presence status message for the given video.
*/
setPresenceStatus (id, statusMsg) {
let remoteVideo = remoteVideos[id];
if (remoteVideo)
remoteVideo.setPresenceStatus(statusMsg);
},
/**
* Shows a visual indicator for the moderator of the conference.
* On local or remote participants.