Ongoing work on video thumbnail layout
This commit is contained in:
parent
3fe43abdea
commit
a17a98991c
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue