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

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