Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

AlwaysOnTop.js 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import React, { Component } from 'react';
  2. import StatelessToolbar from '../toolbox/components/StatelessToolbar';
  3. import StatelessToolbarButton
  4. from '../toolbox/components/StatelessToolbarButton';
  5. const { api } = window.alwaysOnTop;
  6. /**
  7. * The timeout in ms for hidding the toolbar.
  8. */
  9. const TOOLBAR_TIMEOUT = 4000;
  10. /**
  11. * Map with toolbar button descriptors.
  12. */
  13. const toolbarButtons = {
  14. /**
  15. * The descriptor of the camera toolbar button.
  16. */
  17. camera: {
  18. classNames: [ 'button', 'icon-camera' ],
  19. enabled: true,
  20. id: 'toolbar_button_camera',
  21. onClick() {
  22. api.executeCommand('toggleVideo');
  23. }
  24. },
  25. /**
  26. * The descriptor of the toolbar button which hangs up the call/conference.
  27. */
  28. hangup: {
  29. classNames: [ 'button', 'icon-hangup', 'button_hangup' ],
  30. enabled: true,
  31. id: 'toolbar_button_hangup',
  32. onClick() {
  33. api.executeCommand('hangup');
  34. window.close();
  35. }
  36. },
  37. /**
  38. * The descriptor of the microphone toolbar button.
  39. */
  40. microphone: {
  41. classNames: [ 'button', 'icon-microphone' ],
  42. enabled: true,
  43. id: 'toolbar_button_mute',
  44. onClick() {
  45. api.executeCommand('toggleAudio');
  46. }
  47. }
  48. };
  49. /**
  50. * Represents the always on top page.
  51. *
  52. * @class AlwaysOnTop
  53. * @extends Component
  54. */
  55. export default class AlwaysOnTop extends Component<*> {
  56. /**
  57. * Initializes new AlwaysOnTop instance.
  58. *
  59. * @param {Object} props - The read-only properties with which the new
  60. * instance is to be initialized.
  61. */
  62. constructor(props) {
  63. super(props);
  64. this.state = {
  65. visible: true,
  66. audioMuted: false,
  67. videoMuted: false,
  68. audioAvailable: false,
  69. videoAvailable: false
  70. };
  71. this._hovered = false;
  72. this._audioAvailabilityListener
  73. = this._audioAvailabilityListener.bind(this);
  74. this._audioMutedListener = this._audioMutedListener.bind(this);
  75. this._mouseMove = this._mouseMove.bind(this);
  76. this._onMouseOver = this._onMouseOver.bind(this);
  77. this._onMouseOut = this._onMouseOut.bind(this);
  78. this._videoAvailabilityListener
  79. = this._videoAvailabilityListener.bind(this);
  80. this._videoMutedListener = this._videoMutedListener.bind(this);
  81. }
  82. /**
  83. * Handles audio available api events.
  84. *
  85. * @param {{ available: boolean }} status - The new available status.
  86. * @returns {void}
  87. */
  88. _audioAvailabilityListener({ available }) {
  89. this.setState({ audioAvailable: available });
  90. }
  91. /**
  92. * Handles audio muted api events.
  93. *
  94. * @param {{ muted: boolean }} status - The new muted status.
  95. * @returns {void}
  96. */
  97. _audioMutedListener({ muted }) {
  98. this.setState({ audioMuted: muted });
  99. }
  100. /**
  101. * Hides the toolbar after a timeout.
  102. *
  103. * @returns {void}
  104. */
  105. _hideToolbarAfterTimeout() {
  106. setTimeout(() => {
  107. if (this._hovered) {
  108. this._hideToolbarAfterTimeout();
  109. return;
  110. }
  111. this.setState({ visible: false });
  112. }, TOOLBAR_TIMEOUT);
  113. }
  114. /**
  115. * Handles mouse move events.
  116. *
  117. * @returns {void}
  118. */
  119. _mouseMove() {
  120. if (!this.state.visible) {
  121. this.setState({ visible: true });
  122. }
  123. }
  124. /**
  125. * Toolbar mouse over handler.
  126. *
  127. * @returns {void}
  128. */
  129. _onMouseOver() {
  130. this._hovered = true;
  131. }
  132. /**
  133. * Toolbar mouse out handler.
  134. *
  135. * @returns {void}
  136. */
  137. _onMouseOut() {
  138. this._hovered = false;
  139. }
  140. /**
  141. * Handles audio available api events.
  142. *
  143. * @param {{ available: boolean }} status - The new available status.
  144. * @returns {void}
  145. */
  146. _videoAvailabilityListener({ available }) {
  147. this.setState({ videoAvailable: available });
  148. }
  149. /**
  150. * Handles video muted api events.
  151. *
  152. * @param {{ muted: boolean }} status - The new muted status.
  153. * @returns {void}
  154. */
  155. _videoMutedListener({ muted }) {
  156. this.setState({ videoMuted: muted });
  157. }
  158. /**
  159. * Sets mouse move listener and initial toolbar timeout.
  160. *
  161. * @inheritdoc
  162. * @returns {void}
  163. */
  164. componentDidMount() {
  165. api.on('audioMuteStatusChanged', this._audioMutedListener);
  166. api.on('videoMuteStatusChanged', this._videoMutedListener);
  167. api.on('audioAvailabilityChanged', this._audioAvailabilityListener);
  168. api.on('videoAvailabilityChanged', this._videoAvailabilityListener);
  169. Promise.all([
  170. api.isAudioMuted(),
  171. api.isVideoMuted(),
  172. api.isAudioAvailable(),
  173. api.isVideoAvailable()
  174. ])
  175. .then(([
  176. audioMuted = false,
  177. videoMuted = false,
  178. audioAvailable = false,
  179. videoAvailable = false
  180. ]) =>
  181. this.setState({
  182. audioMuted,
  183. videoMuted,
  184. audioAvailable,
  185. videoAvailable
  186. })
  187. )
  188. .catch(console.error);
  189. window.addEventListener('mousemove', this._mouseMove);
  190. this._hideToolbarAfterTimeout();
  191. }
  192. /**
  193. * Removes all listeners.
  194. *
  195. * @inheritdoc
  196. * @returns {void}
  197. */
  198. componentWillUnmount() {
  199. api.removeListener('audioMuteStatusChanged',
  200. this._audioMutedListener);
  201. api.removeListener('videoMuteStatusChanged',
  202. this._videoMutedListener);
  203. api.removeListener('audioAvailabilityChanged',
  204. this._audioAvailabilityListener);
  205. api.removeListener('videoAvailabilityChanged',
  206. this._videoAvailabilityListener);
  207. window.removeEventListener('mousemove', this._mouseMove);
  208. }
  209. /**
  210. * Sets a timeout to hide the toolbar when the toolbar is shown.
  211. *
  212. * @inheritdoc
  213. * @returns {void}
  214. */
  215. componentWillUpdate(nextProps, nextState) {
  216. if (!this.state.visible && nextState.visible) {
  217. this._hideToolbarAfterTimeout();
  218. }
  219. }
  220. /**
  221. * Implements React's {@link Component#render()}.
  222. *
  223. * @inheritdoc
  224. * @returns {ReactElement}
  225. */
  226. render() {
  227. const className
  228. = `toolbar_primary always-on-top ${
  229. this.state.visible ? 'fadeIn' : 'fadeOut'}`;
  230. return (
  231. <StatelessToolbar
  232. className = { className }
  233. onMouseOut = { this._onMouseOut }
  234. onMouseOver = { this._onMouseOver }>
  235. {
  236. Object.entries(toolbarButtons).map(([ key, button ]) => {
  237. const { onClick } = button;
  238. let enabled = false, toggled = false;
  239. switch (key) {
  240. case 'microphone':
  241. enabled = this.state.audioAvailable;
  242. toggled = enabled ? this.state.audioMuted : true;
  243. break;
  244. case 'camera':
  245. enabled = this.state.videoAvailable;
  246. toggled = enabled ? this.state.videoMuted : true;
  247. break;
  248. default: // hangup button
  249. toggled = false;
  250. enabled = true;
  251. }
  252. const updatedButton = {
  253. ...button,
  254. enabled,
  255. toggled
  256. };
  257. return (
  258. <StatelessToolbarButton
  259. button = { updatedButton }
  260. key = { key }
  261. onClick = { onClick } />
  262. );
  263. })
  264. }
  265. </StatelessToolbar>
  266. );
  267. }
  268. }