feat(sound-settings) Added ability to control sounds
This commit is contained in:
parent
251eec19cd
commit
c10805f81b
|
@ -603,6 +603,9 @@ var config = {
|
|||
// conference (if set to true, these sounds will not be played).
|
||||
// disableJoinLeaveSounds: false,
|
||||
|
||||
// Disables the sounds that play when a chat message is received.
|
||||
// disableIncomingMessageSound: false,
|
||||
|
||||
// Information for the chrome extension banner
|
||||
// chromeExtensionBanner: {
|
||||
// // The chrome extension to be installed address
|
||||
|
|
|
@ -174,7 +174,7 @@ var interfaceConfig = {
|
|||
RECENT_LIST_ENABLED: true,
|
||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar', 'sounds' ],
|
||||
|
||||
/**
|
||||
* Specify which sharing features should be displayed. If the value is not set
|
||||
|
|
|
@ -744,6 +744,7 @@
|
|||
"devices": "Devices",
|
||||
"followMe": "Everyone follows me",
|
||||
"framesPerSecond": "frames-per-second",
|
||||
"incomingMessage": "Incoming message",
|
||||
"language": "Language",
|
||||
"loggedIn": "Logged in as {{name}}",
|
||||
"microphones": "Microphones",
|
||||
|
@ -751,13 +752,18 @@
|
|||
"more": "More",
|
||||
"name": "Name",
|
||||
"noDevice": "None",
|
||||
"participantJoined": "Participant Joined",
|
||||
"participantLeft": "Participant Left",
|
||||
"playSounds": "Play sound on",
|
||||
"sameAsSystem": "Same as system ({{label}})",
|
||||
"selectAudioOutput": "Audio output",
|
||||
"selectCamera": "Camera",
|
||||
"selectMic": "Microphone",
|
||||
"sounds": "Sounds",
|
||||
"speakers": "Speakers",
|
||||
"startAudioMuted": "Everyone starts muted",
|
||||
"startVideoMuted": "Everyone starts hidden",
|
||||
"talkWhileMuted": "Talk while muted",
|
||||
"title": "Settings"
|
||||
},
|
||||
"settingsView": {
|
||||
|
|
|
@ -87,6 +87,7 @@ export default [
|
|||
'disableH264',
|
||||
'disableHPF',
|
||||
'disableInviteFunctions',
|
||||
'disableIncomingMessageSound',
|
||||
'disableJoinLeaveSounds',
|
||||
'disableLocalVideoFlip',
|
||||
'disableNS',
|
||||
|
|
|
@ -371,6 +371,7 @@ function _localParticipantLeft({ dispatch }, next, action) {
|
|||
function _maybePlaySounds({ getState, dispatch }, action) {
|
||||
const state = getState();
|
||||
const { startAudioMuted, disableJoinLeaveSounds } = state['features/base/config'];
|
||||
const { soundsParticipantJoined: joinSound, soundsParticipantLeft: leftSound } = state['features/base/settings'];
|
||||
|
||||
// If we have join/leave sounds disabled, don't play anything.
|
||||
if (disableJoinLeaveSounds) {
|
||||
|
@ -387,13 +388,16 @@ function _maybePlaySounds({ getState, dispatch }, action) {
|
|||
const { isReplacing, isReplaced } = action.participant;
|
||||
|
||||
if (action.type === PARTICIPANT_JOINED) {
|
||||
if (!joinSound) {
|
||||
return;
|
||||
}
|
||||
const { presence } = action.participant;
|
||||
|
||||
// The sounds for the poltergeist are handled by features/invite.
|
||||
if (presence !== INVITED && presence !== CALLING && !isReplacing) {
|
||||
dispatch(playSound(PARTICIPANT_JOINED_SOUND_ID));
|
||||
}
|
||||
} else if (action.type === PARTICIPANT_LEFT && !isReplaced) {
|
||||
} else if (action.type === PARTICIPANT_LEFT && !isReplaced && leftSound) {
|
||||
dispatch(playSound(PARTICIPANT_LEFT_SOUND_ID));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ const DEFAULT_STATE = {
|
|||
micDeviceId: undefined,
|
||||
serverURL: undefined,
|
||||
hideShareAudioHelper: false,
|
||||
soundsIncomingMessage: true,
|
||||
soundsParticipantJoined: true,
|
||||
soundsParticipantLeft: true,
|
||||
soundsTalkWhileMuted: true,
|
||||
startAudioOnly: false,
|
||||
startWithAudioMuted: false,
|
||||
startWithVideoMuted: false,
|
||||
|
|
|
@ -305,8 +305,10 @@ function _handleReceivedMessage({ dispatch, getState },
|
|||
// Logic for all platforms:
|
||||
const state = getState();
|
||||
const { isOpen: isChatOpen } = state['features/chat'];
|
||||
const { disableIncomingMessageSound } = state['features/base/config'];
|
||||
const { soundsIncomingMessage: soundEnabled } = state['features/base/settings'];
|
||||
|
||||
if (shouldPlaySound && !isChatOpen) {
|
||||
if (!disableIncomingMessageSound && soundEnabled && shouldPlaySound && !isChatOpen) {
|
||||
dispatch(playSound(INCOMING_MSG_SOUND_ID));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
SET_VIDEO_SETTINGS_VISIBILITY
|
||||
} from './actionTypes';
|
||||
import { LogoutDialog, SettingsDialog } from './components';
|
||||
import { getMoreTabProps, getProfileTabProps } from './functions';
|
||||
import { getMoreTabProps, getProfileTabProps, getSoundsTabProps } from './functions';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
|
@ -129,6 +129,31 @@ export function submitProfileTab(newState: Object): Function {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the settings from the "Sounds" tab of the settings dialog.
|
||||
*
|
||||
* @param {Object} newState - The new settings.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function submitSoundsTab(newState: Object): Function {
|
||||
return (dispatch, getState) => {
|
||||
const currentState = getSoundsTabProps(getState());
|
||||
const shouldUpdate = (newState.soundsIncomingMessage !== currentState.soundsIncomingMessage)
|
||||
|| (newState.soundsParticipantJoined !== currentState.soundsParticipantJoined)
|
||||
|| (newState.soundsParticipantLeft !== currentState.soundsParticipantLeft)
|
||||
|| (newState.soundsTalkWhileMuted !== currentState.soundsTalkWhileMuted);
|
||||
|
||||
if (shouldUpdate) {
|
||||
dispatch(updateSettings({
|
||||
soundsIncomingMessage: newState.soundsIncomingMessage,
|
||||
soundsParticipantJoined: newState.soundsParticipantJoined,
|
||||
soundsParticipantLeft: newState.soundsParticipantLeft,
|
||||
soundsTalkWhileMuted: newState.soundsTalkWhileMuted
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visibility of the audio settings.
|
||||
*
|
||||
|
|
|
@ -11,13 +11,14 @@ import {
|
|||
getDeviceSelectionDialogProps,
|
||||
submitDeviceSelectionTab
|
||||
} from '../../../device-selection';
|
||||
import { submitMoreTab, submitProfileTab } from '../../actions';
|
||||
import { submitMoreTab, submitProfileTab, submitSoundsTab } from '../../actions';
|
||||
import { SETTINGS_TABS } from '../../constants';
|
||||
import { getMoreTabProps, getProfileTabProps } from '../../functions';
|
||||
import { getMoreTabProps, getProfileTabProps, getSoundsTabProps } from '../../functions';
|
||||
|
||||
import CalendarTab from './CalendarTab';
|
||||
import MoreTab from './MoreTab';
|
||||
import ProfileTab from './ProfileTab';
|
||||
import SoundsTab from './SoundsTab';
|
||||
|
||||
declare var APP: Object;
|
||||
declare var interfaceConfig: Object;
|
||||
|
@ -135,6 +136,7 @@ function _mapStateToProps(state) {
|
|||
= configuredTabs.includes('profile') && !state['features/base/config'].disableProfile;
|
||||
const showCalendarSettings
|
||||
= configuredTabs.includes('calendar') && isCalendarEnabled(state);
|
||||
const showSoundsSettings = configuredTabs.includes('sounds');
|
||||
const tabs = [];
|
||||
|
||||
if (showDeviceSettings) {
|
||||
|
@ -183,6 +185,17 @@ function _mapStateToProps(state) {
|
|||
});
|
||||
}
|
||||
|
||||
if (showSoundsSettings) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.SOUNDS,
|
||||
component: SoundsTab,
|
||||
label: 'settings.sounds',
|
||||
props: getSoundsTabProps(state),
|
||||
styles: 'settings-pane profile-pane',
|
||||
submit: submitSoundsTab
|
||||
});
|
||||
}
|
||||
|
||||
if (showModeratorSettings || showLanguageSettings || showPrejoinSettings) {
|
||||
tabs.push({
|
||||
name: SETTINGS_TABS.MORE,
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
// @flow
|
||||
|
||||
import Checkbox from '@atlaskit/checkbox';
|
||||
import React from 'react';
|
||||
|
||||
import { AbstractDialogTab } from '../../../base/dialog';
|
||||
import type { Props as AbstractDialogTabProps } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SoundsTab}.
|
||||
*/
|
||||
export type Props = {
|
||||
...$Exact<AbstractDialogTabProps>,
|
||||
|
||||
/**
|
||||
* Whether or not the sound for the incoming message should play.
|
||||
*/
|
||||
soundsIncomingMessage: Boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the sound for the participant joined should play.
|
||||
*/
|
||||
soundsParticipantJoined: Boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the sound for the participant left should play.
|
||||
*/
|
||||
soundsParticipantLeft: Boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the sound for the talk while muted notification should play.
|
||||
*/
|
||||
soundsTalkWhileMuted: Boolean,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* React {@code Component} for modifying the local user's sound settings.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class SoundsTab extends AbstractDialogTab<Props> {
|
||||
/**
|
||||
* Initializes a new {@code SoundsTab} instance.
|
||||
*
|
||||
* @param {Props} props - The React {@code Component} props to initialize
|
||||
* the new {@code SoundsTab} instance with.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onChange = this._onChange.bind(this);
|
||||
}
|
||||
|
||||
_onChange: (Object) => void;
|
||||
|
||||
/**
|
||||
* Changes a sound setting state.
|
||||
*
|
||||
* @param {Object} e - The key event to handle.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onChange({ target }) {
|
||||
super._onChange({ [target.name]: target.checked });
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
soundsIncomingMessage,
|
||||
soundsParticipantJoined,
|
||||
soundsParticipantLeft,
|
||||
soundsTalkWhileMuted,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'sounds'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
{t('settings.playSounds')}
|
||||
</h2>
|
||||
<Checkbox
|
||||
isChecked = { soundsIncomingMessage }
|
||||
label = { t('settings.incomingMessage') }
|
||||
name = 'soundsIncomingMessage'
|
||||
onChange = { this._onChange } />
|
||||
<Checkbox
|
||||
isChecked = { soundsParticipantJoined }
|
||||
label = { t('settings.participantJoined') }
|
||||
name = 'soundsParticipantJoined'
|
||||
onChange = { this._onChange } />
|
||||
<Checkbox
|
||||
isChecked = { soundsParticipantLeft }
|
||||
label = { t('settings.participantLeft') }
|
||||
name = 'soundsParticipantLeft'
|
||||
onChange = { this._onChange } />
|
||||
<Checkbox
|
||||
isChecked = { soundsTalkWhileMuted }
|
||||
label = { t('settings.talkWhileMuted') }
|
||||
name = 'soundsTalkWhileMuted'
|
||||
onChange = { this._onChange } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(SoundsTab);
|
|
@ -2,7 +2,8 @@ export const SETTINGS_TABS = {
|
|||
CALENDAR: 'calendar_tab',
|
||||
DEVICES: 'devices_tab',
|
||||
MORE: 'more_tab',
|
||||
PROFILE: 'profile_tab'
|
||||
PROFILE: 'profile_tab',
|
||||
SOUNDS: 'sounds_tab'
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -156,6 +156,32 @@ export function getProfileTabProps(stateful: Object | Function) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the properties for the "Sounds" tab from settings dialog from Redux
|
||||
* state.
|
||||
*
|
||||
* @param {(Function|Object)} stateful -The (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the state.
|
||||
* @returns {Object} - The properties for the "Sounds" tab from settings
|
||||
* dialog.
|
||||
*/
|
||||
export function getSoundsTabProps(stateful: Object | Function) {
|
||||
const state = toState(stateful);
|
||||
const {
|
||||
soundsIncomingMessage,
|
||||
soundsParticipantJoined,
|
||||
soundsParticipantLeft,
|
||||
soundsTalkWhileMuted
|
||||
} = state['features/base/settings'];
|
||||
|
||||
return {
|
||||
soundsIncomingMessage,
|
||||
soundsParticipantJoined,
|
||||
soundsParticipantLeft,
|
||||
soundsTalkWhileMuted
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise which resolves with a list of objects containing
|
||||
* all the video jitsiTracks and appropriate errors for the given device ids.
|
||||
|
|
|
@ -47,7 +47,12 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
customActionHandler: () => dispatch(setAudioMuted(false))
|
||||
}));
|
||||
|
||||
const { soundsTalkWhileMuted } = getState()['features/base/settings'];
|
||||
|
||||
if (soundsTalkWhileMuted) {
|
||||
dispatch(playSound(TALK_WHILE_MUTED_SOUND_ID));
|
||||
}
|
||||
|
||||
|
||||
if (notification) {
|
||||
// we store the last start muted notification id that we showed,
|
||||
|
|
Loading…
Reference in New Issue