snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
343
react/features/settings/components/web/SettingsDialog.tsx
Normal file
343
react/features/settings/components/web/SettingsDialog.tsx
Normal file
@@ -0,0 +1,343 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import {
|
||||
IconBell,
|
||||
IconCalendar,
|
||||
IconGear,
|
||||
IconImage,
|
||||
IconModerator,
|
||||
IconShortcuts,
|
||||
IconUser,
|
||||
IconVideo,
|
||||
IconVolumeUp
|
||||
} from '../../../base/icons/svg';
|
||||
import DialogWithTabs, { IDialogTab } from '../../../base/ui/components/web/DialogWithTabs';
|
||||
import { isCalendarEnabled } from '../../../calendar-sync/functions.web';
|
||||
import { submitAudioDeviceSelectionTab, submitVideoDeviceSelectionTab } from '../../../device-selection/actions.web';
|
||||
import AudioDevicesSelection from '../../../device-selection/components/AudioDevicesSelection.web';
|
||||
import VideoDeviceSelection from '../../../device-selection/components/VideoDeviceSelection.web';
|
||||
import {
|
||||
getAudioDeviceSelectionDialogProps,
|
||||
getVideoDeviceSelectionDialogProps
|
||||
} from '../../../device-selection/functions.web';
|
||||
import { checkBlurSupport, checkVirtualBackgroundEnabled } from '../../../virtual-background/functions';
|
||||
import { iAmVisitor } from '../../../visitors/functions';
|
||||
import {
|
||||
submitModeratorTab,
|
||||
submitMoreTab,
|
||||
submitNotificationsTab,
|
||||
submitProfileTab,
|
||||
submitShortcutsTab,
|
||||
submitVirtualBackgroundTab
|
||||
} from '../../actions';
|
||||
import { SETTINGS_TABS } from '../../constants';
|
||||
import {
|
||||
getModeratorTabProps,
|
||||
getMoreTabProps,
|
||||
getNotificationsMap,
|
||||
getNotificationsTabProps,
|
||||
getProfileTabProps,
|
||||
getShortcutsTabProps,
|
||||
getVirtualBackgroundTabProps
|
||||
} from '../../functions';
|
||||
|
||||
import CalendarTab from './CalendarTab';
|
||||
import ModeratorTab from './ModeratorTab';
|
||||
import MoreTab from './MoreTab';
|
||||
import NotificationsTab from './NotificationsTab';
|
||||
import ProfileTab from './ProfileTab';
|
||||
import ShortcutsTab from './ShortcutsTab';
|
||||
import VirtualBackgroundTab from './VirtualBackgroundTab';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of
|
||||
* {@link ConnectedSettingsDialog}.
|
||||
*/
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* Information about the tabs to be rendered.
|
||||
*/
|
||||
_tabs: IDialogTab<any>[];
|
||||
|
||||
/**
|
||||
* Which settings tab should be initially displayed. If not defined then
|
||||
* the first tab will be displayed.
|
||||
*/
|
||||
defaultTab: string;
|
||||
|
||||
/**
|
||||
* Invoked to save changed settings.
|
||||
*/
|
||||
dispatch: IStore['dispatch'];
|
||||
|
||||
/**
|
||||
* Indicates whether the device selection dialog is displayed on the
|
||||
* welcome page or not.
|
||||
*/
|
||||
isDisplayedOnWelcomePage: boolean;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(() => {
|
||||
return {
|
||||
settingsDialog: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const SettingsDialog = ({ _tabs, defaultTab, dispatch }: IProps) => {
|
||||
const { classes } = useStyles();
|
||||
|
||||
const correctDefaultTab = _tabs.find(tab => tab.name === defaultTab)?.name;
|
||||
const tabs = _tabs.map(tab => {
|
||||
return {
|
||||
...tab,
|
||||
className: `settings-pane ${classes.settingsDialog}`,
|
||||
submit: (...args: any) => tab.submit
|
||||
&& dispatch(tab.submit(...args))
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<DialogWithTabs
|
||||
className = 'settings-dialog'
|
||||
defaultTab = { correctDefaultTab }
|
||||
tabs = { tabs }
|
||||
titleKey = 'settings.title' />
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated props for the
|
||||
* {@code ConnectedSettingsDialog} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The props passed to the component.
|
||||
* @private
|
||||
* @returns {{
|
||||
* tabs: Array<Object>
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { isDisplayedOnWelcomePage } = ownProps;
|
||||
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
|
||||
|
||||
// The settings sections to display.
|
||||
const showDeviceSettings = configuredTabs.includes('devices');
|
||||
const moreTabProps = getMoreTabProps(state);
|
||||
const moderatorTabProps = getModeratorTabProps(state);
|
||||
const { showModeratorSettings } = moderatorTabProps;
|
||||
const showMoreTab = configuredTabs.includes('more');
|
||||
const showProfileSettings
|
||||
= configuredTabs.includes('profile') && !state['features/base/config'].disableProfile;
|
||||
const showCalendarSettings
|
||||
= configuredTabs.includes('calendar') && isCalendarEnabled(state);
|
||||
const showShortcutsSettings = configuredTabs.includes('shortcuts');
|
||||
const showSoundsSettings = configuredTabs.includes('sounds');
|
||||
const enabledNotifications = getNotificationsMap(state);
|
||||
const showNotificationsSettings = Object.keys(enabledNotifications).length > 0;
|
||||
const virtualBackgroundSupported = checkBlurSupport();
|
||||
const enableVirtualBackground = checkVirtualBackgroundEnabled(state);
|
||||
const tabs: IDialogTab<any>[] = [];
|
||||
const _iAmVisitor = iAmVisitor(state);
|
||||
|
||||
if (showDeviceSettings) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.AUDIO,
|
||||
component: AudioDevicesSelection,
|
||||
labelKey: 'settings.audio',
|
||||
props: getAudioDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
|
||||
propsUpdateFunction: (tabState: any, newProps: ReturnType<typeof getAudioDeviceSelectionDialogProps>) => {
|
||||
// Ensure the device selection tab gets updated when new devices
|
||||
// are found by taking the new props and only preserving the
|
||||
// current user selected devices. If this were not done, the
|
||||
// tab would keep using a copy of the initial props it received,
|
||||
// leaving the device list to become stale.
|
||||
|
||||
return {
|
||||
...newProps,
|
||||
audioSettings: tabState.audioSettings,
|
||||
noiseSuppressionEnabled: tabState.noiseSuppressionEnabled,
|
||||
selectedAudioInputId: tabState.selectedAudioInputId,
|
||||
selectedAudioOutputId: tabState.selectedAudioOutputId
|
||||
};
|
||||
},
|
||||
submit: (newState: any) => submitAudioDeviceSelectionTab(newState, isDisplayedOnWelcomePage),
|
||||
icon: IconVolumeUp
|
||||
});
|
||||
!_iAmVisitor && tabs.push({
|
||||
name: SETTINGS_TABS.VIDEO,
|
||||
component: VideoDeviceSelection,
|
||||
labelKey: 'settings.video',
|
||||
props: getVideoDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
|
||||
propsUpdateFunction: (tabState: any, newProps: ReturnType<typeof getVideoDeviceSelectionDialogProps>) => {
|
||||
// Ensure the device selection tab gets updated when new devices
|
||||
// are found by taking the new props and only preserving the
|
||||
// current user selected devices. If this were not done, the
|
||||
// tab would keep using a copy of the initial props it received,
|
||||
// leaving the device list to become stale.
|
||||
|
||||
return {
|
||||
...newProps,
|
||||
currentFramerate: tabState?.currentFramerate,
|
||||
localFlipX: tabState.localFlipX,
|
||||
selectedVideoInputId: tabState.selectedVideoInputId
|
||||
};
|
||||
},
|
||||
submit: (newState: any) => submitVideoDeviceSelectionTab(newState, isDisplayedOnWelcomePage),
|
||||
icon: IconVideo
|
||||
});
|
||||
}
|
||||
|
||||
if (virtualBackgroundSupported && !_iAmVisitor && enableVirtualBackground) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.VIRTUAL_BACKGROUND,
|
||||
component: VirtualBackgroundTab,
|
||||
labelKey: 'virtualBackground.title',
|
||||
props: getVirtualBackgroundTabProps(state, isDisplayedOnWelcomePage),
|
||||
propsUpdateFunction: (tabState: any, newProps: ReturnType<typeof getVirtualBackgroundTabProps>,
|
||||
tabStates: any) => {
|
||||
const videoTabState = tabStates[tabs.findIndex(tab => tab.name === SETTINGS_TABS.VIDEO)];
|
||||
|
||||
return {
|
||||
...newProps,
|
||||
selectedVideoInputId: videoTabState?.selectedVideoInputId || newProps.selectedVideoInputId,
|
||||
options: tabState.options
|
||||
};
|
||||
},
|
||||
submit: (newState: any) => submitVirtualBackgroundTab(newState),
|
||||
cancel: () => {
|
||||
const { options } = getVirtualBackgroundTabProps(state, isDisplayedOnWelcomePage);
|
||||
|
||||
return submitVirtualBackgroundTab({ options }, true);
|
||||
},
|
||||
icon: IconImage
|
||||
});
|
||||
}
|
||||
|
||||
if ((showSoundsSettings || showNotificationsSettings) && !_iAmVisitor) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.NOTIFICATIONS,
|
||||
component: NotificationsTab,
|
||||
labelKey: 'settings.notifications',
|
||||
propsUpdateFunction: (tabState: any, newProps: ReturnType<typeof getNotificationsTabProps>) => {
|
||||
return {
|
||||
...newProps,
|
||||
enabledNotifications: tabState?.enabledNotifications || {},
|
||||
soundsIncomingMessage: tabState?.soundsIncomingMessage,
|
||||
soundsParticipantJoined: tabState?.soundsParticipantJoined,
|
||||
soundsParticipantKnocking: tabState?.soundsParticipantKnocking,
|
||||
soundsParticipantLeft: tabState?.soundsParticipantLeft,
|
||||
soundsReactions: tabState?.soundsReactions,
|
||||
soundsTalkWhileMuted: tabState?.soundsTalkWhileMuted
|
||||
};
|
||||
},
|
||||
props: getNotificationsTabProps(state, showSoundsSettings),
|
||||
submit: submitNotificationsTab,
|
||||
icon: IconBell
|
||||
});
|
||||
}
|
||||
|
||||
if (showModeratorSettings && !_iAmVisitor) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.MODERATOR,
|
||||
component: ModeratorTab,
|
||||
labelKey: 'settings.moderator',
|
||||
props: moderatorTabProps,
|
||||
propsUpdateFunction: (tabState: any, newProps: typeof moderatorTabProps) => {
|
||||
// Updates tab props, keeping users selection
|
||||
|
||||
return {
|
||||
...newProps,
|
||||
audioTranslationEnabled: tabState?.audioTranslationEnabled,
|
||||
chatWithPermissionsEnabled: tabState?.chatWithPermissionsEnabled,
|
||||
followMeEnabled: tabState?.followMeEnabled,
|
||||
followMeRecorderEnabled: tabState?.followMeRecorderEnabled,
|
||||
startAudioMuted: tabState?.startAudioMuted,
|
||||
startVideoMuted: tabState?.startVideoMuted,
|
||||
startReactionsMuted: tabState?.startReactionsMuted
|
||||
};
|
||||
},
|
||||
submit: submitModeratorTab,
|
||||
icon: IconModerator
|
||||
});
|
||||
}
|
||||
|
||||
if (showProfileSettings) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.PROFILE,
|
||||
component: ProfileTab,
|
||||
labelKey: 'profile.title',
|
||||
props: getProfileTabProps(state),
|
||||
propsUpdateFunction: (tabState: any, newProps: ReturnType<typeof getProfileTabProps>) => {
|
||||
return {
|
||||
...newProps,
|
||||
displayName: tabState?.displayName,
|
||||
email: tabState?.email
|
||||
};
|
||||
},
|
||||
submit: submitProfileTab,
|
||||
icon: IconUser
|
||||
});
|
||||
}
|
||||
|
||||
if (showCalendarSettings && !_iAmVisitor) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.CALENDAR,
|
||||
component: CalendarTab,
|
||||
labelKey: 'settings.calendar.title',
|
||||
icon: IconCalendar
|
||||
});
|
||||
}
|
||||
|
||||
if (showShortcutsSettings && !_iAmVisitor) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.SHORTCUTS,
|
||||
component: ShortcutsTab,
|
||||
labelKey: 'settings.shortcuts',
|
||||
props: getShortcutsTabProps(state, isDisplayedOnWelcomePage),
|
||||
propsUpdateFunction: (tabState: any, newProps: ReturnType<typeof getShortcutsTabProps>) => {
|
||||
// Updates tab props, keeping users selection
|
||||
|
||||
return {
|
||||
...newProps,
|
||||
ctrlAltReactionShortcutsEnabled: tabState?.ctrlAltReactionShortcutsEnabled,
|
||||
keyboardShortcutsEnabled: tabState?.keyboardShortcutsEnabled
|
||||
};
|
||||
},
|
||||
submit: submitShortcutsTab,
|
||||
icon: IconShortcuts
|
||||
});
|
||||
}
|
||||
|
||||
if (showMoreTab && !_iAmVisitor) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.MORE,
|
||||
component: MoreTab,
|
||||
labelKey: 'settings.more',
|
||||
props: moreTabProps,
|
||||
propsUpdateFunction: (tabState: any, newProps: typeof moreTabProps) => {
|
||||
// Updates tab props, keeping users selection
|
||||
|
||||
return {
|
||||
...newProps,
|
||||
currentLanguage: tabState?.currentLanguage,
|
||||
hideSelfView: tabState?.hideSelfView,
|
||||
showSubtitlesOnStage: tabState?.showSubtitlesOnStage,
|
||||
maxStageParticipants: tabState?.maxStageParticipants
|
||||
};
|
||||
},
|
||||
submit: submitMoreTab,
|
||||
icon: IconGear
|
||||
});
|
||||
}
|
||||
|
||||
return { _tabs: tabs };
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(SettingsDialog);
|
||||
Reference in New Issue
Block a user