diff --git a/react/features/toolbox/components/native/OverflowMenu.js b/react/features/toolbox/components/native/OverflowMenu.js index 08f042d75..e4a112b46 100644 --- a/react/features/toolbox/components/native/OverflowMenu.js +++ b/react/features/toolbox/components/native/OverflowMenu.js @@ -18,6 +18,7 @@ import { ClosedCaptionButton } from '../../../subtitles'; import { TileViewButton } from '../../../video-layout'; import AudioOnlyButton from './AudioOnlyButton'; +import RaiseHandButton from './RaiseHandButton'; import ToggleCameraButton from './ToggleCameraButton'; declare var __DEV__; @@ -95,6 +96,7 @@ class OverflowMenu extends Component { + ); } diff --git a/react/features/toolbox/components/native/RaiseHandButton.js b/react/features/toolbox/components/native/RaiseHandButton.js new file mode 100644 index 000000000..dc2b5049d --- /dev/null +++ b/react/features/toolbox/components/native/RaiseHandButton.js @@ -0,0 +1,113 @@ +// @flow + +import { type Dispatch } from 'redux'; + +import { + createToolbarEvent, + sendAnalytics +} from '../../../analytics'; +import { translate } from '../../../base/i18n'; +import { + getLocalParticipant, + participantUpdated +} from '../../../base/participants'; +import { connect } from '../../../base/redux'; +import { AbstractButton } from '../../../base/toolbox'; +import type { AbstractButtonProps } from '../../../base/toolbox'; + +/** + * The type of the React {@code Component} props of {@link RaiseHandButton}. + */ +type Props = AbstractButtonProps & { + + /** + * The local participant. + */ + _localParticipant: Object, + + /** + * Whether the participant raused their hand or not. + */ + _raisedHand: boolean, + + /** + * The redux {@code dispatch} function. + */ + dispatch: Dispatch +}; + +/** + * An implementation of a button to raise or lower hand. + */ +class RaiseHandButton extends AbstractButton { + accessibilityLabel = 'toolbar.accessibilityLabel.raiseHand'; + iconName = 'raised-hand'; + label = 'toolbar.raiseYourHand'; + toggledIconName = 'raised-hand'; + toggledLabel = 'toolbar.lowerYourHand'; + + /** + * Handles clicking / pressing the button. + * + * @override + * @protected + * @returns {void} + */ + _handleClick() { + this._toggleRaisedHand(); + } + + /** + * Indicates whether this button is in toggled state or not. + * + * @override + * @protected + * @returns {boolean} + */ + _isToggled() { + return this.props._raisedHand; + } + + /** + * Toggles the rased hand status of the local participant. + * + * @returns {void} + */ + _toggleRaisedHand() { + const enable = !this.props._raisedHand; + + sendAnalytics(createToolbarEvent('raise.hand', { enable })); + + this.props.dispatch(participantUpdated({ + // XXX Only the local participant is allowed to update without + // stating the JitsiConference instance (i.e. participant property + // `conference` for a remote participant) because the local + // participant is uniquely identified by the very fact that there is + // only one local participant. + + id: this.props._localParticipant.id, + local: true, + raisedHand: enable + })); + } +} + +/** + * Maps part of the Redux state to the props of this component. + * + * @param {Object} state - The Redux state. + * @private + * @returns {{ + * _raisedHand: boolean + * }} + */ +function _mapStateToProps(state): Object { + const _localParticipant = getLocalParticipant(state); + + return { + _localParticipant, + _raisedHand: _localParticipant.raisedHand + }; +} + +export default translate(connect(_mapStateToProps)(RaiseHandButton));