Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

defaultToolbarButtons.web.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. // @flow
  2. import React from 'react';
  3. import { setFullScreen } from '../toolbox';
  4. import {
  5. ACTION_SHORTCUT_TRIGGERED as TRIGGERED,
  6. AUDIO_MUTE,
  7. VIDEO_MUTE,
  8. createShortcutEvent,
  9. createToolbarEvent,
  10. sendAnalytics
  11. } from '../analytics';
  12. import {
  13. getLocalParticipant,
  14. participantUpdated
  15. } from '../base/participants';
  16. import { ParticipantCounter } from '../contact-list';
  17. import { openDeviceSelectionDialog } from '../device-selection';
  18. import { InfoDialogButton } from '../invite';
  19. import UIEvents from '../../../service/UI/UIEvents';
  20. import { VideoQualityButton } from '../video-quality';
  21. import ProfileButton from './components/ProfileButton';
  22. declare var APP: Object;
  23. declare var interfaceConfig: Object;
  24. /**
  25. * The cache of {@link getDefaultButtons()}.
  26. */
  27. let defaultButtons: Object;
  28. /**
  29. * Returns a map of all button descriptors and according properties.
  30. *
  31. * @returns {Object} - The maps of default button descriptors.
  32. */
  33. export default function getDefaultButtons() {
  34. if (defaultButtons) {
  35. return defaultButtons;
  36. }
  37. defaultButtons = {
  38. /**
  39. * The descriptor of the camera toolbar button.
  40. */
  41. camera: {
  42. classNames: [ 'button', 'icon-camera' ],
  43. enabled: true,
  44. isDisplayed: () => true,
  45. id: 'toolbar_button_camera',
  46. onClick() {
  47. // TODO: Why is this different from the code which handles
  48. // a keyboard shortcut?
  49. const newVideoMutedState = !APP.conference.isLocalVideoMuted();
  50. // The 'enable' attribute in the event is set to true if the
  51. // button click triggered a mute action, and set to false if it
  52. // triggered an unmute action.
  53. sendAnalytics(createToolbarEvent(
  54. VIDEO_MUTE,
  55. {
  56. enable: newVideoMutedState
  57. }));
  58. APP.UI.emitEvent(UIEvents.VIDEO_MUTED, newVideoMutedState);
  59. },
  60. popups: [
  61. {
  62. dataAttr: 'audioOnly.featureToggleDisabled',
  63. dataInterpolate: { feature: 'video mute' },
  64. id: 'unmuteWhileAudioOnly'
  65. }
  66. ],
  67. shortcut: 'V',
  68. shortcutAttr: 'toggleVideoPopover',
  69. shortcutFunc() {
  70. if (APP.conference.isAudioOnly()) {
  71. APP.UI.emitEvent(UIEvents.VIDEO_UNMUTING_WHILE_AUDIO_ONLY);
  72. return;
  73. }
  74. // The 'enable' attribute in the event is set to true if the
  75. // shortcut triggered a mute action, and set to false if it
  76. // triggered an unmute action.
  77. sendAnalytics(createShortcutEvent(
  78. VIDEO_MUTE,
  79. TRIGGERED,
  80. { enable: !APP.conference.isLocalVideoMuted() }));
  81. APP.conference.toggleVideoMuted();
  82. },
  83. shortcutDescription: 'keyboardShortcuts.videoMute',
  84. tooltipKey: 'toolbar.videomute'
  85. },
  86. /**
  87. * The descriptor of the chat toolbar button.
  88. */
  89. chat: {
  90. classNames: [ 'button', 'icon-chat' ],
  91. enabled: true,
  92. html: <span className = 'badge-round'>
  93. <span id = 'unreadMessages' /></span>,
  94. id: 'toolbar_button_chat',
  95. onClick() {
  96. // The 'enable' attribute is set to true if the click resulted
  97. // in the chat panel being shown, and to false if it was hidden.
  98. sendAnalytics(createToolbarEvent(
  99. 'toggle.chat',
  100. {
  101. enable: !APP.UI.isChatVisible()
  102. }));
  103. APP.UI.emitEvent(UIEvents.TOGGLE_CHAT);
  104. },
  105. shortcut: 'C',
  106. shortcutAttr: 'toggleChatPopover',
  107. shortcutFunc() {
  108. // The 'enable' attribute is set to true if the shortcut
  109. // resulted in the chat panel being shown, and to false if it
  110. // was hidden.
  111. sendAnalytics(createShortcutEvent(
  112. 'toggle.chat',
  113. {
  114. enable: !APP.UI.isChatVisible()
  115. }));
  116. APP.UI.toggleChat();
  117. },
  118. shortcutDescription: 'keyboardShortcuts.toggleChat',
  119. sideContainerId: 'chat_container',
  120. tooltipKey: 'toolbar.chat'
  121. },
  122. /**
  123. * The descriptor of the contact list toolbar button.
  124. */
  125. contacts: {
  126. childComponent: ParticipantCounter,
  127. classNames: [ 'button', 'icon-contactList' ],
  128. enabled: true,
  129. id: 'toolbar_contact_list',
  130. onClick() {
  131. // TODO: Include an 'enable' attribute which specifies whether
  132. // the contacts panel was shown or hidden.
  133. sendAnalytics(createToolbarEvent('contacts'));
  134. APP.UI.emitEvent(UIEvents.TOGGLE_CONTACT_LIST);
  135. },
  136. sideContainerId: 'contacts_container',
  137. tooltipKey: 'bottomtoolbar.contactlist'
  138. },
  139. /**
  140. * The descriptor of the desktop sharing toolbar button.
  141. */
  142. desktop: {
  143. classNames: [ 'button', 'icon-share-desktop' ],
  144. enabled: true,
  145. id: 'toolbar_button_desktopsharing',
  146. onClick() {
  147. // TODO: Why is the button clicked handled differently that
  148. // a keyboard shortcut press (firing a TOGGLE_SCREENSHARING
  149. // event vs. directly calling toggleScreenSharing())?
  150. sendAnalytics(createToolbarEvent(
  151. 'screen.sharing',
  152. {
  153. enable: !APP.conference.isSharingScreen
  154. }));
  155. APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING);
  156. },
  157. popups: [
  158. {
  159. dataAttr: 'audioOnly.featureToggleDisabled',
  160. dataInterpolate: { feature: 'screen sharing' },
  161. id: 'screenshareWhileAudioOnly'
  162. }
  163. ],
  164. shortcut: 'D',
  165. shortcutAttr: 'toggleDesktopSharingPopover',
  166. shortcutFunc() {
  167. // The 'enable' attribute is set to true if pressing the
  168. // shortcut resulted in screen sharing being enabled, and false
  169. // if it resulted in screen sharing being disabled.
  170. sendAnalytics(createShortcutEvent(
  171. 'toggle.screen.sharing',
  172. TRIGGERED,
  173. { enable: !APP.conference.isSharingScreen }));
  174. // eslint-disable-next-line no-empty-function
  175. APP.conference.toggleScreenSharing().catch(() => {});
  176. },
  177. shortcutDescription: 'keyboardShortcuts.toggleScreensharing',
  178. tooltipKey: 'toolbar.sharescreen'
  179. },
  180. /**
  181. * The descriptor of the device selection toolbar button.
  182. */
  183. fodeviceselection: {
  184. classNames: [ 'button', 'icon-settings' ],
  185. enabled: true,
  186. isDisplayed() {
  187. return interfaceConfig.filmStripOnly;
  188. },
  189. id: 'toolbar_button_fodeviceselection',
  190. onClick(dispatch: Function) {
  191. sendAnalytics(
  192. createToolbarEvent('filmstrip.only.device.selection'));
  193. dispatch(openDeviceSelectionDialog());
  194. },
  195. sideContainerId: 'settings_container',
  196. tooltipKey: 'toolbar.Settings'
  197. },
  198. /**
  199. * The descriptor of the dialpad toolbar button.
  200. */
  201. dialpad: {
  202. classNames: [ 'button', 'icon-dialpad' ],
  203. enabled: true,
  204. // TODO: remove it after UI.updateDTMFSupport fix
  205. hidden: true,
  206. id: 'toolbar_button_dialpad',
  207. onClick() {
  208. sendAnalytics(createToolbarEvent('dialpad'));
  209. },
  210. tooltipKey: 'toolbar.dialpad'
  211. },
  212. /**
  213. * The descriptor of the etherpad toolbar button.
  214. */
  215. etherpad: {
  216. classNames: [ 'button', 'icon-share-doc' ],
  217. enabled: true,
  218. hidden: true,
  219. id: 'toolbar_button_etherpad',
  220. onClick() {
  221. // The 'enable' attribute is set to true if the click resulted
  222. // in the etherpad panel being shown, or false it it was hidden.
  223. sendAnalytics(createToolbarEvent(
  224. 'toggle.etherpad',
  225. {
  226. enable: !APP.UI.isEtherpadVisible()
  227. }));
  228. APP.UI.emitEvent(UIEvents.ETHERPAD_CLICKED);
  229. },
  230. tooltipKey: 'toolbar.etherpad'
  231. },
  232. /**
  233. * The descriptor of the toolbar button which toggles full-screen mode.
  234. */
  235. fullscreen: {
  236. classNames: [ 'button', 'icon-full-screen' ],
  237. enabled: true,
  238. id: 'toolbar_button_fullScreen',
  239. onClick() {
  240. const state = APP.store.getState();
  241. const isFullScreen = Boolean(
  242. state['features/toolbox'].fullScreen);
  243. // The 'enable' attribute is set to true if the action resulted
  244. // in fullscreen mode being enabled.
  245. sendAnalytics(createToolbarEvent(
  246. 'toggle.fullscreen',
  247. {
  248. enable: !isFullScreen
  249. }));
  250. APP.store.dispatch(setFullScreen(!isFullScreen));
  251. },
  252. shortcut: 'S',
  253. shortcutAttr: 'toggleFullscreenPopover',
  254. shortcutDescription: 'keyboardShortcuts.fullScreen',
  255. shortcutFunc() {
  256. const state = APP.store.getState();
  257. const isFullScreen = Boolean(
  258. state['features/toolbox'].fullScreen);
  259. // The 'enable' attribute is set to true if the action resulted
  260. // in fullscreen mode being enabled.
  261. sendAnalytics(createShortcutEvent(
  262. 'toggle.fullscreen',
  263. {
  264. enable: !isFullScreen
  265. }));
  266. APP.store.dispatch(setFullScreen(!isFullScreen));
  267. },
  268. tooltipKey: 'toolbar.fullscreen'
  269. },
  270. /**
  271. * The descriptor of the toolbar button which hangs up the
  272. * call/conference.
  273. */
  274. hangup: {
  275. classNames: [ 'button', 'icon-hangup', 'button_hangup' ],
  276. enabled: true,
  277. isDisplayed: () => true,
  278. id: 'toolbar_button_hangup',
  279. onClick() {
  280. sendAnalytics(createToolbarEvent('hangup'));
  281. APP.UI.emitEvent(UIEvents.HANGUP);
  282. },
  283. tooltipKey: 'toolbar.hangup'
  284. },
  285. /**
  286. * The descriptor of the toolbar button which opens a dialog for the
  287. * conference URL and inviting others.
  288. */
  289. info: {
  290. component: InfoDialogButton
  291. },
  292. /**
  293. * The descriptor of the microphone toolbar button.
  294. */
  295. microphone: {
  296. classNames: [ 'button', 'icon-microphone' ],
  297. enabled: true,
  298. isDisplayed: () => true,
  299. id: 'toolbar_button_mute',
  300. onClick() {
  301. const sharedVideoManager = APP.UI.getSharedVideoManager();
  302. // TODO: Clicking the mute button and pressing the mute shortcut
  303. // could be handled in a uniform manner. The code below checks
  304. // the mute status and fires the appropriate event (MUTED or
  305. // UNMUTED), while the code which handles the keyboard shortcut
  306. // calls toggleAudioMuted(). Also strangely the the user is
  307. // only warned if they click the button (and not if they use
  308. // the shortcut).
  309. if (APP.conference.isLocalAudioMuted()) {
  310. // If there's a shared video with the volume "on" and we
  311. // aren't the video owner, we warn the user
  312. // that currently it's not possible to unmute.
  313. if (sharedVideoManager
  314. && sharedVideoManager.isSharedVideoVolumeOn()
  315. && !sharedVideoManager.isSharedVideoOwner()) {
  316. APP.UI.showCustomToolbarPopup(
  317. 'microphone', 'unableToUnmutePopup', true, 5000);
  318. } else {
  319. sendAnalytics(createToolbarEvent(
  320. AUDIO_MUTE,
  321. { enable: false }));
  322. APP.UI.emitEvent(UIEvents.AUDIO_MUTED, false, true);
  323. }
  324. } else {
  325. sendAnalytics(createToolbarEvent(
  326. AUDIO_MUTE,
  327. { enable: true }));
  328. APP.UI.emitEvent(UIEvents.AUDIO_MUTED, true, true);
  329. }
  330. },
  331. popups: [
  332. {
  333. dataAttr: 'toolbar.micMutedPopup',
  334. id: 'micMutedPopup'
  335. },
  336. {
  337. dataAttr: 'toolbar.unableToUnmutePopup',
  338. id: 'unableToUnmutePopup'
  339. },
  340. {
  341. dataAttr: 'toolbar.talkWhileMutedPopup',
  342. id: 'talkWhileMutedPopup'
  343. }
  344. ],
  345. shortcut: 'M',
  346. shortcutAttr: 'mutePopover',
  347. shortcutFunc() {
  348. // The 'enable' attribute in the event is set to true if the
  349. // shortcut triggered a mute action, and set to false if it
  350. // triggered an unmute action.
  351. sendAnalytics(createShortcutEvent(
  352. AUDIO_MUTE,
  353. TRIGGERED,
  354. { enable: !APP.conference.isLocalAudioMuted() }));
  355. APP.conference.toggleAudioMuted();
  356. },
  357. shortcutDescription: 'keyboardShortcuts.mute',
  358. tooltipKey: 'toolbar.mute'
  359. },
  360. /**
  361. * The descriptor of the profile toolbar button.
  362. */
  363. profile: {
  364. component: ProfileButton,
  365. sideContainerId: 'profile_container'
  366. },
  367. /**
  368. * The descriptor of the "Raise hand" toolbar button.
  369. */
  370. raisehand: {
  371. classNames: [ 'button', 'icon-raised-hand' ],
  372. enabled: true,
  373. id: 'toolbar_button_raisehand',
  374. onClick() {
  375. // TODO: reduce duplication with shortcutFunc below.
  376. const localParticipant
  377. = getLocalParticipant(APP.store.getState());
  378. const currentRaisedHand = localParticipant.raisedHand;
  379. // The 'enable' attribute is set to true if the pressing of the
  380. // shortcut resulted in the hand being raised, and to false
  381. // if it resulted in the hand being 'lowered'.
  382. sendAnalytics(createToolbarEvent(
  383. 'raise.hand',
  384. { enable: !currentRaisedHand }));
  385. APP.store.dispatch(participantUpdated({
  386. id: localParticipant.id,
  387. local: true,
  388. raisedHand: !currentRaisedHand
  389. }));
  390. },
  391. shortcut: 'R',
  392. shortcutAttr: 'raiseHandPopover',
  393. shortcutDescription: 'keyboardShortcuts.raiseHand',
  394. shortcutFunc() {
  395. const localParticipant
  396. = getLocalParticipant(APP.store.getState());
  397. const currentRaisedHand = localParticipant.raisedHand;
  398. // The 'enable' attribute is set to true if the pressing of the
  399. // shortcut resulted in the hand being raised, and to false
  400. // if it resulted in the hand being 'lowered'.
  401. sendAnalytics(createShortcutEvent(
  402. 'toggle.raise.hand',
  403. TRIGGERED,
  404. { enable: !currentRaisedHand }));
  405. APP.store.dispatch(participantUpdated({
  406. id: localParticipant.id,
  407. local: true,
  408. raisedHand: !currentRaisedHand
  409. }));
  410. },
  411. tooltipKey: 'toolbar.raiseHand'
  412. },
  413. /**
  414. * The descriptor of the recording toolbar button. Requires additional
  415. * initialization in the recording module.
  416. */
  417. recording: {
  418. classNames: [ 'button' ],
  419. enabled: true,
  420. // will be displayed once the recording functionality is detected
  421. hidden: true,
  422. id: 'toolbar_button_record',
  423. tooltipKey: 'liveStreaming.buttonTooltip'
  424. },
  425. /**
  426. * The descriptor of the settings toolbar button.
  427. */
  428. settings: {
  429. classNames: [ 'button', 'icon-settings' ],
  430. enabled: true,
  431. id: 'toolbar_button_settings',
  432. onClick() {
  433. // TODO: Include an 'enable' attribute which specifies whether
  434. // the settings panel was shown or hidden.
  435. sendAnalytics(createToolbarEvent('settings'));
  436. APP.UI.emitEvent(UIEvents.TOGGLE_SETTINGS);
  437. },
  438. sideContainerId: 'settings_container',
  439. tooltipKey: 'toolbar.Settings'
  440. },
  441. /**
  442. * The descriptor of the "Share YouTube video" toolbar button.
  443. */
  444. sharedvideo: {
  445. classNames: [ 'button', 'icon-shared-video' ],
  446. enabled: true,
  447. id: 'toolbar_button_sharedvideo',
  448. onClick() {
  449. // The 'enable' attribute is set to true if the click resulted
  450. // in the "start sharing video" dialog being shown, and false
  451. // if it resulted in the "stop sharing video" dialog being
  452. // shown.
  453. sendAnalytics(createToolbarEvent(
  454. 'shared.video.toggled',
  455. {
  456. enable: !APP.UI.isSharedVideoShown()
  457. }));
  458. APP.UI.emitEvent(UIEvents.SHARED_VIDEO_CLICKED);
  459. },
  460. popups: [
  461. {
  462. dataAttr: 'toolbar.sharedVideoMutedPopup',
  463. id: 'sharedVideoMutedPopup'
  464. }
  465. ],
  466. tooltipKey: 'toolbar.sharedvideo'
  467. },
  468. videoquality: {
  469. component: VideoQualityButton
  470. }
  471. };
  472. Object.keys(defaultButtons).forEach(name => {
  473. const button = defaultButtons[name];
  474. if (!button.isDisplayed) {
  475. button.isDisplayed = _isDisplayed;
  476. }
  477. });
  478. return defaultButtons;
  479. }
  480. /**
  481. * The default implementation of the {@code isDisplayed} method of the toolbar
  482. * button definition returned by {@link getDefaultButtons()}.
  483. *
  484. * @returns {boolean} If the user intarface is full i.e. not filmstrip-only,
  485. * then {@code true}; otherwise, {@code false}.
  486. */
  487. function _isDisplayed() {
  488. return !interfaceConfig.filmStripOnly;
  489. }