Compare commits

...

25 Commits

Author SHA1 Message Date
Hristo Terezov
329c7258e4 fix(horizontal-filmstrip): JS error.
Fixes the following JS error which prevents the whole page from
rendering:
TypeError: Cannot read properties of null (reading 'offsetHeight')
2023-06-20 09:34:44 -05:00
Horatiu Muresan
e5f019249d fix(toolbar) Fix auto-hide toolbar in tileview (#13424) 2023-06-06 15:37:43 +03:00
Horatiu Muresan
78d472799f aesthetics 2023-05-19 10:09:07 -05:00
Horatiu Muresan
0c680ba84b fix(toolbox-visible) Fix hiding toolbox
- clicking toolbox button was keeping focus on toolbox even after mouse move(as focus would only be changed when clicking on some other element), so .toolbox-content-items:focus-within selector was returning a value even when mouse was moved from toolbox
- .filmstrip:focus-within did not seem to ever activate, I replaced with :hover since the intent was probably to keep the toolbox open while filmstrip is hovered
2023-05-19 10:08:50 -05:00
Jaya Allamsetty
66342a0d15 chore(deps) Update lib-jitsi-meet.
f4f79798d9
Fixes spot screenshare issue.
2023-05-18 16:50:28 -04:00
Hristo Terezov
d491f45802 fix(web-hid): Fully disable from config 2023-05-18 14:03:28 -05:00
Robert Pintilii
82edeac963 ref(self-view) Move Hide self view to General tab (#13339)
# Conflicts:
#	react/features/settings/components/web/ProfileTab.tsx
#	react/features/settings/functions.any.ts
2023-05-15 16:37:59 +03:00
Horatiu Muresan
47bd8f6b15 fix(toolbar-buttons) Hide rec and livestream buttons for non-moderators (#13328) 2023-05-08 19:31:32 +03:00
damencho
baf1f04542 feat: Updates unsupported desktop to tsx.
Easier to apply branding.
2023-05-05 12:46:25 -05:00
George Politis
c32890f9c9 Update RTCStats.ts
Addresses an issue where the client is sending malformed stats messages to the server.

Introduced in 78ce68160a .
2023-05-05 14:17:08 +01:00
damencho
2ea67190cb fix(chat): Fixes long display name that overflow the message bubble. 2023-05-03 15:36:14 -05:00
damencho
d1ce52e6bd fix(chat): White square when both scrolls are visible. 2023-05-03 15:36:07 -05:00
damencho
f5e79f4ace Revert "fix(chat) Make the name fit the chat bubble"
This reverts commit e56c7070c2.
2023-05-03 15:36:02 -05:00
Horatiu Muresan
3ae7327633 fix(dial-in) Place PIN on a new line (#13309) 2023-05-02 10:14:18 -05:00
robertpin
5ced8c123b fix(keyboard-a11y) Remove space from click trigger 2023-05-01 16:51:45 +02:00
damencho
c119272447 fix: Hide virtual background for unsupported browsers from vide preview. 2023-04-27 12:43:39 -05:00
robertpin
8e7b44418e fix(dialog) Fix close animation moves whole body 2023-04-27 12:40:14 -05:00
robertpin
693c4066bf fix(chat) Make the name fit the chat bubble 2023-04-27 12:40:00 -05:00
damencho
d122c775e9 fix: Fixes unresolved function. 2023-04-27 12:39:52 -05:00
Robert Pintilii
1ca1ea146a fix(chat) Focus input on chat open (#13285) 2023-04-27 12:39:41 -05:00
Gabriel Borlea
0fe28b4634 fix: multiselect for invite people (#13287)
* fix: multiselect duplicates

* set multiselect height to 200px
2023-04-27 19:41:45 +03:00
Jaya Allamsetty
d69d479409 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1623.0.0+c520877a...v1624.0.0+e3a8472f
2023-04-26 13:34:46 -04:00
Mihaela Dumitru
9f4faae7a6 feat(external-api) support assumed bandwidth bps command + ljm update (#13275) 2023-04-26 17:48:59 +03:00
robertpin
6b9f234b30 fix(dial-in) Make text selectable on Dial In page 2023-04-25 19:44:44 -05:00
Robert Pintilii
3096071bb3 fix(toolbar) Remove focus on hide (#13256) 2023-04-25 17:01:47 +02:00
32 changed files with 169 additions and 77 deletions

View File

@@ -74,6 +74,10 @@
a:active {
color: black;
}
&::-webkit-scrollbar-corner {
background: #3a3a3a;
}
}

View File

@@ -108,6 +108,10 @@
#largeVideoContainer {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
margin: 0 !important;
}
#largeVideoWrapper {

View File

@@ -57,6 +57,10 @@
line-height: 24px;
border-collapse: collapse;
* {
user-select: text;
}
thead {
text-align: left;
}

View File

@@ -115,7 +115,11 @@ import { muteAllParticipants } from '../../react/features/video-menu/actions';
import { setVideoQuality } from '../../react/features/video-quality/actions';
import { getJitsiMeetTransport } from '../transport';
import { API_ID, ENDPOINT_TEXT_MESSAGE_NAME } from './constants';
import {
API_ID,
ASSUMED_BANDWIDTH_BPS,
ENDPOINT_TEXT_MESSAGE_NAME
} from './constants';
const logger = Logger.getLogger(__filename);
@@ -310,6 +314,23 @@ function initCommands() {
APP.store.dispatch(sendTones(tones, duration, pause));
},
'set-assumed-bandwidth-bps': value => {
logger.debug('Set assumed bandwidth bps command received', value);
if (typeof value !== 'number' || isNaN(value)) {
logger.error('Assumed bandwidth bps must be a number.');
return;
}
const { conference } = APP.store.getState()['features/base/conference'];
if (conference) {
conference.setAssumedBandwidthBps(value < ASSUMED_BANDWIDTH_BPS
? ASSUMED_BANDWIDTH_BPS
: value);
}
},
'set-follow-me': value => {
logger.debug('Set follow me command received');

View File

@@ -15,3 +15,10 @@ export const API_ID = parseURLParams(window.location).jitsi_meet_external_api_id
* The payload name for the datachannel/endpoint text message event.
*/
export const ENDPOINT_TEXT_MESSAGE_NAME = 'endpoint-text-message';
/**
* The min value that can be set for the assumed bandwidth.
* Setting it to this value means not assuming any bandwidth,
* but rather allowing the estimations to take place.
*/
export const ASSUMED_BANDWIDTH_BPS = -1;

View File

@@ -59,6 +59,7 @@ const commands = {
sendEndpointTextMessage: 'send-endpoint-text-message',
sendParticipantToRoom: 'send-participant-to-room',
sendTones: 'send-tones',
setAssumedBandwidthBps: 'set-assumed-bandwidth-bps',
setFollowMe: 'set-follow-me',
setLargeVideoParticipant: 'set-large-video-participant',
setMediaEncryptionKey: 'set-media-encryption-key',

View File

@@ -11,11 +11,11 @@ import { setColorAlpha } from '../../react/features/base/util/helpers';
import { setDocumentUrl } from '../../react/features/etherpad/actions';
import { setFilmstripVisible } from '../../react/features/filmstrip/actions.any';
import {
joinLeaveNotificationsDisabled,
setNotificationsEnabled,
showNotification
} from '../../react/features/notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../react/features/notifications/constants';
import { joinLeaveNotificationsDisabled } from '../../react/features/notifications/functions';
import {
dockToolbox,
setToolboxEnabled,

View File

@@ -15,7 +15,7 @@ const Filmstrip = {
// horizontal film strip mode for calculating how tall large video
// display should be.
if (isFilmstripVisible(APP.store) && !interfaceConfig.VERTICAL_FILMSTRIP) {
return document.querySelector('.filmstrip').offsetHeight;
return document.querySelector('.filmstrip')?.offsetHeight ?? 0;
}
return 0;

11
package-lock.json generated
View File

@@ -68,7 +68,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1620.0.0+7f0012f7/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet#f4f79798d9636859bff821fe0e99ca4123507eb1",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -13388,8 +13388,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1620.0.0+7f0012f7/lib-jitsi-meet.tgz",
"integrity": "sha512-F3vOUwD/ys5dGtswR3C5IK8JPDOG+71J+nhkEDLotkni/Zws8KHzf8Ye332UuetUjCTGJP3CbRFe9yJdYERe7g==",
"resolved": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#f4f79798d9636859bff821fe0e99ca4123507eb1",
"integrity": "sha512-1VuyMlI2VF782MFomtwRYFq0uELoVKlPiK5xxdjjXnsTkEeMPqYt5JmatMVRHqu/3xGCGvHLGy5ImZqwXDDi2g==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -30454,8 +30454,9 @@
}
},
"lib-jitsi-meet": {
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1620.0.0+7f0012f7/lib-jitsi-meet.tgz",
"integrity": "sha512-F3vOUwD/ys5dGtswR3C5IK8JPDOG+71J+nhkEDLotkni/Zws8KHzf8Ye332UuetUjCTGJP3CbRFe9yJdYERe7g==",
"version": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#f4f79798d9636859bff821fe0e99ca4123507eb1",
"integrity": "sha512-1VuyMlI2VF782MFomtwRYFq0uELoVKlPiK5xxdjjXnsTkEeMPqYt5JmatMVRHqu/3xGCGvHLGy5ImZqwXDDi2g==",
"from": "lib-jitsi-meet@https://github.com/jitsi/lib-jitsi-meet#f4f79798d9636859bff821fe0e99ca4123507eb1",
"requires": {
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",

View File

@@ -73,7 +73,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1620.0.0+7f0012f7/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet#f4f79798d9636859bff821fe0e99ca4123507eb1",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -183,7 +183,7 @@
},
"overrides": {
"strophe.js@1.6.0": {
"@xmldom/xmldom": "0.8.7"
"@xmldom/xmldom": "0.8.7"
}
},
"engines": {

View File

@@ -104,6 +104,7 @@ export interface IJitsiConference {
sendTextMessage: Function;
sendTones: Function;
sessionId: string;
setAssumedBandwidthBps: (value: number) => void;
setDesktopSharingFrameRate: Function;
setDisplayName: Function;
setLocalParticipantProperty: Function;

View File

@@ -163,7 +163,7 @@ class MultiSelectAutocomplete extends Component<IProps, IState> {
const autoFocus = this.props.shouldFocus || false;
const disabled = this.props.isDisabled || false;
const placeholder = this.props.placeholder || '';
const noMatchesFound = this.props.noMatchesFound || '';
const noMatchesFound = this.state.loading ? this.props.loadingMessage : this.props.noMatchesFound || '';
const errorDialog = this._renderError();
return (
@@ -200,7 +200,7 @@ class MultiSelectAutocomplete extends Component<IProps, IState> {
error: this.state.error && Boolean(filterValue),
filterValue,
isOpen: Boolean(this.state.items.length) && Boolean(filterValue),
items: filterValue ? this.state.items : [],
items: [],
loading: Boolean(filterValue)
});
if (filterValue) {

View File

@@ -43,7 +43,7 @@ export default class ToolboxItem extends AbstractToolboxItem<IProps> {
* @returns {void}
*/
_onKeyPress(event?: React.KeyboardEvent) {
if (event?.key === 'Enter' || event?.key === ' ') {
if (event?.key === 'Enter') {
event.preventDefault();
this.props.onClick();
}

View File

@@ -24,6 +24,8 @@ interface IProps {
selectedItems?: MultiSelectItem[];
}
const MULTI_SELECT_HEIGHT = 200;
const useStyles = makeStyles()(theme => {
return {
container: {
@@ -41,7 +43,7 @@ const useStyles = makeStyles()(theme => {
borderRadius: `${Number(theme.shape.borderRadius)}px`,
...withPixelLineHeight(theme.typography.bodyShortRegular),
zIndex: 2,
maxHeight: '400px',
maxHeight: `${MULTI_SELECT_HEIGHT}px`,
overflowY: 'auto',
padding: '0'
},
@@ -128,7 +130,7 @@ const MultiSelect = ({
</div>
</div>
))
: <div>{noMatchesText}</div>
: <div className = { classes.listItem }>{noMatchesText}</div>
}
</div>
), [ items ]);

View File

@@ -90,6 +90,8 @@ class ChatInput extends Component<IProps, IState> {
if (isMobileBrowser()) {
// Ensure textarea is not focused when opening chat on mobile browser.
this._textArea?.current && this._textArea.current.blur();
} else {
this._focus();
}
}

View File

@@ -29,9 +29,9 @@ const styles = (theme: Theme) => {
chatMessage: {
display: 'inline-flex',
padding: '12px',
marginRight: '12px',
backgroundColor: theme.palette.ui02,
borderRadius: '4px 12px 12px 12px',
boxSizing: 'border-box' as const,
maxWidth: '100%',
marginTop: '4px',

View File

@@ -97,7 +97,7 @@ class DialInNumber extends Component<IProps> {
{ phoneNumber }
</span>
</span>
<span className = 'spacer'>&nbsp;</span>
<br />
<span className = 'conference-id'>
<span className = 'info-label'>
{ t('info.dialInConferenceID') }

View File

@@ -31,7 +31,11 @@ const useStyles = makeStyles()((theme: Theme) => {
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
borderRadius: 6
borderRadius: 6,
'& *': {
userSelect: 'text'
}
},
confNameLabel: {
...withPixelLineHeight(theme.typography.heading6),

View File

@@ -459,12 +459,14 @@ export function isDialOutEnabled(state: IReduxState): boolean {
* Determines if inviting sip endpoints is enabled or not.
*
* @param {IReduxState} state - Current state.
* @returns {boolean} Indication of whether dial out is currently enabled.
* @returns {boolean} Indication of whether sip invite is currently enabled.
*/
export function isSipInviteEnabled(state: IReduxState): boolean {
const { sipInviteUrl } = state['features/base/config'];
return isJwtFeatureEnabled(state, 'sip-outbound-call') && Boolean(sipInviteUrl);
return isLocalParticipantModerator(state)
&& isJwtFeatureEnabled(state, 'sip-outbound-call')
&& Boolean(sipInviteUrl);
}
/**

View File

@@ -131,8 +131,11 @@ export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
const isModerator = isLocalParticipantModerator(state);
const liveStreaming = getLiveStreaming(state);
visible = isModerator && liveStreaming.enabled;
visible = isJwtFeatureEnabled(state, 'livestreaming', visible);
if (isModerator) {
visible = liveStreaming.enabled ? isJwtFeatureEnabled(state, 'livestreaming', true) : false;
} else {
visible = false;
}
}
// disable the button if the recording is running.

View File

@@ -171,9 +171,13 @@ export function getRecordButtonProps(state: IReduxState) {
const localRecordingEnabled = !localRecording?.disable && supportsLocalRecording();
const dropboxEnabled = isDropboxEnabled(state);
const recordingEnabled = recordingService?.enabled || localRecordingEnabled || dropboxEnabled;
visible = isModerator && (recordingService?.enabled || localRecordingEnabled || dropboxEnabled);
visible = isJwtFeatureEnabled(state, 'recording', visible);
if (isModerator) {
visible = recordingEnabled ? isJwtFeatureEnabled(state, 'recording', true) : false;
} else {
visible = false;
}
// disable the button if the livestreaming is running.
if (visible && getActiveSession(state, JitsiRecordingConstants.mode.STREAM)) {

View File

@@ -84,7 +84,7 @@ class RTCStats {
* @returns {void}
*/
statsEntry(...data: any[]) {
this.trace?.statsEntry(data);
this.trace?.statsEntry(...data);
}
/**

View File

@@ -103,6 +103,10 @@ export function submitMoreTab(newState: any) {
if (newState.maxStageParticipants !== currentState.maxStageParticipants) {
dispatch(updateSettings({ maxStageParticipants: Number(newState.maxStageParticipants) }));
}
if (newState.hideSelfView !== currentState.hideSelfView) {
dispatch(updateSettings({ disableSelfView: newState.hideSelfView }));
}
};
}
@@ -154,10 +158,6 @@ export function submitProfileTab(newState: any) {
APP.conference.changeLocalEmail(newState.email);
}
if (newState.hideSelfView !== currentState.hideSelfView) {
dispatch(updateSettings({ disableSelfView: newState.hideSelfView }));
}
if (newState.currentLanguage !== currentState.currentLanguage) {
i18next.changeLanguage(newState.currentLanguage);
}

View File

@@ -22,11 +22,26 @@ export interface IProps extends AbstractDialogTabProps, WithTranslation {
*/
classes: any;
/**
* Whether to show hide self view setting.
*/
disableHideSelfView: boolean;
/**
* Whether or not follow me is currently active (enabled by some other participant).
*/
followMeActive: boolean;
/**
* Whether or not to hide self-view screen.
*/
hideSelfView: boolean;
/**
* Whether we are in visitors mode.
*/
iAmVisitor: boolean;
/**
* The number of max participants to display on stage.
*/
@@ -66,6 +81,10 @@ const styles = (theme: Theme) => {
height: '1px',
border: 0,
backgroundColor: theme.palette.ui03
},
checkbox: {
margin: `${theme.spacing(3)} 0`
}
};
};
@@ -89,6 +108,7 @@ class MoreTab extends AbstractDialogTab<IProps, any> {
this._onShowPrejoinPageChanged = this._onShowPrejoinPageChanged.bind(this);
this._renderMaxStageParticipantsSelect = this._renderMaxStageParticipantsSelect.bind(this);
this._onMaxStageParticipantsSelect = this._onMaxStageParticipantsSelect.bind(this);
this._onHideSelfViewChanged = this._onHideSelfViewChanged.bind(this);
}
/**
@@ -98,7 +118,7 @@ class MoreTab extends AbstractDialogTab<IProps, any> {
* @returns {ReactElement}
*/
render() {
const { showPrejoinSettings, classes } = this.props;
const { showPrejoinSettings, classes, disableHideSelfView, iAmVisitor, hideSelfView, t } = this.props;
return (
<div
@@ -109,6 +129,14 @@ class MoreTab extends AbstractDialogTab<IProps, any> {
<hr className = { classes.divider } />
</>}
{this._renderMaxStageParticipantsSelect()}
{!disableHideSelfView && !iAmVisitor && (
<Checkbox
checked = { hideSelfView }
className = { classes.checkbox }
label = { t('videothumbnail.hideSelfView') }
name = 'hide-self-view'
onChange = { this._onHideSelfViewChanged } />
)}
</div>
);
}
@@ -138,6 +166,17 @@ class MoreTab extends AbstractDialogTab<IProps, any> {
super._onChange({ maxStageParticipants: maxParticipants });
}
/**
* Callback invoked to select if hide self view should be enabled.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onHideSelfViewChanged({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) {
super._onChange({ hideSelfView: checked });
}
/**
* Returns the React Element for modifying prejoin screen settings.
*

View File

@@ -13,7 +13,6 @@ import AbstractDialogTab, {
import { translate } from '../../../base/i18n/functions';
import { withPixelLineHeight } from '../../../base/styles/functions.web';
import Button from '../../../base/ui/components/web/Button';
import Checkbox from '../../../base/ui/components/web/Checkbox';
import Input from '../../../base/ui/components/web/Input';
import Select from '../../../base/ui/components/web/Select';
import { openLogoutDialog } from '../../actions';
@@ -44,11 +43,6 @@ export interface IProps extends AbstractDialogTabProps, WithTranslation {
*/
currentLanguage: string;
/**
* Whether to show hide self view setting.
*/
disableHideSelfView: boolean;
/**
* The display name to display for the local participant.
*/
@@ -64,11 +58,6 @@ export interface IProps extends AbstractDialogTabProps, WithTranslation {
*/
hideEmailInSettings?: boolean;
/**
* Whether or not to hide self-view screen.
*/
hideSelfView: boolean;
/**
* The id of the local participant.
*/
@@ -146,7 +135,6 @@ class ProfileTab extends AbstractDialogTab<IProps, any> {
this._onAuthToggle = this._onAuthToggle.bind(this);
this._onDisplayNameChange = this._onDisplayNameChange.bind(this);
this._onEmailChange = this._onEmailChange.bind(this);
this._onHideSelfViewChanged = this._onHideSelfViewChanged.bind(this);
this._onLanguageItemSelect = this._onLanguageItemSelect.bind(this);
}
@@ -172,17 +160,6 @@ class ProfileTab extends AbstractDialogTab<IProps, any> {
super._onChange({ email: value });
}
/**
* Callback invoked to select if hide self view should be enabled.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onHideSelfViewChanged({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) {
super._onChange({ hideSelfView: checked });
}
/**
* Callback invoked to select a language from select dropdown.
*
@@ -238,11 +215,9 @@ class ProfileTab extends AbstractDialogTab<IProps, any> {
const {
authEnabled,
classes,
disableHideSelfView,
displayName,
email,
hideEmailInSettings,
hideSelfView,
id,
readOnlyName,
showLanguageSettings,
@@ -277,14 +252,6 @@ class ProfileTab extends AbstractDialogTab<IProps, any> {
type = 'text'
value = { email } />
</div>}
{!disableHideSelfView && (
<Checkbox
checked = { hideSelfView }
className = { classes.bottomMargin }
label = { t('videothumbnail.hideSelfView') }
name = 'hide-self-view'
onChange = { this._onHideSelfViewChanged } />
)}
{showLanguageSettings && this._renderLanguageSelect()}
{ authEnabled && this._renderAuth() }
</div>

View File

@@ -13,6 +13,7 @@ import Checkbox from '../../../../base/ui/components/web/Checkbox';
import ContextMenu from '../../../../base/ui/components/web/ContextMenu';
import ContextMenuItem from '../../../../base/ui/components/web/ContextMenuItem';
import ContextMenuItemGroup from '../../../../base/ui/components/web/ContextMenuItemGroup';
import { checkBlurSupport } from '../../../../virtual-background/functions';
import { openSettingsDialog } from '../../../actions';
import { SETTINGS_TABS } from '../../../constants';
import { createLocalVideoTracks } from '../../../functions.web';
@@ -286,6 +287,8 @@ const VideoSettingsContent = ({
}
}, [ videoDeviceIds ]);
const virtualBackgroundSupported = checkBlurSupport();
return (
<ContextMenu
aria-labelledby = 'video-settings-button'
@@ -298,11 +301,11 @@ const VideoSettingsContent = ({
{trackData.map((data, i) => _renderPreviewEntry(data, i))}
</ContextMenuItemGroup>
<ContextMenuItemGroup>
<ContextMenuItem
{ virtualBackgroundSupported && <ContextMenuItem
accessibilityLabel = 'virtualBackground.title'
icon = { IconImage }
onClick = { selectBackground }
text = { t('virtualBackground.title') } />
text = { t('virtualBackground.title') } /> }
<div
className = { classes.checkboxContainer }
onClick = { stopPropagation }>

View File

@@ -16,6 +16,7 @@ import { isStageFilmstripEnabled } from '../filmstrip/functions';
import { isFollowMeActive } from '../follow-me/functions';
import { getParticipantsPaneConfig } from '../participants-pane/functions';
import { isReactionsEnabled } from '../reactions/functions.any';
import { iAmVisitor } from '../visitors/functions';
/**
* Used for web. Indicates if the setting section is enabled.
@@ -116,7 +117,13 @@ export function getMoreTabProps(stateful: IStateful) {
const state = toState(stateful);
const stageFilmstripEnabled = isStageFilmstripEnabled(state);
// when self view is controlled by the config we hide the settings
const { disableSelfView, disableSelfViewSettings } = state['features/base/config'];
return {
disableHideSelfView: disableSelfViewSettings || disableSelfView,
hideSelfView: getHideSelfView(state),
iAmVisitor: iAmVisitor(state),
showPrejoinPage: !state['features/base/settings'].userSelectedSkipPrejoin,
showPrejoinSettings: state['features/base/config'].prejoinConfig?.enabled,
maxStageParticipants: state['features/base/settings'].maxStageParticipants,
@@ -193,18 +200,13 @@ export function getProfileTabProps(stateful: IStateful) {
const language = i18next.language || DEFAULT_LANGUAGE;
const configuredTabs: string[] = interfaceConfig.SETTINGS_SECTIONS || [];
// when self view is controlled by the config we hide the settings
const { disableSelfView, disableSelfViewSettings } = state['features/base/config'];
return {
authEnabled: Boolean(conference && authEnabled),
authLogin,
disableHideSelfView: disableSelfViewSettings || disableSelfView,
currentLanguage: language,
displayName: localParticipant?.name,
email: localParticipant?.email,
hideEmailInSettings,
hideSelfView: getHideSelfView(state),
id: localParticipant?.id,
languages: LANGUAGES,
readOnlyName: isNameReadOnly(state),

View File

@@ -22,7 +22,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
titleKey: 'notify.selfViewTitle',
customActionNameKey: [ 'settings.title' ],
customActionHandler: [ () =>
dispatch(openSettingsDialog(SETTINGS_TABS.PROFILE))
dispatch(openSettingsDialog(SETTINGS_TABS.MORE))
]
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}

View File

@@ -1,6 +1,7 @@
import { IStore } from '../app/types';
import { overwriteConfig } from '../base/config/actions';
import { isMobileBrowser } from '../base/environment/utils';
import { isLayoutTileView } from '../video-layout/functions.any';
import {
CLEAR_TOOLBOX_TIMEOUT,
@@ -84,13 +85,16 @@ export function hideToolbox(force = false) {
dispatch(clearToolboxTimeout());
const focusSelector = '.toolbox-content-items:focus-within,.filmstrip:focus-within,.remotevideomenu:hover';
const hoverSelector = isLayoutTileView(state)
? '.remotevideomenu:hover'
: '.filmstrip:hover,.remotevideomenu:hover';
const hoveredElem = document.querySelector(hoverSelector);
if (!force
&& (hovered
|| state['features/invite'].calleeInfoVisible
|| (state['features/chat'].isOpen && !autoHideWhileChatIsOpen)
|| document.querySelector(focusSelector))) {
|| hoveredElem)) {
dispatch(
setToolboxTimeout(
() => dispatch(hideToolbox()),

View File

@@ -1,5 +1,5 @@
import { withStyles } from '@mui/styles';
import React, { Component } from 'react';
import React, { Component, RefObject } from 'react';
import { WithTranslation } from 'react-i18next';
import { batch, connect } from 'react-redux';
@@ -359,6 +359,8 @@ const styles = () => {
* @augments Component
*/
class Toolbox extends Component<IProps> {
_toolboxRef: RefObject<HTMLDivElement>;
/**
* Initializes a new {@code Toolbox} instance.
*
@@ -368,6 +370,8 @@ class Toolbox extends Component<IProps> {
constructor(props: IProps) {
super(props);
this._toolboxRef = React.createRef();
// Bind event handlers so they are only bound once per instance.
this._onMouseOut = this._onMouseOut.bind(this);
this._onMouseOver = this._onMouseOver.bind(this);
@@ -506,7 +510,6 @@ class Toolbox extends Component<IProps> {
componentDidUpdate(prevProps: IProps) {
const { _dialog, _visible, dispatch } = this.props;
if (prevProps._overflowMenuVisible
&& !prevProps._dialog
&& _dialog) {
@@ -519,6 +522,13 @@ class Toolbox extends Component<IProps> {
this._onSetHangupVisible(false);
dispatch(setToolbarHovered(false));
}
if (!_visible && prevProps._visible !== _visible) {
if (document.activeElement instanceof HTMLElement
&& this._toolboxRef.current?.contains(document.activeElement)) {
document.activeElement.blur();
}
}
}
/**
@@ -1415,7 +1425,9 @@ class Toolbox extends Component<IProps> {
onMouseOver: this._onMouseOver
}) }>
<div className = 'toolbox-content-items'>
<div
className = 'toolbox-content-items'
ref = { this._toolboxRef }>
{mainMenuButtons.map(({ Content, key, ...rest }) => Content !== Separator && (
<Content
{ ...rest }

View File

@@ -1,5 +1,6 @@
import { IStore } from '../app/types';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
import { getWebHIDFeatureConfig } from '../base/config/functions.web';
import { SET_AUDIO_MUTED } from '../base/media/actionTypes';
import { isAudioMuted } from '../base/media/functions';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
@@ -33,7 +34,11 @@ let updateDeviceListener: (e: any) => void;
* @returns {Function}
*/
MiddlewareRegistry.register((store: IStore) => next => async action => {
const { dispatch } = store;
const { dispatch, getState } = store;
if (!getWebHIDFeatureConfig(getState())) {
return next(action);
}
switch (action.type) {
case APP_WILL_MOUNT: {