Settings split into tabs.
parent
d76682b6c8
commit
130ed19f13
|
|
@ -52,12 +52,18 @@ export const setJoinByAccessCode = (joinByAccessCode) =>
|
||||||
payload : { joinByAccessCode }
|
payload : { joinByAccessCode }
|
||||||
});
|
});
|
||||||
|
|
||||||
export const setSettingsOpen = ({ settingsOpen }) =>
|
export const setSettingsOpen = (settingsOpen) =>
|
||||||
({
|
({
|
||||||
type : 'SET_SETTINGS_OPEN',
|
type : 'SET_SETTINGS_OPEN',
|
||||||
payload : { settingsOpen }
|
payload : { settingsOpen }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setSettingsTab = (tab) =>
|
||||||
|
({
|
||||||
|
type : 'SET_SETTINGS_TAB',
|
||||||
|
payload : { tab }
|
||||||
|
});
|
||||||
|
|
||||||
export const setLockDialogOpen = ({ lockDialogOpen }) =>
|
export const setLockDialogOpen = ({ lockDialogOpen }) =>
|
||||||
({
|
({
|
||||||
type : 'SET_LOCK_DIALOG_OPEN',
|
type : 'SET_LOCK_DIALOG_OPEN',
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,7 @@ const mapDispatchToProps = (dispatch) =>
|
||||||
},
|
},
|
||||||
setSettingsOpen : (settingsOpen) =>
|
setSettingsOpen : (settingsOpen) =>
|
||||||
{
|
{
|
||||||
dispatch(roomActions.setSettingsOpen({ settingsOpen }));
|
dispatch(roomActions.setSettingsOpen(settingsOpen));
|
||||||
},
|
},
|
||||||
setLockDialogOpen : (lockDialogOpen) =>
|
setLockDialogOpen : (lockDialogOpen) =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import { withRoomContext } from '../../RoomContext';
|
||||||
|
import * as settingsActions from '../../actions/settingsActions';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
|
import Select from '@material-ui/core/Select';
|
||||||
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
|
|
||||||
|
const styles = (theme) =>
|
||||||
|
({
|
||||||
|
setting :
|
||||||
|
{
|
||||||
|
padding : theme.spacing(2)
|
||||||
|
},
|
||||||
|
formControl :
|
||||||
|
{
|
||||||
|
display : 'flex'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const AdvancedSettings = ({
|
||||||
|
roomClient,
|
||||||
|
settings,
|
||||||
|
onToggleAdvancedMode,
|
||||||
|
classes
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<FormControlLabel
|
||||||
|
className={classes.setting}
|
||||||
|
control={<Checkbox checked={settings.advancedMode} onChange={onToggleAdvancedMode} value='advancedMode' />}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id : 'settings.advancedMode',
|
||||||
|
defaultMessage : 'Advanced mode'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
{ !window.config.lockLastN &&
|
||||||
|
<form className={classes.setting} autoComplete='off'>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<Select
|
||||||
|
value={settings.lastN || ''}
|
||||||
|
onChange={(event) =>
|
||||||
|
{
|
||||||
|
if (event.target.value)
|
||||||
|
roomClient.changeMaxSpotlights(event.target.value);
|
||||||
|
}}
|
||||||
|
name='Last N'
|
||||||
|
autoWidth
|
||||||
|
className={classes.selectEmpty}
|
||||||
|
>
|
||||||
|
{ Array.from(
|
||||||
|
{ length: window.config.maxLastN || 10 },
|
||||||
|
(_, i) => i + 1
|
||||||
|
).map((lastN) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<MenuItem key={lastN} value={lastN}>
|
||||||
|
{lastN}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
<FormattedMessage
|
||||||
|
id='settings.lastn'
|
||||||
|
defaultMessage='Number of visible videos'
|
||||||
|
/>
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdvancedSettings.propTypes =
|
||||||
|
{
|
||||||
|
roomClient : PropTypes.any.isRequired,
|
||||||
|
settings : PropTypes.object.isRequired,
|
||||||
|
onToggleAdvancedMode : PropTypes.func.isRequired,
|
||||||
|
classes : PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) =>
|
||||||
|
({
|
||||||
|
settings : state.settings
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
onToggleAdvancedMode : settingsActions.toggleAdvancedMode
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withRoomContext(connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
areStatesEqual : (next, prev) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
prev.settings === next.settings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(withStyles(styles)(AdvancedSettings)));
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import * as appPropTypes from '../appPropTypes';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import * as roomActions from '../../actions/roomActions';
|
||||||
|
import * as settingsActions from '../../actions/settingsActions';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
|
import Select from '@material-ui/core/Select';
|
||||||
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
|
|
||||||
|
const styles = (theme) =>
|
||||||
|
({
|
||||||
|
setting :
|
||||||
|
{
|
||||||
|
padding : theme.spacing(2)
|
||||||
|
},
|
||||||
|
formControl :
|
||||||
|
{
|
||||||
|
display : 'flex'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const AppearenceSettings = ({
|
||||||
|
room,
|
||||||
|
settings,
|
||||||
|
onTogglePermanentTopBar,
|
||||||
|
handleChangeMode,
|
||||||
|
classes
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const modes = [ {
|
||||||
|
value : 'democratic',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.democratic',
|
||||||
|
defaultMessage : 'Democratic view'
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
value : 'filmstrip',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.filmstrip',
|
||||||
|
defaultMessage : 'Filmstrip view'
|
||||||
|
})
|
||||||
|
} ];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<form className={classes.setting} autoComplete='off'>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<Select
|
||||||
|
value={room.mode || ''}
|
||||||
|
onChange={(event) =>
|
||||||
|
{
|
||||||
|
if (event.target.value)
|
||||||
|
handleChangeMode(event.target.value);
|
||||||
|
}}
|
||||||
|
name={intl.formatMessage({
|
||||||
|
id : 'settings.layout',
|
||||||
|
defaultMessage : 'Room layout'
|
||||||
|
})}
|
||||||
|
autoWidth
|
||||||
|
className={classes.selectEmpty}
|
||||||
|
>
|
||||||
|
{ modes.map((mode, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<MenuItem key={index} value={mode.value}>
|
||||||
|
{mode.label}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
<FormattedMessage
|
||||||
|
id='settings.selectRoomLayout'
|
||||||
|
defaultMessage='Select room layout'
|
||||||
|
/>
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
<FormControlLabel
|
||||||
|
className={classes.setting}
|
||||||
|
control={<Checkbox checked={settings.permanentTopBar} onChange={onTogglePermanentTopBar} value='permanentTopBar' />}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id : 'settings.permanentTopBar',
|
||||||
|
defaultMessage : 'Permanent top bar'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AppearenceSettings.propTypes =
|
||||||
|
{
|
||||||
|
room : appPropTypes.Room.isRequired,
|
||||||
|
settings : PropTypes.object.isRequired,
|
||||||
|
onTogglePermanentTopBar : PropTypes.func.isRequired,
|
||||||
|
handleChangeMode : PropTypes.func.isRequired,
|
||||||
|
classes : PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) =>
|
||||||
|
({
|
||||||
|
room : state.room,
|
||||||
|
settings : state.settings
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
onTogglePermanentTopBar : settingsActions.togglePermanentTopBar,
|
||||||
|
handleChangeMode : roomActions.setDisplayMode
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
areStatesEqual : (next, prev) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
prev.room === next.room &&
|
||||||
|
prev.settings === next.settings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(withStyles(styles)(AppearenceSettings));
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import * as appPropTypes from '../appPropTypes';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import { withRoomContext } from '../../RoomContext';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import Select from '@material-ui/core/Select';
|
||||||
|
|
||||||
|
const styles = (theme) =>
|
||||||
|
({
|
||||||
|
setting :
|
||||||
|
{
|
||||||
|
padding : theme.spacing(2)
|
||||||
|
},
|
||||||
|
formControl :
|
||||||
|
{
|
||||||
|
display : 'flex'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const MediaSettings = ({
|
||||||
|
roomClient,
|
||||||
|
me,
|
||||||
|
settings,
|
||||||
|
classes
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const resolutions = [ {
|
||||||
|
value : 'low',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.low',
|
||||||
|
defaultMessage : 'Low'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value : 'medium',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.medium',
|
||||||
|
defaultMessage : 'Medium'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value : 'high',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.high',
|
||||||
|
defaultMessage : 'High (HD)'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value : 'veryhigh',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.veryHigh',
|
||||||
|
defaultMessage : 'Very high (FHD)'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value : 'ultra',
|
||||||
|
label : intl.formatMessage({
|
||||||
|
id : 'label.ultra',
|
||||||
|
defaultMessage : 'Ultra (UHD)'
|
||||||
|
})
|
||||||
|
} ];
|
||||||
|
|
||||||
|
let webcams;
|
||||||
|
|
||||||
|
if (me.webcamDevices)
|
||||||
|
webcams = Object.values(me.webcamDevices);
|
||||||
|
else
|
||||||
|
webcams = [];
|
||||||
|
|
||||||
|
let audioDevices;
|
||||||
|
|
||||||
|
if (me.audioDevices)
|
||||||
|
audioDevices = Object.values(me.audioDevices);
|
||||||
|
else
|
||||||
|
audioDevices = [];
|
||||||
|
|
||||||
|
let audioOutputDevices;
|
||||||
|
|
||||||
|
if (me.audioOutputDevices)
|
||||||
|
audioOutputDevices = Object.values(me.audioOutputDevices);
|
||||||
|
else
|
||||||
|
audioOutputDevices = [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<form className={classes.setting} autoComplete='off'>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<Select
|
||||||
|
value={settings.selectedWebcam || ''}
|
||||||
|
onChange={(event) =>
|
||||||
|
{
|
||||||
|
if (event.target.value)
|
||||||
|
roomClient.changeWebcam(event.target.value);
|
||||||
|
}}
|
||||||
|
displayEmpty
|
||||||
|
name={intl.formatMessage({
|
||||||
|
id : 'settings.camera',
|
||||||
|
defaultMessage : 'Camera'
|
||||||
|
})}
|
||||||
|
autoWidth
|
||||||
|
className={classes.selectEmpty}
|
||||||
|
disabled={webcams.length === 0 || me.webcamInProgress}
|
||||||
|
>
|
||||||
|
{ webcams.map((webcam, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<MenuItem key={index} value={webcam.deviceId}>{webcam.label}</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
{ webcams.length > 0 ?
|
||||||
|
intl.formatMessage({
|
||||||
|
id : 'settings.selectCamera',
|
||||||
|
defaultMessage : 'Select video device'
|
||||||
|
})
|
||||||
|
:
|
||||||
|
intl.formatMessage({
|
||||||
|
id : 'settings.cantSelectCamera',
|
||||||
|
defaultMessage : 'Unable to select video device'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
<form className={classes.setting} autoComplete='off'>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<Select
|
||||||
|
value={settings.selectedAudioDevice || ''}
|
||||||
|
onChange={(event) =>
|
||||||
|
{
|
||||||
|
if (event.target.value)
|
||||||
|
roomClient.changeAudioDevice(event.target.value);
|
||||||
|
}}
|
||||||
|
displayEmpty
|
||||||
|
name={intl.formatMessage({
|
||||||
|
id : 'settings.audio',
|
||||||
|
defaultMessage : 'Audio device'
|
||||||
|
})}
|
||||||
|
autoWidth
|
||||||
|
className={classes.selectEmpty}
|
||||||
|
disabled={audioDevices.length === 0 || me.audioInProgress}
|
||||||
|
>
|
||||||
|
{ audioDevices.map((audio, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<MenuItem key={index} value={audio.deviceId}>{audio.label}</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
{ audioDevices.length > 0 ?
|
||||||
|
intl.formatMessage({
|
||||||
|
id : 'settings.selectAudio',
|
||||||
|
defaultMessage : 'Select audio device'
|
||||||
|
})
|
||||||
|
:
|
||||||
|
intl.formatMessage({
|
||||||
|
id : 'settings.cantSelectAudio',
|
||||||
|
defaultMessage : 'Unable to select audio device'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
{ 'audioOutputSupportedBrowsers' in window.config &&
|
||||||
|
window.config.audioOutputSupportedBrowsers.includes(me.browser.name) &&
|
||||||
|
<form className={classes.setting} autoComplete='off'>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<Select
|
||||||
|
value={settings.selectedAudioOutputDevice || ''}
|
||||||
|
onChange={(event) =>
|
||||||
|
{
|
||||||
|
if (event.target.value)
|
||||||
|
roomClient.changeAudioOutputDevice(event.target.value);
|
||||||
|
}}
|
||||||
|
displayEmpty
|
||||||
|
name={intl.formatMessage({
|
||||||
|
id : 'settings.audioOutput',
|
||||||
|
defaultMessage : 'Audio output device'
|
||||||
|
})}
|
||||||
|
autoWidth
|
||||||
|
className={classes.selectEmpty}
|
||||||
|
disabled={audioOutputDevices.length === 0 || me.audioOutputInProgress}
|
||||||
|
>
|
||||||
|
{ audioOutputDevices.map((audioOutput, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={index}
|
||||||
|
value={audioOutput.deviceId}
|
||||||
|
>
|
||||||
|
{audioOutput.label}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
{ audioOutputDevices.length > 0 ?
|
||||||
|
intl.formatMessage({
|
||||||
|
id : 'settings.selectAudioOutput',
|
||||||
|
defaultMessage : 'Select audio output device'
|
||||||
|
})
|
||||||
|
:
|
||||||
|
intl.formatMessage({
|
||||||
|
id : 'settings.cantSelectAudioOutput',
|
||||||
|
defaultMessage : 'Unable to select audio output device'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
<form className={classes.setting} autoComplete='off'>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<Select
|
||||||
|
value={settings.resolution || ''}
|
||||||
|
onChange={(event) =>
|
||||||
|
{
|
||||||
|
if (event.target.value)
|
||||||
|
roomClient.changeVideoResolution(event.target.value);
|
||||||
|
}}
|
||||||
|
name='Video resolution'
|
||||||
|
autoWidth
|
||||||
|
className={classes.selectEmpty}
|
||||||
|
>
|
||||||
|
{ resolutions.map((resolution, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<MenuItem key={index} value={resolution.value}>
|
||||||
|
{resolution.label}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
<FormattedMessage
|
||||||
|
id='settings.resolution'
|
||||||
|
defaultMessage='Select your video resolution'
|
||||||
|
/>
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaSettings.propTypes =
|
||||||
|
{
|
||||||
|
roomClient : PropTypes.any.isRequired,
|
||||||
|
me : appPropTypes.Me.isRequired,
|
||||||
|
settings : PropTypes.object.isRequired,
|
||||||
|
classes : PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) =>
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
me : state.me,
|
||||||
|
settings : state.settings
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withRoomContext(connect(
|
||||||
|
mapStateToProps,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
areStatesEqual : (next, prev) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
prev.me === next.me &&
|
||||||
|
prev.settings === next.settings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(withStyles(styles)(MediaSettings)));
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as appPropTypes from '../appPropTypes';
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import { withRoomContext } from '../../RoomContext';
|
|
||||||
import * as roomActions from '../../actions/roomActions';
|
import * as roomActions from '../../actions/roomActions';
|
||||||
import * as settingsActions from '../../actions/settingsActions';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl, FormattedMessage } from 'react-intl';
|
import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
|
import Tab from '@material-ui/core/Tab';
|
||||||
|
import MediaSettings from './MediaSettings';
|
||||||
|
import AppearenceSettings from './AppearenceSettings';
|
||||||
|
import AdvancedSettings from './AdvancedSettings';
|
||||||
import Dialog from '@material-ui/core/Dialog';
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import DialogActions from '@material-ui/core/DialogActions';
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
|
||||||
import FormHelperText from '@material-ui/core/FormHelperText';
|
const tabs =
|
||||||
import FormControl from '@material-ui/core/FormControl';
|
[
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
'media',
|
||||||
import Select from '@material-ui/core/Select';
|
'appearence',
|
||||||
import Checkbox from '@material-ui/core/Checkbox';
|
'advanced'
|
||||||
|
];
|
||||||
|
|
||||||
const styles = (theme) =>
|
const styles = (theme) =>
|
||||||
({
|
({
|
||||||
|
|
@ -43,106 +46,27 @@ const styles = (theme) =>
|
||||||
width : '90vw'
|
width : '90vw'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setting :
|
tabsHeader :
|
||||||
{
|
{
|
||||||
padding : theme.spacing(2)
|
flexGrow : 1
|
||||||
},
|
|
||||||
formControl :
|
|
||||||
{
|
|
||||||
display : 'flex'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Settings = ({
|
const Settings = ({
|
||||||
roomClient,
|
currentSettingsTab,
|
||||||
room,
|
settingsOpen,
|
||||||
me,
|
|
||||||
settings,
|
|
||||||
onToggleAdvancedMode,
|
|
||||||
onTogglePermanentTopBar,
|
|
||||||
handleCloseSettings,
|
handleCloseSettings,
|
||||||
handleChangeMode,
|
setSettingsTab,
|
||||||
classes
|
classes
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const modes = [ {
|
|
||||||
value : 'democratic',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.democratic',
|
|
||||||
defaultMessage : 'Democratic view'
|
|
||||||
})
|
|
||||||
}, {
|
|
||||||
value : 'filmstrip',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.filmstrip',
|
|
||||||
defaultMessage : 'Filmstrip view'
|
|
||||||
})
|
|
||||||
} ];
|
|
||||||
|
|
||||||
const resolutions = [ {
|
|
||||||
value : 'low',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.low',
|
|
||||||
defaultMessage : 'Low'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value : 'medium',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.medium',
|
|
||||||
defaultMessage : 'Medium'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value : 'high',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.high',
|
|
||||||
defaultMessage : 'High (HD)'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value : 'veryhigh',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.veryHigh',
|
|
||||||
defaultMessage : 'Very high (FHD)'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value : 'ultra',
|
|
||||||
label : intl.formatMessage({
|
|
||||||
id : 'label.ultra',
|
|
||||||
defaultMessage : 'Ultra (UHD)'
|
|
||||||
})
|
|
||||||
} ];
|
|
||||||
|
|
||||||
let webcams;
|
|
||||||
|
|
||||||
if (me.webcamDevices)
|
|
||||||
webcams = Object.values(me.webcamDevices);
|
|
||||||
else
|
|
||||||
webcams = [];
|
|
||||||
|
|
||||||
let audioDevices;
|
|
||||||
|
|
||||||
if (me.audioDevices)
|
|
||||||
audioDevices = Object.values(me.audioDevices);
|
|
||||||
else
|
|
||||||
audioDevices = [];
|
|
||||||
|
|
||||||
let audioOutputDevices;
|
|
||||||
|
|
||||||
if (me.audioOutputDevices)
|
|
||||||
audioOutputDevices = Object.values(me.audioOutputDevices);
|
|
||||||
else
|
|
||||||
audioOutputDevices = [];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
className={classes.root}
|
className={classes.root}
|
||||||
open={room.settingsOpen}
|
open={settingsOpen}
|
||||||
onClose={() => handleCloseSettings({ settingsOpen: false })}
|
onClose={() => handleCloseSettings(false)}
|
||||||
classes={{
|
classes={{
|
||||||
paper : classes.dialogPaper
|
paper : classes.dialogPaper
|
||||||
}}
|
}}
|
||||||
|
|
@ -153,254 +77,40 @@ const Settings = ({
|
||||||
defaultMessage='Settings'
|
defaultMessage='Settings'
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<form className={classes.setting} autoComplete='off'>
|
<Tabs
|
||||||
<FormControl className={classes.formControl}>
|
className={classes.tabsHeader}
|
||||||
<Select
|
value={tabs.indexOf(currentSettingsTab)}
|
||||||
value={settings.selectedWebcam || ''}
|
onChange={(event, value) => setSettingsTab(tabs[value])}
|
||||||
onChange={(event) =>
|
indicatorColor='primary'
|
||||||
{
|
textColor='primary'
|
||||||
if (event.target.value)
|
variant='fullWidth'
|
||||||
roomClient.changeWebcam(event.target.value);
|
|
||||||
}}
|
|
||||||
displayEmpty
|
|
||||||
name={intl.formatMessage({
|
|
||||||
id : 'settings.camera',
|
|
||||||
defaultMessage : 'Camera'
|
|
||||||
})}
|
|
||||||
autoWidth
|
|
||||||
className={classes.selectEmpty}
|
|
||||||
disabled={webcams.length === 0 || me.webcamInProgress}
|
|
||||||
>
|
>
|
||||||
{ webcams.map((webcam, index) =>
|
<Tab
|
||||||
{
|
label={
|
||||||
return (
|
|
||||||
<MenuItem key={index} value={webcam.deviceId}>{webcam.label}</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>
|
|
||||||
{ webcams.length > 0 ?
|
|
||||||
intl.formatMessage({
|
intl.formatMessage({
|
||||||
id : 'settings.selectCamera',
|
id : 'label.media',
|
||||||
defaultMessage : 'Select video device'
|
defaultMessage : 'Media'
|
||||||
})
|
|
||||||
:
|
|
||||||
intl.formatMessage({
|
|
||||||
id : 'settings.cantSelectCamera',
|
|
||||||
defaultMessage : 'Unable to select video device'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</form>
|
|
||||||
<form className={classes.setting} autoComplete='off'>
|
|
||||||
<FormControl className={classes.formControl}>
|
|
||||||
<Select
|
|
||||||
value={settings.selectedAudioDevice || ''}
|
|
||||||
onChange={(event) =>
|
|
||||||
{
|
|
||||||
if (event.target.value)
|
|
||||||
roomClient.changeAudioDevice(event.target.value);
|
|
||||||
}}
|
|
||||||
displayEmpty
|
|
||||||
name={intl.formatMessage({
|
|
||||||
id : 'settings.audio',
|
|
||||||
defaultMessage : 'Audio device'
|
|
||||||
})}
|
|
||||||
autoWidth
|
|
||||||
className={classes.selectEmpty}
|
|
||||||
disabled={audioDevices.length === 0 || me.audioInProgress}
|
|
||||||
>
|
|
||||||
{ audioDevices.map((audio, index) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<MenuItem key={index} value={audio.deviceId}>{audio.label}</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>
|
|
||||||
{ audioDevices.length > 0 ?
|
|
||||||
intl.formatMessage({
|
|
||||||
id : 'settings.selectAudio',
|
|
||||||
defaultMessage : 'Select audio device'
|
|
||||||
})
|
|
||||||
:
|
|
||||||
intl.formatMessage({
|
|
||||||
id : 'settings.cantSelectAudio',
|
|
||||||
defaultMessage : 'Unable to select audio device'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</form>
|
|
||||||
{ 'audioOutputSupportedBrowsers' in window.config &&
|
|
||||||
window.config.audioOutputSupportedBrowsers.includes(me.browser.name) &&
|
|
||||||
<form className={classes.setting} autoComplete='off'>
|
|
||||||
<FormControl className={classes.formControl}>
|
|
||||||
<Select
|
|
||||||
value={settings.selectedAudioOutputDevice || ''}
|
|
||||||
onChange={(event) =>
|
|
||||||
{
|
|
||||||
if (event.target.value)
|
|
||||||
roomClient.changeAudioOutputDevice(event.target.value);
|
|
||||||
}}
|
|
||||||
displayEmpty
|
|
||||||
name={intl.formatMessage({
|
|
||||||
id : 'settings.audioOutput',
|
|
||||||
defaultMessage : 'Audio output device'
|
|
||||||
})}
|
|
||||||
autoWidth
|
|
||||||
className={classes.selectEmpty}
|
|
||||||
disabled={audioOutputDevices.length === 0 || me.audioOutputInProgress}
|
|
||||||
>
|
|
||||||
{ audioOutputDevices.map((audioOutput, index) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
key={index}
|
|
||||||
value={audioOutput.deviceId}
|
|
||||||
>
|
|
||||||
{audioOutput.label}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>
|
|
||||||
{ audioOutputDevices.length > 0 ?
|
|
||||||
intl.formatMessage({
|
|
||||||
id : 'settings.selectAudioOutput',
|
|
||||||
defaultMessage : 'Select audio output device'
|
|
||||||
})
|
|
||||||
:
|
|
||||||
intl.formatMessage({
|
|
||||||
id : 'settings.cantSelectAudioOutput',
|
|
||||||
defaultMessage : 'Unable to select audio output device'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
<form className={classes.setting} autoComplete='off'>
|
|
||||||
<FormControl className={classes.formControl}>
|
|
||||||
<Select
|
|
||||||
value={settings.resolution || ''}
|
|
||||||
onChange={(event) =>
|
|
||||||
{
|
|
||||||
if (event.target.value)
|
|
||||||
roomClient.changeVideoResolution(event.target.value);
|
|
||||||
}}
|
|
||||||
name='Video resolution'
|
|
||||||
autoWidth
|
|
||||||
className={classes.selectEmpty}
|
|
||||||
>
|
|
||||||
{ resolutions.map((resolution, index) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<MenuItem key={index} value={resolution.value}>
|
|
||||||
{resolution.label}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>
|
|
||||||
<FormattedMessage
|
|
||||||
id='settings.resolution'
|
|
||||||
defaultMessage='Select your video resolution'
|
|
||||||
/>
|
/>
|
||||||
</FormHelperText>
|
<Tab
|
||||||
</FormControl>
|
|
||||||
</form>
|
|
||||||
<form className={classes.setting} autoComplete='off'>
|
|
||||||
<FormControl className={classes.formControl}>
|
|
||||||
<Select
|
|
||||||
value={room.mode || ''}
|
|
||||||
onChange={(event) =>
|
|
||||||
{
|
|
||||||
if (event.target.value)
|
|
||||||
handleChangeMode(event.target.value);
|
|
||||||
}}
|
|
||||||
name={intl.formatMessage({
|
|
||||||
id : 'settings.layout',
|
|
||||||
defaultMessage : 'Room layout'
|
|
||||||
})}
|
|
||||||
autoWidth
|
|
||||||
className={classes.selectEmpty}
|
|
||||||
>
|
|
||||||
{ modes.map((mode, index) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<MenuItem key={index} value={mode.value}>
|
|
||||||
{mode.label}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>
|
|
||||||
<FormattedMessage
|
|
||||||
id='settings.selectRoomLayout'
|
|
||||||
defaultMessage='Select room layout'
|
|
||||||
/>
|
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</form>
|
|
||||||
<FormControlLabel
|
|
||||||
className={classes.setting}
|
|
||||||
control={<Checkbox checked={settings.advancedMode} onChange={onToggleAdvancedMode} value='advancedMode' />}
|
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id : 'settings.advancedMode',
|
id : 'label.appearence',
|
||||||
defaultMessage : 'Advanced mode'
|
defaultMessage : 'Appearence'
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
{ settings.advancedMode &&
|
<Tab
|
||||||
<React.Fragment>
|
|
||||||
{ !window.config.lockLastN &&
|
|
||||||
<form className={classes.setting} autoComplete='off'>
|
|
||||||
<FormControl className={classes.formControl}>
|
|
||||||
<Select
|
|
||||||
value={settings.lastN || ''}
|
|
||||||
onChange={(event) =>
|
|
||||||
{
|
|
||||||
if (event.target.value)
|
|
||||||
roomClient.changeMaxSpotlights(event.target.value);
|
|
||||||
}}
|
|
||||||
name='Last N'
|
|
||||||
autoWidth
|
|
||||||
className={classes.selectEmpty}
|
|
||||||
>
|
|
||||||
{ Array.from(
|
|
||||||
{ length: window.config.maxLastN || 10 },
|
|
||||||
(_, i) => i + 1
|
|
||||||
).map((lastN) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<MenuItem key={lastN} value={lastN}>
|
|
||||||
{lastN}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>
|
|
||||||
<FormattedMessage
|
|
||||||
id='settings.lastn'
|
|
||||||
defaultMessage='Number of visible videos'
|
|
||||||
/>
|
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
<FormControlLabel
|
|
||||||
className={classes.setting}
|
|
||||||
control={<Checkbox checked={settings.permanentTopBar} onChange={onTogglePermanentTopBar} value='permanentTopBar' />}
|
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id : 'settings.permanentTopBar',
|
id : 'label.advanced',
|
||||||
defaultMessage : 'Permanent top bar'
|
defaultMessage : 'Advanced'
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</Tabs>
|
||||||
}
|
{currentSettingsTab === 'media' && <MediaSettings />}
|
||||||
|
{currentSettingsTab === 'appearence' && <AppearenceSettings />}
|
||||||
|
{currentSettingsTab === 'advanced' && <AdvancedSettings />}
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => handleCloseSettings({ settingsOpen: false })} color='primary'>
|
<Button onClick={() => handleCloseSettings(false)} color='primary'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='label.close'
|
id='label.close'
|
||||||
defaultMessage='Close'
|
defaultMessage='Close'
|
||||||
|
|
@ -413,34 +123,25 @@ const Settings = ({
|
||||||
|
|
||||||
Settings.propTypes =
|
Settings.propTypes =
|
||||||
{
|
{
|
||||||
roomClient : PropTypes.any.isRequired,
|
currentSettingsTab : PropTypes.string.isRequired,
|
||||||
me : appPropTypes.Me.isRequired,
|
settingsOpen : PropTypes.bool.isRequired,
|
||||||
room : appPropTypes.Room.isRequired,
|
|
||||||
settings : PropTypes.object.isRequired,
|
|
||||||
onToggleAdvancedMode : PropTypes.func.isRequired,
|
|
||||||
onTogglePermanentTopBar : PropTypes.func.isRequired,
|
|
||||||
handleChangeMode : PropTypes.func.isRequired,
|
|
||||||
handleCloseSettings : PropTypes.func.isRequired,
|
handleCloseSettings : PropTypes.func.isRequired,
|
||||||
|
setSettingsTab : PropTypes.func.isRequired,
|
||||||
classes : PropTypes.object.isRequired
|
classes : PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) =>
|
const mapStateToProps = (state) =>
|
||||||
{
|
({
|
||||||
return {
|
currentSettingsTab : state.room.currentSettingsTab,
|
||||||
me : state.me,
|
settingsOpen : state.room.settingsOpen
|
||||||
room : state.room,
|
});
|
||||||
settings : state.settings
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
onToggleAdvancedMode : settingsActions.toggleAdvancedMode,
|
handleCloseSettings : roomActions.setSettingsOpen,
|
||||||
onTogglePermanentTopBar : settingsActions.togglePermanentTopBar,
|
setSettingsTab : roomActions.setSettingsTab
|
||||||
handleChangeMode : roomActions.setDisplayMode,
|
|
||||||
handleCloseSettings : roomActions.setSettingsOpen
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withRoomContext(connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps,
|
mapDispatchToProps,
|
||||||
null,
|
null,
|
||||||
|
|
@ -448,10 +149,9 @@ export default withRoomContext(connect(
|
||||||
areStatesEqual : (next, prev) =>
|
areStatesEqual : (next, prev) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
prev.me === next.me &&
|
prev.room.currentSettingsTab === next.room.currentSettingsTab &&
|
||||||
prev.room === next.room &&
|
prev.room.settingsOpen === next.room.settingsOpen
|
||||||
prev.settings === next.settings
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)(withStyles(styles)(Settings)));
|
)(withStyles(styles)(Settings));
|
||||||
|
|
@ -20,6 +20,7 @@ const initialState =
|
||||||
selectedPeerId : null,
|
selectedPeerId : null,
|
||||||
spotlights : [],
|
spotlights : [],
|
||||||
settingsOpen : false,
|
settingsOpen : false,
|
||||||
|
currentSettingsTab : 'media', // media, appearence, advanced
|
||||||
lockDialogOpen : false,
|
lockDialogOpen : false,
|
||||||
joined : false,
|
joined : false,
|
||||||
muteAllInProgress : false,
|
muteAllInProgress : false,
|
||||||
|
|
@ -113,6 +114,13 @@ const room = (state = initialState, action) =>
|
||||||
return { ...state, settingsOpen };
|
return { ...state, settingsOpen };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'SET_SETTINGS_TAB':
|
||||||
|
{
|
||||||
|
const { tab } = action.payload;
|
||||||
|
|
||||||
|
return { ...state, currentSettingsTab: tab };
|
||||||
|
}
|
||||||
|
|
||||||
case 'SET_ROOM_ACTIVE_SPEAKER':
|
case 'SET_ROOM_ACTIVE_SPEAKER':
|
||||||
{
|
{
|
||||||
const { peerId } = action.payload;
|
const { peerId } = action.payload;
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "非常高 (FHD)",
|
"label.veryHigh": "非常高 (FHD)",
|
||||||
"label.ultra": "超高 (UHD)",
|
"label.ultra": "超高 (UHD)",
|
||||||
"label.close": "关闭",
|
"label.close": "关闭",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "设置",
|
"settings.settings": "设置",
|
||||||
"settings.camera": "视频设备",
|
"settings.camera": "视频设备",
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,9 @@
|
||||||
"label.veryHigh": "Velmi vysoké (FHD)",
|
"label.veryHigh": "Velmi vysoké (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Zavřít",
|
"label.close": "Zavřít",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Nastavení",
|
"settings.settings": "Nastavení",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Sehr hoch (FHD)",
|
"label.veryHigh": "Sehr hoch (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Schließen",
|
"label.close": "Schließen",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Einstellungen",
|
"settings.settings": "Einstellungen",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Meget høj (FHD)",
|
"label.veryHigh": "Meget høj (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Luk",
|
"label.close": "Luk",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Indstillinger",
|
"settings.settings": "Indstillinger",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Πολύ υψηλή (FHD)",
|
"label.veryHigh": "Πολύ υψηλή (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Κλείσιμο",
|
"label.close": "Κλείσιμο",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Ρυθμίσεις",
|
"settings.settings": "Ρυθμίσεις",
|
||||||
"settings.camera": "Κάμερα",
|
"settings.camera": "Κάμερα",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Very high (FHD)",
|
"label.veryHigh": "Very high (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Close",
|
"label.close": "Close",
|
||||||
|
"label.media": "Media",
|
||||||
|
"label.appearence": "Appearence",
|
||||||
|
"label.advanced": "Advanced",
|
||||||
|
|
||||||
"settings.settings": "Settings",
|
"settings.settings": "Settings",
|
||||||
"settings.camera": "Camera",
|
"settings.camera": "Camera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Muy alta (FHD)",
|
"label.veryHigh": "Muy alta (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Cerrar",
|
"label.close": "Cerrar",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Ajustes",
|
"settings.settings": "Ajustes",
|
||||||
"settings.camera": "Cámara",
|
"settings.camera": "Cámara",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Très Haute Définition (FHD)",
|
"label.veryHigh": "Très Haute Définition (FHD)",
|
||||||
"label.ultra": "Ultra Haute Définition",
|
"label.ultra": "Ultra Haute Définition",
|
||||||
"label.close": "Fermer",
|
"label.close": "Fermer",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Paramètres",
|
"settings.settings": "Paramètres",
|
||||||
"settings.camera": "Caméra",
|
"settings.camera": "Caméra",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Vrlo visoka (FHD)",
|
"label.veryHigh": "Vrlo visoka (FHD)",
|
||||||
"label.ultra": "Ultra visoka (UHD)",
|
"label.ultra": "Ultra visoka (UHD)",
|
||||||
"label.close": "Zatvori",
|
"label.close": "Zatvori",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Postavke",
|
"settings.settings": "Postavke",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Nagyon magas (FHD)",
|
"label.veryHigh": "Nagyon magas (FHD)",
|
||||||
"label.ultra": "Ultra magas (UHD)",
|
"label.ultra": "Ultra magas (UHD)",
|
||||||
"label.close": "Bezár",
|
"label.close": "Bezár",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Beállítások",
|
"settings.settings": "Beállítások",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,9 @@
|
||||||
"label.veryHigh": "Molto alta (FHD)",
|
"label.veryHigh": "Molto alta (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Chiudi",
|
"label.close": "Chiudi",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Impostazioni",
|
"settings.settings": "Impostazioni",
|
||||||
"settings.camera": "Videocamera",
|
"settings.camera": "Videocamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Veldig høy (FHD)",
|
"label.veryHigh": "Veldig høy (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Lukk",
|
"label.close": "Lukk",
|
||||||
|
"label.media": "Media",
|
||||||
|
"label.appearence": "Utseende",
|
||||||
|
"label.advanced": "Avansert",
|
||||||
|
|
||||||
"settings.settings": "Innstillinger",
|
"settings.settings": "Innstillinger",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Bardzo wysoka (FHD)",
|
"label.veryHigh": "Bardzo wysoka (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Zamknij",
|
"label.close": "Zamknij",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Ustawienia",
|
"settings.settings": "Ustawienia",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Muito alta (FHD)",
|
"label.veryHigh": "Muito alta (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Fechar",
|
"label.close": "Fechar",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Definições",
|
"settings.settings": "Definições",
|
||||||
"settings.camera": "Camera",
|
"settings.camera": "Camera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Rezoluție foarte înaltă (FHD)",
|
"label.veryHigh": "Rezoluție foarte înaltă (FHD)",
|
||||||
"label.ultra": "Rezoluție ultra înaltă (UHD)",
|
"label.ultra": "Rezoluție ultra înaltă (UHD)",
|
||||||
"label.close": "Închide",
|
"label.close": "Închide",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Setări",
|
"settings.settings": "Setări",
|
||||||
"settings.camera": "Cameră video",
|
"settings.camera": "Cameră video",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Çok Yüksek (FHD)",
|
"label.veryHigh": "Çok Yüksek (FHD)",
|
||||||
"label.ultra": "Ultra (UHD)",
|
"label.ultra": "Ultra (UHD)",
|
||||||
"label.close": "Kapat",
|
"label.close": "Kapat",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Ayarlar",
|
"settings.settings": "Ayarlar",
|
||||||
"settings.camera": "Kamera",
|
"settings.camera": "Kamera",
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@
|
||||||
"label.veryHigh": "Дуже високий (FHD)",
|
"label.veryHigh": "Дуже високий (FHD)",
|
||||||
"label.ultra": "Ультра (UHD)",
|
"label.ultra": "Ультра (UHD)",
|
||||||
"label.close": "Закрити",
|
"label.close": "Закрити",
|
||||||
|
"label.media": null,
|
||||||
|
"label.appearence": null,
|
||||||
|
"label.advanced": null,
|
||||||
|
|
||||||
"settings.settings": "Налаштування",
|
"settings.settings": "Налаштування",
|
||||||
"settings.camera": "Камера",
|
"settings.camera": "Камера",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue