feat(toolbox): Adaptive toolbar on mobile
This commit is contained in:
parent
8da154b185
commit
e7297714c6
|
@ -29,6 +29,7 @@ export const ColorPalette = {
|
||||||
overflowMenuItemUnderlay: '#EEEEEE',
|
overflowMenuItemUnderlay: '#EEEEEE',
|
||||||
red: '#D00000',
|
red: '#D00000',
|
||||||
transparent: 'rgba(0, 0, 0, 0)',
|
transparent: 'rgba(0, 0, 0, 0)',
|
||||||
|
toggled: 'rgba(255,255,255,.15)',
|
||||||
warning: 'rgb(215, 121, 118)',
|
warning: 'rgb(215, 121, 118)',
|
||||||
white: '#FFFFFF',
|
white: '#FFFFFF',
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { RoomLockButton } from '../../../room-lock';
|
||||||
import { SharedVideoButton } from '../../../shared-video/components';
|
import { SharedVideoButton } from '../../../shared-video/components';
|
||||||
import { ClosedCaptionButton } from '../../../subtitles';
|
import { ClosedCaptionButton } from '../../../subtitles';
|
||||||
import { TileViewButton } from '../../../video-layout';
|
import { TileViewButton } from '../../../video-layout';
|
||||||
|
import { getMovableButtons } from '../../functions.native';
|
||||||
import HelpButton from '../HelpButton';
|
import HelpButton from '../HelpButton';
|
||||||
import MuteEveryoneButton from '../MuteEveryoneButton';
|
import MuteEveryoneButton from '../MuteEveryoneButton';
|
||||||
|
|
||||||
|
@ -48,6 +49,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
_recordingEnabled: boolean,
|
_recordingEnabled: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the screen.
|
||||||
|
*/
|
||||||
|
_width: number,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for hiding the dialog when the selection was completed.
|
* Used for hiding the dialog when the selection was completed.
|
||||||
*/
|
*/
|
||||||
|
@ -108,8 +114,9 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { _bottomSheetStyles } = this.props;
|
const { _bottomSheetStyles, _width } = this.props;
|
||||||
const { showMore } = this.state;
|
const { showMore } = this.state;
|
||||||
|
const toolbarButtons = getMovableButtons(_width);
|
||||||
|
|
||||||
const buttonProps = {
|
const buttonProps = {
|
||||||
afterClick: this._onCancel,
|
afterClick: this._onCancel,
|
||||||
|
@ -129,15 +136,15 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||||
onSwipe = { this._onSwipe }
|
onSwipe = { this._onSwipe }
|
||||||
renderHeader = { this._renderMenuExpandToggle }>
|
renderHeader = { this._renderMenuExpandToggle }>
|
||||||
<AudioRouteButton { ...buttonProps } />
|
<AudioRouteButton { ...buttonProps } />
|
||||||
<InviteButton { ...buttonProps } />
|
{!toolbarButtons.has('invite') && <InviteButton { ...buttonProps } />}
|
||||||
<AudioOnlyButton { ...buttonProps } />
|
<AudioOnlyButton { ...buttonProps } />
|
||||||
<RaiseHandButton { ...buttonProps } />
|
{!toolbarButtons.has('raisehand') && <RaiseHandButton { ...buttonProps } />}
|
||||||
<LobbyModeButton { ...buttonProps } />
|
<LobbyModeButton { ...buttonProps } />
|
||||||
<ScreenSharingButton { ...buttonProps } />
|
<ScreenSharingButton { ...buttonProps } />
|
||||||
<MoreOptionsButton { ...moreOptionsButtonProps } />
|
<MoreOptionsButton { ...moreOptionsButtonProps } />
|
||||||
<Collapsible collapsed = { !showMore }>
|
<Collapsible collapsed = { !showMore }>
|
||||||
<ToggleCameraButton { ...buttonProps } />
|
{!toolbarButtons.has('togglecamera') && <ToggleCameraButton { ...buttonProps } />}
|
||||||
<TileViewButton { ...buttonProps } />
|
{!toolbarButtons.has('tileview') && <TileViewButton { ...buttonProps } />}
|
||||||
<RecordButton { ...buttonProps } />
|
<RecordButton { ...buttonProps } />
|
||||||
<LiveStreamButton { ...buttonProps } />
|
<LiveStreamButton { ...buttonProps } />
|
||||||
<SharedVideoButton { ...buttonProps } />
|
<SharedVideoButton { ...buttonProps } />
|
||||||
|
@ -244,7 +251,8 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||||
function _mapStateToProps(state) {
|
function _mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
_bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
_bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||||
_isOpen: isDialogOpen(state, OverflowMenu_)
|
_isOpen: isDialogOpen(state, OverflowMenu_),
|
||||||
|
_width: state['features/base/responsive-ui'].clientWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React, { PureComponent } from 'react';
|
import React from 'react';
|
||||||
import { SafeAreaView, View } from 'react-native';
|
import { SafeAreaView, View } from 'react-native';
|
||||||
|
|
||||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { StyleType } from '../../../base/styles';
|
import { StyleType } from '../../../base/styles';
|
||||||
import { ChatButton } from '../../../chat';
|
import { ChatButton } from '../../../chat';
|
||||||
import { isToolboxVisible } from '../../functions';
|
import { InviteButton } from '../../../invite';
|
||||||
|
import { TileViewButton } from '../../../video-layout';
|
||||||
|
import { isToolboxVisible, getMovableButtons } from '../../functions.native';
|
||||||
import AudioMuteButton from '../AudioMuteButton';
|
import AudioMuteButton from '../AudioMuteButton';
|
||||||
import HangupButton from '../HangupButton';
|
import HangupButton from '../HangupButton';
|
||||||
import VideoMuteButton from '../VideoMuteButton';
|
import VideoMuteButton from '../VideoMuteButton';
|
||||||
|
|
||||||
import OverflowMenuButton from './OverflowMenuButton';
|
import OverflowMenuButton from './OverflowMenuButton';
|
||||||
|
import RaiseHandButton from './RaiseHandButton';
|
||||||
|
import ToggleCameraButton from './ToggleCameraButton';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +34,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
_visible: boolean,
|
_visible: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the screen.
|
||||||
|
*/
|
||||||
|
_width: number,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The redux {@code dispatch} function.
|
* The redux {@code dispatch} function.
|
||||||
*/
|
*/
|
||||||
|
@ -37,22 +46,26 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the conference toolbox on React Native.
|
* Implements the conference Toolbox on React Native.
|
||||||
*/
|
|
||||||
class Toolbox extends PureComponent<Props> {
|
|
||||||
/**
|
|
||||||
* Implements React's {@link Component#render()}.
|
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @param {Object} props - The props of the component.
|
||||||
* @returns {ReactElement}
|
* @returns {React$Element}.
|
||||||
*/
|
*/
|
||||||
render() {
|
function Toolbox(props: Props) {
|
||||||
if (!this.props._visible) {
|
if (!props._visible) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { _styles } = this.props;
|
const { _styles, _width } = props;
|
||||||
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
|
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
|
||||||
|
const additionalButtons = getMovableButtons(_width);
|
||||||
|
const backgroundToggledStyle = {
|
||||||
|
...toggledButtonStyles,
|
||||||
|
style: [
|
||||||
|
toggledButtonStyles.style,
|
||||||
|
_styles.backgroundToggle
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
|
@ -68,9 +81,21 @@ class Toolbox extends PureComponent<Props> {
|
||||||
<VideoMuteButton
|
<VideoMuteButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { toggledButtonStyles } />
|
toggledStyles = { toggledButtonStyles } />
|
||||||
<ChatButton
|
{ additionalButtons.has('chat')
|
||||||
|
&& <ChatButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { this._getChatButtonToggledStyle(toggledButtonStyles) } />
|
toggledStyles = { backgroundToggledStyle } />}
|
||||||
|
|
||||||
|
{ additionalButtons.has('raisehand')
|
||||||
|
&& <RaiseHandButton
|
||||||
|
styles = { buttonStylesBorderless }
|
||||||
|
toggledStyles = { backgroundToggledStyle } />}
|
||||||
|
{additionalButtons.has('tileview') && <TileViewButton styles = { buttonStylesBorderless } />}
|
||||||
|
{additionalButtons.has('invite') && <InviteButton styles = { buttonStylesBorderless } />}
|
||||||
|
{additionalButtons.has('togglecamera')
|
||||||
|
&& <ToggleCameraButton
|
||||||
|
styles = { buttonStylesBorderless }
|
||||||
|
toggledStyles = { backgroundToggledStyle } />}
|
||||||
<OverflowMenuButton
|
<OverflowMenuButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { toggledButtonStyles } />
|
toggledStyles = { toggledButtonStyles } />
|
||||||
|
@ -79,38 +104,6 @@ class Toolbox extends PureComponent<Props> {
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the toggled style of the chat button. This cannot be done by
|
|
||||||
* simple style inheritance due to the size calculation done in this
|
|
||||||
* component.
|
|
||||||
*
|
|
||||||
* @param {Object} baseStyle - The base style that was originally
|
|
||||||
* calculated.
|
|
||||||
* @returns {Object | Array}
|
|
||||||
*/
|
|
||||||
_getChatButtonToggledStyle(baseStyle) {
|
|
||||||
const { _styles } = this.props;
|
|
||||||
|
|
||||||
if (Array.isArray(baseStyle.style)) {
|
|
||||||
return {
|
|
||||||
...baseStyle,
|
|
||||||
style: [
|
|
||||||
...baseStyle.style,
|
|
||||||
_styles.chatButtonOverride.toggled
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...baseStyle,
|
|
||||||
style: [
|
|
||||||
baseStyle.style,
|
|
||||||
_styles.chatButtonOverride.toggled
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,7 +118,8 @@ class Toolbox extends PureComponent<Props> {
|
||||||
function _mapStateToProps(state: Object): Object {
|
function _mapStateToProps(state: Object): Object {
|
||||||
return {
|
return {
|
||||||
_styles: ColorSchemeRegistry.get(state, 'Toolbox'),
|
_styles: ColorSchemeRegistry.get(state, 'Toolbox'),
|
||||||
_visible: isToolboxVisible(state)
|
_visible: isToolboxVisible(state),
|
||||||
|
_width: state['features/base/responsive-ui'].clientWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,8 @@ const toolbarButton = {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
height: BUTTON_SIZE,
|
height: BUTTON_SIZE,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
marginHorizontal: 6,
|
||||||
// XXX We probably tested BoxModel.margin and discovered it to be too small
|
marginTop: 6,
|
||||||
// for our taste.
|
|
||||||
marginHorizontal: 7,
|
|
||||||
width: BUTTON_SIZE
|
width: BUTTON_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,7 +63,8 @@ const styles = {
|
||||||
toolbox: {
|
toolbox: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: ColorPalette.darkBackground,
|
backgroundColor: ColorPalette.darkBackground,
|
||||||
borderRadius: 3,
|
borderTopLeftRadius: 3,
|
||||||
|
borderTopRightRadius: 3,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
flexGrow: 0,
|
flexGrow: 0,
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
@ -108,14 +107,8 @@ ColorSchemeRegistry.register('Toolbox', {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
backgroundToggle: {
|
||||||
* Overrides to the standard styles that we apply to the chat button, as
|
backgroundColor: ColorPalette.toggled
|
||||||
* that behaves slightly differently to other buttons.
|
|
||||||
*/
|
|
||||||
chatButtonOverride: {
|
|
||||||
toggled: {
|
|
||||||
backgroundColor: ColorPalette.blue
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hangupButtonStyles: {
|
hangupButtonStyles: {
|
||||||
|
|
|
@ -5,6 +5,51 @@ import { TOOLBOX_ALWAYS_VISIBLE, getFeatureFlag, TOOLBOX_ENABLED } from '../base
|
||||||
import { toState } from '../base/redux';
|
import { toState } from '../base/redux';
|
||||||
import { isLocalVideoTrackDesktop } from '../base/tracks';
|
import { isLocalVideoTrackDesktop } from '../base/tracks';
|
||||||
|
|
||||||
|
const WIDTH = {
|
||||||
|
FIT_9_ICONS: 560,
|
||||||
|
FIT_8_ICONS: 500,
|
||||||
|
FIT_7_ICONS: 440,
|
||||||
|
FIT_6_ICONS: 380
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of the buttons that are shown in the toolbar
|
||||||
|
* but removed from the overflow menu, based on the width of the screen.
|
||||||
|
*
|
||||||
|
* @param {number} width - The width of the screen.
|
||||||
|
* @returns {Set}
|
||||||
|
*/
|
||||||
|
export function getMovableButtons(width: number): Set<string> {
|
||||||
|
let buttons = [];
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case width >= WIDTH.FIT_9_ICONS: {
|
||||||
|
buttons = [ 'togglecamera', 'chat', 'invite', 'raisehand', 'tileview' ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case width >= WIDTH.FIT_8_ICONS: {
|
||||||
|
buttons = [ 'chat', 'invite', 'raisehand', 'tileview' ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case width >= WIDTH.FIT_7_ICONS: {
|
||||||
|
buttons = [ 'chat', 'raisehand', 'invite' ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case width >= WIDTH.FIT_6_ICONS: {
|
||||||
|
buttons = [ 'chat', 'raisehand' ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
buttons = [ 'chat' ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Set(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the toolbox is visible.
|
* Returns true if the toolbox is visible.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue