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 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 interfaceConfig: Object;
  31. /**
  32. * The type of the React {@code Component} props of
  33. * {@link ConnectedSettingsDialog}.
  34. */
  35. type Props = {
  36. /**
  37. * Which settings tab should be initially displayed. If not defined then
  38. * the first tab will be displayed.
  39. */
  40. defaultTab: string,
  41. /**
  42. * Information about the tabs to be rendered.
  43. */
  44. _tabs: Array<Object>,
  45. /**
  46. * Invoked to save changed settings.
  47. */
  48. dispatch: Function
  49. };
  50. /**
  51. * A React {@code Component} for displaying a dialog to modify local settings
  52. * and conference-wide (moderator) settings. This version is connected to
  53. * redux to get the current settings.
  54. *
  55. * @augments Component
  56. */
  57. class SettingsDialog extends Component<Props> {
  58. /**
  59. * Initializes a new {@code ConnectedSettingsDialog} instance.
  60. *
  61. * @param {Props} props - The React {@code Component} props to initialize
  62. * the new {@code ConnectedSettingsDialog} instance with.
  63. */
  64. constructor(props: Props) {
  65. super(props);
  66. // Bind event handlers so they are only bound once for every instance.
  67. this._closeDialog = this._closeDialog.bind(this);
  68. }
  69. /**
  70. * Implements React's {@link Component#render()}.
  71. *
  72. * @inheritdoc
  73. * @returns {ReactElement}
  74. */
  75. render() {
  76. const { _tabs, defaultTab, dispatch } = this.props;
  77. const onSubmit = this._closeDialog;
  78. const defaultTabIdx
  79. = _tabs.findIndex(({ name }) => name === defaultTab);
  80. const tabs = _tabs.map(tab => {
  81. return {
  82. ...tab,
  83. onMount: tab.onMount
  84. ? (...args) => dispatch(tab.onMount(...args))
  85. : undefined,
  86. submit: (...args) => tab.submit
  87. && dispatch(tab.submit(...args))
  88. };
  89. });
  90. return (
  91. <DialogWithTabs
  92. closeDialog = { this._closeDialog }
  93. cssClassName = 'settings-dialog'
  94. defaultTab = {
  95. defaultTabIdx === -1 ? undefined : defaultTabIdx
  96. }
  97. onSubmit = { onSubmit }
  98. tabs = { tabs }
  99. titleKey = 'settings.title' />
  100. );
  101. }
  102. _closeDialog: () => void;
  103. /**
  104. * Callback invoked to close the dialog without saving changes.
  105. *
  106. * @private
  107. * @returns {void}
  108. */
  109. _closeDialog() {
  110. this.props.dispatch(hideDialog());
  111. }
  112. }
  113. /**
  114. * Maps (parts of) the Redux state to the associated props for the
  115. * {@code ConnectedSettingsDialog} component.
  116. *
  117. * @param {Object} state - The Redux state.
  118. * @private
  119. * @returns {{
  120. * tabs: Array<Object>
  121. * }}
  122. */
  123. function _mapStateToProps(state) {
  124. const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
  125. // The settings sections to display.
  126. const showDeviceSettings = configuredTabs.includes('devices');
  127. const moreTabProps = getMoreTabProps(state);
  128. const moderatorTabProps = getModeratorTabProps(state);
  129. const { showModeratorSettings } = moderatorTabProps;
  130. const { showLanguageSettings, showNotificationsSettings, showPrejoinSettings } = moreTabProps;
  131. const showMoreTab = showLanguageSettings || showNotificationsSettings || showPrejoinSettings;
  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 (showMoreTab) {
  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. hideSelfView: tabState.hideSelfView,
  223. showPrejoinPage: tabState.showPrejoinPage,
  224. enabledNotifications: tabState.enabledNotifications
  225. };
  226. },
  227. styles: 'settings-pane more-pane',
  228. submit: submitMoreTab
  229. });
  230. }
  231. return { _tabs: tabs };
  232. }
  233. export default connect(_mapStateToProps)(SettingsDialog);