feat(toolbox): Adaptive toolbar on mobile

This commit is contained in:
Vlad Piersec 2021-03-22 11:02:57 +02:00 committed by vp8x8
parent 8da154b185
commit e7297714c6
5 changed files with 132 additions and 91 deletions

View File

@ -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',

View File

@ -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
}; };
} }

View File

@ -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
}; };
} }

View File

@ -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: {

View File

@ -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.
* *