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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 { IconVolumeUp } 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. interface IState {
  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: '10px 16px',
  50. '&:hover': {
  51. backgroundColor: theme.palette.ui02
  52. }
  53. },
  54. icon: {
  55. minWidth: '20px',
  56. marginRight: '16px',
  57. position: 'relative' as const
  58. },
  59. sliderContainer: {
  60. position: 'relative' as const,
  61. width: '100%'
  62. },
  63. slider: {
  64. position: 'absolute' as const,
  65. width: '100%',
  66. top: '50%',
  67. transform: 'translate(0, -50%)'
  68. }
  69. };
  70. };
  71. /**
  72. * Implements a React {@link Component} which displays an input slider for
  73. * adjusting the local volume of a remote participant.
  74. *
  75. * @augments Component
  76. */
  77. class VolumeSlider extends Component<IProps, IState> {
  78. /**
  79. * Initializes a new {@code VolumeSlider} instance.
  80. *
  81. * @param {Object} props - The read-only properties with which the new
  82. * instance is to be initialized.
  83. */
  84. constructor(props: IProps) {
  85. super(props);
  86. this.state = {
  87. volumeLevel: (props.initialValue || 0) * VOLUME_SLIDER_SCALE
  88. };
  89. // Bind event handlers so they are only bound once for every instance.
  90. this._onVolumeChange = this._onVolumeChange.bind(this);
  91. }
  92. /**
  93. * Click handler.
  94. *
  95. * @param {MouseEvent} e - Click event.
  96. * @returns {void}
  97. */
  98. _onClick(e: React.MouseEvent) {
  99. e.stopPropagation();
  100. }
  101. /**
  102. * Implements React's {@link Component#render()}.
  103. *
  104. * @inheritdoc
  105. * @returns {ReactElement}
  106. */
  107. render() {
  108. const { classes } = this.props;
  109. return (
  110. <div
  111. aria-label = { this.props.t('volumeSlider') }
  112. className = { clsx('popupmenu__contents', classes.container) }
  113. onClick = { this._onClick }>
  114. <span className = { classes.icon }>
  115. <Icon
  116. size = { 22 }
  117. src = { IconVolumeUp } />
  118. </span>
  119. <div className = { classes.sliderContainer }>
  120. <input
  121. aria-valuemax = { VOLUME_SLIDER_SCALE }
  122. aria-valuemin = { 0 }
  123. aria-valuenow = { this.state.volumeLevel }
  124. className = { clsx('popupmenu__volume-slider', classes.slider) }
  125. max = { VOLUME_SLIDER_SCALE }
  126. min = { 0 }
  127. onChange = { this._onVolumeChange }
  128. tabIndex = { 0 }
  129. type = 'range'
  130. value = { this.state.volumeLevel } />
  131. </div>
  132. </div>
  133. );
  134. }
  135. /**
  136. * Sets the internal state of the volume level for the volume slider.
  137. * Invokes the prop onVolumeChange to notify of volume changes.
  138. *
  139. * @param {Object} event - DOM Event for slider change.
  140. * @private
  141. * @returns {void}
  142. */
  143. _onVolumeChange(event: React.ChangeEvent<HTMLInputElement>) {
  144. const volumeLevel = Number(event.currentTarget.value);
  145. this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE);
  146. this.setState({ volumeLevel });
  147. }
  148. }
  149. export default translate(withStyles(styles)(VolumeSlider));