diff --git a/react/features/base/toolbox/components/AbstractToolboxItem.js b/react/features/base/toolbox/components/AbstractToolboxItem.js index 4da613261..e044bd59b 100644 --- a/react/features/base/toolbox/components/AbstractToolboxItem.js +++ b/react/features/base/toolbox/components/AbstractToolboxItem.js @@ -10,7 +10,7 @@ export type Styles = { iconStyle: Object, /** - * Style for te item's label. + * Style for the item's label. */ labelStyle: Object, @@ -174,7 +174,9 @@ export default class AbstractToolboxItem

extends Component

{ } /** - * Handles rendering of the actual item. + * Renders this {@code AbstractToolboxItem} (if it is {@code visible}). To + * be implemented/overridden by extenders. The default implementation of + * {@code AbstractToolboxItem} does nothing. * * @protected * @returns {ReactElement} diff --git a/react/features/base/toolbox/components/ToolboxItem.native.js b/react/features/base/toolbox/components/ToolboxItem.native.js index 1262cfe33..ef3e67651 100644 --- a/react/features/base/toolbox/components/ToolboxItem.native.js +++ b/react/features/base/toolbox/components/ToolboxItem.native.js @@ -26,7 +26,7 @@ export default class ToolboxItem extends AbstractToolboxItem { } /** - * Helper function to render the {@code Icon} part of this item. + * Renders the {@code Icon} part of this {@code ToolboxItem}. * * @private * @returns {ReactElement} @@ -42,8 +42,9 @@ export default class ToolboxItem extends AbstractToolboxItem { } /** - * Handles rendering of the actual item. + * Renders this {@code ToolboxItem}. Invoked by {@link AbstractToolboxItem}. * + * @override * @protected * @returns {ReactElement} */ @@ -56,25 +57,29 @@ export default class ToolboxItem extends AbstractToolboxItem { styles } = this.props; - let children; + let children = this._renderIcon(); + + // XXX When using a wrapper View, apply the style to it instead of + // applying it to the TouchableHighlight. + let style = styles && styles.style; if (showLabel) { - // eslint-disable-next-line no-extra-parens - children = ( - - { this._renderIcon() } - + // XXX TouchableHighlight requires 1 child. If there's a need to + // show both the icon and the label, then these two need to be + // wrapped in a View. + children = ( // eslint-disable-line no-extra-parens + + { children } + { this.label } ); - } else { - children = this._renderIcon(); - } - // When using a wrapper view, apply the style to it instead of - // applying it to the TouchableHighlight. - const style = showLabel ? undefined : styles && styles.style; + // XXX As stated earlier, the style was applied to the wrapper View + // (above). + style = undefined; + } return ( { accessibilityLabel = 'Share room'; diff --git a/react/features/toolbox/components/native/OverflowMenu.js b/react/features/toolbox/components/native/OverflowMenu.js index 1f1d54892..f29354c56 100644 --- a/react/features/toolbox/components/native/OverflowMenu.js +++ b/react/features/toolbox/components/native/OverflowMenu.js @@ -3,16 +3,18 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { hideDialog, BottomSheet } from '../../../base/dialog'; +import { BottomSheet, hideDialog } from '../../../base/dialog'; import { AudioRouteButton } from '../../../mobile/audio-mode'; import { PictureInPictureButton } from '../../../mobile/picture-in-picture'; import { RoomLockButton } from '../../../room-lock'; import AudioOnlyButton from './AudioOnlyButton'; +import { overflowMenuItemStyles } from './styles'; import ToggleCameraButton from './ToggleCameraButton'; -import { overflowMenuItemStyles } from './styles'; - +/** + * The type of the React {@code Component} props of {@link OverflowMenu}. + */ type Props = { /** @@ -22,12 +24,13 @@ type Props = { }; /** - * The exported React {@code Component}. We need a reference to the wrapped - * component in order to be able to hide it using the dialog hiding logic. + * The exported React {@code Component}. We need it to execute + * {@link hideDialog}. + * + * XXX It does not break our coding style rule to not utilize globals for state, + * because it is merely another name for {@code export}'s {@code default}. */ - -// eslint-disable-next-line prefer-const -let OverflowMenu_; +let OverflowMenu_; // eslint-disable-line prefer-const /** * Implements a React {@code Component} with some extra actions in addition to @@ -42,6 +45,7 @@ class OverflowMenu extends Component { constructor(props: Props) { super(props); + // Bind event handlers so they are only bound once per instance. this._onCancel = this._onCancel.bind(this); } @@ -76,7 +80,7 @@ class OverflowMenu extends Component { _onCancel: () => void; /** - * Hides the dialog. + * Hides this {@code OverflowMenu}. * * @private * @returns {void} diff --git a/react/features/toolbox/components/native/OverflowMenuButton.js b/react/features/toolbox/components/native/OverflowMenuButton.js index 985ec2abb..e398fc3a4 100644 --- a/react/features/toolbox/components/native/OverflowMenuButton.js +++ b/react/features/toolbox/components/native/OverflowMenuButton.js @@ -9,13 +9,16 @@ import type { AbstractButtonProps } from '../../../base/toolbox'; import OverflowMenu from './OverflowMenu'; +/** + * The type of the React {@code Component} props of {@link OverflowMenuButton}. + */ type Props = AbstractButtonProps & { /** * The redux {@code dispatch} function. */ dispatch: Function -} +}; /** * An implementation of a button for showing the {@code OverflowMenu}. @@ -26,9 +29,9 @@ class OverflowMenuButton extends AbstractButton { label = 'toolbar.moreActions'; /** - * Handles clicking / pressing the button. + * Handles clicking / pressing this {@code OverflowMenuButton}. * - * @private + * @protected * @returns {void} */ _handleClick() { diff --git a/react/features/toolbox/components/native/Toolbox.js b/react/features/toolbox/components/native/Toolbox.js index ed60956aa..8fe6876bf 100644 --- a/react/features/toolbox/components/native/Toolbox.js +++ b/react/features/toolbox/components/native/Toolbox.js @@ -13,24 +13,29 @@ import { InviteButton } from '../../../invite'; import AudioMuteButton from '../AudioMuteButton'; import HangupButton from '../HangupButton'; -import VideoMuteButton from '../VideoMuteButton'; - import OverflowMenuButton from './OverflowMenuButton'; import styles, { hangupButtonStyles, toolbarButtonStyles, toolbarToggledButtonStyles } from './styles'; +import VideoMuteButton from '../VideoMuteButton'; /** - * Number of buttons in the toolbar. + * The number of buttons to render in {@link Toolbox}. + * + * @private + * @type number */ -const NUM_TOOLBAR_BUTTONS = 4; +const _BUTTON_COUNT = 4; /** * Factor relating the hangup button and other toolbar buttons. + * + * @private + * @type number */ -const TOOLBAR_BUTTON_SIZE_FACTOR = 0.8; +const _BUTTON_SIZE_FACTOR = 0.8; /** * The type of {@link Toolbox}'s React {@code Component} props. @@ -75,48 +80,10 @@ class Toolbox extends Component { constructor(props: Props) { super(props); + // Bind event handlers so they are only bound once per instance. this._onLayout = this._onLayout.bind(this); } - _onLayout: (Object) => void; - - /** - * Handles the "on layout" View's event and stores the width as state. - * - * @param {Object} event - The "on layout" event object/structure passed - * by react-native. - * @private - * @returns {void} - */ - _onLayout({ nativeEvent: { layout: { width } } }) { - this.setState({ width }); - } - - /** - * Calculates how large our toolbar buttons can be, given the available - * width. In the future we might want to have a size threshold, and once - * it's passed a completely different style could be used, akin to the web. - * - * @private - * @returns {number} - */ - _calculateToolbarButtonSize() { - const width = this.state.width; - const hangupButtonSize = styles.hangupButton.width; - - let buttonSize - = (width - hangupButtonSize - - (NUM_TOOLBAR_BUTTONS * styles.toolbarButton.margin * 2)) - / NUM_TOOLBAR_BUTTONS; - - // Make sure it's an even number. - buttonSize = 2 * Math.round(buttonSize / 2); - - // The button should be at most 80% of the hangup button's size. - return Math.min( - buttonSize, hangupButtonSize * TOOLBAR_BUTTON_SIZE_FACTOR); - } - /** * Implements React's {@link Component#render()}. * @@ -129,31 +96,35 @@ class Toolbox extends Component { ? styles.toolboxNarrow : styles.toolboxWide; const { _visible } = this.props; - const buttonStyles = { - ...toolbarButtonStyles - }; - const toggledButtonStyles = { - ...toolbarToggledButtonStyles - }; + let buttonStyles = toolbarButtonStyles; + let toggledButtonStyles = toolbarToggledButtonStyles; - if (_visible && this.state.width) { - const buttonSize = this._calculateToolbarButtonSize(); - const extraStyle = { - borderRadius: buttonSize / 2, - height: buttonSize, - width: buttonSize - }; + if (_visible) { + const buttonSize = this._calculateButtonSize(); - buttonStyles.style = [ buttonStyles.style, extraStyle ]; - toggledButtonStyles.style - = [ toggledButtonStyles.style, extraStyle ]; + if (buttonSize > 0) { + const extraButtonStyle = { + borderRadius: buttonSize / 2, + height: buttonSize, + width: buttonSize + }; + + buttonStyles = { + ...buttonStyles, + style: [ buttonStyles.style, extraButtonStyle ] + }; + toggledButtonStyles = { + ...toggledButtonStyles, + style: [ toggledButtonStyles.style, extraButtonStyle ] + }; + } } return ( + visible = { _visible }> @@ -172,6 +143,47 @@ class Toolbox extends Component { ); } + + /** + * Calculates how large our toolbar buttons can be, given the available + * width. In the future we might want to have a size threshold, and once + * it's passed a completely different style could be used, akin to the web. + * + * @private + * @returns {number} + */ + _calculateButtonSize() { + const { width } = this.state; + const hangupButtonSize = styles.hangupButton.width; + + let buttonSize + = (width + - hangupButtonSize + - (_BUTTON_COUNT * styles.toolbarButton.margin * 2)) + / _BUTTON_COUNT; + + // Make sure it's an even number. + buttonSize = 2 * Math.round(buttonSize / 2); + + // The button should be at most 80% of the hangup button's size. + return Math.min( + buttonSize, + hangupButtonSize * _BUTTON_SIZE_FACTOR); + } + + _onLayout: (Object) => void; + + /** + * Handles the "on layout" View's event and stores the width as state. + * + * @param {Object} event - The "on layout" event object/structure passed + * by react-native. + * @private + * @returns {void} + */ + _onLayout({ nativeEvent: { layout: { width } } }) { + this.setState({ width }); + } } /** @@ -182,7 +194,6 @@ class Toolbox extends Component { * {@code Toolbox} props. * @private * @returns {{ - * _enabled: boolean, * _visible: boolean * }} */ diff --git a/react/features/toolbox/components/native/styles.js b/react/features/toolbox/components/native/styles.js index c52f95b23..5d1e0eaee 100644 --- a/react/features/toolbox/components/native/styles.js +++ b/react/features/toolbox/components/native/styles.js @@ -1,5 +1,9 @@ +// @flow + import { BoxModel, ColorPalette, createStyleSheet } from '../../../base/styles'; +// Toolbox, toolbar: + /** * The style of toolbar buttons. */ @@ -141,6 +145,8 @@ export const toolbarToggledButtonStyles = { style: styles.whiteToolbarButton }; +// Overflow menu: + /** * Styles for the {@code OverflowMenu} items. *