Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ReactionsMenu.js 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // @flow
  2. /* eslint-disable react/jsx-no-bind */
  3. import { withStyles } from '@material-ui/styles';
  4. import clsx from 'clsx';
  5. import React, { Component } from 'react';
  6. import { bindActionCreators } from 'redux';
  7. import {
  8. createReactionMenuEvent,
  9. createToolbarEvent,
  10. sendAnalytics
  11. } from '../../../analytics';
  12. import { isMobileBrowser } from '../../../base/environment/utils';
  13. import { translate } from '../../../base/i18n';
  14. import { getLocalParticipant, hasRaisedHand, raiseHand } from '../../../base/participants';
  15. import { connect } from '../../../base/redux';
  16. import { GifsMenu, GifsMenuButton } from '../../../gifs/components';
  17. import { isGifEnabled, isGifsMenuOpen } from '../../../gifs/functions';
  18. import { dockToolbox } from '../../../toolbox/actions.web';
  19. import { addReactionToBuffer } from '../../actions.any';
  20. import { toggleReactionsMenuVisibility } from '../../actions.web';
  21. import { REACTIONS, REACTIONS_MENU_HEIGHT } from '../../constants';
  22. import ReactionButton from './ReactionButton';
  23. type Props = {
  24. /**
  25. * Docks the toolbox.
  26. */
  27. _dockToolbox: Function,
  28. /**
  29. * Whether or not the GIF feature is enabled.
  30. */
  31. _isGifEnabled: boolean,
  32. /**
  33. * Whether or not the GIF menu is visible.
  34. */
  35. _isGifMenuVisible: boolean,
  36. /**
  37. * Whether or not it's a mobile browser.
  38. */
  39. _isMobile: boolean,
  40. /**
  41. * The ID of the local participant.
  42. */
  43. _localParticipantID: String,
  44. /**
  45. * Whether or not the local participant's hand is raised.
  46. */
  47. _raisedHand: boolean,
  48. /**
  49. * An object containing the CSS classes.
  50. */
  51. classes: Object,
  52. /**
  53. * The Redux Dispatch function.
  54. */
  55. dispatch: Function,
  56. /**
  57. * Whether or not it's displayed in the overflow menu.
  58. */
  59. overflowMenu: boolean,
  60. /**
  61. * Used for translation.
  62. */
  63. t: Function
  64. };
  65. declare var APP: Object;
  66. const styles = theme => {
  67. return {
  68. overflow: {
  69. width: 'auto',
  70. paddingBottom: 'max(env(safe-area-inset-bottom, 0), 16px)',
  71. backgroundColor: theme.palette.ui01,
  72. boxShadow: 'none',
  73. borderRadius: 0,
  74. position: 'relative',
  75. boxSizing: 'border-box',
  76. height: `${REACTIONS_MENU_HEIGHT}px`
  77. }
  78. };
  79. };
  80. /**
  81. * Implements the reactions menu.
  82. *
  83. * @returns {ReactElement}
  84. */
  85. class ReactionsMenu extends Component<Props> {
  86. /**
  87. * Initializes a new {@code ReactionsMenu} instance.
  88. *
  89. * @param {Props} props - The read-only React {@code Component} props with
  90. * which the new instance is to be initialized.
  91. */
  92. constructor(props: Props) {
  93. super(props);
  94. this._onToolbarToggleRaiseHand = this._onToolbarToggleRaiseHand.bind(this);
  95. this._getReactionButtons = this._getReactionButtons.bind(this);
  96. }
  97. _onToolbarToggleRaiseHand: () => void;
  98. _getReactionButtons: () => Array<React$Element<*>>;
  99. /**
  100. * Implements React Component's componentDidMount.
  101. *
  102. * @inheritdoc
  103. */
  104. componentDidMount() {
  105. this.props._dockToolbox(true);
  106. }
  107. /**
  108. * Implements React Component's componentWillUnmount.
  109. *
  110. * @inheritdoc
  111. */
  112. componentWillUnmount() {
  113. this.props._dockToolbox(false);
  114. }
  115. /**
  116. * Creates an analytics toolbar event and dispatches an action for toggling
  117. * raise hand.
  118. *
  119. * @returns {void}
  120. */
  121. _onToolbarToggleRaiseHand() {
  122. const { dispatch, _raisedHand } = this.props;
  123. sendAnalytics(createToolbarEvent(
  124. 'raise.hand',
  125. { enable: !_raisedHand }));
  126. this._doToggleRaiseHand();
  127. dispatch(toggleReactionsMenuVisibility());
  128. }
  129. /**
  130. * Dispatches an action to toggle the local participant's raised hand state.
  131. *
  132. * @private
  133. * @returns {void}
  134. */
  135. _doToggleRaiseHand() {
  136. const { _raisedHand } = this.props;
  137. this.props.dispatch(raiseHand(!_raisedHand));
  138. }
  139. /**
  140. * Returns the emoji reaction buttons.
  141. *
  142. * @returns {Array}
  143. */
  144. _getReactionButtons() {
  145. const { t, dispatch } = this.props;
  146. let modifierKey = 'Alt';
  147. if (window.navigator?.platform) {
  148. if (window.navigator.platform.indexOf('Mac') !== -1) {
  149. modifierKey = '⌥';
  150. }
  151. }
  152. return Object.keys(REACTIONS).map(key => {
  153. /**
  154. * Sends reaction message.
  155. *
  156. * @returns {void}
  157. */
  158. function doSendReaction() {
  159. dispatch(addReactionToBuffer(key));
  160. sendAnalytics(createReactionMenuEvent(key));
  161. }
  162. return (<ReactionButton
  163. accessibilityLabel = { t(`toolbar.accessibilityLabel.${key}`) }
  164. icon = { REACTIONS[key].emoji }
  165. key = { key }
  166. onClick = { doSendReaction }
  167. toggled = { false }
  168. tooltip = { `${t(`toolbar.${key}`)} (${modifierKey} + ${REACTIONS[key].shortcutChar})` } />);
  169. });
  170. }
  171. /**
  172. * Implements React's {@link Component#render}.
  173. *
  174. * @inheritdoc
  175. */
  176. render() {
  177. const { _raisedHand, t, overflowMenu, _isMobile, classes, _isGifMenuVisible, _isGifEnabled } = this.props;
  178. return (
  179. <div
  180. className = { clsx('reactions-menu', _isGifEnabled && 'with-gif',
  181. overflowMenu && `overflow ${classes.overflow}`) }>
  182. {_isGifEnabled && _isGifMenuVisible && <GifsMenu />}
  183. <div className = 'reactions-row'>
  184. { this._getReactionButtons() }
  185. {_isGifEnabled && <GifsMenuButton />}
  186. </div>
  187. {_isMobile && (
  188. <div className = 'raise-hand-row'>
  189. <ReactionButton
  190. accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
  191. icon = '✋'
  192. key = 'raisehand'
  193. label = {
  194. `${t(`toolbar.${_raisedHand ? 'lowerYourHand' : 'raiseYourHand'}`)}
  195. ${overflowMenu ? '' : ' (R)'}`
  196. }
  197. onClick = { this._onToolbarToggleRaiseHand }
  198. toggled = { true } />
  199. </div>
  200. )}
  201. </div>
  202. );
  203. }
  204. }
  205. /**
  206. * Function that maps parts of Redux state tree into component props.
  207. *
  208. * @param {Object} state - Redux state.
  209. * @returns {Object}
  210. */
  211. function mapStateToProps(state) {
  212. const localParticipant = getLocalParticipant(state);
  213. return {
  214. _localParticipantID: localParticipant.id,
  215. _isMobile: isMobileBrowser(),
  216. _isGifEnabled: isGifEnabled(state),
  217. _isGifMenuVisible: isGifsMenuOpen(state),
  218. _raisedHand: hasRaisedHand(localParticipant)
  219. };
  220. }
  221. /**
  222. * Function that maps parts of Redux actions into component props.
  223. *
  224. * @param {Object} dispatch - Redux dispatch.
  225. * @returns {Object}
  226. */
  227. function mapDispatchToProps(dispatch) {
  228. return {
  229. dispatch,
  230. ...bindActionCreators(
  231. {
  232. _dockToolbox: dockToolbox
  233. }, dispatch)
  234. };
  235. }
  236. export default translate(connect(
  237. mapStateToProps,
  238. mapDispatchToProps
  239. )(withStyles(styles)(ReactionsMenu)));