Self view refactor (#10620)

* feat: Drops hide self-view setting from profile tab.

* feat: Moves function for disableSelfView value in base/settings.

* squash: Drops notification.

* feat: Move hide self view option in more tab.

* feat: Move hide self view option in more tab.

* feat: Adds option to disable self view UI settings.

* squash: Disable settings when controlled from config.
This commit is contained in:
Дамян Минков 2021-12-16 10:55:45 -06:00 committed by GitHub
parent 2a236b9327
commit 5dee37dd82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 152 additions and 142 deletions

View File

@ -89,6 +89,9 @@ var config = {
// Disables self-view tile. (hides it from tile view and from filmstrip) // Disables self-view tile. (hides it from tile view and from filmstrip)
// disableSelfView: false, // disableSelfView: false,
// Disables self-view settings in UI
// disableSelfViewSettings: false,
// Disables ICE/UDP by filtering out local and remote UDP candidates in // Disables ICE/UDP by filtering out local and remote UDP candidates in
// signalling. // signalling.
// webrtcIceUdpDisable: false, // webrtcIceUdpDisable: false,

View File

@ -857,6 +857,7 @@
"selectAudioOutput": "Audio output", "selectAudioOutput": "Audio output",
"selectCamera": "Camera", "selectCamera": "Camera",
"selectMic": "Microphone", "selectMic": "Microphone",
"selfView": "Self view",
"sounds": "Sounds", "sounds": "Sounds",
"speakers": "Speakers", "speakers": "Speakers",
"startAudioMuted": "Everyone starts muted", "startAudioMuted": "Everyone starts muted",

View File

@ -17,6 +17,7 @@ import '../prejoin/middleware';
import '../remote-control/middleware'; import '../remote-control/middleware';
import '../screen-share/middleware'; import '../screen-share/middleware';
import '../shared-video/middleware'; import '../shared-video/middleware';
import '../settings/middleware';
import '../talk-while-muted/middleware'; import '../talk-while-muted/middleware';
import '../virtual-background/middleware'; import '../virtual-background/middleware';
import '../facial-recognition/middleware'; import '../facial-recognition/middleware';

View File

@ -115,6 +115,7 @@ export default [
'disableResponsiveTiles', 'disableResponsiveTiles',
'disableRtx', 'disableRtx',
'disableSelfView', 'disableSelfView',
'disableSelfViewSettings',
'disableScreensharingVirtualBackground', 'disableScreensharingVirtualBackground',
'disableShortcuts', 'disableShortcuts',
'disableShowMoreStats', 'disableShowMoreStats',

View File

@ -125,12 +125,6 @@ function _setConfig({ dispatch, getState }, next, action) {
})); }));
} }
if (action.config.disableSelfView) {
dispatch(updateSettings({
disableSelfView: true
}));
}
dispatch(updateConfig(config)); dispatch(updateConfig(config));
// FIXME On Web we rely on the global 'config' variable which gets altered // FIXME On Web we rely on the global 'config' variable which gets altered

View File

@ -1,5 +1,6 @@
// @flow // @flow
import { CONFIG_WHITELIST } from '../config'; import { CONFIG_WHITELIST } from '../config';
import { getParticipantCount } from '../participants';
import { toState } from '../redux'; import { toState } from '../redux';
import { parseURLParams } from '../util'; import { parseURLParams } from '../util';
@ -256,3 +257,23 @@ export function shouldHideShareAudioHelper(state: Object): boolean {
return state['features/base/settings'].hideShareAudioHelper; return state['features/base/settings'].hideShareAudioHelper;
} }
/**
* Whether we should hide self view.
*
* @param {Object} state - Redux state.
* @returns {boolean}
*/
export function shouldHideSelfView(state: Object) {
return getParticipantCount(state) === 1 ? false : getHideSelfView(state);
}
/**
* Gets the disable self view setting.
*
* @param {Object} state - Redux state.
* @returns {boolean}
*/
export function getHideSelfView(state: Object) {
return state['features/base/config'].disableSelfView || state['features/base/settings'].disableSelfView;
}

View File

@ -2,6 +2,7 @@
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
import { getLocalParticipant, getParticipantById, pinParticipant } from '../base/participants'; import { getLocalParticipant, getParticipantById, pinParticipant } from '../base/participants';
import { shouldHideSelfView } from '../base/settings/functions.any';
import { import {
SET_HORIZONTAL_VIEW_DIMENSIONS, SET_HORIZONTAL_VIEW_DIMENSIONS,
@ -23,7 +24,6 @@ import {
calculateThumbnailSizeForTileView, calculateThumbnailSizeForTileView,
calculateThumbnailSizeForVerticalView calculateThumbnailSizeForVerticalView
} from './functions'; } from './functions';
import { getDisableSelfView } from './functions.any';
export * from './actions.any'; export * from './actions.any';
@ -79,7 +79,7 @@ export function setVerticalViewDimensions() {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState(); const state = getState();
const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui']; const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui'];
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const thumbnails = calculateThumbnailSizeForVerticalView(clientWidth); const thumbnails = calculateThumbnailSizeForVerticalView(clientWidth);
dispatch({ dispatch({
@ -107,7 +107,7 @@ export function setHorizontalViewDimensions() {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState(); const state = getState();
const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui']; const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui'];
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const thumbnails = calculateThumbnailSizeForHorizontalView(clientHeight); const thumbnails = calculateThumbnailSizeForHorizontalView(clientHeight);
dispatch({ dispatch({

View File

@ -7,9 +7,9 @@ import { getLocalParticipant } from '../../../base/participants';
import { Platform } from '../../../base/react'; import { Platform } from '../../../base/react';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants'; import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
import { shouldHideSelfView } from '../../../base/settings/functions.any';
import { setVisibleRemoteParticipants } from '../../actions'; import { setVisibleRemoteParticipants } from '../../actions';
import { isFilmstripVisible, shouldRemoteVideosBeVisible } from '../../functions'; import { isFilmstripVisible, shouldRemoteVideosBeVisible } from '../../functions';
import { getDisableSelfView } from '../../functions.any';
import LocalThumbnail from './LocalThumbnail'; import LocalThumbnail from './LocalThumbnail';
import Thumbnail from './Thumbnail'; import Thumbnail from './Thumbnail';
@ -283,7 +283,7 @@ class Filmstrip extends PureComponent<Props> {
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state) {
const { enabled, remoteParticipants } = state['features/filmstrip']; const { enabled, remoteParticipants } = state['features/filmstrip'];
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const showRemoteVideos = shouldRemoteVideosBeVisible(state); const showRemoteVideos = shouldRemoteVideosBeVisible(state);
const responsiveUI = state['features/base/responsive-ui']; const responsiveUI = state['features/base/responsive-ui'];

View File

@ -10,8 +10,8 @@ import type { Dispatch } from 'redux';
import { getLocalParticipant, getParticipantCountWithFake } from '../../../base/participants'; import { getLocalParticipant, getParticipantCountWithFake } from '../../../base/participants';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { shouldHideSelfView } from '../../../base/settings/functions.any';
import { setVisibleRemoteParticipants } from '../../actions.web'; import { setVisibleRemoteParticipants } from '../../actions.web';
import { getDisableSelfView } from '../../functions.any';
import Thumbnail from './Thumbnail'; import Thumbnail from './Thumbnail';
import styles from './styles'; import styles from './styles';
@ -275,7 +275,7 @@ class TileView extends PureComponent<Props> {
function _mapStateToProps(state) { function _mapStateToProps(state) {
const responsiveUi = state['features/base/responsive-ui']; const responsiveUi = state['features/base/responsive-ui'];
const { remoteParticipants, tileViewDimensions } = state['features/filmstrip']; const { remoteParticipants, tileViewDimensions } = state['features/filmstrip'];
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const { height } = tileViewDimensions.thumbnailSize; const { height } = tileViewDimensions.thumbnailSize;
const { columns } = tileViewDimensions; const { columns } = tileViewDimensions;

View File

@ -14,6 +14,7 @@ import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { Icon, IconMenuDown, IconMenuUp } from '../../../base/icons'; import { Icon, IconMenuDown, IconMenuUp } from '../../../base/icons';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { shouldHideSelfView } from '../../../base/settings/functions.any';
import { showToolbox } from '../../../toolbox/actions.web'; import { showToolbox } from '../../../toolbox/actions.web';
import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web'; import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web';
import { LAYOUTS, getCurrentLayout } from '../../../video-layout'; import { LAYOUTS, getCurrentLayout } from '../../../video-layout';
@ -26,7 +27,6 @@ import {
TOOLBAR_HEIGHT_MOBILE TOOLBAR_HEIGHT_MOBILE
} from '../../constants'; } from '../../constants';
import { shouldRemoteVideosBeVisible } from '../../functions'; import { shouldRemoteVideosBeVisible } from '../../functions';
import { getDisableSelfView } from '../../functions.any';
import AudioTracksContainer from './AudioTracksContainer'; import AudioTracksContainer from './AudioTracksContainer';
import Thumbnail from './Thumbnail'; import Thumbnail from './Thumbnail';
@ -580,7 +580,7 @@ function _mapStateToProps(state) {
thumbnailSize: tileViewThumbnailSize thumbnailSize: tileViewThumbnailSize
} = state['features/filmstrip'].tileViewDimensions; } = state['features/filmstrip'].tileViewDimensions;
const _currentLayout = getCurrentLayout(state); const _currentLayout = getCurrentLayout(state);
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const { clientHeight, clientWidth } = state['features/base/responsive-ui']; const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
const availableSpace = clientHeight - filmstripHeight; const availableSpace = clientHeight - filmstripHeight;

View File

@ -3,8 +3,8 @@ import React, { Component } from 'react';
import { shouldComponentUpdate } from 'react-window'; import { shouldComponentUpdate } from 'react-window';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { shouldHideSelfView } from '../../../base/settings/functions.any';
import { getCurrentLayout, LAYOUTS } from '../../../video-layout'; import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
import { getDisableSelfView } from '../../functions.any';
import Thumbnail from './Thumbnail'; import Thumbnail from './Thumbnail';
@ -118,7 +118,7 @@ function _mapStateToProps(state, ownProps) {
const { remote, local } = state['features/base/participants']; const { remote, local } = state['features/base/participants'];
const remoteParticipantsLength = remoteParticipants.length; const remoteParticipantsLength = remoteParticipants.length;
const { testing = {} } = state['features/base/config']; const { testing = {} } = state['features/base/config'];
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const enableThumbnailReordering = testing.enableThumbnailReordering ?? true; const enableThumbnailReordering = testing.enableThumbnailReordering ?? true;
if (_currentLayout === LAYOUTS.TILE_VIEW) { if (_currentLayout === LAYOUTS.TILE_VIEW) {

View File

@ -1,7 +1,5 @@
// @flow // @flow
import { getParticipantCount } from '../base/participants';
import { setRemoteParticipants } from './actions'; import { setRemoteParticipants } from './actions';
/** /**
@ -82,16 +80,3 @@ export function updateRemoteParticipantsOnLeave(store: Object, participantId: ?s
reorderedParticipants.delete(participantId) reorderedParticipants.delete(participantId)
&& store.dispatch(setRemoteParticipants(Array.from(reorderedParticipants))); && store.dispatch(setRemoteParticipants(Array.from(reorderedParticipants)));
} }
/**
* Gets the disable self view flag.
*
* @param {Object} state - Redux state.
* @returns {boolean}
*/
export function getDisableSelfView(state: Object) {
const { disableSelfView } = state['features/base/settings'];
const participantsCount = getParticipantCount(state);
return participantsCount === 1 ? false : disableSelfView;
}

View File

@ -4,6 +4,7 @@ import { isMobileBrowser } from '../base/environment/utils';
import { getParticipantCountWithFake } from '../base/participants'; import { getParticipantCountWithFake } from '../base/participants';
import { StateListenerRegistry, equals } from '../base/redux'; import { StateListenerRegistry, equals } from '../base/redux';
import { clientResized } from '../base/responsive-ui'; import { clientResized } from '../base/responsive-ui';
import { shouldHideSelfView } from '../base/settings';
import { setFilmstripVisible } from '../filmstrip/actions'; import { setFilmstripVisible } from '../filmstrip/actions';
import { getParticipantsPaneOpen } from '../participants-pane/functions'; import { getParticipantsPaneOpen } from '../participants-pane/functions';
import { setOverflowDrawer } from '../toolbox/actions.web'; import { setOverflowDrawer } from '../toolbox/actions.web';
@ -30,7 +31,7 @@ StateListenerRegistry.register(
/* selector */ state => { /* selector */ state => {
return { return {
numberOfParticipants: getParticipantCountWithFake(state), numberOfParticipants: getParticipantCountWithFake(state),
disableSelfView: state['features/base/settings'].disableSelfView disableSelfView: shouldHideSelfView(state)
}; };
}, },
/* listener */ (currentState, store) => { /* listener */ (currentState, store) => {

View File

@ -1 +0,0 @@
import './middleware.any';

View File

@ -1,40 +0,0 @@
/* @flow */
import { CONFERENCE_JOINED } from '../base/conference';
import { MiddlewareRegistry } from '../base/redux';
import { openSettingsDialog, SETTINGS_TABS } from '../settings';
import {
showNotification
} from './actions';
import { NOTIFICATION_TIMEOUT_TYPE } from './constants';
import './middleware.any';
/**
* Middleware that captures actions to display notifications.
*
* @param {Store} store - The redux store.
* @returns {Function}
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case CONFERENCE_JOINED: {
const { dispatch, getState } = store;
const { disableSelfView } = getState()['features/base/settings'];
if (disableSelfView) {
dispatch(showNotification({
titleKey: 'notify.selfViewTitle',
customActionNameKey: [ 'settings.title' ],
customActionHandler: [ () =>
dispatch(openSettingsDialog(SETTINGS_TABS.PROFILE))
]
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
}
break;
}
}
return next(action);
});

View File

@ -10,7 +10,6 @@ import {
import { openDialog } from '../base/dialog'; import { openDialog } from '../base/dialog';
import { i18next } from '../base/i18n'; import { i18next } from '../base/i18n';
import { updateSettings } from '../base/settings'; import { updateSettings } from '../base/settings';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
import { setPrejoinPageVisibility, setSkipPrejoinIsChanging } from '../prejoin/actions'; import { setPrejoinPageVisibility, setSkipPrejoinIsChanging } from '../prejoin/actions';
import { setScreenshareFramerate } from '../screen-share/actions'; import { setScreenshareFramerate } from '../screen-share/actions';
@ -26,8 +25,6 @@ import {
getSoundsTabProps getSoundsTabProps
} from './functions'; } from './functions';
import { SETTINGS_TABS } from '.';
declare var APP: Object; declare var APP: Object;
/** /**
@ -113,6 +110,10 @@ export function submitMoreTab(newState: Object): Function {
dispatch(setScreenshareFramerate(frameRate)); dispatch(setScreenshareFramerate(frameRate));
} }
if (newState.hideSelfView !== currentState.hideSelfView) {
dispatch(updateSettings({ disableSelfView: newState.hideSelfView }));
}
}; };
} }
@ -163,19 +164,6 @@ export function submitProfileTab(newState: Object): Function {
if (newState.email !== currentState.email) { if (newState.email !== currentState.email) {
APP.conference.changeLocalEmail(newState.email); APP.conference.changeLocalEmail(newState.email);
} }
if (newState.disableSelfView !== currentState.disableSelfView) {
dispatch(updateSettings({ disableSelfView: newState.disableSelfView }));
if (newState.disableSelfView) {
dispatch(showNotification({
titleKey: 'notify.selfViewTitle',
customActionNameKey: [ 'settings.title' ],
customActionHandler: [ () =>
dispatch(openSettingsDialog(SETTINGS_TABS.PROFILE))
]
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}
}
}; };
} }

View File

@ -35,6 +35,11 @@ export type Props = {
*/ */
desktopShareFramerates: Array<number>, desktopShareFramerates: Array<number>,
/**
* Whether to show hide self view setting.
*/
disableHideSelfView: boolean,
/** /**
* Whether or not follow me is currently active (enabled by some other participant). * Whether or not follow me is currently active (enabled by some other participant).
*/ */
@ -65,6 +70,11 @@ export type Props = {
*/ */
showPrejoinPage: boolean, showPrejoinPage: boolean,
/**
* Whether or not to hide self-view screen.
*/
hideSelfView: boolean,
/** /**
* Invoked to obtain translated strings. * Invoked to obtain translated strings.
*/ */
@ -114,6 +124,7 @@ class MoreTab extends AbstractDialogTab<Props, State> {
this._onLanguageItemSelect = this._onLanguageItemSelect.bind(this); this._onLanguageItemSelect = this._onLanguageItemSelect.bind(this);
this._onShowPrejoinPageChanged = this._onShowPrejoinPageChanged.bind(this); this._onShowPrejoinPageChanged = this._onShowPrejoinPageChanged.bind(this);
this._onKeyboardShortcutEnableChanged = this._onKeyboardShortcutEnableChanged.bind(this); this._onKeyboardShortcutEnableChanged = this._onKeyboardShortcutEnableChanged.bind(this);
this._onHideSelfViewChanged = this._onHideSelfViewChanged.bind(this);
} }
/** /**
@ -222,6 +233,19 @@ class MoreTab extends AbstractDialogTab<Props, State> {
super._onChange({ keyboardShortcutEnable: checked }); super._onChange({ keyboardShortcutEnable: checked });
} }
_onHideSelfViewChanged: (Object) => void;
/**
* Callback invoked to select if hide self view should be enabled.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onHideSelfViewChanged({ target: { checked } }) {
super._onChange({ hideSelfView: checked });
}
/** /**
* Returns the React Element for the desktop share frame rate dropdown. * Returns the React Element for the desktop share frame rate dropdown.
* *
@ -300,6 +324,31 @@ class MoreTab extends AbstractDialogTab<Props, State> {
); );
} }
/**
* Returns the React Element for self view setting.
*
* @private
* @returns {ReactElement}
*/
_renderSelfViewCheckbox() {
const { hideSelfView, t } = this.props;
return (
<div
className = 'settings-sub-pane-element'
key = 'selfview'>
<h2 className = 'mock-atlaskit-label'>
{ t('settings.selfView') }
</h2>
<Checkbox
isChecked = { hideSelfView }
label = { t('videothumbnail.hideSelfView') }
name = 'hide-self-view'
onChange = { this._onHideSelfViewChanged } />
</div>
);
}
/** /**
* Returns the menu item for changing displayed language. * Returns the menu item for changing displayed language.
* *
@ -404,7 +453,7 @@ class MoreTab extends AbstractDialogTab<Props, State> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
_renderSettingsLeft() { _renderSettingsLeft() {
const { showPrejoinSettings } = this.props; const { disableHideSelfView, showPrejoinSettings } = this.props;
return ( return (
<div <div
@ -412,6 +461,7 @@ class MoreTab extends AbstractDialogTab<Props, State> {
key = 'settings-sub-pane-left'> key = 'settings-sub-pane-left'>
{ showPrejoinSettings && this._renderPrejoinScreenSettings() } { showPrejoinSettings && this._renderPrejoinScreenSettings() }
{ this._renderKeyboardShortcutCheckbox() } { this._renderKeyboardShortcutCheckbox() }
{ !disableHideSelfView && this._renderSelfViewCheckbox() }
</div> </div>
); );
} }

View File

@ -1,7 +1,6 @@
// @flow // @flow
import Button from '@atlaskit/button/standard-button'; import Button from '@atlaskit/button/standard-button';
import Checkbox from '@atlaskit/checkbox';
import { FieldTextStateless } from '@atlaskit/field-text'; import { FieldTextStateless } from '@atlaskit/field-text';
import React from 'react'; import React from 'react';
@ -33,11 +32,6 @@ export type Props = {
*/ */
authLogin: string, authLogin: string,
/**
* Whether or not to hide the self view.
*/
disableSelfView: boolean,
/** /**
* The display name to display for the local participant. * The display name to display for the local participant.
*/ */
@ -88,7 +82,6 @@ class ProfileTab extends AbstractDialogTab<Props> {
this._onAuthToggle = this._onAuthToggle.bind(this); this._onAuthToggle = this._onAuthToggle.bind(this);
this._onDisplayNameChange = this._onDisplayNameChange.bind(this); this._onDisplayNameChange = this._onDisplayNameChange.bind(this);
this._onEmailChange = this._onEmailChange.bind(this); this._onEmailChange = this._onEmailChange.bind(this);
this._onChange = this._onChange.bind(this);
} }
_onDisplayNameChange: (Object) => void; _onDisplayNameChange: (Object) => void;
@ -117,19 +110,6 @@ class ProfileTab extends AbstractDialogTab<Props> {
super._onChange({ email: value }); super._onChange({ email: value });
} }
_onChange: (Object) => void;
/**
* Changes the disable self view state.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onChange({ target }) {
super._onChange({ disableSelfView: target.checked });
}
/** /**
* Implements React's {@link Component#render()}. * Implements React's {@link Component#render()}.
* *
@ -140,7 +120,6 @@ class ProfileTab extends AbstractDialogTab<Props> {
const { const {
authEnabled, authEnabled,
displayName, displayName,
disableSelfView,
email, email,
hideEmailInSettings, hideEmailInSettings,
readOnlyName, readOnlyName,
@ -175,12 +154,6 @@ class ProfileTab extends AbstractDialogTab<Props> {
value = { email } /> value = { email } />
</div>} </div>}
</div> </div>
<br />
<Checkbox
isChecked = { disableSelfView }
label = { t('videothumbnail.hideSelfView') }
name = 'disableSelfView'
onChange = { this._onChange } />
{ authEnabled && this._renderAuth() } { authEnabled && this._renderAuth() }
</div> </div>
); );

View File

@ -244,6 +244,7 @@ function _mapStateToProps(state) {
...newProps, ...newProps,
currentFramerate: tabState.currentFramerate, currentFramerate: tabState.currentFramerate,
currentLanguage: tabState.currentLanguage, currentLanguage: tabState.currentLanguage,
hideSelfView: tabState.hideSelfView,
showPrejoinPage: tabState.showPrejoinPage showPrejoinPage: tabState.showPrejoinPage
}; };
}, },

View File

@ -9,6 +9,7 @@ import {
isLocalParticipantModerator isLocalParticipantModerator
} from '../base/participants'; } from '../base/participants';
import { toState } from '../base/redux'; import { toState } from '../base/redux';
import { getHideSelfView } from '../base/settings';
import { parseStandardURIString } from '../base/util'; import { parseStandardURIString } from '../base/util';
import { isFollowMeActive } from '../follow-me'; import { isFollowMeActive } from '../follow-me';
import { isReactionsEnabled } from '../reactions/functions.any'; import { isReactionsEnabled } from '../reactions/functions.any';
@ -92,10 +93,15 @@ export function getMoreTabProps(stateful: Object | Function) {
const language = i18next.language || DEFAULT_LANGUAGE; const language = i18next.language || DEFAULT_LANGUAGE;
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || []; const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
// when self view is controlled by the config we hide the settings
const { disableSelfView, disableSelfViewSettings } = state['features/base/config'];
return { return {
currentFramerate: framerate, currentFramerate: framerate,
currentLanguage: language, currentLanguage: language,
desktopShareFramerates: SS_SUPPORTED_FRAMERATES, desktopShareFramerates: SS_SUPPORTED_FRAMERATES,
disableHideSelfView: disableSelfViewSettings || disableSelfView,
hideSelfView: getHideSelfView(state),
languages: LANGUAGES, languages: LANGUAGES,
showLanguageSettings: configuredTabs.includes('language'), showLanguageSettings: configuredTabs.includes('language'),
showPrejoinPage: !state['features/base/settings'].userSelectedSkipPrejoin, showPrejoinPage: !state['features/base/settings'].userSelectedSkipPrejoin,
@ -159,13 +165,11 @@ export function getProfileTabProps(stateful: Object | Function) {
} = state['features/base/conference']; } = state['features/base/conference'];
const { hideEmailInSettings } = state['features/base/config']; const { hideEmailInSettings } = state['features/base/config'];
const localParticipant = getLocalParticipant(state); const localParticipant = getLocalParticipant(state);
const { disableSelfView } = state['features/base/settings'];
return { return {
authEnabled: Boolean(conference && authEnabled), authEnabled: Boolean(conference && authEnabled),
authLogin, authLogin,
displayName: localParticipant.name, displayName: localParticipant.name,
disableSelfView: Boolean(disableSelfView),
email: localParticipant.email, email: localParticipant.email,
readOnlyName: isNameReadOnly(state), readOnlyName: isNameReadOnly(state),
hideEmailInSettings hideEmailInSettings

View File

@ -0,0 +1,30 @@
import { MiddlewareRegistry } from '../base/redux';
import { getHideSelfView, SETTINGS_UPDATED } from '../base/settings';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
import { openSettingsDialog } from './actions';
import { SETTINGS_TABS } from './constants';
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const oldValue = getHideSelfView(getState());
const result = next(action);
switch (action.type) {
case SETTINGS_UPDATED: {
const newValue = action.settings.disableSelfView;
if (newValue !== oldValue && newValue) {
dispatch(showNotification({
titleKey: 'notify.selfViewTitle',
customActionNameKey: [ 'settings.title' ],
customActionHandler: [ () =>
dispatch(openSettingsDialog(SETTINGS_TABS.MORE))
]
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}
}
}
return result;
});

View File

@ -8,6 +8,7 @@ import {
pinParticipant, pinParticipant,
getParticipantCountWithFake getParticipantCountWithFake
} from '../base/participants'; } from '../base/participants';
import { shouldHideSelfView } from '../base/settings/functions.any';
import { import {
ASPECT_RATIO_BREAKPOINT, ASPECT_RATIO_BREAKPOINT,
DEFAULT_MAX_COLUMNS, DEFAULT_MAX_COLUMNS,
@ -15,7 +16,6 @@ import {
SINGLE_COLUMN_BREAKPOINT, SINGLE_COLUMN_BREAKPOINT,
TWO_COLUMN_BREAKPOINT TWO_COLUMN_BREAKPOINT
} from '../filmstrip/constants'; } from '../filmstrip/constants';
import { getDisableSelfView } from '../filmstrip/functions.any';
import { isVideoPlaying } from '../shared-video/functions'; import { isVideoPlaying } from '../shared-video/functions';
import { LAYOUTS } from './constants'; import { LAYOUTS } from './constants';
@ -105,7 +105,7 @@ export function getTileViewGridDimensions(state: Object) {
// When in tile view mode, we must discount ourselves (the local participant) because our // When in tile view mode, we must discount ourselves (the local participant) because our
// tile is not visible. // tile is not visible.
const { iAmRecorder } = state['features/base/config']; const { iAmRecorder } = state['features/base/config'];
const disableSelfView = getDisableSelfView(state); const disableSelfView = shouldHideSelfView(state);
const numberOfParticipants = getParticipantCountWithFake(state) const numberOfParticipants = getParticipantCountWithFake(state)
- (iAmRecorder ? 1 : 0) - (iAmRecorder ? 1 : 0)
- (disableSelfView ? 1 : 0); - (disableSelfView ? 1 : 0);

View File

@ -5,9 +5,7 @@ import React, { PureComponent } from 'react';
import ContextMenuItem from '../../../base/components/context-menu/ContextMenuItem'; import ContextMenuItem from '../../../base/components/context-menu/ContextMenuItem';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { updateSettings } from '../../../base/settings'; import { getHideSelfView, updateSettings } from '../../../base/settings';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../../notifications';
import { openSettingsDialog, SETTINGS_TABS } from '../../../settings';
/** /**
* The type of the React {@code Component} props of {@link HideSelfViewVideoButton}. * The type of the React {@code Component} props of {@link HideSelfViewVideoButton}.
@ -97,15 +95,6 @@ class HideSelfViewVideoButton extends PureComponent<Props> {
dispatch(updateSettings({ dispatch(updateSettings({
disableSelfView: !disableSelfView disableSelfView: !disableSelfView
})); }));
if (!disableSelfView) {
dispatch(showNotification({
titleKey: 'notify.selfViewTitle',
customActionNameKey: [ 'settings.title' ],
customActionHandler: [ () =>
dispatch(openSettingsDialog(SETTINGS_TABS.PROFILE))
]
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}
} }
} }
@ -117,10 +106,8 @@ class HideSelfViewVideoButton extends PureComponent<Props> {
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state) {
const { disableSelfView } = state['features/base/config'];
return { return {
disableSelfView: Boolean(disableSelfView) disableSelfView: Boolean(getHideSelfView(state))
}; };
} }

View File

@ -15,6 +15,7 @@ import {
import { Popover } from '../../../base/popover'; import { Popover } from '../../../base/popover';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { setParticipantContextMenuOpen } from '../../../base/responsive-ui/actions'; import { setParticipantContextMenuOpen } from '../../../base/responsive-ui/actions';
import { getHideSelfView } from '../../../base/settings';
import { getLocalVideoTrack } from '../../../base/tracks'; import { getLocalVideoTrack } from '../../../base/tracks';
import ConnectionIndicatorContent from '../../../connection-indicator/components/web/ConnectionIndicatorContent'; import ConnectionIndicatorContent from '../../../connection-indicator/components/web/ConnectionIndicatorContent';
import { getCurrentLayout, LAYOUTS } from '../../../video-layout'; import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
@ -82,6 +83,11 @@ type Props = {
*/ */
_showConnectionInfo: boolean, _showConnectionInfo: boolean,
/**
* Whether to render the hide self view button.
*/
_showHideSelfViewButton: boolean,
/** /**
* Shows/hides the local video flip button. * Shows/hides the local video flip button.
*/ */
@ -148,8 +154,9 @@ class LocalVideoMenuTriggerButton extends Component<Props> {
const { const {
_localParticipantId, _localParticipantId,
_menuPosition, _menuPosition,
_showConnectionInfo,
_overflowDrawer, _overflowDrawer,
_showConnectionInfo,
_showHideSelfViewButton,
_showLocalVideoFlipButton, _showLocalVideoFlipButton,
buttonVisible, buttonVisible,
classes, classes,
@ -169,9 +176,11 @@ class LocalVideoMenuTriggerButton extends Component<Props> {
<FlipLocalVideoButton <FlipLocalVideoButton
className = { _overflowDrawer ? classes.flipText : '' } className = { _overflowDrawer ? classes.flipText : '' }
onClick = { hidePopover } /> onClick = { hidePopover } />
<HideSelfViewVideoButton { _showHideSelfViewButton
className = { _overflowDrawer ? classes.flipText : '' } && <HideSelfViewVideoButton
onClick = { hidePopover } /> className = { _overflowDrawer ? classes.flipText : '' }
onClick = { hidePopover } />
}
{ isMobileBrowser() { isMobileBrowser()
&& <ConnectionStatusButton participantId = { _localParticipantId } /> && <ConnectionStatusButton participantId = { _localParticipantId } />
} }
@ -249,10 +258,11 @@ class LocalVideoMenuTriggerButton extends Component<Props> {
function _mapStateToProps(state) { function _mapStateToProps(state) {
const currentLayout = getCurrentLayout(state); const currentLayout = getCurrentLayout(state);
const localParticipant = getLocalParticipant(state); const localParticipant = getLocalParticipant(state);
const { disableLocalVideoFlip } = state['features/base/config']; const { disableLocalVideoFlip, disableSelfViewSettings } = state['features/base/config'];
const videoTrack = getLocalVideoTrack(state['features/base/tracks']); const videoTrack = getLocalVideoTrack(state['features/base/tracks']);
const { overflowDrawer } = state['features/toolbox']; const { overflowDrawer } = state['features/toolbox'];
const { showConnectionInfo } = state['features/base/connection']; const { showConnectionInfo } = state['features/base/connection'];
const showHideSelfViewButton = !disableSelfViewSettings && !getHideSelfView(state);
let _menuPosition; let _menuPosition;
@ -273,6 +283,7 @@ function _mapStateToProps(state) {
return { return {
_menuPosition, _menuPosition,
_showLocalVideoFlipButton: !disableLocalVideoFlip && videoTrack?.videoType !== 'desktop', _showLocalVideoFlipButton: !disableLocalVideoFlip && videoTrack?.videoType !== 'desktop',
_showHideSelfViewButton: showHideSelfViewButton,
_overflowDrawer: overflowDrawer, _overflowDrawer: overflowDrawer,
_localParticipantId: localParticipant.id, _localParticipantId: localParticipant.id,
_showConnectionInfo: showConnectionInfo _showConnectionInfo: showConnectionInfo