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.

SettingsDialog.js 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { getAvailableDevices } from '../../../base/devices';
  4. import { DialogWithTabs, hideDialog } from '../../../base/dialog';
  5. import { connect } from '../../../base/redux';
  6. import { isCalendarEnabled } from '../../../calendar-sync';
  7. import {
  8. DeviceSelection,
  9. getDeviceSelectionDialogProps,
  10. submitDeviceSelectionTab
  11. } from '../../../device-selection';
  12. import { submitMoreTab, submitProfileTab, submitSoundsTab } from '../../actions';
  13. import { SETTINGS_TABS } from '../../constants';
  14. import { getMoreTabProps, getProfileTabProps, getSoundsTabProps } from '../../functions';
  15. import CalendarTab from './CalendarTab';
  16. import MoreTab from './MoreTab';
  17. import ProfileTab from './ProfileTab';
  18. import SoundsTab from './SoundsTab';
  19. declare var APP: Object;
  20. declare var interfaceConfig: Object;
  21. /**
  22. * The type of the React {@code Component} props of
  23. * {@link ConnectedSettingsDialog}.
  24. */
  25. type Props = {
  26. /**
  27. * Which settings tab should be initially displayed. If not defined then
  28. * the first tab will be displayed.
  29. */
  30. defaultTab: string,
  31. /**
  32. * Information about the tabs to be rendered.
  33. */
  34. _tabs: Array<Object>,
  35. /**
  36. * Invoked to save changed settings.
  37. */
  38. dispatch: Function
  39. };
  40. /**
  41. * A React {@code Component} for displaying a dialog to modify local settings
  42. * and conference-wide (moderator) settings. This version is connected to
  43. * redux to get the current settings.
  44. *
  45. * @extends Component
  46. */
  47. class SettingsDialog extends Component<Props> {
  48. /**
  49. * Initializes a new {@code ConnectedSettingsDialog} instance.
  50. *
  51. * @param {Props} props - The React {@code Component} props to initialize
  52. * the new {@code ConnectedSettingsDialog} instance with.
  53. */
  54. constructor(props: Props) {
  55. super(props);
  56. // Bind event handlers so they are only bound once for every instance.
  57. this._closeDialog = this._closeDialog.bind(this);
  58. }
  59. /**
  60. * Implements React's {@link Component#render()}.
  61. *
  62. * @inheritdoc
  63. * @returns {ReactElement}
  64. */
  65. render() {
  66. const { _tabs, defaultTab, dispatch } = this.props;
  67. const onSubmit = this._closeDialog;
  68. const defaultTabIdx
  69. = _tabs.findIndex(({ name }) => name === defaultTab);
  70. const tabs = _tabs.map(tab => {
  71. return {
  72. ...tab,
  73. onMount: tab.onMount
  74. ? (...args) => dispatch(tab.onMount(...args))
  75. : undefined,
  76. submit: (...args) => tab.submit
  77. && dispatch(tab.submit(...args))
  78. };
  79. });
  80. return (
  81. <DialogWithTabs
  82. closeDialog = { this._closeDialog }
  83. cssClassName = 'settings-dialog'
  84. defaultTab = {
  85. defaultTabIdx === -1 ? undefined : defaultTabIdx
  86. }
  87. onSubmit = { onSubmit }
  88. tabs = { tabs }
  89. titleKey = 'settings.title' />
  90. );
  91. }
  92. _closeDialog: () => void;
  93. /**
  94. * Callback invoked to close the dialog without saving changes.
  95. *
  96. * @private
  97. * @returns {void}
  98. */
  99. _closeDialog() {
  100. this.props.dispatch(hideDialog());
  101. }
  102. }
  103. /**
  104. * Maps (parts of) the Redux state to the associated props for the
  105. * {@code ConnectedSettingsDialog} component.
  106. *
  107. * @param {Object} state - The Redux state.
  108. * @private
  109. * @returns {{
  110. * tabs: Array<Object>
  111. * }}
  112. */
  113. function _mapStateToProps(state) {
  114. const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
  115. // The settings sections to display.
  116. const showDeviceSettings = configuredTabs.includes('devices');
  117. const moreTabProps = getMoreTabProps(state);
  118. const { showModeratorSettings, showLanguageSettings, showPrejoinSettings } = moreTabProps;
  119. const showProfileSettings
  120. = configuredTabs.includes('profile') && !state['features/base/config'].disableProfile;
  121. const showCalendarSettings
  122. = configuredTabs.includes('calendar') && isCalendarEnabled(state);
  123. const showSoundsSettings = configuredTabs.includes('sounds');
  124. const tabs = [];
  125. if (showDeviceSettings) {
  126. tabs.push({
  127. name: SETTINGS_TABS.DEVICES,
  128. component: DeviceSelection,
  129. label: 'settings.devices',
  130. onMount: getAvailableDevices,
  131. props: getDeviceSelectionDialogProps(state),
  132. propsUpdateFunction: (tabState, newProps) => {
  133. // Ensure the device selection tab gets updated when new devices
  134. // are found by taking the new props and only preserving the
  135. // current user selected devices. If this were not done, the
  136. // tab would keep using a copy of the initial props it received,
  137. // leaving the device list to become stale.
  138. return {
  139. ...newProps,
  140. selectedAudioInputId: tabState.selectedAudioInputId,
  141. selectedAudioOutputId: tabState.selectedAudioOutputId,
  142. selectedVideoInputId: tabState.selectedVideoInputId
  143. };
  144. },
  145. styles: 'settings-pane devices-pane',
  146. submit: submitDeviceSelectionTab
  147. });
  148. }
  149. if (showProfileSettings) {
  150. tabs.push({
  151. name: SETTINGS_TABS.PROFILE,
  152. component: ProfileTab,
  153. label: 'profile.title',
  154. props: getProfileTabProps(state),
  155. styles: 'settings-pane profile-pane',
  156. submit: submitProfileTab
  157. });
  158. }
  159. if (showCalendarSettings) {
  160. tabs.push({
  161. name: SETTINGS_TABS.CALENDAR,
  162. component: CalendarTab,
  163. label: 'settings.calendar.title',
  164. styles: 'settings-pane calendar-pane'
  165. });
  166. }
  167. if (showSoundsSettings) {
  168. tabs.push({
  169. name: SETTINGS_TABS.SOUNDS,
  170. component: SoundsTab,
  171. label: 'settings.sounds',
  172. props: getSoundsTabProps(state),
  173. styles: 'settings-pane profile-pane',
  174. submit: submitSoundsTab
  175. });
  176. }
  177. if (showModeratorSettings || showLanguageSettings || showPrejoinSettings) {
  178. tabs.push({
  179. name: SETTINGS_TABS.MORE,
  180. component: MoreTab,
  181. label: 'settings.more',
  182. props: moreTabProps,
  183. propsUpdateFunction: (tabState, newProps) => {
  184. // Updates tab props, keeping users selection
  185. return {
  186. ...newProps,
  187. currentFramerate: tabState.currentFramerate,
  188. currentLanguage: tabState.currentLanguage,
  189. followMeEnabled: tabState.followMeEnabled,
  190. showPrejoinPage: tabState.showPrejoinPage,
  191. startAudioMuted: tabState.startAudioMuted,
  192. startVideoMuted: tabState.startVideoMuted
  193. };
  194. },
  195. styles: 'settings-pane more-pane',
  196. submit: submitMoreTab
  197. });
  198. }
  199. return { _tabs: tabs };
  200. }
  201. export default connect(_mapStateToProps)(SettingsDialog);