You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Toolbox.js 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { View } from 'react-native';
  4. import { connect } from 'react-redux';
  5. import { Container } from '../../../base/react';
  6. import {
  7. isNarrowAspectRatio,
  8. makeAspectRatioAware
  9. } from '../../../base/responsive-ui';
  10. import { InviteButton } from '../../../invite';
  11. import AudioMuteButton from '../AudioMuteButton';
  12. import HangupButton from '../HangupButton';
  13. import VideoMuteButton from '../VideoMuteButton';
  14. import OverflowMenuButton from './OverflowMenuButton';
  15. import styles, {
  16. hangupButtonStyles,
  17. toolbarButtonStyles,
  18. toolbarToggledButtonStyles
  19. } from './styles';
  20. /**
  21. * Number of buttons in the toolbar.
  22. */
  23. const NUM_TOOLBAR_BUTTONS = 4;
  24. /**
  25. * Factor relating the hangup button and other toolbar buttons.
  26. */
  27. const TOOLBAR_BUTTON_SIZE_FACTOR = 0.8;
  28. /**
  29. * The type of {@link Toolbox}'s React {@code Component} props.
  30. */
  31. type Props = {
  32. /**
  33. * The indicator which determines whether the toolbox is visible.
  34. */
  35. _visible: boolean,
  36. /**
  37. * The redux {@code dispatch} function.
  38. */
  39. dispatch: Function
  40. };
  41. /**
  42. * The type of {@link Toolbox}'s React {@code Component} state.
  43. */
  44. type State = {
  45. /**
  46. * The detected width for this component.
  47. */
  48. width: number
  49. };
  50. /**
  51. * Implements the conference toolbox on React Native.
  52. */
  53. class Toolbox extends Component<Props, State> {
  54. state = {
  55. width: 0
  56. };
  57. /**
  58. * Initializes a new {@code Toolbox} instance.
  59. *
  60. * @inheritdoc
  61. */
  62. constructor(props: Props) {
  63. super(props);
  64. this._onLayout = this._onLayout.bind(this);
  65. }
  66. _onLayout: (Object) => void;
  67. /**
  68. * Handles the "on layout" View's event and stores the width as state.
  69. *
  70. * @param {Object} event - The "on layout" event object/structure passed
  71. * by react-native.
  72. * @private
  73. * @returns {void}
  74. */
  75. _onLayout({ nativeEvent: { layout: { width } } }) {
  76. this.setState({ width });
  77. }
  78. /**
  79. * Calculates how large our toolbar buttons can be, given the available
  80. * width. In the future we might want to have a size threshold, and once
  81. * it's passed a completely different style could be used, akin to the web.
  82. *
  83. * @private
  84. * @returns {number}
  85. */
  86. _calculateToolbarButtonSize() {
  87. const width = this.state.width;
  88. const hangupButtonSize = styles.hangupButton.width;
  89. let buttonSize
  90. = (width - hangupButtonSize
  91. - (NUM_TOOLBAR_BUTTONS * styles.toolbarButton.margin * 2))
  92. / NUM_TOOLBAR_BUTTONS;
  93. // Make sure it's an even number.
  94. buttonSize = 2 * Math.round(buttonSize / 2);
  95. // The button should be at most 80% of the hangup button's size.
  96. return Math.min(
  97. buttonSize, hangupButtonSize * TOOLBAR_BUTTON_SIZE_FACTOR);
  98. }
  99. /**
  100. * Implements React's {@link Component#render()}.
  101. *
  102. * @inheritdoc
  103. * @returns {ReactElement}
  104. */
  105. render() {
  106. const toolboxStyle
  107. = isNarrowAspectRatio(this)
  108. ? styles.toolboxNarrow
  109. : styles.toolboxWide;
  110. const { _visible } = this.props;
  111. const buttonStyles = {
  112. ...toolbarButtonStyles
  113. };
  114. const toggledButtonStyles = {
  115. ...toolbarToggledButtonStyles
  116. };
  117. if (_visible && this.state.width) {
  118. const buttonSize = this._calculateToolbarButtonSize();
  119. const extraStyle = {
  120. borderRadius: buttonSize / 2,
  121. height: buttonSize,
  122. width: buttonSize
  123. };
  124. buttonStyles.style = [ buttonStyles.style, extraStyle ];
  125. toggledButtonStyles.style
  126. = [ toggledButtonStyles.style, extraStyle ];
  127. }
  128. return (
  129. <Container
  130. onLayout = { this._onLayout }
  131. style = { toolboxStyle }
  132. visible = { _visible } >
  133. <View
  134. pointerEvents = 'box-none'
  135. style = { styles.toolbar }>
  136. <InviteButton styles = { buttonStyles } />
  137. <AudioMuteButton
  138. styles = { buttonStyles }
  139. toggledStyles = { toggledButtonStyles } />
  140. <HangupButton styles = { hangupButtonStyles } />
  141. <VideoMuteButton
  142. styles = { buttonStyles }
  143. toggledStyles = { toggledButtonStyles } />
  144. <OverflowMenuButton
  145. styles = { buttonStyles }
  146. toggledStyles = { toggledButtonStyles } />
  147. </View>
  148. </Container>
  149. );
  150. }
  151. }
  152. /**
  153. * Maps parts of the redux state to {@link Toolbox} (React {@code Component})
  154. * props.
  155. *
  156. * @param {Object} state - The redux state of which parts are to be mapped to
  157. * {@code Toolbox} props.
  158. * @private
  159. * @returns {{
  160. * _enabled: boolean,
  161. * _visible: boolean
  162. * }}
  163. */
  164. function _mapStateToProps(state: Object): Object {
  165. const { enabled, visible } = state['features/toolbox'];
  166. return {
  167. _visible: enabled && visible
  168. };
  169. }
  170. export default connect(_mapStateToProps)(makeAspectRatioAware(Toolbox));