feat(welcome-page): be able to open settings dialog (#3327)
* feat(welcome-page): be able to open settings dialog - Create a getter for getting a settings tab's props so the device selection tab can get updated available devices. - Be able to call a function from a tab after it has mounted. This is used for device selection to essentially call enumerateDevices on the welcome page so the device selectors are populated. - Remove event UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED. Instead directly call setAudioOutputDeviceId where possible. - Fix initialization of the audioOutputDeviceId in settings by defaulting the audio output device to the one set in settings. * squash: updateAvailableDevices -> getAvailableDevices, add comment for propsUpdateFunction
This commit is contained in:
parent
81853d971a
commit
cac8888b37
|
@ -45,6 +45,7 @@ import {
|
||||||
setDesktopSharingEnabled
|
setDesktopSharingEnabled
|
||||||
} from './react/features/base/conference';
|
} from './react/features/base/conference';
|
||||||
import {
|
import {
|
||||||
|
getAvailableDevices,
|
||||||
setAudioOutputDeviceId,
|
setAudioOutputDeviceId,
|
||||||
updateDeviceList
|
updateDeviceList
|
||||||
} from './react/features/base/devices';
|
} from './react/features/base/devices';
|
||||||
|
@ -2129,20 +2130,6 @@ export default {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
APP.UI.addListener(
|
|
||||||
UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED,
|
|
||||||
audioOutputDeviceId => {
|
|
||||||
sendAnalytics(createDeviceChangedEvent('audio', 'output'));
|
|
||||||
setAudioOutputDeviceId(audioOutputDeviceId, APP.store.dispatch)
|
|
||||||
.then(() => logger.log('changed audio output device'))
|
|
||||||
.catch(err => {
|
|
||||||
logger.warn('Failed to change audio output device. '
|
|
||||||
+ 'Default or previously set audio output device '
|
|
||||||
+ 'will be used instead.', err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
APP.UI.addListener(UIEvents.TOGGLE_AUDIO_ONLY, audioOnly => {
|
APP.UI.addListener(UIEvents.TOGGLE_AUDIO_ONLY, audioOnly => {
|
||||||
|
|
||||||
// FIXME On web video track is stored both in redux and in
|
// FIXME On web video track is stored both in redux and in
|
||||||
|
@ -2314,39 +2301,43 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Inits list of current devices and event listener for device change.
|
* Inits list of current devices and event listener for device change.
|
||||||
* @private
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
_initDeviceList() {
|
_initDeviceList() {
|
||||||
const { mediaDevices } = JitsiMeetJS;
|
const { mediaDevices } = JitsiMeetJS;
|
||||||
|
|
||||||
if (mediaDevices.isDeviceListAvailable()
|
if (mediaDevices.isDeviceListAvailable()
|
||||||
&& mediaDevices.isDeviceChangeAvailable()) {
|
&& mediaDevices.isDeviceChangeAvailable()) {
|
||||||
mediaDevices.enumerateDevices(devices => {
|
this.deviceChangeListener = devices =>
|
||||||
// Ugly way to synchronize real device IDs with local storage
|
window.setTimeout(() => this._onDeviceListChanged(devices), 0);
|
||||||
// and settings menu. This is a workaround until
|
mediaDevices.addEventListener(
|
||||||
// getConstraints() method will be implemented in browsers.
|
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
|
||||||
|
this.deviceChangeListener);
|
||||||
|
|
||||||
const { dispatch } = APP.store;
|
const { dispatch } = APP.store;
|
||||||
|
|
||||||
|
return dispatch(getAvailableDevices())
|
||||||
|
.then(devices => {
|
||||||
|
// Ugly way to synchronize real device IDs with local
|
||||||
|
// storage and settings menu. This is a workaround until
|
||||||
|
// getConstraints() method will be implemented in browsers.
|
||||||
if (this.localAudio) {
|
if (this.localAudio) {
|
||||||
dispatch(updateSettings({
|
dispatch(updateSettings({
|
||||||
micDeviceId: this.localAudio.getDeviceId()
|
micDeviceId: this.localAudio.getDeviceId()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.localVideo) {
|
if (this.localVideo) {
|
||||||
dispatch(updateSettings({
|
dispatch(updateSettings({
|
||||||
cameraDeviceId: this.localVideo.getDeviceId()
|
cameraDeviceId: this.localVideo.getDeviceId()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
APP.store.dispatch(updateDeviceList(devices));
|
|
||||||
APP.UI.onAvailableDevicesChanged(devices);
|
APP.UI.onAvailableDevicesChanged(devices);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.deviceChangeListener = devices =>
|
|
||||||
window.setTimeout(() => this._onDeviceListChanged(devices), 0);
|
|
||||||
mediaDevices.addEventListener(
|
|
||||||
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
|
|
||||||
this.deviceChangeListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,17 +9,6 @@
|
||||||
*/
|
*/
|
||||||
export const SET_AUDIO_INPUT_DEVICE = Symbol('SET_AUDIO_INPUT_DEVICE');
|
export const SET_AUDIO_INPUT_DEVICE = Symbol('SET_AUDIO_INPUT_DEVICE');
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of Redux action which signals that the currently used audio
|
|
||||||
* output device should be changed.
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* type: SET_AUDIO_OUTPUT_DEVICE,
|
|
||||||
* deviceId: string,
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
export const SET_AUDIO_OUTPUT_DEVICE = Symbol('SET_AUDIO_OUTPUT_DEVICE');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of Redux action which signals that the currently used video
|
* The type of Redux action which signals that the currently used video
|
||||||
* input device should be changed.
|
* input device should be changed.
|
||||||
|
|
|
@ -1,10 +1,34 @@
|
||||||
|
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SET_AUDIO_INPUT_DEVICE,
|
SET_AUDIO_INPUT_DEVICE,
|
||||||
SET_AUDIO_OUTPUT_DEVICE,
|
|
||||||
SET_VIDEO_INPUT_DEVICE,
|
SET_VIDEO_INPUT_DEVICE,
|
||||||
UPDATE_DEVICE_LIST
|
UPDATE_DEVICE_LIST
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries for connected A/V input and output devices and updates the redux
|
||||||
|
* state of known devices.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function getAvailableDevices() {
|
||||||
|
return dispatch => new Promise(resolve => {
|
||||||
|
const { mediaDevices } = JitsiMeetJS;
|
||||||
|
|
||||||
|
if (mediaDevices.isDeviceListAvailable()
|
||||||
|
&& mediaDevices.isDeviceChangeAvailable()) {
|
||||||
|
mediaDevices.enumerateDevices(devices => {
|
||||||
|
dispatch(updateDeviceList(devices));
|
||||||
|
|
||||||
|
resolve(devices);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals to update the currently used audio input device.
|
* Signals to update the currently used audio input device.
|
||||||
*
|
*
|
||||||
|
@ -21,22 +45,6 @@ export function setAudioInputDevice(deviceId) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals to update the currently used audio output device.
|
|
||||||
*
|
|
||||||
* @param {string} deviceId - The id of the new audio ouput device.
|
|
||||||
* @returns {{
|
|
||||||
* type: SET_AUDIO_OUTPUT_DEVICE,
|
|
||||||
* deviceId: string
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
export function setAudioOutputDevice(deviceId) {
|
|
||||||
return {
|
|
||||||
type: SET_AUDIO_OUTPUT_DEVICE,
|
|
||||||
deviceId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals to update the currently used video input device.
|
* Signals to update the currently used video input device.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { MiddlewareRegistry } from '../redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SET_AUDIO_INPUT_DEVICE,
|
SET_AUDIO_INPUT_DEVICE,
|
||||||
SET_AUDIO_OUTPUT_DEVICE,
|
|
||||||
SET_VIDEO_INPUT_DEVICE
|
SET_VIDEO_INPUT_DEVICE
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
|
@ -22,9 +21,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
case SET_AUDIO_INPUT_DEVICE:
|
case SET_AUDIO_INPUT_DEVICE:
|
||||||
APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
|
APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
|
||||||
break;
|
break;
|
||||||
case SET_AUDIO_OUTPUT_DEVICE:
|
|
||||||
APP.UI.emitEvent(UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED, action.deviceId);
|
|
||||||
break;
|
|
||||||
case SET_VIDEO_INPUT_DEVICE:
|
case SET_VIDEO_INPUT_DEVICE:
|
||||||
APP.UI.emitEvent(UIEvents.VIDEO_DEVICE_CHANGED, action.deviceId);
|
APP.UI.emitEvent(UIEvents.VIDEO_DEVICE_CHANGED, action.deviceId);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {
|
import {
|
||||||
SET_AUDIO_INPUT_DEVICE,
|
SET_AUDIO_INPUT_DEVICE,
|
||||||
SET_AUDIO_OUTPUT_DEVICE,
|
|
||||||
SET_VIDEO_INPUT_DEVICE,
|
SET_VIDEO_INPUT_DEVICE,
|
||||||
UPDATE_DEVICE_LIST
|
UPDATE_DEVICE_LIST
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
@ -40,7 +39,6 @@ ReducerRegistry.register(
|
||||||
// now.
|
// now.
|
||||||
case SET_AUDIO_INPUT_DEVICE:
|
case SET_AUDIO_INPUT_DEVICE:
|
||||||
case SET_VIDEO_INPUT_DEVICE:
|
case SET_VIDEO_INPUT_DEVICE:
|
||||||
case SET_AUDIO_OUTPUT_DEVICE:
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,28 @@ class DialogWithTabs extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the props to pass into the tab component.
|
||||||
|
*
|
||||||
|
* @param {number} tabId - The index of the tab configuration within
|
||||||
|
* {@link this.state.tabStates}.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
_getTabProps(tabId) {
|
||||||
|
const { tabs } = this.props;
|
||||||
|
const { tabStates } = this.state;
|
||||||
|
const tabConfiguration = tabs[tabId];
|
||||||
|
const currentTabState = tabStates[tabId];
|
||||||
|
|
||||||
|
if (tabConfiguration.propsUpdateFunction) {
|
||||||
|
return tabConfiguration.propsUpdateFunction(
|
||||||
|
currentTabState,
|
||||||
|
tabConfiguration.props);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...currentTabState };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the tabs from the tab information passed on props.
|
* Renders the tabs from the tab information passed on props.
|
||||||
*
|
*
|
||||||
|
@ -155,10 +177,11 @@ class DialogWithTabs extends Component<Props, State> {
|
||||||
<div className = { styles }>
|
<div className = { styles }>
|
||||||
<TabComponent
|
<TabComponent
|
||||||
closeDialog = { closeDialog }
|
closeDialog = { closeDialog }
|
||||||
|
mountCallback = { this.props.tabs[tabId].onMount }
|
||||||
onTabStateChange
|
onTabStateChange
|
||||||
= { this._onTabStateChange }
|
= { this._onTabStateChange }
|
||||||
tabId = { tabId }
|
tabId = { tabId }
|
||||||
{ ...this.state.tabStates[tabId] } />
|
{ ...this._getTabProps(tabId) } />
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ function _initSettings(featureState) {
|
||||||
if (settings.audioOutputDeviceId
|
if (settings.audioOutputDeviceId
|
||||||
!== JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
|
!== JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
|
||||||
JitsiMeetJS.mediaDevices.setAudioOutputDevice(
|
JitsiMeetJS.mediaDevices.setAudioOutputDevice(
|
||||||
audioOutputDeviceId
|
settings.audioOutputDeviceId
|
||||||
).catch(ex => {
|
).catch(ex => {
|
||||||
logger.warn('Failed to set audio output device from local '
|
logger.warn('Failed to set audio output device from local '
|
||||||
+ 'storage. Default audio output device will be used'
|
+ 'storage. Default audio output device will be used'
|
||||||
|
|
|
@ -4,18 +4,22 @@ import {
|
||||||
Transport
|
Transport
|
||||||
} from '../../../modules/transport';
|
} from '../../../modules/transport';
|
||||||
|
|
||||||
|
import { createDeviceChangedEvent, sendAnalytics } from '../analytics';
|
||||||
import {
|
import {
|
||||||
getAudioOutputDeviceId,
|
getAudioOutputDeviceId,
|
||||||
setAudioInputDevice,
|
setAudioInputDevice,
|
||||||
setAudioOutputDevice,
|
setAudioOutputDeviceId,
|
||||||
setVideoInputDevice
|
setVideoInputDevice
|
||||||
} from '../base/devices';
|
} from '../base/devices';
|
||||||
import { i18next } from '../base/i18n';
|
import { i18next } from '../base/i18n';
|
||||||
import JitsiMeetJS from '../base/lib-jitsi-meet';
|
import JitsiMeetJS from '../base/lib-jitsi-meet';
|
||||||
|
import { updateSettings } from '../base/settings';
|
||||||
|
|
||||||
import { SET_DEVICE_SELECTION_POPUP_DATA } from './actionTypes';
|
import { SET_DEVICE_SELECTION_POPUP_DATA } from './actionTypes';
|
||||||
import { getDeviceSelectionDialogProps } from './functions';
|
import { getDeviceSelectionDialogProps } from './functions';
|
||||||
|
|
||||||
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a popup window with the device selection dialog in it.
|
* Opens a popup window with the device selection dialog in it.
|
||||||
*
|
*
|
||||||
|
@ -115,23 +119,22 @@ function _processRequest(dispatch, getState, request, responseCallback) { // esl
|
||||||
responseCallback(getState()['features/base/devices']);
|
responseCallback(getState()['features/base/devices']);
|
||||||
break;
|
break;
|
||||||
case 'setDevice': {
|
case 'setDevice': {
|
||||||
let action;
|
|
||||||
const { device } = request;
|
const { device } = request;
|
||||||
|
|
||||||
switch (device.kind) {
|
switch (device.kind) {
|
||||||
case 'audioinput':
|
case 'audioinput':
|
||||||
action = setAudioInputDevice;
|
dispatch(setAudioInputDevice(device.id));
|
||||||
break;
|
break;
|
||||||
case 'audiooutput':
|
case 'audiooutput':
|
||||||
action = setAudioOutputDevice;
|
setAudioOutputDeviceId(device.id, dispatch);
|
||||||
break;
|
break;
|
||||||
case 'videoinput':
|
case 'videoinput':
|
||||||
action = setVideoInputDevice;
|
dispatch(setVideoInputDevice(device.id));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
||||||
}
|
}
|
||||||
dispatch(action(device.id));
|
|
||||||
responseCallback(true);
|
responseCallback(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -179,6 +182,10 @@ export function submitDeviceSelectionTab(newState) {
|
||||||
if (newState.selectedVideoInputId
|
if (newState.selectedVideoInputId
|
||||||
&& newState.selectedVideoInputId
|
&& newState.selectedVideoInputId
|
||||||
!== currentState.selectedVideoInputId) {
|
!== currentState.selectedVideoInputId) {
|
||||||
|
dispatch(updateSettings({
|
||||||
|
cameraDeviceId: newState.selectedVideoInputId
|
||||||
|
}));
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setVideoInputDevice(newState.selectedVideoInputId));
|
setVideoInputDevice(newState.selectedVideoInputId));
|
||||||
}
|
}
|
||||||
|
@ -186,6 +193,10 @@ export function submitDeviceSelectionTab(newState) {
|
||||||
if (newState.selectedAudioInputId
|
if (newState.selectedAudioInputId
|
||||||
&& newState.selectedAudioInputId
|
&& newState.selectedAudioInputId
|
||||||
!== currentState.selectedAudioInputId) {
|
!== currentState.selectedAudioInputId) {
|
||||||
|
dispatch(updateSettings({
|
||||||
|
micDeviceId: newState.selectedAudioInputId
|
||||||
|
}));
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setAudioInputDevice(newState.selectedAudioInputId));
|
setAudioInputDevice(newState.selectedAudioInputId));
|
||||||
}
|
}
|
||||||
|
@ -193,8 +204,19 @@ export function submitDeviceSelectionTab(newState) {
|
||||||
if (newState.selectedAudioOutputId
|
if (newState.selectedAudioOutputId
|
||||||
&& newState.selectedAudioOutputId
|
&& newState.selectedAudioOutputId
|
||||||
!== currentState.selectedAudioOutputId) {
|
!== currentState.selectedAudioOutputId) {
|
||||||
dispatch(
|
sendAnalytics(createDeviceChangedEvent('audio', 'output'));
|
||||||
setAudioOutputDevice(newState.selectedAudioOutputId));
|
|
||||||
|
setAudioOutputDeviceId(
|
||||||
|
newState.selectedAudioOutputId,
|
||||||
|
dispatch)
|
||||||
|
.then(() => logger.log('changed audio output device'))
|
||||||
|
.catch(err => {
|
||||||
|
logger.warn(
|
||||||
|
'Failed to change audio output device.',
|
||||||
|
'Default or previously set audio output device will',
|
||||||
|
' be used instead.',
|
||||||
|
err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import AudioOutputPreview from './AudioOutputPreview';
|
||||||
import DeviceSelector from './DeviceSelector';
|
import DeviceSelector from './DeviceSelector';
|
||||||
import VideoInputPreview from './VideoInputPreview';
|
import VideoInputPreview from './VideoInputPreview';
|
||||||
|
|
||||||
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link DeviceSelection}.
|
* The type of the React {@code Component} props of {@link DeviceSelection}.
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +66,12 @@ export type Props = {
|
||||||
*/
|
*/
|
||||||
hideAudioOutputSelect: boolean,
|
hideAudioOutputSelect: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional callback to invoke after the component has completed its
|
||||||
|
* mount logic.
|
||||||
|
*/
|
||||||
|
mountCallback?: Function,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the audio input device to preview.
|
* The id of the audio input device to preview.
|
||||||
*/
|
*/
|
||||||
|
@ -134,8 +142,12 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._createAudioInputTrack(this.props.selectedAudioInputId);
|
Promise.all([
|
||||||
this._createVideoInputTrack(this.props.selectedVideoInputId);
|
this._createAudioInputTrack(this.props.selectedAudioInputId),
|
||||||
|
this._createVideoInputTrack(this.props.selectedVideoInputId)
|
||||||
|
])
|
||||||
|
.catch(err => logger.warn('Failed to initialize preview tracks', err))
|
||||||
|
.then(() => this.props.mountCallback && this.props.mountCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,7 +224,7 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_createAudioInputTrack(deviceId) {
|
_createAudioInputTrack(deviceId) {
|
||||||
this._disposeAudioInputPreview()
|
return this._disposeAudioInputPreview()
|
||||||
.then(() => createLocalTrack('audio', deviceId))
|
.then(() => createLocalTrack('audio', deviceId))
|
||||||
.then(jitsiLocalTrack => {
|
.then(jitsiLocalTrack => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -234,7 +246,7 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_createVideoInputTrack(deviceId) {
|
_createVideoInputTrack(deviceId) {
|
||||||
this._disposeVideoInputPreview()
|
return this._disposeVideoInputPreview()
|
||||||
.then(() => createLocalTrack('video', deviceId))
|
.then(() => createLocalTrack('video', deviceId))
|
||||||
.then(jitsiLocalTrack => {
|
.then(jitsiLocalTrack => {
|
||||||
if (!jitsiLocalTrack) {
|
if (!jitsiLocalTrack) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { getAvailableDevices } from '../../../base/devices';
|
||||||
import { DialogWithTabs, hideDialog } from '../../../base/dialog';
|
import { DialogWithTabs, hideDialog } from '../../../base/dialog';
|
||||||
import {
|
import {
|
||||||
DeviceSelection,
|
DeviceSelection,
|
||||||
|
@ -77,6 +78,9 @@ class SettingsDialog extends Component<Props> {
|
||||||
const tabs = _tabs.map(tab => {
|
const tabs = _tabs.map(tab => {
|
||||||
return {
|
return {
|
||||||
...tab,
|
...tab,
|
||||||
|
onMount: tab.onMount
|
||||||
|
? (...args) => dispatch(tab.onMount(...args))
|
||||||
|
: undefined,
|
||||||
submit: (...args) => dispatch(tab.submit(...args))
|
submit: (...args) => dispatch(tab.submit(...args))
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -133,7 +137,22 @@ function _mapStateToProps(state) {
|
||||||
name: SETTINGS_TABS.DEVICES,
|
name: SETTINGS_TABS.DEVICES,
|
||||||
component: DeviceSelection,
|
component: DeviceSelection,
|
||||||
label: 'settings.devices',
|
label: 'settings.devices',
|
||||||
|
onMount: getAvailableDevices,
|
||||||
props: getDeviceSelectionDialogProps(state),
|
props: getDeviceSelectionDialogProps(state),
|
||||||
|
propsUpdateFunction: (tabState, newProps) => {
|
||||||
|
// 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,
|
||||||
|
selectedAudioInputId: tabState.selectedAudioInputId,
|
||||||
|
selectedAudioOutputId: tabState.selectedAudioOutputId,
|
||||||
|
selectedVideoInputId: tabState.selectedVideoInputId
|
||||||
|
};
|
||||||
|
},
|
||||||
styles: 'settings-pane devices-pane',
|
styles: 'settings-pane devices-pane',
|
||||||
submit: submitDeviceSelectionTab
|
submit: submitDeviceSelectionTab
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,24 +74,30 @@ export function shouldShowOnlyDeviceSelection() {
|
||||||
export function getMoreTabProps(stateful: Object | Function) {
|
export function getMoreTabProps(stateful: Object | Function) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
const language = i18next.language || DEFAULT_LANGUAGE;
|
const language = i18next.language || DEFAULT_LANGUAGE;
|
||||||
const conference = state['features/base/conference'];
|
const {
|
||||||
|
conference,
|
||||||
|
followMeEnabled,
|
||||||
|
startAudioMutedPolicy,
|
||||||
|
startVideoMutedPolicy
|
||||||
|
} = state['features/base/conference'];
|
||||||
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
|
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
|
||||||
const localParticipant = getLocalParticipant(state);
|
const localParticipant = getLocalParticipant(state);
|
||||||
|
|
||||||
|
|
||||||
// The settings sections to display.
|
// The settings sections to display.
|
||||||
const showModeratorSettings
|
const showModeratorSettings = Boolean(
|
||||||
= configuredTabs.includes('moderator')
|
conference
|
||||||
&& localParticipant.role === PARTICIPANT_ROLE.MODERATOR;
|
&& configuredTabs.includes('moderator')
|
||||||
|
&& localParticipant.role === PARTICIPANT_ROLE.MODERATOR);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentLanguage: language,
|
currentLanguage: language,
|
||||||
followMeEnabled: Boolean(conference.followMeEnabled),
|
followMeEnabled: Boolean(conference && followMeEnabled),
|
||||||
languages: LANGUAGES,
|
languages: LANGUAGES,
|
||||||
showLanguageSettings: configuredTabs.includes('language'),
|
showLanguageSettings: configuredTabs.includes('language'),
|
||||||
showModeratorSettings,
|
showModeratorSettings,
|
||||||
startAudioMuted: Boolean(conference.startAudioMutedPolicy),
|
startAudioMuted: Boolean(conference && startAudioMutedPolicy),
|
||||||
startVideoMuted: Boolean(conference.startVideoMutedPolicy)
|
startVideoMuted: Boolean(conference && startVideoMutedPolicy)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,12 +112,16 @@ export function getMoreTabProps(stateful: Object | Function) {
|
||||||
*/
|
*/
|
||||||
export function getProfileTabProps(stateful: Object | Function) {
|
export function getProfileTabProps(stateful: Object | Function) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
const conference = state['features/base/conference'];
|
const {
|
||||||
|
authEnabled,
|
||||||
|
authLogin,
|
||||||
|
conference
|
||||||
|
} = state['features/base/conference'];
|
||||||
const localParticipant = getLocalParticipant(state);
|
const localParticipant = getLocalParticipant(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authEnabled: conference.authEnabled,
|
authEnabled: Boolean(conference && authEnabled),
|
||||||
authLogin: conference.authLogin,
|
authLogin: Boolean(conference && authLogin),
|
||||||
displayName: localParticipant.name,
|
displayName: localParticipant.name,
|
||||||
email: localParticipant.email
|
email: localParticipant.email
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,9 +6,11 @@ import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { DialogContainer } from '../../base/dialog';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import { Watermarks } from '../../base/react';
|
import { Watermarks } from '../../base/react';
|
||||||
import { RecentList } from '../../recent-list';
|
import { RecentList } from '../../recent-list';
|
||||||
|
import { openSettingsDialog } from '../../settings';
|
||||||
|
|
||||||
import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
|
import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
|
||||||
|
|
||||||
|
@ -18,6 +20,15 @@ import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
|
||||||
* @extends AbstractWelcomePage
|
* @extends AbstractWelcomePage
|
||||||
*/
|
*/
|
||||||
class WelcomePage extends AbstractWelcomePage {
|
class WelcomePage extends AbstractWelcomePage {
|
||||||
|
/**
|
||||||
|
* Default values for {@code WelcomePage} component's properties.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static defaultProps = {
|
||||||
|
_room: ''
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new WelcomePage instance.
|
* Initializes a new WelcomePage instance.
|
||||||
*
|
*
|
||||||
|
@ -55,6 +66,7 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onFormSubmit = this._onFormSubmit.bind(this);
|
this._onFormSubmit = this._onFormSubmit.bind(this);
|
||||||
|
this._onOpenSettings = this._onOpenSettings.bind(this);
|
||||||
this._onRoomChange = this._onRoomChange.bind(this);
|
this._onRoomChange = this._onRoomChange.bind(this);
|
||||||
this._setAdditionalContentRef
|
this._setAdditionalContentRef
|
||||||
= this._setAdditionalContentRef.bind(this);
|
= this._setAdditionalContentRef.bind(this);
|
||||||
|
@ -155,6 +167,9 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
ref = { this._setAdditionalContentRef } />
|
ref = { this._setAdditionalContentRef } />
|
||||||
: null }
|
: null }
|
||||||
</div>
|
</div>
|
||||||
|
<AtlasKitThemeProvider mode = 'dark'>
|
||||||
|
<DialogContainer />
|
||||||
|
</AtlasKitThemeProvider>
|
||||||
</AtlasKitThemeProvider>
|
</AtlasKitThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -172,6 +187,16 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
this._onJoin();
|
this._onJoin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens {@code SettingsDialog}.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onOpenSettings() {
|
||||||
|
this.props.dispatch(openSettingsDialog());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the super to account for the differences in the argument types
|
* Overrides the super to account for the differences in the argument types
|
||||||
* provided by HTML and React Native text inputs.
|
* provided by HTML and React Native text inputs.
|
||||||
|
|
|
@ -63,7 +63,6 @@ export default {
|
||||||
LOGOUT: 'UI.logout',
|
LOGOUT: 'UI.logout',
|
||||||
VIDEO_DEVICE_CHANGED: 'UI.video_device_changed',
|
VIDEO_DEVICE_CHANGED: 'UI.video_device_changed',
|
||||||
AUDIO_DEVICE_CHANGED: 'UI.audio_device_changed',
|
AUDIO_DEVICE_CHANGED: 'UI.audio_device_changed',
|
||||||
AUDIO_OUTPUT_DEVICE_CHANGED: 'UI.audio_output_device_changed',
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies interested listeners that the follow-me feature is enabled or
|
* Notifies interested listeners that the follow-me feature is enabled or
|
||||||
|
|
Loading…
Reference in New Issue