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.

VolumeSlider.tsx 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* eslint-disable lines-around-comment */
  2. import { Theme } from '@mui/material';
  3. import { withStyles } from '@mui/styles';
  4. import clsx from 'clsx';
  5. import React, { Component } from 'react';
  6. import { WithTranslation } from 'react-i18next';
  7. import { translate } from '../../../base/i18n/functions';
  8. import Icon from '../../../base/icons/components/Icon';
  9. import { IconVolume } from '../../../base/icons/svg';
  10. import { VOLUME_SLIDER_SCALE } from '../../constants';
  11. /**
  12. * The type of the React {@code Component} props of {@link VolumeSlider}.
  13. */
  14. interface Props extends WithTranslation {
  15. /**
  16. * An object containing the CSS classes.
  17. */
  18. classes: any;
  19. /**
  20. * The value of the audio slider should display at when the component first
  21. * mounts. Changes will be stored in state. The value should be a number
  22. * between 0 and 1.
  23. */
  24. initialValue: number;
  25. /**
  26. * The callback to invoke when the audio slider value changes.
  27. */
  28. onChange: Function;
  29. }
  30. /**
  31. * The type of the React {@code Component} state of {@link VolumeSlider}.
  32. */
  33. type State = {
  34. /**
  35. * The volume of the participant's audio element. The value will
  36. * be represented by a slider.
  37. */
  38. volumeLevel: number;
  39. };
  40. const styles = (theme: Theme) => {
  41. return {
  42. container: {
  43. minHeight: '40px',
  44. minWidth: '180px',
  45. width: '100%',
  46. boxSizing: 'border-box' as const,
  47. cursor: 'pointer',
  48. display: 'flex',
  49. alignItems: 'center',
  50. padding: '0 5px',
  51. '&:hover': {
  52. backgroundColor: theme.palette.ui04
  53. }
  54. },
  55. icon: {
  56. minWidth: '20px',
  57. padding: '5px',
  58. position: 'relative' as const
  59. },
  60. sliderContainer: {
  61. position: 'relative' as const,
  62. width: '100%',
  63. paddingRight: '5px'
  64. },
  65. slider: {
  66. position: 'absolute' as const,
  67. width: '100%',
  68. top: '50%',
  69. transform: 'translate(0, -50%)'
  70. }
  71. };
  72. };
  73. /**
  74. * Implements a React {@link Component} which displays an input slider for
  75. * adjusting the local volume of a remote participant.
  76. *
  77. * @augments Component
  78. */
  79. class VolumeSlider extends Component<Props, State> {
  80. /**
  81. * Initializes a new {@code VolumeSlider} instance.
  82. *
  83. * @param {Object} props - The read-only properties with which the new
  84. * instance is to be initialized.
  85. */
  86. constructor(props: Props) {
  87. super(props);
  88. this.state = {
  89. volumeLevel: (props.initialValue || 0) * VOLUME_SLIDER_SCALE
  90. };
  91. // Bind event handlers so they are only bound once for every instance.
  92. this._onVolumeChange = this._onVolumeChange.bind(this);
  93. }
  94. /**
  95. * Click handler.
  96. *
  97. * @param {MouseEvent} e - Click event.
  98. * @returns {void}
  99. */
  100. _onClick(e: React.MouseEvent) {
  101. e.stopPropagation();
  102. }
  103. /**
  104. * Implements React's {@link Component#render()}.
  105. *
  106. * @inheritdoc
  107. * @returns {ReactElement}
  108. */
  109. render() {
  110. const { classes } = this.props;
  111. return (
  112. <div
  113. aria-label = { this.props.t('volumeSlider') }
  114. className = { clsx('popupmenu__contents', classes.container) }
  115. onClick = { this._onClick }>
  116. <span className = { classes.icon }>
  117. <Icon
  118. size = { 22 }
  119. src = { IconVolume } />
  120. </span>
  121. <div className = { classes.sliderContainer }>
  122. <input
  123. aria-valuemax = { VOLUME_SLIDER_SCALE }
  124. aria-valuemin = { 0 }
  125. aria-valuenow = { this.state.volumeLevel }
  126. className = { clsx('popupmenu__volume-slider', classes.slider) }
  127. max = { VOLUME_SLIDER_SCALE }
  128. min = { 0 }
  129. onChange = { this._onVolumeChange }
  130. tabIndex = { 0 }
  131. type = 'range'
  132. value = { this.state.volumeLevel } />
  133. </div>
  134. </div>
  135. );
  136. }
  137. /**
  138. * Sets the internal state of the volume level for the volume slider.
  139. * Invokes the prop onVolumeChange to notify of volume changes.
  140. *
  141. * @param {Object} event - DOM Event for slider change.
  142. * @private
  143. * @returns {void}
  144. */
  145. _onVolumeChange(event: React.ChangeEvent<HTMLInputElement>) {
  146. const volumeLevel = Number(event.currentTarget.value);
  147. this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE);
  148. this.setState({ volumeLevel });
  149. }
  150. }
  151. export default translate(withStyles(styles)(VolumeSlider));