feat(background alpha) Set background transparency

This commit is contained in:
hmuresan 2021-03-23 14:11:11 +02:00 committed by Horatiu Muresan
parent 8fccb05519
commit f7c0d4f1fe
6 changed files with 124 additions and 1 deletions

View File

@ -677,6 +677,9 @@ var config = {
*/ */
// dynamicBrandingUrl: '', // dynamicBrandingUrl: '',
// Sets the background transparency level. '0' is fully transparent, '1' is opaque.
// backgroundAlpha: 1,
// The URL of the moderated rooms microservice, if available. If it // The URL of the moderated rooms microservice, if available. If it
// is present, a link to the service will be rendered on the welcome page, // is present, a link to the service will be rendered on the welcome page,
// otherwise the app doesn't render it. // otherwise the app doesn't render it.

View File

@ -7,6 +7,7 @@ import EventEmitter from 'events';
import Logger from 'jitsi-meet-logger'; import Logger from 'jitsi-meet-logger';
import { isMobileBrowser } from '../../react/features/base/environment/utils'; import { isMobileBrowser } from '../../react/features/base/environment/utils';
import { setColorAlpha } from '../../react/features/base/util';
import { toggleChat } from '../../react/features/chat'; import { toggleChat } from '../../react/features/chat';
import { setDocumentUrl } from '../../react/features/etherpad'; import { setDocumentUrl } from '../../react/features/etherpad';
import { setFilmstripVisible } from '../../react/features/filmstrip'; import { setFilmstripVisible } from '../../react/features/filmstrip';
@ -129,6 +130,13 @@ UI.start = function() {
$('body').addClass('mobile-browser'); $('body').addClass('mobile-browser');
} else { } else {
$('body').addClass('desktop-browser'); $('body').addClass('desktop-browser');
if (config.backgroundAlpha !== undefined) {
const backgroundColor = $('body').css('background-color');
const alphaColor = setColorAlpha(backgroundColor, config.backgroundAlpha);
$('body').css('background-color', alphaColor);
}
} }
if (config.iAmRecorder) { if (config.iAmRecorder) {

View File

@ -17,6 +17,7 @@ export default [
'audioLevelsInterval', 'audioLevelsInterval',
'apiLogLevels', 'apiLogLevels',
'avgRtpStatsN', 'avgRtpStatsN',
'backgroundAlpha',
/** /**
* The display name of the CallKit call representing the conference/meeting * The display name of the CallKit call representing the conference/meeting

View File

@ -126,3 +126,62 @@ export function reportError(e: Object, msg: string = '') {
console.error(msg, e); console.error(msg, e);
window.onerror && window.onerror(msg, null, null, null, e); window.onerror && window.onerror(msg, null, null, null, e);
} }
/**
* Adds alpha to a color css string.
*
* @param {string} color - The color string either in rgb... Or #... Format.
* @param {number} opacity -The opacity(alpha) to apply to the color. Can take a value between 0 and 1, including.
* @returns {string} - The color with applied alpha.
*/
export function setColorAlpha(color: string, opacity: number) {
if (!color) {
return `rgba(0, 0, 0, ${opacity})`;
}
let b, g, r;
try {
if (color.startsWith('rgb')) {
[ r, g, b ] = color.split('(')[1].split(')')[0].split(',').map(c => c.trim());
} else if (color.startsWith('#')) {
if (color.length === 4) {
[ r, g, b ] = parseShorthandColor(color);
} else {
r = parseInt(color.substring(1, 3), 16);
g = parseInt(color.substring(3, 5), 16);
b = parseInt(color.substring(5, 7), 16);
}
} else {
return color;
}
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
} catch {
return color;
}
}
/**
* Gets the hexa rgb values for a shorthand css color.
*
* @param {string} color -
* @returns {Array<number>} - Array containing parsed r, g, b values of the color.
*/
function parseShorthandColor(color) {
let b, g, r;
r = color.substring(1, 2);
r += r;
r = parseInt(r, 16);
g = color.substring(2, 3);
g += g;
g = parseInt(g, 16);
b = color.substring(3, 4);
b += b;
b = parseInt(b, 16);
return [ r, g, b ];
}

View File

@ -8,6 +8,7 @@ import { getConferenceNameForTitle } from '../../../base/conference';
import { connect, disconnect } from '../../../base/connection'; import { connect, disconnect } from '../../../base/connection';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { connect as reactReduxConnect } from '../../../base/redux'; import { connect as reactReduxConnect } from '../../../base/redux';
import { setColorAlpha } from '../../../base/util';
import { Chat } from '../../../chat'; import { Chat } from '../../../chat';
import { Filmstrip } from '../../../filmstrip'; import { Filmstrip } from '../../../filmstrip';
import { CalleeInfoContainer } from '../../../invite'; import { CalleeInfoContainer } from '../../../invite';
@ -61,6 +62,11 @@ const LAYOUT_CLASSNAMES = {
*/ */
type Props = AbstractProps & { type Props = AbstractProps & {
/**
* The alpha(opacity) of the background
*/
_backgroundAlpha: number,
/** /**
* Whether the local participant is recording the conference. * Whether the local participant is recording the conference.
*/ */
@ -98,6 +104,7 @@ class Conference extends AbstractConference<Props, *> {
_onFullScreenChange: Function; _onFullScreenChange: Function;
_onShowToolbar: Function; _onShowToolbar: Function;
_originalOnShowToolbar: Function; _originalOnShowToolbar: Function;
_setBackground: Function;
/** /**
* Initializes a new Conference instance. * Initializes a new Conference instance.
@ -121,6 +128,7 @@ class Conference extends AbstractConference<Props, *> {
// Bind event handler so it is only bound once for every instance. // Bind event handler so it is only bound once for every instance.
this._onFullScreenChange = this._onFullScreenChange.bind(this); this._onFullScreenChange = this._onFullScreenChange.bind(this);
this._setBackground = this._setBackground.bind(this);
} }
/** /**
@ -186,7 +194,8 @@ class Conference extends AbstractConference<Props, *> {
<div <div
className = { _layoutClassName } className = { _layoutClassName }
id = 'videoconference_page' id = 'videoconference_page'
onMouseMove = { this._onShowToolbar }> onMouseMove = { this._onShowToolbar }
ref = { this._setBackground }>
<Notice /> <Notice />
<div id = 'videospace'> <div id = 'videospace'>
@ -208,6 +217,35 @@ class Conference extends AbstractConference<Props, *> {
); );
} }
/**
* Sets custom background opacity based on config. It also applies the
* opacity on parent element, as the parent element is not accessible directly,
* only though it's child.
*
* @param {Object} element - The DOM element for which to apply opacity.
*
* @private
* @returns {void}
*/
_setBackground(element) {
if (!element) {
return;
}
if (this.props._backgroundAlpha !== undefined) {
const elemColor = element.style.background;
const alphaElemColor = setColorAlpha(elemColor, this.props._backgroundAlpha);
element.style.background = alphaElemColor;
if (element.parentElement) {
const parentColor = element.parentElement.style.background;
const alphaParentColor = setColorAlpha(parentColor, this.props._backgroundAlpha);
element.parentElement.style.background = alphaParentColor;
}
}
}
/** /**
* Updates the Redux state when full screen mode has been enabled or * Updates the Redux state when full screen mode has been enabled or
* disabled. * disabled.
@ -265,6 +303,7 @@ function _mapStateToProps(state) {
return { return {
...abstractMapStateToProps(state), ...abstractMapStateToProps(state),
_iAmRecorder: state['features/base/config'].iAmRecorder, _iAmRecorder: state['features/base/config'].iAmRecorder,
_backgroundAlpha: state['features/base/config'].backgroundAlpha,
_isLobbyScreenVisible: state['features/base/dialog']?.component === LobbyScreen, _isLobbyScreenVisible: state['features/base/dialog']?.component === LobbyScreen,
_layoutClassName: LAYOUT_CLASSNAMES[getCurrentLayout(state)], _layoutClassName: LAYOUT_CLASSNAMES[getCurrentLayout(state)],
_roomName: getConferenceNameForTitle(state), _roomName: getConferenceNameForTitle(state),

View File

@ -4,6 +4,7 @@ import React, { Component } from 'react';
import { Watermarks } from '../../base/react'; import { Watermarks } from '../../base/react';
import { connect } from '../../base/redux'; import { connect } from '../../base/redux';
import { setColorAlpha } from '../../base/util';
import { Subject } from '../../conference'; import { Subject } from '../../conference';
import { fetchCustomBrandingData } from '../../dynamic-branding'; import { fetchCustomBrandingData } from '../../dynamic-branding';
import { Captions } from '../../subtitles/'; import { Captions } from '../../subtitles/';
@ -12,6 +13,11 @@ declare var interfaceConfig: Object;
type Props = { type Props = {
/**
* The alpha(opacity) of the background
*/
_backgroundAlpha: number,
/** /**
* The user selected background color. * The user selected background color.
*/ */
@ -121,6 +127,12 @@ class LargeVideo extends Component<Props> {
styles.backgroundColor = _customBackgroundColor || interfaceConfig.DEFAULT_BACKGROUND; styles.backgroundColor = _customBackgroundColor || interfaceConfig.DEFAULT_BACKGROUND;
if (this.props._backgroundAlpha !== undefined) {
const alphaColor = setColorAlpha(styles.backgroundColor, this.props._backgroundAlpha);
styles.backgroundColor = alphaColor;
}
if (_customBackgroundImageUrl) { if (_customBackgroundImageUrl) {
styles.backgroundImage = `url(${_customBackgroundImageUrl})`; styles.backgroundImage = `url(${_customBackgroundImageUrl})`;
styles.backgroundSize = 'cover'; styles.backgroundSize = 'cover';
@ -144,6 +156,7 @@ function _mapStateToProps(state) {
const { isOpen: isChatOpen } = state['features/chat']; const { isOpen: isChatOpen } = state['features/chat'];
return { return {
_backgroundAlpha: state['features/base/config'].backgroundAlpha,
_customBackgroundColor: backgroundColor, _customBackgroundColor: backgroundColor,
_customBackgroundImageUrl: backgroundImageUrl, _customBackgroundImageUrl: backgroundImageUrl,
_isChatOpen: isChatOpen, _isChatOpen: isChatOpen,