diff --git a/css/_mixins.scss b/css/_mixins.scss index acf7c9679..d28e4504b 100644 --- a/css/_mixins.scss +++ b/css/_mixins.scss @@ -150,4 +150,12 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; +} + +/** + * Creates a semi-transparent background with the given color and alpha + * (opacity) value. + */ +@mixin transparentBg($color, $alpha) { + background-color: rgba(red($color), green($color), blue($color), $alpha); } \ No newline at end of file diff --git a/css/components/_button-control.scss b/css/components/_button-control.scss index 3a2392c99..5fa000292 100644 --- a/css/components/_button-control.scss +++ b/css/components/_button-control.scss @@ -82,4 +82,8 @@ color: $linkHoverFontColor; } } + + &_center { + float: none !important; + } } \ No newline at end of file diff --git a/css/overlay/_overlay.scss b/css/overlay/_overlay.scss index 9727bd7be..0e40f293d 100644 --- a/css/overlay/_overlay.scss +++ b/css/overlay/_overlay.scss @@ -1,5 +1,6 @@ .overlay { - &__container { + &__container, + &__container-light { top: 0; left: 0; width: 100%; @@ -9,6 +10,10 @@ background: $defaultBackground; } + &__container-light { + @include transparentBg($defaultBackground, 0.7); + } + &__content { position: absolute; margin: 0 auto; diff --git a/lang/main.json b/lang/main.json index c43795a84..2dc1487fd 100644 --- a/lang/main.json +++ b/lang/main.json @@ -215,6 +215,9 @@ "failedpermissions": "Failed to obtain permissions to use the local microphone and/or camera.", "conferenceReloadTitle": "Unfortunately, something went wrong", "conferenceReloadMsg": "We're trying to fix this", + "conferenceDisconnectTitle": "You have been disconnected. You may want to check your network connection.", + "conferenceDisconnectMsg": "Reconnecting in...", + "reconnectNow": "Reconnect now", "conferenceReloadTimeLeft": "__seconds__ sec.", "maxUsersLimitReached": "The limit for maximum number of participants in the conference has been reached. The conference is full. Please try again later!", "lockTitle": "Lock failed", diff --git a/modules/UI/UI.js b/modules/UI/UI.js index fdac5ffd1..30fbcf58e 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -17,7 +17,7 @@ import Recording from "./recording/Recording"; import GumPermissionsOverlay from './gum_overlay/UserMediaPermissionsGuidanceOverlay'; -import PageReloadOverlay from './reload_overlay/PageReloadOverlay'; +import * as PageReloadOverlay from './reload_overlay/PageReloadOverlay'; import SuspendedOverlay from './suspended_overlay/SuspendedOverlay'; import VideoLayout from "./videolayout/VideoLayout"; import FilmStrip from "./videolayout/FilmStrip"; diff --git a/modules/UI/overlay/Overlay.js b/modules/UI/overlay/Overlay.js index 361ce890a..f850c2a5f 100644 --- a/modules/UI/overlay/Overlay.js +++ b/modules/UI/overlay/Overlay.js @@ -15,26 +15,38 @@ export default class Overlay{ * @type {jQuery} */ this.$overlay = null; + + /** + * Indicates if this overlay should use the light look & feel or the + * standard one. + * @type {boolean} + */ + this.isLightOverlay = false; } /** * Template method which should be used by subclasses to provide the overlay * content. The contents provided by this method are later subject to * the translation using {@link APP.translation.translateElement}. * @return {string} HTML representation of the overlay dialog contents. - * @private + * @protected */ _buildOverlayContent() { return ''; } /** * Constructs the HTML body of the overlay dialog. + * + * @private */ - buildOverlayHtml() { + _buildOverlayHtml() { let overlayContent = this._buildOverlayContent(); + let containerClass = this.isLightOverlay ? "overlay__container-light" + : "overlay__container"; + this.$overlay = $(` -
+
${overlayContent}
@@ -53,18 +65,18 @@ export default class Overlay{ /** * Template method called just after the overlay is displayed for the first * time. - * @private + * @protected */ _onShow() { // To be overridden by subclasses. } /** - * Shows the overlay dialog adn attaches the underlying HTML representation + * Shows the overlay dialog and attaches the underlying HTML representation * to the DOM. */ show() { - !this.$overlay && this.buildOverlayHtml(); + !this.$overlay && this._buildOverlayHtml(); if (!this.isVisible()) { this.$overlay.appendTo('body'); diff --git a/modules/UI/reload_overlay/PageReloadOverlay.js b/modules/UI/reload_overlay/PageReloadOverlay.js index 7a1d1db37..aec4c5d2b 100644 --- a/modules/UI/reload_overlay/PageReloadOverlay.js +++ b/modules/UI/reload_overlay/PageReloadOverlay.js @@ -1,7 +1,7 @@ /* global $, APP, AJS */ const logger = require("jitsi-meet-logger").getLogger(__filename); -import Overlay from '../overlay/Overlay'; +import Overlay from "../overlay/Overlay"; /** * An overlay dialog which is shown before the conference is reloaded. Shows @@ -12,8 +12,14 @@ class PageReloadOverlayImpl extends Overlay{ * Creates new PageReloadOverlayImpl * @param {number} timeoutSeconds how long the overlay dialog will be * displayed, before the conference will be reloaded. + * @param {string} title the title of the overlay message + * @param {string} message the message of the overlay + * @param {string} buttonHtml the button html or an empty string if there's + * no button + * @param {boolean} isLightOverlay indicates if the overlay should be a + * light overlay or a standard one */ - constructor(timeoutSeconds) { + constructor(timeoutSeconds, title, message, buttonHtml, isLightOverlay) { super(); /** * Conference reload counter in seconds. @@ -25,6 +31,11 @@ class PageReloadOverlayImpl extends Overlay{ * @type {number} */ this.timeout = timeoutSeconds; + + this.title = title; + this.message = message; + this.buttonHtml = buttonHtml; + this.isLightOverlay = isLightOverlay; } /** * Constructs overlay body with the warning message and count down towards @@ -33,9 +44,9 @@ class PageReloadOverlayImpl extends Overlay{ */ _buildOverlayContent() { return `
- -
+ ${this.buttonHtml}
`; } @@ -67,6 +79,9 @@ class PageReloadOverlayImpl extends Overlay{ * @override */ _onShow() { + $("#reconnectNow").click(() => { + APP.ConferenceUrl.reload(); + }); // Initialize displays this.updateDisplay(); @@ -98,40 +113,63 @@ class PageReloadOverlayImpl extends Overlay{ */ let overlay; -export default { - /** - * Checks whether the page reload overlay has been displayed. - * @return {boolean} true if the page reload overlay is currently - * visible or false otherwise. - */ - isVisible() { +/** + * Checks whether the page reload overlay has been displayed. + * @return {boolean} true if the page reload overlay is currently + * visible or false otherwise. + */ +export function isVisible() { return overlay && overlay.isVisible(); - }, - /** - * Shows the page reload overlay which will do the conference reload after - * the given amount of time. - * - * @param {number} timeoutSeconds how many seconds before the conference - * reload will happen. - * @param {boolean} isNetworkFailure true indicates that it's - * caused by network related failure or false when it's - * the infrastructure. - * @param {string} reason a label string identifying the reason for the page - * reload which will be included in details of the log event - */ - show(timeoutSeconds, isNetworkFailure, reason) { +} - if (!overlay) { - overlay = new PageReloadOverlayImpl(timeoutSeconds); - } - // Log the page reload event - if (!this.isVisible()) { - // FIXME (CallStats - issue) this event will not make it to - // the CallStats, because the log queue is not flushed, before - // "fabric terminated" is sent to the backed - APP.conference.logEvent( - 'page.reload', undefined /* value */, reason /* label */); - } - overlay.show(); +/** + * Shows the page reload overlay which will do the conference reload after + * the given amount of time. + * + * @param {number} timeoutSeconds how many seconds before the conference + * reload will happen. + * @param {boolean} isNetworkFailure true indicates that it's + * caused by network related failure or false when it's + * the infrastructure. + * @param {string} reason a label string identifying the reason for the page + * reload which will be included in details of the log event + */ +export function show(timeoutSeconds, isNetworkFailure, reason) { + let title; + let message; + let buttonHtml; + let isLightOverlay; + + if (isNetworkFailure) { + title = "dialog.conferenceDisconnectTitle"; + message = "dialog.conferenceDisconnectMsg"; + buttonHtml + = ``; + isLightOverlay = true; } -}; + else { + title = "dialog.conferenceReloadTitle"; + message = "dialog.conferenceReloadMsg"; + buttonHtml = ""; + isLightOverlay = false; + } + + if (!overlay) { + overlay = new PageReloadOverlayImpl(timeoutSeconds, + title, + message, + buttonHtml, + isLightOverlay); + } + // Log the page reload event + if (!this.isVisible()) { + // FIXME (CallStats - issue) this event will not make it to + // the CallStats, because the log queue is not flushed, before + // "fabric terminated" is sent to the backed + APP.conference.logEvent( + 'page.reload', undefined /* value */, reason /* label */); + } + overlay.show(); +}