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.7KB

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