feat(toolbox): Adaptive toolbar on mobile
This commit is contained in:
parent
8da154b185
commit
e7297714c6
|
@ -29,6 +29,7 @@ export const ColorPalette = {
|
|||
overflowMenuItemUnderlay: '#EEEEEE',
|
||||
red: '#D00000',
|
||||
transparent: 'rgba(0, 0, 0, 0)',
|
||||
toggled: 'rgba(255,255,255,.15)',
|
||||
warning: 'rgb(215, 121, 118)',
|
||||
white: '#FFFFFF',
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import { RoomLockButton } from '../../../room-lock';
|
|||
import { SharedVideoButton } from '../../../shared-video/components';
|
||||
import { ClosedCaptionButton } from '../../../subtitles';
|
||||
import { TileViewButton } from '../../../video-layout';
|
||||
import { getMovableButtons } from '../../functions.native';
|
||||
import HelpButton from '../HelpButton';
|
||||
import MuteEveryoneButton from '../MuteEveryoneButton';
|
||||
|
||||
|
@ -48,6 +49,11 @@ type Props = {
|
|||
*/
|
||||
_recordingEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The width of the screen.
|
||||
*/
|
||||
_width: number,
|
||||
|
||||
/**
|
||||
* Used for hiding the dialog when the selection was completed.
|
||||
*/
|
||||
|
@ -108,8 +114,9 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _bottomSheetStyles } = this.props;
|
||||
const { _bottomSheetStyles, _width } = this.props;
|
||||
const { showMore } = this.state;
|
||||
const toolbarButtons = getMovableButtons(_width);
|
||||
|
||||
const buttonProps = {
|
||||
afterClick: this._onCancel,
|
||||
|
@ -129,15 +136,15 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
onSwipe = { this._onSwipe }
|
||||
renderHeader = { this._renderMenuExpandToggle }>
|
||||
<AudioRouteButton { ...buttonProps } />
|
||||
<InviteButton { ...buttonProps } />
|
||||
{!toolbarButtons.has('invite') && <InviteButton { ...buttonProps } />}
|
||||
<AudioOnlyButton { ...buttonProps } />
|
||||
<RaiseHandButton { ...buttonProps } />
|
||||
{!toolbarButtons.has('raisehand') && <RaiseHandButton { ...buttonProps } />}
|
||||
<LobbyModeButton { ...buttonProps } />
|
||||
<ScreenSharingButton { ...buttonProps } />
|
||||
<MoreOptionsButton { ...moreOptionsButtonProps } />
|
||||
<Collapsible collapsed = { !showMore }>
|
||||
<ToggleCameraButton { ...buttonProps } />
|
||||
<TileViewButton { ...buttonProps } />
|
||||
{!toolbarButtons.has('togglecamera') && <ToggleCameraButton { ...buttonProps } />}
|
||||
{!toolbarButtons.has('tileview') && <TileViewButton { ...buttonProps } />}
|
||||
<RecordButton { ...buttonProps } />
|
||||
<LiveStreamButton { ...buttonProps } />
|
||||
<SharedVideoButton { ...buttonProps } />
|
||||
|
@ -244,7 +251,8 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_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
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import React from 'react';
|
||||
import { SafeAreaView, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
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 HangupButton from '../HangupButton';
|
||||
import VideoMuteButton from '../VideoMuteButton';
|
||||
|
||||
import OverflowMenuButton from './OverflowMenuButton';
|
||||
import RaiseHandButton from './RaiseHandButton';
|
||||
import ToggleCameraButton from './ToggleCameraButton';
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
|
@ -30,6 +34,11 @@ type Props = {
|
|||
*/
|
||||
_visible: boolean,
|
||||
|
||||
/**
|
||||
* The width of the screen.
|
||||
*/
|
||||
_width: number,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
|
@ -37,80 +46,64 @@ type Props = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Implements the conference toolbox on React Native.
|
||||
* Implements the conference Toolbox on React Native.
|
||||
*
|
||||
* @param {Object} props - The props of the component.
|
||||
* @returns {React$Element}.
|
||||
*/
|
||||
class Toolbox extends PureComponent<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
if (!this.props._visible) {
|
||||
return null;
|
||||
}
|
||||
function Toolbox(props: Props) {
|
||||
if (!props._visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { _styles } = this.props;
|
||||
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
|
||||
const { _styles, _width } = props;
|
||||
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
|
||||
const additionalButtons = getMovableButtons(_width);
|
||||
const backgroundToggledStyle = {
|
||||
...toggledButtonStyles,
|
||||
style: [
|
||||
toggledButtonStyles.style,
|
||||
_styles.backgroundToggle
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
return (
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.toolboxContainer }>
|
||||
<SafeAreaView
|
||||
accessibilityRole = 'toolbar'
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.toolboxContainer }>
|
||||
<SafeAreaView
|
||||
accessibilityRole = 'toolbar'
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.toolbox }>
|
||||
<AudioMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
<VideoMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
<ChatButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { this._getChatButtonToggledStyle(toggledButtonStyles) } />
|
||||
<OverflowMenuButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
<HangupButton
|
||||
styles = { hangupButtonStyles } />
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
style = { styles.toolbox }>
|
||||
<AudioMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
<VideoMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
{ additionalButtons.has('chat')
|
||||
&& <ChatButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { backgroundToggledStyle } />}
|
||||
|
||||
/**
|
||||
* 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
|
||||
]
|
||||
};
|
||||
}
|
||||
{ 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
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
<HangupButton
|
||||
styles = { hangupButtonStyles } />
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +118,8 @@ class Toolbox extends PureComponent<Props> {
|
|||
function _mapStateToProps(state: Object): Object {
|
||||
return {
|
||||
_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',
|
||||
height: BUTTON_SIZE,
|
||||
justifyContent: 'center',
|
||||
|
||||
// XXX We probably tested BoxModel.margin and discovered it to be too small
|
||||
// for our taste.
|
||||
marginHorizontal: 7,
|
||||
marginHorizontal: 6,
|
||||
marginTop: 6,
|
||||
width: BUTTON_SIZE
|
||||
};
|
||||
|
||||
|
@ -65,7 +63,8 @@ const styles = {
|
|||
toolbox: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: ColorPalette.darkBackground,
|
||||
borderRadius: 3,
|
||||
borderTopLeftRadius: 3,
|
||||
borderTopRightRadius: 3,
|
||||
flexDirection: 'row',
|
||||
flexGrow: 0,
|
||||
justifyContent: 'space-between',
|
||||
|
@ -108,14 +107,8 @@ ColorSchemeRegistry.register('Toolbox', {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides to the standard styles that we apply to the chat button, as
|
||||
* that behaves slightly differently to other buttons.
|
||||
*/
|
||||
chatButtonOverride: {
|
||||
toggled: {
|
||||
backgroundColor: ColorPalette.blue
|
||||
}
|
||||
backgroundToggle: {
|
||||
backgroundColor: ColorPalette.toggled
|
||||
},
|
||||
|
||||
hangupButtonStyles: {
|
||||
|
|
|
@ -5,6 +5,51 @@ import { TOOLBOX_ALWAYS_VISIBLE, getFeatureFlag, TOOLBOX_ENABLED } from '../base
|
|||
import { toState } from '../base/redux';
|
||||
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.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue