feat(prejoin): Add 'skip prejoin' button
This commit is contained in:
parent
c8444a9a0d
commit
035f720a50
|
@ -36,13 +36,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&-checkbox-container {
|
&-checkbox-container {
|
||||||
align-items: center;
|
margin-bottom: 14px;
|
||||||
color: #fff;
|
|
||||||
display: none;
|
|
||||||
font-size: 13px;
|
|
||||||
justify-content: center;
|
|
||||||
line-height: 20px;
|
|
||||||
margin-top: 16px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,3 +216,66 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin flex-centered() {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin icon-container($bg, $fill) {
|
||||||
|
.toggle-button-icon-container {
|
||||||
|
background: $bg;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $fill
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-button {
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
height: 40px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 320px;
|
||||||
|
|
||||||
|
@include flex-centered();
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #1C2025;
|
||||||
|
|
||||||
|
@include icon-container(#A4B8D1, #1C2025);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
@include flex-centered();
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon-container {
|
||||||
|
border-radius: 50%;
|
||||||
|
left: -22px;
|
||||||
|
padding: 2px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--toggled {
|
||||||
|
background: #75757A;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #75757A;
|
||||||
|
|
||||||
|
@include icon-container(#A4B8D1, #75757A);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include icon-container(#A4B8D1, #75757A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
title: string,
|
title: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'Skip prejoin' button to be rendered (if any).
|
||||||
|
*/
|
||||||
|
skipPrejoinButton?: React$Node,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the preview overlay should be muted, false otherwise.
|
* True if the preview overlay should be muted, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -97,6 +102,7 @@ export default class PreMeetingScreen extends PureComponent<Props> {
|
||||||
<AudioSettingsButton visible = { true } />
|
<AudioSettingsButton visible = { true } />
|
||||||
<VideoSettingsButton visible = { true } />
|
<VideoSettingsButton visible = { true } />
|
||||||
</div>
|
</div>
|
||||||
|
{ this.props.skipPrejoinButton }
|
||||||
{ this.props.footer }
|
{ this.props.footer }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Icon, IconCheck } from '../../../icons';
|
||||||
|
|
||||||
|
const mainClass = 'toggle-button';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text of the button.
|
||||||
|
*/
|
||||||
|
children: React$Node,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the button is toggled or not.
|
||||||
|
*/
|
||||||
|
isToggled?: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OnClick button handler.
|
||||||
|
*/
|
||||||
|
onClick: Function
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Button used as a toggle.
|
||||||
|
*
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
function ToggleButton({ children, isToggled, onClick }: Props) {
|
||||||
|
const className = isToggled ? `${mainClass} ${mainClass}--toggled` : mainClass;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className = { className }
|
||||||
|
onClick = { onClick }>
|
||||||
|
<div className = 'toggle-button-container'>
|
||||||
|
<div className = 'toggle-button-icon-container'>
|
||||||
|
<Icon
|
||||||
|
className = 'toggle-button-icon'
|
||||||
|
size = { 10 }
|
||||||
|
src = { IconCheck } />
|
||||||
|
</div>
|
||||||
|
<span>{children}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToggleButton;
|
|
@ -3,3 +3,4 @@
|
||||||
export { default as ActionButton } from './ActionButton';
|
export { default as ActionButton } from './ActionButton';
|
||||||
export { default as InputField } from './InputField';
|
export { default as InputField } from './InputField';
|
||||||
export { default as PreMeetingScreen } from './PreMeetingScreen';
|
export { default as PreMeetingScreen } from './PreMeetingScreen';
|
||||||
|
export { default as ToggleButton } from './ToggleButton';
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { getRoomName } from '../../base/conference';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import { Icon, IconPhone, IconVolumeOff } from '../../base/icons';
|
import { Icon, IconPhone, IconVolumeOff } from '../../base/icons';
|
||||||
import { isVideoMutedByUser } from '../../base/media';
|
import { isVideoMutedByUser } from '../../base/media';
|
||||||
import { ActionButton, InputField, PreMeetingScreen } from '../../base/premeeting';
|
import { ActionButton, InputField, PreMeetingScreen, ToggleButton } from '../../base/premeeting';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux';
|
||||||
import { getDisplayName, updateSettings } from '../../base/settings';
|
import { getDisplayName, updateSettings } from '../../base/settings';
|
||||||
import { getLocalJitsiVideoTrack } from '../../base/tracks';
|
import { getLocalJitsiVideoTrack } from '../../base/tracks';
|
||||||
|
@ -21,7 +21,8 @@ import {
|
||||||
isDeviceStatusVisible,
|
isDeviceStatusVisible,
|
||||||
isDisplayNameRequired,
|
isDisplayNameRequired,
|
||||||
isJoinByPhoneButtonVisible,
|
isJoinByPhoneButtonVisible,
|
||||||
isJoinByPhoneDialogVisible
|
isJoinByPhoneDialogVisible,
|
||||||
|
isPrejoinSkipped
|
||||||
} from '../functions';
|
} from '../functions';
|
||||||
|
|
||||||
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
||||||
|
@ -29,6 +30,11 @@ import DeviceStatus from './preview/DeviceStatus';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag signaling if the 'skip prejoin' button is toggled or not.
|
||||||
|
*/
|
||||||
|
buttonIsToggled: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag signaling if the device status is visible or not.
|
* Flag signaling if the device status is visible or not.
|
||||||
*/
|
*/
|
||||||
|
@ -145,22 +151,22 @@ class Prejoin extends Component<Props, State> {
|
||||||
|
|
||||||
this._closeDialog = this._closeDialog.bind(this);
|
this._closeDialog = this._closeDialog.bind(this);
|
||||||
this._showDialog = this._showDialog.bind(this);
|
this._showDialog = this._showDialog.bind(this);
|
||||||
this._onCheckboxChange = this._onCheckboxChange.bind(this);
|
this._onToggleButtonClick = this._onToggleButtonClick.bind(this);
|
||||||
this._onDropdownClose = this._onDropdownClose.bind(this);
|
this._onDropdownClose = this._onDropdownClose.bind(this);
|
||||||
this._onOptionsClick = this._onOptionsClick.bind(this);
|
this._onOptionsClick = this._onOptionsClick.bind(this);
|
||||||
this._setName = this._setName.bind(this);
|
this._setName = this._setName.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCheckboxChange: () => void;
|
_onToggleButtonClick: () => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the checkbox.
|
* Handler for the toggle button.
|
||||||
*
|
*
|
||||||
* @param {Object} e - The synthetic event.
|
* @param {Object} e - The synthetic event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onCheckboxChange(e) {
|
_onToggleButtonClick() {
|
||||||
this.props.setSkipPrejoin(e.target.checked);
|
this.props.setSkipPrejoin(!this.props.buttonIsToggled);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDropdownClose: () => void;
|
_onDropdownClose: () => void;
|
||||||
|
@ -250,7 +256,7 @@ class Prejoin extends Component<Props, State> {
|
||||||
videoTrack
|
videoTrack
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { _closeDialog, _onCheckboxChange, _onDropdownClose, _onOptionsClick, _setName, _showDialog } = this;
|
const { _closeDialog, _onDropdownClose, _onOptionsClick, _setName, _showDialog } = this;
|
||||||
const { showJoinByPhoneButtons } = this.state;
|
const { showJoinByPhoneButtons } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -259,6 +265,7 @@ class Prejoin extends Component<Props, State> {
|
||||||
name = { name }
|
name = { name }
|
||||||
showAvatar = { showAvatar }
|
showAvatar = { showAvatar }
|
||||||
showConferenceInfo = { showJoinActions }
|
showConferenceInfo = { showJoinActions }
|
||||||
|
skipPrejoinButton = { this._renderSkipPrejoinButton() }
|
||||||
title = { t('prejoin.joinMeeting') }
|
title = { t('prejoin.joinMeeting') }
|
||||||
videoMuted = { !showCameraPreview }
|
videoMuted = { !showCameraPreview }
|
||||||
videoTrack = { videoTrack }>
|
videoTrack = { videoTrack }>
|
||||||
|
@ -306,14 +313,6 @@ class Prejoin extends Component<Props, State> {
|
||||||
</InlineDialog>
|
</InlineDialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className = 'prejoin-checkbox-container'>
|
|
||||||
<input
|
|
||||||
className = 'prejoin-checkbox'
|
|
||||||
onChange = { _onCheckboxChange }
|
|
||||||
type = 'checkbox' />
|
|
||||||
<span>{t('prejoin.doNotShow')}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ showDialog && (
|
{ showDialog && (
|
||||||
|
@ -333,6 +332,25 @@ class Prejoin extends Component<Props, State> {
|
||||||
_renderFooter() {
|
_renderFooter() {
|
||||||
return this.props.deviceStatusVisible && <DeviceStatus />;
|
return this.props.deviceStatusVisible && <DeviceStatus />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the 'skip prejoin' button.
|
||||||
|
*
|
||||||
|
* @returns {React$Element}
|
||||||
|
*/
|
||||||
|
_renderSkipPrejoinButton() {
|
||||||
|
const { buttonIsToggled, t } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className = 'prejoin-checkbox-container'>
|
||||||
|
<ToggleButton
|
||||||
|
isToggled = { buttonIsToggled }
|
||||||
|
onClick = { this._onToggleButtonClick }>
|
||||||
|
{t('prejoin.doNotShow')}
|
||||||
|
</ToggleButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -346,6 +364,7 @@ function mapStateToProps(state): Object {
|
||||||
const joinButtonDisabled = isDisplayNameRequired(state) && !name;
|
const joinButtonDisabled = isDisplayNameRequired(state) && !name;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
buttonIsToggled: isPrejoinSkipped(state),
|
||||||
joinButtonDisabled,
|
joinButtonDisabled,
|
||||||
name,
|
name,
|
||||||
deviceStatusVisible: isDeviceStatusVisible(state),
|
deviceStatusVisible: isDeviceStatusVisible(state),
|
||||||
|
|
|
@ -36,6 +36,16 @@ export function isDisplayNameRequired(state: Object): boolean {
|
||||||
|| state['features/base/config'].requireDisplayName;
|
|| state['features/base/config'].requireDisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector for determining if the user has chosen to skip prejoin page.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The state of the app.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isPrejoinSkipped(state: Object) {
|
||||||
|
return state['features/prejoin'].userSelectedSkipPrejoin;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text for the prejoin status bar.
|
* Returns the text for the prejoin status bar.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue