diff --git a/css/_base.scss b/css/_base.scss index 5bf154cdd937..a8d27f0d901f 100644 --- a/css/_base.scss +++ b/css/_base.scss @@ -123,12 +123,33 @@ form { } .watermark { - position: relative; - top: 32px; - left: 32px; + position: absolute; + top: 0; + left: 0; min-width: 120px; - height: 74px; + padding-left: 20px; + padding-top: 20px; + padding-bottom: 20px; + width: 100%; z-index: 2; + + &-with-background{ + background-color: rgba(0, 0, 0, 0.2); + } + + .close { + position: absolute; + top: 20px; + right: 40px; + cursor: pointer; + + svg:focus, + svg:hover, + svg:active { + fill: #cccccc + } + } + } .leftwatermark { @@ -146,10 +167,10 @@ form { padding-left: 120px; padding-top: 5px; text-align: left; - color: $defaultDarkColor !important; + color: $defaultColor !important; p { - font-family: "ProximaNovaLtLight"; + font-family: "ProximaNovaLtSbold"; &:first-child { font-size: 24px; @@ -163,6 +184,7 @@ form { @media all and (max-width: 800px) { padding-left: 0; padding-top: 85px; + padding-right: 50px; p { &:first-child { font-size: 16px; diff --git a/css/_toolbars.scss b/css/_toolbars.scss index 6674290d395e..508e4ba52a02 100644 --- a/css/_toolbars.scss +++ b/css/_toolbars.scss @@ -78,6 +78,32 @@ min-width: 200px; } .toolbox-button { + &.test-hangup-btn { + .jitsi-icon { + svg { + fill: #fff !important; + } + } + + & > div > div:nth-child(2) > div { + top: -5!important; + + & > div:nth-child(1) { + padding: 5px 20px 5px 10px; + line-height: 20px; + + span:after { + content: ""; + position: absolute; + bottom: -5px; + right: 90px; + border-width: 5px 5px 0; + border-style: solid; + border-color: #283447 transparent; + } + } + } + } .toolbox-icon { @media all and (max-width: 420px) { @@ -90,31 +116,31 @@ margin: 0px 4px; width: 38px; height: 38px; - + &:hover { background-color: #daebfa; border: 1px solid #daebfa; } - + &.toggled { background: #2a3a4b; border: 1px solid #5e6d7a; - + svg { fill: #fff; } - + &:hover { background-color: #5e6d7a; } } - + &.disabled, .disabled & { cursor: initial; color: #fff; background-color: #a4b8d1; } - + svg { fill: #5e6d7a; } @@ -130,7 +156,7 @@ border: 1px solid $hangupColor; width: 40px; height: 40px; - + &:hover { background-color: $hangupColor; } @@ -268,7 +294,7 @@ &:hover, &.toggled { background: $newToolbarButtonHoverColor; } - + &.disabled { cursor: initial !important; background-color: #a4b8d1 !important; diff --git a/css/_video-preview.css b/css/_video-preview.css index 084714dbb71a..df91701f354e 100644 --- a/css/_video-preview.css +++ b/css/_video-preview.css @@ -1,6 +1,5 @@ .video-preview { max-height: 290px; - overflow: auto; &-entry { cursor: pointer; diff --git a/react/features/base/conference/functions.js b/react/features/base/conference/functions.js index ec3c147bcb71..85d9c6c7d941 100644 --- a/react/features/base/conference/functions.js +++ b/react/features/base/conference/functions.js @@ -22,6 +22,7 @@ import { } from './constants'; import logger from './logger'; +import jwtDecode from 'jwt-decode'; /** * Attach a set of local tracks to a conference. * @@ -370,3 +371,15 @@ function safeStartCase(s = '') { (result, word, index) => result + (index ? ' ' : '') + _.upperFirst(word) , ''); } + +export function isJaneTestMode(state: Object) { + const { jwt } = state['features/base/jwt']; + const jwtPayload = jwt && jwtDecode(jwt) || null; + const context = jwtPayload && jwtPayload.context || null; + const user = context && context.user || null; + const participantId = user && user.participant_id; + const videoChatSessionId = context && context.video_chat_session_id; + const participantEmail = user && user.email; + + return participantId === 0 && videoChatSessionId === 0 && participantEmail === 'test@test.com'; +} diff --git a/react/features/base/react/components/web/WaitingMessage.js b/react/features/base/react/components/web/WaitingMessage.js index 3ccad3d45437..0c7c8caf7a95 100644 --- a/react/features/base/react/components/web/WaitingMessage.js +++ b/react/features/base/react/components/web/WaitingMessage.js @@ -7,12 +7,19 @@ import { connect } from '../../../redux'; import { getParticipantCount } from '../../../participants'; import { getRemoteTracks } from '../../../tracks'; import jwtDecode from 'jwt-decode'; +import { + IconClose +} from '../../../../base/icons'; +import { Icon } from '../../../icons/components'; +import { isJaneTestMode } from '../../../conference'; type Props = { _isGuest: boolean, jwt: Object, conferenceHasStarted: boolean, - isWelcomePage: boolean + waitingMessageHeader: string, + onClose: Function, + isJaneTestMode: boolean }; type State = { @@ -80,7 +87,7 @@ class WaitingMessage extends Component { } render() { - const { conferenceHasStarted } = this.props; + const { conferenceHasStarted, isJaneTestMode } = this.props; if (conferenceHasStarted) { return null; @@ -91,25 +98,46 @@ class WaitingMessage extends Component { { this._renderWaitingMessage() } + {!isJaneTestMode &&
+ { + this.props.onClose(); + }}/> +
} ); } _renderWaitingMessage() { const { beforeAppointmentStart, appointmentStartAt } = this.state; + const { waitingMessageHeader, isJaneTestMode } = this.props; let header =

Waiting for the other participant to join...

; + let text =

Sit back, relax and take a moment for yourself.

; if (beforeAppointmentStart && appointmentStartAt) { header = (

Your appointment will begin at {getLocalizedDateFormatter(appointmentStartAt).format('hh:mm A')}

); } - return (
+ if (waitingMessageHeader) { + header =

{waitingMessageHeader}

; + } + + if (isJaneTestMode) { + header =

Testing your audio and video...

; + text =

+ This is just a test area. Begin your online appointment from + your Upcoming Appointments page. +

; + } + + return (
{ header } -

Sit back, relax and take a moment for yourself.

+ { + text + }
); } } @@ -119,10 +147,10 @@ function _mapStateToProps(state) { const participantCount = getParticipantCount(state); const remoteTracks = getRemoteTracks(state['features/base/tracks']); - return { jwt, - conferenceHasStarted: participantCount > 1 && remoteTracks.length > 0 + conferenceHasStarted: participantCount > 1 && remoteTracks.length > 0, + isJaneTestMode: isJaneTestMode(state) }; } diff --git a/react/features/base/react/components/web/Watermarks.js b/react/features/base/react/components/web/Watermarks.js index d4ae5cd3358f..57c791c0bee9 100644 --- a/react/features/base/react/components/web/Watermarks.js +++ b/react/features/base/react/components/web/Watermarks.js @@ -10,15 +10,6 @@ import WaitingMessage from './WaitingMessage'; declare var interfaceConfig: Object; -/** - * The CSS style of the element with CSS class {@code rightwatermark}. - * - * @private - */ -const _RIGHT_WATERMARK_STYLE = { - backgroundImage: 'url(images/rightwatermark.png)' -}; - /** * The type of the React {@code Component} props of {@link Watermarks}. */ @@ -29,7 +20,8 @@ type Props = { */ _isGuest: boolean, conferenceHasStarted: boolean, - isWelcomePage: boolean, + hideWaitingMessage: boolean, + waitingMessageHeader: string, /** * Invoked to obtain translated strings. @@ -71,7 +63,8 @@ type State = { /** * Whether or not the show the "powered by Jitsi.org" link. */ - showPoweredBy: boolean + showPoweredBy: boolean, + hideWaitingMessage: boolean }; /** @@ -112,10 +105,25 @@ class Watermarks extends Component { showBrandWatermark, showJitsiWatermark, showJitsiWatermarkForGuests, - showPoweredBy: interfaceConfig.SHOW_POWERED_BY + showPoweredBy: interfaceConfig.SHOW_POWERED_BY, + hideWaitingMessage: props.hideWaitingMessage || false }; } + componentDidUpdate(prevProps) { + if (prevProps.hideWaitingMessage !== this.props.hideWaitingMessage) { + this.setState({ + hideWaitingMessage: prevProps.hideWaitingMessage + }); + } + } + + hideWaitingMessageAction() { + this.setState({ + hideWaitingMessage: true + }); + } + /** * Implements React's {@link Component#render()}. * @@ -139,14 +147,16 @@ class Watermarks extends Component { * @returns {ReactElement|null} */ _renderWatermark() { - const { conferenceHasStarted, isWelcomePage } = this.props; - - - return (
+ const { conferenceHasStarted, waitingMessageHeader } = this.props; + const { hideWaitingMessage } = this.state; + return (
+ className={`leftwatermark ${conferenceHasStarted || hideWaitingMessage ? '' : 'animate-flicker'}`}/> { - !isWelcomePage && + !hideWaitingMessage && + }
); } @@ -165,7 +175,6 @@ function _mapStateToProps(state) { const participantCount = getParticipantCount(state); const remoteTracks = getRemoteTracks(state['features/base/tracks']); - return { _isGuest: isGuest, conferenceHasStarted: participantCount > 1 && remoteTracks.length > 0 diff --git a/react/features/toolbox/components/TestHangupButton.js b/react/features/toolbox/components/TestHangupButton.js new file mode 100644 index 000000000000..829eb9b5802c --- /dev/null +++ b/react/features/toolbox/components/TestHangupButton.js @@ -0,0 +1,102 @@ +// @flow +/* eslint-disable */ + +import React, { Component } from 'react'; +import InlineDialog from '@atlaskit/inline-dialog'; +import { Icon } from '../../base/icons/components'; +import { IconHangup, IconClose } from '../../base/icons'; +import { translate } from '../../base/i18n'; +import { connect } from '../../base/redux'; +import _ from 'lodash'; +import { createToolbarEvent, sendAnalytics } from '../../analytics'; +import { appNavigate } from '../../app'; +import { disconnect } from '../../base/connection'; + +export type Props = { + showTooltip: boolean, + dispatch: Function +}; + +type State = { + showTooltip: boolean, +}; + +const closeIconStyle = { + display: 'inline', + position: 'absolute', + top: 3, + right: 3 +}; + +const toolboxIconStyle = { + background: '#bf2117', + border: '1px solid #bf2117' +}; + + +class TestHangupButton extends Component { + + constructor(props) { + super(props); + this.state = { + showTooltip: props.showTooltip || false + }; + } + + tooltipIsClosedByUser = false; + + _hangup = _.once(() => { + sendAnalytics(createToolbarEvent('hangup')); + this.props.dispatch(disconnect(true)); + }); + + static getDerivedStateFromProps(props, state) { + if (props.showTooltip !== state.showTooltip) { + return { + showTooltip: props.showTooltip + }; + } + return null; + } + + _onClick(): void { + this._hangup(); + } + + _onCloseIconClick(): void { + this.setState({ + showTooltip: false + }, () => { + this.tooltipIsClosedByUser = true; + }); + } + + render(): React$Node { + + return ( +
+ Finished testing? Click here. + + } + isOpen={this.state.showTooltip && !this.tooltipIsClosedByUser} + position={'top center'}> +
+ +
+
+
+ ); + } +} + +export default translate(connect()(TestHangupButton)); diff --git a/react/features/toolbox/components/web/Toolbox.js b/react/features/toolbox/components/web/Toolbox.js index 77c35767bf62..e377a901b2c9 100644 --- a/react/features/toolbox/components/web/Toolbox.js +++ b/react/features/toolbox/components/web/Toolbox.js @@ -86,6 +86,8 @@ import VideoSettingsButton from './VideoSettingsButton'; import { ClosedCaptionButton } from '../../../subtitles'; +import TestHangupButton from '../TestHangupButton'; +import { isJaneTestMode } from '../../../base/conference'; /** * The type of the React {@code Component} props of {@link Toolbox}. @@ -192,7 +194,8 @@ type Props = { /** * Invoked to obtain translated strings. */ - t: Function + t: Function, + _isJaneTestMode: boolean }; /** @@ -1168,6 +1171,8 @@ class Toolbox extends Component { _hideInviteButton, _overflowMenuVisible, _raisedHand, + _visible, + _isJaneTestMode, t } = this.props; const overflowMenuContent = this._renderOverflowMenuContent(); @@ -1276,11 +1281,13 @@ class Toolbox extends Component { && }
-
- { this._renderAudioButton() } +
+ {this._renderAudioButton()} - { this._renderVideoButton() } + visible={this._shouldShowButton('hangup') && !_isJaneTestMode}/> + {_isJaneTestMode && + } + {this._renderVideoButton()}
{ buttonsRight.indexOf('localrecording') !== -1 @@ -1402,7 +1409,8 @@ function _mapStateToProps(state) { || sharedVideoStatus === 'start' || sharedVideoStatus === 'pause', _visible: isToolboxVisible(state), - _visibleButtons: equals(visibleButtons, buttons) ? visibleButtons : buttons + _visibleButtons: equals(visibleButtons, buttons) ? visibleButtons : buttons, + _isJaneTestMode: isJaneTestMode(state) }; } diff --git a/react/features/welcome/components/WelcomePage.web.js b/react/features/welcome/components/WelcomePage.web.js index 73c988132423..7dfa38079259 100644 --- a/react/features/welcome/components/WelcomePage.web.js +++ b/react/features/welcome/components/WelcomePage.web.js @@ -170,7 +170,7 @@ class WelcomePage extends AbstractWelcomePage { ? 'with-content' : 'without-content'}` } id = 'welcome_page'>
- +